Source code for jitx.design

"""
Design definition
=================

This module provides the Design class, which is the root of a JITX design.
"""

from dataclasses import dataclass

from jitx.board import Board
from jitx.circuit import Circuit
from jitx.substrate import Substrate
from .context import Context
from .events import Event, EventContext
from ._structural import Structural
from jitx.decorators import early, late


[docs] class Design(Structural): """To create a JITX design, create a subclass of this class. It will need a :py:class:`~jitx.board.Board`, a :py:class:`~jitx.substrate.Substrate` and a :py:class:`~jitx.circuit.Circuit`. >>> class MyDesign(Design): ... board = MyBoard() ... substrate = MySubstrate() ... circuit = MyCircuit() """ board: Board substrate: Substrate circuit: Circuit
[docs] @dataclass class Initialized(Event): """Event that is fired once the entire design has been gone through the initial construction and initialization. The design has not yet been dispatched for processing, and can still be modified if needed. >>> class MyComponent(Component): @Design.Initialized.on def on_initialized(self, init: Design.Initialized): ... # do something after initialization """ design: "Design" """The initialized design."""
@early def setup(self): DesignContext(self).set() EventContext().set() @late def finalize(self): self.Initialized(self).fire() def __init_subclass__(cls): super().__init_subclass__() if cls.__module__ == "__main__": global _main_module_catch if not _main_module_catch: import atexit @atexit.register def _(): import os import sys if "jitx.run" not in sys.modules: # File with a design was run directly, but never # imported jitx.run to run it manually. Let's be # helpful to someone who presses the play button. print( "It appears we're attempting to run a JITX", "design file. We'll try to run it from the proper", "entry point. If this was unintended, please import", "jitx.run to suppress this behavior.", file=sys.stderr, ) main = sys.modules["__main__"] path: str | None = None if hasattr(main, "__file__") and main.__file__: path = main.__file__ else: loader = main.__loader__ if loader and hasattr(loader, "path"): # pyright does not do hasattr type narrowing path = loader.path # type: ignore if not path: print( "Unable to determine design file path", file=sys.stderr ) return os.execl( sys.executable, sys.executable, "-m", "jitx", "build", path ) # if exec failed (unsupported on some weird platform constellations) import subprocess p = subprocess.Popen([sys.executable, "jitx", "build", path]) p.wait() _main_module_catch = True
_main_module_catch = False
[docs] @dataclass class DesignContext(Context): """Context object representing the currently active design. Should not be used directly, but rather accessed through :py:data:`jitx.current`'s :py:attr:`~jitx.Current.design` instead. >>> def design_elements() -> tuple[Board, Substrate, Circuit]: ... design = jitx.current.design ... return (design.board, design.substrate, design.circuit) """ design: Design
[docs] def name(design: Design) -> str: """Get the fully qualified name of a design. Args: design: The design instance. Returns: The fully qualified name, or just the class name if from __main__. """ cls = type(design) if cls.__module__ == "__main__": return cls.__name__ return f"{cls.__module__}.{cls.__name__}"