reagento / dishka

Cute DI framework with agreeable API and everything you need
https://dishka.readthedocs.io
Apache License 2.0
391 stars 40 forks source link

Add metadata of user-defined code to exceptions #164

Open AbstractiveNord opened 4 months ago

AbstractiveNord commented 4 months ago

As discussed on Podlodka Presentation, traceback have multiple Dishka internal calls between user incorrect code and traceback of exception, for example, dependency loop found. Quite useful to grab a metadata of user code, such as filename and position, and place that information close to ASCII image of dependency loop.

Tishka17 commented 4 months ago

current traceback example:

Traceback (most recent call last):
  File "/home/tishka17/src/dishka/tmp/cycle_2comp.py", line 36, in <module>
    c = make_container(Provider1(), Provider2())
  File "/home/tishka17/src/dishka/src/dishka/container.py", line 184, in make_container
    ).build()
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 365, in build
    GraphValidator(registries).validate()
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 195, in validate
    raise e from None
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 189, in validate
    self._validate_factory(factory, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 170, in _validate_factory
    self._validate_key(dep, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 158, in _validate_key
    self._validate_factory(factory, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 170, in _validate_factory
    self._validate_key(dep, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 158, in _validate_key
    self._validate_factory(factory, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 170, in _validate_factory
    self._validate_key(dep, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 158, in _validate_key
    self._validate_factory(factory, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 170, in _validate_factory
    self._validate_key(dep, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 158, in _validate_key
    self._validate_factory(factory, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 170, in _validate_factory
    self._validate_key(dep, registry_index)
  File "/home/tishka17/src/dishka/src/dishka/registry.py", line 153, in _validate_key
    raise CycleDependenciesError(factories)
dishka.exceptions.CycleDependenciesError: Cycle dependencies detected.
         ~~~ component='', Scope.APP ~~~
    → →  <class '__main__.A'> 
   ↑   ↓ <class 'int'>        Provider1.a1
   ↑   ↓ <class 'float'>      Provider1.a2
   ↑   ↓ <class 'bool'>       Provider1.a3
    ← ←  <class 'complex'>    Provider1.a4
AbstractiveNord commented 4 months ago

Second line of traceback contains the information, which is good to be placed close to Cycle ASCII diagram. For example, it may be like that:

In file "/home/tishka17/src/dishka/tmp/cycle_2comp.py", line 36,
dishka.exceptions.CycleDependenciesError: Cycle dependencies detected.
         ~~~ component='', Scope.APP ~~~
    → →  <class '__main__.A'> 
   ↑   ↓ <class 'int'>        Provider1.a1
   ↑   ↓ <class 'float'>      Provider1.a2
   ↑   ↓ <class 'bool'>       Provider1.a3
    ← ←  <class 'complex'>    Provider1.a4

Or, alternatively:

dishka.exceptions.CycleDependenciesError: Cycle dependencies detected.
         ~~~ component='', Scope.APP ~~~
    → →  <class '__main__.A'> 
   ↑   ↓ <class 'int'>        Provider1.a1
   ↑   ↓ <class 'float'>      Provider1.a2
   ↑   ↓ <class 'bool'>       Provider1.a3
    ← ←  <class 'complex'>    Provider1.a4
Problem is located down to the file "/home/tishka17/src/dishka/tmp/cycle_2comp.py", line 36,
    c = make_container(Provider1(), Provider2())