diff --git a/src/faebryk/core/parameter.py b/src/faebryk/core/parameter.py index e1b51300..606ca950 100644 --- a/src/faebryk/core/parameter.py +++ b/src/faebryk/core/parameter.py @@ -13,11 +13,21 @@ from faebryk.core.trait import Trait from faebryk.libs.sets import P_Set, Range, Ranges from faebryk.libs.units import HasUnit, Quantity, Unit, dimensionless -from faebryk.libs.util import abstract, cast_assert, find +from faebryk.libs.util import KeyErrorNotFound, abstract, cast_assert, find logger = logging.getLogger(__name__) +class ParameterOperableException(Exception): + def __init__(self, parameter: "ParameterOperatable", msg: str): + self.parameter = parameter + super().__init__(msg) + + +class ParameterOperableHasNoLiteral(ParameterOperableException): + pass + + # When we make this generic, two types, type T of elements, and type S of known subsets # boolean: T == S == bool # enum: T == S == Enum @@ -374,7 +384,12 @@ def get_operators[T: "Expression"](self, types: type[T] | None = None) -> list[T def get_literal(self) -> Literal: iss = self.get_operators(Is) - literal_is = find(o for i in iss for o in i.get_literal_operands()) + try: + literal_is = find(o for i in iss for o in i.get_literal_operands()) + except KeyErrorNotFound: + raise ParameterOperableHasNoLiteral( + self, f"Parameter {self} has no literal" + ) return literal_is diff --git a/src/faebryk/library/has_simple_value_representation_based_on_params_chain.py b/src/faebryk/library/has_simple_value_representation_based_on_params_chain.py index 67ec9de3..3c84cd5f 100644 --- a/src/faebryk/library/has_simple_value_representation_based_on_params_chain.py +++ b/src/faebryk/library/has_simple_value_representation_based_on_params_chain.py @@ -4,10 +4,16 @@ from dataclasses import dataclass import faebryk.library._F as F -from faebryk.core.parameter import Boolean, EnumDomain, Numbers, Parameter +from faebryk.core.parameter import ( + Boolean, + EnumDomain, + Numbers, + Parameter, + ParameterOperableHasNoLiteral, +) from faebryk.libs.sets import P_Set, Range from faebryk.libs.units import Quantity, Unit, to_si_str -from faebryk.libs.util import KeyErrorNotFound, join_if_non_empty +from faebryk.libs.util import join_if_non_empty class has_simple_value_representation_based_on_params_chain( @@ -32,7 +38,7 @@ class Spec: def _get_value(self) -> str: try: value = self.param.get_literal() - except KeyErrorNotFound: + except ParameterOperableHasNoLiteral: if self.default is not None: return self.default raise diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index 105ac7f4..e05c55d5 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -4,7 +4,7 @@ import faebryk.library._F as F from faebryk.core.module import Module -from faebryk.core.parameter import Parameter +from faebryk.core.parameter import EnumDomain, Parameter, ParameterOperableHasNoLiteral from faebryk.core.solver import Solver from faebryk.libs.e_series import E_SERIES_VALUES from faebryk.libs.library import L @@ -17,7 +17,8 @@ DescriptiveProperties, PickError, ) -from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound, cast_assert +from faebryk.libs.sets import P_Set +from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound logger = logging.getLogger(__name__) @@ -50,24 +51,22 @@ def f(x: str) -> L.PlainSet[T]: def enum_to_str(x: Parameter, force: bool = True) -> set[str]: - # FIXME - raise NotImplementedError() - val = x.get_most_narrow() - if isinstance(val, F.Constant): - val = F.Set([val]) - - if not isinstance(val, F.Set) or not all( - isinstance(inner, F.Constant) for inner in val.params - ): + assert isinstance(x.domain, EnumDomain) + try: + val = x.get_literal() + except ParameterOperableHasNoLiteral: if force: - raise ValueError(f"Expected a constant or set of constants, got {val}") - else: - return set() + raise + return set() + + if isinstance(val, x.domain.enum_t): + return {val.value} + + if isinstance(val, P_Set): + # TODO handle sets + raise NotImplementedError() - return { - cast_assert(Enum, cast_assert(F.Constant, inner).value).name - for inner in val.params - } + raise ValueError(f"Expected an enum, got {val}") _MAPPINGS_BY_TYPE: dict[type[Module], list[MappingParameterDB]] = { @@ -501,8 +500,7 @@ def find_led(cmp: Module, solver: Solver): .filter_by_stock(qty) .filter_by_traits(cmp) .filter_by_specified_parameters(mapping) - # TODO - # .filter_by_attribute_mention(list(enum_to_str(cmp.color, force=False))) + .filter_by_attribute_mention(list(enum_to_str(cmp.color, force=False))) .sort_by_price(qty) .filter_by_module_params_and_attach(cmp, mapping, solver, qty) )