diff --git a/src/faebryk/core/graph.py b/src/faebryk/core/graph.py index a22e28ec..1dff6c16 100644 --- a/src/faebryk/core/graph.py +++ b/src/faebryk/core/graph.py @@ -20,7 +20,7 @@ # only for typechecker if TYPE_CHECKING: - from faebryk.core.core import Link + from faebryk.core.link import Link # TODO create GraphView base class diff --git a/src/faebryk/core/graph_backends/graphgt.py b/src/faebryk/core/graph_backends/graphgt.py index a1701f02..d8f25bc8 100644 --- a/src/faebryk/core/graph_backends/graphgt.py +++ b/src/faebryk/core/graph_backends/graphgt.py @@ -15,7 +15,7 @@ # only for typechecker if TYPE_CHECKING: - from faebryk.core.core import Link + from faebryk.core.link import Link class GraphGT[T](Graph[T, gt.Graph]): diff --git a/src/faebryk/core/graph_backends/graphnx.py b/src/faebryk/core/graph_backends/graphnx.py index 440cb674..ea22051f 100644 --- a/src/faebryk/core/graph_backends/graphnx.py +++ b/src/faebryk/core/graph_backends/graphnx.py @@ -13,7 +13,7 @@ # only for typechecker if TYPE_CHECKING: - from faebryk.core.core import Link + from faebryk.core.link import Link class GraphNX[T](Graph[T, nx.Graph]): diff --git a/src/faebryk/core/graph_backends/graphpy.py b/src/faebryk/core/graph_backends/graphpy.py index 1f382b17..40f95ef1 100644 --- a/src/faebryk/core/graph_backends/graphpy.py +++ b/src/faebryk/core/graph_backends/graphpy.py @@ -12,7 +12,7 @@ # only for typechecker if TYPE_CHECKING: - from faebryk.core.core import Link + from faebryk.core.link import Link type L = "Link" diff --git a/src/faebryk/core/node.py b/src/faebryk/core/node.py index 90ba40d1..eefd3317 100644 --- a/src/faebryk/core/node.py +++ b/src/faebryk/core/node.py @@ -104,6 +104,16 @@ def __init__(self, node: "Node", *args: object) -> None: self.node = node +class NodeAlreadyBound(NodeException): + def __init__(self, node: "Node", other: "Node", *args: object) -> None: + super().__init__( + node, + *args, + f"Node {other} already bound to" + f" {other.get_parent()}, can't bind to {node}", + ) + + class Node(FaebrykLibObject, metaclass=PostInitCaller): runtime_anon: list["Node"] runtime: dict[str, "Node"] @@ -369,17 +379,17 @@ def _handle_add_gif(self, name: str, gif: GraphInterface): gif.connect(self.self_gif, linkcls=LinkSibling) def _handle_add_node(self, name: str, node: "Node"): - assert not ( - other_p := node.get_parent() - ), f"{node} already has parent: {other_p}" + if node.get_parent(): + raise NodeAlreadyBound(self, node) from faebryk.core.trait import TraitImpl if isinstance(node, TraitImpl): if self.has_trait(node._trait): - node.handle_duplicate( + if not node.handle_duplicate( cast_assert(TraitImpl, self.get_trait(node._trait)), self - ) + ): + return node.parent.connect(self.children, LinkNamedParent.curry(name)) node._handle_added_to_parent() diff --git a/src/faebryk/core/trait.py b/src/faebryk/core/trait.py index 3a473cf2..0a727212 100644 --- a/src/faebryk/core/trait.py +++ b/src/faebryk/core/trait.py @@ -28,6 +28,11 @@ def __init__(self, node: Node, trait: "TraitImpl", *args: object) -> None: self.trait = trait +class TraitUnbound(NodeException): + def __init__(self, node: Node, *args: object) -> None: + super().__init__(node, *args, f"Trait {node} is not bound to a node") + + class Trait(Node): @classmethod def impl[T: "Trait"](cls: type[T]): @@ -64,7 +69,7 @@ def __preinit__(self) -> None: def obj(self) -> Node: p = self.get_parent() if not p: - raise Exception("trait is not linked to node") + raise TraitUnbound(self) return p[0] def get_obj[T: Node](self, type: type[T]) -> T: @@ -95,9 +100,16 @@ def _handle_added_to_parent(self): def on_obj_set(self): ... - def handle_duplicate(self, other: "TraitImpl", node: Node): + def handle_duplicate(self, other: "TraitImpl", node: Node) -> bool: assert other is not self - raise TraitAlreadyExists(node, self) + _, candidate = other.cmp(self) + if candidate is not self: + return False + + node.del_trait(other._trait) + return True + + # raise TraitAlreadyExists(node, self) # override this to implement a dynamic trait def is_implemented(self): diff --git a/test/core/test_core.py b/test/core/test_core.py index 567094af..7f497ae1 100644 --- a/test/core/test_core.py +++ b/test/core/test_core.py @@ -6,8 +6,14 @@ from typing import cast from faebryk.core.link import LinkDirect, LinkParent, LinkSibling -from faebryk.core.node import Node -from faebryk.core.trait import Trait, TraitImpl +from faebryk.core.node import Node, NodeAlreadyBound +from faebryk.core.trait import ( + Trait, + TraitAlreadyExists, + TraitImpl, + TraitNotFound, + TraitUnbound, +) class TestTraits(unittest.TestCase): @@ -111,7 +117,7 @@ class impl2(trait2.impl()): # Test failure on getting non existent self.assertFalse(obj.has_trait(trait1)) - self.assertRaises(AssertionError, lambda: obj.get_trait(trait1)) + self.assertRaises(TraitNotFound, lambda: obj.get_trait(trait1)) trait1_inst = trait1impl() cfgtrait1_inst = cfgtrait1(5) @@ -124,7 +130,7 @@ class impl2(trait2.impl()): self.assertEqual(trait1_inst.do(), obj.get_trait(trait1).do()) # Test double add - self.assertRaises(AssertionError, lambda: obj.add_trait(trait1_inst)) + self.assertRaises(NodeAlreadyBound, lambda: obj.add_trait(trait1_inst)) # Test replace obj.add_trait(cfgtrait1_inst) @@ -140,12 +146,12 @@ class impl2(trait2.impl()): self.assertFalse(obj.has_trait(trait1)) # Test get obj - self.assertRaises(AssertionError, lambda: trait1_inst.obj) + self.assertRaises(TraitUnbound, lambda: trait1_inst.obj) obj.add_trait(trait1_inst) _impl: TraitImpl = cast(TraitImpl, obj.get_trait(trait1)) self.assertEqual(_impl.obj, obj) obj.del_trait(trait1) - self.assertRaises(AssertionError, lambda: trait1_inst.obj) + self.assertRaises(TraitUnbound, lambda: trait1_inst.obj) # Test specific override obj.add_trait(impl2_inst) diff --git a/test/core/test_hierarchy_connect.py b/test/core/test_hierarchy_connect.py index d03d220a..ffec1f04 100644 --- a/test/core/test_hierarchy_connect.py +++ b/test/core/test_hierarchy_connect.py @@ -5,14 +5,10 @@ import unittest from itertools import chain -from faebryk.core.core import ( - LinkDirect, - LinkDirectShallow, - Module, - ModuleInterface, - _TLinkDirectShallow, -) from faebryk.core.core import logger as core_logger +from faebryk.core.link import LinkDirect, LinkDirectShallow, _TLinkDirectShallow +from faebryk.core.module import Module +from faebryk.core.moduleinterface import ModuleInterface from faebryk.core.util import specialize_interface from faebryk.library.Electrical import Electrical from faebryk.library.ElectricLogic import ElectricLogic @@ -38,18 +34,18 @@ class _IFs(super().IFS()): self.IFs = _IFs(self) - bus_in = self.IFs.bus_in - bus_out = self.IFs.bus_out + bus_in = self.bus_in + bus_out = self.bus_out - bus_in.IFs.rx.IFs.signal.connect(bus_out.IFs.rx.IFs.signal) - bus_in.IFs.tx.IFs.signal.connect(bus_out.IFs.tx.IFs.signal) - bus_in.IFs.rx.IFs.reference.connect(bus_out.IFs.rx.IFs.reference) + bus_in.rx.signal.connect(bus_out.rx.signal) + bus_in.tx.signal.connect(bus_out.tx.signal) + bus_in.rx.reference.connect(bus_out.rx.reference) app = UARTBuffer() - self.assertTrue(app.IFs.bus_in.IFs.rx.is_connected_to(app.IFs.bus_out.IFs.rx)) - self.assertTrue(app.IFs.bus_in.IFs.tx.is_connected_to(app.IFs.bus_out.IFs.tx)) - self.assertTrue(app.IFs.bus_in.is_connected_to(app.IFs.bus_out)) + self.assertTrue(app.bus_in.rx.is_connected_to(app.bus_out.rx)) + self.assertTrue(app.bus_in.tx.is_connected_to(app.bus_out.tx)) + self.assertTrue(app.bus_in.is_connected_to(app.bus_out)) def test_chains(self): mifs = times(3, ModuleInterface) @@ -76,16 +72,16 @@ def test_chains(self): self.assertTrue(mifs[0].is_connected_to(mifs[2])) self.assertIsInstance(mifs[0].is_connected_to(mifs[2]), _TLinkDirectShallow) - self.assertTrue(mifs[1].IFs.signal.is_connected_to(mifs[2].IFs.signal)) - self.assertTrue(mifs[1].IFs.reference.is_connected_to(mifs[2].IFs.reference)) - self.assertFalse(mifs[0].IFs.signal.is_connected_to(mifs[1].IFs.signal)) - self.assertFalse(mifs[0].IFs.reference.is_connected_to(mifs[1].IFs.reference)) - self.assertFalse(mifs[0].IFs.signal.is_connected_to(mifs[2].IFs.signal)) - self.assertFalse(mifs[0].IFs.reference.is_connected_to(mifs[2].IFs.reference)) + self.assertTrue(mifs[1].signal.is_connected_to(mifs[2].signal)) + self.assertTrue(mifs[1].reference.is_connected_to(mifs[2].reference)) + self.assertFalse(mifs[0].signal.is_connected_to(mifs[1].signal)) + self.assertFalse(mifs[0].reference.is_connected_to(mifs[1].reference)) + self.assertFalse(mifs[0].signal.is_connected_to(mifs[2].signal)) + self.assertFalse(mifs[0].reference.is_connected_to(mifs[2].reference)) # Test duplicate resolution - mifs[0].IFs.signal.connect(mifs[1].IFs.signal) - mifs[0].IFs.reference.connect(mifs[1].IFs.reference) + mifs[0].signal.connect(mifs[1].signal) + mifs[0].reference.connect(mifs[1].reference) self.assertIsInstance(mifs[0].is_connected_to(mifs[1]), LinkDirect) self.assertIsInstance(mifs[0].is_connected_to(mifs[2]), LinkDirect) @@ -107,12 +103,12 @@ class _IFs(super().IFS()): self.add_trait(has_single_electric_reference_defined(ref)) for el, lo in chain( - zip(self.IFs.ins, self.IFs.ins_l), - zip(self.IFs.outs, self.IFs.outs_l), + zip(self.ins, self.ins_l), + zip(self.outs, self.outs_l), ): - lo.IFs.signal.connect(el) + lo.signal.connect(el) - for l1, l2 in zip(self.IFs.ins_l, self.IFs.outs_l): + for l1, l2 in zip(self.ins_l, self.outs_l): l1.connect_shallow(l2) class UARTBuffer(Module): @@ -131,14 +127,14 @@ class _IFs(super().IFS()): ElectricLogic.connect_all_module_references(self) - bus1 = self.IFs.bus_in - bus2 = self.IFs.bus_out - buf = self.NODEs.buf + bus1 = self.bus_in + bus2 = self.bus_out + buf = self.buf - bus1.IFs.tx.IFs.signal.connect(buf.IFs.ins[0]) - bus1.IFs.rx.IFs.signal.connect(buf.IFs.ins[1]) - bus2.IFs.tx.IFs.signal.connect(buf.IFs.outs[0]) - bus2.IFs.rx.IFs.signal.connect(buf.IFs.outs[1]) + bus1.tx.signal.connect(buf.ins[0]) + bus1.rx.signal.connect(buf.ins[1]) + bus2.tx.signal.connect(buf.outs[0]) + bus2.rx.signal.connect(buf.outs[1]) import faebryk.core.core as c @@ -153,19 +149,19 @@ def _assert_no_link(mif1, mif2): err = "\n" + print_stack(link.tb) self.assertFalse(link, err) - bus1 = app.IFs.bus_in - bus2 = app.IFs.bus_out - buf = app.NODEs.buf + bus1 = app.bus_in + bus2 = app.bus_out + buf = app.buf # Check that the two buffer sides are not connected electrically - _assert_no_link(buf.IFs.ins[0], buf.IFs.outs[0]) - _assert_no_link(buf.IFs.ins[1], buf.IFs.outs[1]) - _assert_no_link(bus1.IFs.rx.IFs.signal, bus2.IFs.rx.IFs.signal) - _assert_no_link(bus1.IFs.tx.IFs.signal, bus2.IFs.tx.IFs.signal) + _assert_no_link(buf.ins[0], buf.outs[0]) + _assert_no_link(buf.ins[1], buf.outs[1]) + _assert_no_link(bus1.rx.signal, bus2.rx.signal) + _assert_no_link(bus1.tx.signal, bus2.tx.signal) # Check that the two buffer sides are connected logically - self.assertTrue(bus1.IFs.rx.is_connected_to(bus2.IFs.rx)) - self.assertTrue(bus1.IFs.tx.is_connected_to(bus2.IFs.tx)) + self.assertTrue(bus1.rx.is_connected_to(bus2.rx)) + self.assertTrue(bus1.tx.is_connected_to(bus2.tx)) self.assertTrue(bus1.is_connected_to(bus2)) def test_specialize(self): diff --git a/test/core/test_parameters.py b/test/core/test_parameters.py index 8c1c2977..688fcade 100644 --- a/test/core/test_parameters.py +++ b/test/core/test_parameters.py @@ -7,7 +7,8 @@ from typing import TypeVar from faebryk.core.core import logger as core_logger -from faebryk.core.module import Module, Parameter +from faebryk.core.module import Module +from faebryk.core.parameter import Parameter from faebryk.core.util import specialize_module from faebryk.library.ANY import ANY from faebryk.library.Constant import Constant @@ -271,26 +272,26 @@ class NODES(super().NODES()): m = Modules() - UART_A = m.NODEs.UART_A - UART_B = m.NODEs.UART_B - UART_C = m.NODEs.UART_C + UART_A = m.UART_A + UART_B = m.UART_B + UART_C = m.UART_C UART_A.connect(UART_B) - UART_A.PARAMs.baud.merge(Constant(9600 * P.baud)) + UART_A.baud.merge(Constant(9600 * P.baud)) for uart in [UART_A, UART_B]: self.assertEqual( - assertIsInstance(uart.PARAMs.baud.get_most_narrow(), Constant).value, + assertIsInstance(uart.baud.get_most_narrow(), Constant).value, 9600 * P.baud, ) - UART_C.PARAMs.baud.merge(Range(1200 * P.baud, 115200 * P.baud)) + UART_C.baud.merge(Range(1200 * P.baud, 115200 * P.baud)) UART_A.connect(UART_C) for uart in [UART_A, UART_B, UART_C]: self.assertEqual( - assertIsInstance(uart.PARAMs.baud.get_most_narrow(), Constant).value, + assertIsInstance(uart.baud.get_most_narrow(), Constant).value, 9600 * P.baud, ) @@ -343,34 +344,34 @@ class _NODES(Module.NODES()): self.NODEs = _NODES(self) - self.NODEs.led.IFs.power.connect(self.NODEs.battery.IFs.power) + self.led.power.connect(self.battery.power) # Parametrize - self.NODEs.led.NODEs.led.PARAMs.color.merge(F.LED.Color.YELLOW) - self.NODEs.led.NODEs.led.PARAMs.brightness.merge( + self.led.led.color.merge(F.LED.Color.YELLOW) + self.led.led.brightness.merge( TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value ) app = App() - bcell = specialize_module(app.NODEs.battery, F.ButtonCell()) - bcell.PARAMs.voltage.merge(3 * P.V) - bcell.PARAMs.capacity.merge(Range.from_center(225 * P.mAh, 50 * P.mAh)) - bcell.PARAMs.material.merge(F.ButtonCell.Material.Lithium) - bcell.PARAMs.size.merge(F.ButtonCell.Size.N_2032) - bcell.PARAMs.shape.merge(F.ButtonCell.Shape.Round) + bcell = specialize_module(app.battery, F.ButtonCell()) + bcell.voltage.merge(3 * P.V) + bcell.capacity.merge(Range.from_center(225 * P.mAh, 50 * P.mAh)) + bcell.material.merge(F.ButtonCell.Material.Lithium) + bcell.size.merge(F.ButtonCell.Size.N_2032) + bcell.shape.merge(F.ButtonCell.Shape.Round) - app.NODEs.led.NODEs.led.PARAMs.color.merge(F.LED.Color.YELLOW) - app.NODEs.led.NODEs.led.PARAMs.max_brightness.merge(500 * P.millicandela) - app.NODEs.led.NODEs.led.PARAMs.forward_voltage.merge(1.2 * P.V) - app.NODEs.led.NODEs.led.PARAMs.max_current.merge(20 * P.mA) + app.led.led.color.merge(F.LED.Color.YELLOW) + app.led.led.max_brightness.merge(500 * P.millicandela) + app.led.led.forward_voltage.merge(1.2 * P.V) + app.led.led.max_current.merge(20 * P.mA) - v = app.NODEs.battery.PARAMs.voltage - # vbcell = bcell.PARAMs.voltage + v = app.battery.voltage + # vbcell = bcell.voltage # print(pretty_param_tree_top(v)) # print(pretty_param_tree_top(vbcell)) self.assertEqual(v.get_most_narrow(), 3 * P.V) - r = app.NODEs.led.NODEs.current_limiting_resistor.PARAMs.resistance + r = app.led.current_limiting_resistor.resistance r = r.get_most_narrow() self.assertIsInstance(r, Range, f"{type(r)}") diff --git a/test/core/test_performance.py b/test/core/test_performance.py index 74ac8b3a..6f1e6a59 100644 --- a/test/core/test_performance.py +++ b/test/core/test_performance.py @@ -8,7 +8,9 @@ from typing import Callable import faebryk.core.util as core_util -from faebryk.core.graphinterface import GraphInterface, Module, ModuleInterface +from faebryk.core.graphinterface import GraphInterface +from faebryk.core.module import Module +from faebryk.core.moduleinterface import ModuleInterface from faebryk.library.Resistor import Resistor from faebryk.libs.util import times @@ -71,7 +73,7 @@ class NODES(super().NODES()): timings.add("set NODES") core_util.connect_all_interfaces( - r.IFs.unnamed[0] for r in self.NODEs.resistors + r.unnamed[0] for r in self.resistors ) timings.add("connect") @@ -95,7 +97,7 @@ def _common_timings( core_util.node_projected_graph(G) timings.add("get_all_nodes_graph") - for n in [app, app.NODEs.resistors[0]]: + for n in [app, app.resistors[0]]: name = type(n).__name__[0] core_util.get_node_children_all(n) diff --git a/test/core/test_util.py b/test/core/test_util.py index 79e17192..640eeadc 100644 --- a/test/core/test_util.py +++ b/test/core/test_util.py @@ -5,8 +5,11 @@ from enum import StrEnum from typing import Iterable -from faebryk.core.module import Module, ModuleInterface, Node, Parameter -from faebryk.core.util import get_children, get_node_tree, iter_tree_by_depth +from faebryk.core.module import Module +from faebryk.core.moduleinterface import ModuleInterface +from faebryk.core.node import Node +from faebryk.core.parameter import Parameter +from faebryk.core.util import get_node_tree, iter_tree_by_depth class TestUtil(unittest.TestCase): @@ -45,9 +48,9 @@ def assertEqual(n1: list[Node], n2: list[Node]): assertEqual(levels[0], [n]) n_i = n for i in range(1, level_count + 1): - assertEqual(levels[i], [n_i.NODEs.n, n_i.IFs.mif]) - n_i = n_i.NODEs.n - assertEqual(levels[level_count + 1], [n_i.IFs.mif]) + assertEqual(levels[i], [n_i.n, n_i.mif]) + n_i = n_i.n + assertEqual(levels[level_count + 1], [n_i.mif]) def test_children(self): # TODO this is a really annoying to debug test @@ -152,28 +155,28 @@ def visit_tree(t, keys=None, typ=EN): mod = moduleFromTree(tree, EN)() - direct_children_top = get_children(mod, direct_only=True, types=Module) + direct_children_top = mod.get_children(direct_only=True, types=Module) assertEqual(direct_children_top, tree[EN]) - direct_children_top_all_types = get_children(mod, direct_only=True) + direct_children_top_all_types = mod.get_children(direct_only=True, types=Node) assertEqual(direct_children_top_all_types, tree[EN] + tree[EI] + tree[EP]) - all_children_top = get_children(mod, direct_only=False, include_root=True) + all_children_top = mod.get_children( + direct_only=False, include_root=True, types=Node + ) assertEqual(all_children_top, list(visit_tree(tree))) - all_children_top_typed = get_children( - mod, direct_only=False, types=Module, include_root=True + all_children_top_typed = mod.get_children( + direct_only=False, types=Module, include_root=True ) assertEqual(all_children_top_typed, list(visit_tree(tree, [EN]))) - direct_children_middle = get_children(mod.NODEs.i0, direct_only=True) + direct_children_middle = mod.i0.get_children(direct_only=True) assertEqual( direct_children_middle, tree[EN][0][EN] + tree[EN][0][EI] + tree[EN][0][EP] ) - all_children_middle = get_children( - mod.NODEs.i0, direct_only=False, include_root=True - ) + all_children_middle = mod.i0.get_children(direct_only=False, include_root=True) assertEqual( all_children_middle, list(visit_tree(tree[EN][0])), diff --git a/test/exporters/netlist/kicad/test_netlist_kicad.py b/test/exporters/netlist/kicad/test_netlist_kicad.py index 61811df5..1fb260d7 100644 --- a/test/exporters/netlist/kicad/test_netlist_kicad.py +++ b/test/exporters/netlist/kicad/test_netlist_kicad.py @@ -25,21 +25,21 @@ def _test_netlist_graph(): from faebryk.library.Resistor import Resistor from faebryk.library.SMDTwoPin import SMDTwoPin - resistor1 = Resistor().builder(lambda r: r.PARAMs.resistance.merge(100)) - resistor2 = Resistor().builder(lambda r: r.PARAMs.resistance.merge(200)) + resistor1 = Resistor().builder(lambda r: r.resistance.merge(100)) + resistor2 = Resistor().builder(lambda r: r.resistance.merge(200)) power = ElectricPower() # net labels vcc = Net.with_name("+3V3") gnd = Net.with_name("GND") - power.IFs.hv.connect(vcc.IFs.part_of) - power.IFs.lv.connect(gnd.IFs.part_of) + power.hv.connect(vcc.part_of) + power.lv.connect(gnd.part_of) # connect - resistor1.IFs.unnamed[0].connect(power.IFs.hv) - resistor1.IFs.unnamed[1].connect(power.IFs.lv) - resistor2.IFs.unnamed[0].connect(resistor1.IFs.unnamed[0]) - resistor2.IFs.unnamed[1].connect(resistor1.IFs.unnamed[1]) + resistor1.unnamed[0].connect(power.hv) + resistor1.unnamed[1].connect(power.lv) + resistor2.unnamed[0].connect(resistor1.unnamed[0]) + resistor2.unnamed[1].connect(resistor1.unnamed[1]) # attach footprint & designator for i, r in enumerate([resistor1, resistor2]): diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index ae03dc22..10ab7aaf 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -9,7 +9,6 @@ import faebryk.libs.picker.lcsc as lcsc from faebryk.core.module import Module from faebryk.core.parameter import Parameter -from faebryk.core.util import get_children from faebryk.libs.logging import setup_basic_logging from faebryk.libs.picker.jlcpcb.jlcpcb import JLCPCB_DB from faebryk.libs.picker.jlcpcb.pickers import add_jlcpcb_pickers @@ -94,8 +93,8 @@ def satisfies_requirements(self): ) for req, res in zip( - get_children(self.requirement, direct_only=True, types=Parameter), - get_children(self.result, direct_only=True, types=Parameter), + self.requirement.get_children(direct_only=True, types=Parameter), + self.result.get_children(direct_only=True, types=Parameter), ): req = req.get_most_narrow() res = res.get_most_narrow() @@ -160,17 +159,15 @@ def test(self): def test_find_manufacturer_partnumber(self): requirement = F.OpAmp().builder( lambda r: ( - r.PARAMs.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.PARAMs.common_mode_rejection_ratio.merge( + r.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.common_mode_rejection_ratio.merge( F.Range.lower_bound(Quantity(50, P.dB)) ), - r.PARAMs.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), - r.PARAMs.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), - r.PARAMs.gain_bandwidth_product.merge( - F.Range.upper_bound(1 * P.Mhertz) - ), - r.PARAMs.output_current.merge(F.Range.upper_bound(1 * P.mA)), - r.PARAMs.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), + r.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), + r.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), + r.gain_bandwidth_product.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.output_current.merge(F.Range.upper_bound(1 * P.mA)), + r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), ) ) requirement.add_trait( @@ -190,17 +187,15 @@ def test_find_manufacturer_partnumber(self): def test_find_lcsc_partnumber(self): requirement = F.OpAmp().builder( lambda r: ( - r.PARAMs.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.PARAMs.common_mode_rejection_ratio.merge( + r.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.common_mode_rejection_ratio.merge( F.Range.lower_bound(Quantity(50, P.dB)) ), - r.PARAMs.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), - r.PARAMs.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), - r.PARAMs.gain_bandwidth_product.merge( - F.Range.upper_bound(1 * P.Mhertz) - ), - r.PARAMs.output_current.merge(F.Range.upper_bound(1 * P.mA)), - r.PARAMs.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), + r.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), + r.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), + r.gain_bandwidth_product.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.output_current.merge(F.Range.upper_bound(1 * P.mA)), + r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), ) ) requirement.add_trait( @@ -221,11 +216,9 @@ def test_find_resistor(self): self, requirement=F.Resistor().builder( lambda r: ( - r.PARAMs.resistance.merge( - F.Range.from_center(10 * P.kohm, 1 * P.kohm) - ), - r.PARAMs.rated_power.merge(F.Range.lower_bound(0.05 * P.W)), - r.PARAMs.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), + r.resistance.merge(F.Range.from_center(10 * P.kohm, 1 * P.kohm)), + r.rated_power.merge(F.Range.lower_bound(0.05 * P.W)), + r.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), ) ), footprint=[("0402", 2)], @@ -235,11 +228,9 @@ def test_find_resistor(self): self, requirement=F.Resistor().builder( lambda r: ( - r.PARAMs.resistance.merge( - F.Range.from_center(69 * P.kohm, 2 * P.kohm) - ), - r.PARAMs.rated_power.merge(F.Range.lower_bound(0.1 * P.W)), - r.PARAMs.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), + r.resistance.merge(F.Range.from_center(69 * P.kohm, 2 * P.kohm)), + r.rated_power.merge(F.Range.lower_bound(0.1 * P.W)), + r.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), ) ), footprint=[("0603", 2)], @@ -250,11 +241,9 @@ def test_find_capacitor(self): self, requirement=F.Capacitor().builder( lambda c: ( - c.PARAMs.capacitance.merge( - F.Range.from_center(100 * P.nF, 10 * P.nF) - ), - c.PARAMs.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), - c.PARAMs.temperature_coefficient.merge( + c.capacitance.merge(F.Range.from_center(100 * P.nF, 10 * P.nF)), + c.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), + c.temperature_coefficient.merge( F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.X7R) ), ) @@ -266,11 +255,9 @@ def test_find_capacitor(self): self, requirement=F.Capacitor().builder( lambda c: ( - c.PARAMs.capacitance.merge( - F.Range.from_center(47 * P.pF, 4.7 * P.pF) - ), - c.PARAMs.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), - c.PARAMs.temperature_coefficient.merge( + c.capacitance.merge(F.Range.from_center(47 * P.pF, 4.7 * P.pF)), + c.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), + c.temperature_coefficient.merge( F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.C0G) ), ) @@ -283,12 +270,10 @@ def test_find_inductor(self): self, requirement=F.Inductor().builder( lambda i: ( - i.PARAMs.inductance.merge( - F.Range.from_center(4.7 * P.nH, 0.47 * P.nH) - ), - i.PARAMs.rated_current.merge(F.Range.lower_bound(0.01 * P.A)), - i.PARAMs.dc_resistance.merge(F.Range.upper_bound(1 * P.ohm)), - i.PARAMs.self_resonant_frequency.merge( + i.inductance.merge(F.Range.from_center(4.7 * P.nH, 0.47 * P.nH)), + i.rated_current.merge(F.Range.lower_bound(0.01 * P.A)), + i.dc_resistance.merge(F.Range.upper_bound(1 * P.ohm)), + i.self_resonant_frequency.merge( F.Range.lower_bound(100 * P.Mhertz) ), ) @@ -301,22 +286,14 @@ def test_find_mosfet(self): self, requirement=F.MOSFET().builder( lambda m: ( - m.PARAMs.channel_type.merge( - F.Constant(F.MOSFET.ChannelType.N_CHANNEL) - ), - m.PARAMs.saturation_type.merge( + m.channel_type.merge(F.Constant(F.MOSFET.ChannelType.N_CHANNEL)), + m.saturation_type.merge( F.Constant(F.MOSFET.SaturationType.ENHANCEMENT) ), - m.PARAMs.gate_source_threshold_voltage.merge( - F.Range(0.4 * P.V, 3 * P.V) - ), - m.PARAMs.max_drain_source_voltage.merge( - F.Range.lower_bound(20 * P.V) - ), - m.PARAMs.max_continuous_drain_current.merge( - F.Range.lower_bound(2 * P.A) - ), - m.PARAMs.on_resistance.merge(F.Range.upper_bound(0.1 * P.ohm)), + m.gate_source_threshold_voltage.merge(F.Range(0.4 * P.V, 3 * P.V)), + m.max_drain_source_voltage.merge(F.Range.lower_bound(20 * P.V)), + m.max_continuous_drain_current.merge(F.Range.lower_bound(2 * P.A)), + m.on_resistance.merge(F.Range.upper_bound(0.1 * P.ohm)), ) ), footprint=[("SOT-23", 3)], @@ -327,15 +304,11 @@ def test_find_diode(self): self, requirement=F.Diode().builder( lambda d: ( - d.PARAMs.current.merge(F.Range.lower_bound(1 * P.A)), - d.PARAMs.forward_voltage.merge(F.Range.upper_bound(1.7 * P.V)), - d.PARAMs.reverse_working_voltage.merge( - F.Range.lower_bound(20 * P.V) - ), - d.PARAMs.reverse_leakage_current.merge( - F.Range.upper_bound(100 * P.uA) - ), - d.PARAMs.max_current.merge(F.Range.lower_bound(1 * P.A)), + d.current.merge(F.Range.lower_bound(1 * P.A)), + d.forward_voltage.merge(F.Range.upper_bound(1.7 * P.V)), + d.reverse_working_voltage.merge(F.Range.lower_bound(20 * P.V)), + d.reverse_leakage_current.merge(F.Range.upper_bound(100 * P.uA)), + d.max_current.merge(F.Range.lower_bound(1 * P.A)), ) ), footprint=[("SOD-123", 2)], @@ -348,16 +321,12 @@ def test_find_tvs(self): lambda t: ( # TODO: There is no current specified for TVS diodes, only peak # current - t.PARAMs.current.merge(F.ANY()), - t.PARAMs.forward_voltage.merge(F.ANY()), - t.PARAMs.reverse_working_voltage.merge( - F.Range.lower_bound(5 * P.V) - ), - t.PARAMs.reverse_leakage_current.merge(F.ANY()), - t.PARAMs.max_current.merge(F.Range.lower_bound(10 * P.A)), - t.PARAMs.reverse_breakdown_voltage.merge( - F.Range.upper_bound(8 * P.V) - ), + t.current.merge(F.ANY()), + t.forward_voltage.merge(F.ANY()), + t.reverse_working_voltage.merge(F.Range.lower_bound(5 * P.V)), + t.reverse_leakage_current.merge(F.ANY()), + t.max_current.merge(F.Range.lower_bound(10 * P.A)), + t.reverse_breakdown_voltage.merge(F.Range.upper_bound(8 * P.V)), ) ), footprint=[("SMB(DO-214AA)", 2)], @@ -368,18 +337,14 @@ def test_find_ldo(self): self, F.LDO().builder( lambda u: ( - u.PARAMs.output_voltage.merge( - F.Range.from_center(3.3 * P.V, 0.1 * P.V) - ), - u.PARAMs.output_current.merge(F.Range.lower_bound(0.1 * P.A)), - u.PARAMs.max_input_voltage.merge(F.Range.lower_bound(5 * P.V)), - u.PARAMs.dropout_voltage.merge(F.Range.upper_bound(1 * P.V)), - u.PARAMs.output_polarity.merge( - F.Constant(F.LDO.OutputPolarity.POSITIVE) - ), - u.PARAMs.output_type.merge(F.Constant(F.LDO.OutputType.FIXED)), - u.PARAMs.psrr.merge(F.ANY()), - u.PARAMs.quiescent_current.merge(F.ANY()), + u.output_voltage.merge(F.Range.from_center(3.3 * P.V, 0.1 * P.V)), + u.output_current.merge(F.Range.lower_bound(0.1 * P.A)), + u.max_input_voltage.merge(F.Range.lower_bound(5 * P.V)), + u.dropout_voltage.merge(F.Range.upper_bound(1 * P.V)), + u.output_polarity.merge(F.Constant(F.LDO.OutputPolarity.POSITIVE)), + u.output_type.merge(F.Constant(F.LDO.OutputType.FIXED)), + u.psrr.merge(F.ANY()), + u.quiescent_current.merge(F.ANY()), ) ), footprint=[