Skip to content
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

Experimental API for port and param docs #343

Merged
merged 1 commit into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions edg_core/Blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,12 @@ def __init__(self) -> None:

# TODO delete type ignore after https://github.com/python/mypy/issues/5374
self._parameters: SubElementDict[ConstraintExpr] = self.manager.new_dict(ConstraintExpr) # type: ignore
self._param_docs = IdentityDict[ConstraintExpr, str]()

self._ports: SubElementDict[BasePort] = self.manager.new_dict(BasePort) # type: ignore
self._required_ports = IdentitySet[BasePort]()
self._port_docs = IdentityDict[BasePort, str]()

self._connects = self.manager.new_dict(Connection, anon_prefix='anon_link')
self._connects_by_port = IdentityDict[BasePort, Connection]() # port -> connection
self._connect_delegateds = IdentityDict[Connection, List[Connection]]() # for net joins, joined connect -> prior connects
Expand Down Expand Up @@ -474,7 +478,7 @@ def assign(self, target: ConstraintExpr[ConstrType, Any],
return constraint

T = TypeVar('T', bound=BasePort)
def Port(self, tpe: T, *, optional: bool = False) -> T:
def Port(self, tpe: T, *, optional: bool = False, doc: Optional[str] = None) -> T:
"""Registers a port for this Block"""
if self._elaboration_state != BlockElaborationState.init:
raise BlockDefinitionError(self, "can't call Port(...) outside __init__",
Expand All @@ -488,10 +492,13 @@ def Port(self, tpe: T, *, optional: bool = False) -> T:
if not optional:
self._required_ports.add(elt)

if doc is not None:
self._port_docs[elt] = doc

return elt

ConstraintType = TypeVar('ConstraintType', bound=ConstraintExpr)
def Parameter(self, tpe: ConstraintType) -> ConstraintType:
def Parameter(self, tpe: ConstraintType, *, doc: Optional[str] = None) -> ConstraintType:
"""Registers a parameter for this Block"""
if self._elaboration_state != BlockElaborationState.init:
raise BlockDefinitionError(self, "can't call Parameter(...) outside __init__",
Expand All @@ -504,6 +511,9 @@ def Parameter(self, tpe: ConstraintType) -> ConstraintType:
if elt.initializer is not None:
self._check_constraint(elt.initializer)

if doc is not None:
self._param_docs[elt] = doc

return elt

def connect(self, *connects: Union[BasePort, Connection], flatten=False) -> Connection:
Expand Down
36 changes: 20 additions & 16 deletions edg_core/HierarchyBlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,27 +455,27 @@ def connect(self, *connects: Union[BasePort, Connection], flatten=False) -> Conn
from .ConstraintExpr import BoolLike, BoolExpr, FloatLike, FloatExpr, RangeLike, RangeExpr
# type ignore is needed because IntLike overlaps BoolLike
@overload
def ArgParameter(self, param: BoolLike) -> BoolExpr: ... # type: ignore
def ArgParameter(self, param: BoolLike, *, doc: Optional[str] = None) -> BoolExpr: ... # type: ignore
@overload
def ArgParameter(self, param: IntLike) -> IntExpr: ... # type: ignore
def ArgParameter(self, param: IntLike, *, doc: Optional[str] = None) -> IntExpr: ... # type: ignore
@overload
def ArgParameter(self, param: FloatLike) -> FloatExpr: ... # type: ignore
def ArgParameter(self, param: FloatLike, *, doc: Optional[str] = None) -> FloatExpr: ... # type: ignore
@overload
def ArgParameter(self, param: RangeLike) -> RangeExpr: ... # type: ignore
def ArgParameter(self, param: RangeLike, *, doc: Optional[str] = None) -> RangeExpr: ... # type: ignore
@overload
def ArgParameter(self, param: StringLike) -> StringExpr: ... # type: ignore
def ArgParameter(self, param: StringLike, *, doc: Optional[str] = None) -> StringExpr: ... # type: ignore
@overload
def ArgParameter(self, param: ArrayBoolLike) -> ArrayBoolExpr: ... # type: ignore
def ArgParameter(self, param: ArrayBoolLike, *, doc: Optional[str] = None) -> ArrayBoolExpr: ... # type: ignore
@overload
def ArgParameter(self, param: ArrayIntLike) -> ArrayIntExpr: ... # type: ignore
def ArgParameter(self, param: ArrayIntLike, *, doc: Optional[str] = None) -> ArrayIntExpr: ... # type: ignore
@overload
def ArgParameter(self, param: ArrayFloatLike) -> ArrayFloatExpr: ... # type: ignore
def ArgParameter(self, param: ArrayFloatLike, *, doc: Optional[str] = None) -> ArrayFloatExpr: ... # type: ignore
@overload
def ArgParameter(self, param: ArrayRangeLike) -> ArrayRangeExpr: ... # type: ignore
def ArgParameter(self, param: ArrayRangeLike, *, doc: Optional[str] = None) -> ArrayRangeExpr: ... # type: ignore
@overload
def ArgParameter(self, param: ArrayStringLike) -> ArrayStringExpr: ... # type: ignore
def ArgParameter(self, param: ArrayStringLike, *, doc: Optional[str] = None) -> ArrayStringExpr: ... # type: ignore

def ArgParameter(self, param: CastableType) -> ConstraintExpr[Any, CastableType]:
def ArgParameter(self, param: CastableType, *, doc: Optional[str] = None) -> ConstraintExpr[Any, CastableType]:
"""Registers a constructor argument parameter for this Block.
This doesn't actually do anything, but is needed to help the type system converter the *Like to a *Expr."""
if not isinstance(param, ConstraintExpr):
Expand All @@ -484,23 +484,27 @@ def ArgParameter(self, param: CastableType) -> ConstraintExpr[Any, CastableType]
raise TypeError(f"param to ArgParameter(...) must have binding")
if not isinstance(param.binding, InitParamBinding):
raise TypeError(f"param to ArgParameter(...) must be __init__ argument with @init_in_parent")

if doc is not None:
self._param_docs[param] = doc

return param

T = TypeVar('T', bound=BasePort)
def Port(self, tpe: T, tags: Iterable[PortTag]=[], *, optional: bool = False) -> T:
def Port(self, tpe: T, tags: Iterable[PortTag]=[], *, optional: bool = False, doc: Optional[str] = None) -> T:
"""Registers a port for this Block"""
if not isinstance(tpe, (Port, Vector)):
raise NotImplementedError("Non-Port (eg, Vector) ports not (yet?) supported")
for tag in tags:
assert_cast(tag, PortTag, "tag for Port(...)")

port = super().Port(tpe, optional=optional)
port = super().Port(tpe, optional=optional, doc=doc)

self._port_tags[port] = set(tags)
return port # type: ignore

ExportType = TypeVar('ExportType', bound=BasePort)
def Export(self, port: ExportType, tags: Iterable[PortTag]=[], *, optional: bool = False) -> ExportType:
def Export(self, port: ExportType, tags: Iterable[PortTag]=[], *, optional: bool = False, doc: Optional[str] = None) -> ExportType:
"""Exports a port of a child block, but does not propagate tags or optional."""
assert port._is_bound(), "can only export bound type"
port_parent = port._block_parent()
Expand All @@ -510,10 +514,10 @@ def Export(self, port: ExportType, tags: Iterable[PortTag]=[], *, optional: bool
if isinstance(port, BaseVector): # TODO can the vector and non-vector paths be unified?
assert isinstance(port, Vector)
new_port: BasePort = self.Port(Vector(port._tpe.empty()),
tags, optional=optional)
tags, optional=optional, doc=doc)
elif isinstance(port, Port):
new_port = self.Port(type(port).empty(), # TODO is dropping args safe in all cases?
tags, optional=optional)
tags, optional=optional, doc=doc)
else:
raise NotImplementedError(f"unknown exported port type {port}")

Expand Down
Loading