Architecture Patterns with Python Example Code
repository·master·Indexed 25 days ago
https://github.com/cosmicpython/codeExample application code for the 'Architecture Patterns with Python' book. The repository demonstrates various architectural patterns through incremental, chapter-based development using Git branches. It includes a Flask API, SQLAlchemy persistence, and a message bus, with support for Docker and Python 3.8 environments.
What's inside cosmicpython-code
- This repository contains example application code for the book 'Architecture Patterns with Python'. The code is organized by chapters and exercises using Git branches. Each chapter branch represents the state of the code at the end of that chapter. To code along with a chapter, check out the branch for the previous chapter.
Run tests
masterYou can run the test suite using the Makefile or directly via
pytestif you are using a local virtual environment. The tests are categorized into unit, integration, and end-to-end (e2e) tests.# Using Makefile make test # or individual types: make unit-tests make integration-tests make e2e-tests # Using local virtualenv make up pytest tests/unit pytest tests/integration pytest tests/e2eSet up the project using Docker
masterFrom chapter 3 onwards, you can use Docker and Docker Compose to run the application. Use the provided Makefile to build and start the containers.
Requirements:
- Docker with
docker-compose
make build make up # or make all # builds, brings containers up, runs tests- Docker with
Set up a local Python virtual environment
masterYou can optionally use a local Python 3.8 virtual environment instead of Docker. The required dependencies vary depending on which chapter you are working on.
Requirements:
- Python 3.8
Run the Redis event consumer entrypoint
masterThe
redis_eventconsumer.pyscript serves as an entrypoint for an event-driven consumer that listens to Redis Pub/Sub channels. It subscribes to thechange_batch_quantitychannel and processes incoming messages by converting them intoChangeBatchQuantitycommands, which are then dispatched via the application's command bus.To use this entrypoint, ensure that:
- A Redis instance is running and accessible via the configuration provided by
allocation.config.get_redis_host_and_port(). - The
allocationpackage is installed and configured. - Messages published to the
change_batch_quantitychannel follow the expected JSON format:{"batchref": <string>, "qty": <number>}.
- A Redis instance is running and accessible via the configuration provided by
Configure Email service connection details
masterThe
get_email_host_and_port()function returns a dictionary containing connection details for the email service. It uses the following environment variable:EMAIL_HOST: The email host (defaults tolocalhost).
Note: If
EMAIL_HOSTis set tolocalhost, theportdefaults to11025and thehttp_portdefaults to18025. For any other host,portdefaults to1025andhttp_portdefaults to8025.Configure Redis connection details
masterThe
get_redis_host_and_port()function returns a dictionary containing the Redis connection parameters. It uses the following environment variable:REDIS_HOST: The Redis host (defaults tolocalhost).
Note: If
REDIS_HOSTis set tolocalhost, the port defaults to63791. For any other host, it defaults to6379.Configure PostgreSQL connection URI
masterThe
get_postgres_uri()function constructs a PostgreSQL connection string. It uses the following environment variables:DB_HOST: The database host (defaults tolocalhost).DB_PASSWORD: The database password (defaults toabc123).
Note: If
DB_HOSTis set tolocalhost, the port defaults to54321. For any other host, it defaults to5432. The username is fixed asallocationand the database name is fixed asallocation.Configure the application environment via docker-compose.yml
masterThe project uses Docker Compose to orchestrate several services:
api,redis_pubsub,postgres,redis, andmailhog.Service Environment Variables
When running the services, the following environment variables are used to configure connectivity and behavior:
For
apiandredis_pubsubservices:DB_HOST: Hostname for the PostgreSQL database (default:postgres).DB_PASSWORD: Password for the database (default:abc123).REDIS_HOST: Hostname for the Redis instance (default:redis).EMAIL_HOST: Hostname for the MailHog instance (default:mailhog).PYTHONDONTWRITEBYTECODE: Set to1to prevent Python from writing.pycfiles.
Specific to
apiservice:API_HOST: Hostname for the API (default:api).FLASK_APP: Path to the Flask application entrypoint (default:allocation/entrypoints/flask_app.py).FLASK_DEBUG: Set to1to enable Flask debug mode.PYTHONUNBUFFERED: Set to1to ensure logs are sent to stdout/stderr immediately.
Specific to
postgresservice:POSTGRES_USER: Username for the database (default:allocation).POSTGRES_PASSWORD: Password for the database (default:abc123).
Configure API URL
masterThe
get_api_url()function constructs the base URL for the API. It uses the following environment variable:API_HOST: The API host (defaults tolocalhost).
Note: If
API_HOSTis set tolocalhost, the port defaults to5005. For any other host, it defaults to80.Implement the Unit of Work pattern with AbstractUnitOfWork
masterThe
AbstractUnitOfWorkdefines the interface for managing transaction boundaries and coordinating multiple repositories. It provides a context manager interface and a method to collect domain events from repositories.Key methods:
__enter__: Starts the transaction context.__exit__: Automatically callsrollback()if an exception occurs.commit(): Triggers the internal_commit()method to persist changes.collect_new_events(): A generator that yields domain events from all products currently tracked by theproductsrepository.
Use SqlAlchemyRepository for SQLAlchemy persistence
masterTheSqlAlchemyRepositoryis a concrete implementation ofAbstractRepositorydesigned to work with a SQLAlchemy session. It provides implementations for adding products and retrieving them by SKU or batch reference using SQLAlchemy queries.