Skip to content

Commit 550af83

Browse files
committed
🚸 Include resource soure information in resource-not-found errors
1 parent 0f02aee commit 550af83

File tree

3 files changed

+32
-7
lines changed

3 files changed

+32
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3131
- Moved `pygraphviz` from requirements to `graphviz` optional dependencies group.
3232
- Automatically tag untagged `subject_id` and `unique_id` as `!!str` when loading data config files.
3333
- Made orientation configurable (was hard-coded as "RPI").
34+
- Resource-not-found errors now include information about where to source those resources.
3435

3536
### Fixed
3637

CPAC/pipeline/engine.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,12 @@ def get(
420420
if report_fetched:
421421
return (None, None)
422422
return None
423+
from CPAC.pipeline.resource_inventory import where_to_find
424+
423425
msg = (
424426
"\n\n[!] C-PAC says: None of the listed resources are in "
425-
f"the resource pool:\n\n {resource}\n\nOptions:\n- You "
426-
"can enable a node block earlier in the pipeline which "
427+
f"the resource pool:\n\n {where_to_find(resource)}\n\nOptions:\n"
428+
"- You can enable a node block earlier in the pipeline which "
427429
"produces these resources. Check the 'outputs:' field in "
428430
"a node block's documentation.\n- You can directly "
429431
"provide this required data by pulling it from another "
@@ -458,7 +460,9 @@ def copy_resource(self, resource, new_name):
458460
try:
459461
self.rpool[new_name] = self.rpool[resource]
460462
except KeyError:
461-
msg = f"[!] {resource} not in the resource pool."
463+
from CPAC.pipeline.resource_inventory import where_to_find
464+
465+
msg = f"[!] Not in the resource pool:\n{where_to_find(resource)}"
462466
raise Exception(msg)
463467

464468
def update_resource(self, resource, new_name):
@@ -630,11 +634,13 @@ def get_strats(self, resources, debug=False):
630634
total_pool.append(sub_pool)
631635

632636
if not total_pool:
637+
from CPAC.pipeline.resource_inventory import where_to_find
638+
633639
raise LookupError(
634640
"\n\n[!] C-PAC says: None of the listed "
635641
"resources in the node block being connected "
636642
"exist in the resource pool.\n\nResources:\n"
637-
"%s\n\n" % resource_list
643+
"%s\n\n" % where_to_find(resource_list)
638644
)
639645

640646
# TODO: right now total_pool is:

CPAC/pipeline/resource_inventory.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def cli_parser() -> Namespace:
214214
return parser.parse_args()
215215

216216

217-
def _flatten_io(io: list[Iterable]) -> list[str]:
217+
def _flatten_io(io: Iterable[Iterable]) -> list[str]:
218218
"""Given a list of strings or iterables thereof, flatten the list to all strings."""
219219
if all(isinstance(resource, str) for resource in io):
220220
return cast(list[str], io)
@@ -243,7 +243,7 @@ def find_directly_set_resources(package_name: str) -> dict[str, list[str]]:
243243
dict
244244
A dictionary containing the name of the resource and the name of the functions that set it.
245245
"""
246-
resources: dict[str[list[str]]] = {}
246+
resources: dict[str, list[str]] = {}
247247
for dirpath, _, filenames in os.walk(str(files(package_name))):
248248
for filename in filenames:
249249
if filename.endswith(".py"):
@@ -280,7 +280,7 @@ def resource_inventory(package: str = "CPAC") -> dict[str, ResourceIO]:
280280
"CPAC.unet._torch",
281281
],
282282
):
283-
nbf_name = f"{nbf.__module__}.{nbf.__qualname__}"
283+
nbf_name = f"{nbf.name} ({nbf.__module__}.{nbf.__qualname__})"
284284
if hasattr(nbf, "inputs"):
285285
for nbf_input in _flatten_io(cast(list[Iterable], nbf.inputs)):
286286
if nbf_input:
@@ -331,6 +331,24 @@ def dump_inventory_to_yaml(inventory: dict[str, ResourceIO]) -> str:
331331
)
332332

333333

334+
def where_to_find(resources: list[str] | str) -> str:
335+
"""Return a multiline string describing where each listed resource is output from."""
336+
if isinstance(resources, str):
337+
resources = [resources]
338+
resources = _flatten_io(resources)
339+
inventory = resource_inventory("CPAC")
340+
output = ""
341+
for resource in resources:
342+
output += f"'{resource}' is output from:\n"
343+
if resource in inventory:
344+
for source in inventory[resource].output_from:
345+
output += f" {source}\n"
346+
else:
347+
output += " !! Nowhere !!\n"
348+
output += "\n"
349+
return output.rstrip()
350+
351+
334352
def main() -> None:
335353
"""Save the NodeBlock inventory to a file."""
336354
args = cli_parser()

0 commit comments

Comments
 (0)