diff --git a/metaflow/parameters.py b/metaflow/parameters.py index 862c94555b..b91e5efdde 100644 --- a/metaflow/parameters.py +++ b/metaflow/parameters.py @@ -369,7 +369,7 @@ def init(self, ignore_errors=False): # Resolve any value from configurations self.kwargs = unpack_delayed_evaluator(self.kwargs, ignore_errors=ignore_errors) # Do it one item at a time so errors are ignored at that level (as opposed to - # at the entire kwargs leve) + # at the entire kwargs level) self.kwargs = { k: resolve_delayed_evaluator(v, ignore_errors=ignore_errors) for k, v in self.kwargs.items() diff --git a/metaflow/user_configs/config_parameters.py b/metaflow/user_configs/config_parameters.py index cbb36ae296..6c5315c6bc 100644 --- a/metaflow/user_configs/config_parameters.py +++ b/metaflow/user_configs/config_parameters.py @@ -183,7 +183,7 @@ def __len__(self): def __getattr__(self, name): if self._access is None: - raise AttributeError() + raise AttributeError(name) self._access.append(name) return self @@ -350,16 +350,20 @@ def __getattr__(self, name): # Next three methods are to implement mapping to support ** syntax def __iter__(self): - return iter(DelayEvaluator(self.name.lower())) + yield "%s%s" % (UNPACK_KEY, id(self)) def __len__(self): - return len(DelayEvaluator(self.name.lower())) + return 1 def __getitem__(self, key): - return DelayEvaluator(self.name.lower())[key] + if key == "%s%d" % (UNPACK_KEY, id(self)): + return DelayEvaluator(self.name.lower()) + raise KeyError(key) def resolve_delayed_evaluator(v: Any, ignore_errors: bool = False) -> Any: + # NOTE: We don't ignore errors in downstream calls because we want to have either + # all or nothing for the top-level call by the user. try: if isinstance(v, DelayEvaluator): return v() @@ -397,7 +401,7 @@ def unpack_delayed_evaluator( else: # k.startswith(UNPACK_KEY) try: - result.update(resolve_delayed_evaluator(v[k])) + result.update(resolve_delayed_evaluator(v)) except Exception as e: if ignore_errors: continue