From 883e046c6741c977f2f6163d1105da9393a4de8b Mon Sep 17 00:00:00 2001 From: Torsten Ueberschar Date: Thu, 13 Oct 2022 11:49:00 +0200 Subject: [PATCH] add skeleton --- .gitignore | 224 +++++++++++++++++++++++++++++++++++++++++++++++ __main__.py | 19 ++++ containers.py | 19 ++++ requirements.txt | 3 + services.py | 21 +++++ tests.py | 29 ++++++ 6 files changed, 315 insertions(+) create mode 100644 .gitignore create mode 100644 __main__.py create mode 100644 containers.py create mode 100644 requirements.txt create mode 100644 services.py create mode 100644 tests.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6511a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,224 @@ +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + diff --git a/__main__.py b/__main__.py new file mode 100644 index 0000000..f4c8a3b --- /dev/null +++ b/__main__.py @@ -0,0 +1,19 @@ +# pip install dependency-injector +# https://python-dependency-injector.ets-labs.org/index.html +from dependency_injector.wiring import Provide, inject + +from containers import Container +from services import BusinessLogic + + +@inject +def main(business: BusinessLogic = Provide(Container.business_logic)) -> None: + business.send("me") + + +if __name__ == '__main__': + container = Container() + container.init_resources() + container.wire(modules=[__name__]) + + main() diff --git a/containers.py b/containers.py new file mode 100644 index 0000000..d20241f --- /dev/null +++ b/containers.py @@ -0,0 +1,19 @@ +from dependency_injector import containers, providers + +import services + + +class Container(containers.DeclarativeContainer): + email_service = providers.Factory( + services.EmailService + ) + + invoice_service = providers.Factory( + services.InvoiceService + ) + + business_logic = providers.Factory( + services.BusinessLogic, + invoice=invoice_service, + email=email_service + ) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ca32a4e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +dependency-injector==4.40.0 +mock==4.0.3 +pytest==7.1.3 diff --git a/services.py b/services.py new file mode 100644 index 0000000..be3ab79 --- /dev/null +++ b/services.py @@ -0,0 +1,21 @@ +class InvoiceService: + def create_invoice(self) -> str: + return "invoice created by service" + + +class EmailService: + def send(self, receiver, invoice) -> None: + print(f'e-mail service is sending "{invoice}" to "{receiver}"') + + +class BusinessLogic: + def __init__(self, invoice: InvoiceService, email: EmailService) -> None: + self.email_service = email + self.invoice_service = invoice + + def send(self, email_address) -> None: + print('create invoice') + invoice = self.invoice_service.create_invoice() + print(f'sending invoice "{invoice}" to "{email_address}"') + self.email_service.send(email_address, invoice) + print('wat fott is is fott') diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..4fccb9d --- /dev/null +++ b/tests.py @@ -0,0 +1,29 @@ +from unittest import mock + +import services +from containers import Container +from dependency_injector.wiring import Provide, inject + + +@inject +def run(service: services.BusinessLogic = Provide[Container.business_logic]): + service.send("test@receiver") + + +def test_is_mail_send(): + container = Container() + container.init_resources() + container.wire(modules=[__name__]) + + email_service = mock.Mock(services.EmailService) + invoice_service = mock.Mock(services.InvoiceService) + + invoice_service.create_invoice.return_value = "test invoice" + + with container.override_providers( + email_service=email_service, + invoice_service=invoice_service): + run() + + email_service.send.assert_called_once_with("test@receiver", "test invoice") + invoice_service.create_invoice.assert_called()