diff --git a/src/faebryk/core/graphinterface.py b/src/faebryk/core/graphinterface.py index 568d8458..742f16cd 100644 --- a/src/faebryk/core/graphinterface.py +++ b/src/faebryk/core/graphinterface.py @@ -1,7 +1,7 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT import logging -from typing import TYPE_CHECKING, Mapping, Optional, cast +from typing import TYPE_CHECKING, Mapping, Optional from typing_extensions import Self, deprecated @@ -18,7 +18,8 @@ logger = logging.getLogger(__name__) -Graph = GraphImpl["GraphInterface"] + +class Graph(GraphImpl["GraphInterface"]): ... class GraphInterface(FaebrykLibObject): diff --git a/src/faebryk/core/parameter.py b/src/faebryk/core/parameter.py index ea82754b..d736ed9d 100644 --- a/src/faebryk/core/parameter.py +++ b/src/faebryk/core/parameter.py @@ -3,6 +3,7 @@ import logging from typing import ( Callable, + Concatenate, Optional, Sequence, ) @@ -12,6 +13,7 @@ from faebryk.core.graphinterface import GraphInterface from faebryk.core.node import Node from faebryk.core.trait import Trait +from faebryk.libs.units import Quantity, UnitsContainer, to_si_str from faebryk.libs.util import Tree, TwistArgs, is_type_pair, try_avoid_endless_recursion logger = logging.getLogger(__name__) @@ -33,6 +35,19 @@ def wrap(*args): return wrap +def _resolved_self[PV, O, **P]( + func: Callable[Concatenate["Parameter[PV]", P], O], +) -> Callable[Concatenate["PV | set[PV] | tuple[PV, PV] | Parameter[PV]", P], O]: + def wrap( + p: "PV | set[PV] | tuple[PV, PV] | Parameter[PV]", + *args: P.args, + **kwargs: P.kwargs, + ): + return func(Parameter.from_literal(p).get_most_narrow(), *args, **kwargs) + + return wrap + + class Parameter[PV](Node): type LIT = PV | set[PV] | tuple[PV, PV] type LIT_OR_PARAM = LIT | "Parameter[PV]" @@ -416,3 +431,63 @@ def get_tree_param(self, include_root: bool = True) -> Tree["Parameter"]: if include_root: out = Tree[Parameter]({self: out}) return out + + # TODO make those all abstract ------------------------------------------------------ + @_resolved_self + def enum_parameter_representation( + self: "Parameter[PV]", required: bool = False + ) -> str: + return self._enum_parameter_representation(required=required) + + def _enum_parameter_representation(self, required: bool = False) -> str: + return self.as_unit("", required=required) + + @_resolved_self + def as_unit( + self: "Parameter[PV]", + unit: UnitsContainer, + base: int = 1000, + required: bool = False, + ) -> str: + if base != 1000: + raise NotImplementedError("Only base 1000 supported") + + return self._as_unit(unit, base=base, required=required) + + def _as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str: + raise ValueError(f"Unsupported {self}") + + @_resolved_self + def as_unit_with_tolerance( + self: "Parameter[PV]", + unit: UnitsContainer, + base: int = 1000, + required: bool = False, + ) -> str: + return self._as_unit_with_tolerance(unit, base=base, required=required) + + def _as_unit_with_tolerance( + self, unit: UnitsContainer, base: int, required: bool + ) -> str: + return self._as_unit(unit, base=base, required=required) + + @_resolved_self + def get_max(self: "Parameter[PV]") -> PV: + return self._max() + + def _max(self): + raise ValueError(f"Can't get max for {self}") + + def with_same_unit( + self: "Quantity | float | int | LIT_OR_PARAM", + to_convert: float | int, + ): + from faebryk.library.Constant import Constant + + if isinstance(self, Constant) and isinstance(self.value, Quantity): + return Quantity(to_convert, self.value.units) + if isinstance(self, Quantity): + return Quantity(to_convert, self.units) + if isinstance(self, (float, int)): + return to_convert + raise NotImplementedError(f"Unsupported {self=}") diff --git a/src/faebryk/core/util.py b/src/faebryk/core/util.py index cd85c33a..aa5b8309 100644 --- a/src/faebryk/core/util.py +++ b/src/faebryk/core/util.py @@ -2,133 +2,18 @@ # SPDX-License-Identifier: MIT import logging -from enum import Enum -from textwrap import indent -from typing import ( - Callable, - Iterable, - Sequence, - cast, -) +from typing import Iterable from typing_extensions import deprecated import faebryk.library._F as F -from faebryk.core.graphinterface import ( - Graph, - GraphInterface, - GraphInterfaceSelf, -) -from faebryk.core.link import Link, LinkDirect -from faebryk.core.module import Module +from faebryk.core.graphinterface import Graph, GraphInterfaceSelf from faebryk.core.moduleinterface import ModuleInterface from faebryk.core.node import Node -from faebryk.core.parameter import Parameter from faebryk.core.trait import Trait -from faebryk.libs.units import Quantity, UnitsContainer, to_si_str -from faebryk.libs.util import NotNone, Tree, cast_assert, zip_dicts_by_key, zip_exhaust logger = logging.getLogger(__name__) -# Parameter ---------------------------------------------------------------------------- - - -def enum_parameter_representation(param: Parameter, required: bool = False) -> str: - if isinstance(param, F.Constant): - return param.value.name if isinstance(param.value, Enum) else str(param.value) - elif isinstance(param, F.Range): - return ( - f"{enum_parameter_representation(param.min)} - " - f"{enum_parameter_representation(param.max)}" - ) - elif isinstance(param, F.Set): - return f"Set({', '.join(map(enum_parameter_representation, param.params))})" - elif isinstance(param, F.TBD): - return "TBD" if required else "" - elif isinstance(param, F.ANY): - return "ANY" if required else "" - else: - return type(param).__name__ - - -def as_unit( - param: Parameter[Quantity], - unit: str | UnitsContainer, - base: int = 1000, - required: bool = False, -) -> str: - if base != 1000: - raise NotImplementedError("Only base 1000 supported") - if isinstance(param, F.Constant): - return to_si_str(param.value, unit) - elif isinstance(param, F.Range): - return ( - as_unit(param.min, unit, base=base) - + " - " - + as_unit(param.max, unit, base=base, required=True) - ) - elif isinstance(param, F.Set): - return ( - "Set(" - + ", ".join(map(lambda x: as_unit(x, unit, required=True), param.params)) - + ")" - ) - elif isinstance(param, F.TBD): - return "TBD" if required else "" - elif isinstance(param, F.ANY): - return "ANY" if required else "" - - raise ValueError(f"Unsupported {param=}") - - -def as_unit_with_tolerance( - param: Parameter, unit: str, base: int = 1000, required: bool = False -) -> str: - if isinstance(param, F.Constant): - return as_unit(param, unit, base=base) - elif isinstance(param, F.Range): - center, delta = param.as_center_tuple(relative=True) - delta_percent_str = f"±{to_si_str(delta.value, "%", 0)}" - return ( - f"{as_unit(center, unit, base=base, required=required)} {delta_percent_str}" - ) - elif isinstance(param, F.Set): - return ( - "Set(" - + ", ".join( - map(lambda x: as_unit_with_tolerance(x, unit, base), param.params) - ) - + ")" - ) - elif isinstance(param, F.TBD): - return "TBD" if required else "" - elif isinstance(param, F.ANY): - return "ANY" if required else "" - raise ValueError(f"Unsupported {param=}") - - -def get_parameter_max(param: Parameter): - if isinstance(param, F.Constant): - return param.value - if isinstance(param, F.Range): - return param.max - if isinstance(param, F.Set): - return max(map(get_parameter_max, param.params)) - raise ValueError(f"Can't get max for {param}") - - -def with_same_unit(to_convert: float | int, param: Parameter | Quantity | float | int): - if isinstance(param, F.Constant) and isinstance(param.value, Quantity): - return Quantity(to_convert, param.value.units) - if isinstance(param, Quantity): - return Quantity(to_convert, param.units) - if isinstance(param, (float, int)): - return to_convert - raise NotImplementedError(f"Unsupported {param=}") - - -# -------------------------------------------------------------------------------------- - # Graph Querying ----------------------------------------------------------------------- @@ -183,41 +68,6 @@ def get_all_nodes_of_types(g: Graph, t: tuple[type[Node], ...]) -> set[Node]: return {n for n in node_projected_graph(g) if isinstance(n, t)} -def get_direct_connected_nodes[T: Node]( - gif: GraphInterface, ty: type[T] = Node -) -> set[T]: - out = Node.get_nodes_from_gifs( - g for g, t in gif.edges.items() if isinstance(t, LinkDirect) - ) - assert all(isinstance(n, ty) for n in out) - return cast(set[T], out) - - -def get_mif_tree( - obj: ModuleInterface | Module, -) -> dict[ModuleInterface, dict[ModuleInterface, dict]]: - mifs = obj.get_children(direct_only=True, types=ModuleInterface) - - return {mif: get_mif_tree(mif) for mif in mifs} - - -def format_mif_tree(tree: dict[ModuleInterface, dict[ModuleInterface, dict]]) -> str: - def str_tree( - tree: dict[ModuleInterface, dict[ModuleInterface, dict]], - ) -> dict[str, dict]: - def get_name(k: ModuleInterface): - # get_parent never none, since k gotten from parent - return NotNone(k.get_parent())[1] - - return { - f"{get_name(k)} ({type(k).__name__})": str_tree(v) for k, v in tree.items() - } - - import json - - return json.dumps(str_tree(tree), indent=4) - - # -------------------------------------------------------------------------------------- @@ -229,7 +79,7 @@ def use_interface_names_as_net_names(node: Node, name: str | None = None): name_prefix = node.get_full_name() - el_ifs = {n for n in get_all_nodes(node) if isinstance(n, F.Electrical)} + el_ifs = node.get_children(types=F.Electrical, direct_only=False) # for el_if in el_ifs: # print(el_if) @@ -295,7 +145,3 @@ def use_interface_names_as_net_names(node: Node, name: str | None = None): net.part_of.connect(el_if) logger.debug(f"Created {net_name} for {el_if}") nets[net_name] = net, el_if - - -def with_names[N: Node](nodes: Iterable[N]) -> dict[str, N]: - return {n.get_name(): n for n in nodes} diff --git a/src/faebryk/library/ANY.py b/src/faebryk/library/ANY.py index c8b7421d..fd81098c 100644 --- a/src/faebryk/library/ANY.py +++ b/src/faebryk/library/ANY.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT from faebryk.core.parameter import Parameter +from faebryk.libs.units import UnitsContainer class ANY[PV](Parameter[PV]): @@ -19,3 +20,6 @@ def __eq__(self, __value: object) -> bool: def __hash__(self) -> int: return super().__hash__() + + def _as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str: + return "ANY" if required else "" diff --git a/src/faebryk/library/Capacitor.py b/src/faebryk/library/Capacitor.py index 3e4e6244..74c9b557 100644 --- a/src/faebryk/library/Capacitor.py +++ b/src/faebryk/library/Capacitor.py @@ -38,26 +38,17 @@ def can_bridge(self): @L.rt_field def simple_value_representation(self): - from faebryk.core.util import ( - as_unit, - as_unit_with_tolerance, - enum_parameter_representation, - ) - return F.has_simple_value_representation_based_on_params( ( self.capacitance, self.rated_voltage, self.temperature_coefficient, ), - lambda ps: " ".join( - filter( - None, - [ - as_unit_with_tolerance(ps[0], "F"), - as_unit(ps[1], "V"), - enum_parameter_representation(ps[2].get_most_narrow()), - ], - ) + lambda c, v, t: " ".join( + [ + c.as_unit_with_tolerance("F"), + v.as_unit("V"), + t.enum_parameter_representation(), + ], ), ) diff --git a/src/faebryk/library/Comparator.py b/src/faebryk/library/Comparator.py index e7c2905a..e919c039 100644 --- a/src/faebryk/library/Comparator.py +++ b/src/faebryk/library/Comparator.py @@ -29,19 +29,24 @@ class OutputType(Enum): @L.rt_field def simple_value_representation(self): - from faebryk.core.util import as_unit - return F.has_simple_value_representation_based_on_params( - [ + ( self.common_mode_rejection_ratio, self.input_bias_current, self.input_hysteresis_voltage, self.input_offset_voltage, self.propagation_delay, - ], - lambda p: ( - f"{p[0]} CMRR, {as_unit(p[1], 'A')} Ib, {as_unit(p[2], 'V')} Vhys, " - f"{as_unit(p[3], 'V')} Vos, {as_unit(p[4], 's')} tpd" + ), + lambda cmrr, ib, vhys, vos, tpd: ( + ", ".join( + [ + f"{cmrr} CMRR", + f"{ib.as_unit('A')} Ib", + f"{vhys.as_unit('V')} Vhys", + f"{vos.as_unit('V')} Vos", + f"{tpd.as_unit('s')} tpd", + ] + ) ), ) diff --git a/src/faebryk/library/Constant.py b/src/faebryk/library/Constant.py index ec9c853a..2b978b04 100644 --- a/src/faebryk/library/Constant.py +++ b/src/faebryk/library/Constant.py @@ -1,12 +1,13 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT +from enum import Enum from typing import Self, SupportsAbs import numpy as np from faebryk.core.parameter import Parameter, _resolved -from faebryk.libs.units import Quantity +from faebryk.libs.units import Quantity, UnitsContainer, to_si_str class Constant[PV](Parameter[PV], Parameter[PV].SupportsSetOps): @@ -98,3 +99,12 @@ def try_compress(self) -> Parameter[PV]: if isinstance(self.value, Parameter): return self.value return super().try_compress() + + def _max(self): + return self.value + + def as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str: + return to_si_str(self.value, unit) + + def _enum_parameter_representation(self, required: bool) -> str: + return self.value.name if isinstance(self.value, Enum) else str(self.value) diff --git a/src/faebryk/library/Diode.py b/src/faebryk/library/Diode.py index caa64319..abe53a88 100644 --- a/src/faebryk/library/Diode.py +++ b/src/faebryk/library/Diode.py @@ -24,11 +24,9 @@ def can_bridge(self): @L.rt_field def simple_value_representation(self): - from faebryk.core.util import as_unit - - return F.has_simple_value_representation_based_on_param( - self.forward_voltage, - lambda p: as_unit(p, "V"), + return F.has_simple_value_representation_based_on_params( + (self.forward_voltage,), + lambda p: p.as_unit("V"), ) designator_prefix = L.f_field(F.has_designator_prefix_defined)("D") diff --git a/src/faebryk/library/Inductor.py b/src/faebryk/library/Inductor.py index 727b4ac4..832285cd 100644 --- a/src/faebryk/library/Inductor.py +++ b/src/faebryk/library/Inductor.py @@ -24,11 +24,6 @@ def can_bridge(self): @L.rt_field def simple_value_representation(self): - from faebryk.core.util import ( - as_unit, - as_unit_with_tolerance, - ) - return F.has_simple_value_representation_based_on_params( ( self.inductance, @@ -36,16 +31,16 @@ def simple_value_representation(self): self.rated_current, self.dc_resistance, ), - lambda ps: " ".join( - filter( - None, - [ - as_unit_with_tolerance(ps[0], "H"), - as_unit(ps[1], "Hz"), - as_unit(ps[2], "A"), - as_unit(ps[3], "Ω"), - ], - ) + lambda inductance, + self_resonant_frequency, + rated_current, + dc_resistance: " ".join( + [ + inductance.as_unit_with_tolerance("H"), + self_resonant_frequency.as_unit("Hz"), + rated_current.as_unit("A"), + dc_resistance.as_unit("Ω"), + ], ), ) diff --git a/src/faebryk/library/LDO.py b/src/faebryk/library/LDO.py index 2e98fbd0..73797f19 100644 --- a/src/faebryk/library/LDO.py +++ b/src/faebryk/library/LDO.py @@ -56,8 +56,6 @@ def can_bridge(self): @L.rt_field def simple_value_representation(self): - from faebryk.core.util import as_unit, as_unit_with_tolerance - return F.has_simple_value_representation_based_on_params( ( self.output_polarity, @@ -69,15 +67,22 @@ def simple_value_representation(self): self.max_input_voltage, self.quiescent_current, ), - lambda ps: "LDO " + lambda output_polarity, + output_type, + output_voltage, + output_current, + psrr, + dropout_voltage, + max_input_voltage, + quiescent_current: "LDO " + " ".join( [ - as_unit_with_tolerance(ps[2], "V"), - as_unit(ps[3], "A"), - as_unit(ps[4], "dB"), - as_unit(ps[5], "V"), - f"Vin max {as_unit(ps[6], 'V')}", - f"Iq {as_unit(ps[7], 'A')}", + output_voltage.as_unit_with_tolerance("V"), + output_current.as_unit("A"), + psrr.as_unit("dB"), + dropout_voltage.as_unit("V"), + f"Vin max {max_input_voltage.as_unit("V")}", + f"Iq {quiescent_current.as_unit("A")}", ] ), ) diff --git a/src/faebryk/library/OpAmp.py b/src/faebryk/library/OpAmp.py index 5dfef26d..06a060cb 100644 --- a/src/faebryk/library/OpAmp.py +++ b/src/faebryk/library/OpAmp.py @@ -23,10 +23,8 @@ class OpAmp(Module): @L.rt_field def simple_value_representation(self): - from faebryk.core.util import as_unit - return F.has_simple_value_representation_based_on_params( - [ + ( self.bandwidth, self.common_mode_rejection_ratio, self.input_bias_current, @@ -34,11 +32,23 @@ def simple_value_representation(self): self.gain_bandwidth_product, self.output_current, self.slew_rate, - ], - lambda p: ( - f"{as_unit(p[0], 'Hz')} BW, {p[1]} CMRR, {as_unit(p[2], 'A')} Ib, " - f"{as_unit(p[3], 'V')} Vos, {as_unit(p[4], 'Hz')} GBW, " - f"{as_unit(p[5], 'A')} Iout, {as_unit(p[6], 'V/s')} SR" + ), + lambda bandwidth, + common_mode_rejection_ratio, + input_bias_current, + input_offset_voltage, + gain_bandwidth_product, + output_current, + slew_rate: ", ".join( + [ + f"{bandwidth.as_unit("Hz")} BW", + f"{common_mode_rejection_ratio} CMRR", + f"{input_bias_current.as_unit("A")} Ib", + f"{input_offset_voltage.as_unit("V")} Vos", + f"{gain_bandwidth_product.as_unit("Hz")} GBW", + f"{output_current.as_unit("A")} Iout", + f"{slew_rate.as_unit("V/s")} SR", + ] ), ) diff --git a/src/faebryk/library/Range.py b/src/faebryk/library/Range.py index 37928733..26027715 100644 --- a/src/faebryk/library/Range.py +++ b/src/faebryk/library/Range.py @@ -5,6 +5,7 @@ from typing import Any, Protocol, Self from faebryk.core.parameter import Parameter +from faebryk.libs.units import UnitsContainer, to_si_str class _SupportsRangeOps(Protocol): @@ -18,7 +19,7 @@ def __ge__(self, __value) -> bool: ... class Range[PV: _SupportsRangeOps](Parameter[PV], Parameter[PV].SupportsSetOps): - type LIT_OR_PARAM = Parameter[PV].LIT_OR_PARAM + type LIT_OR_PARAM = Parameter.LIT_OR_PARAM class MinMaxError(Exception): ... @@ -73,14 +74,12 @@ def from_center_rel(cls, center: PV, factor: PV) -> "Range[PV]": @classmethod def _with_bound(cls, bound: LIT_OR_PARAM, other: float) -> "Range[PV]": - from faebryk.core.util import with_same_unit - try: - other = with_same_unit(other, bound) + other_with_unit = Parameter.with_same_unit(bound, other) except NotImplementedError: raise NotImplementedError("Specify zero/inf manually in params") - return cls(bound, other) + return cls(bound, other_with_unit) @classmethod def lower_bound(cls, lower: LIT_OR_PARAM) -> "Range[PV]": @@ -134,3 +133,28 @@ def try_compress(self) -> Parameter[PV]: def __contains__(self, other: LIT_OR_PARAM) -> bool: return self.min <= other and self.max >= other + + def _max(self): + return max(p.get_max() for p in self._get_narrowed_bounds()) + + def _as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str: + return ( + self.min.as_unit(unit, base=base) + + " - " + + self.max.as_unit(unit, base=base, required=True) + ) + + def _as_unit_with_tolerance( + self, unit: UnitsContainer, base: int, required: bool + ) -> str: + center, delta = self.as_center_tuple(relative=True) + delta_percent_str = f"±{to_si_str(delta.value, "%", 0)}" + return ( + f"{center.as_unit(unit, base=base, required=required)} {delta_percent_str}" + ) + + def _enum_parameter_representation(self, required: bool) -> str: + return ( + f"{self.min.enum_parameter_representation(required)} - " + f"{self.max.enum_parameter_representation(required)}" + ) diff --git a/src/faebryk/library/Resistor.py b/src/faebryk/library/Resistor.py index 8a2e059b..c1defc33 100644 --- a/src/faebryk/library/Resistor.py +++ b/src/faebryk/library/Resistor.py @@ -27,21 +27,16 @@ def can_bridge(self): @L.rt_field def simple_value_representation(self): - from faebryk.core.util import ( - as_unit, - as_unit_with_tolerance, - ) - return F.has_simple_value_representation_based_on_params( ( self.resistance, self.rated_power, ), - lambda ps: " ".join( - filter( - None, - [as_unit_with_tolerance(ps[0], "Ω"), as_unit(ps[1], "W")], - ) + lambda resistance, rated_power: " ".join( + [ + resistance.as_unit_with_tolerance("Ω"), + rated_power.as_unit("W"), + ], ), ) diff --git a/src/faebryk/library/Set.py b/src/faebryk/library/Set.py index 48b44966..112b5ece 100644 --- a/src/faebryk/library/Set.py +++ b/src/faebryk/library/Set.py @@ -5,6 +5,7 @@ import faebryk.library._F as F from faebryk.core.parameter import Parameter, _resolved +from faebryk.libs.units import UnitsContainer class Set[PV](Parameter[PV], Parameter[PV].SupportsSetOps): @@ -81,3 +82,31 @@ def try_compress(self) -> Parameter[PV]: if len(set(map(id, self.params))) == 1: return Parameter.from_literal(next(iter(self.params))) return super().try_compress() + + def _max(self): + return max(p.get_max() for p in self.params) + + def _as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str: + return ( + "Set(" + + ", ".join(x.as_unit(unit, required=True) for x in self.params) + + ")" + ) + + def _as_unit_with_tolerance( + self, unit: UnitsContainer, base: int, required: bool + ) -> str: + return ( + "Set(" + + ", ".join( + x.as_unit_with_tolerance(unit, base, required) for x in self.params + ) + + ")" + ) + + def _enum_parameter_representation(self, required: bool) -> str: + return ( + "Set(" + + ", ".join(p.enum_parameter_representation(required) for p in self.params) + + ")" + ) diff --git a/src/faebryk/library/TBD.py b/src/faebryk/library/TBD.py index 56139ffd..0f52ec82 100644 --- a/src/faebryk/library/TBD.py +++ b/src/faebryk/library/TBD.py @@ -4,6 +4,7 @@ from textwrap import indent from faebryk.core.parameter import Parameter +from faebryk.libs.units import UnitsContainer class TBD[PV](Parameter[PV]): @@ -29,3 +30,6 @@ def __repr__(self) -> str: out += or_ return out + + def _as_unit(self, unit: UnitsContainer, base: int, required: bool) -> str: + return "TBD" if required else "" diff --git a/src/faebryk/library/has_simple_value_representation_based_on_param.py b/src/faebryk/library/has_simple_value_representation_based_on_param.py deleted file mode 100644 index ffcb1829..00000000 --- a/src/faebryk/library/has_simple_value_representation_based_on_param.py +++ /dev/null @@ -1,26 +0,0 @@ -# This file is part of the faebryk project -# SPDX-License-Identifier: MIT - -from typing import Callable - -import faebryk.library._F as F -from faebryk.core.parameter import Parameter - - -class has_simple_value_representation_based_on_param( - F.has_simple_value_representation.impl() -): - def __init__( - self, param: Parameter, transformer: Callable[[F.Constant], str] - ) -> None: - super().__init__() - self.param = param - self.transformer = transformer - - def get_value(self) -> str: - param_const = self.param.get_most_narrow() - assert isinstance(param_const, F.Constant) - return self.transformer(param_const) - - def is_implemented(self): - return isinstance(self.param.get_most_narrow(), F.Constant) diff --git a/src/faebryk/library/has_simple_value_representation_based_on_params.py b/src/faebryk/library/has_simple_value_representation_based_on_params.py index 70fa30ab..31a2c255 100644 --- a/src/faebryk/library/has_simple_value_representation_based_on_params.py +++ b/src/faebryk/library/has_simple_value_representation_based_on_params.py @@ -1,7 +1,7 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT -from typing import Callable, Sequence +from typing import Callable import faebryk.library._F as F from faebryk.core.parameter import Parameter @@ -10,15 +10,16 @@ class has_simple_value_representation_based_on_params( F.has_simple_value_representation.impl() ): - def __init__( + def __init__[*P]( self, - params: Sequence[Parameter], - transformer: Callable[[Sequence[Parameter]], str], + params: tuple[*P], + transformer: Callable[[*P], str], ) -> None: super().__init__() self.transformer = transformer + assert all(isinstance(p, Parameter) for p in params) self.params = params def get_value(self) -> str: params_const = tuple(param.get_most_narrow() for param in self.params) - return self.transformer(params_const) + return self.transformer(*params_const) diff --git a/src/faebryk/libs/units.py b/src/faebryk/libs/units.py index 61fab54e..e4bf4c51 100644 --- a/src/faebryk/libs/units.py +++ b/src/faebryk/libs/units.py @@ -4,16 +4,17 @@ # re-exporting Quantity in-case we ever want to change it from pint import Quantity as _Quantity # noqa: F401 from pint import UndefinedUnitError, Unit, UnitRegistry # noqa: F401 -from pint.util import UnitsContainer # noqa: F401 +from pint.util import UnitsContainer as _UnitsContainer P = UnitRegistry() +UnitsContainer = _UnitsContainer | str Quantity = P.Quantity def to_si_str( value: Quantity | float | int, - unit: str | UnitsContainer, + unit: UnitsContainer, num_decimals: int = 2, ) -> str: """ diff --git a/test/core/test_performance.py b/test/core/test_performance.py index 2564a5c0..a34cc744 100644 --- a/test/core/test_performance.py +++ b/test/core/test_performance.py @@ -103,7 +103,7 @@ def _common_timings( n.get_tree(types=Node) timings.add(f"get_node_tree {name}") - core_util.get_mif_tree(n) + n.get_tree(types=ModuleInterface) timings.add(f"get_mif_tree {name}") n.get_children(direct_only=True, types=Node)