@gen-xu I can not accept the PR: with this change, we generally convert any type of exception to theException . This is a serious API change that can create unexpected problems. I'm thankful for the contribution, but we need to look for another solution to prettify the stack trace.
I fully agree with your concern. The reason why it is hard to debug on errors like that is mainly because cython doesn't add locals variables to the traceback object corresponding to the exception instance.see also: cython docs. So, even with good package liketraceback_with_variables (which basically iterate overException.__traceback__.tb_frame.f_locals to print variables) we wouldn't be able to know the name of the callable object. So I am wondering if adding locals manually to thee.__traceback__.tb_frame.f_locals would work in this case without breaking API. I have added a new commit to the PR. fromdependency_injector.containersimportDeclarativeContainerfromdependency_injector.providersimportCallable,Configuration,SingletonclassA:def__init__(self,config)->None:passclassB:def__init__(self,config)->None:passclassSomeContainer(DeclarativeContainer):config=Configuration()a=Singleton(A,config)b=Singleton(B)c=Callable(print,a,b) For the code example above, after this change, the new stacktrace would be something like this | After | Before |
---|
Traceback (mostrecentcalllast):File"C:\Users\Gen\Repos\python-dependency-injector\exp.py",line20,in<module>s.c()File"src/dependency_injector/providers.pxd",line579,independency_injector.providers.__callreturncall(*args,**kwargs)TypeError:__init__()missing1requiredpositionalargument:'config' | Traceback (mostrecentcalllast):File"C:\Users\Gen\Repos\python-dependency-injector\exp.py",line20,in<module>s.c()File"src/dependency_injector/providers.pyx",line207,independency_injector.providers.Provider.__call__result=self._provide(args,kwargs)File"src/dependency_injector/providers.pyx",line1212,independency_injector.providers.Callable._providereturn__callable_call(self,args,kwargs)File"src/dependency_injector/providers.pxd",line606,independency_injector.providers.__callable_callFile"src/dependency_injector/providers.pxd",line547,independency_injector.providers.__callargs=__provide_positional_args(File"src/dependency_injector/providers.pxd",line390,independency_injector.providers.__provide_positional_argsvalue=__get_value(injection)File"src/dependency_injector/providers.pxd",line345,independency_injector.providers.__get_valuereturnself.__value()File"src/dependency_injector/providers.pyx",line207,independency_injector.providers.Provider.__call__result=self._provide(args,kwargs)File"src/dependency_injector/providers.pyx",line2822,independency_injector.providers.Singleton._provideinstance=__factory_call(self.__instantiator,args,kwargs)File"src/dependency_injector/providers.pxd",line620,independency_injector.providers.__factory_callcdefinlineobject__factory_call(Factoryself,tupleargs,dictkwargs):File"src/dependency_injector/providers.pxd",line606,independency_injector.providers.__callable_callFile"src/dependency_injector/providers.pxd",line579,independency_injector.providers.__callreturncall(*args,**kwargs)TypeError:__init__()missing1requiredpositionalargument:'config' |
and with the help oftraceback_with_variables s=SomeContainer()try:s.c()except:fromtraceback_with_variablesimportprint_excprint_exc() | After | Before |
---|
Tracebackwithvariables (mostrecentcalllast):File"C:\Users\Gen\Repos\python-dependency-injector\exp.py",line21,in<module>s.c()__name__='__main__'__doc__=None__package__=None__loader__=<_frozen_importlib_external.SourceFileLoaderobjectat0x00000248EF47A100>__spec__=None__annotations__= {}__builtins__=<module'builtins' (built-in)>__file__='C:\\Users\\Gen\\Repos\\python-dependency-injector\\exp.py'__cached__=NoneDeclarativeContainer=<class'dependency_injector.containers.DeclarativeContainer'>Callable=<class'dependency_injector.providers.Callable'>Configuration=<class'dependency_injector.providers.Configuration'>Singleton=<class'dependency_injector.providers.Singleton'>print_exc=<functionprint_excat0x00000248F2254EE0>A=<class'__main__.A'>B=<class'__main__.B'>SomeContainer=<class'__main__.SomeContainer'>s=<dependency_injector.containers.DynamicContainerobjectat0x00000248EF9C8FA0>File"src/dependency_injector/providers.pxd",line579,independency_injector.providers.__callreturncall(*args,**kwargs)args= ()call=<class'__main__.B'>context_args= ()context_kwargs= {}e=TypeError("__init__() missing 1 required positional argument: 'config'")injection_args= ()injection_args_len=0injection_kwargs= ()injection_kwargs_len=0is_future_args=Falseis_future_kwargs=Falsekwargs= {}builtins.TypeError:__init__()missing1requiredpositionalargument:'config' | Tracebackwithvariables (mostrecentcalllast):File"src/dependency_injector/providers.pxd",line579,independency_injector.providers.__callreturncall(*args,**kwargs)__name__='dependency_injector.providers'__doc__='Providers module.'__package__='dependency_injector'__loader__=<_frozen_importlib_external.ExtensionFileLoaderobjectat0x000001D78BFA9460>__spec__=ModuleSpec(name='dependency_injector.providers',loader=<_frozen_importlib_external.ExtensionFileLoaderobjectat0x000001D78BFA9460>,origin='C:\\Users\\Gen\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages\\dependency_injector\\providers.cp39-win_amd64.pyd') ...Provider=<class'dependency_injector.providers.Provider'>Object=<class'dependency_injector.providers.Object'>Self=<class'dependency_injector.providers.Self'>Delegate=<class'dependency_injector.providers.Delegate'>Dependency=<class'dependency_injector.providers.Dependency'>ExternalDependency=<class'dependency_injector.providers.ExternalDependency'> ...Error=<class'dependency_injector.errors.Error'>NoSuchProviderError=<class'dependency_injector.errors.NoSuchProviderError'>config_env_marker_pattern=re.compile('\\${(?P<name>[^}^{:]+)(?P<separator>:?)(?P<default>.*?)}')_resolve_config_env_markers=<built-infunction_resolve_config_env_markers>_parse_ini_file=<built-infunction_parse_ini_file>YamlLoader=<class'dependency_injector.providers.YamlLoader'>UNDEFINED=<objectobjectat0x000001D78B518F00>CHILD_PROVIDERS= (<class'dependency_injector.providers.Dependency'>,<class'dependency_injector.providers.DependenciesContainer'>,<class'dependency_injector.providers.Container'>)__add_sys_streams=<built-infunction__add_sys_streams>merge_dicts=<built-infunctionmerge_dicts>traverse=<built-infunctiontraverse>isawaitable=<built-infunctionisawaitable>iscoroutinefunction=<built-infunctioniscoroutinefunction>isasyncgenfunction=<built-infunctionisasyncgenfunction>__pyx_unpickle_Provider=<built-infunction__pyx_unpickle_Provider>__pyx_unpickle_Object=<built-infunction__pyx_unpickle_Object>__pyx_unpickle_Self=<built-infunction__pyx_unpickle_Self> ...__test__= {}builtins.TypeError:__init__()missing1requiredpositionalargument:'config' |
|
This PR addresses#509