├── .env.example ├── .github └── workflows │ ├── python-app.yml │ └── static.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── alembic.ini ├── alembic ├── README ├── env.py ├── script.py.mako └── versions │ └── 0ca47c9b66bd_adding_professionsdbmodel.py ├── cli_memory_process_handler.py ├── configs ├── __init__.py └── config.py ├── docs ├── Makefile ├── build │ ├── doctrees │ │ ├── cli_memory_process_handler.doctree │ │ ├── configs.doctree │ │ ├── environment.pickle │ │ ├── flask_memory_process_handler.doctree │ │ ├── flask_postgresql_process_handler.doctree │ │ ├── index.doctree │ │ ├── modules.doctree │ │ ├── src.app.cli_memory.controllers.doctree │ │ ├── src.app.cli_memory.doctree │ │ ├── src.app.cli_memory.presenters.doctree │ │ ├── src.app.cli_memory.views.doctree │ │ ├── src.app.doctree │ │ ├── src.app.flask_memory.blueprints.doctree │ │ ├── src.app.flask_memory.controllers.doctree │ │ ├── src.app.flask_memory.doctree │ │ ├── src.app.flask_memory.interfaces.doctree │ │ ├── src.app.flask_memory.presenters.doctree │ │ ├── src.app.flask_postgresql.blueprints.doctree │ │ ├── src.app.flask_postgresql.controllers.doctree │ │ ├── src.app.flask_postgresql.doctree │ │ ├── src.app.flask_postgresql.interfaces.doctree │ │ ├── src.app.flask_postgresql.presenters.doctree │ │ ├── src.doctree │ │ ├── src.domain.doctree │ │ ├── src.domain.entities.doctree │ │ ├── src.infra.db_models.doctree │ │ ├── src.infra.doctree │ │ ├── src.infra.repositories.doctree │ │ ├── src.interactor.doctree │ │ ├── src.interactor.dtos.doctree │ │ ├── src.interactor.errors.doctree │ │ ├── src.interactor.interfaces.doctree │ │ ├── src.interactor.interfaces.logger.doctree │ │ ├── src.interactor.interfaces.presenters.doctree │ │ ├── src.interactor.interfaces.repositories.doctree │ │ ├── src.interactor.use_cases.doctree │ │ └── src.interactor.validations.doctree │ └── html │ │ ├── .buildinfo │ │ ├── _sources │ │ ├── cli_memory_process_handler.rst.txt │ │ ├── configs.rst.txt │ │ ├── flask_memory_process_handler.rst.txt │ │ ├── flask_postgresql_process_handler.rst.txt │ │ ├── index.rst.txt │ │ ├── modules.rst.txt │ │ ├── src.app.cli_memory.controllers.rst.txt │ │ ├── src.app.cli_memory.presenters.rst.txt │ │ ├── src.app.cli_memory.rst.txt │ │ ├── src.app.cli_memory.views.rst.txt │ │ ├── src.app.flask_memory.blueprints.rst.txt │ │ ├── src.app.flask_memory.controllers.rst.txt │ │ ├── src.app.flask_memory.interfaces.rst.txt │ │ ├── src.app.flask_memory.presenters.rst.txt │ │ ├── src.app.flask_memory.rst.txt │ │ ├── src.app.flask_postgresql.blueprints.rst.txt │ │ ├── src.app.flask_postgresql.controllers.rst.txt │ │ ├── src.app.flask_postgresql.interfaces.rst.txt │ │ ├── src.app.flask_postgresql.presenters.rst.txt │ │ ├── src.app.flask_postgresql.rst.txt │ │ ├── src.app.rst.txt │ │ ├── src.domain.entities.rst.txt │ │ ├── src.domain.rst.txt │ │ ├── src.infra.db_models.rst.txt │ │ ├── src.infra.repositories.rst.txt │ │ ├── src.infra.rst.txt │ │ ├── src.interactor.dtos.rst.txt │ │ ├── src.interactor.errors.rst.txt │ │ ├── src.interactor.interfaces.logger.rst.txt │ │ ├── src.interactor.interfaces.presenters.rst.txt │ │ ├── src.interactor.interfaces.repositories.rst.txt │ │ ├── src.interactor.interfaces.rst.txt │ │ ├── src.interactor.rst.txt │ │ ├── src.interactor.use_cases.rst.txt │ │ ├── src.interactor.validations.rst.txt │ │ └── src.rst.txt │ │ ├── _static │ │ ├── _sphinx_javascript_frameworks_compat.js │ │ ├── basic.css │ │ ├── css │ │ │ ├── badge_only.css │ │ │ ├── fonts │ │ │ │ ├── Roboto-Slab-Bold.woff │ │ │ │ ├── Roboto-Slab-Bold.woff2 │ │ │ │ ├── Roboto-Slab-Regular.woff │ │ │ │ ├── Roboto-Slab-Regular.woff2 │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ ├── fontawesome-webfont.woff2 │ │ │ │ ├── lato-bold-italic.woff │ │ │ │ ├── lato-bold-italic.woff2 │ │ │ │ ├── lato-bold.woff │ │ │ │ ├── lato-bold.woff2 │ │ │ │ ├── lato-normal-italic.woff │ │ │ │ ├── lato-normal-italic.woff2 │ │ │ │ ├── lato-normal.woff │ │ │ │ └── lato-normal.woff2 │ │ │ └── theme.css │ │ ├── doctools.js │ │ ├── documentation_options.js │ │ ├── file.png │ │ ├── jquery.js │ │ ├── js │ │ │ ├── badge_only.js │ │ │ ├── html5shiv-printshiv.min.js │ │ │ ├── html5shiv.min.js │ │ │ └── theme.js │ │ ├── language_data.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ └── sphinx_highlight.js │ │ ├── cli_memory_process_handler.html │ │ ├── configs.html │ │ ├── flask_memory_process_handler.html │ │ ├── flask_postgresql_process_handler.html │ │ ├── genindex.html │ │ ├── index.html │ │ ├── modules.html │ │ ├── objects.inv │ │ ├── py-modindex.html │ │ ├── search.html │ │ ├── searchindex.js │ │ ├── src.app.cli_memory.controllers.html │ │ ├── src.app.cli_memory.html │ │ ├── src.app.cli_memory.presenters.html │ │ ├── src.app.cli_memory.views.html │ │ ├── src.app.flask_memory.blueprints.html │ │ ├── src.app.flask_memory.controllers.html │ │ ├── src.app.flask_memory.html │ │ ├── src.app.flask_memory.interfaces.html │ │ ├── src.app.flask_memory.presenters.html │ │ ├── src.app.flask_postgresql.blueprints.html │ │ ├── src.app.flask_postgresql.controllers.html │ │ ├── src.app.flask_postgresql.html │ │ ├── src.app.flask_postgresql.interfaces.html │ │ ├── src.app.flask_postgresql.presenters.html │ │ ├── src.app.html │ │ ├── src.domain.entities.html │ │ ├── src.domain.html │ │ ├── src.html │ │ ├── src.infra.db_models.html │ │ ├── src.infra.html │ │ ├── src.infra.repositories.html │ │ ├── src.interactor.dtos.html │ │ ├── src.interactor.errors.html │ │ ├── src.interactor.html │ │ ├── src.interactor.interfaces.html │ │ ├── src.interactor.interfaces.logger.html │ │ ├── src.interactor.interfaces.presenters.html │ │ ├── src.interactor.interfaces.repositories.html │ │ ├── src.interactor.use_cases.html │ │ └── src.interactor.validations.html ├── make.bat └── source │ ├── cli_memory_process_handler.rst │ ├── conf.py │ ├── configs.rst │ ├── flask_memory_process_handler.rst │ ├── flask_postgresql_process_handler.rst │ ├── index.rst │ ├── modules.rst │ ├── src.app.cli_memory.controllers.rst │ ├── src.app.cli_memory.presenters.rst │ ├── src.app.cli_memory.rst │ ├── src.app.cli_memory.views.rst │ ├── src.app.flask_memory.blueprints.rst │ ├── src.app.flask_memory.controllers.rst │ ├── src.app.flask_memory.interfaces.rst │ ├── src.app.flask_memory.presenters.rst │ ├── src.app.flask_memory.rst │ ├── src.app.flask_postgresql.blueprints.rst │ ├── src.app.flask_postgresql.controllers.rst │ ├── src.app.flask_postgresql.interfaces.rst │ ├── src.app.flask_postgresql.presenters.rst │ ├── src.app.flask_postgresql.rst │ ├── src.app.rst │ ├── src.domain.entities.rst │ ├── src.domain.rst │ ├── src.infra.db_models.rst │ ├── src.infra.repositories.rst │ ├── src.infra.rst │ ├── src.interactor.dtos.rst │ ├── src.interactor.errors.rst │ ├── src.interactor.interfaces.logger.rst │ ├── src.interactor.interfaces.presenters.rst │ ├── src.interactor.interfaces.repositories.rst │ ├── src.interactor.interfaces.rst │ ├── src.interactor.rst │ ├── src.interactor.use_cases.rst │ ├── src.interactor.validations.rst │ └── src.rst ├── flask_memory_process_handler.py ├── flask_postgresql_process_handler.py ├── requirements.txt └── src ├── __init__.py ├── app ├── __init__.py ├── cli_memory │ ├── __init__.py │ ├── controllers │ │ ├── __init__.py │ │ ├── create_profession_controller.py │ │ ├── create_profession_controller_test.py │ │ └── exit_controller.py │ ├── interfaces │ │ └── cli_memory_controller_interface.py │ ├── presenters │ │ ├── __init__.py │ │ ├── create_profession_presenter.py │ │ └── create_profession_presenter_test.py │ └── views │ │ ├── __init__.py │ │ ├── create_profession_view.py │ │ └── create_profession_view_test.py ├── flask_memory │ ├── __init__.py │ ├── blueprints │ │ ├── __init__.py │ │ └── create_profession_blueprint.py │ ├── controllers │ │ ├── __init__.py │ │ ├── create_profession_controller.py │ │ └── create_profession_controller_test.py │ ├── create_flask_memory_app.py │ ├── create_flask_memory_app_test.py │ ├── interfaces │ │ ├── __init__.py │ │ └── flask_memory_controller_interface.py │ └── presenters │ │ ├── __init__.py │ │ ├── create_profession_presenter.py │ │ └── create_profession_presenter_test.py └── flask_postgresql │ ├── __init__.py │ ├── blueprints │ ├── __init__.py │ └── create_profession_blueprint.py │ ├── controllers │ ├── __init__.py │ ├── create_profession_controller.py │ └── create_profession_controller_test.py │ ├── create_flask_postgresql_app.py │ ├── create_flask_postgresql_app_test.py │ ├── interfaces │ ├── __init__.py │ └── flask_postgresql_controller_interface.py │ └── presenters │ ├── __init__.py │ ├── create_profession_presenter.py │ └── create_profession_presenter_test.py ├── conftest.py ├── domain ├── __init__.py ├── entities │ ├── __init__.py │ ├── profession.py │ └── profession_test.py └── value_objects.py ├── infra ├── __init__.py ├── db_models │ ├── __init__.py │ ├── db_base.py │ └── profession_db_model.py ├── loggers │ ├── logger_default.py │ └── logger_default_test.py └── repositories │ ├── __init__.py │ ├── profession_in_memory_repository.py │ ├── profession_in_memory_repository_test.py │ ├── profession_postgresql_repository.py │ └── profession_postgresql_repository_test.py └── interactor ├── __init__.py ├── dtos ├── __init__.py ├── create_profession_dtos.py └── create_profession_dtos_test.py ├── errors ├── __init__.py ├── error_classes.py └── error_classes_test.py ├── interfaces ├── __init__.py ├── logger │ ├── __init__.py │ └── logger.py ├── presenters │ ├── __init__.py │ └── create_profession_presenter.py └── repositories │ ├── __init__.py │ └── profession_repository.py ├── use_cases ├── __init__.py ├── create_profession.py └── create_profession_test.py └── validations ├── __init__.py ├── base_input_validator.py ├── base_input_validator_test.py ├── create_profession_validator.py └── create_profession_validator_test.py /.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_USER="db_user" 2 | DATABASE_PASSWORD="db_pass" 3 | DATABASE_NAME="db_name" 4 | DATABASE_HOST="localhost" 5 | -------------------------------------------------------------------------------- /.github/workflows/python-app.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: pytesting 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | permissions: 13 | contents: write 14 | 15 | jobs: 16 | build: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Set up Python 3.10 23 | uses: actions/setup-python@v3 24 | with: 25 | python-version: "3.10" 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install pytest pytest-cov pytest-mock pytest-coverage 30 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 31 | - name: Test with pytest 32 | run: | 33 | pytest --cov 34 | - name: Creating coverage folder 35 | run: | 36 | mkdir -p coverage 37 | - name: Coverage Bagdge 38 | uses: tj-actions/coverage-badge-py@v1.8 39 | with: 40 | output: coverage/coverage.svg 41 | - name: Publish coverage report to coverage-badge branch 42 | uses: JamesIves/github-pages-deploy-action@v4 43 | with: 44 | branch: coverage-badge 45 | folder: coverage 46 | -------------------------------------------------------------------------------- /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Single deploy job since we're just deploying 26 | deploy: 27 | environment: 28 | name: github-pages 29 | url: ${{ steps.deployment.outputs.page_url }} 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v3 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v3 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v1 38 | with: 39 | # Upload entire repository 40 | path: '.' 41 | - name: Deploy to GitHub Pages 42 | id: deployment 43 | uses: actions/deploy-pages@v2 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | .pytest_cache 3 | venv 4 | .env 5 | 6 | .coverage 7 | 8 | ##### Specific to this application ##### 9 | # Log 10 | app.log -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://gitlab.com/pycqa/flake8 3 | rev: 3.7.9 4 | hooks: 5 | - id: flake8 6 | stages: [commit] 7 | exclude: '(migrations|alembic|docs)/.*' 8 | - repo: local 9 | hooks: 10 | - id: pytest 11 | name: pytest 12 | language: system 13 | entry: pytest -v -s --cov --cov-fail-under=100 14 | always_run: true 15 | pass_filenames: false 16 | stages: [commit] 17 | - repo: local 18 | hooks: 19 | - id: requirements 20 | name: requirements 21 | entry: bash -c 'pip3 freeze > requirements.txt; git add requirements.txt' 22 | language: system 23 | pass_filenames: false 24 | stages: [commit] 25 | - repo: local 26 | hooks: 27 | - id: mypy 28 | name: mypy 29 | entry: "mypy --exclude '(docs|venv|alembic)' --explicit-package-bases ./" 30 | language: python 31 | # trigger for commits changing Python files 32 | types: [python] 33 | # use require_serial so that script 34 | # is only called once per commit 35 | require_serial: true 36 | # print the number of files as a sanity-check 37 | verbose: true 38 | pass_filenames: false -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.enabled": true, 3 | "python.linting.pylintEnabled": true, 4 | "python.linting.pylintArgs": [ 5 | "--max-line-length=79", 6 | "--load-plugins", 7 | "pylint_pytest", 8 | "--ignore-patterns=alembic/versions/*" 9 | ], 10 | "python.linting.mypyEnabled": true, 11 | "files.exclude": { 12 | "**/*.pyc": {"when": "$(basename).py"}, 13 | "**/__pycache__": true, 14 | "**/*.pytest_cache": true 15 | }, 16 | "[python]": { 17 | "editor.rulers": [ 18 | 79 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Claudio Shigueo Watanabe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![tests](https://github.com/claudiosw/python-clean-architecture-example/workflows/pytesting/badge.svg)   ![code coverage](https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/coverage-badge/coverage.svg?raw=true) 2 | 3 | # About 4 | This repository is a simple example of an implementation Clean Architecture using Python. 5 | 6 | # Articles about this project 7 | I am writing a series of Linkedin articles related to this project: 8 | * [Python Clean Architecture In-memory CLI implementation](https://www.linkedin.com/pulse/implementation-clean-architecture-python-part-1-cli-watanabe/): I wrote [this article](https://www.linkedin.com/pulse/implementation-clean-architecture-python-part-1-cli-watanabe/) explaining the Clean Architecture, its layers and a Python implementation of an in-memory CLI. 9 | * [Error Handling, Logging and Validation implementation in Python Clean Architecture](https://www.linkedin.com/pulse/implementation-clean-architecture-python-part-2-error-watanabe/): I wrote [this article](https://www.linkedin.com/pulse/implementation-clean-architecture-python-part-2-error-watanabe/) about error handling, logging and validation, including some Python best practices around these topics. I complemented our Python Clean Architecture implementation with those topics. 10 | * [Python Clean Architecture Flask Web API In-memory implementation](https://www.linkedin.com/pulse/implementation-clean-architecture-python-part-3-adding-watanabe/): In [this article](https://www.linkedin.com/pulse/implementation-clean-architecture-python-part-3-adding-watanabe/), I wrote about basic Flask concepts, Flask blueprints and how to test a Flask application. I also talked about the addition of a Flask web API to our Python Clean Architecture implementation. 11 | * [Python Clean Architecture Flask Web API Postgresql implementation](https//www.linkedin.com/pulse/implementation-clean-architecture-python-part-4-adding-watanabe/): In [this article](https//www.linkedin.com/pulse/implementation-clean-architecture-python-part-4-adding-watanabe/), I wrote about about the inclusion of the Flask PostgreSQL flavour in my Python Clean Architecture repository. I talked about the SQLAlchemy model, Alembic database migrations, using .env files to protect sensitive information and also how to close the database connection when the http connection is closed. 12 | 13 | Also, [check this repository](https://github.com/claudiosw/python-best-practices) where you can find examples and explanations of Python best practices that complement this repository and its articles. 14 | 15 | # Instalation 16 | 17 | ## On prompt, acess the directory that want to download the project 18 | ``` 19 | git clone https://github.com/claudiosw/python-clean-architecture-example-1.git 20 | ``` 21 | 22 | ## Create the virtual environment: 23 | ``` 24 | python -m venv venv 25 | 26 | ``` 27 | 28 | ## Run the virtual environment: 29 | ### Windows 30 | ``` 31 | venv\Scripts\activate 32 | 33 | ``` 34 | ### Linux/MacOS 35 | ``` 36 | source venv/bin/activate 37 | ``` 38 | 39 | ## Install the required Python packages: 40 | ``` 41 | pip install -r requirements.txt 42 | pre-commit install 43 | ``` 44 | 45 | # Run the In-Memory CLI 46 | ``` 47 | python .\cli_memory_process_handler.py 48 | ``` 49 | 50 | # Run the In-Memory Flask API 51 | ``` 52 | python .\flask_memory_process_handler.py 53 | ``` 54 | 55 | # Prepare the PostgreSQL database 56 | 57 | To use the PostgreSQL flavour of our app, we need to install PostgreSQL software. It can be in other machine as well. We will need a database and a user to access this database. 58 | 59 | Create a .env file. Use the .env.example file as a template. Set the values considering your scenario. 60 | 61 | ## Apply database migrations 62 | 63 | With the PostgreSQL database installed and configured, you can apply the database migrations with the command below: 64 | 65 | ``` 66 | alembic upgrade head 67 | ``` 68 | 69 | # Run the PostgreSQL Flask API 70 | ``` 71 | python .\flask_postgresql_process_handler.py 72 | ``` 73 | 74 | # Documentation 75 | 76 | ## API Documentation of the Flask PostgreSQL flavor of this project: 77 | You can access the API documentation [here](https://documenter.getpostman.com/view/27866946/2s93saZYEK). 78 | 79 | ## Documentation Generated by Sphinx 80 | You can see the documentation of this project generated by Sphinx in [here](https://claudiosw.github.io/python-clean-architecture-example/docs/build/html/index.html). 81 | 82 | 83 | # Closing 84 | 85 | I hope this repository and my article series were valuable to you. If that was the case, please star it. 86 | 87 | If you want to contact me, reach me on [LinkedIn](https://www.linkedin.com/in/claudiosw/) or [Twitter](https://twitter.com/ClaudioShigueoW). 88 | 89 | I am looking for a Python position. I also offer paid mentoring. -------------------------------------------------------------------------------- /alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = alembic 6 | 7 | # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s 8 | # Uncomment the line below if you want the files to be prepended with date and time 9 | # see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file 10 | # for all available tokens 11 | # file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s 12 | 13 | # sys.path path, will be prepended to sys.path if present. 14 | # defaults to the current working directory. 15 | prepend_sys_path = . 16 | 17 | # timezone to use when rendering the date within the migration file 18 | # as well as the filename. 19 | # If specified, requires the python-dateutil library that can be 20 | # installed by adding `alembic[tz]` to the pip requirements 21 | # string value is passed to dateutil.tz.gettz() 22 | # leave blank for localtime 23 | # timezone = 24 | 25 | # max length of characters to apply to the 26 | # "slug" field 27 | # truncate_slug_length = 40 28 | 29 | # set to 'true' to run the environment during 30 | # the 'revision' command, regardless of autogenerate 31 | # revision_environment = false 32 | 33 | # set to 'true' to allow .pyc and .pyo files without 34 | # a source .py file to be detected as revisions in the 35 | # versions/ directory 36 | # sourceless = false 37 | 38 | # version location specification; This defaults 39 | # to alembic/versions. When using multiple version 40 | # directories, initial revisions must be specified with --version-path. 41 | # The path separator used here should be the separator specified by "version_path_separator" below. 42 | # version_locations = %(here)s/bar:%(here)s/bat:alembic/versions 43 | 44 | # version path separator; As mentioned above, this is the character used to split 45 | # version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. 46 | # If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. 47 | # Valid values for version_path_separator are: 48 | # 49 | # version_path_separator = : 50 | # version_path_separator = ; 51 | # version_path_separator = space 52 | version_path_separator = os # Use os.pathsep. Default configuration used for new projects. 53 | 54 | # set to 'true' to search source files recursively 55 | # in each "version_locations" directory 56 | # new in Alembic version 1.10 57 | # recursive_version_locations = false 58 | 59 | # the output encoding used when revision files 60 | # are written from script.py.mako 61 | # output_encoding = utf-8 62 | 63 | # sqlalchemy.url = driver://user:pass@localhost/dbname 64 | # sqlalchemy.echo = True 65 | 66 | 67 | [post_write_hooks] 68 | # post_write_hooks defines scripts or Python functions that are run 69 | # on newly generated revision scripts. See the documentation for further 70 | # detail and examples 71 | 72 | # format using "black" - use the console_scripts runner, against the "black" entrypoint 73 | # hooks = black 74 | # black.type = console_scripts 75 | # black.entrypoint = black 76 | # black.options = -l 79 REVISION_SCRIPT_FILENAME 77 | 78 | # Logging configuration 79 | [loggers] 80 | keys = root,sqlalchemy,alembic 81 | 82 | [handlers] 83 | keys = console 84 | 85 | [formatters] 86 | keys = generic 87 | 88 | [logger_root] 89 | level = WARN 90 | handlers = console 91 | qualname = 92 | 93 | [logger_sqlalchemy] 94 | level = WARN 95 | handlers = 96 | qualname = sqlalchemy.engine 97 | 98 | [logger_alembic] 99 | level = INFO 100 | handlers = 101 | qualname = alembic 102 | 103 | [handler_console] 104 | class = StreamHandler 105 | args = (sys.stderr,) 106 | level = NOTSET 107 | formatter = generic 108 | 109 | [formatter_generic] 110 | format = %(levelname)-5.5s [%(name)s] %(message)s 111 | datefmt = %H:%M:%S 112 | -------------------------------------------------------------------------------- /alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /alembic/env.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=no-member 2 | # pylint: disable=missing-module-docstring 3 | 4 | 5 | from logging.config import fileConfig 6 | 7 | from sqlalchemy import engine_from_config 8 | from sqlalchemy import pool 9 | 10 | from alembic import context 11 | 12 | from configs import config as config_app 13 | from src.infra.db_models.db_base import Base 14 | from src.infra.db_models.profession_db_model import ProfessionsDBModel 15 | 16 | 17 | # this is the Alembic Config object, which provides 18 | # access to the values within the .ini file in use. 19 | config = context.config 20 | 21 | 22 | config.set_main_option('sqlalchemy.url', config_app.DB_URI) 23 | 24 | 25 | # Interpret the config file for Python logging. 26 | # This line sets up loggers basically. 27 | if config.config_file_name is not None: 28 | fileConfig(config.config_file_name) 29 | 30 | # add your model's MetaData object here 31 | # for 'autogenerate' support 32 | # from myapp import mymodel 33 | # target_metadata = mymodel.Base.metadata 34 | target_metadata = Base.metadata 35 | 36 | # other values from the config, defined by the needs of env.py, 37 | # can be acquired: 38 | # my_important_option = config.get_main_option("my_important_option") 39 | # ... etc. 40 | 41 | 42 | def run_migrations_offline() -> None: 43 | """Run migrations in 'offline' mode. 44 | 45 | This configures the context with just a URL 46 | and not an Engine, though an Engine is acceptable 47 | here as well. By skipping the Engine creation 48 | we don't even need a DBAPI to be available. 49 | 50 | Calls to context.execute() here emit the given string to the 51 | script output. 52 | 53 | """ 54 | url = config.get_main_option("sqlalchemy.url") 55 | context.configure( 56 | url=url, 57 | target_metadata=target_metadata, 58 | literal_binds=True, 59 | dialect_opts={"paramstyle": "named"}, 60 | ) 61 | 62 | with context.begin_transaction(): 63 | context.run_migrations() 64 | 65 | 66 | def run_migrations_online() -> None: 67 | """Run migrations in 'online' mode. 68 | 69 | In this scenario we need to create an Engine 70 | and associate a connection with the context. 71 | 72 | """ 73 | connectable = engine_from_config( 74 | config.get_section(config.config_ini_section, {}), 75 | prefix="sqlalchemy.", 76 | poolclass=pool.NullPool, 77 | ) 78 | 79 | with connectable.connect() as connection: 80 | context.configure( 81 | connection=connection, target_metadata=target_metadata 82 | ) 83 | 84 | with context.begin_transaction(): 85 | context.run_migrations() 86 | 87 | 88 | if context.is_offline_mode(): 89 | run_migrations_offline() 90 | else: 91 | run_migrations_online() 92 | -------------------------------------------------------------------------------- /alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade() -> None: 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade() -> None: 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /alembic/versions/0ca47c9b66bd_adding_professionsdbmodel.py: -------------------------------------------------------------------------------- 1 | """Adding ProfessionsDBModel 2 | 3 | Revision ID: 0ca47c9b66bd 4 | Revises: 5 | Create Date: 2023-05-31 15:27:45.862478 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '0ca47c9b66bd' 14 | down_revision = None 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade() -> None: 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('professions', 22 | sa.Column('profession_id', sa.UUID(), nullable=False), 23 | sa.Column('name', sa.String(length=80), nullable=False), 24 | sa.Column('description', sa.String(length=200), nullable=False), 25 | sa.PrimaryKeyConstraint('profession_id'), 26 | sa.UniqueConstraint('name') 27 | ) 28 | # ### end Alembic commands ### 29 | 30 | 31 | def downgrade() -> None: 32 | # ### commands auto generated by Alembic - please adjust! ### 33 | op.drop_table('professions') 34 | # ### end Alembic commands ### 35 | -------------------------------------------------------------------------------- /cli_memory_process_handler.py: -------------------------------------------------------------------------------- 1 | """ This module contains the ProcessHandler for Cli that uses Memory repository 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from src.app.cli_memory.interfaces.cli_memory_controller_interface \ 7 | import CliMemoryControllerInterface 8 | from src.app.cli_memory.controllers.exit_controller \ 9 | import ExitController 10 | from src.app.cli_memory.controllers.create_profession_controller \ 11 | import CreateProfessionController 12 | from src.interactor.errors.error_classes import FieldValueNotPermittedException 13 | from src.interactor.interfaces.logger.logger import LoggerInterface 14 | from src.infra.loggers.logger_default import LoggerDefault 15 | 16 | 17 | class CliMemoryProcessHandler: 18 | """ The ProcessHandler for Cli that uses Memory repository 19 | """ 20 | def __init__(self, logger: LoggerInterface) -> None: 21 | self.logger = logger 22 | self.options: Dict = {} 23 | 24 | def add_option( 25 | self, 26 | option: str, 27 | controller: CliMemoryControllerInterface 28 | ) -> None: 29 | """ Add an option to the ProcessHandler 30 | :param option: The option 31 | :param controller: The controller for the option 32 | :return: None 33 | """ 34 | self.options[option] = controller 35 | 36 | def show_options(self): 37 | """ Print the options to the ProcessHandler 38 | :return: None 39 | """ 40 | for option, controller in self.options.items(): 41 | print(f"{option}: {controller.__class__.__name__}") 42 | 43 | def execute(self) -> None: 44 | """ Execute the ProcessHandler 45 | :return: None 46 | """ 47 | while True: 48 | print("Please choose an option:") 49 | self.show_options() 50 | choice = input("> ") 51 | option = self.options.get(choice) 52 | if option: 53 | try: 54 | option.execute() 55 | except ( 56 | ValueError, 57 | FieldValueNotPermittedException 58 | ) as exception: 59 | print(f'\nERROR: {str(exception)}\n') 60 | self.logger.log_exception(str(exception)) 61 | else: 62 | print("Invalid choice.") 63 | self.logger.log_info(f"Invalid user choice: {option}") 64 | 65 | 66 | if __name__ == "__main__": 67 | logger_default = LoggerDefault() 68 | process = CliMemoryProcessHandler(logger_default) 69 | process.add_option("0", ExitController()) 70 | process.add_option("1", CreateProfessionController(logger_default)) 71 | process.execute() 72 | -------------------------------------------------------------------------------- /configs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/configs/__init__.py -------------------------------------------------------------------------------- /configs/config.py: -------------------------------------------------------------------------------- 1 | """ Configuration file 2 | """ 3 | 4 | 5 | import os 6 | from dotenv import load_dotenv 7 | 8 | 9 | load_dotenv() 10 | 11 | 12 | DB_USER = os.getenv("DATABASE_USER") 13 | DB_PASS = os.getenv("DATABASE_PASSWORD") 14 | DB_NAME = os.getenv("DATABASE_NAME") 15 | DB_HOST = os.getenv("DATABASE_HOST") 16 | DB_PORT = os.getenv("DATABASE_PORT") 17 | DB_DRIVER = "postgresql+psycopg2" 18 | 19 | 20 | DB_URI = f"{DB_DRIVER}://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}" 21 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/build/doctrees/cli_memory_process_handler.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/cli_memory_process_handler.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/configs.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/configs.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/build/doctrees/flask_memory_process_handler.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/flask_memory_process_handler.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/flask_postgresql_process_handler.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/flask_postgresql_process_handler.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/modules.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/modules.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.cli_memory.controllers.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.cli_memory.controllers.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.cli_memory.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.cli_memory.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.cli_memory.presenters.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.cli_memory.presenters.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.cli_memory.views.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.cli_memory.views.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_memory.blueprints.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_memory.blueprints.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_memory.controllers.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_memory.controllers.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_memory.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_memory.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_memory.interfaces.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_memory.interfaces.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_memory.presenters.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_memory.presenters.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_postgresql.blueprints.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_postgresql.blueprints.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_postgresql.controllers.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_postgresql.controllers.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_postgresql.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_postgresql.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_postgresql.interfaces.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_postgresql.interfaces.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.app.flask_postgresql.presenters.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.app.flask_postgresql.presenters.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.domain.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.domain.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.domain.entities.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.domain.entities.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.infra.db_models.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.infra.db_models.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.infra.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.infra.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.infra.repositories.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.infra.repositories.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.dtos.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.dtos.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.errors.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.errors.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.interfaces.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.interfaces.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.interfaces.logger.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.interfaces.logger.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.interfaces.presenters.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.interfaces.presenters.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.interfaces.repositories.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.interfaces.repositories.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.use_cases.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.use_cases.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/src.interactor.validations.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/doctrees/src.interactor.validations.doctree -------------------------------------------------------------------------------- /docs/build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: b2150682404517c2bb08c35bea2b3281 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/build/html/_sources/cli_memory_process_handler.rst.txt: -------------------------------------------------------------------------------- 1 | cli\_memory\_process\_handler module 2 | ==================================== 3 | 4 | .. automodule:: cli_memory_process_handler 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/build/html/_sources/configs.rst.txt: -------------------------------------------------------------------------------- 1 | configs package 2 | =============== 3 | 4 | Submodules 5 | ---------- 6 | 7 | configs.config module 8 | --------------------- 9 | 10 | .. automodule:: configs.config 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: configs 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/flask_memory_process_handler.rst.txt: -------------------------------------------------------------------------------- 1 | flask\_memory\_process\_handler module 2 | ====================================== 3 | 4 | .. automodule:: flask_memory_process_handler 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/build/html/_sources/flask_postgresql_process_handler.rst.txt: -------------------------------------------------------------------------------- 1 | flask\_postgresql\_process\_handler module 2 | ========================================== 3 | 4 | .. automodule:: flask_postgresql_process_handler 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. Python Clean Architecture example documentation master file, created by 2 | sphinx-quickstart on Thu Jun 8 19:17:15 2023. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Python Clean Architecture example's documentation! 7 | ============================================================= 8 | 9 | .. toctree:: 10 | :maxdepth: 7 11 | :caption: Contents: 12 | 13 | modules 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/build/html/_sources/modules.rst.txt: -------------------------------------------------------------------------------- 1 | python-clean-architecture-example 2 | ================================= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | cli_memory_process_handler 8 | configs 9 | flask_memory_process_handler 10 | flask_postgresql_process_handler 11 | src 12 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.cli_memory.controllers.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory.controllers package 2 | ======================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.cli\_memory.controllers.create\_profession\_controller module 8 | --------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.cli_memory.controllers.create_profession_controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.cli\_memory.controllers.create\_profession\_controller\_test module 16 | --------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.cli_memory.controllers.create_profession_controller_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | src.app.cli\_memory.controllers.exit\_controller module 24 | ------------------------------------------------------- 25 | 26 | .. automodule:: src.app.cli_memory.controllers.exit_controller 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | Module contents 32 | --------------- 33 | 34 | .. automodule:: src.app.cli_memory.controllers 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.cli_memory.presenters.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory.presenters package 2 | ====================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.cli\_memory.presenters.create\_profession\_presenter module 8 | ------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.cli_memory.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.cli\_memory.presenters.create\_profession\_presenter\_test module 16 | ------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.cli_memory.presenters.create_profession_presenter_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.cli_memory.presenters 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.cli_memory.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory package 2 | =========================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.cli_memory.controllers 11 | src.app.cli_memory.presenters 12 | src.app.cli_memory.views 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: src.app.cli_memory 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.cli_memory.views.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory.views package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.cli\_memory.views.create\_profession\_view module 8 | --------------------------------------------------------- 9 | 10 | .. automodule:: src.app.cli_memory.views.create_profession_view 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.cli\_memory.views.create\_profession\_view\_test module 16 | --------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.cli_memory.views.create_profession_view_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.cli_memory.views 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_memory.blueprints.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.blueprints package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.blueprints.create\_profession\_blueprint module 8 | --------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.blueprints.create_profession_blueprint 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_memory.blueprints 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_memory.controllers.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.controllers package 2 | ========================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.controllers.create\_profession\_controller module 8 | ----------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.controllers.create_profession_controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_memory.controllers.create\_profession\_controller\_test module 16 | ----------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_memory.controllers.create_profession_controller_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_memory.controllers 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_memory.interfaces.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.interfaces package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.interfaces.flask\_memory\_controller\_interface module 8 | ---------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.interfaces.flask_memory_controller_interface 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_memory.interfaces 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_memory.presenters.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.presenters package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.presenters.create\_profession\_presenter module 8 | --------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_memory.presenters.create\_profession\_presenter\_test module 16 | --------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_memory.presenters.create_profession_presenter_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_memory.presenters 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_memory.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory package 2 | ============================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.flask_memory.blueprints 11 | src.app.flask_memory.controllers 12 | src.app.flask_memory.interfaces 13 | src.app.flask_memory.presenters 14 | 15 | Submodules 16 | ---------- 17 | 18 | src.app.flask\_memory.create\_flask\_memory\_app module 19 | ------------------------------------------------------- 20 | 21 | .. automodule:: src.app.flask_memory.create_flask_memory_app 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | src.app.flask\_memory.create\_flask\_memory\_app\_test module 27 | ------------------------------------------------------------- 28 | 29 | .. automodule:: src.app.flask_memory.create_flask_memory_app_test 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | Module contents 35 | --------------- 36 | 37 | .. automodule:: src.app.flask_memory 38 | :members: 39 | :undoc-members: 40 | :show-inheritance: 41 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_postgresql.blueprints.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.blueprints package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.blueprints.create\_profession\_blueprint module 8 | ------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_postgresql.blueprints.create_profession_blueprint 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.blueprints 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_postgresql.controllers.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.controllers package 2 | ============================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.controllers.create\_profession\_controller module 8 | --------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_postgresql.controllers.create_profession_controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_postgresql.controllers.create\_profession\_controller\_test module 16 | --------------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.controllers.create_profession_controller_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_postgresql.controllers 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_postgresql.interfaces.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.interfaces package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.interfaces.flask\_postgresql\_controller\_interface module 8 | ------------------------------------------------------------------------------------ 9 | 10 | .. automodule:: src.app.flask_postgresql.interfaces.flask_postgresql_controller_interface 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.interfaces 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_postgresql.presenters.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.presenters package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.presenters.create\_profession\_presenter module 8 | ------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_postgresql.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_postgresql.presenters.create\_profession\_presenter\_test module 16 | ------------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.presenters.create_profession_presenter_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_postgresql.presenters 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.flask_postgresql.rst.txt: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql package 2 | ================================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.flask_postgresql.blueprints 11 | src.app.flask_postgresql.controllers 12 | src.app.flask_postgresql.interfaces 13 | src.app.flask_postgresql.presenters 14 | 15 | Submodules 16 | ---------- 17 | 18 | src.app.flask\_postgresql.create\_flask\_postgresql\_app module 19 | --------------------------------------------------------------- 20 | 21 | .. automodule:: src.app.flask_postgresql.create_flask_postgresql_app 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | src.app.flask\_postgresql.create\_flask\_postgresql\_app\_test module 27 | --------------------------------------------------------------------- 28 | 29 | .. automodule:: src.app.flask_postgresql.create_flask_postgresql_app_test 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | Module contents 35 | --------------- 36 | 37 | .. automodule:: src.app.flask_postgresql 38 | :members: 39 | :undoc-members: 40 | :show-inheritance: 41 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.app.rst.txt: -------------------------------------------------------------------------------- 1 | src.app package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.cli_memory 11 | src.app.flask_memory 12 | src.app.flask_postgresql 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: src.app 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.domain.entities.rst.txt: -------------------------------------------------------------------------------- 1 | src.domain.entities package 2 | =========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.domain.entities.profession module 8 | ------------------------------------- 9 | 10 | .. automodule:: src.domain.entities.profession 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.domain.entities.profession\_test module 16 | ------------------------------------------- 17 | 18 | .. automodule:: src.domain.entities.profession_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.domain.entities 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.domain.rst.txt: -------------------------------------------------------------------------------- 1 | src.domain package 2 | ================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.domain.entities 11 | 12 | Submodules 13 | ---------- 14 | 15 | src.domain.value\_objects module 16 | -------------------------------- 17 | 18 | .. automodule:: src.domain.value_objects 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.domain 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.infra.db_models.rst.txt: -------------------------------------------------------------------------------- 1 | src.infra.db\_models package 2 | ============================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.infra.db\_models.db\_base module 8 | ------------------------------------ 9 | 10 | .. automodule:: src.infra.db_models.db_base 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.infra.db\_models.profession\_db\_model module 16 | ------------------------------------------------- 17 | 18 | .. automodule:: src.infra.db_models.profession_db_model 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.infra.db_models 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.infra.repositories.rst.txt: -------------------------------------------------------------------------------- 1 | src.infra.repositories package 2 | ============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.infra.repositories.profession\_in\_memory\_repository module 8 | ---------------------------------------------------------------- 9 | 10 | .. automodule:: src.infra.repositories.profession_in_memory_repository 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.infra.repositories.profession\_in\_memory\_repository\_test module 16 | ---------------------------------------------------------------------- 17 | 18 | .. automodule:: src.infra.repositories.profession_in_memory_repository_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | src.infra.repositories.profession\_postgresql\_repository module 24 | ---------------------------------------------------------------- 25 | 26 | .. automodule:: src.infra.repositories.profession_postgresql_repository 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | src.infra.repositories.profession\_postgresql\_repository\_test module 32 | ---------------------------------------------------------------------- 33 | 34 | .. automodule:: src.infra.repositories.profession_postgresql_repository_test 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: src.infra.repositories 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.infra.rst.txt: -------------------------------------------------------------------------------- 1 | src.infra package 2 | ================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.infra.db_models 11 | src.infra.repositories 12 | 13 | Module contents 14 | --------------- 15 | 16 | .. automodule:: src.infra 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.dtos.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.dtos package 2 | =========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.dtos.create\_profession\_dtos module 8 | --------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.dtos.create_profession_dtos 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.dtos.create\_profession\_dtos\_test module 16 | --------------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.dtos.create_profession_dtos_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.interactor.dtos 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.errors.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.errors package 2 | ============================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.errors.error\_classes module 8 | ------------------------------------------- 9 | 10 | .. automodule:: src.interactor.errors.error_classes 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.errors.error\_classes\_test module 16 | ------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.errors.error_classes_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.interactor.errors 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.interfaces.logger.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces.logger package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.interfaces.logger.logger module 8 | ---------------------------------------------- 9 | 10 | .. automodule:: src.interactor.interfaces.logger.logger 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.interactor.interfaces.logger 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.interfaces.presenters.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces.presenters package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.interfaces.presenters.create\_profession\_presenter module 8 | ------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.interfaces.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.interactor.interfaces.presenters 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.interfaces.repositories.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces.repositories package 2 | ============================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.interfaces.repositories.profession\_repository module 8 | -------------------------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.interfaces.repositories.profession_repository 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.interactor.interfaces.repositories 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.interfaces.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces package 2 | ================================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.interactor.interfaces.logger 11 | src.interactor.interfaces.presenters 12 | src.interactor.interfaces.repositories 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: src.interactor.interfaces 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor package 2 | ====================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.interactor.dtos 11 | src.interactor.errors 12 | src.interactor.interfaces 13 | src.interactor.use_cases 14 | src.interactor.validations 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: src.interactor 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.use_cases.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.use\_cases package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.use\_cases.create\_profession module 8 | --------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.use_cases.create_profession 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.use\_cases.create\_profession\_test module 16 | --------------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.use_cases.create_profession_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.interactor.use_cases 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.interactor.validations.rst.txt: -------------------------------------------------------------------------------- 1 | src.interactor.validations package 2 | ================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.validations.base\_input\_validator module 8 | -------------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.validations.base_input_validator 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.validations.base\_input\_validator\_test module 16 | -------------------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.validations.base_input_validator_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | src.interactor.validations.create\_profession\_validator module 24 | --------------------------------------------------------------- 25 | 26 | .. automodule:: src.interactor.validations.create_profession_validator 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | src.interactor.validations.create\_profession\_validator\_test module 32 | --------------------------------------------------------------------- 33 | 34 | .. automodule:: src.interactor.validations.create_profession_validator_test 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: src.interactor.validations 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /docs/build/html/_sources/src.rst.txt: -------------------------------------------------------------------------------- 1 | src package 2 | =========== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app 11 | src.domain 12 | src.infra 13 | src.interactor 14 | 15 | Submodules 16 | ---------- 17 | 18 | src.conftest module 19 | ------------------- 20 | 21 | .. automodule:: src.conftest 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | Module contents 27 | --------------- 28 | 29 | .. automodule:: src 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | -------------------------------------------------------------------------------- /docs/build/html/_static/css/badge_only.css: -------------------------------------------------------------------------------- 1 | .clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-bold-italic.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-bold-italic.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-bold.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-bold.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-normal-italic.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-normal-italic.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-normal.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/css/fonts/lato-normal.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | var DOCUMENTATION_OPTIONS = { 2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), 3 | VERSION: '1.0.0', 4 | LANGUAGE: 'en', 5 | COLLAPSE_INDEX: false, 6 | BUILDER: 'html', 7 | FILE_SUFFIX: '.html', 8 | LINK_SUFFIX: '.html', 9 | HAS_SOURCE: true, 10 | SOURCELINK_SUFFIX: '.txt', 11 | NAVIGATION_WITH_KEYS: false, 12 | SHOW_SEARCH_SUMMARY: true, 13 | ENABLE_SEARCH_SHORTCUTS: true, 14 | }; -------------------------------------------------------------------------------- /docs/build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/_static/file.png -------------------------------------------------------------------------------- /docs/build/html/_static/js/badge_only.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); -------------------------------------------------------------------------------- /docs/build/html/_static/js/html5shiv-printshiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /docs/build/html/_static/js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /docs/build/html/_static/js/theme.js: -------------------------------------------------------------------------------- 1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t 2 | 3 | 4 | 5 | 6 | 7 | flask_memory_process_handler module — Python Clean Architecture example 1.0.0 documentation 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 51 | 52 |
56 | 57 |
58 |
59 |
60 | 67 |
68 |
69 |
70 |
71 | 72 |
73 |

flask_memory_process_handler module

74 |

Flask In-Memory Process Handler

75 |
76 | 77 | 78 |
79 |
80 |
81 | 82 |
83 | 84 |
85 |

© Copyright 2023, Claudio Shigueo Watanabe.

86 |
87 | 88 | Built with Sphinx using a 89 | theme 90 | provided by Read the Docs. 91 | 92 | 93 |
94 |
95 |
96 |
97 |
98 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/build/html/flask_postgresql_process_handler.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | flask_postgresql_process_handler module — Python Clean Architecture example 1.0.0 documentation 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 51 | 52 |
56 | 57 |
58 |
59 |
60 |
    61 |
  • 62 | 63 |
  • 64 | View page source 65 |
  • 66 |
67 |
68 |
69 |
70 |
71 | 72 |
73 |

flask_postgresql_process_handler module

74 |

Flask PostgreSQL Process Handler

75 |
76 | 77 | 78 |
79 |
80 |
81 | 82 |
83 | 84 |
85 |

© Copyright 2023, Claudio Shigueo Watanabe.

86 |
87 | 88 | Built with Sphinx using a 89 | theme 90 | provided by Read the Docs. 91 | 92 | 93 |
94 |
95 |
96 |
97 |
98 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/docs/build/html/objects.inv -------------------------------------------------------------------------------- /docs/build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Search — Python Clean Architecture example 1.0.0 documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 53 | 54 |
58 | 59 |
60 |
61 |
62 |
    63 |
  • 64 | 65 |
  • 66 |
  • 67 |
68 |
69 |
70 |
71 |
72 | 73 | 80 | 81 | 82 |
83 | 84 |
85 | 86 |
87 |
88 |
89 | 90 |
91 | 92 |
93 |

© Copyright 2023, Claudio Shigueo Watanabe.

94 |
95 | 96 | Built with Sphinx using a 97 | theme 98 | provided by Read the Docs. 99 | 100 | 101 |
102 |
103 |
104 |
105 |
106 | 111 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/cli_memory_process_handler.rst: -------------------------------------------------------------------------------- 1 | cli\_memory\_process\_handler module 2 | ==================================== 3 | 4 | .. automodule:: cli_memory_process_handler 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # pylint: skip-file 2 | # type: ignore 3 | 4 | # Configuration file for the Sphinx documentation builder. 5 | # 6 | # For the full list of built-in configuration values, see the documentation: 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 8 | 9 | # -- Project information ----------------------------------------------------- 10 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 11 | 12 | import os 13 | import sys 14 | # Use this line if you chose to separate source and build directories 15 | sys.path.insert(0, os.path.abspath('../..')) 16 | # Use this line if you chose to NOT separate source and build directories 17 | # sys.path.insert(0, os.path.abspath('..')) 18 | 19 | 20 | project = 'Python Clean Architecture example' 21 | copyright = '2023, Claudio Shigueo Watanabe' 22 | author = 'Claudio Shigueo Watanabe' 23 | release = '1.0.0' 24 | 25 | # -- General configuration --------------------------------------------------- 26 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 27 | 28 | extensions = ['sphinx.ext.autodoc'] 29 | 30 | templates_path = ['_templates'] 31 | exclude_patterns = [] 32 | 33 | 34 | 35 | # -- Options for HTML output ------------------------------------------------- 36 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 37 | 38 | html_theme = 'sphinx_rtd_theme' 39 | html_static_path = ['_static'] 40 | -------------------------------------------------------------------------------- /docs/source/configs.rst: -------------------------------------------------------------------------------- 1 | configs package 2 | =============== 3 | 4 | Submodules 5 | ---------- 6 | 7 | configs.config module 8 | --------------------- 9 | 10 | .. automodule:: configs.config 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: configs 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/flask_memory_process_handler.rst: -------------------------------------------------------------------------------- 1 | flask\_memory\_process\_handler module 2 | ====================================== 3 | 4 | .. automodule:: flask_memory_process_handler 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/flask_postgresql_process_handler.rst: -------------------------------------------------------------------------------- 1 | flask\_postgresql\_process\_handler module 2 | ========================================== 3 | 4 | .. automodule:: flask_postgresql_process_handler 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. Python Clean Architecture example documentation master file, created by 2 | sphinx-quickstart on Thu Jun 8 19:17:15 2023. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Python Clean Architecture example's documentation! 7 | ============================================================= 8 | 9 | .. toctree:: 10 | :maxdepth: 7 11 | :caption: Contents: 12 | 13 | modules 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | python-clean-architecture-example 2 | ================================= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | cli_memory_process_handler 8 | configs 9 | flask_memory_process_handler 10 | flask_postgresql_process_handler 11 | src 12 | -------------------------------------------------------------------------------- /docs/source/src.app.cli_memory.controllers.rst: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory.controllers package 2 | ======================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.cli\_memory.controllers.create\_profession\_controller module 8 | --------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.cli_memory.controllers.create_profession_controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.cli\_memory.controllers.create\_profession\_controller\_test module 16 | --------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.cli_memory.controllers.create_profession_controller_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | src.app.cli\_memory.controllers.exit\_controller module 24 | ------------------------------------------------------- 25 | 26 | .. automodule:: src.app.cli_memory.controllers.exit_controller 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | Module contents 32 | --------------- 33 | 34 | .. automodule:: src.app.cli_memory.controllers 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | -------------------------------------------------------------------------------- /docs/source/src.app.cli_memory.presenters.rst: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory.presenters package 2 | ====================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.cli\_memory.presenters.create\_profession\_presenter module 8 | ------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.cli_memory.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.cli\_memory.presenters.create\_profession\_presenter\_test module 16 | ------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.cli_memory.presenters.create_profession_presenter_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.cli_memory.presenters 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.app.cli_memory.rst: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory package 2 | =========================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.cli_memory.controllers 11 | src.app.cli_memory.presenters 12 | src.app.cli_memory.views 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: src.app.cli_memory 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/source/src.app.cli_memory.views.rst: -------------------------------------------------------------------------------- 1 | src.app.cli\_memory.views package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.cli\_memory.views.create\_profession\_view module 8 | --------------------------------------------------------- 9 | 10 | .. automodule:: src.app.cli_memory.views.create_profession_view 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.cli\_memory.views.create\_profession\_view\_test module 16 | --------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.cli_memory.views.create_profession_view_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.cli_memory.views 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_memory.blueprints.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.blueprints package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.blueprints.create\_profession\_blueprint module 8 | --------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.blueprints.create_profession_blueprint 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_memory.blueprints 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_memory.controllers.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.controllers package 2 | ========================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.controllers.create\_profession\_controller module 8 | ----------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.controllers.create_profession_controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_memory.controllers.create\_profession\_controller\_test module 16 | ----------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_memory.controllers.create_profession_controller_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_memory.controllers 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_memory.interfaces.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.interfaces package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.interfaces.flask\_memory\_controller\_interface module 8 | ---------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.interfaces.flask_memory_controller_interface 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_memory.interfaces 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_memory.presenters.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory.presenters package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_memory.presenters.create\_profession\_presenter module 8 | --------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_memory.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_memory.presenters.create\_profession\_presenter\_test module 16 | --------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_memory.presenters.create_profession_presenter_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_memory.presenters 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_memory.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_memory package 2 | ============================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.flask_memory.blueprints 11 | src.app.flask_memory.controllers 12 | src.app.flask_memory.interfaces 13 | src.app.flask_memory.presenters 14 | 15 | Submodules 16 | ---------- 17 | 18 | src.app.flask\_memory.create\_flask\_memory\_app module 19 | ------------------------------------------------------- 20 | 21 | .. automodule:: src.app.flask_memory.create_flask_memory_app 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | src.app.flask\_memory.create\_flask\_memory\_app\_test module 27 | ------------------------------------------------------------- 28 | 29 | .. automodule:: src.app.flask_memory.create_flask_memory_app_test 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | Module contents 35 | --------------- 36 | 37 | .. automodule:: src.app.flask_memory 38 | :members: 39 | :undoc-members: 40 | :show-inheritance: 41 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_postgresql.blueprints.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.blueprints package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.blueprints.create\_profession\_blueprint module 8 | ------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_postgresql.blueprints.create_profession_blueprint 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.blueprints 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_postgresql.controllers.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.controllers package 2 | ============================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.controllers.create\_profession\_controller module 8 | --------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_postgresql.controllers.create_profession_controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_postgresql.controllers.create\_profession\_controller\_test module 16 | --------------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.controllers.create_profession_controller_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_postgresql.controllers 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_postgresql.interfaces.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.interfaces package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.interfaces.flask\_postgresql\_controller\_interface module 8 | ------------------------------------------------------------------------------------ 9 | 10 | .. automodule:: src.app.flask_postgresql.interfaces.flask_postgresql_controller_interface 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.interfaces 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_postgresql.presenters.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql.presenters package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.app.flask\_postgresql.presenters.create\_profession\_presenter module 8 | ------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.app.flask_postgresql.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.app.flask\_postgresql.presenters.create\_profession\_presenter\_test module 16 | ------------------------------------------------------------------------------- 17 | 18 | .. automodule:: src.app.flask_postgresql.presenters.create_profession_presenter_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.app.flask_postgresql.presenters 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.app.flask_postgresql.rst: -------------------------------------------------------------------------------- 1 | src.app.flask\_postgresql package 2 | ================================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.flask_postgresql.blueprints 11 | src.app.flask_postgresql.controllers 12 | src.app.flask_postgresql.interfaces 13 | src.app.flask_postgresql.presenters 14 | 15 | Submodules 16 | ---------- 17 | 18 | src.app.flask\_postgresql.create\_flask\_postgresql\_app module 19 | --------------------------------------------------------------- 20 | 21 | .. automodule:: src.app.flask_postgresql.create_flask_postgresql_app 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | src.app.flask\_postgresql.create\_flask\_postgresql\_app\_test module 27 | --------------------------------------------------------------------- 28 | 29 | .. automodule:: src.app.flask_postgresql.create_flask_postgresql_app_test 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | Module contents 35 | --------------- 36 | 37 | .. automodule:: src.app.flask_postgresql 38 | :members: 39 | :undoc-members: 40 | :show-inheritance: 41 | -------------------------------------------------------------------------------- /docs/source/src.app.rst: -------------------------------------------------------------------------------- 1 | src.app package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app.cli_memory 11 | src.app.flask_memory 12 | src.app.flask_postgresql 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: src.app 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/source/src.domain.entities.rst: -------------------------------------------------------------------------------- 1 | src.domain.entities package 2 | =========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.domain.entities.profession module 8 | ------------------------------------- 9 | 10 | .. automodule:: src.domain.entities.profession 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.domain.entities.profession\_test module 16 | ------------------------------------------- 17 | 18 | .. automodule:: src.domain.entities.profession_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.domain.entities 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.domain.rst: -------------------------------------------------------------------------------- 1 | src.domain package 2 | ================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.domain.entities 11 | 12 | Submodules 13 | ---------- 14 | 15 | src.domain.value\_objects module 16 | -------------------------------- 17 | 18 | .. automodule:: src.domain.value_objects 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.domain 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.infra.db_models.rst: -------------------------------------------------------------------------------- 1 | src.infra.db\_models package 2 | ============================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.infra.db\_models.db\_base module 8 | ------------------------------------ 9 | 10 | .. automodule:: src.infra.db_models.db_base 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.infra.db\_models.profession\_db\_model module 16 | ------------------------------------------------- 17 | 18 | .. automodule:: src.infra.db_models.profession_db_model 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.infra.db_models 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.infra.repositories.rst: -------------------------------------------------------------------------------- 1 | src.infra.repositories package 2 | ============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.infra.repositories.profession\_in\_memory\_repository module 8 | ---------------------------------------------------------------- 9 | 10 | .. automodule:: src.infra.repositories.profession_in_memory_repository 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.infra.repositories.profession\_in\_memory\_repository\_test module 16 | ---------------------------------------------------------------------- 17 | 18 | .. automodule:: src.infra.repositories.profession_in_memory_repository_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | src.infra.repositories.profession\_postgresql\_repository module 24 | ---------------------------------------------------------------- 25 | 26 | .. automodule:: src.infra.repositories.profession_postgresql_repository 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | src.infra.repositories.profession\_postgresql\_repository\_test module 32 | ---------------------------------------------------------------------- 33 | 34 | .. automodule:: src.infra.repositories.profession_postgresql_repository_test 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: src.infra.repositories 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /docs/source/src.infra.rst: -------------------------------------------------------------------------------- 1 | src.infra package 2 | ================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.infra.db_models 11 | src.infra.repositories 12 | 13 | Module contents 14 | --------------- 15 | 16 | .. automodule:: src.infra 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | -------------------------------------------------------------------------------- /docs/source/src.interactor.dtos.rst: -------------------------------------------------------------------------------- 1 | src.interactor.dtos package 2 | =========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.dtos.create\_profession\_dtos module 8 | --------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.dtos.create_profession_dtos 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.dtos.create\_profession\_dtos\_test module 16 | --------------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.dtos.create_profession_dtos_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.interactor.dtos 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.interactor.errors.rst: -------------------------------------------------------------------------------- 1 | src.interactor.errors package 2 | ============================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.errors.error\_classes module 8 | ------------------------------------------- 9 | 10 | .. automodule:: src.interactor.errors.error_classes 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.errors.error\_classes\_test module 16 | ------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.errors.error_classes_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.interactor.errors 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.interactor.interfaces.logger.rst: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces.logger package 2 | ======================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.interfaces.logger.logger module 8 | ---------------------------------------------- 9 | 10 | .. automodule:: src.interactor.interfaces.logger.logger 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.interactor.interfaces.logger 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/src.interactor.interfaces.presenters.rst: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces.presenters package 2 | ============================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.interfaces.presenters.create\_profession\_presenter module 8 | ------------------------------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.interfaces.presenters.create_profession_presenter 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.interactor.interfaces.presenters 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/src.interactor.interfaces.repositories.rst: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces.repositories package 2 | ============================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.interfaces.repositories.profession\_repository module 8 | -------------------------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.interfaces.repositories.profession_repository 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: src.interactor.interfaces.repositories 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/src.interactor.interfaces.rst: -------------------------------------------------------------------------------- 1 | src.interactor.interfaces package 2 | ================================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.interactor.interfaces.logger 11 | src.interactor.interfaces.presenters 12 | src.interactor.interfaces.repositories 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: src.interactor.interfaces 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/source/src.interactor.rst: -------------------------------------------------------------------------------- 1 | src.interactor package 2 | ====================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.interactor.dtos 11 | src.interactor.errors 12 | src.interactor.interfaces 13 | src.interactor.use_cases 14 | src.interactor.validations 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: src.interactor 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/source/src.interactor.use_cases.rst: -------------------------------------------------------------------------------- 1 | src.interactor.use\_cases package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.use\_cases.create\_profession module 8 | --------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.use_cases.create_profession 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.use\_cases.create\_profession\_test module 16 | --------------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.use_cases.create_profession_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: src.interactor.use_cases 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/src.interactor.validations.rst: -------------------------------------------------------------------------------- 1 | src.interactor.validations package 2 | ================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | src.interactor.validations.base\_input\_validator module 8 | -------------------------------------------------------- 9 | 10 | .. automodule:: src.interactor.validations.base_input_validator 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | src.interactor.validations.base\_input\_validator\_test module 16 | -------------------------------------------------------------- 17 | 18 | .. automodule:: src.interactor.validations.base_input_validator_test 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | src.interactor.validations.create\_profession\_validator module 24 | --------------------------------------------------------------- 25 | 26 | .. automodule:: src.interactor.validations.create_profession_validator 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | src.interactor.validations.create\_profession\_validator\_test module 32 | --------------------------------------------------------------------- 33 | 34 | .. automodule:: src.interactor.validations.create_profession_validator_test 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: src.interactor.validations 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /docs/source/src.rst: -------------------------------------------------------------------------------- 1 | src package 2 | =========== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | src.app 11 | src.domain 12 | src.infra 13 | src.interactor 14 | 15 | Submodules 16 | ---------- 17 | 18 | src.conftest module 19 | ------------------- 20 | 21 | .. automodule:: src.conftest 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | Module contents 27 | --------------- 28 | 29 | .. automodule:: src 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | -------------------------------------------------------------------------------- /flask_memory_process_handler.py: -------------------------------------------------------------------------------- 1 | """ Flask In-Memory Process Handler 2 | """ 3 | 4 | 5 | from src.app.flask_memory.create_flask_memory_app \ 6 | import create_flask_memory_app 7 | from src.infra.loggers.logger_default import LoggerDefault 8 | 9 | 10 | logger = LoggerDefault() 11 | 12 | 13 | if __name__ == "__main__": 14 | flask_memory_app = create_flask_memory_app(logger) 15 | flask_memory_app.run(debug=True) 16 | -------------------------------------------------------------------------------- /flask_postgresql_process_handler.py: -------------------------------------------------------------------------------- 1 | """ Flask PostgreSQL Process Handler 2 | """ 3 | 4 | 5 | from src.app.flask_postgresql.create_flask_postgresql_app \ 6 | import create_flask_postgresql_app 7 | from src.infra.loggers.logger_default import LoggerDefault 8 | 9 | 10 | logger = LoggerDefault() 11 | 12 | 13 | if __name__ == "__main__": 14 | flask_memory_app = create_flask_postgresql_app(logger) 15 | flask_memory_app.run(debug=True) 16 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | alabaster==0.7.13 2 | alembic==1.11.1 3 | astroid==2.15.3 4 | Babel==2.12.1 5 | blinker==1.6.2 6 | Cerberus==1.3.4 7 | certifi==2023.5.7 8 | cfgv==3.3.1 9 | charset-normalizer==3.1.0 10 | click==8.1.3 11 | colorama==0.4.6 12 | coverage==7.2.3 13 | dill==0.3.6 14 | distlib==0.3.6 15 | docutils==0.18.1 16 | exceptiongroup==1.1.1 17 | filelock==3.12.0 18 | Flask==2.3.2 19 | greenlet==2.0.2 20 | identify==2.5.22 21 | idna==3.4 22 | imagesize==1.4.1 23 | importlib-metadata==6.6.0 24 | iniconfig==2.0.0 25 | install==1.3.5 26 | isort==5.12.0 27 | itsdangerous==2.1.2 28 | Jinja2==3.1.2 29 | lazy-object-proxy==1.9.0 30 | lxml-stubs==0.4.0 31 | Mako==1.2.4 32 | MarkupSafe==2.1.2 33 | mccabe==0.7.0 34 | mypy==1.3.0 35 | mypy-extensions==1.0.0 36 | nodeenv==1.7.0 37 | packaging==23.1 38 | platformdirs==3.2.0 39 | pluggy==1.0.0 40 | pre-commit==3.2.2 41 | psycopg2==2.9.6 42 | Pygments==2.15.1 43 | pylint==2.17.2 44 | pylint-pytest==1.1.2 45 | pytest==7.3.1 46 | pytest-cov==4.0.0 47 | pytest-cover==3.0.0 48 | pytest-coverage==0.0 49 | pytest-flask==1.2.0 50 | pytest-mock==3.10.0 51 | python-dotenv==1.0.0 52 | PyYAML==6.0 53 | requests==2.31.0 54 | six==1.16.0 55 | snowballstemmer==2.2.0 56 | Sphinx==6.2.1 57 | sphinx-rtd-theme==1.2.2 58 | sphinxcontrib-applehelp==1.0.4 59 | sphinxcontrib-devhelp==1.0.2 60 | sphinxcontrib-htmlhelp==2.0.1 61 | sphinxcontrib-jquery==4.1 62 | sphinxcontrib-jsmath==1.0.1 63 | sphinxcontrib-qthelp==1.0.3 64 | sphinxcontrib-serializinghtml==1.1.5 65 | SQLAlchemy==2.0.15 66 | toml==0.10.2 67 | tomli==2.0.1 68 | tomlkit==0.11.7 69 | types-docutils==0.20.0.1 70 | typing_extensions==4.5.0 71 | urllib3==2.0.3 72 | virtualenv==20.22.0 73 | Werkzeug==2.3.4 74 | wrapt==1.15.0 75 | zipp==3.15.0 76 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/__init__.py -------------------------------------------------------------------------------- /src/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/__init__.py -------------------------------------------------------------------------------- /src/app/cli_memory/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/cli_memory/__init__.py -------------------------------------------------------------------------------- /src/app/cli_memory/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/cli_memory/controllers/__init__.py -------------------------------------------------------------------------------- /src/app/cli_memory/controllers/create_profession_controller.py: -------------------------------------------------------------------------------- 1 | """Create Profession Controller Module""" 2 | 3 | 4 | from src.interactor.use_cases.create_profession import CreateProfessionUseCase 5 | from src.infra.repositories.profession_in_memory_repository \ 6 | import ProfessionInMemoryRepository 7 | from src.interactor.dtos.create_profession_dtos import CreateProfessionInputDto 8 | from src.app.cli_memory.interfaces.cli_memory_controller_interface \ 9 | import CliMemoryControllerInterface 10 | from src.interactor.interfaces.logger.logger import LoggerInterface 11 | from ..presenters.create_profession_presenter import CreateProfessionPresenter 12 | from ..views.create_profession_view import CreateProfessionView 13 | 14 | 15 | class CreateProfessionController(CliMemoryControllerInterface): 16 | """ Create Profession Controller Class 17 | """ 18 | def __init__(self, logger: LoggerInterface): 19 | self.logger = logger 20 | 21 | def _get_profession_info(self) -> CreateProfessionInputDto: 22 | name = input("Enter the profession name:") 23 | description = input("Enter the profession description:") 24 | return CreateProfessionInputDto(name, description) 25 | 26 | def execute(self): 27 | """ Execute the create profession controller 28 | """ 29 | repository = ProfessionInMemoryRepository() 30 | presenter = CreateProfessionPresenter() 31 | input_dto = self._get_profession_info() 32 | use_case = CreateProfessionUseCase(presenter, repository, self.logger) 33 | result = use_case.execute(input_dto) 34 | view = CreateProfessionView() 35 | view.show(result) 36 | -------------------------------------------------------------------------------- /src/app/cli_memory/controllers/create_profession_controller_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from src.app.cli_memory.controllers.create_profession_controller \ 7 | import CreateProfessionController 8 | from src.interactor.dtos.create_profession_dtos import CreateProfessionInputDto 9 | from src.interactor.interfaces.logger.logger import LoggerInterface 10 | 11 | 12 | def test_create_profession(monkeypatch, mocker, fixture_profession_developer): 13 | name = fixture_profession_developer["name"] 14 | description = fixture_profession_developer["description"] 15 | fake_user_inputs = iter([name, description]) 16 | monkeypatch.setattr('builtins.input', lambda _: next(fake_user_inputs)) 17 | 18 | mock_repository = mocker.patch( 19 | 'src.app.cli_memory.controllers.create_profession_controller.\ 20 | ProfessionInMemoryRepository') 21 | mock_presenter = mocker.patch( 22 | 'src.app.cli_memory.controllers.create_profession_controller.\ 23 | CreateProfessionPresenter') 24 | mock_use_case = mocker.patch( 25 | 'src.app.cli_memory.controllers.create_profession_controller.\ 26 | CreateProfessionUseCase') 27 | mock_use_case_instance = mock_use_case.return_value 28 | mock_view = mocker.patch( 29 | 'src.app.cli_memory.controllers.create_profession_controller.\ 30 | CreateProfessionView') 31 | logger_mock = mocker.patch.object( 32 | LoggerInterface, 33 | "log_info" 34 | ) 35 | result_use_case = { 36 | "profession_id": fixture_profession_developer["profession_id"], 37 | "name": fixture_profession_developer["name"], 38 | "description": fixture_profession_developer["description"] 39 | } 40 | mock_use_case_instance.execute.return_value = result_use_case 41 | mock_view_instance = mock_view.return_value 42 | 43 | controller = CreateProfessionController(logger_mock) 44 | controller.execute() 45 | 46 | mock_repository.assert_called_once_with() 47 | mock_presenter.assert_called_once_with() 48 | mock_use_case.assert_called_once_with( 49 | mock_presenter.return_value, 50 | mock_repository.return_value, 51 | logger_mock 52 | ) 53 | input_dto = CreateProfessionInputDto(name, description) 54 | mock_use_case_instance.execute.assert_called_once_with(input_dto) 55 | mock_view_instance.show.assert_called_once_with(result_use_case) 56 | -------------------------------------------------------------------------------- /src/app/cli_memory/controllers/exit_controller.py: -------------------------------------------------------------------------------- 1 | """ This module contains the ExitController class 2 | """ 3 | 4 | 5 | import sys 6 | from src.app.cli_memory.interfaces.cli_memory_controller_interface \ 7 | import CliMemoryControllerInterface 8 | 9 | 10 | class ExitController(CliMemoryControllerInterface): 11 | """ This class is a controller for exiting the program 12 | """ 13 | def execute(self): 14 | """ This method executes the controller, exiting the program 15 | """ 16 | print("Exiting the program") 17 | sys.exit() 18 | -------------------------------------------------------------------------------- /src/app/cli_memory/interfaces/cli_memory_controller_interface.py: -------------------------------------------------------------------------------- 1 | """ This module contains the CliMemoryControllerInterface class 2 | """ 3 | 4 | 5 | from abc import ABC, abstractmethod 6 | 7 | 8 | class CliMemoryControllerInterface(ABC): 9 | """ This class is the interface for the CliMemoryController class 10 | """ 11 | @abstractmethod 12 | def execute(self): 13 | """ Executes the controller 14 | """ 15 | -------------------------------------------------------------------------------- /src/app/cli_memory/presenters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/cli_memory/presenters/__init__.py -------------------------------------------------------------------------------- /src/app/cli_memory/presenters/create_profession_presenter.py: -------------------------------------------------------------------------------- 1 | """ Module for the CreateProfessionPresenter 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from src.interactor.dtos.create_profession_dtos \ 7 | import CreateProfessionOutputDto 8 | from src.interactor.interfaces.presenters.create_profession_presenter \ 9 | import CreateProfessionPresenterInterface 10 | 11 | 12 | class CreateProfessionPresenter(CreateProfessionPresenterInterface): 13 | """ Class for the CreateProfessionPresenter 14 | """ 15 | def present(self, output_dto: CreateProfessionOutputDto) -> Dict: 16 | """ Present the CreateProfession 17 | :param output_dto: CreateProfessionOutputDto 18 | :return: Dict 19 | """ 20 | return { 21 | "profession_id": output_dto.profession.profession_id, 22 | "name": output_dto.profession.name, 23 | "description": output_dto.profession.description 24 | } 25 | -------------------------------------------------------------------------------- /src/app/cli_memory/presenters/create_profession_presenter_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from src.interactor.dtos.create_profession_dtos \ 7 | import CreateProfessionOutputDto 8 | from src.domain.entities.profession import Profession 9 | from .create_profession_presenter import CreateProfessionPresenter 10 | 11 | 12 | def test_create_profession_presenter(fixture_profession_developer): 13 | profession = Profession( 14 | profession_id=fixture_profession_developer["profession_id"], 15 | name=fixture_profession_developer["name"], 16 | description=fixture_profession_developer["description"] 17 | ) 18 | output_dto = CreateProfessionOutputDto(profession) 19 | presenter = CreateProfessionPresenter() 20 | assert presenter.present(output_dto) == { 21 | "profession_id": fixture_profession_developer["profession_id"], 22 | "name": fixture_profession_developer["name"], 23 | "description": fixture_profession_developer["description"] 24 | } 25 | -------------------------------------------------------------------------------- /src/app/cli_memory/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/cli_memory/views/__init__.py -------------------------------------------------------------------------------- /src/app/cli_memory/views/create_profession_view.py: -------------------------------------------------------------------------------- 1 | """ Create profession view Module """ 2 | 3 | 4 | from typing import Dict 5 | 6 | 7 | class CreateProfessionView: 8 | """ Create profession view Class """ 9 | def show(self, data: Dict) -> None: 10 | """ Show profession view 11 | :param data: data to show 12 | :return: None 13 | """ 14 | print(data) 15 | -------------------------------------------------------------------------------- /src/app/cli_memory/views/create_profession_view_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from .create_profession_view import CreateProfessionView 7 | 8 | 9 | def test_create_profession_presenter(capsys, fixture_profession_developer): 10 | profession_dict = { 11 | "profession_id": fixture_profession_developer["profession_id"], 12 | "name": fixture_profession_developer["name"], 13 | "description": fixture_profession_developer["description"] 14 | } 15 | view = CreateProfessionView() 16 | view.show(profession_dict) 17 | captured = capsys.readouterr() 18 | assert captured.out == str(profession_dict) + "\n" 19 | -------------------------------------------------------------------------------- /src/app/flask_memory/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_memory/__init__.py -------------------------------------------------------------------------------- /src/app/flask_memory/blueprints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_memory/blueprints/__init__.py -------------------------------------------------------------------------------- /src/app/flask_memory/blueprints/create_profession_blueprint.py: -------------------------------------------------------------------------------- 1 | """ Flask Blueprint Create Profession 2 | """ 3 | 4 | 5 | from flask import Blueprint, request, current_app 6 | from src.app.flask_memory.controllers.create_profession_controller import \ 7 | CreateProfessionController 8 | 9 | 10 | blueprint_create_profession = Blueprint('create_profession', __name__) 11 | 12 | 13 | @blueprint_create_profession.route('/profession/', methods=["POST"]) 14 | def create_profession_blueprint(): 15 | """ Create Profession Blueprint 16 | """ 17 | logger = current_app.config['logger'] 18 | input_json = request.get_json(force=True) 19 | controller = CreateProfessionController(logger) 20 | controller.get_profession_info(input_json) 21 | result = controller.execute() 22 | return result 23 | -------------------------------------------------------------------------------- /src/app/flask_memory/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_memory/controllers/__init__.py -------------------------------------------------------------------------------- /src/app/flask_memory/controllers/create_profession_controller.py: -------------------------------------------------------------------------------- 1 | """Create Profession Controller Module""" 2 | 3 | 4 | from typing import Dict 5 | from src.interactor.use_cases.create_profession import CreateProfessionUseCase 6 | from src.infra.repositories.profession_in_memory_repository \ 7 | import ProfessionInMemoryRepository 8 | from src.interactor.dtos.create_profession_dtos import CreateProfessionInputDto 9 | from src.app.flask_memory.interfaces.flask_memory_controller_interface \ 10 | import FlaskMemoryControllerInterface 11 | from src.interactor.interfaces.logger.logger import LoggerInterface 12 | from src.app.flask_memory.presenters.create_profession_presenter import \ 13 | CreateProfessionPresenter 14 | 15 | 16 | class CreateProfessionController(FlaskMemoryControllerInterface): 17 | """ Create Profession Controller Class 18 | """ 19 | def __init__(self, logger: LoggerInterface): 20 | self.logger = logger 21 | self.input_dto: CreateProfessionInputDto 22 | 23 | def get_profession_info(self, json_input) -> None: 24 | """ Get Profession Info 25 | :param json_input: Input data 26 | :raises: ValueError if profession name or description are missing. 27 | """ 28 | if "name" in json_input: 29 | name = json_input["name"] 30 | else: 31 | raise ValueError("Missing Profession Name") 32 | if "description" in json_input: 33 | description = json_input["description"] 34 | else: 35 | raise ValueError("Missing Profession Description") 36 | self.input_dto = CreateProfessionInputDto(name, description) 37 | 38 | def execute(self) -> Dict: 39 | """ Execute the create profession controller 40 | :returns: Profession created 41 | """ 42 | repository = ProfessionInMemoryRepository() 43 | presenter = CreateProfessionPresenter() 44 | use_case = CreateProfessionUseCase(presenter, repository, self.logger) 45 | result = use_case.execute(self.input_dto) 46 | return result 47 | -------------------------------------------------------------------------------- /src/app/flask_memory/controllers/create_profession_controller_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import pytest 7 | from src.app.flask_memory.controllers.create_profession_controller \ 8 | import CreateProfessionController 9 | from src.interactor.dtos.create_profession_dtos import CreateProfessionInputDto 10 | from src.interactor.interfaces.logger.logger import LoggerInterface 11 | 12 | 13 | def test_create_profession(monkeypatch, mocker, fixture_profession_developer): 14 | name = fixture_profession_developer["name"] 15 | description = fixture_profession_developer["description"] 16 | fake_user_inputs = { 17 | "name": name, 18 | "description": description 19 | } 20 | monkeypatch.setattr('builtins.input', lambda _: next(fake_user_inputs)) 21 | 22 | mock_repository = mocker.patch( 23 | 'src.app.flask_memory.controllers.create_profession_controller.\ 24 | ProfessionInMemoryRepository') 25 | mock_presenter = mocker.patch( 26 | 'src.app.flask_memory.controllers.create_profession_controller.\ 27 | CreateProfessionPresenter') 28 | mock_use_case = mocker.patch( 29 | 'src.app.flask_memory.controllers.create_profession_controller.\ 30 | CreateProfessionUseCase') 31 | mock_use_case_instance = mock_use_case.return_value 32 | logger_mock = mocker.patch.object( 33 | LoggerInterface, 34 | "log_info" 35 | ) 36 | result_use_case = { 37 | "profession_id": fixture_profession_developer["profession_id"], 38 | "name": fixture_profession_developer["name"], 39 | "description": fixture_profession_developer["description"] 40 | } 41 | mock_use_case_instance.execute.return_value = result_use_case 42 | 43 | controller = CreateProfessionController(logger_mock) 44 | controller.get_profession_info(fake_user_inputs) 45 | result = controller.execute() 46 | 47 | mock_repository.assert_called_once_with() 48 | mock_presenter.assert_called_once_with() 49 | mock_use_case.assert_called_once_with( 50 | mock_presenter.return_value, 51 | mock_repository.return_value, 52 | logger_mock 53 | ) 54 | input_dto = CreateProfessionInputDto(name, description) 55 | mock_use_case_instance.execute.assert_called_once_with(input_dto) 56 | assert result["name"] == name 57 | assert result["description"] == description 58 | 59 | # Test for missing inputs (name) 60 | fake_user_inputs = { 61 | "nam": name, 62 | "description": description 63 | } 64 | with pytest.raises(ValueError) as exception_info: 65 | controller.get_profession_info(fake_user_inputs) 66 | assert str(exception_info.value) == "Missing Profession Name" 67 | 68 | # Test for missing inputs (description) 69 | fake_user_inputs = { 70 | "name": name, 71 | "descriptio": description 72 | } 73 | with pytest.raises(ValueError) as exception_info: 74 | controller.get_profession_info(fake_user_inputs) 75 | assert str(exception_info.value) == "Missing Profession Description" 76 | -------------------------------------------------------------------------------- /src/app/flask_memory/create_flask_memory_app.py: -------------------------------------------------------------------------------- 1 | """ Main Flask In-Memory app 2 | """ 3 | 4 | 5 | from flask import Flask 6 | from werkzeug.exceptions import HTTPException 7 | from src.app.flask_memory.blueprints.create_profession_blueprint \ 8 | import blueprint_create_profession 9 | from src.interactor.interfaces.logger.logger import LoggerInterface 10 | from src.interactor.errors.error_classes \ 11 | import FieldValueNotPermittedException 12 | 13 | 14 | def format_error_response( 15 | error: Exception, 16 | error_code: int, 17 | logger: LoggerInterface 18 | ): 19 | """ Format Error Response """ 20 | logger.log_exception(f"500 - Internal Server Error: {str(error)}") 21 | 22 | response = { 23 | 'status_code': error_code, 24 | 'error': error.__class__.__name__, 25 | 'message': str(error) 26 | } 27 | return response, error_code 28 | 29 | 30 | def create_flask_memory_app(logger: LoggerInterface): 31 | """ Create Main Flask In-Memory app 32 | """ 33 | app = Flask(__name__) 34 | app.config['logger'] = logger 35 | app.register_blueprint(blueprint_create_profession, url_prefix='/v1') 36 | 37 | @app.errorhandler(HTTPException) 38 | def handle_http_error(error: HTTPException): 39 | """ Handle HTTP Error Response """ 40 | logger.log_exception(str(error.__class__.__name__)) 41 | logger.log_exception(str(error.description)) 42 | response = { 43 | 'error': error.__class__.__name__, 44 | 'message': error.description, 45 | } 46 | return response, error.code 47 | 48 | @app.errorhandler(ValueError) 49 | def handle_value_error(error: ValueError): 50 | """ Handle Value Error Response """ 51 | return format_error_response(error, 400, logger) 52 | 53 | @app.errorhandler(FieldValueNotPermittedException) 54 | def handle_field_not_permitted_error(error: ValueError): 55 | """ Handle Value Error Response """ 56 | return format_error_response(error, 400, logger) 57 | 58 | @app.errorhandler(Exception) 59 | def handle_general_exception(error): 60 | """ Handle Other Errors Response """ 61 | return format_error_response(error, 500, logger) 62 | 63 | return app 64 | -------------------------------------------------------------------------------- /src/app/flask_memory/create_flask_memory_app_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import pytest 7 | from src.infra.loggers.logger_default import LoggerDefault 8 | from src.app.flask_memory.controllers.create_profession_controller import \ 9 | CreateProfessionController 10 | from .create_flask_memory_app import create_flask_memory_app 11 | 12 | 13 | logger = LoggerDefault() 14 | 15 | 16 | @pytest.fixture(name="app_flask_memory_app") 17 | def fixture_app_flask_memory_app(): 18 | """ Fixture for flask app with blueprint 19 | """ 20 | app = create_flask_memory_app(logger) 21 | app.config.update({ 22 | "TESTING": True, 23 | }) 24 | 25 | yield app 26 | 27 | 28 | @pytest.fixture(name="client_flask_memory_app") 29 | def fixture_client_flask_memory_app(app_flask_memory_app): 30 | """ Fixture to test app_flask_with_blueprint 31 | """ 32 | return app_flask_memory_app.test_client() 33 | 34 | 35 | def test_request_profession( 36 | client_flask_memory_app, 37 | fixture_profession_developer 38 | ): 39 | """ Test request example 40 | """ 41 | input_data = { 42 | "name": fixture_profession_developer["name"], 43 | "description": fixture_profession_developer["description"] 44 | } 45 | response = client_flask_memory_app.post("/v1/profession/", json=input_data) 46 | assert b"Developer" in response.data 47 | assert b"Developer is a person that write software code" in response.data 48 | 49 | 50 | def test_request_profession_missing_name_error( 51 | client_flask_memory_app, 52 | fixture_profession_developer 53 | ): 54 | """ Test request example 55 | """ 56 | input_data = { 57 | "nam": fixture_profession_developer["name"], 58 | "description": fixture_profession_developer["description"] 59 | } 60 | response = client_flask_memory_app.post("/v1/profession/", json=input_data) 61 | assert b"Missing Profession Name" in response.data 62 | 63 | 64 | def test_request_profession_invalid_name_error( 65 | client_flask_memory_app, 66 | fixture_profession_developer 67 | ): 68 | """ Test request invalid name 69 | """ 70 | input_data = { 71 | "name": "Profession", 72 | "description": fixture_profession_developer["description"] 73 | } 74 | response = client_flask_memory_app.post("/v1/profession/", json=input_data) 75 | assert b"Name: Profession is not permitted" in response.data 76 | 77 | 78 | def test_request_profession_wrong_url_error( 79 | client_flask_memory_app, 80 | fixture_profession_developer 81 | ): 82 | """ Test request HTTPException error 83 | """ 84 | input_data = { 85 | "name": fixture_profession_developer["name"], 86 | "description": fixture_profession_developer["description"] 87 | } 88 | response = client_flask_memory_app.post("/v1/professio/", json=input_data) 89 | assert b"The requested URL was not found on the server" in response.data 90 | 91 | 92 | def test_request_profession_500_status_code( 93 | client_flask_memory_app, 94 | fixture_profession_developer, 95 | mocker 96 | ): 97 | """ Test handling of exception that should return a 500 status code 98 | """ 99 | blueprint_mock = mocker.patch.object( 100 | CreateProfessionController, 101 | "get_profession_info" 102 | ) 103 | blueprint_mock.side_effect = Exception('Unexpected error!') 104 | input_data = { 105 | "name": fixture_profession_developer["name"], 106 | "description": fixture_profession_developer["description"] 107 | } 108 | response = client_flask_memory_app.post("/v1/profession/", json=input_data) 109 | assert b'"status_code":500' in response.data 110 | -------------------------------------------------------------------------------- /src/app/flask_memory/interfaces/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_memory/interfaces/__init__.py -------------------------------------------------------------------------------- /src/app/flask_memory/interfaces/flask_memory_controller_interface.py: -------------------------------------------------------------------------------- 1 | """ This module contains the FlaskMemoryControllerInterface class 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class FlaskMemoryControllerInterface(ABC): 10 | """ This class is the interface for the Flask Memory Controller class 11 | """ 12 | 13 | def get_profession_info(self, json_input) -> None: 14 | """ Get Profession Info 15 | :param json_input: Input data 16 | :raises: ValueError if profession name or description are missing. 17 | """ 18 | 19 | @abstractmethod 20 | def execute(self) -> Dict: 21 | """ Executes the controller 22 | :returns: Profession created 23 | """ 24 | -------------------------------------------------------------------------------- /src/app/flask_memory/presenters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_memory/presenters/__init__.py -------------------------------------------------------------------------------- /src/app/flask_memory/presenters/create_profession_presenter.py: -------------------------------------------------------------------------------- 1 | """ Module for the CreateProfessionPresenter 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from src.interactor.dtos.create_profession_dtos \ 7 | import CreateProfessionOutputDto 8 | from src.interactor.interfaces.presenters.create_profession_presenter \ 9 | import CreateProfessionPresenterInterface 10 | 11 | 12 | class CreateProfessionPresenter(CreateProfessionPresenterInterface): 13 | """ Class for the CreateProfessionPresenter 14 | """ 15 | def present(self, output_dto: CreateProfessionOutputDto) -> Dict: 16 | """ Present the CreateProfession 17 | :param output_dto: CreateProfessionOutputDto 18 | :return: Dict 19 | """ 20 | return { 21 | "profession_id": output_dto.profession.profession_id, 22 | "name": output_dto.profession.name, 23 | "description": output_dto.profession.description 24 | } 25 | -------------------------------------------------------------------------------- /src/app/flask_memory/presenters/create_profession_presenter_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from src.interactor.dtos.create_profession_dtos \ 7 | import CreateProfessionOutputDto 8 | from src.domain.entities.profession import Profession 9 | from .create_profession_presenter import CreateProfessionPresenter 10 | 11 | 12 | def test_create_profession_presenter(fixture_profession_developer): 13 | profession = Profession( 14 | profession_id=fixture_profession_developer["profession_id"], 15 | name=fixture_profession_developer["name"], 16 | description=fixture_profession_developer["description"] 17 | ) 18 | output_dto = CreateProfessionOutputDto(profession) 19 | presenter = CreateProfessionPresenter() 20 | assert presenter.present(output_dto) == { 21 | "profession_id": fixture_profession_developer["profession_id"], 22 | "name": fixture_profession_developer["name"], 23 | "description": fixture_profession_developer["description"] 24 | } 25 | -------------------------------------------------------------------------------- /src/app/flask_postgresql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_postgresql/__init__.py -------------------------------------------------------------------------------- /src/app/flask_postgresql/blueprints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_postgresql/blueprints/__init__.py -------------------------------------------------------------------------------- /src/app/flask_postgresql/blueprints/create_profession_blueprint.py: -------------------------------------------------------------------------------- 1 | """ Flask PostgreSQL Blueprint Create Profession 2 | """ 3 | 4 | 5 | from flask import jsonify 6 | from flask import Blueprint, request, current_app 7 | from src.app.flask_postgresql.controllers.create_profession_controller import \ 8 | CreateProfessionController 9 | 10 | 11 | blueprint_create_profession = Blueprint('create_profession', __name__) 12 | 13 | 14 | @blueprint_create_profession.route('/profession/', methods=["POST"]) 15 | def create_profession_blueprint(): 16 | """ Create Profession Blueprint 17 | """ 18 | logger = current_app.config['logger'] 19 | input_json = request.get_json(force=True) 20 | controller = CreateProfessionController(logger) 21 | controller.get_profession_info(input_json) 22 | result = controller.execute() 23 | return jsonify(result), 201 24 | -------------------------------------------------------------------------------- /src/app/flask_postgresql/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_postgresql/controllers/__init__.py -------------------------------------------------------------------------------- /src/app/flask_postgresql/controllers/create_profession_controller.py: -------------------------------------------------------------------------------- 1 | """Create Profession Controller Module""" 2 | 3 | 4 | from typing import Dict 5 | from src.interactor.use_cases.create_profession import CreateProfessionUseCase 6 | from src.infra.repositories.profession_postgresql_repository \ 7 | import ProfessionPostgresqlRepository 8 | from src.interactor.dtos.create_profession_dtos import CreateProfessionInputDto 9 | from src.app.flask_postgresql.interfaces.flask_postgresql_controller_interface\ 10 | import FlaskPostgresqlControllerInterface 11 | from src.interactor.interfaces.logger.logger import LoggerInterface 12 | from src.app.flask_postgresql.presenters.create_profession_presenter import \ 13 | CreateProfessionPresenter 14 | 15 | 16 | class CreateProfessionController(FlaskPostgresqlControllerInterface): 17 | """ Create Profession Controller Class 18 | """ 19 | def __init__(self, logger: LoggerInterface): 20 | self.logger = logger 21 | self.input_dto: CreateProfessionInputDto 22 | 23 | def get_profession_info(self, json_input) -> None: 24 | """ Get Profession Info 25 | :param json_input: Input data 26 | :raises: ValueError if profession name or description are missing. 27 | """ 28 | if "name" in json_input: 29 | name = json_input["name"] 30 | else: 31 | raise ValueError("Missing Profession Name") 32 | if "description" in json_input: 33 | description = json_input["description"] 34 | else: 35 | raise ValueError("Missing Profession Description") 36 | self.input_dto = CreateProfessionInputDto(name, description) 37 | 38 | def execute(self) -> Dict: 39 | """ Execute the create profession controller 40 | :returns: Profession created 41 | """ 42 | repository = ProfessionPostgresqlRepository() 43 | presenter = CreateProfessionPresenter() 44 | use_case = CreateProfessionUseCase(presenter, repository, self.logger) 45 | result = use_case.execute(self.input_dto) 46 | return result 47 | -------------------------------------------------------------------------------- /src/app/flask_postgresql/controllers/create_profession_controller_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import pytest 7 | from unittest import mock 8 | from src.interactor.dtos.create_profession_dtos import CreateProfessionInputDto 9 | from src.interactor.interfaces.logger.logger import LoggerInterface 10 | 11 | with mock.patch( 12 | "sqlalchemy.create_engine" 13 | ) as mock_create_engine: 14 | from src.app.flask_postgresql.controllers.create_profession_controller \ 15 | import CreateProfessionController 16 | 17 | 18 | def test_create_profession(monkeypatch, mocker, fixture_profession_developer): 19 | name = fixture_profession_developer["name"] 20 | description = fixture_profession_developer["description"] 21 | fake_user_inputs = { 22 | "name": name, 23 | "description": description 24 | } 25 | monkeypatch.setattr('builtins.input', lambda _: next(fake_user_inputs)) 26 | 27 | mock_repository = mocker.patch( 28 | 'src.app.flask_postgresql.controllers.create_profession_controller.\ 29 | ProfessionPostgresqlRepository') 30 | mock_presenter = mocker.patch( 31 | 'src.app.flask_postgresql.controllers.create_profession_controller.\ 32 | CreateProfessionPresenter') 33 | mock_use_case = mocker.patch( 34 | 'src.app.flask_postgresql.controllers.create_profession_controller.\ 35 | CreateProfessionUseCase') 36 | mock_use_case_instance = mock_use_case.return_value 37 | logger_mock = mocker.patch.object( 38 | LoggerInterface, 39 | "log_info" 40 | ) 41 | result_use_case = { 42 | "profession_id": fixture_profession_developer["profession_id"], 43 | "name": fixture_profession_developer["name"], 44 | "description": fixture_profession_developer["description"] 45 | } 46 | mock_use_case_instance.execute.return_value = result_use_case 47 | 48 | controller = CreateProfessionController(logger_mock) 49 | controller.get_profession_info(fake_user_inputs) 50 | result = controller.execute() 51 | 52 | mock_repository.assert_called_once_with() 53 | mock_presenter.assert_called_once_with() 54 | mock_use_case.assert_called_once_with( 55 | mock_presenter.return_value, 56 | mock_repository.return_value, 57 | logger_mock 58 | ) 59 | input_dto = CreateProfessionInputDto(name, description) 60 | mock_use_case_instance.execute.assert_called_once_with(input_dto) 61 | assert result["name"] == name 62 | assert result["description"] == description 63 | 64 | # Test for missing inputs (name) 65 | fake_user_inputs = { 66 | "nam": name, 67 | "description": description 68 | } 69 | with pytest.raises(ValueError) as exception_info: 70 | controller.get_profession_info(fake_user_inputs) 71 | assert str(exception_info.value) == "Missing Profession Name" 72 | 73 | # Test for missing inputs (description) 74 | fake_user_inputs = { 75 | "name": name, 76 | "descriptio": description 77 | } 78 | with pytest.raises(ValueError) as exception_info: 79 | controller.get_profession_info(fake_user_inputs) 80 | assert str(exception_info.value) == "Missing Profession Description" 81 | -------------------------------------------------------------------------------- /src/app/flask_postgresql/create_flask_postgresql_app.py: -------------------------------------------------------------------------------- 1 | """ Main Flask PostgreSQL app 2 | """ 3 | 4 | 5 | from flask import Flask, g 6 | from werkzeug.exceptions import HTTPException 7 | from src.app.flask_postgresql.blueprints.create_profession_blueprint \ 8 | import blueprint_create_profession 9 | from src.interactor.interfaces.logger.logger import LoggerInterface 10 | from src.interactor.errors.error_classes \ 11 | import FieldValueNotPermittedException 12 | from src.infra.db_models.db_base import Session 13 | from src.interactor.errors.error_classes import UniqueViolationError 14 | 15 | 16 | def format_error_response( 17 | error: Exception, 18 | error_code: int, 19 | logger: LoggerInterface 20 | ): 21 | """ Format Error Response """ 22 | logger.log_exception(f"500 - Internal Server Error: {str(error)}") 23 | 24 | response = { 25 | 'status_code': error_code, 26 | 'error': error.__class__.__name__, 27 | 'message': str(error) 28 | } 29 | return response, error_code 30 | 31 | 32 | def create_flask_postgresql_app(logger: LoggerInterface): 33 | """ Create Main Flask PostgreSQL app 34 | """ 35 | app = Flask(__name__) 36 | app.config['logger'] = logger 37 | app.register_blueprint(blueprint_create_profession, url_prefix='/v1') 38 | 39 | @app.errorhandler(HTTPException) 40 | def handle_http_error(error: HTTPException): 41 | """ Handle HTTP Error Response """ 42 | logger.log_exception(str(error.__class__.__name__)) 43 | logger.log_exception(str(error.description)) 44 | response = { 45 | 'error': error.__class__.__name__, 46 | 'message': error.description, 47 | } 48 | return response, error.code 49 | 50 | @app.errorhandler(ValueError) 51 | def handle_value_error(error: ValueError): 52 | """ Handle Value Error Response """ 53 | return format_error_response(error, 400, logger) 54 | 55 | @app.errorhandler(FieldValueNotPermittedException) 56 | def handle_field_not_permitted_error( 57 | error: FieldValueNotPermittedException 58 | ): 59 | """ Handle Value Error Response """ 60 | return format_error_response(error, 400, logger) 61 | 62 | @app.errorhandler(UniqueViolationError) 63 | def handle_unique_violation_error(error: UniqueViolationError): 64 | """ Handle Unique Violation Error Response """ 65 | return format_error_response(error, 409, logger) 66 | 67 | @app.errorhandler(Exception) 68 | def handle_general_exception(error): 69 | """ Handle Other Errors Response """ 70 | return format_error_response(error, 500, logger) 71 | 72 | @app.before_request 73 | def before_request(): 74 | """ Before Request """ 75 | g.db = Session() 76 | 77 | @app.teardown_request 78 | def teardown_request(_unused=False): 79 | """ After Request """ 80 | dbc = getattr(g, 'db', None) 81 | if dbc is not None: 82 | dbc.close() 83 | 84 | return app 85 | -------------------------------------------------------------------------------- /src/app/flask_postgresql/interfaces/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_postgresql/interfaces/__init__.py -------------------------------------------------------------------------------- /src/app/flask_postgresql/interfaces/flask_postgresql_controller_interface.py: -------------------------------------------------------------------------------- 1 | """ This module contains the FlaskPostgresqlControllerInterface class 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from abc import ABC, abstractmethod 7 | 8 | 9 | class FlaskPostgresqlControllerInterface(ABC): 10 | """ This class is the interface for the Flask Postgresql Controller class 11 | """ 12 | 13 | def get_profession_info(self, json_input) -> None: 14 | """ Get Profession Info 15 | :param json_input: Input data 16 | :raises: ValueError if profession name or description are missing. 17 | """ 18 | 19 | @abstractmethod 20 | def execute(self) -> Dict: 21 | """ Executes the controller 22 | :returns: Profession created 23 | """ 24 | -------------------------------------------------------------------------------- /src/app/flask_postgresql/presenters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/app/flask_postgresql/presenters/__init__.py -------------------------------------------------------------------------------- /src/app/flask_postgresql/presenters/create_profession_presenter.py: -------------------------------------------------------------------------------- 1 | """ Module for the CreateProfessionPresenter 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from src.interactor.dtos.create_profession_dtos \ 7 | import CreateProfessionOutputDto 8 | from src.interactor.interfaces.presenters.create_profession_presenter \ 9 | import CreateProfessionPresenterInterface 10 | 11 | 12 | class CreateProfessionPresenter(CreateProfessionPresenterInterface): 13 | """ Class for the CreateProfessionPresenter 14 | """ 15 | def present(self, output_dto: CreateProfessionOutputDto) -> Dict: 16 | """ Present the CreateProfession 17 | :param output_dto: CreateProfessionOutputDto 18 | :return: Dict 19 | """ 20 | return { 21 | "profession_id": output_dto.profession.profession_id, 22 | "name": output_dto.profession.name, 23 | "description": output_dto.profession.description 24 | } 25 | -------------------------------------------------------------------------------- /src/app/flask_postgresql/presenters/create_profession_presenter_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from src.interactor.dtos.create_profession_dtos \ 7 | import CreateProfessionOutputDto 8 | from src.domain.entities.profession import Profession 9 | from .create_profession_presenter import CreateProfessionPresenter 10 | 11 | 12 | def test_create_profession_presenter(fixture_profession_developer): 13 | profession = Profession( 14 | profession_id=fixture_profession_developer["profession_id"], 15 | name=fixture_profession_developer["name"], 16 | description=fixture_profession_developer["description"] 17 | ) 18 | output_dto = CreateProfessionOutputDto(profession) 19 | presenter = CreateProfessionPresenter() 20 | assert presenter.present(output_dto) == { 21 | "profession_id": fixture_profession_developer["profession_id"], 22 | "name": fixture_profession_developer["name"], 23 | "description": fixture_profession_developer["description"] 24 | } 25 | -------------------------------------------------------------------------------- /src/conftest.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import uuid 7 | import pytest 8 | 9 | 10 | @pytest.fixture 11 | def fixture_profession_developer(): 12 | """ Fixture with Profession example """ 13 | return { 14 | "profession_id": uuid.uuid4(), 15 | "name": "Developer - Test", 16 | "description": "Developer is a person that write software code. This \ 17 | professional needs to know at least one programming language." 18 | } 19 | -------------------------------------------------------------------------------- /src/domain/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/domain/__init__.py -------------------------------------------------------------------------------- /src/domain/entities/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/domain/entities/__init__.py -------------------------------------------------------------------------------- /src/domain/entities/profession.py: -------------------------------------------------------------------------------- 1 | """ This module has definition of the Profession entity 2 | """ 3 | 4 | 5 | from dataclasses import dataclass, asdict 6 | from src.domain.value_objects import ProfessionId 7 | 8 | 9 | @dataclass 10 | class Profession: 11 | """ Definition of the Profession entity 12 | """ 13 | profession_id: ProfessionId 14 | name: str 15 | description: str 16 | 17 | @classmethod 18 | def from_dict(cls, data): 19 | """ Convert data from a dictionary 20 | """ 21 | return cls(**data) 22 | 23 | def to_dict(self): 24 | """ Convert data into dictionary 25 | """ 26 | return asdict(self) 27 | -------------------------------------------------------------------------------- /src/domain/entities/profession_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from .profession import Profession 7 | 8 | 9 | def test_profession_creation(fixture_profession_developer): 10 | profession = Profession( 11 | profession_id=fixture_profession_developer["profession_id"], 12 | name=fixture_profession_developer["name"], 13 | description=fixture_profession_developer["description"] 14 | ) 15 | assert profession.name == fixture_profession_developer["name"] 16 | assert (profession.description 17 | == fixture_profession_developer["description"]) 18 | 19 | 20 | def test_profession_from_dict(fixture_profession_developer): 21 | profession = Profession.from_dict(fixture_profession_developer) 22 | assert profession.name == fixture_profession_developer["name"] 23 | assert (profession.description 24 | == fixture_profession_developer["description"]) 25 | 26 | 27 | def test_profession_to_dict(fixture_profession_developer): 28 | profession = Profession.from_dict(fixture_profession_developer) 29 | assert profession.to_dict() == fixture_profession_developer 30 | 31 | 32 | def test_profession_comparison(fixture_profession_developer): 33 | profession_1 = Profession.from_dict(fixture_profession_developer) 34 | profession_2 = Profession.from_dict(fixture_profession_developer) 35 | assert profession_1 == profession_2 36 | -------------------------------------------------------------------------------- /src/domain/value_objects.py: -------------------------------------------------------------------------------- 1 | """ Module for Value Objects 2 | """ 3 | 4 | 5 | import uuid 6 | 7 | 8 | ProfessionId = uuid.UUID 9 | -------------------------------------------------------------------------------- /src/infra/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/infra/__init__.py -------------------------------------------------------------------------------- /src/infra/db_models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/infra/db_models/__init__.py -------------------------------------------------------------------------------- /src/infra/db_models/db_base.py: -------------------------------------------------------------------------------- 1 | """ Base class for all models 2 | """ 3 | 4 | 5 | from sqlalchemy.orm import DeclarativeBase, sessionmaker, scoped_session 6 | from sqlalchemy import create_engine 7 | from configs import config 8 | 9 | 10 | class Base(DeclarativeBase): 11 | """ Base class for all models 12 | """ 13 | 14 | 15 | engine = create_engine(config.DB_URI) 16 | Session = scoped_session(sessionmaker(bind=engine)) 17 | -------------------------------------------------------------------------------- /src/infra/db_models/profession_db_model.py: -------------------------------------------------------------------------------- 1 | """ Defines the professions database model. 2 | """ 3 | 4 | 5 | import uuid 6 | from sqlalchemy import String 7 | from sqlalchemy.orm import Mapped, mapped_column 8 | from sqlalchemy.dialects.postgresql import UUID 9 | from src.infra.db_models.db_base import Base 10 | 11 | 12 | class ProfessionsDBModel(Base): 13 | """ Defines the professions database model. 14 | """ 15 | 16 | __tablename__ = "professions" 17 | 18 | profession_id: Mapped[uuid.UUID] = \ 19 | mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) 20 | name: Mapped[str] = mapped_column(String(80), nullable=False, unique=True) 21 | description: Mapped[str] = mapped_column(String(200), nullable=False) 22 | -------------------------------------------------------------------------------- /src/infra/loggers/logger_default.py: -------------------------------------------------------------------------------- 1 | """ Module for LoggerDefault class.""" 2 | 3 | 4 | import logging 5 | from src.interactor.interfaces.logger.logger import LoggerInterface 6 | 7 | 8 | class LoggerDefault(LoggerInterface): 9 | """ LoggerDefault class. 10 | """ 11 | 12 | def __init__(self): 13 | logging.basicConfig( 14 | filename='app.log', 15 | filemode='a', 16 | datefmt='%Y-%m-%d %H:%M:%S', 17 | format='%(asctime)-s - %(levelname)s - %(message)s', 18 | level=logging.INFO 19 | ) 20 | 21 | def log_debug(self, message: str) -> None: 22 | """ Log debug message. 23 | :param message: Message to log. 24 | """ 25 | logging.debug(message) 26 | 27 | def log_info(self, message: str) -> None: 28 | """ Log info message. 29 | :param message: Message to log. 30 | """ 31 | logging.info(message) 32 | 33 | def log_warning(self, message: str) -> None: 34 | """ Log warning message. 35 | :param message: Message to log. 36 | """ 37 | logging.warning(message) 38 | 39 | def log_error(self, message: str) -> None: 40 | """ Log error message. 41 | :param message: Message to log. 42 | """ 43 | logging.error(message) 44 | 45 | def log_critical(self, message: str) -> None: 46 | """ Log critical message. 47 | :param message: Message to log. 48 | """ 49 | logging.critical(message) 50 | 51 | def log_exception(self, message: str) -> None: 52 | """ Log exception message with exception info. 53 | :param message: Message to log. 54 | """ 55 | logging.exception(message) 56 | -------------------------------------------------------------------------------- /src/infra/loggers/logger_default_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import logging 7 | from src.infra.loggers.logger_default import LoggerDefault 8 | 9 | 10 | def test_logger_default(mocker): 11 | mocker.patch.object(logging, 'debug') 12 | logger = LoggerDefault() 13 | logger.log_debug('testdebug') 14 | logging.debug.assert_called_once_with('testdebug') # pylint: disable=E1101 15 | 16 | mocker.patch.object(logging, 'info') 17 | logger = LoggerDefault() 18 | logger.log_info('testinfo') 19 | logging.info.assert_called_once_with('testinfo') # pylint: disable=E1101 20 | 21 | mocker.patch.object(logging, 'warning') 22 | logger = LoggerDefault() 23 | logger.log_warning('tstwarn') 24 | logging.warning.assert_called_once_with('tstwarn') # pylint: disable=E1101 25 | 26 | mocker.patch.object(logging, 'error') 27 | logger = LoggerDefault() 28 | logger.log_error('testerror') 29 | logging.error.assert_called_once_with('testerror') # pylint: disable=E1101 30 | 31 | mocker.patch.object(logging, 'critical') 32 | logger = LoggerDefault() 33 | logger.log_critical('tcrit') 34 | logging.critical.assert_called_once_with('tcrit') # pylint: disable=E1101 35 | 36 | mocker.patch.object(logging, 'exception') 37 | logger = LoggerDefault() 38 | logger.log_exception('texce') 39 | logging.exception.assert_called_once_with('texce') # pylint: disable=E1101 40 | -------------------------------------------------------------------------------- /src/infra/repositories/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/infra/repositories/__init__.py -------------------------------------------------------------------------------- /src/infra/repositories/profession_in_memory_repository.py: -------------------------------------------------------------------------------- 1 | """ Module for ProfessionInMemoryRepository 2 | """ 3 | 4 | 5 | from typing import Dict 6 | import copy 7 | import uuid 8 | from src.domain.entities.profession import Profession 9 | from src.interactor.interfaces.repositories.profession_repository \ 10 | import ProfessionRepositoryInterface 11 | from src.domain.value_objects import ProfessionId 12 | 13 | 14 | class ProfessionInMemoryRepository(ProfessionRepositoryInterface): 15 | """ InMemory Repository for Profession 16 | """ 17 | def __init__(self) -> None: 18 | self._data: Dict[ProfessionId, Profession] = {} 19 | 20 | def get(self, profession_id: ProfessionId) -> Profession: 21 | """ Get Profession by id 22 | 23 | :param profession_id: ProfessionId 24 | :return: Profession 25 | """ 26 | return copy.deepcopy(self._data[profession_id]) 27 | 28 | def create(self, name: str, description: str) -> Profession: 29 | profession = Profession( 30 | profession_id=uuid.uuid4(), 31 | name=name, 32 | description=description 33 | ) 34 | self._data[profession.profession_id] = copy.deepcopy(profession) 35 | return copy.deepcopy(self._data[profession.profession_id]) 36 | 37 | def update(self, profession: Profession) -> Profession: 38 | self._data[profession.profession_id] = copy.deepcopy(profession) 39 | return copy.deepcopy(self._data[profession.profession_id]) 40 | -------------------------------------------------------------------------------- /src/infra/repositories/profession_in_memory_repository_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from src.domain.entities.profession import Profession 7 | from .profession_in_memory_repository import ProfessionInMemoryRepository 8 | 9 | 10 | def test_profession_in_memory_repository(fixture_profession_developer): 11 | repository = ProfessionInMemoryRepository() 12 | profession = repository.create( 13 | fixture_profession_developer["name"], 14 | fixture_profession_developer["description"] 15 | ) 16 | response = repository.get(profession.profession_id) 17 | assert response.name == fixture_profession_developer["name"] 18 | assert response.description == fixture_profession_developer["description"] 19 | new_profession = Profession( 20 | profession.profession_id, 21 | "new name", 22 | "new description" 23 | ) 24 | response_update = repository.update(new_profession) 25 | assert response_update.name == "new name" 26 | assert response_update.description == "new description" 27 | -------------------------------------------------------------------------------- /src/infra/repositories/profession_postgresql_repository.py: -------------------------------------------------------------------------------- 1 | """ Module for ProfessionPostgresqlRepository 2 | """ 3 | 4 | from typing import Optional 5 | import uuid 6 | from sqlalchemy.exc import IntegrityError 7 | from src.domain.entities.profession import Profession 8 | from src.interactor.interfaces.repositories.profession_repository \ 9 | import ProfessionRepositoryInterface 10 | from src.domain.value_objects import ProfessionId 11 | from src.infra.db_models.db_base import Session 12 | from src.infra.db_models.profession_db_model import ProfessionsDBModel 13 | from src.interactor.errors.error_classes import UniqueViolationError 14 | 15 | 16 | class ProfessionPostgresqlRepository(ProfessionRepositoryInterface): 17 | """ Postgresql Repository for Profession 18 | """ 19 | def __init__(self) -> None: 20 | self.__session = Session 21 | 22 | def __db_to_entity( 23 | self, db_row: ProfessionsDBModel 24 | ) -> Optional[Profession]: 25 | return Profession( 26 | profession_id=db_row.profession_id, 27 | name=db_row.name, 28 | description=db_row.description 29 | ) 30 | 31 | def create(self, name: str, description: str) -> Optional[Profession]: 32 | """ Create Profession 33 | :param name: str 34 | :param description: str 35 | :return: Optional[Profession] 36 | """ 37 | profession_id = uuid.uuid4() 38 | profession_db_model = ProfessionsDBModel( 39 | profession_id=profession_id, 40 | name=name, 41 | description=description 42 | ) 43 | 44 | try: 45 | self.__session.add(profession_db_model) 46 | self.__session.commit() 47 | self.__session.refresh(profession_db_model) 48 | except IntegrityError as exception: 49 | if "violates unique constraint" in str(exception.orig): 50 | raise UniqueViolationError( 51 | "Profession with the same name already exists" 52 | ) from exception 53 | raise 54 | 55 | if profession_db_model is not None: 56 | return self.__db_to_entity(profession_db_model) 57 | return None 58 | 59 | def get(self, profession_id: ProfessionId) -> Optional[Profession]: 60 | """ Get Profession by id 61 | :param profession_id: ProfessionId 62 | :return: Optional[Profession] 63 | """ 64 | result = self.__session.query(ProfessionsDBModel).get(profession_id) 65 | if result is not None: 66 | return self.__db_to_entity(result) 67 | return None 68 | 69 | def update(self, profession: Profession) -> Optional[Profession]: 70 | """ Update Profession 71 | :param profession: Profession 72 | :return: Optional[Profession] 73 | """ 74 | profession_db_model = ProfessionsDBModel( 75 | profession_id=profession.profession_id, 76 | name=profession.name, 77 | description=profession.description 78 | ) 79 | result = self.__session.query( 80 | ProfessionsDBModel 81 | ).filter_by( 82 | profession_id=profession.profession_id 83 | ).update( 84 | { 85 | "name": profession.name, 86 | "description": profession.description 87 | } 88 | ) 89 | if result == 0: 90 | return None 91 | self.__session.commit() 92 | return self.__db_to_entity(profession_db_model) 93 | -------------------------------------------------------------------------------- /src/interactor/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/__init__.py -------------------------------------------------------------------------------- /src/interactor/dtos/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/dtos/__init__.py -------------------------------------------------------------------------------- /src/interactor/dtos/create_profession_dtos.py: -------------------------------------------------------------------------------- 1 | """ Module for CreateProfession Dtos 2 | """ 3 | 4 | 5 | from dataclasses import dataclass, asdict 6 | from src.domain.entities.profession import Profession 7 | 8 | 9 | @dataclass 10 | class CreateProfessionInputDto: 11 | """ Input Dto for create profession """ 12 | name: str 13 | description: str 14 | 15 | def to_dict(self): 16 | """ Convert data into dictionary 17 | """ 18 | return asdict(self) 19 | 20 | 21 | @dataclass 22 | class CreateProfessionOutputDto: 23 | """ Output Dto for create profession """ 24 | profession: Profession 25 | -------------------------------------------------------------------------------- /src/interactor/dtos/create_profession_dtos_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from .create_profession_dtos import CreateProfessionInputDto 7 | 8 | 9 | def test_create_profession_input_dto_valid(fixture_profession_developer): 10 | input_dto = CreateProfessionInputDto( 11 | name=fixture_profession_developer["name"], 12 | description=fixture_profession_developer["description"] 13 | ) 14 | assert input_dto.name == fixture_profession_developer["name"] 15 | assert input_dto.description == fixture_profession_developer["description"] 16 | assert input_dto.to_dict() == { 17 | "name": fixture_profession_developer["name"], 18 | "description": fixture_profession_developer["description"] 19 | } 20 | -------------------------------------------------------------------------------- /src/interactor/errors/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/errors/__init__.py -------------------------------------------------------------------------------- /src/interactor/errors/error_classes.py: -------------------------------------------------------------------------------- 1 | """ This module contains exceptions for the Use Cases layer 2 | """ 3 | 4 | 5 | class FieldValueNotPermittedException(Exception): 6 | """ Exception raised when a field is empty """ 7 | def __init__(self, field_name: str, field_value: str) -> None: 8 | self.field_name = field_name 9 | self.field_value = field_value 10 | 11 | def __str__(self) -> str: 12 | return f"{self.field_name.capitalize()}: {self.field_value} is not \ 13 | permitted" 14 | 15 | 16 | class ItemNotCreatedException(Exception): 17 | """ Exception raised when an item is not created """ 18 | def __init__(self, item_name: str, item_type: str) -> None: 19 | self.item_name = item_name 20 | self.item_type = item_type 21 | 22 | def __str__(self) -> str: 23 | return f"{self.item_type.capitalize()} '{self.item_name}' was not \ 24 | created correctly" 25 | 26 | 27 | class UniqueViolationError(Exception): 28 | """ Exception raised when a unique constraint is violated """ 29 | -------------------------------------------------------------------------------- /src/interactor/errors/error_classes_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import pytest 7 | from src.interactor.errors.error_classes \ 8 | import FieldValueNotPermittedException 9 | from src.interactor.errors.error_classes import ItemNotCreatedException 10 | 11 | 12 | def test_empty_field_exception(): 13 | with pytest.raises(FieldValueNotPermittedException) as exception_info: 14 | raise FieldValueNotPermittedException("name", "Profession") 15 | assert str(exception_info.value) == "Name: Profession is not permitted" 16 | 17 | 18 | def test_item_not_created_exception(): 19 | with pytest.raises(ItemNotCreatedException) as exception_info: 20 | raise ItemNotCreatedException("profession name", "profession") 21 | assert str(exception_info.value) == \ 22 | "Profession 'profession name' was not created correctly" 23 | -------------------------------------------------------------------------------- /src/interactor/interfaces/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/interfaces/__init__.py -------------------------------------------------------------------------------- /src/interactor/interfaces/logger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/interfaces/logger/__init__.py -------------------------------------------------------------------------------- /src/interactor/interfaces/logger/logger.py: -------------------------------------------------------------------------------- 1 | """ Module provides a logger interface. 2 | """ 3 | 4 | 5 | from abc import ABC, abstractmethod 6 | 7 | 8 | class LoggerInterface(ABC): 9 | """ LoggerInterface class provides an interface for logging. 10 | """ 11 | 12 | @abstractmethod 13 | def log_debug(self, message: str) -> None: 14 | """ Log debug message. 15 | :param message: Message to log. 16 | """ 17 | 18 | @abstractmethod 19 | def log_info(self, message: str) -> None: 20 | """ Log info message. 21 | :param message: Message to log. 22 | """ 23 | 24 | @abstractmethod 25 | def log_warning(self, message: str) -> None: 26 | """ Log warning message. 27 | :param message: Message to log. 28 | """ 29 | 30 | @abstractmethod 31 | def log_error(self, message: str) -> None: 32 | """ Log error message. 33 | :param message: Message to log. 34 | """ 35 | 36 | @abstractmethod 37 | def log_critical(self, message: str) -> None: 38 | """ Log critical message. 39 | :param message: Message to log. 40 | """ 41 | 42 | @abstractmethod 43 | def log_exception(self, message: str) -> None: 44 | """ Log exception message with exception info. 45 | :param message: Message to log. 46 | """ 47 | -------------------------------------------------------------------------------- /src/interactor/interfaces/presenters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/interfaces/presenters/__init__.py -------------------------------------------------------------------------------- /src/interactor/interfaces/presenters/create_profession_presenter.py: -------------------------------------------------------------------------------- 1 | """ Module for the CreateProfessionPresenterInterface 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from abc import ABC, abstractmethod 7 | from src.interactor.dtos.create_profession_dtos \ 8 | import CreateProfessionOutputDto 9 | 10 | 11 | class CreateProfessionPresenterInterface(ABC): 12 | """ Class for the Interface of the ProfessionPresenter 13 | """ 14 | @abstractmethod 15 | def present(self, output_dto: CreateProfessionOutputDto) -> Dict: 16 | """ Present the Profession 17 | """ 18 | -------------------------------------------------------------------------------- /src/interactor/interfaces/repositories/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/interfaces/repositories/__init__.py -------------------------------------------------------------------------------- /src/interactor/interfaces/repositories/profession_repository.py: -------------------------------------------------------------------------------- 1 | """ This module contains the interface for the ProfessionRepository 2 | """ 3 | 4 | 5 | from abc import ABC, abstractmethod 6 | from typing import Optional 7 | from src.domain.value_objects import ProfessionId 8 | from src.domain.entities.profession import Profession 9 | 10 | 11 | class ProfessionRepositoryInterface(ABC): 12 | """ This class is the interface for the ProfessionRepository 13 | """ 14 | 15 | @abstractmethod 16 | def get(self, profession_id: ProfessionId) -> Optional[Profession]: 17 | """ Get a Profession by id 18 | 19 | :param profession_id: ProfessionId 20 | :return: Profession 21 | """ 22 | 23 | @abstractmethod 24 | def create(self, name: str, description: str) -> Optional[Profession]: 25 | """ Create a Profession 26 | 27 | :param name: Profession Name 28 | :param description: Profession Description 29 | :return: ProfessionId 30 | """ 31 | 32 | @abstractmethod 33 | def update(self, profession: Profession) -> Optional[Profession]: 34 | """ Save a Profession 35 | 36 | :param Profession: Profession 37 | :return: Profession 38 | """ 39 | -------------------------------------------------------------------------------- /src/interactor/use_cases/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/use_cases/__init__.py -------------------------------------------------------------------------------- /src/interactor/use_cases/create_profession.py: -------------------------------------------------------------------------------- 1 | """ This module is responsible for creating a new profession. 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from src.interactor.dtos.create_profession_dtos \ 7 | import CreateProfessionInputDto, CreateProfessionOutputDto 8 | from src.interactor.interfaces.presenters.create_profession_presenter \ 9 | import CreateProfessionPresenterInterface 10 | from src.interactor.interfaces.repositories.profession_repository \ 11 | import ProfessionRepositoryInterface 12 | from src.interactor.validations.create_profession_validator \ 13 | import CreateProfessionInputDtoValidator 14 | from src.interactor.interfaces.logger.logger import LoggerInterface 15 | from src.interactor.errors.error_classes import ItemNotCreatedException 16 | 17 | 18 | class CreateProfessionUseCase(): 19 | """ This class is responsible for creating a new profession. 20 | """ 21 | 22 | def __init__( 23 | self, 24 | presenter: CreateProfessionPresenterInterface, 25 | repository: ProfessionRepositoryInterface, 26 | logger: LoggerInterface 27 | ): 28 | self.presenter = presenter 29 | self.repository = repository 30 | self.logger = logger 31 | 32 | def execute( 33 | self, 34 | input_dto: CreateProfessionInputDto 35 | ) -> Dict: 36 | """ This method is responsible for creating a new profession. 37 | :param input_dto: The input data transfer object. 38 | :type input_dto: CreateProfessionInputDto 39 | :return: Dict 40 | """ 41 | 42 | validator = CreateProfessionInputDtoValidator(input_dto.to_dict()) 43 | validator.validate() 44 | profession = self.repository.create( 45 | input_dto.name, 46 | input_dto.description 47 | ) 48 | if profession is None: 49 | self.logger.log_exception("Profession creation failed") 50 | raise ItemNotCreatedException(input_dto.name, "Profession") 51 | output_dto = CreateProfessionOutputDto(profession) 52 | presenter_response = self.presenter.present(output_dto) 53 | self.logger.log_info("Profession created successfully") 54 | return presenter_response 55 | -------------------------------------------------------------------------------- /src/interactor/use_cases/create_profession_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import pytest 7 | from src.interactor.use_cases import create_profession 8 | from src.domain.entities.profession import Profession 9 | from src.interactor.dtos.create_profession_dtos \ 10 | import CreateProfessionInputDto, CreateProfessionOutputDto 11 | from src.interactor.interfaces.presenters.create_profession_presenter \ 12 | import CreateProfessionPresenterInterface 13 | from src.interactor.interfaces.repositories.profession_repository \ 14 | import ProfessionRepositoryInterface 15 | from src.interactor.interfaces.logger.logger import LoggerInterface 16 | from src.interactor.errors.error_classes import ItemNotCreatedException 17 | 18 | 19 | def test_create_profession(mocker, fixture_profession_developer): 20 | profession = Profession( 21 | profession_id=fixture_profession_developer["profession_id"], 22 | name=fixture_profession_developer["name"], 23 | description=fixture_profession_developer["description"] 24 | ) 25 | presenter_mock = mocker.patch.object( 26 | CreateProfessionPresenterInterface, 27 | "present" 28 | ) 29 | repository_mock = mocker.patch.object( 30 | ProfessionRepositoryInterface, 31 | "create" 32 | ) 33 | 34 | input_dto_validator_mock = mocker.patch( 35 | "src.interactor.use_cases.create_profession.\ 36 | CreateProfessionInputDtoValidator" 37 | ) 38 | logger_mock = mocker.patch.object( 39 | LoggerInterface, 40 | "log_info" 41 | ) 42 | repository_mock.create.return_value = profession 43 | presenter_mock.present.return_value = "Test output" 44 | use_case = create_profession.CreateProfessionUseCase( 45 | presenter_mock, 46 | repository_mock, 47 | logger_mock 48 | ) 49 | input_dto = CreateProfessionInputDto( 50 | name=fixture_profession_developer["name"], 51 | description=fixture_profession_developer["description"] 52 | ) 53 | result = use_case.execute(input_dto) 54 | repository_mock.create.assert_called_once() 55 | input_dto_validator_mock.assert_called_once_with(input_dto.to_dict()) 56 | input_dto_validator_instance = input_dto_validator_mock.return_value 57 | input_dto_validator_instance.validate.assert_called_once_with() 58 | logger_mock.log_info.assert_called_once_with( 59 | "Profession created successfully") 60 | output_dto = CreateProfessionOutputDto(profession) 61 | presenter_mock.present.assert_called_once_with(output_dto) 62 | assert result == "Test output" 63 | 64 | # Testing None return value from repository 65 | repository_mock.create.return_value = None 66 | profession_name = fixture_profession_developer["name"] 67 | with pytest.raises(ItemNotCreatedException) as exception_info: 68 | use_case.execute(input_dto) 69 | assert str(exception_info.value) == \ 70 | f"Profession '{profession_name}' was not created correctly" 71 | 72 | 73 | def test_create_profession_empty_field(mocker, fixture_profession_developer): 74 | presenter_mock = mocker.patch.object( 75 | CreateProfessionPresenterInterface, 76 | "present" 77 | ) 78 | repository_mock = mocker.patch.object( 79 | ProfessionRepositoryInterface, 80 | "create" 81 | ) 82 | logger_mock = mocker.patch.object( 83 | LoggerInterface, 84 | "log_info" 85 | ) 86 | use_case = create_profession.CreateProfessionUseCase( 87 | presenter_mock, 88 | repository_mock, 89 | logger_mock 90 | ) 91 | input_dto = CreateProfessionInputDto( 92 | name="", 93 | description=fixture_profession_developer["description"] 94 | ) 95 | with pytest.raises(ValueError) as exception_info: 96 | use_case.execute(input_dto) 97 | assert str(exception_info.value) == "Name: empty values not allowed" 98 | 99 | repository_mock.create.assert_not_called() 100 | presenter_mock.present.assert_not_called() 101 | -------------------------------------------------------------------------------- /src/interactor/validations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudiosw/python-clean-architecture-example/2050a235efe2d62a282fb6a11e8400ce1b65629f/src/interactor/validations/__init__.py -------------------------------------------------------------------------------- /src/interactor/validations/base_input_validator.py: -------------------------------------------------------------------------------- 1 | """ This module provides the base class BaseInputValidator for input validation 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from cerberus import Validator # type: ignore 7 | 8 | 9 | class BaseInputValidator: 10 | """ This class provides the base class for input validation 11 | """ 12 | def __init__(self, data: Dict[str, str]): 13 | self.data = data 14 | self.errors: Dict = {} 15 | 16 | def verify(self, schema: Dict) -> None: 17 | """ Validates the input data against the provided schema 18 | :param schema: The schema to validate against 19 | :return: None 20 | :raises ValueError: If the input data is invalid. 21 | """ 22 | validator = Validator(schema) 23 | if not validator.validate(self.data): 24 | self.errors = validator.errors 25 | self._raise_validation_error() 26 | 27 | def _raise_validation_error(self): 28 | error_messages = [] 29 | for field, messages in self.errors.items(): 30 | for message in messages: 31 | error_messages.append(f"{field.capitalize()}: {message}") 32 | raise ValueError("\n".join(error_messages)) 33 | -------------------------------------------------------------------------------- /src/interactor/validations/base_input_validator_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | from typing import Dict 7 | import pytest 8 | from src.interactor.validations.base_input_validator import BaseInputValidator 9 | 10 | 11 | class BaseValidator(BaseInputValidator): 12 | def __init__(self, data: Dict): 13 | super().__init__(data) 14 | self.schema = { 15 | "name": { 16 | "type": "string", 17 | "minlength": 3, 18 | "maxlength": 10, 19 | "required": True, 20 | "empty": False 21 | }, 22 | "description": { 23 | "type": "string", 24 | "minlength": 3, 25 | "maxlength": 10, 26 | "required": False, 27 | "empty": True 28 | } 29 | } 30 | 31 | def validate(self): 32 | super().verify(self.schema) 33 | 34 | 35 | def test_base_validator_with_valid_data(): 36 | data = {'name': 'test'} 37 | validator = BaseValidator(data) 38 | validator.validate() 39 | 40 | 41 | def test_base_validator_with_small_data(): 42 | data = {'name': 'a', 'description': 'a'} 43 | validator = BaseValidator(data) 44 | with pytest.raises(ValueError) as exception_info: 45 | validator.validate() 46 | assert str(exception_info.value) == "Description: min length is 3\n\ 47 | Name: min length is 3" 48 | 49 | 50 | def test_base_validator_with_long_data(): 51 | data = {'name': 'this is a long name'} 52 | validator = BaseValidator(data) 53 | with pytest.raises(ValueError) as exception_info: 54 | validator.validate() 55 | assert str(exception_info.value) == "Name: max length is 10" 56 | 57 | 58 | def test_base_validator_with_empty_data(): 59 | data = {'name': ''} 60 | validator = BaseValidator(data) 61 | with pytest.raises(ValueError) as exception_info: 62 | validator.validate() 63 | assert str(exception_info.value) == "Name: empty values not allowed" 64 | 65 | 66 | def test_base_validator_without_required_data(): 67 | data = {} 68 | validator = BaseValidator(data) 69 | with pytest.raises(ValueError) as exception_info: 70 | validator.validate() 71 | assert str(exception_info.value) == "Name: required field" 72 | -------------------------------------------------------------------------------- /src/interactor/validations/create_profession_validator.py: -------------------------------------------------------------------------------- 1 | """ Defines the validator for the create profession input data. 2 | """ 3 | 4 | 5 | from typing import Dict 6 | from src.interactor.validations.base_input_validator import BaseInputValidator 7 | from src.interactor.errors.error_classes import FieldValueNotPermittedException 8 | 9 | 10 | class CreateProfessionInputDtoValidator(BaseInputValidator): 11 | """ Validates the create profession input data. 12 | :param input_data: The input data to be validated. 13 | """ 14 | 15 | def __init__(self, input_data: Dict) -> None: 16 | super().__init__(input_data) 17 | self.input_data = input_data 18 | self.__schema = { 19 | "name": { 20 | "type": "string", 21 | "minlength": 3, 22 | "maxlength": 80, 23 | "required": True, 24 | "empty": False 25 | }, 26 | "description": { 27 | "type": "string", 28 | "minlength": 5, 29 | "maxlength": 200, 30 | "required": True, 31 | "empty": False 32 | } 33 | } 34 | 35 | def validate(self) -> None: 36 | """ Validates the input data 37 | """ 38 | # Verify the input data using BaseInputValidator method 39 | super().verify(self.__schema) 40 | # This is an example of a custom validation 41 | if self.input_data["name"] == "Profession": 42 | raise FieldValueNotPermittedException("name", "Profession") 43 | -------------------------------------------------------------------------------- /src/interactor/validations/create_profession_validator_test.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-module-docstring 2 | # pylint: disable=missing-class-docstring 3 | # pylint: disable=missing-function-docstring 4 | 5 | 6 | import pytest 7 | from src.interactor.validations.create_profession_validator \ 8 | import CreateProfessionInputDtoValidator 9 | from src.interactor.errors.error_classes import FieldValueNotPermittedException 10 | 11 | 12 | def test_create_profession_validator_valid_data( 13 | mocker, 14 | fixture_profession_developer 15 | ): 16 | mocker.patch("src.interactor.validations.base_input_validator.\ 17 | BaseInputValidator.verify") 18 | input_data = { 19 | "name": fixture_profession_developer["name"], 20 | "description": fixture_profession_developer["description"] 21 | } 22 | schema = { 23 | "name": { 24 | "type": "string", 25 | "minlength": 3, 26 | "maxlength": 80, 27 | "required": True, 28 | "empty": False 29 | }, 30 | "description": { 31 | "type": "string", 32 | "minlength": 5, 33 | "maxlength": 200, 34 | "required": True, 35 | "empty": False 36 | } 37 | } 38 | validator = CreateProfessionInputDtoValidator(input_data) 39 | validator.validate() 40 | validator.verify.assert_called_once_with(schema) # pylint: disable=E1101 41 | 42 | 43 | def test_create_profession_validator_empty_input(fixture_profession_developer): 44 | # We are doing just a simple test as the complete test is done in 45 | # base_input_validator_test.py 46 | input_data = { 47 | "name": fixture_profession_developer["name"], 48 | "description": "", 49 | } 50 | validator = CreateProfessionInputDtoValidator(input_data) 51 | with pytest.raises(ValueError) as exception_info: 52 | validator.validate() 53 | assert str(exception_info.value) == "Description: empty values not allowed" 54 | 55 | 56 | def test_create_profession_custom_validation(fixture_profession_developer): 57 | input_data = { 58 | "name": "Profession", 59 | "description": fixture_profession_developer["description"], 60 | } 61 | validator = CreateProfessionInputDtoValidator(input_data) 62 | with pytest.raises(FieldValueNotPermittedException) as exception_info: 63 | validator.validate() 64 | assert str(exception_info.value) == "Name: Profession is not permitted" 65 | --------------------------------------------------------------------------------