Skip to content

Commit dfeb554

Browse files
authored
Allow unnamed elements in error messages (#361)
Prior, exceptions that use _name_of that had an unknown element would stack-trace with the _name_of. This could happen, for instance, during an invalid implicit connect before the Block is assigned a name. This adds an optional argument to _name_of to auto-generate unknown names for elements. The generate unknown names behavior isn't default for cases where the name must be valid (as opposed to only being helpfully informative).
1 parent 2aa5c06 commit dfeb554

File tree

3 files changed

+29
-17
lines changed

3 files changed

+29
-17
lines changed

edg/core/Array.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def items(self) -> ItemsView[str, VectorType]:
130130
return self._elts.items()
131131

132132
# unlike most other LibraryElement types, the names are stored in _elts and _allocates
133-
def _name_of_child(self, subelt: Any) -> str:
133+
def _name_of_child(self, subelt: Any, allow_unknown: bool = False) -> str:
134134
from .HierarchyBlock import Block
135135
block_parent = self._block_parent()
136136
assert isinstance(block_parent, Block)
@@ -141,7 +141,10 @@ def _name_of_child(self, subelt: Any) -> str:
141141
for (name, elt) in self._elts.items():
142142
if subelt is elt:
143143
return name
144-
raise ValueError(f"no name for {subelt}")
144+
if allow_unknown:
145+
return f"(unknown {subelt.__class__.__name__})"
146+
else:
147+
raise ValueError(f"no name for {subelt}")
145148
elif builder.get_enclosing_block() is block_parent._parent:
146149
# in block enclosing the block defining this port (allocate required)
147150
for (i, (suggested_name, allocate_elt)) in enumerate(self._requests):
@@ -150,7 +153,10 @@ def _name_of_child(self, subelt: Any) -> str:
150153
return suggested_name
151154
else:
152155
return f"_allocate_{i}"
153-
raise ValueError(f"allocated elt not found {subelt}")
156+
if allow_unknown:
157+
return f"(unknown {subelt.__class__.__name__})"
158+
else:
159+
raise ValueError(f"allocated elt not found {subelt}")
154160
else:
155161
raise ValueError(f"unknown context of array")
156162

edg/core/Blocks.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def add_ports(self, ports: Iterable[BasePort]):
8888
if is_export:
8989
(ext_port, int_port) = is_export
9090
if ext_port._get_initializers([]):
91-
raise UnconnectableError(f"Connected boundary port {ext_port._name_from(self.parent)} may not have initializers")
91+
raise UnconnectableError(f"Connected boundary port {ext_port._name_from(self.parent, allow_unknown=True)} may not have initializers")
9292
return # is an export, not a connection
9393

9494
# otherwise, is a link-mediated connection
@@ -111,19 +111,19 @@ def add_ports(self, ports: Iterable[BasePort]):
111111
if isinstance(self.parent, Block): # check if bridge is needed
112112
if port._block_parent() is self.parent:
113113
if port._get_initializers([]):
114-
raise UnconnectableError(f"Connected boundary port {port._name_from(self.parent)} may not have initializers")
114+
raise UnconnectableError(f"Connected boundary port {port._name_from(self.parent, allow_unknown=True)} may not have initializers")
115115
if not isinstance(port, Port):
116-
raise UnconnectableError(f"Can't generate bridge for non-Port {port._name_from(self.parent)}")
116+
raise UnconnectableError(f"Can't generate bridge for non-Port {port._name_from(self.parent, allow_unknown=True)}")
117117

118118
bridge = port._bridge()
119119
if bridge is None:
120-
raise UnconnectableError(f"No bridge for {port._name_from(self.parent)}")
120+
raise UnconnectableError(f"No bridge for {port._name_from(self.parent, allow_unknown=True)}")
121121
link_facing_port = self.bridged_ports[port] = bridge.inner_link
122122
else:
123123
link_facing_port = port
124124
elif isinstance(self.parent, Link): # links don't bridge, all ports are treated as internal
125125
if port._block_parent() is not self.parent:
126-
raise UnconnectableError(f"Port {port._name_from(self.parent)} not in containing link")
126+
raise UnconnectableError(f"Port {port._name_from(self.parent, allow_unknown=True)} not in containing link")
127127
link_facing_port = port
128128
else:
129129
raise ValueError(f"unknown parent {self.parent}")
@@ -134,13 +134,13 @@ def add_ports(self, ports: Iterable[BasePort]):
134134

135135
# allocate the connection
136136
if self._baseport_leaf_type(link_facing_port).link_type is not type(link):
137-
raise UnconnectableError(f"Can't connect {port._name_from(self.parent)} to link of type {type(link)}")
137+
raise UnconnectableError(f"Can't connect {port._name_from(self.parent, allow_unknown=True)} to link of type {type(link)}")
138138
port_type = type(self._baseport_leaf_type(link_facing_port))
139139
allocatable_link_ports = self.available_link_ports_by_type.get(port_type, None)
140140
if allocatable_link_ports is None:
141-
raise UnconnectableError(f"No link port for {port._name_from(self.parent)} of type {port_type}")
141+
raise UnconnectableError(f"No link port for {port._name_from(self.parent, allow_unknown=True)} of type {port_type}")
142142
if not allocatable_link_ports:
143-
raise UnconnectableError(f"No remaining link ports to {port._name_from(self.parent)}")
143+
raise UnconnectableError(f"No remaining link ports to {port._name_from(self.parent, allow_unknown=True)}")
144144

145145
allocated_link_port = allocatable_link_ports[0]
146146
if isinstance(allocated_link_port, BaseVector): # array on link side, can connected multiple ports

edg/core/Core.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,22 +214,28 @@ def __setattr__(self, name: str, value: Any) -> None:
214214
self.manager.add_element(name, value)
215215
super().__setattr__(name, value)
216216

217-
def _name_of_child(self, subelt: Any) -> str:
217+
def _name_of_child(self, subelt: Any, allow_unknown: bool = False) -> str:
218218
self_name = self.manager.name_of(subelt)
219219
if self_name is not None:
220220
return self_name
221221
else:
222-
raise ValueError(f"no name for {subelt}")
222+
if allow_unknown:
223+
return f"(unknown {subelt.__class__.__name__})"
224+
else:
225+
raise ValueError(f"no name for {subelt}")
223226

224-
def _path_from(self, base: LibraryElement) -> List[str]:
227+
def _path_from(self, base: LibraryElement, allow_unknown: bool = False) -> List[str]:
225228
if base is self:
226229
return []
227230
else:
228231
assert self._parent is not None, "can't get path / name for non-bound element"
229-
return self._parent._path_from(base) + [self._parent._name_of_child(self)]
232+
return self._parent._path_from(base, allow_unknown) + [self._parent._name_of_child(self, allow_unknown)]
230233

231-
def _name_from(self, base: LibraryElement) -> str:
232-
return '.'.join(self._path_from(base))
234+
def _name_from(self, base: LibraryElement, allow_unknown: bool = False) -> str:
235+
"""Returns the path name to (inclusive) this element from some starting point.
236+
allow_unknown allows elements that haven't been assigned a name yet to not crash,
237+
this is useful when called from an error so the _name_from error doesn't stomp the real error."""
238+
return '.'.join(self._path_from(base, allow_unknown))
233239

234240
@classmethod
235241
def _static_def_name(cls) -> str:

0 commit comments

Comments
 (0)