Skip to main content
drawing By: CenturyBoys

Witch-doctor

A simple dependency injection library for Python

Register

Witch Doctor provides a structured method to register interfaces, implementations, injection types, constructor arguments, and container scopes.

  • It validates the inheritance relationship between the interface and implementation. If there’s a mismatch, a TypeError is raised.

  • The injection type is also validated and must be either "singleton" or "factory".

    • "singleton" returns the same instance on every injection.
    • "factory" creates a new instance for each injection. An invalid type will raise a TypeError.
  • If no arguments are provided, the constructor will be called without parameters.

  • The container_name allows you to isolate dependency registrations by scope, enabling multi-context injection.

class WitchDoctor:
    @classmethod
    def register(
        cls,
        interface: Type[ABC],
        class_ref: Any,
        injection_type: InjectionType,
        args: List[any] = None,
        container: str = DEFAULT,
    ):
        """
        WitchDoctor.register will check inherit of the interface and class_ref.
        Will raise a TypeError on validation error\n
        :param interface: Interface that inherits from ABC
        :param class_ref: A implementation of the interface
        :param injection_type: The injection type that must be used for this register. Allowed Factory or Singleton
        :param args: List of args tha will be used to instantiate the class object
        :param container: Container name where the reference will be saved.
        """
        pass

Container

You can register your injections using containers. The method contianer will provide a container register with the same signature as teh register without the container param. To use the created container you need to load it using load_container. The base work load will set all registers in the DEFAULT group

from abc import ABC, abstractmethod

from witch_doctor import WitchDoctor, InjectionType

class IStubFromABCClass(ABC):
    @abstractmethod
    def sum(self, a: int, b: int):
        pass
    
class StubFromABCClass(IStubFromABCClass):
    def sum(self, a: int, b: int):
        return a + b

container = WitchDoctor.container("prod")
WitchDoctor.register(IStubFromABCClass, StubFromABCClass, InjectionType.SINGLETON)   
WitchDoctor.load_container("prod")

Injection

Witch Doctor can be used as decorator. The function signature will ber check and if some values was not provide Witch Doctor will search on the registered interfaces to inject the dependencies.

class WitchDoctor:
    @classmethod
    def injection(cls, function: Callable):
        """
        WitchDoctor.injection is a function decorator that will match the
        function params signature and inject the  dependencies.
        Will raise AttributeError is some args was pass throw\n

        :type function: Callable
        """
        pass

Usage example

from abc import ABC, abstractmethod

from witch_doctor import WitchDoctor, InjectionType


# Abstract class
class IStubFromABCClass(ABC):
    @abstractmethod
    def sum(self, a: int, b: int):
        pass

    
# Implementation
class StubFromABCClass(IStubFromABCClass):
    def __init__(self, a: int):
        self.a = a

    def sum(self, a: int, b: int):
        return a + b + self.a

# Usage
@WitchDoctor.injection
def func_t(a: int, b: int, c: IStubFromABCClass):
    return c.sum(a, b)

# Containers
container = WitchDoctor.container()
container(IStubFromABCClass, StubFromABCClass, InjectionType.FACTORY, args=[10])

container = WitchDoctor.container("prod")
container(IStubFromABCClass, StubFromABCClass, InjectionType.SINGLETON, args=[20])

# Loading and using
WitchDoctor.load_container()

result_a1 = func_t(a=1, b=2)
result_a2 = func_t(a=2, b=2)

assert result_a1 == 13
assert result_a2 == 14

WitchDoctor.load_container("prod")

result_a1 = func_t(a=1, b=2)
result_a2 = func_t(a=2, b=2)

assert result_a1 == 23
assert result_a2 == 24

Resolve

The resolve method is used to retrieve an instance of a class registered in Witch Doctor. It validates the class signature and searches for the matching implementation based on the registered interfaces. Dependencies are automatically injected.

class WitchDoctor:
    @classmethod
    def resolve(cls, interface: T, container_name: str = CURRENT) -> Type[T]:
        """
        WitchDoctor.resolve will return an instance of the registered class_ref interface.
        Will raise a TypeError if interface is not registered\n
        :param interface: A implementation of the interface
        :param container_name: You can specify the container name to be used by the resolve method
        """
        pass

Usage example

from abc import ABC, abstractmethod

from witch_doctor import WitchDoctor, InjectionType


# Abstract class
class IStubFromABCClass(ABC):
    @abstractmethod
    def sum(self, a: int, b: int):
        pass

    
# Implementation
class StubFromABCClass(IStubFromABCClass):
    def __init__(self, a: int):
        self.a = a

    def sum(self, a: int, b: int):
        return a + b + self.a

# Usage
@WitchDoctor.injection
def func_t(a: int, b: int, c: IStubFromABCClass):
    return c.sum(a, b)

# Containers
container = WitchDoctor.container()
container(IStubFromABCClass, StubFromABCClass, InjectionType.FACTORY, args=[10])

# Loading and using
WitchDoctor.load_container()

result_a1 = WitchDoctor.resolve(IStubFromABCClass)
result_a2 = WitchDoctor.resolve(IStubFromABCClass)

Release files for witch-doctor 1.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for witch-doctor 1.3.1
File Size Uploaded
witch_doctor-1.3.1.tar.gz 8.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for witch-doctor 1.3.1
File Interpreter ABI Platform
witch_doctor-1.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 18.0 kB

Release files / witch_doctor-1.3.1.tar.gz

Download URL witch_doctor-1.3.1.tar.gz
Size 8.6 kB
Tags Source
SHA-256 checksum
How to use checksums
a0d23a68a34091fc91cc25558837f6bd9849e5acbfdfd13dfa84285ac5d5a2fd
BLAKE2b-256 checksum
How to use checksums
a9f500c8f5c9c13df3cca78cf9126753f709dad30013e2cfc854bfef8b5e0366
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.10.19 Linux/6.14.0-1017-azure

Release files / witch_doctor-1.3.1-py3-none-any.whl

Download URL witch_doctor-1.3.1-py3-none-any.whl
Size 9.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
251b1eb76bc1aef65a28e8630e9db750cac6b089e3d787dda401905c3182c36d
BLAKE2b-256 checksum
How to use checksums
6943099e68474d1ea67bb64a1bbfeb453a829acd5234652d82355516e88bbbd3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.10.19 Linux/6.14.0-1017-azure

Release history Release notifications | RSS feed

This release

1.3.1 This release

2 release files

1.3.0

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page