mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-21 14:05:11 +03:00
Merge branch 'release/3.30.0' into master
This commit is contained in:
commit
3ddf131180
|
@ -157,6 +157,7 @@ Choose one of the following:
|
||||||
- `Flask web application tutorial <http://python-dependency-injector.ets-labs.org/tutorials/flask.html>`_
|
- `Flask web application tutorial <http://python-dependency-injector.ets-labs.org/tutorials/flask.html>`_
|
||||||
- `Aiohttp REST API tutorial <http://python-dependency-injector.ets-labs.org/tutorials/aiohttp.html>`_
|
- `Aiohttp REST API tutorial <http://python-dependency-injector.ets-labs.org/tutorials/aiohttp.html>`_
|
||||||
- `Asyncio monitoring daemon tutorial <http://python-dependency-injector.ets-labs.org/tutorials/asyncio-daemon.html>`_
|
- `Asyncio monitoring daemon tutorial <http://python-dependency-injector.ets-labs.org/tutorials/asyncio-daemon.html>`_
|
||||||
|
- `CLI application tutorial <http://python-dependency-injector.ets-labs.org/tutorials/cli.html>`_
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
============
|
============
|
||||||
|
|
|
@ -15,7 +15,6 @@ and powered by *Dependency Injector* framework.
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
movie_lister
|
|
||||||
services_miniapp_v1
|
services_miniapp_v1
|
||||||
services_miniapp_v2
|
services_miniapp_v2
|
||||||
bundles_miniapp
|
bundles_miniapp
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
Movie lister naive example
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
.. meta::
|
|
||||||
:description: Movie lister - is a naive example of dependency injection and
|
|
||||||
inversion of control containers on Python. Original example
|
|
||||||
was taken from Martin Fowler's article about dependency
|
|
||||||
injection and inversion of control.
|
|
||||||
|
|
||||||
This naive example was taken from Martin Fowler's article about dependency
|
|
||||||
injection and inversion of control: http://www.martinfowler.com/articles/injection.html
|
|
||||||
|
|
||||||
Like Martin says:
|
|
||||||
|
|
||||||
.. pull-quote::
|
|
||||||
|
|
||||||
*Like all of my examples it's one of those super-simple examples;
|
|
||||||
small enough to be unreal, but hopefully enough for you to visualize
|
|
||||||
what's going on without falling into the bog of a real example.*
|
|
||||||
|
|
||||||
While original Martin's MovieLister example was a bit modified here, it
|
|
||||||
makes sense to provide some description. So, the idea of this example is to
|
|
||||||
create ``movies`` library that can be configured to work with different
|
|
||||||
movie databases (csv, sqlite, etc...) and provide 2 main features:
|
|
||||||
|
|
||||||
1. List all movies that were directed by certain person.
|
|
||||||
2. List all movies that were released in certain year.
|
|
||||||
|
|
||||||
Also this example contains 3 mini applications that are based on ``movies``
|
|
||||||
library:
|
|
||||||
|
|
||||||
1. ``app_csv.py`` - list movies by certain criteria from csv file database.
|
|
||||||
2. ``app_db.py`` - list movies by certain criteria from sqlite database.
|
|
||||||
3. ``app_db_csv.py`` - list movies by certain criteria from csv file and
|
|
||||||
sqlite databases.
|
|
||||||
|
|
||||||
Instructions for running:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python app_csv.py
|
|
||||||
python app_db.py
|
|
||||||
python app_db_csv.py
|
|
||||||
|
|
||||||
|
|
||||||
Full code of example could be found on GitHub_.
|
|
||||||
|
|
||||||
Movies library
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Classes diagram:
|
|
||||||
|
|
||||||
.. image:: /images/miniapps/movie_lister/classes.png
|
|
||||||
:width: 100%
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
|
|
||||||
Movies library structure:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
/movies
|
|
||||||
/__init__.py
|
|
||||||
/finders.py
|
|
||||||
/listers.py
|
|
||||||
/models.py
|
|
||||||
|
|
||||||
|
|
||||||
Listing of ``movies/__init__.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/movies/__init__.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Example application
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Example application structure:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
/example
|
|
||||||
/__init__.py
|
|
||||||
/db.py
|
|
||||||
/main.py
|
|
||||||
|
|
||||||
Listing of ``examples/main.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/example/main.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Listing of ``examples/db.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/example/db.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Csv application
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Listing of ``app_csv.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/app_csv.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Database application
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Listing of ``app_db.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Csv and database application
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Listing of ``app_db_csv.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db_csv.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
|
||||||
|
|
||||||
|
|
||||||
.. _GitHub: https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/movie_lister
|
|
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
|
@ -135,8 +135,9 @@ Choose one of the following as a next step:
|
||||||
+ :ref:`flask-tutorial`
|
+ :ref:`flask-tutorial`
|
||||||
+ :ref:`aiohttp-tutorial`
|
+ :ref:`aiohttp-tutorial`
|
||||||
+ :ref:`asyncio-daemon-tutorial`
|
+ :ref:`asyncio-daemon-tutorial`
|
||||||
+ Know more about the :ref:`providers`.
|
+ :ref:`cli-tutorial`
|
||||||
+ Go to the :ref:`contents`.
|
+ Know more about the :ref:`providers`
|
||||||
|
+ Go to the :ref:`contents`
|
||||||
|
|
||||||
Useful links
|
Useful links
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
|
@ -7,6 +7,13 @@ that were made in every particular version.
|
||||||
From version 0.7.6 *Dependency Injector* framework strictly
|
From version 0.7.6 *Dependency Injector* framework strictly
|
||||||
follows `Semantic versioning`_
|
follows `Semantic versioning`_
|
||||||
|
|
||||||
|
3.30.0
|
||||||
|
------
|
||||||
|
- Rework ``Movie Lister`` example.
|
||||||
|
- Add tutorial for building ``Movie Lister``.
|
||||||
|
- Make some rewording for the other tutorials.
|
||||||
|
- Fix a couple of typos.
|
||||||
|
|
||||||
3.29.0
|
3.29.0
|
||||||
------
|
------
|
||||||
- Update README with the more direct message on what is ``Dependency Injector`` and how is it
|
- Update README with the more direct message on what is ``Dependency Injector`` and how is it
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _selector-provider:
|
||||||
|
|
||||||
Selector providers
|
Selector providers
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -922,7 +922,7 @@ We've used the ``Dependency Injector`` as a dependency injection framework.
|
||||||
|
|
||||||
The benefit you get with the ``Dependency Injector`` is the container. It starts to payoff
|
The benefit you get with the ``Dependency Injector`` is the container. It starts to payoff
|
||||||
when you need to understand or change your application structure. It's easy with the container,
|
when you need to understand or change your application structure. It's easy with the container,
|
||||||
cause you have everything in one place:
|
cause you have everything defined explicitly in one place:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -962,8 +962,8 @@ cause you have everything in one place:
|
||||||
|
|
||||||
What's next?
|
What's next?
|
||||||
|
|
||||||
- Look at the other :ref:`tutorials`.
|
- Look at the other :ref:`tutorials`
|
||||||
- Know more about the :ref:`providers`.
|
- Know more about the :ref:`providers`
|
||||||
- Go to the :ref:`contents`.
|
- Go to the :ref:`contents`
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1030,7 +1030,7 @@ We've used the ``Dependency Injector`` as a dependency injection framework.
|
||||||
|
|
||||||
The benefit you get with the ``Dependency Injector`` is the container. It starts to payoff
|
The benefit you get with the ``Dependency Injector`` is the container. It starts to payoff
|
||||||
when you need to understand or change your application structure. It's easy with the container,
|
when you need to understand or change your application structure. It's easy with the container,
|
||||||
cause you have everything in one place:
|
cause you have everything defined explicitly in one place:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -1080,8 +1080,8 @@ cause you have everything in one place:
|
||||||
|
|
||||||
What's next?
|
What's next?
|
||||||
|
|
||||||
- Look at the other :ref:`tutorials`.
|
- Look at the other :ref:`tutorials`
|
||||||
- Know more about the :ref:`providers`.
|
- Know more about the :ref:`providers`
|
||||||
- Go to the :ref:`contents`.
|
- Go to the :ref:`contents`
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
BIN
docs/tutorials/cli-images/classes_01.png
Normal file
BIN
docs/tutorials/cli-images/classes_01.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
docs/tutorials/cli-images/classes_02.png
Normal file
BIN
docs/tutorials/cli-images/classes_02.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
1054
docs/tutorials/cli.rst
Normal file
1054
docs/tutorials/cli.rst
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1097,7 +1097,7 @@ In this tutorial we've built a ``Flask`` application following the dependency in
|
||||||
We've used the ``Dependency Injector`` as a dependency injection framework.
|
We've used the ``Dependency Injector`` as a dependency injection framework.
|
||||||
|
|
||||||
The main part of this application is the container. It keeps all the application components and
|
The main part of this application is the container. It keeps all the application components and
|
||||||
their dependencies in one place:
|
their dependencies defined explicitly in one place:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -1141,9 +1141,9 @@ their dependencies in one place:
|
||||||
|
|
||||||
What's next?
|
What's next?
|
||||||
|
|
||||||
- Look at the other :ref:`tutorials`.
|
- Look at the other :ref:`tutorials`
|
||||||
- Know more about the :ref:`providers`.
|
- Know more about the :ref:`providers`
|
||||||
- Go to the :ref:`contents`.
|
- Go to the :ref:`contents`
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -12,5 +12,6 @@ frameworks.
|
||||||
flask
|
flask
|
||||||
aiohttp
|
aiohttp
|
||||||
asyncio-daemon
|
asyncio-daemon
|
||||||
|
cli
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[pydocstyle]
|
[pydocstyle]
|
||||||
ignore = D100,D101,D102,D103,D107,D203,D213
|
ignore = D100,D101,D102,D103,D105,D107,D203,D213
|
||||||
|
|
75
examples/miniapps/movie-lister/README.rst
Normal file
75
examples/miniapps/movie-lister/README.rst
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
Movie lister - a naive example of dependency injection in Python
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
This is a Python implementation of the dependency injection example from Martin Fowler's
|
||||||
|
article:
|
||||||
|
|
||||||
|
http://www.martinfowler.com/articles/injection.html
|
||||||
|
|
||||||
|
Run
|
||||||
|
---
|
||||||
|
|
||||||
|
Create a virtual environment:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
virtualenv venv
|
||||||
|
. venv/bin/activate
|
||||||
|
|
||||||
|
Install the requirements:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
To create the fixtures do:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python data/fixtures.py
|
||||||
|
|
||||||
|
To run the application do:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
MOVIE_FINDER_TYPE=csv python -m movies
|
||||||
|
MOVIE_FINDER_TYPE=sqlite python -m movies
|
||||||
|
|
||||||
|
The output should be something like this for each command:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
Francis Lawrence movies: [Movie(title='The Hunger Games: Mockingjay - Part 2', year=2015, director='Francis Lawrence')]
|
||||||
|
2016 movies: [Movie(title='Rogue One: A Star Wars Story', year=2016, director='Gareth Edwards'), Movie(title='The Jungle Book', year=2016, director='Jon Favreau')]
|
||||||
|
|
||||||
|
Test
|
||||||
|
----
|
||||||
|
|
||||||
|
To run the tests do:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pytest movies/tests.py --cov=movies
|
||||||
|
|
||||||
|
The output should be something like:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
|
||||||
|
plugins: cov-2.10.0
|
||||||
|
collected 2 items
|
||||||
|
|
||||||
|
movies/tests.py .. [100%]
|
||||||
|
|
||||||
|
---------- coverage: platform darwin, python 3.8.3-final-0 -----------
|
||||||
|
Name Stmts Miss Cover
|
||||||
|
------------------------------------------
|
||||||
|
movies/__init__.py 0 0 100%
|
||||||
|
movies/__main__.py 10 10 0%
|
||||||
|
movies/containers.py 9 0 100%
|
||||||
|
movies/entities.py 7 1 86%
|
||||||
|
movies/finders.py 26 13 50%
|
||||||
|
movies/listers.py 8 0 100%
|
||||||
|
movies/tests.py 24 0 100%
|
||||||
|
------------------------------------------
|
||||||
|
TOTAL 84 24 71%
|
8
examples/miniapps/movie-lister/config.yml
Normal file
8
examples/miniapps/movie-lister/config.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
finder:
|
||||||
|
|
||||||
|
csv:
|
||||||
|
path: "data/movies.csv"
|
||||||
|
delimiter: ","
|
||||||
|
|
||||||
|
sqlite:
|
||||||
|
path: "data/movies.db"
|
6
examples/miniapps/movie-lister/data/.gitignore
vendored
Normal file
6
examples/miniapps/movie-lister/data/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Everything
|
||||||
|
*
|
||||||
|
|
||||||
|
# Except this file:
|
||||||
|
!.gitignore
|
||||||
|
!fixtures.py
|
44
examples/miniapps/movie-lister/data/fixtures.py
Normal file
44
examples/miniapps/movie-lister/data/fixtures.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
"""Fixtures module."""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import sqlite3
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
|
SAMPLE_DATA = [
|
||||||
|
('The Hunger Games: Mockingjay - Part 2', 2015, 'Francis Lawrence'),
|
||||||
|
('Rogue One: A Star Wars Story', 2016, 'Gareth Edwards'),
|
||||||
|
('The Jungle Book', 2016, 'Jon Favreau'),
|
||||||
|
]
|
||||||
|
|
||||||
|
FILE = pathlib.Path(__file__)
|
||||||
|
DIR = FILE.parent
|
||||||
|
CSV_FILE = DIR / 'movies.csv'
|
||||||
|
SQLITE_FILE = DIR / 'movies.db'
|
||||||
|
|
||||||
|
|
||||||
|
def create_csv(movies_data, path):
|
||||||
|
with open(path, 'w') as opened_file:
|
||||||
|
writer = csv.writer(opened_file)
|
||||||
|
for row in movies_data:
|
||||||
|
writer.writerow(row)
|
||||||
|
|
||||||
|
|
||||||
|
def create_sqlite(movies_data, path):
|
||||||
|
with sqlite3.connect(path) as db:
|
||||||
|
db.execute(
|
||||||
|
'CREATE TABLE IF NOT EXISTS movies '
|
||||||
|
'(title text, year int, director text)'
|
||||||
|
)
|
||||||
|
db.execute('DELETE FROM movies')
|
||||||
|
db.executemany('INSERT INTO movies VALUES (?,?,?)', movies_data)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
create_csv(SAMPLE_DATA, CSV_FILE)
|
||||||
|
create_sqlite(SAMPLE_DATA, SQLITE_FILE)
|
||||||
|
print('OK')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
1
examples/miniapps/movie-lister/movies/__init__.py
Normal file
1
examples/miniapps/movie-lister/movies/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"""Top-level package."""
|
25
examples/miniapps/movie-lister/movies/__main__.py
Normal file
25
examples/miniapps/movie-lister/movies/__main__.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
"""Main module."""
|
||||||
|
|
||||||
|
from .containers import ApplicationContainer
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
container = ApplicationContainer()
|
||||||
|
|
||||||
|
container.config.from_yaml('config.yml')
|
||||||
|
container.config.finder.type.from_env('MOVIE_FINDER_TYPE')
|
||||||
|
|
||||||
|
lister = container.lister()
|
||||||
|
|
||||||
|
print(
|
||||||
|
'Francis Lawrence movies:',
|
||||||
|
lister.movies_directed_by('Francis Lawrence'),
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
'2016 movies:',
|
||||||
|
lister.movies_released_in(2016),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
36
examples/miniapps/movie-lister/movies/containers.py
Normal file
36
examples/miniapps/movie-lister/movies/containers.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
"""Containers module."""
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
from . import finders, listers, entities
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationContainer(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
config = providers.Configuration()
|
||||||
|
|
||||||
|
movie = providers.Factory(entities.Movie)
|
||||||
|
|
||||||
|
csv_finder = providers.Singleton(
|
||||||
|
finders.CsvMovieFinder,
|
||||||
|
movie_factory=movie.provider,
|
||||||
|
path=config.finder.csv.path,
|
||||||
|
delimiter=config.finder.csv.delimiter,
|
||||||
|
)
|
||||||
|
|
||||||
|
sqlite_finder = providers.Singleton(
|
||||||
|
finders.SqliteMovieFinder,
|
||||||
|
movie_factory=movie.provider,
|
||||||
|
path=config.finder.sqlite.path,
|
||||||
|
)
|
||||||
|
|
||||||
|
finder = providers.Selector(
|
||||||
|
config.finder.type,
|
||||||
|
csv=csv_finder,
|
||||||
|
sqlite=sqlite_finder,
|
||||||
|
)
|
||||||
|
|
||||||
|
lister = providers.Factory(
|
||||||
|
listers.MovieLister,
|
||||||
|
movie_finder=finder,
|
||||||
|
)
|
17
examples/miniapps/movie-lister/movies/entities.py
Normal file
17
examples/miniapps/movie-lister/movies/entities.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
"""Movie entities module."""
|
||||||
|
|
||||||
|
|
||||||
|
class Movie:
|
||||||
|
|
||||||
|
def __init__(self, title: str, year: int, director: str):
|
||||||
|
self.title = str(title)
|
||||||
|
self.year = int(year)
|
||||||
|
self.director = str(director)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '{0}(title={1}, year={2}, director={3})'.format(
|
||||||
|
self.__class__.__name__,
|
||||||
|
repr(self.title),
|
||||||
|
repr(self.year),
|
||||||
|
repr(self.director),
|
||||||
|
)
|
50
examples/miniapps/movie-lister/movies/finders.py
Normal file
50
examples/miniapps/movie-lister/movies/finders.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
"""Movie finders module."""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import sqlite3
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
|
from .entities import Movie
|
||||||
|
|
||||||
|
|
||||||
|
class MovieFinder:
|
||||||
|
|
||||||
|
def __init__(self, movie_factory: Callable[..., Movie]) -> None:
|
||||||
|
self._movie_factory = movie_factory
|
||||||
|
|
||||||
|
def find_all(self) -> List[Movie]:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class CsvMovieFinder(MovieFinder):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
movie_factory: Callable[..., Movie],
|
||||||
|
path: str,
|
||||||
|
delimiter: str,
|
||||||
|
) -> None:
|
||||||
|
self._csv_file_path = path
|
||||||
|
self._delimiter = delimiter
|
||||||
|
super().__init__(movie_factory)
|
||||||
|
|
||||||
|
def find_all(self) -> List[Movie]:
|
||||||
|
with open(self._csv_file_path) as csv_file:
|
||||||
|
csv_reader = csv.reader(csv_file, delimiter=self._delimiter)
|
||||||
|
return [self._movie_factory(*row) for row in csv_reader]
|
||||||
|
|
||||||
|
|
||||||
|
class SqliteMovieFinder(MovieFinder):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
movie_factory: Callable[..., Movie],
|
||||||
|
path: str,
|
||||||
|
) -> None:
|
||||||
|
self._database = sqlite3.connect(path)
|
||||||
|
super().__init__(movie_factory)
|
||||||
|
|
||||||
|
def find_all(self) -> List[Movie]:
|
||||||
|
with self._database as db:
|
||||||
|
rows = db.execute('SELECT title, year, director FROM movies')
|
||||||
|
return [self._movie_factory(*row) for row in rows]
|
21
examples/miniapps/movie-lister/movies/listers.py
Normal file
21
examples/miniapps/movie-lister/movies/listers.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
"""Movie listers module."""
|
||||||
|
|
||||||
|
from .finders import MovieFinder
|
||||||
|
|
||||||
|
|
||||||
|
class MovieLister:
|
||||||
|
|
||||||
|
def __init__(self, movie_finder: MovieFinder):
|
||||||
|
self._movie_finder = movie_finder
|
||||||
|
|
||||||
|
def movies_directed_by(self, director):
|
||||||
|
return [
|
||||||
|
movie for movie in self._movie_finder.find_all()
|
||||||
|
if movie.director == director
|
||||||
|
]
|
||||||
|
|
||||||
|
def movies_released_in(self, year):
|
||||||
|
return [
|
||||||
|
movie for movie in self._movie_finder.find_all()
|
||||||
|
if movie.year == year
|
||||||
|
]
|
55
examples/miniapps/movie-lister/movies/tests.py
Normal file
55
examples/miniapps/movie-lister/movies/tests.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
"""Tests module."""
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from .containers import ApplicationContainer
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def container():
|
||||||
|
container = ApplicationContainer()
|
||||||
|
container.config.from_dict({
|
||||||
|
'finder': {
|
||||||
|
'type': 'csv',
|
||||||
|
'csv': {
|
||||||
|
'path': '/fake-movies.csv',
|
||||||
|
'delimiter': ',',
|
||||||
|
},
|
||||||
|
'sqlite': {
|
||||||
|
'path': '/fake-movies.db',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return container
|
||||||
|
|
||||||
|
|
||||||
|
def test_movies_directed_by(container):
|
||||||
|
finder_mock = mock.Mock()
|
||||||
|
finder_mock.find_all.return_value = [
|
||||||
|
container.movie('The 33', 2015, 'Patricia Riggen'),
|
||||||
|
container.movie('The Jungle Book', 2016, 'Jon Favreau'),
|
||||||
|
]
|
||||||
|
|
||||||
|
with container.finder.override(finder_mock):
|
||||||
|
lister = container.lister()
|
||||||
|
movies = lister.movies_directed_by('Jon Favreau')
|
||||||
|
|
||||||
|
assert len(movies) == 1
|
||||||
|
assert movies[0].title == 'The Jungle Book'
|
||||||
|
|
||||||
|
|
||||||
|
def test_movies_released_in(container):
|
||||||
|
finder_mock = mock.Mock()
|
||||||
|
finder_mock.find_all.return_value = [
|
||||||
|
container.movie('The 33', 2015, 'Patricia Riggen'),
|
||||||
|
container.movie('The Jungle Book', 2016, 'Jon Favreau'),
|
||||||
|
]
|
||||||
|
|
||||||
|
with container.finder.override(finder_mock):
|
||||||
|
lister = container.lister()
|
||||||
|
movies = lister.movies_released_in(2015)
|
||||||
|
|
||||||
|
assert len(movies) == 1
|
||||||
|
assert movies[0].title == 'The 33'
|
4
examples/miniapps/movie-lister/requirements.txt
Normal file
4
examples/miniapps/movie-lister/requirements.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
dependency-injector
|
||||||
|
pyyaml
|
||||||
|
pytest
|
||||||
|
pytest-cov
|
|
@ -1,16 +0,0 @@
|
||||||
A naive example of dependency injection in Python
|
|
||||||
=================================================
|
|
||||||
|
|
||||||
Example implementation of dependency injection on Python from Martin Fowler's
|
|
||||||
article about dependency injection and inversion of control:
|
|
||||||
|
|
||||||
http://www.martinfowler.com/articles/injection.html
|
|
||||||
|
|
||||||
|
|
||||||
Instructions for running:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python app_csv.py
|
|
||||||
python app_db.py
|
|
||||||
python app_db_csv.py
|
|
|
@ -1,49 +0,0 @@
|
||||||
"""A naive example of dependency injection on Python.
|
|
||||||
|
|
||||||
Example implementation of dependency injection in Python from Martin Fowler's
|
|
||||||
article about dependency injection and inversion of control:
|
|
||||||
|
|
||||||
http://www.martinfowler.com/articles/injection.html
|
|
||||||
|
|
||||||
This mini application uses ``movies`` library, that is configured to work with
|
|
||||||
csv file movies database.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import movies
|
|
||||||
import movies.finders
|
|
||||||
|
|
||||||
import example.db
|
|
||||||
import example.main
|
|
||||||
|
|
||||||
import settings
|
|
||||||
import fixtures
|
|
||||||
|
|
||||||
import dependency_injector.containers as containers
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
@containers.override(movies.MoviesModule)
|
|
||||||
class MyMoviesModule(containers.DeclarativeContainer):
|
|
||||||
"""IoC container for overriding movies module component providers."""
|
|
||||||
|
|
||||||
finder = providers.Factory(movies.finders.CsvMovieFinder,
|
|
||||||
csv_file_path=settings.MOVIES_CSV_PATH,
|
|
||||||
delimiter=',',
|
|
||||||
**movies.MoviesModule.finder.kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class CsvApplication(containers.DeclarativeContainer):
|
|
||||||
"""IoC container of csv application component providers."""
|
|
||||||
|
|
||||||
main = providers.Callable(example.main.main,
|
|
||||||
movie_lister=movies.MoviesModule.lister)
|
|
||||||
|
|
||||||
init_db = providers.Callable(example.db.init_csv,
|
|
||||||
movies_data=fixtures.MOVIES_SAMPLE_DATA,
|
|
||||||
csv_file_path=settings.MOVIES_CSV_PATH,
|
|
||||||
delimiter=',')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
CsvApplication.init_db()
|
|
||||||
CsvApplication.main()
|
|
|
@ -1,55 +0,0 @@
|
||||||
"""A naive example of dependency injection on Python.
|
|
||||||
|
|
||||||
Example implementation of dependency injection in Python from Martin Fowler's
|
|
||||||
article about dependency injection and inversion of control:
|
|
||||||
|
|
||||||
http://www.martinfowler.com/articles/injection.html
|
|
||||||
|
|
||||||
This mini application uses ``movies`` library, that is configured to work with
|
|
||||||
sqlite movies database.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
import movies
|
|
||||||
import movies.finders
|
|
||||||
|
|
||||||
import example.db
|
|
||||||
import example.main
|
|
||||||
|
|
||||||
import settings
|
|
||||||
import fixtures
|
|
||||||
|
|
||||||
import dependency_injector.containers as containers
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
class ResourcesModule(containers.DeclarativeContainer):
|
|
||||||
"""IoC container of application resource providers."""
|
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, settings.MOVIES_DB_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
@containers.override(movies.MoviesModule)
|
|
||||||
class MyMoviesModule(containers.DeclarativeContainer):
|
|
||||||
"""IoC container for overriding movies module component providers."""
|
|
||||||
|
|
||||||
finder = providers.Factory(movies.finders.SqliteMovieFinder,
|
|
||||||
database=ResourcesModule.database,
|
|
||||||
**movies.MoviesModule.finder.kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class DbApplication(containers.DeclarativeContainer):
|
|
||||||
"""IoC container of database application component providers."""
|
|
||||||
|
|
||||||
main = providers.Callable(example.main.main,
|
|
||||||
movie_lister=movies.MoviesModule.lister)
|
|
||||||
|
|
||||||
init_db = providers.Callable(example.db.init_sqlite,
|
|
||||||
movies_data=fixtures.MOVIES_SAMPLE_DATA,
|
|
||||||
database=ResourcesModule.database)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
DbApplication.init_db()
|
|
||||||
DbApplication.main()
|
|
|
@ -1,80 +0,0 @@
|
||||||
"""A naive example of dependency injection on Python.
|
|
||||||
|
|
||||||
Example implementation of dependency injection in Python from Martin Fowler's
|
|
||||||
article about dependency injection and inversion of control:
|
|
||||||
|
|
||||||
http://www.martinfowler.com/articles/injection.html
|
|
||||||
|
|
||||||
This mini application uses ``movies`` library, that is configured to work with
|
|
||||||
sqlite movies database and csv file movies database.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
import movies
|
|
||||||
import movies.finders
|
|
||||||
|
|
||||||
import example.db
|
|
||||||
import example.main
|
|
||||||
|
|
||||||
import settings
|
|
||||||
import fixtures
|
|
||||||
|
|
||||||
import dependency_injector.containers as containers
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
class ResourcesModule(containers.DeclarativeContainer):
|
|
||||||
"""IoC container of application resource providers."""
|
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, settings.MOVIES_DB_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
@containers.copy(movies.MoviesModule)
|
|
||||||
class DbMoviesModule(movies.MoviesModule):
|
|
||||||
"""IoC container for overriding movies module component providers."""
|
|
||||||
|
|
||||||
finder = providers.Factory(movies.finders.SqliteMovieFinder,
|
|
||||||
database=ResourcesModule.database,
|
|
||||||
**movies.MoviesModule.finder.kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
@containers.copy(movies.MoviesModule)
|
|
||||||
class CsvMoviesModule(movies.MoviesModule):
|
|
||||||
"""IoC container for overriding movies module component providers."""
|
|
||||||
|
|
||||||
finder = providers.Factory(movies.finders.CsvMovieFinder,
|
|
||||||
csv_file_path=settings.MOVIES_CSV_PATH,
|
|
||||||
delimiter=',',
|
|
||||||
**movies.MoviesModule.finder.kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class DbApplication(containers.DeclarativeContainer):
|
|
||||||
"""IoC container of database application component providers."""
|
|
||||||
|
|
||||||
main = providers.Callable(example.main.main,
|
|
||||||
movie_lister=DbMoviesModule.lister)
|
|
||||||
|
|
||||||
init_db = providers.Callable(example.db.init_sqlite,
|
|
||||||
movies_data=fixtures.MOVIES_SAMPLE_DATA,
|
|
||||||
database=ResourcesModule.database)
|
|
||||||
|
|
||||||
|
|
||||||
class CsvApplication(containers.DeclarativeContainer):
|
|
||||||
"""IoC container of csv application component providers."""
|
|
||||||
|
|
||||||
main = providers.Callable(example.main.main,
|
|
||||||
movie_lister=CsvMoviesModule.lister)
|
|
||||||
|
|
||||||
init_db = providers.Callable(example.db.init_csv,
|
|
||||||
movies_data=fixtures.MOVIES_SAMPLE_DATA,
|
|
||||||
csv_file_path=settings.MOVIES_CSV_PATH,
|
|
||||||
delimiter=',')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
DbApplication.init_db()
|
|
||||||
DbApplication.main()
|
|
||||||
|
|
||||||
CsvApplication.init_db()
|
|
||||||
CsvApplication.main()
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Ignore everything in this directory
|
|
||||||
*
|
|
||||||
|
|
||||||
# Except this file:
|
|
||||||
!.gitignore
|
|
|
@ -1,3 +0,0 @@
|
||||||
The Hunger Games: Mockingjay - Part 2,2015,Francis Lawrence
|
|
||||||
The 33,2015,Patricia Riggen
|
|
||||||
Star Wars: Episode VII - The Force Awakens,2015,JJ Abrams
|
|
|
|
@ -1 +0,0 @@
|
||||||
"""Example top-level package."""
|
|
|
@ -1,35 +0,0 @@
|
||||||
"""Example database module."""
|
|
||||||
|
|
||||||
import csv
|
|
||||||
|
|
||||||
|
|
||||||
def init_sqlite(movies_data, database):
|
|
||||||
"""Initialize sqlite3 movies database.
|
|
||||||
|
|
||||||
:param movies_data: Data about movies
|
|
||||||
:type movies_data: tuple[tuple]
|
|
||||||
|
|
||||||
:param database: Connection to sqlite database with movies data
|
|
||||||
:type database: sqlite3.Connection
|
|
||||||
"""
|
|
||||||
with database:
|
|
||||||
database.execute('CREATE TABLE IF NOT EXISTS movies '
|
|
||||||
'(name text, year int, director text)')
|
|
||||||
database.execute('DELETE FROM movies')
|
|
||||||
database.executemany('INSERT INTO movies VALUES (?,?,?)', movies_data)
|
|
||||||
|
|
||||||
|
|
||||||
def init_csv(movies_data, csv_file_path, delimiter):
|
|
||||||
"""Initialize csv movies database.
|
|
||||||
|
|
||||||
:param movies_data: Data about movies
|
|
||||||
:type movies_data: tuple[tuple]
|
|
||||||
|
|
||||||
:param csv_file_path: Path to csv file with movies data
|
|
||||||
:type csv_file_path: str
|
|
||||||
|
|
||||||
:param delimiter: Csv file's delimiter
|
|
||||||
:type delimiter: str
|
|
||||||
"""
|
|
||||||
with open(csv_file_path, 'w') as csv_file:
|
|
||||||
csv.writer(csv_file, delimiter=delimiter).writerows(movies_data)
|
|
|
@ -1,17 +0,0 @@
|
||||||
"""Example main module."""
|
|
||||||
|
|
||||||
|
|
||||||
def main(movie_lister):
|
|
||||||
"""Run application.
|
|
||||||
|
|
||||||
This program prints info about all movies that were directed by different
|
|
||||||
persons and then prints all movies that were released in 2015.
|
|
||||||
|
|
||||||
:param movie_lister: Movie lister instance
|
|
||||||
:type movie_lister: movies.listers.MovieLister
|
|
||||||
"""
|
|
||||||
print(movie_lister.movies_directed_by('Francis Lawrence'))
|
|
||||||
print(movie_lister.movies_directed_by('Patricia Riggen'))
|
|
||||||
print(movie_lister.movies_directed_by('JJ Abrams'))
|
|
||||||
|
|
||||||
print(movie_lister.movies_released_in(2015))
|
|
|
@ -1,8 +0,0 @@
|
||||||
"""Fixtures module."""
|
|
||||||
|
|
||||||
|
|
||||||
MOVIES_SAMPLE_DATA = (
|
|
||||||
('The Hunger Games: Mockingjay - Part 2', 2015, 'Francis Lawrence'),
|
|
||||||
('The 33', 2015, 'Patricia Riggen'),
|
|
||||||
('Star Wars: Episode VII - The Force Awakens', 2015, 'JJ Abrams'),
|
|
||||||
)
|
|
|
@ -1,32 +0,0 @@
|
||||||
"""Movies package.
|
|
||||||
|
|
||||||
Top-level package of movies library. This package contains IoC container of
|
|
||||||
movies module component providers - ``MoviesModule``. It is recommended to use
|
|
||||||
movies library functionality by fetching required instances from
|
|
||||||
``MoviesModule`` providers.
|
|
||||||
|
|
||||||
``MoviesModule.finder`` is a factory that provides abstract component
|
|
||||||
``finders.MovieFinder``. This provider should be overridden by provider of
|
|
||||||
concrete finder implementation in terms of library configuration.
|
|
||||||
|
|
||||||
Each of ``MoviesModule`` providers could be overridden.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import movies.finders
|
|
||||||
import movies.listers
|
|
||||||
import movies.models
|
|
||||||
|
|
||||||
import dependency_injector.containers as containers
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
class MoviesModule(containers.DeclarativeContainer):
|
|
||||||
"""IoC container of movies module component providers."""
|
|
||||||
|
|
||||||
movie = providers.Factory(movies.models.Movie)
|
|
||||||
|
|
||||||
finder = providers.AbstractFactory(movies.finders.MovieFinder,
|
|
||||||
movie_model=movie.provider)
|
|
||||||
|
|
||||||
lister = providers.Factory(movies.listers.MovieLister,
|
|
||||||
movie_finder=finder)
|
|
|
@ -1,87 +0,0 @@
|
||||||
"""Movie finders module.
|
|
||||||
|
|
||||||
This module contains all finder implementations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import csv
|
|
||||||
|
|
||||||
|
|
||||||
class MovieFinder:
|
|
||||||
"""Movie finder component.
|
|
||||||
|
|
||||||
Movie finder component is responsible for fetching movies data from
|
|
||||||
various storage.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, movie_model):
|
|
||||||
"""Initialize instance.
|
|
||||||
|
|
||||||
:param movie_model: Movie model's factory
|
|
||||||
:type movie_model: movies.models.Movie
|
|
||||||
"""
|
|
||||||
self._movie_model = movie_model
|
|
||||||
|
|
||||||
def find_all(self):
|
|
||||||
"""Return all found movies.
|
|
||||||
|
|
||||||
:rtype: list[movies.models.Movie]
|
|
||||||
:return: List of movie instances.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
class CsvMovieFinder(MovieFinder):
|
|
||||||
"""Movie finder that fetches movies data from csv file."""
|
|
||||||
|
|
||||||
def __init__(self, movie_model, csv_file_path, delimiter):
|
|
||||||
"""Initialize instance.
|
|
||||||
|
|
||||||
:param movie_model: Movie model's factory
|
|
||||||
:type movie_model: movies.models.Movie
|
|
||||||
|
|
||||||
:param csv_file_path: Path to csv file with movies data
|
|
||||||
:type csv_file_path: str
|
|
||||||
|
|
||||||
:param delimiter: Csv file's delimiter
|
|
||||||
:type delimiter: str
|
|
||||||
"""
|
|
||||||
self._csv_file_path = csv_file_path
|
|
||||||
self._delimiter = delimiter
|
|
||||||
super().__init__(movie_model)
|
|
||||||
|
|
||||||
def find_all(self):
|
|
||||||
"""Return all found movies.
|
|
||||||
|
|
||||||
:rtype: list[movies.models.Movie]
|
|
||||||
:return: List of movie instances.
|
|
||||||
"""
|
|
||||||
with open(self._csv_file_path) as csv_file:
|
|
||||||
csv_reader = csv.reader(csv_file, delimiter=self._delimiter)
|
|
||||||
return [self._movie_model(*row) for row in csv_reader]
|
|
||||||
|
|
||||||
|
|
||||||
class SqliteMovieFinder(MovieFinder):
|
|
||||||
"""Movie finder that fetches movies data from sqlite database."""
|
|
||||||
|
|
||||||
def __init__(self, movie_model, database):
|
|
||||||
"""Initialize instance.
|
|
||||||
|
|
||||||
:param movie_model: Movie model's factory
|
|
||||||
:type movie_model: (object) -> movies.models.Movie
|
|
||||||
|
|
||||||
:param database: Connection to sqlite database with movies data
|
|
||||||
:type database: sqlite3.Connection
|
|
||||||
"""
|
|
||||||
self._database = database
|
|
||||||
super().__init__(movie_model)
|
|
||||||
|
|
||||||
def find_all(self):
|
|
||||||
"""Return all found movies.
|
|
||||||
|
|
||||||
:rtype: list[movies.models.Movie]
|
|
||||||
:return: List of movie instances.
|
|
||||||
"""
|
|
||||||
with self._database:
|
|
||||||
rows = self._database.execute('SELECT name, year, director '
|
|
||||||
'FROM movies')
|
|
||||||
return [self._movie_model(*row) for row in rows]
|
|
|
@ -1,44 +0,0 @@
|
||||||
"""Movie listers module.
|
|
||||||
|
|
||||||
This module contains all lister implementations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class MovieLister:
|
|
||||||
"""Movie lister component.
|
|
||||||
|
|
||||||
Movie lister component provides several methods for filtering movies by
|
|
||||||
specific criteria.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, movie_finder):
|
|
||||||
"""Initialize instance.
|
|
||||||
|
|
||||||
:param movie_finder: Movie finder instance
|
|
||||||
:type movie_finder: movies.finders.MovieFinder
|
|
||||||
"""
|
|
||||||
self._movie_finder = movie_finder
|
|
||||||
|
|
||||||
def movies_directed_by(self, director):
|
|
||||||
"""Return list of movies that were directed by certain person.
|
|
||||||
|
|
||||||
:param director: Director's name
|
|
||||||
:type director: str
|
|
||||||
|
|
||||||
:rtype: list[movies.models.Movie]
|
|
||||||
:return: List of movie instances.
|
|
||||||
"""
|
|
||||||
return [movie for movie in self._movie_finder.find_all()
|
|
||||||
if movie.director == director]
|
|
||||||
|
|
||||||
def movies_released_in(self, year):
|
|
||||||
"""Return list of movies that were released in certain year.
|
|
||||||
|
|
||||||
:param year: Release year
|
|
||||||
:type year: int
|
|
||||||
|
|
||||||
:rtype: list[movies.models.Movie]
|
|
||||||
:return: List of movie instances.
|
|
||||||
"""
|
|
||||||
return [movie for movie in self._movie_finder.find_all()
|
|
||||||
if movie.year == year]
|
|
|
@ -1,36 +0,0 @@
|
||||||
"""Movie models module.
|
|
||||||
|
|
||||||
This module contains all model implementations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class Movie:
|
|
||||||
"""Base movie model."""
|
|
||||||
|
|
||||||
def __init__(self, name, year, director):
|
|
||||||
"""Initialize instance.
|
|
||||||
|
|
||||||
:param name: Movie's name
|
|
||||||
:type name: str
|
|
||||||
|
|
||||||
:param year: Year, when movie was released
|
|
||||||
:type year: int
|
|
||||||
|
|
||||||
:param director: Name of person, that directed the movie
|
|
||||||
:type director: str
|
|
||||||
"""
|
|
||||||
self.name = str(name)
|
|
||||||
self.year = int(year)
|
|
||||||
self.director = str(director)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Return string representation of movie instance.
|
|
||||||
|
|
||||||
:rtype: str
|
|
||||||
:return: Movie's string representation.
|
|
||||||
"""
|
|
||||||
return '{0}(name={1}, year={2}, director={3})'.format(
|
|
||||||
self.__class__.__name__,
|
|
||||||
repr(self.name),
|
|
||||||
repr(self.year),
|
|
||||||
repr(self.director))
|
|
|
@ -1,11 +0,0 @@
|
||||||
"""Settings module.
|
|
||||||
|
|
||||||
This module contains application's settings and constants.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
DATA_DIR = os.path.abspath(os.path.dirname(__file__) + '/data')
|
|
||||||
MOVIES_CSV_PATH = DATA_DIR + '/movies.csv'
|
|
||||||
MOVIES_DB_PATH = DATA_DIR + '/movies.db'
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Dependency injector top-level package."""
|
"""Dependency injector top-level package."""
|
||||||
|
|
||||||
__version__ = '3.29.0'
|
__version__ = '3.30.0'
|
||||||
"""Version number that follows semantic versioning.
|
"""Version number that follows semantic versioning.
|
||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
|
|
Loading…
Reference in New Issue
Block a user