Skip to content

Commit a5bb606

Browse files
authored
Caching, Testing, and Documentation Updates (#19)
* Caching, Testing, and Documentation Updates * Fix CLI tests with certain options
1 parent b471ac1 commit a5bb606

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+11544
-120
lines changed

.github/workflows/test.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
test-template:
1111
runs-on: ubuntu-latest
1212
strategy:
13+
fail-fast: false
1314
matrix:
1415
config-file:
1516
- full.yaml
@@ -25,9 +26,36 @@ jobs:
2526
with:
2627
python-version: "3.x"
2728

29+
- name: Install yq
30+
run: |
31+
sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
32+
sudo chmod +x /usr/local/bin/yq
33+
2834
- name: Install cookiecutter
2935
run: pip install cookiecutter
3036

3137
- name: Run cookiecutter template
3238
run: |
3339
cookiecutter . --no-input --config-file tests/${{ matrix.config-file }} --output-dir /tmp
40+
41+
- name: Get project name
42+
id: project
43+
run: |
44+
PROJECT_NAME=$(yq -r '.default_context.package_name' tests/${{ matrix.config-file }})
45+
echo "name=$PROJECT_NAME" >> $GITHUB_OUTPUT
46+
47+
- name: Run pytest
48+
working-directory: /tmp/${{ steps.project.outputs.name }}
49+
run: make pytest
50+
51+
- name: Run ruff check
52+
working-directory: /tmp/${{ steps.project.outputs.name }}
53+
run: make ruff_check
54+
55+
- name: Run black format check
56+
working-directory: /tmp/${{ steps.project.outputs.name }}
57+
run: make black_check
58+
59+
- name: Run mypy
60+
working-directory: /tmp/${{ steps.project.outputs.name }}
61+
run: make mypy_check

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
workspaces/

AGENTS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Agent Instructions
2+
3+
This project is a CookieCutter template used to generate new python projects. It is extremely dynamic, with many optional settings. Make sure to review the README.md to get more context, as well as the AGENTS.md file int he project template itself (`{{cookiecutter.__package_slug}}/AGENTS.md`).
4+
5+
Since this is a Cookiecutter template you should expect to encounter Jinja2 template blocks in various files.
6+
7+
When being asked to test functionality that requires you to create a new project from the template create them in the `workspaces` directory.
8+
9+
When creating new files for optional services make sure you include them in the post_gen_project.py configuration so that unneeded files are removed. For example, if the caching functionality is not enabled the system should remove all of the caching related files.

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ Pick and choose the features you need. Unused components are completely removed
8686
- Type-safe configuration using Pydantic for automatic validation of input data, with configurable queue sizes, worker counts, and graceful shutdown handling
8787
- Perfect for CPU-intensive workloads like data processing, image manipulation, scientific computing, and batch operations that need to scale beyond single-threaded execution
8888

89+
### Caching
90+
91+
**[aiocache](https://aiocache.readthedocs.io/) Integration**
92+
93+
- High-performance async caching library with support for multiple backends including Redis, Memcached, and in-memory storage, providing millisecond-level response times for frequently accessed data
94+
- Automatic cache configuration and connection management with separate cache instances for different TTL requirements: default (5 minutes), persistent (1 hour), and custom durations for specific use cases
95+
- Decorator-based caching with `@cached` for effortless function result memoization, automatically serializing complex Python objects including Pydantic models, dataclasses, and custom types
96+
- Built-in cache warming on application startup for Celery workers and web servers, pre-populating critical data to eliminate cold-start latency and ensure consistent performance from the first request
97+
- Type-safe settings configuration for cache behavior including host, port, TTL values, and enable/disable flags, with automatic validation and clear error messages for misconfigurations
98+
- Production-ready Redis integration with connection pooling, automatic reconnection handling, and graceful degradation when cache is unavailable, preventing cascading failures
99+
89100
### Database & ORM
90101

91102
**[SQLAlchemy](https://www.sqlalchemy.org/) + [Alembic](https://alembic.sqlalchemy.org/en/latest/)**
@@ -156,6 +167,7 @@ Every generated project includes documentation tailored to your selected feature
156167
- **Developer Guide Hub**: Organized documentation index in `docs/dev/` with dedicated guides for each enabled feature
157168
- **FastAPI Documentation**: Integration guide covering static file serving, Docker configuration, and FastAPI dependency system usage
158169
- **Database Documentation**: SQLAlchemy and Alembic guide covering model organization, migration creation using Make commands, FastAPI integration, and automatic schema diagram generation with Paracelsus
170+
- **Caching Documentation**: aiocache integration guide covering cache configuration, decorator usage, multiple TTL strategies, and cache warming for optimal performance
159171
- **Task Processing Guides**: Documentation for Celery (worker and beat configuration, Docker setup) and QuasiQueue (configuration file location, Docker images)
160172
- **CLI Documentation**: Guide showing how to use the generated CLI and where to add new commands
161173
- **Docker Documentation**: Container setup documentation covering image sources, development environment, and registry publishing
@@ -167,7 +179,8 @@ Every generated project includes documentation tailored to your selected feature
167179
The template intelligently configures itself based on your choices through sophisticated post-generation hooks:
168180

169181
- **Surgical Dependency Management**: Only includes packages you actually need in `pyproject.toml`, with proper optional dependency groups for dev tools, testing, and feature-specific requirements, avoiding bloated dependency trees
170-
- **Conditional Docker Services**: Automatically generates docker-compose.yaml with only the services your project requires: PostgreSQL for SQLAlchemy, Redis for Celery/caching, with properly configured health checks, volumes, and networking
182+
- **Conditional Docker Services**: Automatically generates docker-compose.yaml with only the services your project requires: PostgreSQL for SQLAlchemy, Redis for Celery/aiocache caching, with properly configured health checks, volumes, and networking
183+
- **Cache-Aware Configuration**: When aiocache is enabled, automatically configures Redis connection settings, multiple cache instances with different TTL strategies, and cache warming hooks for FastAPI and Celery startup events
171184
- **Database-Aware Configuration**: Sets up appropriate connection strings, pool sizes, and dialect-specific settings for PostgreSQL or SQLite, with Alembic migrations configured for cross-database compatibility
172185
- **Feature-Driven CI/CD Workflows**: GitHub Actions workflows are conditionally installed based on your feature selection: container building and publishing only when Docker is enabled, PyPI publishing workflow only when configured, eliminating unused automation files from your repository
173186
- **Framework Integration**: Automatically wires together selected components (FastAPI with SQLAlchemy database dependencies, Celery with Redis broker, CLI with async command support) providing working examples of how pieces fit together

cookiecutter.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"author_name": "",
44
"short_description": "",
55
"python_version": "3.14",
6+
"github_org": "EXAMPLE",
67
"license": [
78
"All Rights Reserved",
89
"MIT license",
@@ -15,7 +16,7 @@
1516
"include_sqlalchemy": "y/N",
1617
"include_quasiqueue": "y/N",
1718
"include_jinja2": "y/N",
18-
"include_dogpile": "y/N",
19+
"include_aiocache": "y/N",
1920
"include_celery": "y/N",
2021
"include_docker": "y/N",
2122
"include_github_actions": "y/N",

hooks/post_gen_project.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
INCLUDE_DOCKER={% if cookiecutter.include_docker == "y" %}True{% else %}False{% endif %}
1111
INCLUDE_QUASIQUEUE={% if cookiecutter.include_quasiqueue == "y" %}True{% else %}False{% endif %}
1212
INCLUDE_JINJA2={% if cookiecutter.include_jinja2 == "y" %}True{% else %}False{% endif %}
13-
INCLUDE_DOGPILE={% if cookiecutter.include_dogpile == "y" %}True{% else %}False{% endif %}
13+
INCLUDE_AIOCACHE={% if cookiecutter.include_aiocache == "y" %}True{% else %}False{% endif %}
1414
INCLUDE_SQLALCHEMY={% if cookiecutter.include_sqlalchemy == "y" %}True{% else %}False{% endif %}
1515
INCLUDE_GITHUB_ACTIONS={% if cookiecutter.include_github_actions == "y" %}True{% else %}False{% endif %}
1616
INCLUDE_REQUIREMENTS_FILES={% if cookiecutter.include_requirements_files == "y" %}True{% else %}False{% endif %}
@@ -30,6 +30,7 @@
3030
remove_paths.add(f'dockerfile.www')
3131
remove_paths.add(f'docker/www')
3232
remove_paths.add(f'docs/dev/api.md')
33+
remove_paths.add(f'tests/test_www.py')
3334

3435
if INCLUDE_CELERY:
3536
docker_containers.add('celery')
@@ -38,13 +39,15 @@
3839
remove_paths.add(f'dockerfile.celery')
3940
remove_paths.add(f'docker/celery')
4041
remove_paths.add(f'docs/dev/celery.md')
42+
remove_paths.add(f'tests/test_celery.py')
4143

4244
if INCLUDE_QUASIQUEUE:
4345
docker_containers.add('qq')
4446
else:
4547
remove_paths.add(f'{PACKAGE_SLUG}/qq.py')
4648
remove_paths.add(f'dockerfile.qq')
4749
remove_paths.add(f'docs/dev/quasiqueue.md')
50+
remove_paths.add(f'tests/test_qq.py')
4851

4952
if not INCLUDE_SQLALCHEMY:
5053
remove_paths.add(f'{PACKAGE_SLUG}/models')
@@ -59,16 +62,23 @@
5962
if not INCLUDE_CLI:
6063
remove_paths.add(f'{PACKAGE_SLUG}/cli.py')
6164
remove_paths.add(f'docs/dev/cli.md')
65+
remove_paths.add(f'tests/test_cli.py')
6266

6367
if not INCLUDE_JINJA2:
6468
remove_paths.add(f'{PACKAGE_SLUG}/templates')
6569
remove_paths.add(f'{PACKAGE_SLUG}/services/jinja.py')
6670
remove_paths.add(f'docs/dev/templates.md')
71+
remove_paths.add(f'tests/services/test_jinja.py')
6772

68-
if not INCLUDE_DOGPILE:
73+
if not INCLUDE_AIOCACHE:
74+
remove_paths.add(f'{PACKAGE_SLUG}/conf/cache.py')
6975
remove_paths.add(f'{PACKAGE_SLUG}/services/cache.py')
76+
remove_paths.add(f'tests/services/test_cache.py')
7077
remove_paths.add(f'docs/dev/cache.md')
7178

79+
# Always include test_settings.py as it tests core settings functionality
80+
# that exists regardless of optional features
81+
7282
if not INCLUDE_DOCKER:
7383
remove_paths.add('.dockerignore')
7484
remove_paths.add('compose.yaml')

tests/bare.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ default_context:
88
include_fastapi: "n"
99
include_sqlalchemy: "n"
1010
include_jinja2: "n"
11-
include_dogpile: "n"
11+
include_aiocache: "n"
1212
include_celery: "n"
1313
include_docker: "n"
1414
include_github_actions: "n"

tests/full.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ default_context:
99
include_sqlalchemy: "y"
1010
include_quasiqueue: "y"
1111
include_jinja2: "y"
12-
include_dogpile: "y"
12+
include_aiocache: "y"
1313
include_celery: "y"
1414
include_docker: "y"
1515
include_github_actions: "y"

tests/library.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ default_context:
88
include_fastapi: "n"
99
include_sqlalchemy: "n"
1010
include_jinja2: "n"
11-
include_dogpile: "n"
11+
include_aiocache: "n"
1212
include_celery: "n"
1313
include_docker: "n"
1414
include_github_actions: "y"

{{cookiecutter.__package_slug}}/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,27 @@ pip install {{ cookiecutter.package_name }}
2222
```
2323

2424
{%- endif %}
25+
26+
## Developer Documentation
27+
28+
Comprehensive developer documentation is available in [`docs/dev/`](./docs/dev/) covering testing, configuration, deployment, and all project features.
29+
30+
### Quick Start for Developers
31+
32+
```bash
33+
# Install development environment
34+
make install
35+
{%- if cookiecutter.include_docker == "y" %}
36+
37+
# Start services with Docker
38+
docker compose up -d
39+
{%- endif %}
40+
41+
# Run tests
42+
make tests
43+
44+
# Auto-fix formatting
45+
make chores
46+
```
47+
48+
See the [developer documentation](./docs/dev/README.md) for complete guides and reference.

0 commit comments

Comments
 (0)