diff --git a/docs/examples-other/bundles_miniapp.rst b/docs/examples-other/bundles_miniapp.rst
deleted file mode 100644
index 4be60cb5..00000000
--- a/docs/examples-other/bundles_miniapp.rst
+++ /dev/null
@@ -1,74 +0,0 @@
-Bundles mini application example
---------------------------------
-
-.. currentmodule:: dependency_injector.containers
-
-"Bundles" is an example mini application that is intended to demonstrate the
-power of dependency injection for creation of re-usable application components
-("bundles") with 100% transparency of their dependencies.
-
-Example application
-~~~~~~~~~~~~~~~~~~~
-
-"Bundles" mini application has next structure:
-
-.. code-block:: bash
-
- bundles/
- bundles/ <-- Bundles package
- photos/ <-- Photos bundle
- __init__.py <-- Photos bundle dependency injection container
- entities.py
- repositories.py
- users/ <-- Users bundle
- __init__.py <-- Users bundle dependency injection container
- entities.py
- repositories.py
- run.py <-- Entrypoint
-
-
-IoC containers
-~~~~~~~~~~~~~~
-
-Next two listings show :py:class:`DeclarativeContainer`'s for "users" and
-"photos" bundles.
-
-Listing of ``bundles/users/__init__.py``:
-
-.. literalinclude:: ../../examples/miniapps/bundles/bundles/users/__init__.py
- :language: python
-
-.. note::
-
- - ``Users`` container has dependency on database.
-
-Listing of ``bundles/photos/__init__.py``:
-
-.. literalinclude:: ../../examples/miniapps/bundles/bundles/photos/__init__.py
- :language: python
-
-.. note::
-
- - ``Photos`` container has dependencies on database and file storage.
-
-Run application
-~~~~~~~~~~~~~~~
-
-Finally, both "bundles" are initialized by providing needed dependencies.
-Initialization of dependencies happens right in the runtime, not earlier.
-Generally, it means, that any part of any bundle could be overridden on the
-fly.
-
-Listing of ``run.py``:
-
-.. literalinclude:: ../../examples/miniapps/bundles/run.py
- :language: python
-
-Links
-~~~~~
-
-+ `Dependency Injector `_
-+ `Full example sources `_
-
-
-.. disqus::
diff --git a/docs/examples-other/index.rst b/docs/examples-other/index.rst
index e99ec099..8b082fa8 100644
--- a/docs/examples-other/index.rst
+++ b/docs/examples-other/index.rst
@@ -8,14 +8,11 @@ Other examples
of inversion of control principle and powered by
"Dependency Injector" framework.
-Current section of documentation is designed to provide several example mini
-applications that are built according to the inversion of control principle
-and powered by *Dependency Injector* framework.
+This sections contains assorted ``Dependency Injector`` examples.
.. toctree::
:maxdepth: 2
- bundles_miniapp
use_cases_miniapp
password_hashing_miniapp
chained_factories
diff --git a/docs/examples/decoupled-packages.rst b/docs/examples/decoupled-packages.rst
new file mode 100644
index 00000000..a030938e
--- /dev/null
+++ b/docs/examples/decoupled-packages.rst
@@ -0,0 +1,130 @@
+Decoupled packages example (multiple containers)
+================================================
+
+.. meta::
+ :keywords: Python,Dependency Injection,Inversion of Control,Container,Example,Application,
+ Framework,AWS,boto3,client
+ :description: This example shows how to use Dependency Injector to create Python decoupled packages.
+ To achieve a decoupling each package has a container with the components. When
+ a component needs a dependency from the outside of the package scope we use the
+ Dependency provider. The package container has no knowledge on where the
+ dependencies come from. It states a need that the dependencies must be provided.
+ This helps to decouple a package from the 3rd party dependencies and other
+ packages.
+
+This example shows how to use ``Dependency Injector`` to create decoupled packages.
+
+To achieve a decoupling each package has a container with the components. When a component needs a
+dependency from the outside of the package scope we use the ``Dependency`` provider. The package
+container has no knowledge on where the dependencies come from. It states a need that the
+dependencies must be provided. This helps to decouple a package from the 3rd party dependencies
+and other packages.
+
+To wire the packages we use an application container. Application container has all 3rd party
+dependencies and package containers. It wires the packages and dependencies to create a
+complete application.
+
+We build an example micro application that consists of 3 packages:
+
+- ``user`` - a package with user domain logic, depends on a database
+- ``photo`` - a package with photo domain logic, depends on a database and AWS S3
+- ``analytics`` - a package with analytics domain logic, depends on the ``user`` and ``photo``
+ package components
+
+.. image:: images/decoupled-packages.png
+ :width: 100%
+ :align: center
+
+Start from the scratch or jump to the section:
+
+.. contents::
+ :local:
+ :backlinks: none
+
+You can find the source code and instructions for running on the `Github `_.
+
+Application structure
+---------------------
+
+Application consists of an ``example`` package, a configuration file and a ``requirements.txt``
+file.
+
+.. code-block:: bash
+
+ ./
+ ├── example/
+ │ ├── analytics/
+ │ │ ├── __init__.py
+ │ │ ├── containers.py
+ │ │ └── services.py
+ │ ├── photo/
+ │ │ ├── __init__.py
+ │ │ ├── containers.py
+ │ │ ├── entities.py
+ │ │ └── repositories.py
+ │ ├── user/
+ │ │ ├── __init__.py
+ │ │ ├── containers.py
+ │ │ ├── entities.py
+ │ │ └── repositories.py
+ │ ├── __init__.py
+ │ ├── __main__.py
+ │ └── containers.py
+ ├── config.ini
+ └── requirements.txt
+
+Package containers
+------------------
+
+Listing of the ``example/user/containers.py``:
+
+.. literalinclude:: ../../examples/miniapps/decoupled-packages/example/user/containers.py
+ :language: python
+
+Listing of the ``example/photo/containers.py``:
+
+.. literalinclude:: ../../examples/miniapps/decoupled-packages/example/photo/containers.py
+ :language: python
+
+Listing of the ``example/analytics/containers.py``:
+
+.. literalinclude:: ../../examples/miniapps/decoupled-packages/example/analytics/containers.py
+ :language: python
+
+Application container
+---------------------
+
+Application container consists of all packages and 3rd party dependencies. Its role is to wire
+everything together in a complete application.
+
+Listing of the ``example/containers.py``:
+
+.. literalinclude:: ../../examples/miniapps/decoupled-packages/example/containers.py
+ :language: python
+
+.. note::
+ Package ``analytics`` has dependencies on the repositories from the ``user`` and
+ ``photo`` packages. This is an example of how you can pass the dependencies from one package
+ to another.
+
+Main module
+-----------
+Listing of the ``example/__main__.py``:
+
+.. literalinclude:: ../../examples/miniapps/decoupled-packages/example/__main__.py
+ :language: python
+
+Configuration
+-------------
+
+Listing of the ``config.ini``:
+
+.. literalinclude:: ../../examples/miniapps/decoupled-packages/config.ini
+ :language: ini
+
+Run the application
+-------------------
+
+You can find the source code and instructions for running on the `Github `_.
+
+.. disqus::
diff --git a/docs/examples/images/decoupled-packages.png b/docs/examples/images/decoupled-packages.png
new file mode 100644
index 00000000..4e626b0c
Binary files /dev/null and b/docs/examples/images/decoupled-packages.png differ
diff --git a/docs/examples/index.rst b/docs/examples/index.rst
index 2d3545f2..17c62462 100644
--- a/docs/examples/index.rst
+++ b/docs/examples/index.rst
@@ -12,5 +12,6 @@ Explore the examples to see the ``Dependency Injector`` in action.
application-single-container
application-multiple-containers
+ decoupled-packages
.. disqus::
diff --git a/examples/miniapps/bundles/README.rst b/examples/miniapps/bundles/README.rst
deleted file mode 100644
index a794d4b5..00000000
--- a/examples/miniapps/bundles/README.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Dependency Injector Bundles example
-===================================
-
-Instructions for running
-
-.. code-block:: bash
-
- python run.py
diff --git a/examples/miniapps/bundles/bundles/__init__.py b/examples/miniapps/bundles/bundles/__init__.py
deleted file mode 100644
index de248351..00000000
--- a/examples/miniapps/bundles/bundles/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""Bundles package."""
diff --git a/examples/miniapps/bundles/bundles/photos/__init__.py b/examples/miniapps/bundles/bundles/photos/__init__.py
deleted file mode 100644
index 08f443f4..00000000
--- a/examples/miniapps/bundles/bundles/photos/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""Photos bundle."""
-
-from dependency_injector import containers
-from dependency_injector import providers
-
-from . import entities
-from . import repositories
-
-
-class Photos(containers.DeclarativeContainer):
- """Photos bundle container."""
-
- database = providers.Dependency()
- file_storage = providers.Dependency()
-
- photo = providers.Factory(entities.Photo)
- photo_repository = providers.Singleton(repositories.PhotoRepository,
- object_factory=photo.provider,
- fs=file_storage,
- db=database)
diff --git a/examples/miniapps/bundles/bundles/photos/entities.py b/examples/miniapps/bundles/bundles/photos/entities.py
deleted file mode 100644
index f93b9f22..00000000
--- a/examples/miniapps/bundles/bundles/photos/entities.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""Photos bundle entities module."""
-
-
-class Photo:
- """Photo entity."""
diff --git a/examples/miniapps/bundles/bundles/photos/repositories.py b/examples/miniapps/bundles/bundles/photos/repositories.py
deleted file mode 100644
index 229b907e..00000000
--- a/examples/miniapps/bundles/bundles/photos/repositories.py
+++ /dev/null
@@ -1,11 +0,0 @@
-"""Photos bundle entity repositories module."""
-
-
-class PhotoRepository:
- """Photo entity repository."""
-
- def __init__(self, object_factory, fs, db):
- """Initialize instance."""
- self.object_factory = object_factory
- self.fs = fs
- self.db = db
diff --git a/examples/miniapps/bundles/bundles/users/__init__.py b/examples/miniapps/bundles/bundles/users/__init__.py
deleted file mode 100644
index 6b23144e..00000000
--- a/examples/miniapps/bundles/bundles/users/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Users bundle."""
-
-from dependency_injector import containers
-from dependency_injector import providers
-
-from . import entities
-from . import repositories
-
-
-class Users(containers.DeclarativeContainer):
- """Users bundle container."""
-
- database = providers.Dependency()
-
- user = providers.Factory(entities.User)
- user_repository = providers.Singleton(repositories.UserRepository,
- object_factory=user.provider,
- db=database)
diff --git a/examples/miniapps/bundles/bundles/users/entities.py b/examples/miniapps/bundles/bundles/users/entities.py
deleted file mode 100644
index 399b3164..00000000
--- a/examples/miniapps/bundles/bundles/users/entities.py
+++ /dev/null
@@ -1,9 +0,0 @@
-"""Users bundle entities module."""
-
-
-class User:
- """User entity."""
-
- def __init__(self, id):
- """Initialize instance."""
- self.id = id
diff --git a/examples/miniapps/bundles/bundles/users/repositories.py b/examples/miniapps/bundles/bundles/users/repositories.py
deleted file mode 100644
index cf4ad06b..00000000
--- a/examples/miniapps/bundles/bundles/users/repositories.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Users bundle entity repositories module."""
-
-
-class UserRepository:
- """User entity repository."""
-
- def __init__(self, object_factory, db):
- """Initialize instance."""
- self.object_factory = object_factory
- self.db = db
-
- def get(self, id):
- """Return user entity with given identifier."""
- return self.object_factory(id=id)
diff --git a/examples/miniapps/bundles/run.py b/examples/miniapps/bundles/run.py
deleted file mode 100644
index 3749cea6..00000000
--- a/examples/miniapps/bundles/run.py
+++ /dev/null
@@ -1,40 +0,0 @@
-"""Run 'Bundles' example application."""
-
-import sqlite3
-import boto3
-
-from dependency_injector import containers
-from dependency_injector import providers
-
-from bundles.users import Users
-from bundles.photos import Photos
-
-
-class Core(containers.DeclarativeContainer):
- """Core container."""
-
- config = providers.Configuration('config')
- sqlite = providers.Singleton(sqlite3.connect, config.database.dsn)
- s3 = providers.Singleton(
- boto3.client, 's3',
- aws_access_key_id=config.aws.access_key_id,
- aws_secret_access_key=config.aws.secret_access_key)
-
-
-if __name__ == '__main__':
- # Initializing containers
- core = Core(config={'database': {'dsn': ':memory:'},
- 'aws': {'access_key_id': 'KEY',
- 'secret_access_key': 'SECRET'}})
- users = Users(database=core.sqlite)
- photos = Photos(database=core.sqlite, file_storage=core.s3)
-
- # Fetching few users
- user_repository = users.user_repository()
- user1 = user_repository.get(id=1)
- user2 = user_repository.get(id=2)
-
- # Making some checks
- assert user1.id == 1
- assert user2.id == 2
- assert user_repository.db is core.sqlite()
diff --git a/examples/miniapps/decoupled-packages/README.rst b/examples/miniapps/decoupled-packages/README.rst
new file mode 100644
index 00000000..94b42003
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/README.rst
@@ -0,0 +1,29 @@
+Decoupled packages example
+==========================
+
+Create virtual env:
+
+.. code-block:: bash
+
+ python3 -m venv venv
+ . venv/bin/activate
+
+Install requirements:
+
+.. code-block:: bash
+
+ pip install -r requirements.txt
+
+Run:
+
+.. code-block:: bash
+
+ python -m example
+
+You should see:
+
+.. code-block:: bash
+
+ Retrieve user id=1, photos count=5
+ Retrieve user id=2, photos count=10
+ Aggregate analytics from user and photo bundles
diff --git a/examples/miniapps/decoupled-packages/config.ini b/examples/miniapps/decoupled-packages/config.ini
new file mode 100644
index 00000000..c2a88c21
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/config.ini
@@ -0,0 +1,6 @@
+[database]
+dsn=:memory:
+
+[aws]
+access_key_id=KEY
+secret_access_key=SECRET
diff --git a/examples/miniapps/decoupled-packages/example/__init__.py b/examples/miniapps/decoupled-packages/example/__init__.py
new file mode 100644
index 00000000..1c744ca5
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/__init__.py
@@ -0,0 +1 @@
+"""Top-level package."""
diff --git a/examples/miniapps/decoupled-packages/example/__main__.py b/examples/miniapps/decoupled-packages/example/__main__.py
new file mode 100644
index 00000000..2e4e74da
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/__main__.py
@@ -0,0 +1,24 @@
+"""Main module."""
+
+from .containers import ApplicationContainer
+
+
+if __name__ == '__main__':
+ application = ApplicationContainer()
+ application.config.from_ini('config.ini')
+
+ user_repository = application.user_package.user_repository()
+ photo_repository = application.photo_package.photo_repository()
+
+ user1 = user_repository.get(id=1)
+ user1_photos = photo_repository.get_photos(user1.id)
+ print(f'Retrieve user id={user1.id}, photos count={len(user1_photos)}')
+
+ user2 = user_repository.get(id=2)
+ user2_photos = photo_repository.get_photos(user2.id)
+ print(f'Retrieve user id={user2.id}, photos count={len(user2_photos)}')
+
+ aggregation_service = application.analytics_package.aggregation_service()
+ assert aggregation_service.user_repository is user_repository
+ assert aggregation_service.photo_repository is photo_repository
+ print('Aggregate analytics from user and photo packages')
diff --git a/examples/miniapps/decoupled-packages/example/analytics/__init__.py b/examples/miniapps/decoupled-packages/example/analytics/__init__.py
new file mode 100644
index 00000000..b224cd40
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/analytics/__init__.py
@@ -0,0 +1 @@
+"""Analytics package."""
diff --git a/examples/miniapps/decoupled-packages/example/analytics/containers.py b/examples/miniapps/decoupled-packages/example/analytics/containers.py
new file mode 100644
index 00000000..c4b5abba
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/analytics/containers.py
@@ -0,0 +1,17 @@
+"""Analytics containers module."""
+
+from dependency_injector import containers, providers
+
+from . import services
+
+
+class AnalyticsContainer(containers.DeclarativeContainer):
+
+ user_repository = providers.Dependency()
+ photo_repository = providers.Dependency()
+
+ aggregation_service = providers.Singleton(
+ services.AggregationService,
+ user_repository=user_repository,
+ photo_repository=photo_repository,
+ )
diff --git a/examples/miniapps/decoupled-packages/example/analytics/services.py b/examples/miniapps/decoupled-packages/example/analytics/services.py
new file mode 100644
index 00000000..46b42ae8
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/analytics/services.py
@@ -0,0 +1,8 @@
+"""Analytics services module."""
+
+
+class AggregationService:
+
+ def __init__(self, user_repository, photo_repository):
+ self.user_repository = user_repository
+ self.photo_repository = photo_repository
diff --git a/examples/miniapps/decoupled-packages/example/containers.py b/examples/miniapps/decoupled-packages/example/containers.py
new file mode 100644
index 00000000..ede2bae9
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/containers.py
@@ -0,0 +1,41 @@
+"""Containers module."""
+
+import sqlite3
+
+import boto3
+from dependency_injector import containers, providers
+
+from .user.containers import UserContainer
+from .photo.containers import PhotoContainer
+from .analytics.containers import AnalyticsContainer
+
+
+class ApplicationContainer(containers.DeclarativeContainer):
+
+ config = providers.Configuration()
+
+ sqlite = providers.Singleton(sqlite3.connect, config.database.dsn)
+
+ s3 = providers.Singleton(
+ boto3.client,
+ service_name='s3',
+ aws_access_key_id=config.aws.access_key_id,
+ aws_secret_access_key=config.aws.secret_access_key,
+ )
+
+ user_package = providers.Container(
+ UserContainer,
+ database=sqlite,
+ )
+
+ photo_package = providers.Container(
+ PhotoContainer,
+ database=sqlite,
+ file_storage=s3,
+ )
+
+ analytics_package = providers.Container(
+ AnalyticsContainer,
+ user_repository=user_package.user_repository,
+ photo_repository=photo_package.photo_repository,
+ )
diff --git a/examples/miniapps/decoupled-packages/example/photo/__init__.py b/examples/miniapps/decoupled-packages/example/photo/__init__.py
new file mode 100644
index 00000000..8ba19ff9
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/photo/__init__.py
@@ -0,0 +1 @@
+"""Photo package."""
diff --git a/examples/miniapps/decoupled-packages/example/photo/containers.py b/examples/miniapps/decoupled-packages/example/photo/containers.py
new file mode 100644
index 00000000..a192185f
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/photo/containers.py
@@ -0,0 +1,20 @@
+"""Photo containers module."""
+
+from dependency_injector import containers, providers
+
+from . import entities, repositories
+
+
+class PhotoContainer(containers.DeclarativeContainer):
+
+ database = providers.Dependency()
+ file_storage = providers.Dependency()
+
+ photo = providers.Factory(entities.Photo)
+
+ photo_repository = providers.Singleton(
+ repositories.PhotoRepository,
+ entity_factory=photo.provider,
+ fs=file_storage,
+ db=database,
+ )
diff --git a/examples/miniapps/decoupled-packages/example/photo/entities.py b/examples/miniapps/decoupled-packages/example/photo/entities.py
new file mode 100644
index 00000000..16029e34
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/photo/entities.py
@@ -0,0 +1,5 @@
+"""Photo entities module."""
+
+
+class Photo:
+ ...
diff --git a/examples/miniapps/decoupled-packages/example/photo/repositories.py b/examples/miniapps/decoupled-packages/example/photo/repositories.py
new file mode 100644
index 00000000..b3c3d3b4
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/photo/repositories.py
@@ -0,0 +1,12 @@
+"""Photo repositories module."""
+
+
+class PhotoRepository:
+
+ def __init__(self, entity_factory, fs, db):
+ self.entity_factory = entity_factory
+ self.fs = fs
+ self.db = db
+
+ def get_photos(self, user_id):
+ return [self.entity_factory() for _ in range(user_id*5)]
diff --git a/examples/miniapps/decoupled-packages/example/user/__init__.py b/examples/miniapps/decoupled-packages/example/user/__init__.py
new file mode 100644
index 00000000..ba752168
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/user/__init__.py
@@ -0,0 +1 @@
+"""User package."""
diff --git a/examples/miniapps/decoupled-packages/example/user/containers.py b/examples/miniapps/decoupled-packages/example/user/containers.py
new file mode 100644
index 00000000..e9e6ff72
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/user/containers.py
@@ -0,0 +1,18 @@
+"""User containers module."""
+
+from dependency_injector import containers, providers
+
+from . import entities, repositories
+
+
+class UserContainer(containers.DeclarativeContainer):
+
+ database = providers.Dependency()
+
+ user = providers.Factory(entities.User)
+
+ user_repository = providers.Singleton(
+ repositories.UserRepository,
+ entity_factory=user.provider,
+ db=database,
+ )
diff --git a/examples/miniapps/decoupled-packages/example/user/entities.py b/examples/miniapps/decoupled-packages/example/user/entities.py
new file mode 100644
index 00000000..b4a715ab
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/user/entities.py
@@ -0,0 +1,7 @@
+"""User entities module."""
+
+
+class User:
+
+ def __init__(self, id):
+ self.id = id
diff --git a/examples/miniapps/decoupled-packages/example/user/repositories.py b/examples/miniapps/decoupled-packages/example/user/repositories.py
new file mode 100644
index 00000000..75392433
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/example/user/repositories.py
@@ -0,0 +1,11 @@
+"""User repositories module."""
+
+
+class UserRepository:
+
+ def __init__(self, entity_factory, db):
+ self.entity_factory = entity_factory
+ self.db = db
+
+ def get(self, id):
+ return self.entity_factory(id=id)
diff --git a/examples/miniapps/decoupled-packages/requirements.txt b/examples/miniapps/decoupled-packages/requirements.txt
new file mode 100644
index 00000000..5b522e73
--- /dev/null
+++ b/examples/miniapps/decoupled-packages/requirements.txt
@@ -0,0 +1,2 @@
+dependency-injector
+boto3
diff --git a/src/dependency_injector/providers.pyi b/src/dependency_injector/providers.pyi
index 53052c76..2b8b6855 100644
--- a/src/dependency_injector/providers.pyi
+++ b/src/dependency_injector/providers.pyi
@@ -59,7 +59,7 @@ class Delegate(Provider):
class Dependency(Provider, Generic[T]):
- def __init__(self, instance_of: Type[T]) -> None: ...
+ def __init__(self, instance_of: Type[T] = object) -> None: ...
def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
@property
def provided(self) -> ProvidedInstance: ...