-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bikey-Wagon Learnings #14
base: main
Are you sure you want to change the base?
Changes from all commits
f5e6bda
5a372a8
ed88839
1169587
e263abb
37622b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# This file is part of the faebryk project | ||
# SPDX-License-Identifier: MIT | ||
|
||
import logging | ||
from enum import Enum | ||
|
||
import faebryk.library._F as F | ||
from faebryk.core.module import Module | ||
from faebryk.core.moduleinterface import ModuleInterface | ||
from faebryk.library.Electrical import Electrical | ||
from faebryk.library.KicadFootprint import KicadFootprint | ||
from faebryk.libs.picker.picker import has_part_picked_remove | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class NetTie[T: ModuleInterface](Module): | ||
class Size(float, Enum): | ||
_2_0MM = 2.0 | ||
_0_5MM = 0.5 | ||
|
||
unnamed: list[T] | ||
|
||
def __init__( | ||
self, | ||
width: Size, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the width be a parameter instead of constructor argument? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally, but then I'd need to defer construction until later to make the footprint trait work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need delayed construction, because you are not constructing anything. Adding a trait is always possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. width: TBD[Quantity]
...
@L.rt_field
def footprint(self):
class _(F.has_footprint):
@staticmethod
def get_footprint():
value = self.width.get_most_narrow()
assert isinstance(value, Constant)
width_mm = value ...
return F.KicadFootprint(f"NetTie:NetTie-2_SMD_Pad{width_mm:.1f}mm", pin_names=["1", "2"])
@staticmethod
def is_implemented(_self):
return isinstance(self.width.get_most_narrow(), Constant)
return _() |
||
interface_type: type[T] = Electrical, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is a net tie for non-electrical? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should make a tree (maybe as a build artifact) of the types. It's non-obvious that |
||
) -> None: | ||
super().__init__() | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. init in fab ll is purely for argument passing def __init__(
self,
width: Size,
interface_type: type[T] = Electrical,
) -> None:
super().__init__()
self._interface_type = interface_type
self._width = width
def __preinit__(self): ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait though, if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The order is init, annotations, d_fields, rt_fields, preinit, postinit |
||
# dynamically construct the interfaces | ||
self.unnamed = self.add([interface_type(), interface_type()], "unnamed") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to do the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use self.add(times(2, self._interface_type), "unnamed") |
||
|
||
# add dem trairs | ||
self.add(F.can_bridge_defined(*self.unnamed)) | ||
|
||
width_mm = NetTie.Size(width).value | ||
|
||
self.add(F.can_attach_to_footprint_symmetrically()) | ||
self.add(F.has_designator_prefix_defined("H")) | ||
# TODO: "removed" isn't really true, but seems to work | ||
self.add(has_part_picked_remove()) | ||
|
||
# TODO: generate the kicad footprint instead of loading it | ||
self.add( | ||
F.has_footprint_defined( | ||
KicadFootprint( | ||
f"NetTie:NetTie-2_SMD_Pad{width_mm:.1f}mm", pin_names=["1", "2"] | ||
) | ||
) | ||
) | ||
Comment on lines
+39
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. static traits should be in the class body attach_to_footprint: F.can_attach_to_footprint_symmetrically
designator_prefix = L.f_field(F.has_designator_prefix_defined)("H")
@L.rt_field
def footprint(self):
width_mm = NetTie.Size(self._width).value
return F.has_footprint_defined(
KicadFootprint(
f"NetTie:NetTie-2_SMD_Pad{width_mm:.1f}mm", pin_names=["1", "2"]
)
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,13 @@ | |
|
||
import logging | ||
from abc import abstractmethod | ||
from typing import Callable, Mapping | ||
from typing import Callable, Mapping, Self | ||
|
||
import faebryk.library._F as F | ||
from faebryk.core.module import Module | ||
from faebryk.core.node import Node | ||
from faebryk.core.trait import TraitImpl | ||
from faebryk.libs.picker.picker import PickError | ||
from faebryk.libs.picker.picker import PickError, has_part_picked_remove | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -84,3 +84,19 @@ def handle_duplicate(self, other: TraitImpl, node: Node) -> bool: | |
other.pickers.extend(self.pickers) | ||
other.pickers.sort(key=lambda x: x[0]) | ||
return False | ||
|
||
@classmethod | ||
def remove_if[T: Module]( | ||
cls, m: T, condition: Callable[[T], bool], prio: int = -10 | ||
) -> Self: | ||
def replace(module: Module): | ||
assert module is m | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those captures inhibit python from caching anonymous functions |
||
|
||
if condition(module): | ||
module.add_trait(has_part_picked_remove()) | ||
|
||
raise PickError("", m) | ||
Comment on lines
+95
to
+98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return in if missing |
||
|
||
m.add(has_multi_picker(prio, has_multi_picker.FunctionPicker(replace))) | ||
|
||
return m |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import importlib | ||
import subprocess | ||
import sys | ||
from types import ModuleType | ||
|
||
from rich.prompt import Confirm | ||
|
||
|
||
class InstallationError(Exception): | ||
"""Raised when there's a problem installing a module.""" | ||
|
||
|
||
def offer_install(module_name, install_name=None, ex=None) -> ModuleType | None: | ||
""" | ||
Offer to install a missing module using pip. | ||
""" | ||
cmd = [sys.executable, "-m", "pip", "install", install_name or module_name] | ||
|
||
print(f"The module '{module_name}' is not installed.") | ||
|
||
if Confirm.ask( | ||
f"Do you want to run the install command [cyan mono]`{' '.join(cmd)}`[/]" | ||
): | ||
try: | ||
# Attempt to install the module using pip | ||
subprocess.check_call(cmd) | ||
|
||
except subprocess.CalledProcessError: | ||
print(f"Failed to install {module_name}. Please install it manually.") | ||
raise ex or InstallationError(f"Failed to install {module_name}") | ||
|
||
print(f"Successfully installed {module_name}") | ||
return importlib.import_module(module_name) | ||
|
||
|
||
def offer_missing_install( | ||
module_name: str, install_name: str = None | ||
) -> ModuleType | None: | ||
""" | ||
Offer to install a missing module using pip. | ||
""" | ||
try: | ||
return importlib.import_module(module_name) | ||
except ModuleNotFoundError: | ||
return offer_install(module_name, install_name) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid direct imports from faebryk.library, use F.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pulling this into my project for now and separating the PRs.
Here's another draft for it specifically: #39