This repository serves as a professional-grade template for a modern Python project. It demonstrates a robust, component-based architecture by building the core components for an AI-powered email assistant that interacts with the Gmail API.
The project emphasizes a strict separation of concerns, dependency injection, and a comprehensive, automated toolchain to enforce code quality and best practices.
This project is built on the principle of "programming integrated over time." The architecture is designed to combat complexity and ensure the system is maintainable and evolvable.
- Component-Based Design: The system is broken down into four distinct, self-contained components. Each component has a single responsibility and can be "forklifted" out of this project to be used in another with minimal effort.
- Interface-Implementation Separation: Every piece of functionality is defined by an abstract protocol (the "what") and fulfilled by a concrete implementation (the "how"). This decouples our business logic from specific technologies (like Gmail).
- Dependency Injection: Implementations are "injected" into the abstract protocols at runtime. This means consumers of the API only ever depend on the stable interface, not the volatile implementation details.
The project is a uv
workspace containing four primary packages:
message
: Defines the abstractMessage
protocol. This is the contract for what an email message looks like.gmail_message_impl
: Provides theGmailMessage
class, a concrete implementation that knows how to parse raw data from the Gmail API into aMessage
object.mail_client_api
: Defines the abstractClient
protocol. This is the contract for what actions a mail client can perform (e.g.,get_messages
).gmail_client_impl
: Provides theGmailClient
class, a concrete implementation that uses the Google API to perform the actions defined in theClient
protocol.
ta-assignment/
├── src/ # Source packages (uv workspace members)
│ ├── message/ # Abstract message protocol
│ ├── gmail_message_impl/ # Gmail-specific message implementation
│ ├── mail_client_api/ # Abstract mail client protocol
│ └── gmail_client_impl/ # Gmail-specific client implementation
├── tests/ # Integration and E2E tests
│ ├── integration/ # Component integration tests
│ └── e2e/ # End-to-end application tests
├── docs/ # Documentation source files
├── .circleci/ # CircleCI configuration
├── main.py # Main application entry point
├── pyproject.toml # Project configuration (dependencies, tools)
├── uv.lock # Locked dependency versions
└── credentials.json # Google OAuth credentials (local only)
- Python 3.11 or higher
uv
– A fast, all-in-one Python package manager.
-
Install
uv
:# macOS / Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows (PowerShell) irm https://astral.sh/uv/install.ps1 | iex
-
Clone the Repository:
git clone <your-repository-url> cd ta-assignment
-
Set Up Google Credentials:
- Follow the Google Cloud instructions to enable the Gmail API and download your OAuth 2.0 credentials.
- Rename the downloaded file to
credentials.json
and place it in the root of this project. - Alternative: For CI/CD environments, you can use environment variables instead:
export GMAIL_CLIENT_ID="your_client_id" export GMAIL_CLIENT_SECRET="your_client_secret" export GMAIL_REFRESH_TOKEN="your_refresh_token"
- Important: Credential files contain secrets and are ignored by
.gitignore
.
-
Create and Sync the Virtual Environment: This single command creates a
.venv
folder and installs all packages (including workspace members and development tools) defined inuv.lock
.uv sync --all-packages --extra dev
-
Activate the Virtual Environment:
# macOS / Linux source .venv/bin/activate # Windows (PowerShell) .venv\Scripts\Activate.ps1
-
Perform Initial Authentication: Run the main application once to perform the interactive OAuth flow. This will open a browser window for you to grant permission.
uv run python main.py
After you approve, a
token.json
file will be created. This file is also ignored by.gitignore
and will be used for authentication in subsequent runs.
All commands should be run from the project root with the virtual environment activated.
To run the main demonstration script:
uv run python main.py
-
Linting & Formatting (Ruff): The project uses Ruff with comprehensive rules configured in
pyproject.toml
.# Check for issues uv run ruff check . # Automatically fix issues uv run ruff check . --fix # Check formatting uv run ruff format --check . # Apply formatting uv run ruff format .
-
Static Type Checking (MyPy):
uv run mypy src tests
-
Testing (Pytest):
I'd recommend only running:
uv run pytest src/ tests/ -m "not local_credentials" -v
for simplicity.The project uses a comprehensive testing strategy with different test categories.
# Run all tests (includes unit, integration, and e2e tests) uv run pytest # Run only unit tests (fast, no external dependencies - from src/ directories) uv run pytest src/ # Run all tests except those requiring local credential files uv run pytest src/ tests/ -m "not local_credentials" # Run only integration tests (requires environment variables or credentials) uv run pytest -m integration # Run only end-to-end tests (requires credentials) uv run pytest -m e2e # Run only CircleCI-compatible tests (CI/CD environment) uv run pytest -m circleci # Run tests with coverage reporting uv run pytest --cov=src --cov-report=term-missing
This project uses MkDocs for documentation.
# Start the live-reloading documentation server
uv run mkdocs serve
Open your browser to http://127.0.0.1:8000
to view the site.
The project implements a sophisticated testing strategy designed for both local development and CI/CD environments:
- Unit Tests (
src/*/tests/
): Fast, isolated tests with mocked dependencies - Integration Tests (
tests/integration/
): Tests that verify component interactions - End-to-End Tests (
tests/e2e/
): Full application workflow tests - CircleCI Tests: CI/CD-compatible tests that handle missing credentials gracefully
- Local Credentials Tests: Tests that require
credentials.json
ortoken.json
files
The project uses pytest markers to categorize tests:
@pytest.mark.unit # Fast unit tests
@pytest.mark.integration # Integration tests
@pytest.mark.e2e # End-to-end tests
@pytest.mark.circleci # CI/CD compatible
@pytest.mark.local_credentials # Requires local auth files
The testing infrastructure handles different authentication scenarios:
- Local Development: Uses
credentials.json
andtoken.json
files - CI/CD Environment: Uses environment variables (
GMAIL_CLIENT_ID
,GMAIL_CLIENT_SECRET
,GMAIL_REFRESH_TOKEN
) - Missing Credentials: Tests fail fast with clear error messages (no hanging)
The project includes a comprehensive CircleCI configuration (.circleci/config.yml
) with:
- All Branches: Unit tests, linting, and CI-compatible tests
- Main/Develop: Additional integration tests with real Gmail API calls
- Artifacts: Coverage reports, test results, and build summaries
See docs/circleci-setup.md
for detailed CI/CD setup instructions.
- Install dependencies:
uv sync --all-packages --extra dev
- Run tests:
uv run pytest tests/ -v
oruv run pytest src/ tests/ -m "not local_credentials" -v
- Check code quality:
uv run ruff check . && uv run ruff format --check .
- Fix formatting:
uv run ruff format .
- View documentation:
uv run mkdocs serve
- Run unit tests (
uv run pytest src/
) during development for fast feedback - Use integration tests (
uv run pytest -m integration
) to verify component interactions - Run full test suite (
uv run pytest
) before pushing to ensure CI compatibility - The CircleCI pipeline provides automated validation on every push