Debugging

You made it to the final chapter. You’re no longer just a user — you’re a practitioner of FunDI!

Testing is good, but debugging is what separates the script kiddie from the software monk

FunDI provides useful functions to help you debug and optimize your dependency injection:
  • tree — Generates a tree that shows how dependencies will be resolved — including resolution order and value mapping.

    from fundi import Scope, tree, scan
    
    print(tree(Scope({"username": "user"}), scan(application)))
    

    Outputs:

    {'call': <function application at ...>, 'values': {'username': 'user', 'user': {'call': <function require_user at ...>, 'values': {'username': 'user'}}}}
    

    Each node contains the function being called (call) and the values being injected into it (values).

  • order — generates list that contains order in which dependencies will be called.

    Note: Result does not include function that is being passed to order function.

    from fundi import Scope, order, scan
    
    print(order(Scope({"username": "user"}), scan(application)))
    

    Outputs:

    [<function require_user at ...>]
    

    Want more details? Try tree(). Want less pain? Good luck.

Exceptions

During injection an exception may be raised, so you should understand why it happens.

Scope value not found

If the scope does not contain the value required by a dependency — FunDI will raise ScopeValueNotFoundError

Tracing

FunDI helps you understand direct cause of exceptions and place where did they happen — library adds its injection trace to exception.

from contextlib import ExitStack

from fundi import Scope, from_, scan, inject, injection_trace


def require_random_animal() -> str:
    raise ConnectionRefusedError("Failed to connect to server :<")
    return random.choice(["cat", "dog", "chicken", "horse", "platypus", "cow"])


def application(
    animal: str = from_(require_random_animal),
):
    print("Animal:", animal)


try:
    inject(Scope(), scan(application))
except Exception as e:
    print(injection_trace(e))

Output would be:

InjectionTrace(info=CallableInfo(call=<function application at ...>, ...), values={}, origin=InjectionTrace(info=CallableInfo(call=<function require_random_animal at ...>, ...), values={}, origin=None))