From 431dee80d88b60e3a36d0fc044c212bce0a1a1df Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Fri, 22 Jun 2018 09:52:58 +0300 Subject: [PATCH 1/8] Add ioc_container example --- docs/main/changelog.rst | 4 + examples/miniapps/ioc_container/README.rst | 8 ++ examples/miniapps/ioc_container/container.py | 55 ++++++++++ .../ioc_container/example/__init__.py | 1 + .../miniapps/ioc_container/example/main.py | 27 +++++ .../ioc_container/example/services.py | 103 ++++++++++++++++++ examples/miniapps/ioc_container/run.py | 21 ++++ 7 files changed, 219 insertions(+) create mode 100644 examples/miniapps/ioc_container/README.rst create mode 100644 examples/miniapps/ioc_container/container.py create mode 100644 examples/miniapps/ioc_container/example/__init__.py create mode 100644 examples/miniapps/ioc_container/example/main.py create mode 100644 examples/miniapps/ioc_container/example/services.py create mode 100644 examples/miniapps/ioc_container/run.py diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 24f1e103..6e7287b0 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -7,6 +7,10 @@ that were made in every particular version. From version 0.7.6 *Dependency Injector* framework strictly follows `Semantic versioning`_ +Development version +------------------- +- Add new example miniapp "ioc_container". + 3.12.0 ------ - Regenerate C sources using Cython 0.28.2. diff --git a/examples/miniapps/ioc_container/README.rst b/examples/miniapps/ioc_container/README.rst new file mode 100644 index 00000000..87373537 --- /dev/null +++ b/examples/miniapps/ioc_container/README.rst @@ -0,0 +1,8 @@ +Dependency Injector IoC containers example +========================================== + +Instructions for running + +.. code-block:: bash + + python run.py 1 secret photo.jpg diff --git a/examples/miniapps/ioc_container/container.py b/examples/miniapps/ioc_container/container.py new file mode 100644 index 00000000..39e3be89 --- /dev/null +++ b/examples/miniapps/ioc_container/container.py @@ -0,0 +1,55 @@ +"""Example of dependency injection in Python.""" + +import logging +import sqlite3 + +import boto3 + +import example.main +import example.services + +import dependency_injector.containers as containers +import dependency_injector.providers as providers + + +class IocContainer(containers.DeclarativeContainer): + """Application IoC container.""" + + config = providers.Configuration('config') + logger = providers.Singleton(logging.Logger, name='example') + + # Gateways + + database_client = providers.Singleton(sqlite3.connect, config.database.dsn) + + s3_client = providers.Singleton( + boto3.client, 's3', + aws_access_key_id=config.aws.access_key_id, + aws_secret_access_key=config.aws.secret_access_key) + + # Services + + users_service = providers.Factory( + example.services.UsersService, + db=database_client, + logger=logger) + + auth_service = providers.Factory( + example.services.AuthService, + token_ttl=config.auth.token_ttl, + db=database_client, + logger=logger) + + photos_service = providers.Factory( + example.services.PhotosService, + db=database_client, + s3=s3_client, + logger=logger) + + # Misc + + main = providers.Callable( + example.main.main, + users_service=users_service, + auth_service=auth_service, + photos_service=photos_service) diff --git a/examples/miniapps/ioc_container/example/__init__.py b/examples/miniapps/ioc_container/example/__init__.py new file mode 100644 index 00000000..bfa99aa2 --- /dev/null +++ b/examples/miniapps/ioc_container/example/__init__.py @@ -0,0 +1 @@ +"""Example top-level package.""" diff --git a/examples/miniapps/ioc_container/example/main.py b/examples/miniapps/ioc_container/example/main.py new file mode 100644 index 00000000..f1386c1a --- /dev/null +++ b/examples/miniapps/ioc_container/example/main.py @@ -0,0 +1,27 @@ +"""Example main module.""" + + +def main(uid, password, photo, users_service, auth_service, photos_service): + """Authenticate user and upload photo. + + :param uid: User identifier. + :type uid: int + + :param password: User's password for verification. + :type password: str + + :param photo_path: Path to photo for uploading. + :type photo_path: str + + :param users_service: Users service. + :type users_service: example.services.UsersService + + :param auth_service: Authentication service. + :type auth_service: example.services.AuthService + + :param photo_service: Photo service. + :type photo_service: example.services.PhotoService + """ + user = users_service.get_user_by_id(uid) + auth_service.authenticate(user, password) + photos_service.upload_photo(user['uid'], photo) diff --git a/examples/miniapps/ioc_container/example/services.py b/examples/miniapps/ioc_container/example/services.py new file mode 100644 index 00000000..77e1ae99 --- /dev/null +++ b/examples/miniapps/ioc_container/example/services.py @@ -0,0 +1,103 @@ +"""Example business services module.""" + + +class BaseService(object): + """Service base class.""" + + +class UsersService(BaseService): + """Users service.""" + + def __init__(self, logger, db): + """Initializer. + + :param logger: Logger instance. + :type logger: logging.Logger + + :param db: Database connection. + :type db: sqlite3.Connection + """ + self.logger = logger + self.db = db + + def get_user_by_id(self, uid): + """Return user's data by identifier. + + :param uid: User identifier. + :type uid: int + + :rtype: dict + """ + self.logger.debug('User %s has been found in database', uid) + return dict(uid=uid, password_hash='secret_hash') + + +class AuthService(BaseService): + """Authentication service.""" + + def __init__(self, logger, db, token_ttl): + """Initializer. + + :param logger: Logger instance. + :type logger: logging.Logger + + :param db: Database connection. + :type db: sqlite3.Connection + + :param token_ttl: Token lifetime in seconds. + :type token_ttl: int + """ + self.logger = logger + self.db = db + self.token_ttl = token_ttl + + def authenticate(self, user, password): + """Authenticate user. + + :param user: User's data. + :type user: dict + + :param password: User's password for verification. + :type password: str + + :raises: AssertionError when password is wrong + + :rtype: None + """ + assert user['password_hash'] == '_'.join((password, 'hash')) + self.logger.debug('User %s has been successfully authenticated', + user['uid']) + + +class PhotosService(BaseService): + """Photos service.""" + + def __init__(self, logger, db, s3): + """Initializer. + + :param logger: Logger instance. + :type logger: logging.Logger + + :param db: Database connection. + :type db: sqlite3.Connection + + :param s3: AWS S3 client. + :type s3: botocore.client.S3 + """ + self.logger = logger + self.db = db + self.s3 = s3 + + def upload_photo(self, uid, photo_path): + """Upload user photo. + + :param uid: User identifier. + :type uid: int + + :param photo_path: Path to photo for uploading. + :type photo_path: str + + :rtpe: None + """ + self.logger.debug('Photo %s has been successfully uploaded by user %s', + photo_path, uid) diff --git a/examples/miniapps/ioc_container/run.py b/examples/miniapps/ioc_container/run.py new file mode 100644 index 00000000..50caff94 --- /dev/null +++ b/examples/miniapps/ioc_container/run.py @@ -0,0 +1,21 @@ +"""Run example of dependency injection in Python.""" + +import sys +import logging + +from container import IocContainer + + +if __name__ == '__main__': + # Configure platform: + container = IocContainer( + config={'database': {'dsn': ':memory:'}, + 'aws': {'access_key_id': 'KEY', + 'secret_access_key': 'SECRET'}, + 'auth': {'token_ttl': 3600}}) + container.logger().addHandler(logging.StreamHandler(sys.stdout)) + + # Run application: + container.main(uid=sys.argv[1], + password=sys.argv[2], + photo=sys.argv[3]) From 926d152d3b5b4df37a92cb7ffb6919152e3662fd Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Fri, 22 Jun 2018 10:18:33 +0300 Subject: [PATCH 2/8] Fix incompatibility issue between pip10 and virtualenv16 (travis) --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9e9c826f..42d594fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ sudo: false install: - pip install tox -script: + - if [[ $TRAVIS_PYTHON_VERSION == 3.3 ]]; then pip install virtualenv==15.2.0; fi +script: - tox language: - python From 4d3573dd6fa5ce36d41dd37fc0974ad31a48522a Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Fri, 22 Jun 2018 10:39:56 +0300 Subject: [PATCH 3/8] Regenerate C sources using Cython 0.28.3 --- docs/main/changelog.rst | 4 ++++ requirements-dev.txt | 2 +- src/dependency_injector/containers.c | 17 ++++++++++++----- src/dependency_injector/providers.c | 17 ++++++++++++----- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 6e7287b0..2a326b7c 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -10,6 +10,10 @@ follows `Semantic versioning`_ Development version ------------------- - Add new example miniapp "ioc_container". +- Fix incompatibility issue between Python 3.3, pip 10.0.0 and virtualenv + 16.0.0 (`details `_) + that caused failures of Python 3.3 tests on Travis. +- Regenerate C sources using Cython 0.28.3. 3.12.0 ------ diff --git a/requirements-dev.txt b/requirements-dev.txt index 537818f7..c4a4aac5 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,4 @@ -cython==0.27.3 +cython==0.28.3 tox unittest2 coverage diff --git a/src/dependency_injector/containers.c b/src/dependency_injector/containers.c index aa106f14..9aa65b9c 100644 --- a/src/dependency_injector/containers.c +++ b/src/dependency_injector/containers.c @@ -1,4 +1,4 @@ -/* Generated by Cython 0.28.2 */ +/* Generated by Cython 0.28.3 */ #define PY_SSIZE_T_CLEAN #include "Python.h" @@ -7,7 +7,7 @@ #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) #error Cython requires Python 2.6+ or Python 3.3+. #else -#define CYTHON_ABI "0_28_2" +#define CYTHON_ABI "0_28_3" #define CYTHON_FUTURE_DIVISION 0 #include #ifndef offsetof @@ -453,6 +453,7 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { #define PyString_Type PyUnicode_Type #define PyString_Check PyUnicode_Check #define PyString_CheckExact PyUnicode_CheckExact + #define PyObject_Unicode PyObject_Str #endif #if PY_MAJOR_VERSION >= 3 #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) @@ -645,7 +646,7 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { #define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode #define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) #define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) -#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False)) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); #define __Pyx_PySequence_Tuple(obj)\ @@ -753,7 +754,7 @@ static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } static PyObject *__pyx_m = NULL; static PyObject *__pyx_d; static PyObject *__pyx_b; -static PyObject *__pyx_cython_runtime; +static PyObject *__pyx_cython_runtime = NULL; static PyObject *__pyx_empty_tuple; static PyObject *__pyx_empty_bytes; static PyObject *__pyx_empty_unicode; @@ -11455,7 +11456,7 @@ static int __Pyx_modinit_function_import_code(void) { #ifndef CYTHON_SMALL_CODE #if defined(__clang__) #define CYTHON_SMALL_CODE -#elif defined(__GNUC__) +#elif defined(__GNUC__) && (!(defined(__cplusplus)) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))) #define CYTHON_SMALL_CODE __attribute__((optimize("Os"))) #else #define CYTHON_SMALL_CODE @@ -14131,6 +14132,9 @@ static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_li #if CYTHON_COMPILING_IN_CPYTHON PyObject **cython_runtime_dict; #endif + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); #if CYTHON_COMPILING_IN_CPYTHON cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); @@ -16325,6 +16329,9 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { Py_DECREF(x); return ival; } +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { return PyInt_FromSize_t(ival); } diff --git a/src/dependency_injector/providers.c b/src/dependency_injector/providers.c index bc8da2eb..70834f83 100644 --- a/src/dependency_injector/providers.c +++ b/src/dependency_injector/providers.c @@ -1,4 +1,4 @@ -/* Generated by Cython 0.28.2 */ +/* Generated by Cython 0.28.3 */ #define PY_SSIZE_T_CLEAN #include "Python.h" @@ -7,7 +7,7 @@ #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) #error Cython requires Python 2.6+ or Python 3.3+. #else -#define CYTHON_ABI "0_28_2" +#define CYTHON_ABI "0_28_3" #define CYTHON_FUTURE_DIVISION 0 #include #ifndef offsetof @@ -453,6 +453,7 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { #define PyString_Type PyUnicode_Type #define PyString_Check PyUnicode_Check #define PyString_CheckExact PyUnicode_CheckExact + #define PyObject_Unicode PyObject_Str #endif #if PY_MAJOR_VERSION >= 3 #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) @@ -645,7 +646,7 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { #define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode #define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) #define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) -#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False)) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); #define __Pyx_PySequence_Tuple(obj)\ @@ -753,7 +754,7 @@ static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } static PyObject *__pyx_m = NULL; static PyObject *__pyx_d; static PyObject *__pyx_b; -static PyObject *__pyx_cython_runtime; +static PyObject *__pyx_cython_runtime = NULL; static PyObject *__pyx_empty_tuple; static PyObject *__pyx_empty_bytes; static PyObject *__pyx_empty_unicode; @@ -56515,7 +56516,7 @@ static int __Pyx_modinit_function_import_code(void) { #ifndef CYTHON_SMALL_CODE #if defined(__clang__) #define CYTHON_SMALL_CODE -#elif defined(__GNUC__) +#elif defined(__GNUC__) && (!(defined(__cplusplus)) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))) #define CYTHON_SMALL_CODE __attribute__((optimize("Os"))) #else #define CYTHON_SMALL_CODE @@ -59958,6 +59959,9 @@ static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_li #if CYTHON_COMPILING_IN_CPYTHON PyObject **cython_runtime_dict; #endif + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); #if CYTHON_COMPILING_IN_CPYTHON cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); @@ -60939,6 +60943,9 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { Py_DECREF(x); return ival; } +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { return PyInt_FromSize_t(ival); } From 32a8052715fabf58d9cb61cff739b2872ad45614 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Wed, 27 Jun 2018 17:37:03 +0300 Subject: [PATCH 4/8] Update main page example and fix few typos --- README.rst | 86 ++++++++++++++++++++--------------------- docs/main/changelog.rst | 2 + 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/README.rst b/README.rst index fd9335c2..2d2f86b0 100644 --- a/README.rst +++ b/README.rst @@ -270,9 +270,9 @@ Dependency Injector in action ----------------------------- Brief example below is a simplified version of inversion of control -containters from one of the real-life applications. This example demonstrates -usage of *Dependency Injector* inversion of control containers & providers -for specifying all application components and their dependencies beetween +container from one of the real-life applications. This example demonstrates +usage of *Dependency Injector* inversion of control container & providers +for specifying all application components and their dependencies between each other in one module. Besides other listed above advantages, it gives a great opportunity to control & manage application's structure in one place. @@ -292,75 +292,73 @@ great opportunity to control & manage application's structure in one place. import dependency_injector.providers as providers - class Core(containers.DeclarativeContainer): - """IoC container of core component providers.""" + class IocContainer(containers.DeclarativeContainer): + """Application IoC container.""" config = providers.Configuration('config') - logger = providers.Singleton(logging.Logger, name='example') + # Gateways - class Gateways(containers.DeclarativeContainer): - """IoC container of gateway (API clients to remote services) providers.""" + database_client = providers.Singleton(sqlite3.connect, config.database.dsn) - database = providers.Singleton(sqlite3.connect, Core.config.database.dsn) - - s3 = providers.Singleton( + s3_client = providers.Singleton( boto3.client, 's3', - aws_access_key_id=Core.config.aws.access_key_id, - aws_secret_access_key=Core.config.aws.secret_access_key) + aws_access_key_id=config.aws.access_key_id, + aws_secret_access_key=config.aws.secret_access_key) + # Services - class Services(containers.DeclarativeContainer): - """IoC container of business service providers.""" + users_service = providers.Factory( + example.services.UsersService, + db=database_client, + logger=logger) - users = providers.Factory(example.services.UsersService, - db=Gateways.database, - logger=Core.logger) + auth_service = providers.Factory( + example.services.AuthService, + token_ttl=config.auth.token_ttl, + db=database_client, + logger=logger) - auth = providers.Factory(example.services.AuthService, - db=Gateways.database, - logger=Core.logger, - token_ttl=Core.config.auth.token_ttl) + photos_service = providers.Factory( + example.services.PhotosService, + db=database_client, + s3=s3_client, + logger=logger) - photos = providers.Factory(example.services.PhotosService, - db=Gateways.database, - s3=Gateways.s3, - logger=Core.logger) + # Misc - - class Application(containers.DeclarativeContainer): - """IoC container of application component providers.""" - - main = providers.Callable(example.main.main, - users_service=Services.users, - auth_service=Services.auth, - photos_service=Services.photos) + main = providers.Callable( + example.main.main, + users_service=users_service, + auth_service=auth_service, + photos_service=photos_service) Next example demonstrates run of example application defined above: .. code-block:: python - """Run example application.""" + """Run example of dependency injection in Python.""" import sys import logging - from containers import Core, Application + from container import IocContainer if __name__ == '__main__': # Configure platform: - Core.config.override({'database': {'dsn': ':memory:'}, - 'aws': {'access_key_id': 'KEY', - 'secret_access_key': 'SECRET'}, - 'auth': {'token_ttl': 3600}}) - Core.logger().addHandler(logging.StreamHandler(sys.stdout)) + container = IocContainer( + config={'database': {'dsn': ':memory:'}, + 'aws': {'access_key_id': 'KEY', + 'secret_access_key': 'SECRET'}, + 'auth': {'token_ttl': 3600}}) + container.logger().addHandler(logging.StreamHandler(sys.stdout)) # Run application: - Application.main(uid=sys.argv[1], - password=sys.argv[2], - photo=sys.argv[3]) + container.main(uid=sys.argv[1], + password=sys.argv[2], + photo=sys.argv[3]) You can get more *Dependency Injector* examples in ``/examples`` directory on GitHub: diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 2a326b7c..0f48a211 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -9,6 +9,8 @@ follows `Semantic versioning`_ Development version ------------------- +- Update main page example from "services" to "ioc_container". +- Fix few typos on main page. - Add new example miniapp "ioc_container". - Fix incompatibility issue between Python 3.3, pip 10.0.0 and virtualenv 16.0.0 (`details `_) From 96b44004b17add80613fe9413451d95ffc98fde1 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Wed, 27 Jun 2018 19:06:56 +0300 Subject: [PATCH 5/8] Refactor example miniapps - services_v1, services_v2 --- docs/examples/index.rst | 3 +- ...es_miniapp.rst => services_miniapp_v1.rst} | 15 +-- docs/examples/services_miniapp_v2.rst | 77 +++++++++++++ .../miniapps/ioc_container/example/main.py | 27 ----- .../ioc_container/example/services.py | 103 ------------------ examples/miniapps/services/example/main.py | 27 ----- .../miniapps/services/example/services.py | 103 ------------------ .../{ioc_container => services_v1}/README.rst | 0 .../{services => services_v1}/containers.py | 0 .../example/__init__.py | 0 examples/miniapps/services_v1/example/main.py | 8 ++ .../miniapps/services_v1/example/services.py | 50 +++++++++ .../miniapps/{services => services_v1}/run.py | 0 .../{services => services_v2}/README.rst | 0 .../container.py | 0 .../example/__init__.py | 0 examples/miniapps/services_v2/example/main.py | 8 ++ .../miniapps/services_v2/example/services.py | 50 +++++++++ .../{ioc_container => services_v2}/run.py | 0 19 files changed, 203 insertions(+), 268 deletions(-) rename docs/examples/{services_miniapp.rst => services_miniapp_v1.rst} (72%) create mode 100644 docs/examples/services_miniapp_v2.rst delete mode 100644 examples/miniapps/ioc_container/example/main.py delete mode 100644 examples/miniapps/ioc_container/example/services.py delete mode 100644 examples/miniapps/services/example/main.py delete mode 100644 examples/miniapps/services/example/services.py rename examples/miniapps/{ioc_container => services_v1}/README.rst (100%) rename examples/miniapps/{services => services_v1}/containers.py (100%) rename examples/miniapps/{ioc_container => services_v1}/example/__init__.py (100%) create mode 100644 examples/miniapps/services_v1/example/main.py create mode 100644 examples/miniapps/services_v1/example/services.py rename examples/miniapps/{services => services_v1}/run.py (100%) rename examples/miniapps/{services => services_v2}/README.rst (100%) rename examples/miniapps/{ioc_container => services_v2}/container.py (100%) rename examples/miniapps/{services => services_v2}/example/__init__.py (100%) create mode 100644 examples/miniapps/services_v2/example/main.py create mode 100644 examples/miniapps/services_v2/example/services.py rename examples/miniapps/{ioc_container => services_v2}/run.py (100%) diff --git a/docs/examples/index.rst b/docs/examples/index.rst index 7c375cd8..ac1a59da 100644 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -16,6 +16,7 @@ and powered by *Dependency Injector* framework. :maxdepth: 2 movie_lister - services_miniapp + services_miniapp_v1 + services_miniapp_v2 bundles_miniapp use_cases_miniapp diff --git a/docs/examples/services_miniapp.rst b/docs/examples/services_miniapp_v1.rst similarity index 72% rename from docs/examples/services_miniapp.rst rename to docs/examples/services_miniapp_v1.rst index b274e8bc..aa0df055 100644 --- a/docs/examples/services_miniapp.rst +++ b/docs/examples/services_miniapp_v1.rst @@ -1,5 +1,5 @@ -Services mini application example ---------------------------------- +Services mini application example (v1 - multiple containers) +------------------------------------------------------------ .. meta:: :description: "Services miniapp" is an example mini application that @@ -7,7 +7,8 @@ Services mini application example some standard and 3rd-party libraries for logging, interaction with database and remote service via API. "Services miniapp" example demonstrates usage of - Dependency Injector for creating several IoC containers. + Dependency Injector for creating several inversion of control / + dependency injection containers. "Services miniapp" is an example mini application that consists from several services that have dependencies on some standard and 3rd-party libraries for @@ -44,13 +45,13 @@ Example application structure: Listing of ``example/services.py``: -.. literalinclude:: ../../examples/miniapps/services/example/services.py +.. literalinclude:: ../../examples/miniapps/services_v1/example/services.py :language: python :linenos: Listing of ``example/main.py``: -.. literalinclude:: ../../examples/miniapps/services/example/main.py +.. literalinclude:: ../../examples/miniapps/services_v1/example/main.py :language: python :linenos: @@ -59,7 +60,7 @@ IoC containers Listing of ``containers.py``: -.. literalinclude:: ../../examples/miniapps/services/containers.py +.. literalinclude:: ../../examples/miniapps/services_v1/containers.py :language: python :linenos: @@ -68,7 +69,7 @@ Run application Listing of ``run.py``: -.. literalinclude:: ../../examples/miniapps/services/run.py +.. literalinclude:: ../../examples/miniapps/services_v1/run.py :language: python :linenos: diff --git a/docs/examples/services_miniapp_v2.rst b/docs/examples/services_miniapp_v2.rst new file mode 100644 index 00000000..b507c606 --- /dev/null +++ b/docs/examples/services_miniapp_v2.rst @@ -0,0 +1,77 @@ +Services mini application example (v2 - single container) +--------------------------------------------------------- + +.. meta:: + :description: "Services miniapp" is an example mini application that + consists from several services that have dependencies on + some standard and 3rd-party libraries for logging, + interaction with database and remote service via API. + "Services miniapp" example demonstrates usage of + Dependency Injector for creating inversion of control / + dependency injection container. + +"Services miniapp" is an example mini application that consists from several +services that have dependencies on some standard and 3rd-party libraries for +logging, interaction with database and remote service calls via API. + +"Services miniapp" example demonstrates usage of +:doc:`Dependency Injector <../index>` for creating IoC container. + +Instructions for running: + +.. code-block:: bash + + python run.py 1 secret photo.jpg + +Example application +~~~~~~~~~~~~~~~~~~~ + +Classes diagram: + +.. image:: /images/miniapps/services/classes.png + :width: 100% + :align: center + + +Example application structure: + +.. code-block:: bash + + /example + /__init__.py + /main.py + /services.py + + +Listing of ``example/services.py``: + +.. literalinclude:: ../../examples/miniapps/services_v2/example/services.py + :language: python + :linenos: + +Listing of ``example/main.py``: + +.. literalinclude:: ../../examples/miniapps/services_v2/example/main.py + :language: python + :linenos: + +IoC container +~~~~~~~~~~~~~ + +Listing of ``container.py``: + +.. literalinclude:: ../../examples/miniapps/services_v2/container.py + :language: python + :linenos: + +Run application +~~~~~~~~~~~~~~~ + +Listing of ``run.py``: + +.. literalinclude:: ../../examples/miniapps/services_v2/run.py + :language: python + :linenos: + + +.. disqus:: diff --git a/examples/miniapps/ioc_container/example/main.py b/examples/miniapps/ioc_container/example/main.py deleted file mode 100644 index f1386c1a..00000000 --- a/examples/miniapps/ioc_container/example/main.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Example main module.""" - - -def main(uid, password, photo, users_service, auth_service, photos_service): - """Authenticate user and upload photo. - - :param uid: User identifier. - :type uid: int - - :param password: User's password for verification. - :type password: str - - :param photo_path: Path to photo for uploading. - :type photo_path: str - - :param users_service: Users service. - :type users_service: example.services.UsersService - - :param auth_service: Authentication service. - :type auth_service: example.services.AuthService - - :param photo_service: Photo service. - :type photo_service: example.services.PhotoService - """ - user = users_service.get_user_by_id(uid) - auth_service.authenticate(user, password) - photos_service.upload_photo(user['uid'], photo) diff --git a/examples/miniapps/ioc_container/example/services.py b/examples/miniapps/ioc_container/example/services.py deleted file mode 100644 index 77e1ae99..00000000 --- a/examples/miniapps/ioc_container/example/services.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Example business services module.""" - - -class BaseService(object): - """Service base class.""" - - -class UsersService(BaseService): - """Users service.""" - - def __init__(self, logger, db): - """Initializer. - - :param logger: Logger instance. - :type logger: logging.Logger - - :param db: Database connection. - :type db: sqlite3.Connection - """ - self.logger = logger - self.db = db - - def get_user_by_id(self, uid): - """Return user's data by identifier. - - :param uid: User identifier. - :type uid: int - - :rtype: dict - """ - self.logger.debug('User %s has been found in database', uid) - return dict(uid=uid, password_hash='secret_hash') - - -class AuthService(BaseService): - """Authentication service.""" - - def __init__(self, logger, db, token_ttl): - """Initializer. - - :param logger: Logger instance. - :type logger: logging.Logger - - :param db: Database connection. - :type db: sqlite3.Connection - - :param token_ttl: Token lifetime in seconds. - :type token_ttl: int - """ - self.logger = logger - self.db = db - self.token_ttl = token_ttl - - def authenticate(self, user, password): - """Authenticate user. - - :param user: User's data. - :type user: dict - - :param password: User's password for verification. - :type password: str - - :raises: AssertionError when password is wrong - - :rtype: None - """ - assert user['password_hash'] == '_'.join((password, 'hash')) - self.logger.debug('User %s has been successfully authenticated', - user['uid']) - - -class PhotosService(BaseService): - """Photos service.""" - - def __init__(self, logger, db, s3): - """Initializer. - - :param logger: Logger instance. - :type logger: logging.Logger - - :param db: Database connection. - :type db: sqlite3.Connection - - :param s3: AWS S3 client. - :type s3: botocore.client.S3 - """ - self.logger = logger - self.db = db - self.s3 = s3 - - def upload_photo(self, uid, photo_path): - """Upload user photo. - - :param uid: User identifier. - :type uid: int - - :param photo_path: Path to photo for uploading. - :type photo_path: str - - :rtpe: None - """ - self.logger.debug('Photo %s has been successfully uploaded by user %s', - photo_path, uid) diff --git a/examples/miniapps/services/example/main.py b/examples/miniapps/services/example/main.py deleted file mode 100644 index f1386c1a..00000000 --- a/examples/miniapps/services/example/main.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Example main module.""" - - -def main(uid, password, photo, users_service, auth_service, photos_service): - """Authenticate user and upload photo. - - :param uid: User identifier. - :type uid: int - - :param password: User's password for verification. - :type password: str - - :param photo_path: Path to photo for uploading. - :type photo_path: str - - :param users_service: Users service. - :type users_service: example.services.UsersService - - :param auth_service: Authentication service. - :type auth_service: example.services.AuthService - - :param photo_service: Photo service. - :type photo_service: example.services.PhotoService - """ - user = users_service.get_user_by_id(uid) - auth_service.authenticate(user, password) - photos_service.upload_photo(user['uid'], photo) diff --git a/examples/miniapps/services/example/services.py b/examples/miniapps/services/example/services.py deleted file mode 100644 index 77e1ae99..00000000 --- a/examples/miniapps/services/example/services.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Example business services module.""" - - -class BaseService(object): - """Service base class.""" - - -class UsersService(BaseService): - """Users service.""" - - def __init__(self, logger, db): - """Initializer. - - :param logger: Logger instance. - :type logger: logging.Logger - - :param db: Database connection. - :type db: sqlite3.Connection - """ - self.logger = logger - self.db = db - - def get_user_by_id(self, uid): - """Return user's data by identifier. - - :param uid: User identifier. - :type uid: int - - :rtype: dict - """ - self.logger.debug('User %s has been found in database', uid) - return dict(uid=uid, password_hash='secret_hash') - - -class AuthService(BaseService): - """Authentication service.""" - - def __init__(self, logger, db, token_ttl): - """Initializer. - - :param logger: Logger instance. - :type logger: logging.Logger - - :param db: Database connection. - :type db: sqlite3.Connection - - :param token_ttl: Token lifetime in seconds. - :type token_ttl: int - """ - self.logger = logger - self.db = db - self.token_ttl = token_ttl - - def authenticate(self, user, password): - """Authenticate user. - - :param user: User's data. - :type user: dict - - :param password: User's password for verification. - :type password: str - - :raises: AssertionError when password is wrong - - :rtype: None - """ - assert user['password_hash'] == '_'.join((password, 'hash')) - self.logger.debug('User %s has been successfully authenticated', - user['uid']) - - -class PhotosService(BaseService): - """Photos service.""" - - def __init__(self, logger, db, s3): - """Initializer. - - :param logger: Logger instance. - :type logger: logging.Logger - - :param db: Database connection. - :type db: sqlite3.Connection - - :param s3: AWS S3 client. - :type s3: botocore.client.S3 - """ - self.logger = logger - self.db = db - self.s3 = s3 - - def upload_photo(self, uid, photo_path): - """Upload user photo. - - :param uid: User identifier. - :type uid: int - - :param photo_path: Path to photo for uploading. - :type photo_path: str - - :rtpe: None - """ - self.logger.debug('Photo %s has been successfully uploaded by user %s', - photo_path, uid) diff --git a/examples/miniapps/ioc_container/README.rst b/examples/miniapps/services_v1/README.rst similarity index 100% rename from examples/miniapps/ioc_container/README.rst rename to examples/miniapps/services_v1/README.rst diff --git a/examples/miniapps/services/containers.py b/examples/miniapps/services_v1/containers.py similarity index 100% rename from examples/miniapps/services/containers.py rename to examples/miniapps/services_v1/containers.py diff --git a/examples/miniapps/ioc_container/example/__init__.py b/examples/miniapps/services_v1/example/__init__.py similarity index 100% rename from examples/miniapps/ioc_container/example/__init__.py rename to examples/miniapps/services_v1/example/__init__.py diff --git a/examples/miniapps/services_v1/example/main.py b/examples/miniapps/services_v1/example/main.py new file mode 100644 index 00000000..2f80a1c7 --- /dev/null +++ b/examples/miniapps/services_v1/example/main.py @@ -0,0 +1,8 @@ +"""Example main module.""" + + +def main(uid, password, photo, users_service, auth_service, photos_service): + """Authenticate user and upload photo.""" + user = users_service.get_user_by_id(uid) + auth_service.authenticate(user, password) + photos_service.upload_photo(user['uid'], photo) diff --git a/examples/miniapps/services_v1/example/services.py b/examples/miniapps/services_v1/example/services.py new file mode 100644 index 00000000..c3b1b7cf --- /dev/null +++ b/examples/miniapps/services_v1/example/services.py @@ -0,0 +1,50 @@ +"""Example business services module.""" + + +class BaseService(object): + """Service base class.""" + + +class UsersService(BaseService): + """Users service.""" + + def __init__(self, logger, db): + """Initializer.""" + self.logger = logger + self.db = db + + def get_user_by_id(self, uid): + """Return user's data by identifier.""" + self.logger.debug('User %s has been found in database', uid) + return dict(uid=uid, password_hash='secret_hash') + + +class AuthService(BaseService): + """Authentication service.""" + + def __init__(self, logger, db, token_ttl): + """Initializer.""" + self.logger = logger + self.db = db + self.token_ttl = token_ttl + + def authenticate(self, user, password): + """Authenticate user.""" + assert user['password_hash'] == '_'.join((password, 'hash')) + self.logger.debug('User %s has been successfully authenticated', + user['uid']) + + +class PhotosService(BaseService): + """Photos service.""" + + def __init__(self, logger, db, s3): + """Initializer.""" + self.logger = logger + self.db = db + self.s3 = s3 + + def upload_photo(self, uid, photo_path): + """Upload user photo.""" + self.logger.debug('Photo %s has been successfully uploaded by user %s', + photo_path, uid) diff --git a/examples/miniapps/services/run.py b/examples/miniapps/services_v1/run.py similarity index 100% rename from examples/miniapps/services/run.py rename to examples/miniapps/services_v1/run.py diff --git a/examples/miniapps/services/README.rst b/examples/miniapps/services_v2/README.rst similarity index 100% rename from examples/miniapps/services/README.rst rename to examples/miniapps/services_v2/README.rst diff --git a/examples/miniapps/ioc_container/container.py b/examples/miniapps/services_v2/container.py similarity index 100% rename from examples/miniapps/ioc_container/container.py rename to examples/miniapps/services_v2/container.py diff --git a/examples/miniapps/services/example/__init__.py b/examples/miniapps/services_v2/example/__init__.py similarity index 100% rename from examples/miniapps/services/example/__init__.py rename to examples/miniapps/services_v2/example/__init__.py diff --git a/examples/miniapps/services_v2/example/main.py b/examples/miniapps/services_v2/example/main.py new file mode 100644 index 00000000..2f80a1c7 --- /dev/null +++ b/examples/miniapps/services_v2/example/main.py @@ -0,0 +1,8 @@ +"""Example main module.""" + + +def main(uid, password, photo, users_service, auth_service, photos_service): + """Authenticate user and upload photo.""" + user = users_service.get_user_by_id(uid) + auth_service.authenticate(user, password) + photos_service.upload_photo(user['uid'], photo) diff --git a/examples/miniapps/services_v2/example/services.py b/examples/miniapps/services_v2/example/services.py new file mode 100644 index 00000000..c3b1b7cf --- /dev/null +++ b/examples/miniapps/services_v2/example/services.py @@ -0,0 +1,50 @@ +"""Example business services module.""" + + +class BaseService(object): + """Service base class.""" + + +class UsersService(BaseService): + """Users service.""" + + def __init__(self, logger, db): + """Initializer.""" + self.logger = logger + self.db = db + + def get_user_by_id(self, uid): + """Return user's data by identifier.""" + self.logger.debug('User %s has been found in database', uid) + return dict(uid=uid, password_hash='secret_hash') + + +class AuthService(BaseService): + """Authentication service.""" + + def __init__(self, logger, db, token_ttl): + """Initializer.""" + self.logger = logger + self.db = db + self.token_ttl = token_ttl + + def authenticate(self, user, password): + """Authenticate user.""" + assert user['password_hash'] == '_'.join((password, 'hash')) + self.logger.debug('User %s has been successfully authenticated', + user['uid']) + + +class PhotosService(BaseService): + """Photos service.""" + + def __init__(self, logger, db, s3): + """Initializer.""" + self.logger = logger + self.db = db + self.s3 = s3 + + def upload_photo(self, uid, photo_path): + """Upload user photo.""" + self.logger.debug('Photo %s has been successfully uploaded by user %s', + photo_path, uid) diff --git a/examples/miniapps/ioc_container/run.py b/examples/miniapps/services_v2/run.py similarity index 100% rename from examples/miniapps/ioc_container/run.py rename to examples/miniapps/services_v2/run.py From a8dd335d71d812498e8ec9c4dc7dd730a2528d88 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Wed, 27 Jun 2018 19:29:55 +0300 Subject: [PATCH 6/8] Add example of callable delegation --- docs/examples/index.rst | 1 + docs/examples/password_hashing_miniapp.rst | 19 +++++++++ docs/main/changelog.rst | 6 ++- examples/miniapps/password_hashing/README.rst | 12 ++++++ examples/miniapps/password_hashing/example.py | 42 +++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 docs/examples/password_hashing_miniapp.rst create mode 100644 examples/miniapps/password_hashing/README.rst create mode 100644 examples/miniapps/password_hashing/example.py diff --git a/docs/examples/index.rst b/docs/examples/index.rst index ac1a59da..977a35a2 100644 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -20,3 +20,4 @@ and powered by *Dependency Injector* framework. services_miniapp_v2 bundles_miniapp use_cases_miniapp + password_hashing_miniapp diff --git a/docs/examples/password_hashing_miniapp.rst b/docs/examples/password_hashing_miniapp.rst new file mode 100644 index 00000000..45eb1d4c --- /dev/null +++ b/docs/examples/password_hashing_miniapp.rst @@ -0,0 +1,19 @@ +Dependency injection and password hashing in Python +=================================================== + +Small example that demonstrates using of dependency injection for user +password hashing. + +Instructions for running: + +.. code-block:: bash + + python example.py + +Listing of ``example.py``: + +.. literalinclude:: ../../examples/miniapps/password_hashing/example.py + :language: python + :linenos: + +.. disqus:: diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 0f48a211..503e2714 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -9,9 +9,11 @@ follows `Semantic versioning`_ Development version ------------------- -- Update main page example from "services" to "ioc_container". +- Update main page example from "services_v1" to "services_v2". - Fix few typos on main page. -- Add new example miniapp "ioc_container". +- Add new example miniapp "password_hashing". +- Add new example miniapp "services_v2". +- Rename example miniapp "services" to "services_v1". - Fix incompatibility issue between Python 3.3, pip 10.0.0 and virtualenv 16.0.0 (`details `_) that caused failures of Python 3.3 tests on Travis. diff --git a/examples/miniapps/password_hashing/README.rst b/examples/miniapps/password_hashing/README.rst new file mode 100644 index 00000000..9c306ab5 --- /dev/null +++ b/examples/miniapps/password_hashing/README.rst @@ -0,0 +1,12 @@ +Dependency injection and password hashing in Python +=================================================== + +Small example that demonstrates using of dependency injection for user +password hashing. + + +instructions for running: + +.. code-block:: bash + + python example.py diff --git a/examples/miniapps/password_hashing/example.py b/examples/miniapps/password_hashing/example.py new file mode 100644 index 00000000..a291485d --- /dev/null +++ b/examples/miniapps/password_hashing/example.py @@ -0,0 +1,42 @@ +"""Example of dependency injection and password hashing in Python.""" + +import passlib.hash + +import dependency_injector.containers as containers +import dependency_injector.providers as providers + + +class UsersService(object): + """Users service.""" + + def __init__(self, password_hasher): + """Initializer.""" + self._password_hasher = password_hasher + + def create_user(self, name, password): + """Create user with hashed password.""" + hashed_password = self._password_hasher(password) + return dict(name=name, password=hashed_password) + + +class Container(containers.DeclarativeContainer): + """Inversion of control container.""" + + password_hasher = providers.Callable( + passlib.hash.sha256_crypt.encrypt, + salt_size=16, + rounds=10000) + + users_service = providers.Factory( + UsersService, + password_hasher=password_hasher.provider) + + +if __name__ == '__main__': + container = Container() + users_service = container.users_service() + + user1 = users_service.create_user(name='Roman', password='secret1') + user2 = users_service.create_user(name='Vitaly', password='secret2') + + print(user1, user2) From f1c1a4ed0cabf707eda583b4b9e9cb2d81a75574 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Mon, 2 Jul 2018 16:43:23 +0300 Subject: [PATCH 7/8] Change code layout of services_v2 miniapp --- README.rst | 53 +++++++++++++--------- examples/miniapps/services_v2/container.py | 30 ++++++------ examples/miniapps/services_v2/run.py | 23 ++++++---- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/README.rst b/README.rst index 2d2f86b0..bb6ae685 100644 --- a/README.rst +++ b/README.rst @@ -285,11 +285,8 @@ great opportunity to control & manage application's structure in one place. import boto3 - import example.main - import example.services - - import dependency_injector.containers as containers - import dependency_injector.providers as providers + from dependency_injector import containers, providers + from example import services, main class IocContainer(containers.DeclarativeContainer): @@ -305,34 +302,39 @@ great opportunity to control & manage application's structure in one place. s3_client = providers.Singleton( boto3.client, 's3', aws_access_key_id=config.aws.access_key_id, - aws_secret_access_key=config.aws.secret_access_key) + aws_secret_access_key=config.aws.secret_access_key + ) # Services users_service = providers.Factory( - example.services.UsersService, + services.UsersService, db=database_client, - logger=logger) + logger=logger + ) auth_service = providers.Factory( - example.services.AuthService, + services.AuthService, token_ttl=config.auth.token_ttl, db=database_client, - logger=logger) + logger=logger + ) photos_service = providers.Factory( - example.services.PhotosService, + services.PhotosService, db=database_client, s3=s3_client, - logger=logger) + logger=logger + ) # Misc main = providers.Callable( - example.main.main, + main.main, users_service=users_service, auth_service=auth_service, - photos_service=photos_service) + photos_service=photos_service + ) Next example demonstrates run of example application defined above: @@ -347,18 +349,25 @@ Next example demonstrates run of example application defined above: if __name__ == '__main__': - # Configure platform: + # Configure container: container = IocContainer( - config={'database': {'dsn': ':memory:'}, - 'aws': {'access_key_id': 'KEY', - 'secret_access_key': 'SECRET'}, - 'auth': {'token_ttl': 3600}}) + config={ + 'database': { + 'dsn': ':memory:' + }, + 'aws': { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET' + }, + 'auth': { + 'token_ttl': 3600 + } + } + ) container.logger().addHandler(logging.StreamHandler(sys.stdout)) # Run application: - container.main(uid=sys.argv[1], - password=sys.argv[2], - photo=sys.argv[3]) + container.main(*sys.argv[1:]) You can get more *Dependency Injector* examples in ``/examples`` directory on GitHub: diff --git a/examples/miniapps/services_v2/container.py b/examples/miniapps/services_v2/container.py index 39e3be89..863b612a 100644 --- a/examples/miniapps/services_v2/container.py +++ b/examples/miniapps/services_v2/container.py @@ -5,11 +5,8 @@ import sqlite3 import boto3 -import example.main -import example.services - -import dependency_injector.containers as containers -import dependency_injector.providers as providers +from dependency_injector import containers, providers +from example import services, main class IocContainer(containers.DeclarativeContainer): @@ -25,31 +22,36 @@ class IocContainer(containers.DeclarativeContainer): s3_client = providers.Singleton( boto3.client, 's3', aws_access_key_id=config.aws.access_key_id, - aws_secret_access_key=config.aws.secret_access_key) + aws_secret_access_key=config.aws.secret_access_key + ) # Services users_service = providers.Factory( - example.services.UsersService, + services.UsersService, db=database_client, - logger=logger) + logger=logger + ) auth_service = providers.Factory( - example.services.AuthService, + services.AuthService, token_ttl=config.auth.token_ttl, db=database_client, - logger=logger) + logger=logger + ) photos_service = providers.Factory( - example.services.PhotosService, + services.PhotosService, db=database_client, s3=s3_client, - logger=logger) + logger=logger + ) # Misc main = providers.Callable( - example.main.main, + main.main, users_service=users_service, auth_service=auth_service, - photos_service=photos_service) + photos_service=photos_service + ) diff --git a/examples/miniapps/services_v2/run.py b/examples/miniapps/services_v2/run.py index 50caff94..30af1c07 100644 --- a/examples/miniapps/services_v2/run.py +++ b/examples/miniapps/services_v2/run.py @@ -7,15 +7,22 @@ from container import IocContainer if __name__ == '__main__': - # Configure platform: + # Configure container: container = IocContainer( - config={'database': {'dsn': ':memory:'}, - 'aws': {'access_key_id': 'KEY', - 'secret_access_key': 'SECRET'}, - 'auth': {'token_ttl': 3600}}) + config={ + 'database': { + 'dsn': ':memory:' + }, + 'aws': { + 'access_key_id': 'KEY', + 'secret_access_key': 'SECRET' + }, + 'auth': { + 'token_ttl': 3600 + } + } + ) container.logger().addHandler(logging.StreamHandler(sys.stdout)) # Run application: - container.main(uid=sys.argv[1], - password=sys.argv[2], - photo=sys.argv[3]) + container.main(*sys.argv[1:]) From 1eabebd0b82053d2214d625d1c8f775347fe66b6 Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Mon, 2 Jul 2018 16:47:46 +0300 Subject: [PATCH 8/8] Bump version to 3.12.1 --- docs/main/changelog.rst | 4 ++-- src/dependency_injector/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index 503e2714..0c96b61a 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -7,8 +7,8 @@ that were made in every particular version. From version 0.7.6 *Dependency Injector* framework strictly follows `Semantic versioning`_ -Development version -------------------- +3.12.1 +------ - Update main page example from "services_v1" to "services_v2". - Fix few typos on main page. - Add new example miniapp "password_hashing". diff --git a/src/dependency_injector/__init__.py b/src/dependency_injector/__init__.py index 05506f38..500de89e 100644 --- a/src/dependency_injector/__init__.py +++ b/src/dependency_injector/__init__.py @@ -1,6 +1,6 @@ """Dependency injector top-level package.""" -__version__ = '3.12.0' +__version__ = '3.12.1' """Version number that follows semantic versioning. :type: str