Metadata-Version: 1.1
Name: Inject
Version: 3.3.0
Summary: Python dependency injection framework
Home-page: https://github.com/ivankorobkov/python-inject
Author: Ivan Korobkov
Author-email: ivan.korobkov@gmail.com
License: Apache License 2.0
Description: python-inject
        =============
        Dependency injection the python way, the good way. Not a port of Guice or Spring.
        
        Key features
        ------------
        - Fast.
        - Thread-safe.
        - Simple to use.
        - Does not steal class constructors.
        - Does not try to manage your application object graph.
        - Transparently integrates into tests.
        - Supports Python 2.7 and Python 3.3+.
        
        
        Usage
        -----
        Installation::
        
            pip install inject
        
        Example::
        
            # Import the inject module.
            import inject
            
            
            # `inject.instance` requests dependencies from the injector.
            def foo(bar):
                cache = inject.instance(Cache)
                cache.save('bar', bar)
            
            
            # `inject.params` injects dependencies as keyword arguments or positional argument.
            @inject.params(cache=Cache, user=CurrentUser)
            def baz(foo, cache=None, user=None):
                cache.save('foo', foo, user)
         
            # this can be called in different ways:
            # with injected arguments
            baz('foo')
            
            # with positional arguments
            baz('foo', my_cache)
            
            # with keyword arguments
            baz('foo', my_cache, user=current_user)
            
            
            # `inject.param` is deprecated, use `inject.params` instead.
            @inject.param('cache', Cache)
            def bar(foo, cache=None):
                cache.save('foo', foo)
            
            
            # `inject.attr` creates properties (descriptors) which request dependencies on access.
            class User(object):
                cache = inject.attr(Cache)
                        
                def __init__(self, id):
                    self.id = id
        
                def save(self):
                    self.cache.save('users', self)
                
                @classmethod
                def load(cls, id):
                    return cls.cache.load('users', id)
            
            
            # Create an optional configuration.
            def my_config(binder):
                binder.install(my_config2)  # Add bindings from another config.
                binder.bind(Cache, RedisCache('localhost:1234'))
            
            # Configure a shared injector.
            inject.configure(my_config)
            
            
            # Instantiate User as a normal class. Its `cache` dependency is injected when accessed.
            user = User(10)
            user.save()
            
            # Call the functions, the dependencies are automatically injected.
            foo('Hello')
            bar('world')
        
        
        Usage with Django
        -----------------
        Django can load some modules multiple times which can lead to 
        `InjectorException: Injector is already configured`. You can use `configure_once` which
        is guaranteed to run only once when the injector is absent::
        
            import inject
            inject.configure_once(my_config)
        
        
        Testing
        -------
        In tests use ``inject.clear_and_configure(callable)`` to create a new injector on setup,
        and optionally ``inject.clear()`` to clean up on tear down::
            
            class MyTest(unittest.TestCase):
                def setUp(self):
                    inject.clear_and_configure(lambda binder: binder
                        .bind(Cache, Mock() \
                        .bind(Validator, TestValidator())
                
                def tearDown(self):
                    inject.clear()
        
        
        Thread-safety
        -------------
        After configuration the injector is thread-safe and can be safely reused by multiple threads.
        
        Binding types
        -------------
        - Instance bindings always return the same instance::
            
            redis = RedisCache(address='localhost:1234')
            def config(binder):
                binder.bind(Cache, redis)
            
        - Constructor bindings create a singleton on injection::
            
            def config(binder):
                # Creates a redis cache singleton on first injection.
                binder.bind_to_constructor(Cache, lambda: RedisCache(address='localhost:1234'))
        
        - Provider bindings call the provider on injection::
        
            def get_my_thread_local_cache():
                pass
        
            def config(binder):
                # Executes the provider on each injection.
                binder.bind_to_provider(Cache, get_my_thread_local_cache) 
        
        - Runtime bindings automatically create singletons on injection, require no configuration.
          For example, only the ``Config`` class binding is present, other bindings are runtime::
        
            class Config(object):
                pass
            
            class Cache(object):
                config = inject.attr(Config)
            
            class Db(object):
                config = inject.attr(Config)
            
            class User(object):
                cache = inject.attr(Cache)
                db = inject.attr(Db)
                
                @classmethod
                def load(cls, user_id):
                    return cls.cache.load('users', user_id) or cls.db.load('users', user_id)
             
            inject.configure(lambda binder: binder.bind(Config, load_config_file()))
            user = User.load(10)
        
        Keys
        ----
        It is possible to use any hashable object as a binding key.
        For example::
            
            import inject
            
            inject.configure(lambda binder: \
                binder.bind('host', 'localhost') \
                binder.bind('port', 1234))
        
        
        Why no scopes?
        --------------
        I've used Guice and Spring in Java for a lot of years, and I don't like their scopes.
        ``python-inject`` by default creates objects as singletons. It does not need a prototype scope
        as in Spring or NO_SCOPE as in Guice because ``python-inject`` does not steal your class 
        constructors. Create instances the way you like and then inject dependencies into them.
        
        Other scopes such as a request scope or a session scope are fragile, introduce high coupling,
        and are difficult to test. In ``python-inject`` write custom providers which can be thread-local, 
        request-local, etc.
        
        For example, a thread-local current user provider::
        
            import inject
            import threading
            
            # Given a user class.
            class User(object):
                pass
            
            # Create a thread-local current user storage.
            _LOCAL = threading.local()
            
            def get_current_user():
                return getattr(_LOCAL, 'user', None)
            
            def set_current_user(user):
                _LOCAL.user = user
            
            # Bind User to a custom provider.
            inject.configure(lambda binder: binder.bind_to_provider(User, get_current_user))
            
            # Inject the current user.
            @inject.params(user=User)
            def foo(user):
                pass
        
        
        Links
        -----
        - Project: https://github.com/ivankorobkov/python-inject
        
        License
        -------
        Apache License 2.0
        
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
