Skip to content

Commit ae04b8d

Browse files
committed
🎨 Clean up Configuration syntax
1 parent 4981141 commit ae04b8d

File tree

1 file changed

+49
-26
lines changed

1 file changed

+49
-26
lines changed

CPAC/utils/configuration/configuration.py

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616
# License along with C-PAC. If not, see <https://www.gnu.org/licenses/>.
1717
"""C-PAC Configuration class and related functions."""
1818

19-
from collections.abc import Iterable
19+
from collections.abc import Iterable, KeysView
20+
from importlib.resources import files
2021
import os
2122
import re
2223
from typing import Any, cast, Literal, Optional, overload
2324
from warnings import warn
2425

2526
from click import BadParameter
26-
import pkg_resources as p
2727
import yaml
2828

2929
from CPAC.pipeline.nipype_pipeline_engine import MapNode, Node
30-
from .diff import dct_diff
30+
from .diff import dct_diff, DiffDict
3131

3232
CONFIG_KEY_TYPE = str | list[str]
3333
_DICT = dict
@@ -48,6 +48,10 @@ def __init__(self):
4848
class NestedKeyMixin:
4949
"""Provide methods for getting and setting nested keys."""
5050

51+
def dict(self) -> dict[Any, Any]:
52+
"""Show contents as a dict."""
53+
return {k: v for k, v in self.__dict__.items() if not callable(v)}
54+
5155
def __contains__(self, item: str | list[Any]) -> bool:
5256
"""Check if an item is in the Configuration."""
5357
if isinstance(item, str):
@@ -59,7 +63,7 @@ def __contains__(self, item: str | list[Any]) -> bool:
5963
return False
6064

6165
def __getitem__(self, key: Iterable) -> Any:
62-
"""Get an item from a Configuration."""
66+
"""Get an item from a nested dictionary."""
6367
self._check_keys(key)
6468
if isinstance(key, str):
6569
return getattr(self, key)
@@ -69,7 +73,7 @@ def __getitem__(self, key: Iterable) -> Any:
6973
return None
7074

7175
def __setitem__(self, key: Iterable, value: Any) -> None:
72-
"""Set an item in a Configuration."""
76+
"""Set an item in a nested dictionary."""
7377
self._check_keys(key)
7478
if isinstance(key, str):
7579
setattr(self, key, value)
@@ -78,8 +82,8 @@ def __setitem__(self, key: Iterable, value: Any) -> None:
7882
else:
7983
self.key_type_error(key)
8084

81-
def __sub__(self: "Configuration", other: "Configuration"):
82-
"""Return the set difference between two Configurations.
85+
def __sub__(self: "NestedKeyMixin", other: "NestedKeyMixin") -> DiffDict:
86+
"""Return the set difference between two nested dictionaries.
8387
8488
Examples
8589
--------
@@ -133,7 +137,7 @@ def _nonestr_to_None(self, d):
133137
if isinstance(d, list):
134138
return [self._nonestr_to_None(i) for i in d]
135139
if isinstance(d, set):
136-
return {self._nonestr_to_None(i) for i in d}
140+
return {self._nonestr_to_None(i) for i in list(d)}
137141
if isinstance(d, dict):
138142
return {i: self._nonestr_to_None(d[i]) for i in d}
139143
return d
@@ -150,7 +154,7 @@ def _check_keys(keys: Iterable) -> None:
150154
msg = f"`set_nested` keys must be iterable, got {type(keys)}."
151155
raise error(msg)
152156

153-
def get_nested(self, _d: "Configuration | _DICT", keys: Iterable) -> Any:
157+
def get_nested(self, _d: "NestedKeyMixin | _DICT", keys: Iterable) -> Any:
154158
"""Get a value from a Configuration dictionary given a nested key."""
155159
self._check_keys(keys)
156160
if _d is None:
@@ -164,16 +168,20 @@ def get_nested(self, _d: "Configuration | _DICT", keys: Iterable) -> Any:
164168
return _d[keys[0]]
165169
return _d
166170

171+
def keys(self) -> KeysView[Any]:
172+
"""Show toplevel keys of a nested dict."""
173+
return self.dict().keys()
174+
167175
@overload
168176
def set_nested(
169-
self, d: "Configuration", keys: Iterable, value: Any
170-
) -> "Configuration": ...
177+
self, d: "NestedKeyMixin", keys: Iterable, value: Any
178+
) -> "NestedKeyMixin": ...
171179
@overload
172180
def set_nested(self, d: _DICT, keys: Iterable, value: Any) -> _DICT: ...
173181
def set_nested(
174-
self, d: "Configuration | _DICT", keys: Iterable, value: Any
175-
) -> "Configuration | _DICT":
176-
"""Set a nested key in a Configuration dictionary."""
182+
self, d: "NestedKeyMixin | _DICT", keys: Iterable, value: Any
183+
) -> "NestedKeyMixin | _DICT":
184+
"""Set a nested key in a nested dictionary."""
177185
self._check_keys(keys)
178186
if isinstance(keys, str):
179187
d[keys] = value
@@ -435,6 +443,25 @@ class Configuration(NestedKeyMixin):
435443
'slack_420349_preconfig'
436444
"""
437445

446+
amplitude_low_frequency_fluctuation: dict
447+
anatomical_preproc: dict
448+
FROM: str
449+
functional_preproc: dict
450+
longitudinal_template_generation: dict
451+
network_centrality: dict
452+
nuisance_corrections: dict
453+
pipeline_setup: dict
454+
post_processing: dict
455+
PyPEER: dict
456+
regional_homogeneity: dict
457+
registration_workflows: dict
458+
seed_based_correlation_analysis: dict
459+
segmentation: dict
460+
skip_env_check: bool
461+
surface_analysis: dict
462+
timeseries_extraction: dict
463+
voxel_mirrored_homotopic_connectivity: dict
464+
438465
def __init__(
439466
self, config_map: Optional[dict] = None, skip_env_check: bool = False
440467
) -> None:
@@ -490,6 +517,7 @@ def __init__(
490517
regressor["Name"] = nipype_friendly_name(regressor["Name"])
491518

492519
config_map = schema(config_map)
520+
assert isinstance(config_map, dict)
493521

494522
# remove 'skip env check' now that the config is validated
495523
if "skip env check" in config_map:
@@ -525,15 +553,12 @@ def __repr__(self):
525553
return str(self.dict())
526554

527555
def __copy__(self):
556+
"""Copy a pipeline Configuration."""
528557
newone = type(self)({})
529558
newone.__dict__.update(self.__dict__)
530559
newone._update_attr()
531560
return newone
532561

533-
def dict(self) -> dict[Any, Any]:
534-
"""Show contents of a C-PAC configuration as a dict."""
535-
return {k: v for k, v in self.__dict__.items() if not callable(v)}
536-
537562
def get(self, key: Any, default: Any = None, /) -> Any:
538563
"""Provide convenience access from `Configuration` to :meth:`dict.get` .
539564
@@ -549,10 +574,6 @@ def get(self, key: Any, default: Any = None, /) -> Any:
549574
"""
550575
return self.dict().get(key, default)
551576

552-
def keys(self):
553-
"""Show toplevel keys of a C-PAC configuration dict."""
554-
return self.dict().keys()
555-
556577
def set_from_ENV(self, conf): # pylint: disable=invalid-name
557578
"""Replace strings like $VAR and ${VAR} with environment variable values.
558579
@@ -625,9 +646,11 @@ def set_without_ENV(self, conf): # pylint: disable=invalid-name
625646
return conf
626647

627648
def sub_pattern(self, pattern, orig_key):
649+
"""Make a defined pattern substitution."""
628650
return orig_key.replace(pattern, self[pattern[2:-1].split(".")])
629651

630652
def check_pattern(self, orig_key, tags=None):
653+
"""Make defined pattern substitutions."""
631654
if tags is None:
632655
tags = []
633656
if isinstance(orig_key, dict):
@@ -681,6 +704,7 @@ def check_path(key):
681704
setattr(self, attr_key, new_key)
682705

683706
def update(self, key, val=ConfigurationDictUpdateConflation()):
707+
"""Update a C-PAC pipeline Configuration."""
684708
if isinstance(key, dict):
685709
raise ConfigurationDictUpdateConflation
686710
if isinstance(val, Exception):
@@ -704,7 +728,7 @@ def orientation_node(
704728
return orientation_node(name=name, orientation=orientation, node_type=node_type)
705729

706730

707-
def check_pname(p_name: str, pipe_config: Configuration) -> str:
731+
def check_pname(p_name: Optional[str], pipe_config: Configuration) -> str:
708732
"""Check / set `p_name`, the str representation of a pipeline for use in filetrees.
709733
710734
Parameters
@@ -816,9 +840,8 @@ def preconfig_yaml(preconfig_name="default", load=False):
816840
if load:
817841
with open(preconfig_yaml(preconfig_name), "r", encoding="utf-8") as _f:
818842
return yaml.safe_load(_f)
819-
return p.resource_filename(
820-
"CPAC",
821-
os.path.join("resources", "configs", f"pipeline_config_{preconfig_name}.yml"),
843+
return files("CPAC").joinpath(
844+
f"resources/configs/pipeline_config_{preconfig_name}.yml"
822845
)
823846

824847

0 commit comments

Comments
 (0)