Skip to main content

This package provides a simple inversion-of-control container.

Install with

pip install pythonioc

Quick Start

The main idea is: services are registered to a service-registry and can be injected into users of that service (which can of course be services themselves).

You have two options:

  1. use a global registry (never create a registry yourself)

  2. use a local registry

Examples are below, more details will follow.

Global Registry

import pythonioc

# register your service with a default name (here: 'someService', see Notes On Names)
@pythonioc.Service
class SomeService(object):

    # called when the service is auto-instantiated.
    def postInit(self):
        pass

@pythonioc.NamedService('DifferentNameService')
class DifferentService(object):
    pass

# for classes which we cannot decorate:
pythonioc.registerService(ExternalService)

# when we don't even have the class (or don't care about lazy-initialization)
pythonioc.registerServiceInstance(SomeService())


class ServiceUser(object):
    # inject the dependency by class
    service = pythonioc.Inject(SomeService)

    # inject the dependency by name (for cyclic dependencies)
    service2 = pythonioc.Inject('DifferentNameService')


 myUser = ServiceUser()

 myUser.service # --> automatically created and injected service instance.

 # explicitly get a service
 pythonioc.getService(SomeService)
 pythonioc.getService('DifferentNameService')

Local Registry

class Service(object):

    # this will make the service registry inject a service named "someOtherService" which
    # comes from class SomeOtherService
    _someOtherService = None

    def __init__(self):
        pass

    # will be called after everything is injected
    def postInit(self):
        pass

    # will be called right before the object is destroyed (the registry's clean
    # method is called)
    def preDestroy(self):
        pass



class SomeOtherService(object):
    pass

# let's register our services
reg = ServiceRegistry()
reg.registerService(Service)
reg.registerService(SomeOtherService)

Once everything is registered, a service can be injected by

class WiredUser(object):

    _service=None

    def __init__(self, *args):
        pass

wiredUser = reg.createWired(WiredUser, 'arg1', 'arg2')

Wired objects are not automatically part of the service registry, only if added by calling reg.registerServiceInstance.

Wired objects can inject their own service registry, so they can create wired objects on the fly:

class WiredUser(object):
    _service=None


class UserCreator(object):
    _serviceRegistry=None

    def createUser(self):
        return self._serviceRegistry.createWired(WiredUser)

userCreator = reg.createWired(UserCreator)

# create some wired users
userA = userCreator.createUser()
userB = userCreator.createUser()

Notes on Names

Services added to the registry need a name. If no name is provided, the class’ name (or the instance’s class name) is used. The name’s first character is lowered by convention.

Example:

import pythonioc

class MyService(object):
    pass

pythonioc.registerService(MyService)            # --> name is 'myService'
pythonioc.registerServiceInstance(MyService())  # --> name is 'myService'
pythonioc.registerService(MyService, serviceName='customName') # --> name is 'customName'
pythonioc.registerServiceInstance(MyService(), serviceName='customName2')  # --> name is 'customName2'

Notes on Dependency Cycles

Generally, dependency cycles are resolved by lazily initializing services. Critical cycles can still occur, when two services depend on each other within their postInit-methods that are executed after initialization. Those cycles are detected by keeping track of the currently running postInit methods and throwing an exception.

The service creation is thread safe, so accessing a non-initialized service with a long-running init or postInit method from two different threads will block one of the threads.

Bugs

Bug reports, suggestions for improvements etc. are always welcome!

Release files for pythonioc 0.4.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 pythonioc 0.4.1
File Size Uploaded
pythonioc-0.4.1.tar.gz 10.5 kB Details

Release files / pythonioc-0.4.1.tar.gz

Download URL pythonioc-0.4.1.tar.gz
Size 10.5 kB
Tags Source
SHA-256 checksum
How to use checksums
57790a1a39a7daa8a6a9cd4981b94676c80cfa5456112e91a371dc93a2097c9f
BLAKE2b-256 checksum
How to use checksums
ba5f6bcbf40e2539278ec60488117b25c39d67ccd98cf00d4ef99af0385f03fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

0.4.1 This release

1 release file

0.4.0

1 release file

0.3.2

1 release file

0.3.1

1 release file

0.3.0

1 release file

0.2.8

1 release file

0.2.7

1 release file

0.2.6

1 release file

0.2.5

1 release file

0.2.4

1 release file

0.2.3

1 release file

0.2.2

1 release file

0.2.1

1 release file

0.2

1 release file

0.1

1 release file

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