@@ -128,6 +128,8 @@ def resolve(cfg, *, freeze=True):
128128 Returns:
129129 The resolved config.
130130 """
131+ # Hide the function from the traceback (in Pytest and IPython 7).
132+ __tracebackhide__ = True # pylint: disable=unused-variable,invalid-name
131133
132134 # Check if the config has a `_konfig_experimental_nofreeze` key.
133135 # TODO(klausg): make freeze=False the default and remove this.
@@ -140,6 +142,7 @@ def resolve(cfg, *, freeze=True):
140142 return _ConstructorResolver (freeze = freeze )._resolve_value (cfg ) # pylint: disable=protected-access
141143 except Exception as e : # pylint: disable=broad-exception-caught
142144 logging .info (f'Full config (failing): { cfg } ' ) # pylint: disable=logging-fstring-interpolation
145+ utils .filter_traceback (e .__traceback__ )
143146 epy .reraise (e , 'Error resolving the config:\n ' )
144147
145148
@@ -250,8 +253,11 @@ def _resolve_dict(self, value):
250253 for k , v in kwargs .items ()
251254 }
252255 args = [kwargs .pop (str (i )) for i in range (num_args (kwargs ))]
253- with epy . maybe_reraise ( prefix = lambda : _make_cfg_error_msg ( value )) :
256+ try :
254257 obj = constructor (* args , ** kwargs )
258+ except Exception as e : # pylint: disable=broad-exception-caught
259+ e = _wrap_cfg_error (e , value , frame = value ._frame ) # pylint: disable=protected-access
260+ raise e from e .__cause__
255261 # Allow the object to save the config it is comming from.
256262 if hasattr (type (obj ), '__post_konfig_resolve__' ):
257263 obj .__post_konfig_resolve__ (value )
@@ -283,12 +289,40 @@ def num_args(obj: Mapping[str, Any]) -> int:
283289 return arg_id # pylint: disable=undefined-loop-variable,undefined-variable
284290
285291
286- def _make_cfg_error_msg (cfg : ml_collections .ConfigDict ) -> str :
292+ def _wrap_cfg_error (
293+ e : Exception ,
294+ cfg : ml_collections .ConfigDict ,
295+ frame : utils .FrameStack ,
296+ ) -> Exception :
297+ """Wrap the exception with the config information."""
287298 cfg_str = repr (cfg )
288299 cfg_str = cfg_str .removeprefix ('<ConfigDict[' ).removesuffix (']>' )
289300 if len (cfg_str ) > 300 : # `textwrap.shorten` remove `\n` so don't use it
290301 cfg_str = cfg_str [:295 ] + '[...]'
291- return f'Error while constructing cfg: { cfg_str } \n '
302+ msg = (
303+ f'For: { cfg_str } \n '
304+ 'Look at the the exception cause above to see where the ConfigDict'
305+ ' was created.\n '
306+ '======================================================================\n '
307+ )
308+
309+ cause = ValueError ('The ConfigDict was created here.' ).with_traceback (
310+ frame .as_traceback ()
311+ )
312+
313+ # Backward compatibility.
314+ if not hasattr (epy .reraise_utils , 'wrap_error' ):
315+ try :
316+ epy .reraise (e , prefix = msg )
317+ except Exception as exc : # pylint: disable=broad-exception-caught
318+ e = exc
319+ else :
320+ e = epy .reraise_utils .wrap_error (e , prefix = msg )
321+
322+ while e .__cause__ is not None :
323+ e = e .__cause__
324+ e .__cause__ = cause
325+ return e
292326
293327
294328def _as_dict (values : Mapping [str , Any ]) -> dict [str , Any ]:
0 commit comments