A simple, lightweight Python Dependency Injection Container (IOC), inspired by Pimple
Project description
Medley is a simple, lightweight Dependency Injection Container for Python, inspired by [Pimple](https://github.com/silexphp/Pimple).
Requirements
------------
Medley requires Python >=2.7 or Python >=3.2
[![Build Status](https://travis-ci.org/illumine-interactive/medley.svg?branch=master)](https://travis-ci.org/illumine-interactive/medley)
Installation
------------
Install Medley using pip
```bash
$ pip install medley
```
Usage
-----
Build your container by creating a ``MedleyContainer`` instance:
```python
from medley import MedleyContainer
container = MedleyContainer()
```
Medley manages two different kind of data: **services** and **parameters**.
Defining Services
-----------------
A service is an object that does something as part of a larger system. Examples
of services: a database connection, a templating engine, or a mailer. Almost
any **global** object can be a service.
Services are defined by **functions and lambdas** that return an instance of an
object:
Example using **lambdas**:
```python
# define some services
container['session_storage'] = lambda c: SessionStorage('SESSION_ID')
container['session'] = lambda c: Session(c['session_storage'])
```
Notice that service definition functions do require the container argument.
Lambdas must have access to the current container instance, allowing references
to other services or parameters.
A **service decorator** is also available to wrap defined functions as a service
```python
@container.service('session_storage')
def session_storage(c):
return SessionStorage('SESSION_ID')
@container.service('session')
def session(c):
return Session(c['session_storage'])
```
Objects are **lazy-loaded**, so the order in which you define services
does not matter.
Getting a defined service is easy:
```python
session = container['session']
# the above call is roughly equivalent to the following code:
# storage = SessionStorage('SESSION_ID')
# session = Session(storage)
```
Defining Factory Services
-------------------------
By default, each time you get a service, Medley returns the **same instance**
of it. If you want a different instance to be returned for all calls, wrap your
anonymous function with the ``factory()`` method
```python
container['session'] = container.factory(lambda c: Session(c['session_storage']))
# you may also use a decorator
@container.create_factory('session')
def session(c):
return Session(c['session_storage'])
```
Now, each call to ``container['session']`` returns a new instance of the
session.
Defining Parameters
-------------------
Defining a parameter allows to ease the configuration of your container from
the outside and to store global values:
``` python
# define some parameters
container['cookie_name'] = 'SESSION_ID';
container['session_storage_class'] = 'SessionStorage';
```
If you change the ``session_storage`` service definition like below:
```python
container['session_storage'] = lambda c: c['session_storage_class'](c['cookie_name'])
```
You can now easily change the cookie name by overriding the
``cookie_name`` parameter instead of redefining the service
definition.
Protecting Parameters
---------------------
Because Medley sees lambdas as service definitions, you need to
wrap lambdas with the ``protect()`` method to store them as
parameters:
``` python
from random import random
container['random_func'] = container.protect(lambda: random())
```
Modifying Services after Definition
-----------------------------------
In some cases you may want to modify a service definition after it has been
defined. You can use the ``extend()`` method to define additional code to be
run on your service just after it is created:
```python
container['session_storage'] = lambda c: c['session_storage_class'](c['cookie_name'])
container.extend('session_storage' lambda storage, c: storage.some_call()
```
The first argument of the lambda is the name of the service to extend, the
second a function that gets access to the object instance and the container.
The available **extends** decorator is usually more user-friendly when extending
definitions, particularly when a service needs to be modified and returned
```python
@container.service('session_storage')
def session_storage(c):
return c['session_storage_class'](c['cookie_name'])
@container.extends('session_storage')
def extended_session_storage(storage, c):
storage.some_call()
return storage
```
Extending a Container
---------------------
You can build a set of libraries with Medley using the Providers. You might want
to reuse some services from one project to the next one; package your services
into a **provider** by implementing ``medley.ServiceProviderInterface``:
```python
from medley import MedleyContainer, ServiceProviderInterface
class FooProvider(ServiceProviderInterface):
def register(container: MedleyContainer):
# register some services and parameters on container
container['foo'] = lambda c: return 'bar'
```
Then, register the provider on a MedleyContainer:
```python
container.register(FooProvider())
```
Fetching the Service Creation Function
--------------------------------------
When you access an object via ```container['some_id']```, Medley automatically
calls the function that you defined, which creates the service object for you.
If you want to get raw access to this function, you can use the ``raw()``
method:
```python
container['session'] = lambda c: Session(c['session_storage'])
session_function = container.raw('session')
```
Requirements
------------
Medley requires Python >=2.7 or Python >=3.2
[![Build Status](https://travis-ci.org/illumine-interactive/medley.svg?branch=master)](https://travis-ci.org/illumine-interactive/medley)
Installation
------------
Install Medley using pip
```bash
$ pip install medley
```
Usage
-----
Build your container by creating a ``MedleyContainer`` instance:
```python
from medley import MedleyContainer
container = MedleyContainer()
```
Medley manages two different kind of data: **services** and **parameters**.
Defining Services
-----------------
A service is an object that does something as part of a larger system. Examples
of services: a database connection, a templating engine, or a mailer. Almost
any **global** object can be a service.
Services are defined by **functions and lambdas** that return an instance of an
object:
Example using **lambdas**:
```python
# define some services
container['session_storage'] = lambda c: SessionStorage('SESSION_ID')
container['session'] = lambda c: Session(c['session_storage'])
```
Notice that service definition functions do require the container argument.
Lambdas must have access to the current container instance, allowing references
to other services or parameters.
A **service decorator** is also available to wrap defined functions as a service
```python
@container.service('session_storage')
def session_storage(c):
return SessionStorage('SESSION_ID')
@container.service('session')
def session(c):
return Session(c['session_storage'])
```
Objects are **lazy-loaded**, so the order in which you define services
does not matter.
Getting a defined service is easy:
```python
session = container['session']
# the above call is roughly equivalent to the following code:
# storage = SessionStorage('SESSION_ID')
# session = Session(storage)
```
Defining Factory Services
-------------------------
By default, each time you get a service, Medley returns the **same instance**
of it. If you want a different instance to be returned for all calls, wrap your
anonymous function with the ``factory()`` method
```python
container['session'] = container.factory(lambda c: Session(c['session_storage']))
# you may also use a decorator
@container.create_factory('session')
def session(c):
return Session(c['session_storage'])
```
Now, each call to ``container['session']`` returns a new instance of the
session.
Defining Parameters
-------------------
Defining a parameter allows to ease the configuration of your container from
the outside and to store global values:
``` python
# define some parameters
container['cookie_name'] = 'SESSION_ID';
container['session_storage_class'] = 'SessionStorage';
```
If you change the ``session_storage`` service definition like below:
```python
container['session_storage'] = lambda c: c['session_storage_class'](c['cookie_name'])
```
You can now easily change the cookie name by overriding the
``cookie_name`` parameter instead of redefining the service
definition.
Protecting Parameters
---------------------
Because Medley sees lambdas as service definitions, you need to
wrap lambdas with the ``protect()`` method to store them as
parameters:
``` python
from random import random
container['random_func'] = container.protect(lambda: random())
```
Modifying Services after Definition
-----------------------------------
In some cases you may want to modify a service definition after it has been
defined. You can use the ``extend()`` method to define additional code to be
run on your service just after it is created:
```python
container['session_storage'] = lambda c: c['session_storage_class'](c['cookie_name'])
container.extend('session_storage' lambda storage, c: storage.some_call()
```
The first argument of the lambda is the name of the service to extend, the
second a function that gets access to the object instance and the container.
The available **extends** decorator is usually more user-friendly when extending
definitions, particularly when a service needs to be modified and returned
```python
@container.service('session_storage')
def session_storage(c):
return c['session_storage_class'](c['cookie_name'])
@container.extends('session_storage')
def extended_session_storage(storage, c):
storage.some_call()
return storage
```
Extending a Container
---------------------
You can build a set of libraries with Medley using the Providers. You might want
to reuse some services from one project to the next one; package your services
into a **provider** by implementing ``medley.ServiceProviderInterface``:
```python
from medley import MedleyContainer, ServiceProviderInterface
class FooProvider(ServiceProviderInterface):
def register(container: MedleyContainer):
# register some services and parameters on container
container['foo'] = lambda c: return 'bar'
```
Then, register the provider on a MedleyContainer:
```python
container.register(FooProvider())
```
Fetching the Service Creation Function
--------------------------------------
When you access an object via ```container['some_id']```, Medley automatically
calls the function that you defined, which creates the service object for you.
If you want to get raw access to this function, you can use the ``raw()``
method:
```python
container['session'] = lambda c: Session(c['session_storage'])
session_function = container.raw('session')
```
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
medley-1.0.0.tar.gz
(4.8 kB
view details)
Built Distributions
File details
Details for the file medley-1.0.0.tar.gz
.
File metadata
- Download URL: medley-1.0.0.tar.gz
- Upload date:
- Size: 4.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 36777a321a72d43cfd5101246c2f4fdb703ca7ca775073dd50e221f5b71a6a91 |
|
MD5 | 367e016645c11d09372e74abedd53485 |
|
BLAKE2b-256 | d77102dc8a0fa3bf4c8f0b6d5c2886d83c95fca8f38064d44961df46ceeb2a08 |
File details
Details for the file medley-1.0.0-py3-none-any.whl
.
File metadata
- Download URL: medley-1.0.0-py3-none-any.whl
- Upload date:
- Size: 5.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 68c2171f9db0bec0e99fb9a75725d726240f8ba865609addad12eda7cb51c59e |
|
MD5 | b3b986eda3b2df078ca70c8a506481af |
|
BLAKE2b-256 | 6cc68e96475a8ace39fabff2b94376ce13efc0b726b4398d16053c828763f9fa |
File details
Details for the file medley-1.0.0-py2-none-any.whl
.
File metadata
- Download URL: medley-1.0.0-py2-none-any.whl
- Upload date:
- Size: 5.1 kB
- Tags: Python 2
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a21c106bc0fc373c35f50d9034e0758da71b6cd29125a5a927d584e3f0aeea58 |
|
MD5 | 16ead85f9f8ba36144bd269f6dccc6ac |
|
BLAKE2b-256 | 60687b267dc42f4dbbc5fbe313398139b7424b527ca76ae3c68f5dd2630e4634 |