Merge pull request 'Removing mxpic_forge from dependency' (#2) from main into pengkun_main #3
+56
-8
@@ -12,6 +12,7 @@ from .technology import apply_technology_manifest, load_technology_manifest
|
|||||||
ROUTE_MIN_SPACING = 10.0
|
ROUTE_MIN_SPACING = 10.0
|
||||||
ROUTE_ENDPOINT_SPACING_IGNORE = ROUTE_MIN_SPACING * 2.0
|
ROUTE_ENDPOINT_SPACING_IGNORE = ROUTE_MIN_SPACING * 2.0
|
||||||
ROUTE_SPACING_GEOMETRY_ADJUSTMENT_ENABLED = False
|
ROUTE_SPACING_GEOMETRY_ADJUSTMENT_ENABLED = False
|
||||||
|
ROUTE_SBEND_GROUP_SPAN_GRID = 100.0
|
||||||
|
|
||||||
|
|
||||||
def build_project_gds(
|
def build_project_gds(
|
||||||
@@ -370,7 +371,7 @@ def _assign_sbend_lstart_spacing(plans: list) -> None:
|
|||||||
for group in groups.values():
|
for group in groups.values():
|
||||||
if len(group) < 2:
|
if len(group) < 2:
|
||||||
continue
|
continue
|
||||||
axis = _dominant_spacing_axis(group[0]["points"][0], group[0]["points"][-1])
|
axis = _sbend_forward_axis(group[0])
|
||||||
coord_key = "y" if axis == "horizontal" else "x"
|
coord_key = "y" if axis == "horizontal" else "x"
|
||||||
step = _sbend_lstart_step(group)
|
step = _sbend_lstart_step(group)
|
||||||
for plan, rank in _sbend_lstart_ranks(group, coord_key):
|
for plan, rank in _sbend_lstart_ranks(group, coord_key):
|
||||||
@@ -386,16 +387,16 @@ def _sbend_lstart_ranks(group: list, coord_key: str) -> list:
|
|||||||
deltas = [_route_coord_delta(plan, coord_key) for plan in group]
|
deltas = [_route_coord_delta(plan, coord_key) for plan in group]
|
||||||
nonzero_deltas = [delta for delta in deltas if abs(delta) > 1e-9]
|
nonzero_deltas = [delta for delta in deltas if abs(delta) > 1e-9]
|
||||||
if nonzero_deltas and all(delta > 0 for delta in nonzero_deltas):
|
if nonzero_deltas and all(delta > 0 for delta in nonzero_deltas):
|
||||||
ordered = sorted(group, key=lambda plan: _route_mid_coord(plan, coord_key))
|
ordered = sorted(group, key=lambda plan: _route_start_coord(plan, coord_key), reverse=True)
|
||||||
return [(plan, len(ordered) - index) for index, plan in enumerate(ordered)]
|
return [(plan, index + 1) for index, plan in enumerate(ordered)]
|
||||||
if nonzero_deltas and all(delta < 0 for delta in nonzero_deltas):
|
if nonzero_deltas and all(delta < 0 for delta in nonzero_deltas):
|
||||||
ordered = sorted(group, key=lambda plan: _route_mid_coord(plan, coord_key), reverse=True)
|
ordered = sorted(group, key=lambda plan: _route_start_coord(plan, coord_key), reverse=True)
|
||||||
return [(plan, len(ordered) - index) for index, plan in enumerate(ordered)]
|
return [(plan, len(ordered) - index) for index, plan in enumerate(ordered)]
|
||||||
|
|
||||||
center = sum(_route_mid_coord(plan, coord_key) for plan in group) / len(group)
|
center = sum(_route_start_coord(plan, coord_key) for plan in group) / len(group)
|
||||||
distances = sorted({round(abs(_route_mid_coord(plan, coord_key) - center), 6) for plan in group})
|
distances = sorted({round(abs(_route_start_coord(plan, coord_key) - center), 6) for plan in group})
|
||||||
return [
|
return [
|
||||||
(plan, distances.index(round(abs(_route_mid_coord(plan, coord_key) - center), 6)) + 1)
|
(plan, distances.index(round(abs(_route_start_coord(plan, coord_key) - center), 6)) + 1)
|
||||||
for plan in group
|
for plan in group
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -408,15 +409,58 @@ def _route_coord_delta(plan: dict, coord_key: str) -> float:
|
|||||||
|
|
||||||
def _sbend_spacing_group_key(plan: dict):
|
def _sbend_spacing_group_key(plan: dict):
|
||||||
link = plan["link"]
|
link = plan["link"]
|
||||||
axis = _dominant_spacing_axis(plan["points"][0], plan["points"][-1])
|
axis = _sbend_forward_axis(plan)
|
||||||
|
main_key = "x" if axis == "horizontal" else "y"
|
||||||
|
main_delta = _route_coord_delta(plan, main_key)
|
||||||
|
explicit_group = _link_explicit_route_group(link)
|
||||||
|
if explicit_group:
|
||||||
|
route_scope = ("explicit", explicit_group)
|
||||||
|
else:
|
||||||
|
route_scope = (
|
||||||
|
"span",
|
||||||
|
_sbend_span_bucket(plan["points"][0][main_key]),
|
||||||
|
_sbend_span_bucket(plan["points"][-1][main_key]),
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
axis,
|
axis,
|
||||||
|
_route_direction_sign(main_delta),
|
||||||
|
route_scope,
|
||||||
str(link.xsection or ""),
|
str(link.xsection or ""),
|
||||||
_safe_float(link.width, 0.0),
|
_safe_float(link.width, 0.0),
|
||||||
_safe_float(link.radius, 0.0),
|
_safe_float(link.radius, 0.0),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _sbend_forward_axis(plan: dict) -> str:
|
||||||
|
angle = _pin_angle(plan["pin1"])
|
||||||
|
if angle is None:
|
||||||
|
angle = _pin_angle(plan["pin2"])
|
||||||
|
if angle is None:
|
||||||
|
return _dominant_spacing_axis(plan["points"][0], plan["points"][-1])
|
||||||
|
normalized = angle % 180
|
||||||
|
if abs(normalized) <= 45 or abs(normalized - 180) <= 45:
|
||||||
|
return "horizontal"
|
||||||
|
if abs(normalized - 90) <= 45:
|
||||||
|
return "vertical"
|
||||||
|
return _dominant_spacing_axis(plan["points"][0], plan["points"][-1])
|
||||||
|
|
||||||
|
|
||||||
|
def _link_explicit_route_group(link: LinkSpec) -> str:
|
||||||
|
return str(getattr(link, "route_group", "") or "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def _route_direction_sign(delta: float) -> int:
|
||||||
|
if delta > 1e-9:
|
||||||
|
return 1
|
||||||
|
if delta < -1e-9:
|
||||||
|
return -1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _sbend_span_bucket(value: float) -> int:
|
||||||
|
return round(float(value) / ROUTE_SBEND_GROUP_SPAN_GRID)
|
||||||
|
|
||||||
|
|
||||||
def _route_group_needs_spacing(group: list) -> bool:
|
def _route_group_needs_spacing(group: list) -> bool:
|
||||||
check_points = [_route_spacing_check_points(plan["points"]) for plan in group]
|
check_points = [_route_spacing_check_points(plan["points"]) for plan in group]
|
||||||
threshold = _sbend_lstart_step(group)
|
threshold = _sbend_lstart_step(group)
|
||||||
@@ -433,6 +477,10 @@ def _route_mid_coord(plan: dict, coord_key: str) -> float:
|
|||||||
return (float(start[coord_key]) + float(end[coord_key])) / 2.0
|
return (float(start[coord_key]) + float(end[coord_key])) / 2.0
|
||||||
|
|
||||||
|
|
||||||
|
def _route_start_coord(plan: dict, coord_key: str) -> float:
|
||||||
|
return float(plan["points"][0][coord_key])
|
||||||
|
|
||||||
|
|
||||||
def _route_spacing_reference_points(link: LinkSpec, pin1, pin2) -> list:
|
def _route_spacing_reference_points(link: LinkSpec, pin1, pin2) -> list:
|
||||||
if len(link.points or []) >= 2:
|
if len(link.points or []) >= 2:
|
||||||
return _route_points_with_pin_endpoints(link.points, pin1, pin2)
|
return _route_points_with_pin_endpoints(link.points, pin1, pin2)
|
||||||
|
|||||||
+218
-207
@@ -1,227 +1,238 @@
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PinSpec:
|
class PinSpec:
|
||||||
name: str
|
name: str
|
||||||
x: float = 0.0
|
x: float = 0.0
|
||||||
y: float = 0.0
|
y: float = 0.0
|
||||||
angle: float = 0.0
|
angle: float = 0.0
|
||||||
width: float = 0.5
|
width: float = 0.5
|
||||||
layer: str = "WG_CORE"
|
layer: str = "WG_CORE"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class InstanceSpec:
|
class InstanceSpec:
|
||||||
name: str
|
name: str
|
||||||
component: str
|
component: str
|
||||||
x: float = 0.0
|
x: float = 0.0
|
||||||
y: float = 0.0
|
y: float = 0.0
|
||||||
rotation: float = 0.0
|
rotation: float = 0.0
|
||||||
flip: bool = False
|
flip: bool = False
|
||||||
flop: bool = False
|
flop: bool = False
|
||||||
mirror: bool = False
|
mirror: bool = False
|
||||||
settings: Dict = field(default_factory=dict)
|
settings: Dict = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ElementSpec:
|
class ElementSpec:
|
||||||
name: str
|
name: str
|
||||||
type: str
|
type: str
|
||||||
x: float = 0.0
|
x: float = 0.0
|
||||||
y: float = 0.0
|
y: float = 0.0
|
||||||
angle: float = 0.0
|
angle: float = 0.0
|
||||||
width: float = 0.5
|
width: float = 0.5
|
||||||
port_number: int = 1
|
port_number: int = 1
|
||||||
pitch: float = 10.0
|
pitch: float = 10.0
|
||||||
layer: str = "WG_CORE"
|
layer: str = "WG_CORE"
|
||||||
description: str = ""
|
description: str = ""
|
||||||
pins: List[Dict[str, str]] = field(default_factory=list)
|
pins: List[Dict[str, str]] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LinkSpec:
|
class LinkSpec:
|
||||||
src_inst: str = ""
|
src_inst: str = ""
|
||||||
src_pin: str = ""
|
src_pin: str = ""
|
||||||
dst_inst: str = ""
|
dst_inst: str = ""
|
||||||
dst_pin: str = ""
|
dst_pin: str = ""
|
||||||
xsection: str = "strip"
|
xsection: str = "strip"
|
||||||
family: str = "optical"
|
family: str = "optical"
|
||||||
width: Optional[float] = None
|
width: Optional[float] = None
|
||||||
radius: Optional[float] = None
|
radius: Optional[float] = None
|
||||||
routing_type: str = "euler_bend"
|
routing_type: str = "euler_bend"
|
||||||
|
bundle: str = ""
|
||||||
|
route_group: str = ""
|
||||||
points: List[Dict[str, float]] = field(default_factory=list)
|
points: List[Dict[str, float]] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class BundleSpec:
|
class BundleSpec:
|
||||||
name: str
|
name: str
|
||||||
links: List[LinkSpec] = field(default_factory=list)
|
links: List[LinkSpec] = field(default_factory=list)
|
||||||
routing_type: str = "euler_bend"
|
routing_type: str = "euler_bend"
|
||||||
radius: Optional[float] = None
|
radius: Optional[float] = None
|
||||||
width: Optional[float] = None
|
width: Optional[float] = None
|
||||||
xsection: str = "strip"
|
xsection: str = "strip"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CellSpec:
|
class CellSpec:
|
||||||
name: str
|
name: str
|
||||||
type: str = "composite"
|
type: str = "composite"
|
||||||
version: str = "1.0.0"
|
version: str = "1.0.0"
|
||||||
pins: Dict[str, PinSpec] = field(default_factory=dict)
|
pins: Dict[str, PinSpec] = field(default_factory=dict)
|
||||||
elements: Dict[str, ElementSpec] = field(default_factory=dict)
|
elements: Dict[str, ElementSpec] = field(default_factory=dict)
|
||||||
instances: Dict[str, InstanceSpec] = field(default_factory=dict)
|
instances: Dict[str, InstanceSpec] = field(default_factory=dict)
|
||||||
bundles: Dict[str, BundleSpec] = field(default_factory=dict)
|
bundles: Dict[str, BundleSpec] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
def load_cell_spec(path: str) -> CellSpec:
|
def load_cell_spec(path: str) -> CellSpec:
|
||||||
with open(path, "r", encoding="utf-8") as file:
|
with open(path, "r", encoding="utf-8") as file:
|
||||||
return parse_cell_dict(yaml.safe_load(file) or {})
|
return parse_cell_dict(yaml.safe_load(file) or {})
|
||||||
|
|
||||||
|
|
||||||
def parse_cell_dict(data: dict) -> CellSpec:
|
def parse_cell_dict(data: dict) -> CellSpec:
|
||||||
spec = CellSpec(
|
spec = CellSpec(
|
||||||
name=str(data.get("name") or "cell"),
|
name=str(data.get("name") or "cell"),
|
||||||
type=str(data.get("type") or "composite"),
|
type=str(data.get("type") or "composite"),
|
||||||
version=str(data.get("version") or "1.0.0"),
|
version=str(data.get("version") or "1.0.0"),
|
||||||
)
|
)
|
||||||
|
|
||||||
for pin in data.get("pins", []) or []:
|
for pin in data.get("pins", []) or []:
|
||||||
name = str(pin.get("name") or "pin")
|
name = str(pin.get("name") or "pin")
|
||||||
spec.pins[name] = PinSpec(
|
spec.pins[name] = PinSpec(
|
||||||
name=name,
|
name=name,
|
||||||
x=_float(pin.get("x")),
|
x=_float(pin.get("x")),
|
||||||
y=_float(pin.get("y")),
|
y=_float(pin.get("y")),
|
||||||
angle=_float(pin.get("angle", pin.get("a"))),
|
angle=_float(pin.get("angle", pin.get("a"))),
|
||||||
width=_float(pin.get("width"), 0.5),
|
width=_float(pin.get("width"), 0.5),
|
||||||
layer=str(pin.get("layer") or "WG_CORE"),
|
layer=str(pin.get("layer") or "WG_CORE"),
|
||||||
)
|
)
|
||||||
|
|
||||||
for element_name, element in (data.get("elements") or {}).items():
|
for element_name, element in (data.get("elements") or {}).items():
|
||||||
spec.elements[str(element_name)] = ElementSpec(
|
spec.elements[str(element_name)] = ElementSpec(
|
||||||
name=str(element_name),
|
name=str(element_name),
|
||||||
type=str(element.get("type") or "anchor"),
|
type=str(element.get("type") or "anchor"),
|
||||||
x=_float(element.get("x")),
|
x=_float(element.get("x")),
|
||||||
y=_float(element.get("y")),
|
y=_float(element.get("y")),
|
||||||
angle=_float(element.get("angle", element.get("a"))),
|
angle=_float(element.get("angle", element.get("a"))),
|
||||||
width=_float(element.get("width"), 0.5),
|
width=_float(element.get("width"), 0.5),
|
||||||
port_number=_int(element.get("pin_number", element.get("pinNumber", element.get("port_number", element.get("portNumber")))), 1),
|
port_number=_int(element.get("pin_number", element.get("pinNumber", element.get("port_number", element.get("portNumber")))), 1),
|
||||||
pitch=_float(element.get("pitch"), 10.0),
|
pitch=_float(element.get("pitch"), 10.0),
|
||||||
layer=str(element.get("layer") or "WG_CORE"),
|
layer=str(element.get("layer") or "WG_CORE"),
|
||||||
description=str(element.get("description") or ""),
|
description=str(element.get("description") or ""),
|
||||||
pins=_pins(element.get("pins")),
|
pins=_pins(element.get("pins")),
|
||||||
)
|
)
|
||||||
|
|
||||||
for instance_name, instance in (data.get("instances") or {}).items():
|
for instance_name, instance in (data.get("instances") or {}).items():
|
||||||
spec.instances[str(instance_name)] = InstanceSpec(
|
spec.instances[str(instance_name)] = InstanceSpec(
|
||||||
name=str(instance_name),
|
name=str(instance_name),
|
||||||
component=str(instance.get("component") or ""),
|
component=str(instance.get("component") or ""),
|
||||||
x=_float(instance.get("x")),
|
x=_float(instance.get("x")),
|
||||||
y=_float(instance.get("y")),
|
y=_float(instance.get("y")),
|
||||||
rotation=_float(instance.get("rotation")),
|
rotation=_float(instance.get("rotation")),
|
||||||
flip=_bool(instance.get("flip", instance.get("mirror", False))),
|
flip=_bool(instance.get("flip", instance.get("mirror", False))),
|
||||||
flop=_bool(instance.get("flop", False)),
|
flop=_bool(instance.get("flop", False)),
|
||||||
mirror=_bool(instance.get("mirror", instance.get("flip", False))),
|
mirror=_bool(instance.get("mirror", instance.get("flip", False))),
|
||||||
settings=instance.get("settings") or {},
|
settings=instance.get("settings") or {},
|
||||||
)
|
)
|
||||||
|
|
||||||
for bundle_name, bundle_data in (data.get("bundles") or {}).items():
|
for bundle_name, bundle_data in (data.get("bundles") or {}).items():
|
||||||
bundle = BundleSpec(
|
bundle = BundleSpec(
|
||||||
name=str(bundle_name),
|
name=str(bundle_name),
|
||||||
routing_type=str(bundle_data.get("routing_type") or "euler_bend"),
|
routing_type=str(bundle_data.get("routing_type") or "euler_bend"),
|
||||||
radius=_optional_float(bundle_data.get("radius")),
|
radius=_optional_float(bundle_data.get("radius")),
|
||||||
width=_optional_float(bundle_data.get("width")),
|
width=_optional_float(bundle_data.get("width")),
|
||||||
xsection=str(bundle_data.get("xsection") or bundle_data.get("xs") or "strip"),
|
xsection=str(bundle_data.get("xsection") or bundle_data.get("xs") or "strip"),
|
||||||
)
|
)
|
||||||
for link_data in bundle_data.get("links", []) or []:
|
for link_data in bundle_data.get("links", []) or []:
|
||||||
src_inst, src_pin = _endpoint(link_data.get("from"), link_data.get("src_inst"), link_data.get("src_pin"))
|
src_inst, src_pin = _endpoint(link_data.get("from"), link_data.get("src_inst"), link_data.get("src_pin"))
|
||||||
dst_inst, dst_pin = _endpoint(link_data.get("to"), link_data.get("dst_inst"), link_data.get("dst_pin"))
|
dst_inst, dst_pin = _endpoint(link_data.get("to"), link_data.get("dst_inst"), link_data.get("dst_pin"))
|
||||||
xsection = str(link_data.get("xsection") or link_data.get("xs") or bundle.xsection)
|
xsection = str(link_data.get("xsection") or link_data.get("xs") or bundle.xsection)
|
||||||
bundle.links.append(LinkSpec(
|
bundle.links.append(LinkSpec(
|
||||||
src_inst=src_inst,
|
src_inst=src_inst,
|
||||||
src_pin=src_pin,
|
src_pin=src_pin,
|
||||||
dst_inst=dst_inst,
|
dst_inst=dst_inst,
|
||||||
dst_pin=dst_pin,
|
dst_pin=dst_pin,
|
||||||
xsection=xsection,
|
xsection=xsection,
|
||||||
family=str(link_data.get("family") or _family_from_xsection(xsection)),
|
family=str(link_data.get("family") or _family_from_xsection(xsection)),
|
||||||
width=_optional_float(link_data.get("width"), bundle.width),
|
width=_optional_float(link_data.get("width"), bundle.width),
|
||||||
radius=_optional_float(link_data.get("radius"), bundle.radius),
|
radius=_optional_float(link_data.get("radius"), bundle.radius),
|
||||||
routing_type=str(link_data.get("routing_type") or bundle.routing_type),
|
routing_type=str(link_data.get("routing_type") or bundle.routing_type),
|
||||||
|
bundle=bundle.name,
|
||||||
|
route_group=str(
|
||||||
|
link_data.get("route_group")
|
||||||
|
or link_data.get("routeGroup")
|
||||||
|
or link_data.get("group")
|
||||||
|
or link_data.get("bundle_group")
|
||||||
|
or link_data.get("bundleGroup")
|
||||||
|
or ""
|
||||||
|
),
|
||||||
points=_points(link_data.get("points")),
|
points=_points(link_data.get("points")),
|
||||||
))
|
))
|
||||||
spec.bundles[bundle.name] = bundle
|
spec.bundles[bundle.name] = bundle
|
||||||
|
|
||||||
return spec
|
return spec
|
||||||
|
|
||||||
|
|
||||||
def _endpoint(compact, inst, port):
|
def _endpoint(compact, inst, port):
|
||||||
if compact:
|
if compact:
|
||||||
value = str(compact)
|
value = str(compact)
|
||||||
if ":" in value:
|
if ":" in value:
|
||||||
left, right = value.split(":", 1)
|
left, right = value.split(":", 1)
|
||||||
return left, right
|
return left, right
|
||||||
if inst or port:
|
if inst or port:
|
||||||
return str(inst or ""), str(port or "")
|
return str(inst or ""), str(port or "")
|
||||||
return "", ""
|
return "", ""
|
||||||
|
|
||||||
|
|
||||||
def _family_from_xsection(xsection: str) -> str:
|
def _family_from_xsection(xsection: str) -> str:
|
||||||
return "electrical" if str(xsection).startswith("metal") else "optical"
|
return "electrical" if str(xsection).startswith("metal") else "optical"
|
||||||
|
|
||||||
|
|
||||||
def _points(points) -> List[Dict[str, float]]:
|
def _points(points) -> List[Dict[str, float]]:
|
||||||
parsed = []
|
parsed = []
|
||||||
for point in points or []:
|
for point in points or []:
|
||||||
if not isinstance(point, dict):
|
if not isinstance(point, dict):
|
||||||
continue
|
continue
|
||||||
x = _optional_float(point.get("x"))
|
x = _optional_float(point.get("x"))
|
||||||
y = _optional_float(point.get("y"))
|
y = _optional_float(point.get("y"))
|
||||||
if x is None or y is None:
|
if x is None or y is None:
|
||||||
continue
|
continue
|
||||||
parsed.append({"x": x, "y": y})
|
parsed.append({"x": x, "y": y})
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
def _pins(pins) -> List[Dict[str, str]]:
|
def _pins(pins) -> List[Dict[str, str]]:
|
||||||
parsed = []
|
parsed = []
|
||||||
for pin in pins or []:
|
for pin in pins or []:
|
||||||
if not isinstance(pin, dict):
|
if not isinstance(pin, dict):
|
||||||
continue
|
continue
|
||||||
name = str(pin.get("name") or "").strip()
|
name = str(pin.get("name") or "").strip()
|
||||||
role = str(pin.get("role") or "").strip()
|
role = str(pin.get("role") or "").strip()
|
||||||
if name:
|
if name:
|
||||||
parsed.append({"name": name, "role": role})
|
parsed.append({"name": name, "role": role})
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
def _optional_float(value, default=None):
|
def _optional_float(value, default=None):
|
||||||
if value is None or value == "":
|
if value is None or value == "":
|
||||||
return default
|
return default
|
||||||
return _float(value, default)
|
return _float(value, default)
|
||||||
|
|
||||||
|
|
||||||
def _bool(value) -> bool:
|
def _bool(value) -> bool:
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
return value.strip().lower() in {"1", "true", "yes", "on"}
|
return value.strip().lower() in {"1", "true", "yes", "on"}
|
||||||
return bool(value)
|
return bool(value)
|
||||||
|
|
||||||
|
|
||||||
def _float(value, default=0.0):
|
def _float(value, default=0.0):
|
||||||
try:
|
try:
|
||||||
if value is None or value == "":
|
if value is None or value == "":
|
||||||
return default
|
return default
|
||||||
return float(value)
|
return float(value)
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def _int(value, default=0):
|
def _int(value, default=0):
|
||||||
try:
|
try:
|
||||||
if value is None or value == "":
|
if value is None or value == "":
|
||||||
return default
|
return default
|
||||||
return max(1, int(float(value)))
|
return max(1, int(float(value)))
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
return default
|
return default
|
||||||
|
|||||||
Reference in New Issue
Block a user