mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-10-31 16:07:51 +03:00 
			
		
		
		
	Merge pull request #142 from ets-labs/138_cython_injections
Add injections extension
This commit is contained in:
		
						commit
						55cde4729d
					
				|  | @ -1,6 +1,7 @@ | |||
| [run] | ||||
| include = dependency_injector/* | ||||
| omit = tests/* | ||||
| source = src/dependency_injector | ||||
| omit = tests/unit | ||||
| plugins = Cython.Coverage | ||||
| 
 | ||||
| [html] | ||||
| directory=reports/unittests/ | ||||
|  |  | |||
							
								
								
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -63,7 +63,7 @@ venv/ | |||
| .ropeproject/ | ||||
| 
 | ||||
| # C extensions | ||||
| dependency_injector/*.c | ||||
| dependency_injector/*.so | ||||
| dependency_injector/providers/*.c | ||||
| dependency_injector/providers/*.so | ||||
| src/dependency_injector/*.c | ||||
| src/dependency_injector/*.so | ||||
| src/dependency_injector/providers/*.c | ||||
| src/dependency_injector/providers/*.so | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| # Add <file or directory> to the black list. It should be a base name, not a | ||||
| # path. You may set this option multiple times. | ||||
| ignore=utils,test | ||||
| ignore=utils,tests | ||||
| 
 | ||||
| [MESSAGES CONTROL] | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										10
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.travis.yml
									
									
									
									
									
								
							|  | @ -1,11 +1,15 @@ | |||
| sudo: false | ||||
| install:  | ||||
|     - pip install tox | ||||
|     - pip install cython | ||||
|     - make cythonize | ||||
| script:  | ||||
|     - tox | ||||
| language: python | ||||
| install: pip install tox | ||||
| script: tox | ||||
| python: | ||||
|     - 3.5 | ||||
| env: | ||||
|   - TOXENV=coveralls | ||||
|     - TOXENV=coveralls DEPENDENCY_INJECTOR_DEBUG_MODE=1 | ||||
|     - TOXENV=pylint | ||||
|     - TOXENV=flake8 | ||||
|     - TOXENV=pydocstyle | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| include dependency_injector/* | ||||
| recursive-include src/dependency_injector *.py *.pyx *.pxd *.c | ||||
| include README.rst | ||||
| include CONTRIBUTORS.rst | ||||
| include LICENSE.rst | ||||
|  |  | |||
							
								
								
									
										51
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								Makefile
									
									
									
									
									
								
							|  | @ -1,11 +1,22 @@ | |||
| VERSION:=$(shell python setup.py --version) | ||||
| VERSION := $(shell python setup.py --version) | ||||
| 
 | ||||
| CYTHON_SRC := $(shell find src/dependency_injector -name '*.pyx') | ||||
| 
 | ||||
| CYTHON_DIRECTIVES = | ||||
| 
 | ||||
| ifdef DEPENDENCY_INJECTOR_DEBUG_MODE | ||||
| 	CYTHON_DIRECTIVES += -Xprofile=True | ||||
| 	CYTHON_DIRECTIVES += -Xlinetrace=True | ||||
| endif | ||||
| 
 | ||||
| 
 | ||||
| clean: | ||||
| 	# Clean sources | ||||
| 	find dependency_injector -name '*.py[co]' -delete | ||||
| 	find dependency_injector -name '__pycache__' -delete | ||||
| 	find dependency_injector -name '*.c' -delete | ||||
| 	find dependency_injector -name '*.so' -delete | ||||
| 	find src -name '*.py[cod]' -delete | ||||
| 	find src -name '__pycache__' -delete | ||||
| 	find src -name '*.c' -delete | ||||
| 	find src -name '*.so' -delete | ||||
| 	find src -name '*.html' -delete | ||||
| 	# Clean tests | ||||
| 	find tests -name '*.py[co]' -delete | ||||
| 	find tests -name '__pycache__' -delete | ||||
|  | @ -13,21 +24,39 @@ clean: | |||
| 	find examples -name '*.py[co]' -delete | ||||
| 	find examples -name '__pycache__' -delete | ||||
| 
 | ||||
| tests: clean | ||||
| cythonize: | ||||
| 	# Compile Cython to C | ||||
| 	cython -a $(CYTHON_DIRECTIVES) $(CYTHON_SRC) | ||||
| 	# Move all Cython html reports | ||||
| 	mkdir -p reports/cython/ | ||||
| 	find src -name '*.html' -exec mv {}  reports/cython/  \; | ||||
| 
 | ||||
| build: clean cythonize | ||||
| 	# Compile C extensions | ||||
| 	python setup.py build_ext --inplace | ||||
| 
 | ||||
| install: uninstall clean cythonize | ||||
| 	pip install -ve . | ||||
| 
 | ||||
| uninstall: | ||||
| 	- pip uninstall -y -q dependency-injector 2> /dev/null | ||||
| 
 | ||||
| test: build | ||||
| 	# Unit tests with coverage report | ||||
| 	coverage erase | ||||
| 	coverage run --rcfile=./.coveragerc -m unittest2 discover tests | ||||
| 	coverage run --rcfile=./.coveragerc -m unittest2 discover tests/unit | ||||
| 	coverage report --rcfile=./.coveragerc | ||||
| 	coverage html --rcfile=./.coveragerc | ||||
| 	coverage erase | ||||
| 
 | ||||
| check: | ||||
| 	# Static analysis | ||||
| 	flake8 --max-complexity=10 dependency_injector/ | ||||
| 	flake8 --max-complexity=10 src/dependency_injector/ | ||||
| 	flake8 --max-complexity=10 examples/ | ||||
| 	# Code style analysis | ||||
| 	pydocstyle dependency_injector/ | ||||
| 	pydocstyle src/dependency_injector/ | ||||
| 	pydocstyle examples/ | ||||
| 
 | ||||
| publish: clean | ||||
| publish: cythonize | ||||
| 	# Create and upload build | ||||
| 	python setup.py sdist upload | ||||
| 	# Create and upload tag | ||||
|  |  | |||
|  | @ -56,7 +56,7 @@ author = u'ETS Labs' | |||
| # | ||||
| # The short X.Y version. | ||||
| # Getting version: | ||||
| with open('../dependency_injector/__init__.py') as init_file: | ||||
| with open('../src/dependency_injector/__init__.py') as init_file: | ||||
|     version = re.search('VERSION = \'(.*?)\'', init_file.read()).group(1) | ||||
| 
 | ||||
| # The full version, including alpha/beta/rc tags. | ||||
|  | @ -281,7 +281,7 @@ man_pages = [ | |||
| #  dir menu entry, description, category) | ||||
| texinfo_documents = [ | ||||
|   (master_doc, 'Dependency Injector', u'Dependency Injector Documentation', | ||||
|    author, 'Dependency Injector', 'Python dependency injection framework', | ||||
|    author, 'Dependency Injector', 'Dependency injection microframework for Python', | ||||
|    'Miscellaneous'), | ||||
| ] | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,8 +9,14 @@ follows `Semantic versioning`_ | |||
| 
 | ||||
| Development version | ||||
| ------------------- | ||||
| - Add ``dependency_injector.injections`` module (C extension). | ||||
| - Remove ``@inject`` decorator. | ||||
| - Add makefile (``clean``, ``tests`` & ``publish`` commands). | ||||
| - Add makefile (``clean``, ``test``, ``build``, ``install``, ``uninstall``  | ||||
|   & ``publish`` commands). | ||||
| - Update repository structure: | ||||
| 
 | ||||
|     - Sources are moved under ``src``. | ||||
|     - Tests are moved under ``tests/unit``. | ||||
| 
 | ||||
| .. - No features. | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,33 +0,0 @@ | |||
| """`inject()` decorator and Flask view example.""" | ||||
| 
 | ||||
| import sqlite3 | ||||
| import flask | ||||
| 
 | ||||
| import dependency_injector.providers as providers | ||||
| import dependency_injector.injections as injections | ||||
| 
 | ||||
| 
 | ||||
| database = providers.Singleton(sqlite3.connect, | ||||
|                                ':memory:', | ||||
|                                timeout=30, | ||||
|                                detect_types=True, | ||||
|                                isolation_level='EXCLUSIVE') | ||||
| 
 | ||||
| app = flask.Flask(__name__) | ||||
| 
 | ||||
| 
 | ||||
| @app.route('/') | ||||
| @injections.inject(database) | ||||
| @injections.inject(flask.request) | ||||
| def hello(request, database): | ||||
|     """Example Flask view.""" | ||||
|     print request | ||||
|     one = database.execute('SELECT 1').fetchone()[0] | ||||
|     return 'Query returned {0}, db connection {1}'.format(one, database) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     app.run() | ||||
| 
 | ||||
| # Example output of "GET / HTTP/1.1" is: | ||||
| # Query returned 1, db connection <sqlite3.Connection object at 0x1057e4030> | ||||
|  | @ -1,43 +0,0 @@ | |||
| """`inject()` decorator with classes example.""" | ||||
| 
 | ||||
| import sqlite3 | ||||
| import flask | ||||
| import flask.views | ||||
| 
 | ||||
| import dependency_injector.providers as providers | ||||
| import dependency_injector.injections as injections | ||||
| 
 | ||||
| 
 | ||||
| database = providers.Singleton(sqlite3.Connection, | ||||
|                                database=':memory:', | ||||
|                                timeout=30, | ||||
|                                detect_types=True, | ||||
|                                isolation_level='EXCLUSIVE') | ||||
| 
 | ||||
| app = flask.Flask(__name__) | ||||
| 
 | ||||
| 
 | ||||
| @injections.inject(database=database) | ||||
| @injections.inject(some_setting=777) | ||||
| class HelloView(flask.views.View): | ||||
|     """Example flask class-based view.""" | ||||
| 
 | ||||
|     def __init__(self, database, some_setting): | ||||
|         """Initializer.""" | ||||
|         self.database = database | ||||
|         self.some_setting = some_setting | ||||
| 
 | ||||
|     def dispatch_request(self): | ||||
|         """Handle example request.""" | ||||
|         one = self.database.execute('SELECT 1').fetchone()[0] | ||||
|         one *= self.some_setting | ||||
|         return 'Query returned {0}, db connection {1}'.format(one, database) | ||||
| 
 | ||||
| 
 | ||||
| app.add_url_rule('/', view_func=HelloView.as_view('hello_view')) | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     app.run() | ||||
| 
 | ||||
| # Example output of "GET / HTTP/1.1" is: | ||||
| # Query returned 777, db connection <sqlite3.Connection object at 0x1057e4030> | ||||
|  | @ -1,28 +0,0 @@ | |||
| """`inject()` decorator simple example.""" | ||||
| 
 | ||||
| import dependency_injector.providers as providers | ||||
| import dependency_injector.injections as injections | ||||
| 
 | ||||
| 
 | ||||
| dependency_injector_factory = providers.Factory(object) | ||||
| 
 | ||||
| 
 | ||||
| # Example of using `inject()` decorator keyword argument injections: | ||||
| @injections.inject(new_object=dependency_injector_factory) | ||||
| @injections.inject(some_setting=1334) | ||||
| def example_callback1(new_object, some_setting): | ||||
|     """Example callback that does some asserts for input args.""" | ||||
|     assert isinstance(new_object, object) | ||||
|     assert some_setting == 1334 | ||||
| 
 | ||||
| 
 | ||||
| # Example of using `inject()` decorator with positional argument injections: | ||||
| @injections.inject(dependency_injector_factory, 1334) | ||||
| def example_callback2(new_object, some_setting): | ||||
|     """Example callback that does some asserts for input args.""" | ||||
|     assert isinstance(new_object, object) | ||||
|     assert some_setting == 1334 | ||||
| 
 | ||||
| 
 | ||||
| example_callback1() | ||||
| example_callback2() | ||||
|  | @ -30,7 +30,7 @@ if __name__ == '__main__': | |||
|         class _SequenceContainer1(SequencesContainer): | ||||
|             object_provider = providers.Factory(object) | ||||
|     except errors.Error as exception: | ||||
|         print exception | ||||
|         print(exception) | ||||
|         # <class '__main__._SequenceContainer1'> can contain only | ||||
|         # <class '__main__.SequenceProvider'> instances | ||||
| 
 | ||||
|  | @ -38,7 +38,7 @@ if __name__ == '__main__': | |||
|         class _SequenceContainer2(SequencesContainer): | ||||
|             object_provider = SequenceProvider(object) | ||||
|     except errors.Error as exception: | ||||
|         print exception | ||||
|         print(exception) | ||||
|         # <class '__main__.SequenceProvider'> can provide only | ||||
|         # <class '_abcoll.Sequence'> instances | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ if __name__ == '__main__': | |||
|     try: | ||||
|         sequences_container.object_provider = providers.Factory(object) | ||||
|     except errors.Error as exception: | ||||
|         print exception | ||||
|         print(exception) | ||||
|         # <dependency_injector.containers.DynamicContainer object at | ||||
|         # 0x107820ed0> can contain only <class '__main__.SequenceProvider'> | ||||
|         # instances | ||||
|  | @ -32,7 +32,7 @@ if __name__ == '__main__': | |||
|     try: | ||||
|         sequences_container.object_provider = SequenceProvider(object) | ||||
|     except errors.Error as exception: | ||||
|         print exception | ||||
|         print(exception) | ||||
|         # <class '__main__.SequenceProvider'> can provide only | ||||
|         # <class '_abcoll.Sequence'> instances | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,5 +11,5 @@ class ApiClient(object): | |||
| 
 | ||||
|     def call(self, operation, data): | ||||
|         """Make some network operations.""" | ||||
|         print 'API call [{0}:{1}], method - {2}, data - {3}'.format( | ||||
|             self.host, self.api_key, operation, repr(data)) | ||||
|         print('API call [{0}:{1}], method - {2}, data - {3}'.format( | ||||
|             self.host, self.api_key, operation, repr(data))) | ||||
|  |  | |||
|  | @ -1,40 +0,0 @@ | |||
| """Pythonic way for Dependency Injection - Auth System.""" | ||||
| 
 | ||||
| from dependency_injector import providers | ||||
| from dependency_injector import injections | ||||
| 
 | ||||
| 
 | ||||
| @providers.DelegatedCallable | ||||
| def get_user_info(user_id): | ||||
|     """Return user info.""" | ||||
|     raise NotImplementedError() | ||||
| 
 | ||||
| 
 | ||||
| @providers.Factory | ||||
| @injections.inject(get_user_info=get_user_info) | ||||
| class AuthComponent(object): | ||||
|     """Some authentication component.""" | ||||
| 
 | ||||
|     def __init__(self, get_user_info): | ||||
|         """Initializer.""" | ||||
|         self.get_user_info = get_user_info | ||||
| 
 | ||||
|     def authenticate_user(self, token): | ||||
|         """Authenticate user by token.""" | ||||
|         user_info = self.get_user_info(user_id=token + '1') | ||||
|         return user_info | ||||
| 
 | ||||
| 
 | ||||
| print AuthComponent | ||||
| print get_user_info | ||||
| 
 | ||||
| 
 | ||||
| @providers.override(get_user_info) | ||||
| @providers.DelegatedCallable | ||||
| def get_user_info(user_id): | ||||
|     """Return user info.""" | ||||
|     return {'user_id': user_id} | ||||
| 
 | ||||
| 
 | ||||
| print AuthComponent().authenticate_user(token='abc') | ||||
| # {'user_id': 'abc1'} | ||||
|  | @ -1,66 +0,0 @@ | |||
| """Pythonic way for Dependency Injection - callback-based IoC container.""" | ||||
| 
 | ||||
| import sqlite3 | ||||
| 
 | ||||
| from dependency_injector import containers | ||||
| from dependency_injector import providers | ||||
| from dependency_injector import injections | ||||
| 
 | ||||
| 
 | ||||
| class UsersService(object): | ||||
|     """Users service, that has dependency on database.""" | ||||
| 
 | ||||
|     def __init__(self, db): | ||||
|         """Initializer.""" | ||||
|         self.db = db | ||||
| 
 | ||||
| 
 | ||||
| class AuthService(object): | ||||
|     """Auth service, that has dependencies on users service and database.""" | ||||
| 
 | ||||
|     def __init__(self, db, users_service): | ||||
|         """Initializer.""" | ||||
|         self.db = db | ||||
|         self.users_service = users_service | ||||
| 
 | ||||
| 
 | ||||
| class Services(containers.DeclarativeContainer): | ||||
|     """IoC container of service providers.""" | ||||
| 
 | ||||
|     @providers.Singleton | ||||
|     def database(): | ||||
|         """Provide database connection. | ||||
| 
 | ||||
|         :rtype: sqlite3.Connection | ||||
|         """ | ||||
|         return sqlite3.connect(':memory:') | ||||
| 
 | ||||
|     @providers.Factory | ||||
|     @injections.inject(db=database) | ||||
|     def users(**kwargs): | ||||
|         """Provide users service. | ||||
| 
 | ||||
|         :rtype: UsersService | ||||
|         """ | ||||
|         return UsersService(**kwargs) | ||||
| 
 | ||||
|     @providers.Factory | ||||
|     @injections.inject(db=database) | ||||
|     @injections.inject(users_service=users) | ||||
|     def auth(**kwargs): | ||||
|         """Provide users service. | ||||
| 
 | ||||
|         :rtype: AuthService | ||||
|         """ | ||||
|         return AuthService(**kwargs) | ||||
| 
 | ||||
| 
 | ||||
| # Retrieving services: | ||||
| users_service = Services.users() | ||||
| auth_service = Services.auth() | ||||
| 
 | ||||
| # Making some asserts: | ||||
| assert users_service.db is auth_service.db is Services.database() | ||||
| assert isinstance(auth_service.users_service, UsersService) | ||||
| assert users_service is not Services.users() | ||||
| assert auth_service is not Services.auth() | ||||
|  | @ -7,9 +7,9 @@ import dependency_injector.providers as providers | |||
| even_filter = providers.Callable(filter, lambda x: x % 2 == 0) | ||||
| odd_filter = providers.Callable(filter, lambda x: x % 2 != 0) | ||||
| 
 | ||||
| # Creating even and odd ranges using xrange() and filter providers: | ||||
| even_range = even_filter(xrange(1, 10)) | ||||
| odd_range = odd_filter(xrange(1, 10)) | ||||
| # Creating even and odd ranges using range() and filter providers: | ||||
| even_range = even_filter(range(1, 10)) | ||||
| odd_range = odd_filter(range(1, 10)) | ||||
| 
 | ||||
| # Making some asserts: | ||||
| assert even_range == [2, 4, 6, 8] | ||||
|  |  | |||
|  | @ -25,6 +25,6 @@ some_service_provider = ServiceProvider(SomeService) | |||
| try: | ||||
|     some_service_provider = ServiceProvider(object) | ||||
| except errors.Error as exception: | ||||
|     print exception | ||||
|     print(exception) | ||||
|     # <class '__main__.ServiceProvider'> can provide only | ||||
|     # <class '__main__.BaseService'> instances | ||||
|  |  | |||
|  | @ -30,6 +30,6 @@ photos_service_provider = ServiceProvider(PhotosService) | |||
| try: | ||||
|     some_service_provider = ServiceProvider(object) | ||||
| except errors.Error as exception: | ||||
|     print exception | ||||
|     print(exception) | ||||
|     # <class '__main__.ServiceProvider'> can provide only | ||||
|     # <class '__main__.BaseService'> instances | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ thread_factory = providers.Factory(threading.Thread, | |||
| if __name__ == '__main__': | ||||
|     # Create 10 threads for concurrent execution of example(): | ||||
|     threads = [] | ||||
|     for thread_number in xrange(10): | ||||
|     for thread_number in range(10): | ||||
|         threads.append(thread_factory(name='Thread{0}'.format(thread_number))) | ||||
| 
 | ||||
|     # Start execution of all created threads: | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| cython | ||||
| tox | ||||
| unittest2 | ||||
| sphinx | ||||
|  |  | |||
							
								
								
									
										39
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -1,10 +1,14 @@ | |||
| """`Dependency injector` setup script.""" | ||||
| 
 | ||||
| import os | ||||
| import re | ||||
| 
 | ||||
| from setuptools import setup | ||||
| from setuptools import setup, Extension | ||||
| 
 | ||||
| 
 | ||||
| # Defining setup variables: | ||||
| defined_macros = list() | ||||
| 
 | ||||
| # Getting description: | ||||
| with open('README.rst') as readme_file: | ||||
|     description = readme_file.read() | ||||
|  | @ -14,9 +18,14 @@ with open('requirements.txt') as version: | |||
|     requirements = version.readlines() | ||||
| 
 | ||||
| # Getting version: | ||||
| with open('dependency_injector/__init__.py') as init_file: | ||||
| with open('src/dependency_injector/__init__.py') as init_file: | ||||
|     version = re.search('VERSION = \'(.*?)\'', init_file.read()).group(1) | ||||
| 
 | ||||
| # Adding debug options: | ||||
| if os.environ.get('DEPENDENCY_INJECTOR_DEBUG_MODE') == '1': | ||||
|     defined_macros.append(('CYTHON_TRACE', 1)) | ||||
|     defined_macros.append(('CYTHON_TRACE_NOGIL', 1)) | ||||
| 
 | ||||
| 
 | ||||
| setup(name='dependency-injector', | ||||
|       version=version, | ||||
|  | @ -27,15 +36,27 @@ setup(name='dependency-injector', | |||
|       maintainer='Roman Mogilatov', | ||||
|       maintainer_email='rmogilatov@gmail.com', | ||||
|       url='https://github.com/ets-labs/python-dependency-injector', | ||||
|       bugtrack_url='https://github.com/ets-labs/python-dependency-injector' + | ||||
|                    '/issues', | ||||
|       download_url='https://pypi.python.org/pypi/dependency_injector', | ||||
|       license='BSD New', | ||||
|       packages=['dependency_injector', | ||||
|                 'dependency_injector.providers'], | ||||
|       platforms=['any'], | ||||
|       zip_safe=True, | ||||
|       install_requires=requirements, | ||||
|       packages=[ | ||||
|           'dependency_injector', | ||||
|           'dependency_injector.providers', | ||||
|       ], | ||||
|       package_dir={ | ||||
|           '': 'src', | ||||
|       }, | ||||
|       ext_modules=[ | ||||
|           Extension('dependency_injector.injections', | ||||
|                     ['src/dependency_injector/injections.c'], | ||||
|                     define_macros=defined_macros, | ||||
|                     extra_compile_args=['-O2']), | ||||
|       ], | ||||
|       package_data={ | ||||
|           'dependency_injector': ['*.pxd'], | ||||
|       }, | ||||
|       zip_safe=True, | ||||
|       license='BSD New', | ||||
|       platforms=['any'], | ||||
|       keywords=[ | ||||
|           'DI', | ||||
|           'Dependency injection', | ||||
|  |  | |||
							
								
								
									
										63
									
								
								src/dependency_injector/injections.pxd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/dependency_injector/injections.pxd
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| """Dependency injector injections. | ||||
| 
 | ||||
| Cython optimized code. | ||||
| """ | ||||
| 
 | ||||
| cpdef tuple parse_positional_injections(tuple args) | ||||
| cpdef tuple parse_named_injections(dict kwargs) | ||||
| 
 | ||||
| 
 | ||||
| cdef class Injection: | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| cdef class PositionalInjection(Injection): | ||||
|     cdef object __value | ||||
|     cdef int __is_provider | ||||
|     cdef int __is_delegated | ||||
|     cdef int __call | ||||
| 
 | ||||
|     cdef inline object __get_value(self): | ||||
|         if self.__call == 0: | ||||
|             return self.__value | ||||
|         return self.__value() | ||||
| 
 | ||||
| 
 | ||||
| cdef class NamedInjection(Injection): | ||||
|     cdef object __name | ||||
|     cdef object __value | ||||
|     cdef int __is_provider | ||||
|     cdef int __is_delegated | ||||
|     cdef int __call | ||||
| 
 | ||||
|     cdef inline object __get_name(self): | ||||
|         return self.__name | ||||
| 
 | ||||
|     cdef inline object __get_value(self): | ||||
|         if self.__call == 0: | ||||
|             return self.__value | ||||
|         return self.__value() | ||||
| 
 | ||||
| 
 | ||||
| cdef inline tuple __provide_positional_args(tuple inj_args, | ||||
|                                             int inj_args_len, | ||||
|                                             tuple args): | ||||
|     cdef PositionalInjection injection | ||||
|     if inj_args_len > 0: | ||||
|         positional_args = list() | ||||
|         for index in range(inj_args_len): | ||||
|             injection = <PositionalInjection>inj_args[index] | ||||
|             positional_args.append(injection.get_value()) | ||||
|         positional_args.extend(args) | ||||
|         args = positional_args | ||||
|     return args | ||||
| 
 | ||||
| cdef inline dict __provide_keyword_args(tuple inj_kwargs, | ||||
|                                         int inj_kwargs_len, | ||||
|                                         dict kwargs): | ||||
|     cdef NamedInjection kw_injection | ||||
|     if inj_kwargs_len > 0: | ||||
|         for index in range(inj_kwargs_len): | ||||
|             kw_injection = <NamedInjection>inj_kwargs[index] | ||||
|             kwargs[kw_injection.get_name()] = kw_injection.get_value() | ||||
|     return kwargs | ||||
							
								
								
									
										78
									
								
								src/dependency_injector/injections.pyx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/dependency_injector/injections.pyx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | |||
| """Dependency injector injections. | ||||
| 
 | ||||
| Cython optimized code. | ||||
| """ | ||||
| 
 | ||||
| # TODO: replace to cimport | ||||
| from .utils import is_provider | ||||
| 
 | ||||
| 
 | ||||
| cdef class Injection: | ||||
|     """Abstract injection class.""" | ||||
| 
 | ||||
| 
 | ||||
| cdef class PositionalInjection(Injection): | ||||
|     """Positional injection class.""" | ||||
| 
 | ||||
|     def __init__(self, value): | ||||
|         """Initializer.""" | ||||
|         self.__value = value | ||||
|         self.__is_provider = <int>is_provider(value) | ||||
|         self.__is_delegated = 0  # TODO: use utils.is_delegated() | ||||
|         self.__call = <int>self.__is_provider == 1 and self.__is_delegated == 0 | ||||
| 
 | ||||
|     def get_value(self): | ||||
|         """Return injection value.""" | ||||
|         return self.__get_value() | ||||
| 
 | ||||
| 
 | ||||
| cdef class NamedInjection(Injection): | ||||
|     """Keyword injection class.""" | ||||
| 
 | ||||
|     def __init__(self, name, value): | ||||
|         """Initializer.""" | ||||
|         self.__name = name | ||||
|         self.__value = value | ||||
|         self.__is_provider = <int>is_provider(value) | ||||
|         self.__is_delegated = 0  # TODO: use utils.is_delegated() | ||||
|         self.__call = <int>self.__is_provider == 1 and self.__is_delegated == 0 | ||||
| 
 | ||||
|     def get_name(self): | ||||
|         """Return injection value.""" | ||||
|         return self.__get_name() | ||||
| 
 | ||||
|     def get_value(self): | ||||
|         """Return injection value.""" | ||||
|         return self.__get_value() | ||||
| 
 | ||||
| 
 | ||||
| cpdef tuple parse_positional_injections(tuple args): | ||||
|     """Parse positional injections.""" | ||||
|     cdef list injections = list() | ||||
|     cdef int args_len = len(args) | ||||
| 
 | ||||
|     cdef object arg | ||||
|     cdef int index | ||||
|     cdef PositionalInjection injection | ||||
| 
 | ||||
|     for index in range(args_len): | ||||
|         arg = args[index] | ||||
|         injection = PositionalInjection(arg) | ||||
|         injections.append(injection) | ||||
| 
 | ||||
|     return tuple(injections) | ||||
| 
 | ||||
| 
 | ||||
| cpdef tuple parse_named_injections(dict kwargs): | ||||
|     """Parse named injections.""" | ||||
|     cdef list injections = list() | ||||
| 
 | ||||
|     cdef object name | ||||
|     cdef object arg | ||||
|     cdef NamedInjection injection | ||||
| 
 | ||||
|     for name, arg in kwargs.items(): | ||||
|         injection = NamedInjection(name, arg) | ||||
|         injections.append(injection) | ||||
| 
 | ||||
|     return tuple(injections) | ||||
							
								
								
									
										2
									
								
								tests/unit/.pydocstylerc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/unit/.pydocstylerc
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| [pydocstyle] | ||||
| ignore = D101,D102 | ||||
							
								
								
									
										53
									
								
								tests/unit/test_injections.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								tests/unit/test_injections.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| """Dependency injector injections unit tests.""" | ||||
| 
 | ||||
| import unittest2 as unittest | ||||
| 
 | ||||
| from dependency_injector import injections | ||||
| from dependency_injector import providers | ||||
| 
 | ||||
| 
 | ||||
| class PositionalInjectionTests(unittest.TestCase): | ||||
| 
 | ||||
|     def test_isinstance(self): | ||||
|         injection = injections.PositionalInjection(1) | ||||
|         self.assertIsInstance(injection, injections.Injection) | ||||
| 
 | ||||
|     def test_get_value_with_not_provider(self): | ||||
|         injection = injections.PositionalInjection(123) | ||||
|         self.assertEquals(injection.get_value(), 123) | ||||
| 
 | ||||
|     def test_get_value_with_factory(self): | ||||
|         injection = injections.PositionalInjection(providers.Factory(object)) | ||||
| 
 | ||||
|         obj1 = injection.get_value() | ||||
|         obj2 = injection.get_value() | ||||
| 
 | ||||
|         self.assertIs(type(obj1), object) | ||||
|         self.assertIs(type(obj2), object) | ||||
|         self.assertIsNot(obj1, obj2) | ||||
| 
 | ||||
| 
 | ||||
| class NamedInjectionTests(unittest.TestCase): | ||||
| 
 | ||||
|     def test_isinstance(self): | ||||
|         injection = injections.NamedInjection('name', 1) | ||||
|         self.assertIsInstance(injection, injections.Injection) | ||||
| 
 | ||||
|     def test_get_name(self): | ||||
|         injection = injections.NamedInjection('name', 123) | ||||
|         self.assertEquals(injection.get_name(), 'name') | ||||
| 
 | ||||
|     def test_get_value_with_not_provider(self): | ||||
|         injection = injections.NamedInjection('name', 123) | ||||
|         self.assertEquals(injection.get_value(), 123) | ||||
| 
 | ||||
|     def test_get_value_with_factory(self): | ||||
|         injection = injections.NamedInjection('name', | ||||
|                                               providers.Factory(object)) | ||||
| 
 | ||||
|         obj1 = injection.get_value() | ||||
|         obj2 = injection.get_value() | ||||
| 
 | ||||
|         self.assertIs(type(obj1), object) | ||||
|         self.assertIs(type(obj2), object) | ||||
|         self.assertIsNot(obj1, obj2) | ||||
							
								
								
									
										20
									
								
								tox.ini
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								tox.ini
									
									
									
									
									
								
							|  | @ -6,39 +6,39 @@ envlist= | |||
| deps= | ||||
|     unittest2 | ||||
| commands= | ||||
|     unit2 discover tests [] | ||||
|     unit2 discover tests/unit | ||||
| 
 | ||||
| [testenv:coveralls] | ||||
| basepython=python2.7 | ||||
| passenv=TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH | ||||
| passenv=TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH DEPENDENCY_INJECTOR_DEBUG_MODE | ||||
| basepython=python3.5 | ||||
| usedevelop=True | ||||
| deps= | ||||
|     {[testenv]deps} | ||||
|     cython | ||||
|     coverage | ||||
|     coveralls | ||||
| commands= | ||||
|     coverage erase | ||||
|     coverage run --rcfile=./.coveragerc -m unittest2 discover tests [] | ||||
|     coverage run --rcfile=./.coveragerc -m unittest2 discover tests/unit | ||||
|     coverage report --rcfile=./.coveragerc | ||||
|     coveralls | ||||
| 
 | ||||
| [testenv:pylint] | ||||
| basepython=python2.7 | ||||
| deps= | ||||
|     pylint | ||||
| commands= | ||||
|     - pylint -f colorized --rcfile=./.pylintrc dependency_injector | ||||
|     - pylint -f colorized --rcfile=./.pylintrc src/dependency_injector | ||||
| 
 | ||||
| [testenv:flake8] | ||||
| basepython=python2.7 | ||||
| deps= | ||||
|     flake8 | ||||
| commands= | ||||
|     flake8 --max-complexity=10 dependency_injector/ | ||||
|     flake8 --max-complexity=10 src/dependency_injector/ | ||||
|     flake8 --max-complexity=10 examples/ | ||||
| 
 | ||||
| [testenv:pydocstyle] | ||||
| basepython=python2.7 | ||||
| deps= | ||||
|     pydocstyle | ||||
| commands= | ||||
|     pydocstyle dependency_injector/ | ||||
|     pydocstyle src/dependency_injector/ | ||||
|     pydocstyle examples/ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user