diff --git a/src/faebryk/exporters/bom/jlcpcb.py b/src/faebryk/exporters/bom/jlcpcb.py index 2d23f06e..9e6b8b8d 100644 --- a/src/faebryk/exporters/bom/jlcpcb.py +++ b/src/faebryk/exporters/bom/jlcpcb.py @@ -1,3 +1,6 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + import csv import logging import os @@ -5,14 +8,8 @@ from dataclasses import dataclass from pathlib import Path +import faebryk.library._F as F from faebryk.core.module import Module -from faebryk.library.has_descriptive_properties import has_descriptive_properties -from faebryk.library.has_designator import has_designator -from faebryk.library.has_footprint import has_footprint -from faebryk.library.has_kicad_footprint import has_kicad_footprint -from faebryk.library.has_simple_value_representation import ( - has_simple_value_representation, -) from faebryk.libs.picker.picker import DescriptiveProperties logger = logging.getLogger(__name__) @@ -104,30 +101,30 @@ def _compact_bomlines(bomlines: list[BOMLine]) -> list[BOMLine]: def _get_bomline(cmp: Module) -> BOMLine | None: - if not cmp.has_trait(has_footprint): + if not cmp.has_trait(F.has_footprint): return if not all( cmp.has_trait(t) for t in ( - has_descriptive_properties, - has_designator, + F.has_descriptive_properties, + F.has_designator, ) ): logger.warning(f"Missing fields on component {cmp}") return - properties = cmp.get_trait(has_descriptive_properties).get_properties() - footprint = cmp.get_trait(has_footprint).get_footprint() + properties = cmp.get_trait(F.has_descriptive_properties).get_properties() + footprint = cmp.get_trait(F.has_footprint).get_footprint() value = ( - cmp.get_trait(has_simple_value_representation).get_value() - if cmp.has_trait(has_simple_value_representation) + cmp.get_trait(F.has_simple_value_representation).get_value() + if cmp.has_trait(F.has_simple_value_representation) else "" ) - designator = cmp.get_trait(has_designator).get_designator() + designator = cmp.get_trait(F.has_designator).get_designator() - if not footprint.has_trait(has_kicad_footprint): + if not footprint.has_trait(F.has_kicad_footprint): logger.warning(f"Missing kicad footprint on component {cmp}") return @@ -145,7 +142,9 @@ def _get_bomline(cmp: Module) -> BOMLine | None: else "" ) - footprint_name = footprint.get_trait(has_kicad_footprint).get_kicad_footprint_name() + footprint_name = footprint.get_trait( + F.has_kicad_footprint + ).get_kicad_footprint_name() return BOMLine( Designator=designator, diff --git a/src/faebryk/exporters/esphome/esphome.py b/src/faebryk/exporters/esphome/esphome.py index 11b8dac2..4496f9f4 100644 --- a/src/faebryk/exporters/esphome/esphome.py +++ b/src/faebryk/exporters/esphome/esphome.py @@ -6,10 +6,9 @@ import yaml +import faebryk.library._F as F from faebryk.core.graphinterface import Graph from faebryk.core.parameter import Parameter -from faebryk.library.Constant import Constant -from faebryk.library.has_esphome_config import has_esphome_config logger = logging.getLogger(__name__) @@ -56,7 +55,7 @@ def merge_dicts(*dicts: dict) -> dict: def make_esphome_config(G: Graph) -> dict: from faebryk.core.util import get_all_nodes_with_trait - esphome_components = get_all_nodes_with_trait(G, has_esphome_config) + esphome_components = get_all_nodes_with_trait(G, F.has_esphome_config) esphome_config = merge_dicts(*[t.get_config() for _, t in esphome_components]) @@ -64,9 +63,9 @@ def instantiate_param(param: Parameter | Any): if not isinstance(param, Parameter): return param - if not isinstance(param, Constant): + if not isinstance(param, F.Constant): raise Exception( - f"Parameter {param} is not a Constant, but {type(param)}" + f"Parameter {param} is not a F.Constant, but {type(param)}" f"Config: {esphome_config}" ) return param.value diff --git a/src/faebryk/exporters/netlist/graph.py b/src/faebryk/exporters/netlist/graph.py index 01e897a1..a18f01f8 100644 --- a/src/faebryk/exporters/netlist/graph.py +++ b/src/faebryk/exporters/netlist/graph.py @@ -6,29 +6,15 @@ import networkx as nx +import faebryk.library._F as F from faebryk.core.graphinterface import Graph from faebryk.core.module import Module from faebryk.exporters.netlist.netlist import T2Netlist -from faebryk.library.Electrical import Electrical -from faebryk.library.Footprint import Footprint -from faebryk.library.has_descriptive_properties import has_descriptive_properties -from faebryk.library.has_descriptive_properties_defined import ( - has_descriptive_properties_defined, -) -from faebryk.library.has_footprint import has_footprint -from faebryk.library.has_kicad_footprint import has_kicad_footprint -from faebryk.library.has_overriden_name import has_overriden_name -from faebryk.library.has_overriden_name_defined import has_overriden_name_defined -from faebryk.library.has_simple_value_representation import ( - has_simple_value_representation, -) -from faebryk.library.Net import Net -from faebryk.library.Pad import Pad logger = logging.getLogger(__name__) -class can_represent_kicad_footprint(Footprint.TraitT): +class can_represent_kicad_footprint(F.Footprint.TraitT): kicad_footprint = T2Netlist.Component @abstractmethod @@ -38,19 +24,19 @@ def get_name_and_value(self) -> tuple[str, str]: ... def get_kicad_obj(self) -> kicad_footprint: ... @abstractmethod - def get_pin_name(self, pin: Pad) -> str: ... + def get_pin_name(self, pin: F.Pad) -> str: ... def get_or_set_name_and_value_of_node(c: Module): value = ( - c.get_trait(has_simple_value_representation).get_value() - if c.has_trait(has_simple_value_representation) + c.get_trait(F.has_simple_value_representation).get_value() + if c.has_trait(F.has_simple_value_representation) else type(c).__name__ ) - if not c.has_trait(has_overriden_name): + if not c.has_trait(F.has_overriden_name): c.add_trait( - has_overriden_name_defined( + F.has_overriden_name_defined( "{}[{}:{}]".format( c.get_full_name(), type(c).__name__, @@ -59,11 +45,11 @@ def get_or_set_name_and_value_of_node(c: Module): ) ) - has_descriptive_properties_defined.add_properties_to( + F.has_descriptive_properties_defined.add_properties_to( c, {"faebryk_name": c.get_full_name()} ) - return c.get_trait(has_overriden_name).get_name(), value + return c.get_trait(F.has_overriden_name).get_name(), value class can_represent_kicad_footprint_via_attached_component( @@ -81,20 +67,20 @@ def __init__(self, component: Module, graph: nx.Graph) -> None: def get_name_and_value(self): return get_or_set_name_and_value_of_node(self.component) - def get_pin_name(self, pin: Pad): - return self.obj.get_trait(has_kicad_footprint).get_pin_names()[pin] + def get_pin_name(self, pin: F.Pad): + return self.obj.get_trait(F.has_kicad_footprint).get_pin_names()[pin] def get_kicad_obj(self): - fp = self.get_obj(Footprint) + fp = self.get_obj(F.Footprint) properties = { - "footprint": fp.get_trait(has_kicad_footprint).get_kicad_footprint() + "footprint": fp.get_trait(F.has_kicad_footprint).get_kicad_footprint() } for c in [fp, self.component]: - if c.has_trait(has_descriptive_properties): + if c.has_trait(F.has_descriptive_properties): properties.update( - c.get_trait(has_descriptive_properties).get_properties() + c.get_trait(F.has_descriptive_properties).get_properties() ) name, value = self.get_name_and_value() @@ -106,17 +92,17 @@ def get_kicad_obj(self): ) -def add_or_get_net(interface: Electrical): +def add_or_get_net(interface: F.Electrical): from faebryk.core.util import get_connected_mifs mifs = get_connected_mifs(interface.connected) nets = { p[0] for mif in mifs - if (p := mif.get_parent()) is not None and isinstance(p[0], Net) + if (p := mif.get_parent()) is not None and isinstance(p[0], F.Net) } if not nets: - net = Net() + net = F.Net() net.part_of.connect(interface) return net if len(nets) > 1: @@ -135,7 +121,7 @@ def attach_nets_and_kicad_info(g: Graph): n: t.get_footprint() # TODO maybe nicer to just look for footprints # and get their respective components instead - for n, t in get_all_nodes_with_trait(Gclosed, has_footprint) + for n, t in get_all_nodes_with_trait(Gclosed, F.has_footprint) if isinstance(n, Module) } @@ -151,5 +137,5 @@ def attach_nets_and_kicad_info(g: Graph): for fp in node_fps.values(): # TODO use graph - for mif in fp.get_children(direct_only=True, types=Pad): + for mif in fp.get_children(direct_only=True, types=F.Pad): add_or_get_net(mif.net) diff --git a/src/faebryk/exporters/netlist/netlist.py b/src/faebryk/exporters/netlist/netlist.py index cd8cb571..0e7d77cd 100644 --- a/src/faebryk/exporters/netlist/netlist.py +++ b/src/faebryk/exporters/netlist/netlist.py @@ -4,9 +4,8 @@ import logging from dataclasses import dataclass +import faebryk.library._F as F from faebryk.core.graphinterface import Graph -from faebryk.library.has_footprint import has_footprint -from faebryk.library.has_overriden_name import has_overriden_name logger = logging.getLogger(__name__) @@ -45,7 +44,7 @@ def make_t2_netlist_from_graph(G: Graph) -> T2Netlist: t2_nets = [ T2Netlist.Net( - properties={"name": net.get_trait(has_overriden_name).get_name()}, + properties={"name": net.get_trait(F.has_overriden_name).get_name()}, vertices=sorted( [ T2Netlist.Net.Vertex( @@ -63,7 +62,7 @@ def make_t2_netlist_from_graph(G: Graph) -> T2Netlist: comps = { t.get_footprint().get_trait(can_represent_kicad_footprint).get_kicad_obj() - for _, t in get_all_nodes_with_trait(G, has_footprint) + for _, t in get_all_nodes_with_trait(G, F.has_footprint) } not_found = [ diff --git a/src/faebryk/exporters/pcb/routing/routing.py b/src/faebryk/exporters/pcb/routing/routing.py index 177f72b4..92cbb30c 100644 --- a/src/faebryk/exporters/pcb/routing/routing.py +++ b/src/faebryk/exporters/pcb/routing/routing.py @@ -10,6 +10,7 @@ import networkx as nx +import faebryk.library._F as F from faebryk.exporters.pcb.kicad.transformer import PCB_Transformer from faebryk.exporters.pcb.routing.grid import ( Coord, @@ -18,8 +19,6 @@ GridInvalidVertexException, OutCoord, ) -from faebryk.library.has_overriden_name import has_overriden_name -from faebryk.library.Net import Net from faebryk.libs.geometry.basic import Geometry from faebryk.libs.kicad.pcb import Footprint, GR_Circle, GR_Line, GR_Rect, Pad @@ -126,13 +125,12 @@ def draw_circle(self, coord: OutCoord, size=0.5, layer="User.9"): def route_all(self): from faebryk.core.util import get_all_nodes_of_type - from faebryk.library.Net import Net as FNet - nets = get_all_nodes_of_type(self.transformer.graph, FNet) + nets = get_all_nodes_of_type(self.transformer.graph, F.Net) # TODO add net picking heuristic for net in nets: - netname = net.get_trait(has_overriden_name).get_name() + netname = net.get_trait(F.has_overriden_name).get_name() try: self.route_net(net) except GridInvalidVertexException as e: @@ -158,12 +156,12 @@ def layer(p): return [layer(p) for p in pad.pos] - def route_net(self, net: Net): + def route_net(self, net: F.Net): transformer = self.transformer assert net is not None pcb_net = transformer.get_net(net) - net_name = net.get_trait(has_overriden_name).get_name() + net_name = net.get_trait(F.has_overriden_name).get_name() mifs = net.get_connected_interfaces() # get pads diff --git a/src/faebryk/exporters/pcb/routing/util.py b/src/faebryk/exporters/pcb/routing/util.py index 3e395df6..5bef9acb 100644 --- a/src/faebryk/exporters/pcb/routing/util.py +++ b/src/faebryk/exporters/pcb/routing/util.py @@ -5,12 +5,10 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Iterable, Sequence +import faebryk.library._F as F from faebryk.core.module import Module from faebryk.core.moduleinterface import ModuleInterface from faebryk.core.node import Node -from faebryk.library.Electrical import Electrical -from faebryk.library.Net import Net -from faebryk.library.Pad import Pad from faebryk.libs.geometry.basic import Geometry if TYPE_CHECKING: @@ -89,12 +87,12 @@ def __add__(self, other: "Path"): class Route(Module): - net_: Electrical + net_: F.Electrical pcb: ModuleInterface def __init__( self, - pads: Iterable[Pad], + pads: Iterable[F.Pad], path: Path | None = None, ): super().__init__() @@ -172,7 +170,7 @@ def apply_route_in_pcb(route: Route, transformer: "PCB_Transformer"): def get_internal_nets_of_node( node: Node, -) -> dict[Net | None, Iterable[ModuleInterface]]: +) -> dict[F.Net | None, Iterable[ModuleInterface]]: """ Returns all Nets occuring (at least partially) within Node and returns for each of those the corresponding mifs @@ -186,16 +184,16 @@ def get_internal_nets_of_node( ) from faebryk.libs.util import groupby - if isinstance(node, Net): + if isinstance(node, F.Net): return {node: get_connected_mifs(node.part_of.connected)} - mifs = {n for n in get_all_nodes(node) + [node] if isinstance(n, Electrical)} + mifs = {n for n in get_all_nodes(node) + [node] if isinstance(n, F.Electrical)} nets = groupby(mifs, lambda mif: get_net(mif)) return nets -def get_pads_pos_of_mifs(mifs: Sequence[Electrical]): +def get_pads_pos_of_mifs(mifs: Sequence[F.Electrical]): from faebryk.exporters.pcb.kicad.transformer import PCB_Transformer return { @@ -206,9 +204,9 @@ def get_pads_pos_of_mifs(mifs: Sequence[Electrical]): def group_pads_that_are_connected_already( - pads: Iterable[Pad], -) -> list[set[Pad]]: - out: list[set[Pad]] = [] + pads: Iterable[F.Pad], +) -> list[set[F.Pad]]: + out: list[set[F.Pad]] = [] for pad in pads: for group in out: # Only need to check first, because transitively connected @@ -220,7 +218,7 @@ def group_pads_that_are_connected_already( return out -def get_routes_of_pad(pad: Pad): +def get_routes_of_pad(pad: F.Pad): from faebryk.core.util import get_parent_of_type return { diff --git a/src/faebryk/library/KicadFootprint.py b/src/faebryk/library/KicadFootprint.py index a9c91080..9026c68f 100644 --- a/src/faebryk/library/KicadFootprint.py +++ b/src/faebryk/library/KicadFootprint.py @@ -2,12 +2,11 @@ # SPDX-License-Identifier: MIT import faebryk.library._F as F -from faebryk.library.Footprint import Footprint from faebryk.libs.library import L from faebryk.libs.util import times -class KicadFootprint(Footprint): +class KicadFootprint(F.Footprint): def __init__(self, kicad_identifier: str, pin_names: list[str]) -> None: super().__init__() diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index 05907fb0..5ca758bc 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -15,19 +15,19 @@ # flake8: noqa: I001 # flake8: noqa: E501 -from faebryk.library.has_pcb_position import has_pcb_position -from faebryk.library.Range import Range +from faebryk.library.has_simple_value_representation import has_simple_value_representation +from faebryk.library.has_footprint import has_footprint +from faebryk.library.has_overriden_name import has_overriden_name +from faebryk.library.has_descriptive_properties import has_descriptive_properties from faebryk.library.Constant import Constant +from faebryk.library.Range import Range +from faebryk.library.has_pcb_position import has_pcb_position from faebryk.library.Operation import Operation from faebryk.library.TBD import TBD -from faebryk.library.has_overriden_name import has_overriden_name -from faebryk.library.has_footprint import has_footprint from faebryk.library.has_datasheet import has_datasheet from faebryk.library.has_esphome_config import has_esphome_config -from faebryk.library.has_descriptive_properties import has_descriptive_properties from faebryk.library.has_single_electric_reference import has_single_electric_reference from faebryk.library.is_esphome_bus import is_esphome_bus -from faebryk.library.has_simple_value_representation import has_simple_value_representation from faebryk.library.has_pcb_layout import has_pcb_layout from faebryk.library.has_designator_prefix import has_designator_prefix from faebryk.library.Power import Power @@ -43,23 +43,23 @@ from faebryk.library.Mechanical import Mechanical from faebryk.library.is_representable_by_single_value import is_representable_by_single_value from faebryk.library.has_kicad_ref import has_kicad_ref +from faebryk.library.has_simple_value_representation_defined import has_simple_value_representation_defined +from faebryk.library.has_simple_value_representation_based_on_params import has_simple_value_representation_based_on_params +from faebryk.library.Footprint import Footprint +from faebryk.library.has_overriden_name_defined import has_overriden_name_defined +from faebryk.library.has_descriptive_properties_defined import has_descriptive_properties_defined +from faebryk.library.has_simple_value_representation_based_on_param import has_simple_value_representation_based_on_param +from faebryk.library.Logic import Logic +from faebryk.library.Set import Set from faebryk.library.has_pcb_position_defined_relative import has_pcb_position_defined_relative from faebryk.library.has_pcb_position_defined import has_pcb_position_defined from faebryk.library.has_pcb_position_defined_relative_to_parent import has_pcb_position_defined_relative_to_parent -from faebryk.library.Logic import Logic -from faebryk.library.Set import Set from faebryk.library.Electrical import Electrical from faebryk.library.ANY import ANY -from faebryk.library.has_overriden_name_defined import has_overriden_name_defined -from faebryk.library.Footprint import Footprint from faebryk.library.has_datasheet_defined import has_datasheet_defined from faebryk.library.has_esphome_config_defined import has_esphome_config_defined -from faebryk.library.has_descriptive_properties_defined import has_descriptive_properties_defined from faebryk.library.has_single_electric_reference_defined import has_single_electric_reference_defined from faebryk.library.is_esphome_bus_defined import is_esphome_bus_defined -from faebryk.library.has_simple_value_representation_based_on_param import has_simple_value_representation_based_on_param -from faebryk.library.has_simple_value_representation_defined import has_simple_value_representation_defined -from faebryk.library.has_simple_value_representation_based_on_params import has_simple_value_representation_based_on_params from faebryk.library.has_pcb_layout_defined import has_pcb_layout_defined from faebryk.library.has_designator_prefix_defined import has_designator_prefix_defined from faebryk.library.has_single_connection_impl import has_single_connection_impl @@ -70,13 +70,13 @@ from faebryk.library.has_footprint_requirement_defined import has_footprint_requirement_defined from faebryk.library.has_multi_picker import has_multi_picker from faebryk.library.is_representable_by_single_value_defined import is_representable_by_single_value_defined +from faebryk.library.has_footprint_impl import has_footprint_impl +from faebryk.library.can_attach_to_footprint import can_attach_to_footprint +from faebryk.library.has_kicad_footprint import has_kicad_footprint from faebryk.library.LogicOps import LogicOps from faebryk.library.has_pin_association_heuristic import has_pin_association_heuristic from faebryk.library.SPI import SPI from faebryk.library.DifferentialPair import DifferentialPair -from faebryk.library.has_footprint_impl import has_footprint_impl -from faebryk.library.can_attach_to_footprint import can_attach_to_footprint -from faebryk.library.has_kicad_footprint import has_kicad_footprint from faebryk.library.can_attach_via_pinmap import can_attach_via_pinmap from faebryk.library.PJ398SM import PJ398SM from faebryk.library.Common_Mode_Filter import Common_Mode_Filter @@ -87,28 +87,27 @@ from faebryk.library.Pad import Pad from faebryk.library.GDT import GDT from faebryk.library.Button import Button +from faebryk.library.has_footprint_defined import has_footprint_defined from faebryk.library.LogicGate import LogicGate from faebryk.library.has_pin_association_heuristic_lookup_table import has_pin_association_heuristic_lookup_table from faebryk.library.RS485 import RS485 from faebryk.library.Ethernet import Ethernet -from faebryk.library.has_footprint_defined import has_footprint_defined from faebryk.library.Net import Net from faebryk.library.has_equal_pins import has_equal_pins from faebryk.library.has_kicad_manual_footprint import has_kicad_manual_footprint from faebryk.library.can_attach_via_pinmap_pinlist import can_attach_via_pinmap_pinlist +from faebryk.library.can_attach_to_footprint_via_pinmap import can_attach_to_footprint_via_pinmap +from faebryk.library.can_attach_to_footprint_symmetrically import can_attach_to_footprint_symmetrically from faebryk.library.LogicGates import LogicGates from faebryk.library.MOSFET import MOSFET from faebryk.library.Diode import Diode from faebryk.library.BJT import BJT -from faebryk.library.can_attach_to_footprint_via_pinmap import can_attach_to_footprint_via_pinmap -from faebryk.library.can_attach_to_footprint_symmetrically import can_attach_to_footprint_symmetrically from faebryk.library.has_pcb_routing_strategy_via_to_layer import has_pcb_routing_strategy_via_to_layer from faebryk.library.has_pcb_routing_strategy_manual import has_pcb_routing_strategy_manual from faebryk.library.can_attach_via_pinmap_equal import can_attach_via_pinmap_equal from faebryk.library.has_kicad_footprint_equal_ifs import has_kicad_footprint_equal_ifs from faebryk.library.has_equal_pins_in_ifs import has_equal_pins_in_ifs from faebryk.library.KicadFootprint import KicadFootprint -from faebryk.library.TVS import TVS from faebryk.library.B4B_ZR_SM4_TF import B4B_ZR_SM4_TF from faebryk.library.pf_533984002 import pf_533984002 from faebryk.library.USB_Type_C_Receptacle_24_pin import USB_Type_C_Receptacle_24_pin @@ -117,22 +116,23 @@ from faebryk.library.Resistor import Resistor from faebryk.library.Inductor import Inductor from faebryk.library.Capacitor import Capacitor +from faebryk.library.TVS import TVS from faebryk.library.has_kicad_footprint_equal_ifs_defined import has_kicad_footprint_equal_ifs_defined from faebryk.library.DIP import DIP from faebryk.library.SMDTwoPin import SMDTwoPin from faebryk.library.QFN import QFN from faebryk.library.SOIC import SOIC from faebryk.library.Mounting_Hole import Mounting_Hole -from faebryk.library.can_be_surge_protected import can_be_surge_protected -from faebryk.library.is_surge_protected import is_surge_protected from faebryk.library.Potentiometer import Potentiometer from faebryk.library.Resistor_Voltage_Divider import Resistor_Voltage_Divider from faebryk.library.is_decoupled import is_decoupled from faebryk.library.can_be_decoupled import can_be_decoupled -from faebryk.library.is_surge_protected_defined import is_surge_protected_defined +from faebryk.library.can_be_surge_protected import can_be_surge_protected +from faebryk.library.is_surge_protected import is_surge_protected from faebryk.library.is_decoupled_nodes import is_decoupled_nodes -from faebryk.library.can_be_surge_protected_defined import can_be_surge_protected_defined +from faebryk.library.is_surge_protected_defined import is_surge_protected_defined from faebryk.library.can_be_decoupled_defined import can_be_decoupled_defined +from faebryk.library.can_be_surge_protected_defined import can_be_surge_protected_defined from faebryk.library.ElectricPower import ElectricPower from faebryk.library.Comparator import Comparator from faebryk.library.ElectricLogic import ElectricLogic diff --git a/src/faebryk/library/has_pcb_routing_strategy_greedy_direct_line.py b/src/faebryk/library/has_pcb_routing_strategy_greedy_direct_line.py index 2cbefa53..031ff73b 100644 --- a/src/faebryk/library/has_pcb_routing_strategy_greedy_direct_line.py +++ b/src/faebryk/library/has_pcb_routing_strategy_greedy_direct_line.py @@ -6,14 +6,6 @@ from typing import TYPE_CHECKING import faebryk.library._F as F -from faebryk.exporters.pcb.routing.util import ( - DEFAULT_TRACE_WIDTH, - Path, - Route, - get_internal_nets_of_node, - get_pads_pos_of_mifs, - group_pads_that_are_connected_already, -) from faebryk.libs.geometry.basic import Geometry if TYPE_CHECKING: @@ -33,6 +25,15 @@ def __init__(self, topology: Topology = Topology.DIRECT, priority: float = 0.0): self.topology = topology def calculate(self, transformer: "PCB_Transformer"): + from faebryk.exporters.pcb.routing.util import ( + DEFAULT_TRACE_WIDTH, + Path, + Route, + get_internal_nets_of_node, + get_pads_pos_of_mifs, + group_pads_that_are_connected_already, + ) + node = self.obj nets = get_internal_nets_of_node(node) diff --git a/src/faebryk/libs/app/designators.py b/src/faebryk/libs/app/designators.py index dc199154..02026e5e 100644 --- a/src/faebryk/libs/app/designators.py +++ b/src/faebryk/libs/app/designators.py @@ -8,18 +8,13 @@ from pathlib import Path from typing import cast +import faebryk.library._F as F from faebryk.core.graphinterface import Graph from faebryk.core.util import ( get_all_nodes_by_names, get_all_nodes_with_trait, ) from faebryk.exporters.netlist.netlist import T2Netlist -from faebryk.library.has_designator import has_designator -from faebryk.library.has_designator_defined import has_designator_defined -from faebryk.library.has_designator_prefix import has_designator_prefix -from faebryk.library.has_footprint import has_footprint -from faebryk.library.has_overriden_name import has_overriden_name -from faebryk.library.has_overriden_name_defined import has_overriden_name_defined from faebryk.libs.kicad.fileformats import C_kicad_pcb_file from faebryk.libs.util import duplicates, get_key, groupby @@ -31,12 +26,12 @@ def attach_random_designators(graph: Graph): sorts nodes by path and then sequentially assigns designators """ - nodes = {n for n, _ in get_all_nodes_with_trait(graph, has_footprint)} + nodes = {n for n, _ in get_all_nodes_with_trait(graph, F.has_footprint)} in_use = { - n.get_trait(has_designator).get_designator() + n.get_trait(F.has_designator).get_designator() for n in nodes - if n.has_trait(has_designator) + if n.has_trait(F.has_designator) } pattern = re.compile(r"([A-Z]+)([0-9]+)") @@ -60,35 +55,35 @@ def _get_first_hole(used: list[int]): nodes_sorted = sorted(nodes, key=lambda x: x.get_full_name()) for n in nodes_sorted: - if n.has_trait(has_designator): + if n.has_trait(F.has_designator): continue - if not n.has_trait(has_designator_prefix): + if not n.has_trait(F.has_designator_prefix): prefix = type(n).__name__ logger.warning(f"Node {prefix} has no designator prefix") - prefix = n.get_trait(has_designator_prefix).get_prefix() + prefix = n.get_trait(F.has_designator_prefix).get_prefix() next_num = _get_first_hole(assigned[prefix]) designator = f"{prefix}{next_num}" - n.add_trait(has_designator_defined(designator)) + n.add_trait(F.has_designator_defined(designator)) assigned[prefix].append(next_num) - no_designator = {n for n in nodes if not n.has_trait(has_designator)} + no_designator = {n for n in nodes if not n.has_trait(F.has_designator)} assert not no_designator - dupes = duplicates(nodes, lambda n: n.get_trait(has_designator).get_designator()) + dupes = duplicates(nodes, lambda n: n.get_trait(F.has_designator).get_designator()) assert not dupes, f"Duplcicate designators: {dupes}" def override_names_with_designators(graph: Graph): - for n, t in get_all_nodes_with_trait(graph, has_designator): + for n, t in get_all_nodes_with_trait(graph, F.has_designator): name = t.get_designator() - if n.has_trait(has_overriden_name): + if n.has_trait(F.has_overriden_name): logger.warning( - f"Renaming: {n.get_trait(has_overriden_name).get_name()} -> {name}" + f"Renaming: {n.get_trait(F.has_overriden_name).get_name()} -> {name}" ) - n.add_trait(has_overriden_name_defined(name)) + n.add_trait(F.has_overriden_name_defined(name)) def attach_hierarchical_designators(graph: Graph): @@ -112,7 +107,7 @@ def load_designators_from_netlist( for _, (n, designator) in matched_nodes.items(): logger.debug(f"Matched {n} to {designator}") - n.add_trait(has_designator_defined(designator)) + n.add_trait(F.has_designator_defined(designator)) logger.info(f"Matched {len(matched_nodes)}/{len(designators)} designators") nomatch = { @@ -131,7 +126,7 @@ def replace_faebryk_names_with_designators_in_kicad_pcb(graph: Graph, pcbfile: P pattern = re.compile(r"^(.*)\[[^\]]*\]$") translation = { n.get_full_name(): t.get_name() - for n, t in get_all_nodes_with_trait(graph, has_overriden_name) + for n, t in get_all_nodes_with_trait(graph, F.has_overriden_name) } for fp in pcb.kicad_pcb.footprints: diff --git a/src/faebryk/libs/app/erc.py b/src/faebryk/libs/app/erc.py index b33bac5c..c182e9d1 100644 --- a/src/faebryk/libs/app/erc.py +++ b/src/faebryk/libs/app/erc.py @@ -5,6 +5,7 @@ import logging from typing import Callable, Iterable, Sequence +import faebryk.library._F as F from faebryk.core.graphinterface import Graph from faebryk.core.module import Module from faebryk.core.moduleinterface import ModuleInterface @@ -12,7 +13,6 @@ get_all_nodes_of_type, get_all_nodes_of_types, ) -from faebryk.library.has_overriden_name import has_overriden_name from faebryk.libs.picker.picker import has_part_picked from faebryk.libs.util import groupby, print_stack @@ -91,7 +91,7 @@ def simple_erc(G: Graph): net_name_collisions = { k: v for k, v in groupby( - nets, lambda n: n.get_trait(has_overriden_name).get_name() + nets, lambda n: n.get_trait(F.has_overriden_name).get_name() ).items() if len(v) > 1 } diff --git a/src/faebryk/libs/app/parameters.py b/src/faebryk/libs/app/parameters.py index 66c5f5af..4af45c73 100644 --- a/src/faebryk/libs/app/parameters.py +++ b/src/faebryk/libs/app/parameters.py @@ -3,20 +3,19 @@ import logging +import faebryk.library._F as F from faebryk.core.module import Module from faebryk.core.parameter import Parameter -from faebryk.library.ANY import ANY -from faebryk.library.TBD import TBD logger = logging.getLogger(__name__) def replace_tbd_with_any(module: Module, recursive: bool, loglvl: int | None = None): """ - Replace all TBD instances with ANY instances in the given module. + Replace all F.TBD instances with F.ANY instances in the given module. - :param module: The module to replace TBD instances in. - :param recursive: If True, replace TBD instances in submodules as well. + :param module: The module to replace F.TBD instances in. + :param recursive: If True, replace F.TBD instances in submodules as well. """ from faebryk.core.util import get_all_modules @@ -27,9 +26,9 @@ def replace_tbd_with_any(module: Module, recursive: bool, loglvl: int | None = N module = module.get_most_special() for param in module.get_children(direct_only=True, types=Parameter): - if isinstance(param.get_most_narrow(), TBD): - logger.debug(f"Replacing in {module}: {param} with ANY") - param.merge(ANY()) + if isinstance(param.get_most_narrow(), F.TBD): + logger.debug(f"Replacing in {module}: {param} with F.ANY") + param.merge(F.ANY()) logger.setLevel(lvl) diff --git a/src/faebryk/libs/app/pcb.py b/src/faebryk/libs/app/pcb.py index a90e7b44..8820d265 100644 --- a/src/faebryk/libs/app/pcb.py +++ b/src/faebryk/libs/app/pcb.py @@ -7,15 +7,12 @@ from pathlib import Path from typing import Any, Callable +import faebryk.library._F as F from faebryk.core.graph import Graph from faebryk.core.module import Module from faebryk.core.util import get_node_tree, iter_tree_by_depth from faebryk.exporters.pcb.kicad.transformer import PCB_Transformer from faebryk.exporters.pcb.routing.util import apply_route_in_pcb -from faebryk.library.has_pcb_layout import has_pcb_layout -from faebryk.library.has_pcb_position import has_pcb_position -from faebryk.library.has_pcb_position_defined import has_pcb_position_defined -from faebryk.library.has_pcb_routing_strategy import has_pcb_routing_strategy from faebryk.libs.app.kicad_netlist import write_netlist from faebryk.libs.kicad.fileformats import ( C_kicad_fp_lib_table_file, @@ -27,30 +24,30 @@ def apply_layouts(app: Module): - if not app.has_trait(has_pcb_position): + if not app.has_trait(F.has_pcb_position): app.add_trait( - has_pcb_position_defined( - has_pcb_position.Point((0, 0, 0, has_pcb_position.layer_type.NONE)) + F.has_pcb_position_defined( + F.has_pcb_position.Point((0, 0, 0, F.has_pcb_position.layer_type.NONE)) ) ) tree = get_node_tree(app) for level in iter_tree_by_depth(tree): for n in level: - if n.has_trait(has_pcb_layout): - n.get_trait(has_pcb_layout).apply() + if n.has_trait(F.has_pcb_layout): + n.get_trait(F.has_pcb_layout).apply() def apply_routing(app: Module, transformer: PCB_Transformer): - strategies: list[tuple[has_pcb_routing_strategy, int]] = [] + strategies: list[tuple[F.has_pcb_routing_strategy, int]] = [] tree = get_node_tree(app) for i, level in enumerate(list(iter_tree_by_depth(tree))): for n in level: - if not n.has_trait(has_pcb_routing_strategy): + if not n.has_trait(F.has_pcb_routing_strategy): continue - strategies.append((n.get_trait(has_pcb_routing_strategy), i)) + strategies.append((n.get_trait(F.has_pcb_routing_strategy), i)) logger.info("Applying routes") diff --git a/src/faebryk/libs/brightness.py b/src/faebryk/libs/brightness.py index 6c3a016c..678e31b4 100644 --- a/src/faebryk/libs/brightness.py +++ b/src/faebryk/libs/brightness.py @@ -4,9 +4,8 @@ from copy import copy from enum import Enum +import faebryk.library._F as F from faebryk.core.parameter import Parameter -from faebryk.library.Constant import Constant -from faebryk.library.Range import Range from faebryk.libs.units import P, Quantity """ @@ -80,50 +79,50 @@ class TypicalLuminousIntensity(Enum): Well known luminous intensities in candela. """ - CANDLE = LuminousFlux(Constant(1 * P.candela)) + CANDLE = LuminousFlux(F.Constant(1 * P.candela)) - CREE_SMD_LED_EXTREMELY_DIM = LuminousFlux(Constant(10 * P.millicandela)) - CREE_SMD_LED_VERY_DIM = LuminousFlux(Constant(25 * P.millicandela)) - CREE_SMD_LED_DIM = LuminousFlux(Constant(50 * P.millicandela)) - CREE_SMD_LED_NORMAL = LuminousFlux(Constant(100 * P.millicandela)) - CREE_SMD_LED_BRIGHT = LuminousFlux(Constant(250 * P.millicandela)) - CREE_SMD_LED_VERY_BRIGHT = LuminousFlux(Constant(2 * P.candela)) - CREE_SMD_LED_EXTREMELY_BRIGHT = LuminousFlux(Constant(14 * P.candela)) + CREE_SMD_LED_EXTREMELY_DIM = LuminousFlux(F.Constant(10 * P.millicandela)) + CREE_SMD_LED_VERY_DIM = LuminousFlux(F.Constant(25 * P.millicandela)) + CREE_SMD_LED_DIM = LuminousFlux(F.Constant(50 * P.millicandela)) + CREE_SMD_LED_NORMAL = LuminousFlux(F.Constant(100 * P.millicandela)) + CREE_SMD_LED_BRIGHT = LuminousFlux(F.Constant(250 * P.millicandela)) + CREE_SMD_LED_VERY_BRIGHT = LuminousFlux(F.Constant(2 * P.candela)) + CREE_SMD_LED_EXTREMELY_BRIGHT = LuminousFlux(F.Constant(14 * P.candela)) TYPICAL_SMD_LED_MAX_BRIGHTNESS = LuminousFlux( - Range(60 * P.millicandela, 800 * P.mcandela) + F.Range(60 * P.millicandela, 800 * P.mcandela) ) - WS2812B_LED_RED = LuminousFlux(Constant(420 * P.millicandela)) - WS2812B_LED_GREEN = LuminousFlux(Constant(720 * P.millicandela)) - WS2812B_LED_BLUE = LuminousFlux(Constant(200 * P.millicandela)) + WS2812B_LED_RED = LuminousFlux(F.Constant(420 * P.millicandela)) + WS2812B_LED_GREEN = LuminousFlux(F.Constant(720 * P.millicandela)) + WS2812B_LED_BLUE = LuminousFlux(F.Constant(200 * P.millicandela)) APPLICATION_CAR_HEADLIGHTS_HALOGEN_LOW_BEAM_MEDIUM = LuminousFlux( - Constant(20 * P.kcandela) + F.Constant(20 * P.kcandela) ) APPLICATION_CAR_HEADLIGHTS_HALOGEN_HIGH_BEAM_MEDIUM = LuminousFlux( - Constant(40 * P.kcandela) + F.Constant(40 * P.kcandela) ) - APPLICATION_CAR_TURN_INDICATOR_DIM = LuminousFlux(Constant(1 * P.kcandela)) - APPLICATION_CAR_TURN_INDICATOR_BRIGHT = LuminousFlux(Constant(10 * P.kcandela)) - APPLICATION_CAR_BREAK_LIGHT_DIM = LuminousFlux(Constant(5 * P.kcandela)) - APPLICATION_CAR_BREAK_LIGHT_BRIGHT = LuminousFlux(Constant(50 * P.kcandela)) + APPLICATION_CAR_TURN_INDICATOR_DIM = LuminousFlux(F.Constant(1 * P.kcandela)) + APPLICATION_CAR_TURN_INDICATOR_BRIGHT = LuminousFlux(F.Constant(10 * P.kcandela)) + APPLICATION_CAR_BREAK_LIGHT_DIM = LuminousFlux(F.Constant(5 * P.kcandela)) + APPLICATION_CAR_BREAK_LIGHT_BRIGHT = LuminousFlux(F.Constant(50 * P.kcandela)) # not sure about these values - APPLICATION_LED_STANDBY = LuminousFlux(Range(1 * P.millicandela, 10 * P.mcandela)) + APPLICATION_LED_STANDBY = LuminousFlux(F.Range(1 * P.millicandela, 10 * P.mcandela)) APPLICATION_LED_INDICATOR_INSIDE = LuminousFlux( - Range(10 * P.millicandela, 100 * P.mcandela) + F.Range(10 * P.millicandela, 100 * P.mcandela) ) APPLICATION_LED_KEYBOARD_BACKLIGHT = LuminousFlux( - Range(50 * P.millicandela, 500 * P.mcandela) + F.Range(50 * P.millicandela, 500 * P.mcandela) ) APPLICATION_LED_INDICATOR_OUTSIDE = LuminousFlux( - Range(100 * P.millicandela, 1 * P.candela) + F.Range(100 * P.millicandela, 1 * P.candela) ) APPLICATION_LED_DECORATIVE_LIGHTING = LuminousFlux( - Range(100 * P.millicandela, 1 * P.candela) + F.Range(100 * P.millicandela, 1 * P.candela) ) - APPLICATION_LED_FLASHLIGHT = LuminousFlux(Range(10 * P.candela, 1 * P.kcandela)) + APPLICATION_LED_FLASHLIGHT = LuminousFlux(F.Range(10 * P.candela, 1 * P.kcandela)) class TypicalLuminousFlux(Enum): @@ -131,21 +130,21 @@ class TypicalLuminousFlux(Enum): Well known luminous flux in lumen. """ - IKEA_E14_BULB_LED_DIM = LuminousFlux(Constant(100 * P.lm)) - IKEA_E14_BULB_LED_MEDIUM = LuminousFlux(Constant(250 * P.lm)) - IKEA_E14_BULB_LED_BRIGHT = LuminousFlux(Constant(470 * P.lm)) - IKEA_GU10_BULB_LED_DIM = LuminousFlux(Constant(230 * P.lm)) - IKEA_GU10_BULB_LED_MEDIUM = LuminousFlux(Constant(345 * P.lm)) - IKEA_E27_BULB_LED_DIM = LuminousFlux(Constant(470 * P.lm)) - IKEA_E27_BULB_LED_MEDIUM = LuminousFlux(Constant(806 * P.lm)) - IKEA_E27_BULB_LED_BRIGHT = LuminousFlux(Constant(1500 * P.lm)) + IKEA_E14_BULB_LED_DIM = LuminousFlux(F.Constant(100 * P.lm)) + IKEA_E14_BULB_LED_MEDIUM = LuminousFlux(F.Constant(250 * P.lm)) + IKEA_E14_BULB_LED_BRIGHT = LuminousFlux(F.Constant(470 * P.lm)) + IKEA_GU10_BULB_LED_DIM = LuminousFlux(F.Constant(230 * P.lm)) + IKEA_GU10_BULB_LED_MEDIUM = LuminousFlux(F.Constant(345 * P.lm)) + IKEA_E27_BULB_LED_DIM = LuminousFlux(F.Constant(470 * P.lm)) + IKEA_E27_BULB_LED_MEDIUM = LuminousFlux(F.Constant(806 * P.lm)) + IKEA_E27_BULB_LED_BRIGHT = LuminousFlux(F.Constant(1500 * P.lm)) - CREE_SMD_LED_VERY_BRIGHT = LuminousFlux(Constant(6000 * P.lm)) + CREE_SMD_LED_VERY_BRIGHT = LuminousFlux(F.Constant(6000 * P.lm)) - LASER_POINTER_GREEN_5MW = LuminousFlux(Constant(3.4 * P.lm)) + LASER_POINTER_GREEN_5MW = LuminousFlux(F.Constant(3.4 * P.lm)) - CAR_HEADLIGHTS_HALOGEN_LOW_BEAM_MEDIUM = LuminousFlux(Constant(1000 * P.lm)) - CAR_HEADLIGHTS_HALOGEN_HIGH_BEAM_MEDIUM = LuminousFlux(Constant(1300 * P.lm)) + CAR_HEADLIGHTS_HALOGEN_LOW_BEAM_MEDIUM = LuminousFlux(F.Constant(1000 * P.lm)) + CAR_HEADLIGHTS_HALOGEN_HIGH_BEAM_MEDIUM = LuminousFlux(F.Constant(1300 * P.lm)) class TypicalIlluminance(Enum): @@ -154,17 +153,17 @@ class TypicalIlluminance(Enum): """ # https://en.wikipedia.org/wiki/Lux - MOONLESS_OVERCAST_NIGHT_SKY_STARLIGHT = Illuminance(Constant(0.0001 * P.lx)) - MOONLESS_CLEAR_NIGHT_SKY_WITH_AIRGLOW = Illuminance(Constant(0.002 * P.lx)) - FULL_MOON_ON_A_CLEAR_NIGHT = Illuminance(Constant(0.05 * P.lx)) - DARK_LIMIT_OF_CIVIL_TWILIGHT_UNDER_A_CLEAR_SKY = Illuminance(Constant(3.4 * P.lx)) - PUBLIC_AREAS_WITH_DARK_SURROUNDINGS = Illuminance(Constant(20 * P.lx)) - FAMILY_LIVING_ROOM_LIGHTS = Illuminance(Constant(50 * P.lx)) - OFFICE_BUILDING_HALLWAY_TOILET_LIGHTING = Illuminance(Constant(80 * P.lx)) - VERY_DARK_OVERCAST_DAY = Illuminance(Constant(100 * P.lx)) - TRAIN_STATION_PLATFORMS = Illuminance(Constant(150 * P.lx)) - OFFICE_LIGHTING = Illuminance(Constant(320 * P.lx)) - SUNRISE_OR_SUNSET_ON_A_CLEAR_DAY = Illuminance(Constant(400 * P.lx)) - OVERCAST_DAY = Illuminance(Constant(1000 * P.lx)) - FULL_DAYLIGHT = Illuminance(Constant(25000 * P.lx)) - DIRECT_SUNLIGHT = Illuminance(Constant(100000 * P.lx)) + MOONLESS_OVERCAST_NIGHT_SKY_STARLIGHT = Illuminance(F.Constant(0.0001 * P.lx)) + MOONLESS_CLEAR_NIGHT_SKY_WITH_AIRGLOW = Illuminance(F.Constant(0.002 * P.lx)) + FULL_MOON_ON_A_CLEAR_NIGHT = Illuminance(F.Constant(0.05 * P.lx)) + DARK_LIMIT_OF_CIVIL_TWILIGHT_UNDER_A_CLEAR_SKY = Illuminance(F.Constant(3.4 * P.lx)) + PUBLIC_AREAS_WITH_DARK_SURROUNDINGS = Illuminance(F.Constant(20 * P.lx)) + FAMILY_LIVING_ROOM_LIGHTS = Illuminance(F.Constant(50 * P.lx)) + OFFICE_BUILDING_HALLWAY_TOILET_LIGHTING = Illuminance(F.Constant(80 * P.lx)) + VERY_DARK_OVERCAST_DAY = Illuminance(F.Constant(100 * P.lx)) + TRAIN_STATION_PLATFORMS = Illuminance(F.Constant(150 * P.lx)) + OFFICE_LIGHTING = Illuminance(F.Constant(320 * P.lx)) + SUNRISE_OR_SUNSET_ON_A_CLEAR_DAY = Illuminance(F.Constant(400 * P.lx)) + OVERCAST_DAY = Illuminance(F.Constant(1000 * P.lx)) + FULL_DAYLIGHT = Illuminance(F.Constant(25000 * P.lx)) + DIRECT_SUNLIGHT = Illuminance(F.Constant(100000 * P.lx)) diff --git a/src/faebryk/libs/examples/pickers.py b/src/faebryk/libs/examples/pickers.py index 50f3e1a9..f30b10d1 100644 --- a/src/faebryk/libs/examples/pickers.py +++ b/src/faebryk/libs/examples/pickers.py @@ -6,17 +6,20 @@ """ import logging +from typing import TYPE_CHECKING import faebryk.library._F as F from faebryk.core.module import Module from faebryk.core.util import specialize_module from faebryk.library._F import Constant, Range -from faebryk.library.Switch import _TSwitch from faebryk.libs.app.parameters import replace_tbd_with_any from faebryk.libs.picker.lcsc import LCSC_Part from faebryk.libs.picker.picker import PickerOption, pick_module_by_params from faebryk.libs.units import P +if TYPE_CHECKING: + from faebryk.library.Switch import _TSwitch + logger = logging.getLogger(__name__) @@ -264,7 +267,7 @@ def pick_battery(module: F.Battery): ) -def pick_switch(module: _TSwitch[F.Electrical]): +def pick_switch(module: "_TSwitch[F.Electrical]"): module.add_trait(F.can_attach_to_footprint_symmetrically()) pick_module_by_params( module, diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index 34a489f8..6120d2e6 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -24,7 +24,6 @@ from faebryk.core.module import Module from faebryk.core.parameter import Parameter from faebryk.core.util import pretty_param_tree, pretty_params -from faebryk.library.Set import Set from faebryk.libs.e_series import ( E_SERIES_VALUES, ParamNotResolvedError, @@ -418,7 +417,7 @@ def filter_by_value( assert not self.results value_query = Q() try: - intersection = Set( + intersection = F.Set( [e_series_intersect(value, e_series or E_SERIES_VALUES.E_ALL)] ).params except ParamNotResolvedError as e: diff --git a/src/faebryk/libs/picker/lcsc.py b/src/faebryk/libs/picker/lcsc.py index a6b5afbd..9e29e921 100644 --- a/src/faebryk/libs/picker/lcsc.py +++ b/src/faebryk/libs/picker/lcsc.py @@ -14,17 +14,8 @@ from easyeda2kicad.kicad.export_kicad_3d_model import Exporter3dModelKicad from easyeda2kicad.kicad.export_kicad_footprint import ExporterFootprintKicad +import faebryk.library._F as F from faebryk.core.module import Module -from faebryk.library.can_attach_to_footprint import can_attach_to_footprint -from faebryk.library.can_attach_to_footprint_via_pinmap import ( - can_attach_to_footprint_via_pinmap, -) -from faebryk.library.has_descriptive_properties_defined import ( - has_descriptive_properties_defined, -) -from faebryk.library.has_footprint import has_footprint -from faebryk.library.has_pin_association_heuristic import has_pin_association_heuristic -from faebryk.library.KicadFootprint import KicadFootprint from faebryk.libs.picker.picker import ( Part, PickerOption, @@ -180,13 +171,13 @@ def attach(component: Module, partno: str, get_model: bool = True): ) # symbol - if not component.has_trait(has_footprint): - if not component.has_trait(can_attach_to_footprint): - if not component.has_trait(has_pin_association_heuristic): + if not component.has_trait(F.has_footprint): + if not component.has_trait(F.can_attach_to_footprint): + if not component.has_trait(F.has_pin_association_heuristic): raise LCSCException( partno, - f"Need either can_attach_to_footprint or " - "has_pin_association_heuristic" + f"Need either F.can_attach_to_footprint or " + "F.has_pin_association_heuristic" f" for {component} with partno {partno}", ) @@ -196,21 +187,21 @@ def attach(component: Module, partno: str, get_model: bool = True): for pin in easyeda_symbol.pins ] try: - pinmap = component.get_trait(has_pin_association_heuristic).get_pins( + pinmap = component.get_trait(F.has_pin_association_heuristic).get_pins( pins ) - except has_pin_association_heuristic.PinMatchException as e: + except F.has_pin_association_heuristic.PinMatchException as e: raise LCSC_PinmapException(partno, f"Failed to get pinmap: {e}") from e - component.add_trait(can_attach_to_footprint_via_pinmap(pinmap)) + component.add_trait(F.can_attach_to_footprint_via_pinmap(pinmap)) # footprint - fp = KicadFootprint( + fp = F.KicadFootprint( f"lcsc:{easyeda_footprint.info.name}", [p.number for p in easyeda_footprint.pads], ) - component.get_trait(can_attach_to_footprint).attach(fp) + component.get_trait(F.can_attach_to_footprint).attach(fp) - has_descriptive_properties_defined.add_properties_to(component, {"LCSC": partno}) + F.has_descriptive_properties_defined.add_properties_to(component, {"LCSC": partno}) # model done by kicad (in fp) @@ -220,7 +211,7 @@ def attach(self, module: Module, part: PickerOption): assert isinstance(part.part, LCSC_Part) attach(component=module, partno=part.part.partno) if part.info is not None: - has_descriptive_properties_defined.add_properties_to(module, part.info) + F.has_descriptive_properties_defined.add_properties_to(module, part.info) class LCSC_Part(Part): diff --git a/src/faebryk/tools/main.py b/src/faebryk/tools/main.py index 4e70677a..d824741b 100644 --- a/src/faebryk/tools/main.py +++ b/src/faebryk/tools/main.py @@ -1,6 +1,7 @@ from faebryk.libs.tools.typer import typer_callback from faebryk.tools.libadd import main as libadd_main from faebryk.tools.project import main as project_main +from faebryk.tools.refactor import main as refactor_main @typer_callback(None) @@ -12,6 +13,7 @@ def main(): def __main__(): main.add_typer(libadd_main, name="libadd") main.add_typer(project_main, name="project") + main.add_typer(refactor_main, name="refactor") main() diff --git a/src/faebryk/tools/refactor.py b/src/faebryk/tools/refactor.py new file mode 100644 index 00000000..aa4e7eb2 --- /dev/null +++ b/src/faebryk/tools/refactor.py @@ -0,0 +1,90 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import re +import subprocess +from dataclasses import dataclass +from pathlib import Path + +import typer + +from faebryk.libs.tools.typer import typer_callback + + +@dataclass +class CTX: ... + + +def get_ctx(ctx: typer.Context) -> "CTX": + return ctx.obj + + +@typer_callback(None) +def main(ctx: typer.Context): + """ + Can be called like this: > faebryk refactor + """ + pass + + +@main.command() +def libtof(ctx: typer.Context, root: Path): + file_paths = list(root.rglob("**/*.py")) + print(f"Found {len(file_paths)} files in path.") + + detection_pattern = re.compile(r"^from faebryk.library.[^_]") + + refactor_files = [ + path + for path in file_paths + if not path.stem.startswith("_") + and any(detection_pattern.match(line) for line in path.read_text().splitlines()) + ] + + print(f"Found {len(refactor_files)} files to refactor.") + + # TO match: + # from faebryk.library.has_kicad_footprint import has_kicad_footprint + # from faebryk.library.has_simple_value_representation import ( + # has_simple_value_representation, + # ) + + pyname = r"[_a-zA-Z][_a-zA-Z0-9]*" + import_pattern = re.compile( + r"^from faebryk.library.([^_][^ ]*) import (" + f"{pyname}$" + "|" + f"\\([\n ]*{pyname},[\n ]*\\)$" # multiline import + r")", + re.MULTILINE, + ) + + def refactor_file(path: Path): + text = path.read_text() + import_symbols = [m[0] for m in import_pattern.findall(text)] + text = import_pattern.subn("import faebryk.library._F as F", text, count=1)[0] + text = import_pattern.sub("", text) + + for sym in import_symbols: + if re.search(rf"from faebryk.library.{sym} import {sym} as", text): + print(f"Warning: skipping {sym} in {path}") + continue + + text = re.sub(rf"^\s*from faebryk.library.{sym} import {sym}$", "", text) + text = re.sub( + rf"^\s*from faebryk.library.{sym} import \(\n\s*{sym},\n\)$", "", text + ) + text = re.sub(rf"([^F][^.])\b{sym}\b", f"\1F.{sym}", text) + + # print(path, import_symbols) + path.write_text(text) + + for path in refactor_files: + refactor_file(path) + + # Run ruff + subprocess.check_call(["ruff", "check", "--fix", root]) + + +if __name__ == "__main__": + main()