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] | [run] | ||||||
| include = dependency_injector/* | source = src/dependency_injector | ||||||
| omit = tests/* | omit = tests/unit | ||||||
|  | plugins = Cython.Coverage | ||||||
| 
 | 
 | ||||||
| [html] | [html] | ||||||
| directory=reports/unittests/ | directory=reports/unittests/ | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -63,7 +63,7 @@ venv/ | ||||||
| .ropeproject/ | .ropeproject/ | ||||||
| 
 | 
 | ||||||
| # C extensions | # C extensions | ||||||
| dependency_injector/*.c | src/dependency_injector/*.c | ||||||
| dependency_injector/*.so | src/dependency_injector/*.so | ||||||
| dependency_injector/providers/*.c | src/dependency_injector/providers/*.c | ||||||
| dependency_injector/providers/*.so | 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 | # Add <file or directory> to the black list. It should be a base name, not a | ||||||
| # path. You may set this option multiple times. | # path. You may set this option multiple times. | ||||||
| ignore=utils,test | ignore=utils,tests | ||||||
| 
 | 
 | ||||||
| [MESSAGES CONTROL] | [MESSAGES CONTROL] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										32
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								.travis.yml
									
									
									
									
									
								
							|  | @ -1,18 +1,22 @@ | ||||||
| sudo: false | sudo: false | ||||||
|  | install:  | ||||||
|  |     - pip install tox | ||||||
|  |     - pip install cython | ||||||
|  |     - make cythonize | ||||||
|  | script:  | ||||||
|  |     - tox | ||||||
| language: python | language: python | ||||||
| install: pip install tox |  | ||||||
| script: tox |  | ||||||
| python: | python: | ||||||
|   - 3.5 |     - 3.5 | ||||||
| env: | env: | ||||||
|   - TOXENV=coveralls |     - TOXENV=coveralls DEPENDENCY_INJECTOR_DEBUG_MODE=1 | ||||||
|   - TOXENV=pylint |     - TOXENV=pylint | ||||||
|   - TOXENV=flake8 |     - TOXENV=flake8 | ||||||
|   - TOXENV=pydocstyle |     - TOXENV=pydocstyle | ||||||
|   - TOXENV=py26 |     - TOXENV=py26 | ||||||
|   - TOXENV=py27 |     - TOXENV=py27 | ||||||
|   - TOXENV=py33 |     - TOXENV=py33 | ||||||
|   - TOXENV=py34 |     - TOXENV=py34 | ||||||
|   - TOXENV=py35 |     - TOXENV=py35 | ||||||
|   - TOXENV=pypy |     - TOXENV=pypy | ||||||
|   - TOXENV=pypy3 |     - TOXENV=pypy3 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| include dependency_injector/* | recursive-include src/dependency_injector *.py *.pyx *.pxd *.c | ||||||
| include README.rst | include README.rst | ||||||
| include CONTRIBUTORS.rst | include CONTRIBUTORS.rst | ||||||
| include LICENSE.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: | ||||||
| 	# Clean sources | 	# Clean sources | ||||||
| 	find dependency_injector -name '*.py[co]' -delete | 	find src -name '*.py[cod]' -delete | ||||||
| 	find dependency_injector -name '__pycache__' -delete | 	find src -name '__pycache__' -delete | ||||||
| 	find dependency_injector -name '*.c' -delete | 	find src -name '*.c' -delete | ||||||
| 	find dependency_injector -name '*.so' -delete | 	find src -name '*.so' -delete | ||||||
|  | 	find src -name '*.html' -delete | ||||||
| 	# Clean tests | 	# Clean tests | ||||||
| 	find tests -name '*.py[co]' -delete | 	find tests -name '*.py[co]' -delete | ||||||
| 	find tests -name '__pycache__' -delete | 	find tests -name '__pycache__' -delete | ||||||
|  | @ -13,21 +24,39 @@ clean: | ||||||
| 	find examples -name '*.py[co]' -delete | 	find examples -name '*.py[co]' -delete | ||||||
| 	find examples -name '__pycache__' -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 | 	# Unit tests with coverage report | ||||||
| 	coverage erase | 	coverage erase | ||||||
| 	coverage run --rcfile=./.coveragerc -m unittest2 discover tests | 	coverage run --rcfile=./.coveragerc -m unittest2 discover tests/unit | ||||||
| 	coverage report --rcfile=./.coveragerc | 	coverage report --rcfile=./.coveragerc | ||||||
| 	coverage html --rcfile=./.coveragerc | 	coverage html --rcfile=./.coveragerc | ||||||
| 	coverage erase | 
 | ||||||
|  | check: | ||||||
| 	# Static analysis | 	# Static analysis | ||||||
| 	flake8 --max-complexity=10 dependency_injector/ | 	flake8 --max-complexity=10 src/dependency_injector/ | ||||||
| 	flake8 --max-complexity=10 examples/ | 	flake8 --max-complexity=10 examples/ | ||||||
| 	# Code style analysis | 	# Code style analysis | ||||||
| 	pydocstyle dependency_injector/ | 	pydocstyle src/dependency_injector/ | ||||||
| 	pydocstyle examples/ | 	pydocstyle examples/ | ||||||
| 
 | 
 | ||||||
| publish: clean | publish: cythonize | ||||||
| 	# Create and upload build | 	# Create and upload build | ||||||
| 	python setup.py sdist upload | 	python setup.py sdist upload | ||||||
| 	# Create and upload tag | 	# Create and upload tag | ||||||
|  |  | ||||||
|  | @ -56,7 +56,7 @@ author = u'ETS Labs' | ||||||
| # | # | ||||||
| # The short X.Y version. | # The short X.Y version. | ||||||
| # Getting 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) |     version = re.search('VERSION = \'(.*?)\'', init_file.read()).group(1) | ||||||
| 
 | 
 | ||||||
| # The full version, including alpha/beta/rc tags. | # The full version, including alpha/beta/rc tags. | ||||||
|  | @ -281,7 +281,7 @@ man_pages = [ | ||||||
| #  dir menu entry, description, category) | #  dir menu entry, description, category) | ||||||
| texinfo_documents = [ | texinfo_documents = [ | ||||||
|   (master_doc, 'Dependency Injector', u'Dependency Injector Documentation', |   (master_doc, 'Dependency Injector', u'Dependency Injector Documentation', | ||||||
|    author, 'Dependency Injector', 'Python dependency injection framework', |    author, 'Dependency Injector', 'Dependency injection microframework for Python', | ||||||
|    'Miscellaneous'), |    'Miscellaneous'), | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,8 +9,14 @@ follows `Semantic versioning`_ | ||||||
| 
 | 
 | ||||||
| Development version | Development version | ||||||
| ------------------- | ------------------- | ||||||
|  | - Add ``dependency_injector.injections`` module (C extension). | ||||||
| - Remove ``@inject`` decorator. | - 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. | .. - 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): |         class _SequenceContainer1(SequencesContainer): | ||||||
|             object_provider = providers.Factory(object) |             object_provider = providers.Factory(object) | ||||||
|     except errors.Error as exception: |     except errors.Error as exception: | ||||||
|         print exception |         print(exception) | ||||||
|         # <class '__main__._SequenceContainer1'> can contain only |         # <class '__main__._SequenceContainer1'> can contain only | ||||||
|         # <class '__main__.SequenceProvider'> instances |         # <class '__main__.SequenceProvider'> instances | ||||||
| 
 | 
 | ||||||
|  | @ -38,7 +38,7 @@ if __name__ == '__main__': | ||||||
|         class _SequenceContainer2(SequencesContainer): |         class _SequenceContainer2(SequencesContainer): | ||||||
|             object_provider = SequenceProvider(object) |             object_provider = SequenceProvider(object) | ||||||
|     except errors.Error as exception: |     except errors.Error as exception: | ||||||
|         print exception |         print(exception) | ||||||
|         # <class '__main__.SequenceProvider'> can provide only |         # <class '__main__.SequenceProvider'> can provide only | ||||||
|         # <class '_abcoll.Sequence'> instances |         # <class '_abcoll.Sequence'> instances | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ if __name__ == '__main__': | ||||||
|     try: |     try: | ||||||
|         sequences_container.object_provider = providers.Factory(object) |         sequences_container.object_provider = providers.Factory(object) | ||||||
|     except errors.Error as exception: |     except errors.Error as exception: | ||||||
|         print exception |         print(exception) | ||||||
|         # <dependency_injector.containers.DynamicContainer object at |         # <dependency_injector.containers.DynamicContainer object at | ||||||
|         # 0x107820ed0> can contain only <class '__main__.SequenceProvider'> |         # 0x107820ed0> can contain only <class '__main__.SequenceProvider'> | ||||||
|         # instances |         # instances | ||||||
|  | @ -32,7 +32,7 @@ if __name__ == '__main__': | ||||||
|     try: |     try: | ||||||
|         sequences_container.object_provider = SequenceProvider(object) |         sequences_container.object_provider = SequenceProvider(object) | ||||||
|     except errors.Error as exception: |     except errors.Error as exception: | ||||||
|         print exception |         print(exception) | ||||||
|         # <class '__main__.SequenceProvider'> can provide only |         # <class '__main__.SequenceProvider'> can provide only | ||||||
|         # <class '_abcoll.Sequence'> instances |         # <class '_abcoll.Sequence'> instances | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,5 +11,5 @@ class ApiClient(object): | ||||||
| 
 | 
 | ||||||
|     def call(self, operation, data): |     def call(self, operation, data): | ||||||
|         """Make some network operations.""" |         """Make some network operations.""" | ||||||
|         print 'API call [{0}:{1}], method - {2}, data - {3}'.format( |         print('API call [{0}:{1}], method - {2}, data - {3}'.format( | ||||||
|             self.host, self.api_key, operation, repr(data)) |             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) | even_filter = providers.Callable(filter, lambda x: x % 2 == 0) | ||||||
| odd_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: | # Creating even and odd ranges using range() and filter providers: | ||||||
| even_range = even_filter(xrange(1, 10)) | even_range = even_filter(range(1, 10)) | ||||||
| odd_range = odd_filter(xrange(1, 10)) | odd_range = odd_filter(range(1, 10)) | ||||||
| 
 | 
 | ||||||
| # Making some asserts: | # Making some asserts: | ||||||
| assert even_range == [2, 4, 6, 8] | assert even_range == [2, 4, 6, 8] | ||||||
|  |  | ||||||
|  | @ -25,6 +25,6 @@ some_service_provider = ServiceProvider(SomeService) | ||||||
| try: | try: | ||||||
|     some_service_provider = ServiceProvider(object) |     some_service_provider = ServiceProvider(object) | ||||||
| except errors.Error as exception: | except errors.Error as exception: | ||||||
|     print exception |     print(exception) | ||||||
|     # <class '__main__.ServiceProvider'> can provide only |     # <class '__main__.ServiceProvider'> can provide only | ||||||
|     # <class '__main__.BaseService'> instances |     # <class '__main__.BaseService'> instances | ||||||
|  |  | ||||||
|  | @ -30,6 +30,6 @@ photos_service_provider = ServiceProvider(PhotosService) | ||||||
| try: | try: | ||||||
|     some_service_provider = ServiceProvider(object) |     some_service_provider = ServiceProvider(object) | ||||||
| except errors.Error as exception: | except errors.Error as exception: | ||||||
|     print exception |     print(exception) | ||||||
|     # <class '__main__.ServiceProvider'> can provide only |     # <class '__main__.ServiceProvider'> can provide only | ||||||
|     # <class '__main__.BaseService'> instances |     # <class '__main__.BaseService'> instances | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ thread_factory = providers.Factory(threading.Thread, | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     # Create 10 threads for concurrent execution of example(): |     # Create 10 threads for concurrent execution of example(): | ||||||
|     threads = [] |     threads = [] | ||||||
|     for thread_number in xrange(10): |     for thread_number in range(10): | ||||||
|         threads.append(thread_factory(name='Thread{0}'.format(thread_number))) |         threads.append(thread_factory(name='Thread{0}'.format(thread_number))) | ||||||
| 
 | 
 | ||||||
|     # Start execution of all created threads: |     # Start execution of all created threads: | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | cython | ||||||
| tox | tox | ||||||
| unittest2 | unittest2 | ||||||
| sphinx | sphinx | ||||||
|  |  | ||||||
							
								
								
									
										39
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -1,10 +1,14 @@ | ||||||
| """`Dependency injector` setup script.""" | """`Dependency injector` setup script.""" | ||||||
| 
 | 
 | ||||||
|  | import os | ||||||
| import re | import re | ||||||
| 
 | 
 | ||||||
| from setuptools import setup | from setuptools import setup, Extension | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # Defining setup variables: | ||||||
|  | defined_macros = list() | ||||||
|  | 
 | ||||||
| # Getting description: | # Getting description: | ||||||
| with open('README.rst') as readme_file: | with open('README.rst') as readme_file: | ||||||
|     description = readme_file.read() |     description = readme_file.read() | ||||||
|  | @ -14,9 +18,14 @@ with open('requirements.txt') as version: | ||||||
|     requirements = version.readlines() |     requirements = version.readlines() | ||||||
| 
 | 
 | ||||||
| # Getting 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) |     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', | setup(name='dependency-injector', | ||||||
|       version=version, |       version=version, | ||||||
|  | @ -27,15 +36,27 @@ setup(name='dependency-injector', | ||||||
|       maintainer='Roman Mogilatov', |       maintainer='Roman Mogilatov', | ||||||
|       maintainer_email='rmogilatov@gmail.com', |       maintainer_email='rmogilatov@gmail.com', | ||||||
|       url='https://github.com/ets-labs/python-dependency-injector', |       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', |       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, |       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=[ |       keywords=[ | ||||||
|           'DI', |           'DI', | ||||||
|           'Dependency injection', |           '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= | deps= | ||||||
|     unittest2 |     unittest2 | ||||||
| commands= | commands= | ||||||
|     unit2 discover tests [] |     unit2 discover tests/unit | ||||||
| 
 | 
 | ||||||
| [testenv:coveralls] | [testenv:coveralls] | ||||||
| basepython=python2.7 | passenv=TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH DEPENDENCY_INJECTOR_DEBUG_MODE | ||||||
| passenv=TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH | basepython=python3.5 | ||||||
|  | usedevelop=True | ||||||
| deps= | deps= | ||||||
|     {[testenv]deps} |     {[testenv]deps} | ||||||
|  |     cython | ||||||
|     coverage |     coverage | ||||||
|     coveralls |     coveralls | ||||||
| commands= | commands= | ||||||
|     coverage erase |     coverage erase | ||||||
|     coverage run --rcfile=./.coveragerc -m unittest2 discover tests [] |     coverage run --rcfile=./.coveragerc -m unittest2 discover tests/unit | ||||||
|  |     coverage report --rcfile=./.coveragerc | ||||||
|     coveralls |     coveralls | ||||||
| 
 | 
 | ||||||
| [testenv:pylint] | [testenv:pylint] | ||||||
| basepython=python2.7 |  | ||||||
| deps= | deps= | ||||||
|     pylint |     pylint | ||||||
| commands= | commands= | ||||||
|     - pylint -f colorized --rcfile=./.pylintrc dependency_injector |     - pylint -f colorized --rcfile=./.pylintrc src/dependency_injector | ||||||
| 
 | 
 | ||||||
| [testenv:flake8] | [testenv:flake8] | ||||||
| basepython=python2.7 |  | ||||||
| deps= | deps= | ||||||
|     flake8 |     flake8 | ||||||
| commands= | commands= | ||||||
|     flake8 --max-complexity=10 dependency_injector/ |     flake8 --max-complexity=10 src/dependency_injector/ | ||||||
|     flake8 --max-complexity=10 examples/ |     flake8 --max-complexity=10 examples/ | ||||||
| 
 | 
 | ||||||
| [testenv:pydocstyle] | [testenv:pydocstyle] | ||||||
| basepython=python2.7 |  | ||||||
| deps= | deps= | ||||||
|     pydocstyle |     pydocstyle | ||||||
| commands= | commands= | ||||||
|     pydocstyle dependency_injector/ |     pydocstyle src/dependency_injector/ | ||||||
|     pydocstyle examples/ |     pydocstyle examples/ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user