oe-python-template 0.9.7__tar.gz → 0.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {oe_python_template-0.9.7 → oe_python_template-0.10.0}/PKG-INFO +77 -51
- {oe_python_template-0.9.7 → oe_python_template-0.10.0}/README.md +63 -48
- {oe_python_template-0.9.7 → oe_python_template-0.10.0}/pyproject.toml +22 -11
- oe_python_template-0.10.0/src/oe_python_template/__init__.py +6 -0
- oe_python_template-0.10.0/src/oe_python_template/api.py +75 -0
- oe_python_template-0.10.0/src/oe_python_template/cli.py +22 -0
- oe_python_template-0.10.0/src/oe_python_template/constants.py +7 -0
- oe_python_template-0.10.0/src/oe_python_template/hello/__init__.py +17 -0
- oe_python_template-0.10.0/src/oe_python_template/hello/_api.py +94 -0
- oe_python_template-0.10.0/src/oe_python_template/hello/_cli.py +47 -0
- oe_python_template-0.10.0/src/oe_python_template/hello/_constants.py +4 -0
- oe_python_template-0.10.0/src/oe_python_template/hello/_models.py +28 -0
- oe_python_template-0.10.0/src/oe_python_template/hello/_service.py +96 -0
- oe_python_template-0.9.7/src/oe_python_template/settings.py → oe_python_template-0.10.0/src/oe_python_template/hello/_settings.py +6 -4
- oe_python_template-0.10.0/src/oe_python_template/system/__init__.py +17 -0
- oe_python_template-0.10.0/src/oe_python_template/system/_api.py +78 -0
- oe_python_template-0.10.0/src/oe_python_template/system/_cli.py +165 -0
- oe_python_template-0.10.0/src/oe_python_template/system/_service.py +163 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/__init__.py +57 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_api.py +18 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_cli.py +68 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_console.py +14 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_constants.py +48 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_di.py +70 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_health.py +107 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_log.py +122 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_logfire.py +67 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_process.py +41 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_sentry.py +96 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_service.py +39 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/_settings.py +68 -0
- oe_python_template-0.10.0/src/oe_python_template/utils/boot.py +86 -0
- oe_python_template-0.9.7/src/oe_python_template/__init__.py +0 -20
- oe_python_template-0.9.7/src/oe_python_template/api.py +0 -181
- oe_python_template-0.9.7/src/oe_python_template/cli.py +0 -150
- oe_python_template-0.9.7/src/oe_python_template/constants.py +0 -10
- oe_python_template-0.9.7/src/oe_python_template/models.py +0 -44
- oe_python_template-0.9.7/src/oe_python_template/service.py +0 -68
- {oe_python_template-0.9.7 → oe_python_template-0.10.0}/.gitignore +0 -0
- {oe_python_template-0.9.7 → oe_python_template-0.10.0}/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oe-python-template
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: 🧠 Copier template to scaffold Python projects compliant with best practices and modern tooling.
|
|
5
5
|
Project-URL: Homepage, https://oe-python-template.readthedocs.io/en/latest/
|
|
6
6
|
Project-URL: Documentation, https://oe-python-template.readthedocs.io/en/latest/
|
|
@@ -49,13 +49,24 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
49
49
|
Classifier: Typing :: Typed
|
|
50
50
|
Requires-Python: <4.0,>=3.11
|
|
51
51
|
Requires-Dist: fastapi[all,standard]>=0.115.12
|
|
52
|
+
Requires-Dist: logfire[system-metrics]>=3.13.1
|
|
53
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.53b0
|
|
54
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.53b0
|
|
55
|
+
Requires-Dist: opentelemetry-instrumentation-jinja2>=0.53b0
|
|
56
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.53b0
|
|
57
|
+
Requires-Dist: opentelemetry-instrumentation-sqlite3>=0.53b0
|
|
58
|
+
Requires-Dist: opentelemetry-instrumentation-tornado>=0.53b0
|
|
59
|
+
Requires-Dist: opentelemetry-instrumentation-urllib3>=0.53b0
|
|
60
|
+
Requires-Dist: opentelemetry-instrumentation-urllib>=0.53b0
|
|
61
|
+
Requires-Dist: psutil>=7.0.0
|
|
52
62
|
Requires-Dist: pydantic-settings>=2.8.1
|
|
53
|
-
Requires-Dist: pydantic>=2.11.
|
|
63
|
+
Requires-Dist: pydantic>=2.11.3
|
|
64
|
+
Requires-Dist: sentry-sdk>=2.25.1
|
|
54
65
|
Requires-Dist: typer>=0.15.1
|
|
55
66
|
Provides-Extra: examples
|
|
56
67
|
Requires-Dist: jinja2>=3.1.6; extra == 'examples'
|
|
57
68
|
Requires-Dist: jupyter>=1.1.1; extra == 'examples'
|
|
58
|
-
Requires-Dist: marimo>=0.12.
|
|
69
|
+
Requires-Dist: marimo>=0.12.8; extra == 'examples'
|
|
59
70
|
Requires-Dist: streamlit>=1.44.1; extra == 'examples'
|
|
60
71
|
Description-Content-Type: text/markdown
|
|
61
72
|
|
|
@@ -89,6 +100,8 @@ Description-Content-Type: text/markdown
|
|
|
89
100
|
[](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template)
|
|
90
101
|
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template)
|
|
91
102
|
[](https://github.com/codespaces/new/helmut-hoffer-von-ankershoffen/oe-python-template)
|
|
103
|
+
[](https://oe-python-template.vercel.app/docs)
|
|
104
|
+
[](https://helmut-hoffer-von-ankershoffen.betteruptime.com/)
|
|
92
105
|
|
|
93
106
|
<!---
|
|
94
107
|
[](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template/pkgs/container/oe-python-template)
|
|
@@ -124,33 +137,40 @@ Projects generated with this template come with a comprehensive development tool
|
|
|
124
137
|
8. CI/CD pipeline can be run locally with [act](https://github.com/nektos/act)
|
|
125
138
|
9. Code quality and security checks with [SonarQube](https://www.sonarsource.com/products/sonarcloud) and [GitHub CodeQL](https://codeql.github.com/)
|
|
126
139
|
10. Dependency monitoring and vulnerability scanning with [pip-audit](https://pypi.org/project/pip-audit/), [trivy](https://trivy.dev/latest/), [Renovate](https://github.com/renovatebot/renovate), and [GitHub Dependabot](https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide)
|
|
127
|
-
11.
|
|
128
|
-
12.
|
|
129
|
-
13.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
11. Error monitoring and profiling with [Sentry](https://sentry.io/) (optional)
|
|
141
|
+
12. Logging and metrics with [Logfire](https://logfire.dev/) (optional)
|
|
142
|
+
13. Prepared for uptime monitoring with [betterstack](https://betterstack.com/) or alternatives
|
|
143
|
+
13. Licenses of dependencies extracted with [pip-licenses](https://pypi.org/project/pip-licenses/), matched with allow list, and published as release artifacts in CSV and JSON format for further compliance checks
|
|
144
|
+
14. Generation of attributions from extracted licenses
|
|
145
|
+
15. Software Bill of Materials (SBOM) generated in [CycloneDX](https://cyclonedx.org/) and [SPDX](https://spdx.dev/) formats with [cyclonedx-python](https://github.com/CycloneDX/cyclonedx-python) resp. [trivy](https://trivy.dev/latest/), published as release artifacts
|
|
146
|
+
16. Version and release management with [bump-my-version](https://callowayproject.github.io/bump-my-version/)
|
|
147
|
+
17. Changelog and release notes generated with [git-cliff](https://git-cliff.org/)
|
|
148
|
+
18. Documentation generated with [Sphinx](https://www.sphinx-doc.org/en/master/) including reference documentation for the library, CLI, and API
|
|
149
|
+
19. Documentation published to [Read The Docs](https://readthedocs.org/) including generation of PDF and single page HTML versions
|
|
150
|
+
20. Interactive OpenAPI specification with [Swagger](https://swagger.io/)
|
|
151
|
+
21. Python package published to [PyPI](https://pypi.org/)
|
|
152
|
+
22. Docker images published to [Docker.io](https://hub.docker.com/) and [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) with [artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds)
|
|
153
|
+
23. One-click development environments with [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) and [GitHub Codespaces](https://github.com/features/codespaces)
|
|
154
|
+
24. Settings for use with [VSCode](https://code.visualstudio.com/)
|
|
155
|
+
25. Settings and custom instructions for use with [GitHub Copilot](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot)
|
|
156
|
+
26. API deployed as serverless function to [Vercel](https://vercel.com/) (optional)
|
|
140
157
|
|
|
141
158
|
### Application Features
|
|
142
159
|
|
|
143
|
-
Beyond development tooling, projects generated with this template include the code, documentation, and configuration of a fully functioning
|
|
144
|
-
|
|
145
|
-
1.
|
|
146
|
-
2.
|
|
147
|
-
3.
|
|
148
|
-
4.
|
|
149
|
-
5.
|
|
150
|
-
6.
|
|
151
|
-
7.
|
|
152
|
-
8.
|
|
153
|
-
9.
|
|
160
|
+
Beyond development tooling, projects generated with this template include the code, documentation, and configuration of a fully functioning application and service. This reference implementation serves as a starting point for your own business logic with modern patterns and enterprise practices already in place:
|
|
161
|
+
|
|
162
|
+
1. Usable as library with "Hello" module exposing a simple service
|
|
163
|
+
2. Command-line interface (CLI) with [Typer](https://typer.tiangolo.com/)
|
|
164
|
+
3. Versioned webservice API with [FastAPI](https://fastapi.tiangolo.com/)
|
|
165
|
+
4. [Interactive Jupyter notebook](https://jupyter.org/) and [reactive Marimo notebook](https://marimo.io/)
|
|
166
|
+
5. Simple Web UI with [Streamlit](https://streamlit.io/)
|
|
167
|
+
6. Configuration to run the CLI and API in a Docker container including setup for [Docker Compose](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-docker-compose/)
|
|
168
|
+
7. Validation and settings management with [pydantic](https://docs.pydantic.dev/)
|
|
169
|
+
8. Info command enabling to inspect the runtime, compiled settings, and further info provided dynamically by modules
|
|
170
|
+
9. Health endpoint exposing system health dynamically aggregated from all modules and dependencies
|
|
171
|
+
10. Flexible logging and instrumentation, including support for [Sentry](https://sentry.io/) and [Logfire](https://logfire.dev/)
|
|
172
|
+
11. Modular architecture including auto-registration of services, CLI commands and API routes exposed by modules
|
|
173
|
+
12. Documentation including dynamic badges, setup instructions, contribution guide and security policy
|
|
154
174
|
|
|
155
175
|
Explore [here](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example) for what's generated out of the box.
|
|
156
176
|
|
|
@@ -273,7 +293,7 @@ The following examples run from source - clone this repository using
|
|
|
273
293
|
from dotenv import load_dotenv
|
|
274
294
|
from rich.console import Console
|
|
275
295
|
|
|
276
|
-
from oe_python_template import Service
|
|
296
|
+
from oe_python_template.hello import Service
|
|
277
297
|
|
|
278
298
|
console = Console()
|
|
279
299
|
|
|
@@ -355,13 +375,15 @@ uvx oe-python-template --help
|
|
|
355
375
|
Execute commands:
|
|
356
376
|
|
|
357
377
|
```shell
|
|
358
|
-
uvx oe-python-template hello
|
|
359
|
-
uvx oe-python-template echo --help
|
|
360
|
-
uvx oe-python-template echo "Lorem"
|
|
361
|
-
uvx oe-python-template echo "Lorem" --json
|
|
362
|
-
uvx oe-python-template
|
|
363
|
-
uvx oe-python-template
|
|
364
|
-
uvx oe-python-template
|
|
378
|
+
uvx oe-python-template hello world
|
|
379
|
+
uvx oe-python-template hello echo --help
|
|
380
|
+
uvx oe-python-template hello echo "Lorem"
|
|
381
|
+
uvx oe-python-template hello echo "Lorem" --json
|
|
382
|
+
uvx oe-python-template system info
|
|
383
|
+
uvx oe-python-template system health
|
|
384
|
+
uvx oe-python-template system openapi
|
|
385
|
+
uvx oe-python-template system openapi --output-format=json
|
|
386
|
+
uvx oe-python-template system serve
|
|
365
387
|
```
|
|
366
388
|
|
|
367
389
|
See the [reference documentation of the CLI](https://oe-python-template.readthedocs.io/en/latest/cli_reference.html) for detailed documentation of all CLI commands and options.
|
|
@@ -384,19 +406,21 @@ You can as well run the CLI within Docker.
|
|
|
384
406
|
|
|
385
407
|
```shell
|
|
386
408
|
docker run helmuthva/oe-python-template --help
|
|
387
|
-
docker run helmuthva/oe-python-template hello
|
|
388
|
-
docker run helmuthva/oe-python-template echo --help
|
|
389
|
-
docker run helmuthva/oe-python-template echo "Lorem"
|
|
390
|
-
docker run helmuthva/oe-python-template echo "Lorem" --json
|
|
391
|
-
docker run helmuthva/oe-python-template
|
|
392
|
-
docker run helmuthva/oe-python-template
|
|
393
|
-
docker run helmuthva/oe-python-template
|
|
409
|
+
docker run helmuthva/oe-python-template hello world
|
|
410
|
+
docker run helmuthva/oe-python-template hello echo --help
|
|
411
|
+
docker run helmuthva/oe-python-template hello echo "Lorem"
|
|
412
|
+
docker run helmuthva/oe-python-template hello echo "Lorem" --json
|
|
413
|
+
docker run helmuthva/oe-python-template system info
|
|
414
|
+
docker run helmuthva/oe-python-template system health
|
|
415
|
+
docker run helmuthva/oe-python-template system openapi
|
|
416
|
+
docker run helmuthva/oe-python-template system openapi --output-format=json
|
|
417
|
+
docker run helmuthva/oe-python-template system serve
|
|
394
418
|
```
|
|
395
419
|
|
|
396
420
|
Execute command:
|
|
397
421
|
|
|
398
422
|
```shell
|
|
399
|
-
docker run --env THE_VAR=MY_VALUE helmuthva/oe-python-template echo "Lorem Ipsum"
|
|
423
|
+
docker run --env THE_VAR=MY_VALUE helmuthva/oe-python-template hello echo "Lorem Ipsum"
|
|
400
424
|
```
|
|
401
425
|
|
|
402
426
|
Or use docker compose
|
|
@@ -405,12 +429,14 @@ The .env is passed through from the host to the Docker container.
|
|
|
405
429
|
|
|
406
430
|
```shell
|
|
407
431
|
docker compose run --remove-orphans oe-python-template --help
|
|
408
|
-
docker compose run --remove-orphans oe-python-template hello
|
|
409
|
-
docker compose run --remove-orphans oe-python-template echo --help
|
|
410
|
-
docker compose run --remove-orphans oe-python-template echo "Lorem"
|
|
411
|
-
docker compose run --remove-orphans oe-python-template echo "Lorem" --json
|
|
412
|
-
docker compose run --remove-orphans oe-python-template
|
|
413
|
-
docker compose run --remove-orphans oe-python-template
|
|
432
|
+
docker compose run --remove-orphans oe-python-template hello world
|
|
433
|
+
docker compose run --remove-orphans oe-python-template hello echo --help
|
|
434
|
+
docker compose run --remove-orphans oe-python-template hello echo "Lorem"
|
|
435
|
+
docker compose run --remove-orphans oe-python-template hello echo "Lorem" --json
|
|
436
|
+
docker compose run --remove-orphans oe-python-template system info
|
|
437
|
+
docker compose run --remove-orphans oe-python-template system health
|
|
438
|
+
docker compose run --remove-orphans oe-python-template system openapi
|
|
439
|
+
docker compose run --remove-orphans oe-python-template system openapi --output-format=json
|
|
414
440
|
echo "Running OE Python Template's API container as a daemon ..."
|
|
415
441
|
docker compose up -d
|
|
416
442
|
echo "Waiting for the API server to start ..."
|
|
@@ -419,7 +445,7 @@ echo "Checking health of v1 API ..."
|
|
|
419
445
|
curl http://127.0.0.1:8000/api/v1/healthz
|
|
420
446
|
echo ""
|
|
421
447
|
echo "Saying hello world with v1 API ..."
|
|
422
|
-
curl http://127.0.0.1:8000/api/v1/hello
|
|
448
|
+
curl http://127.0.0.1:8000/api/v1/hello/world
|
|
423
449
|
echo ""
|
|
424
450
|
echo "Swagger docs of v1 API ..."
|
|
425
451
|
curl http://127.0.0.1:8000/api/v1/docs
|
|
@@ -428,7 +454,7 @@ echo "Checking health of v2 API ..."
|
|
|
428
454
|
curl http://127.0.0.1:8000/api/v2/healthz
|
|
429
455
|
echo ""
|
|
430
456
|
echo "Saying hello world with v1 API ..."
|
|
431
|
-
curl http://127.0.0.1:8000/api/v2/hello
|
|
457
|
+
curl http://127.0.0.1:8000/api/v2/hello/world
|
|
432
458
|
echo ""
|
|
433
459
|
echo "Swagger docs of v2 API ..."
|
|
434
460
|
curl http://127.0.0.1:8000/api/v2/docs
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
[](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template)
|
|
29
29
|
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template)
|
|
30
30
|
[](https://github.com/codespaces/new/helmut-hoffer-von-ankershoffen/oe-python-template)
|
|
31
|
+
[](https://oe-python-template.vercel.app/docs)
|
|
32
|
+
[](https://helmut-hoffer-von-ankershoffen.betteruptime.com/)
|
|
31
33
|
|
|
32
34
|
<!---
|
|
33
35
|
[](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template/pkgs/container/oe-python-template)
|
|
@@ -63,33 +65,40 @@ Projects generated with this template come with a comprehensive development tool
|
|
|
63
65
|
8. CI/CD pipeline can be run locally with [act](https://github.com/nektos/act)
|
|
64
66
|
9. Code quality and security checks with [SonarQube](https://www.sonarsource.com/products/sonarcloud) and [GitHub CodeQL](https://codeql.github.com/)
|
|
65
67
|
10. Dependency monitoring and vulnerability scanning with [pip-audit](https://pypi.org/project/pip-audit/), [trivy](https://trivy.dev/latest/), [Renovate](https://github.com/renovatebot/renovate), and [GitHub Dependabot](https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide)
|
|
66
|
-
11.
|
|
67
|
-
12.
|
|
68
|
-
13.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
11. Error monitoring and profiling with [Sentry](https://sentry.io/) (optional)
|
|
69
|
+
12. Logging and metrics with [Logfire](https://logfire.dev/) (optional)
|
|
70
|
+
13. Prepared for uptime monitoring with [betterstack](https://betterstack.com/) or alternatives
|
|
71
|
+
13. Licenses of dependencies extracted with [pip-licenses](https://pypi.org/project/pip-licenses/), matched with allow list, and published as release artifacts in CSV and JSON format for further compliance checks
|
|
72
|
+
14. Generation of attributions from extracted licenses
|
|
73
|
+
15. Software Bill of Materials (SBOM) generated in [CycloneDX](https://cyclonedx.org/) and [SPDX](https://spdx.dev/) formats with [cyclonedx-python](https://github.com/CycloneDX/cyclonedx-python) resp. [trivy](https://trivy.dev/latest/), published as release artifacts
|
|
74
|
+
16. Version and release management with [bump-my-version](https://callowayproject.github.io/bump-my-version/)
|
|
75
|
+
17. Changelog and release notes generated with [git-cliff](https://git-cliff.org/)
|
|
76
|
+
18. Documentation generated with [Sphinx](https://www.sphinx-doc.org/en/master/) including reference documentation for the library, CLI, and API
|
|
77
|
+
19. Documentation published to [Read The Docs](https://readthedocs.org/) including generation of PDF and single page HTML versions
|
|
78
|
+
20. Interactive OpenAPI specification with [Swagger](https://swagger.io/)
|
|
79
|
+
21. Python package published to [PyPI](https://pypi.org/)
|
|
80
|
+
22. Docker images published to [Docker.io](https://hub.docker.com/) and [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) with [artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds)
|
|
81
|
+
23. One-click development environments with [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) and [GitHub Codespaces](https://github.com/features/codespaces)
|
|
82
|
+
24. Settings for use with [VSCode](https://code.visualstudio.com/)
|
|
83
|
+
25. Settings and custom instructions for use with [GitHub Copilot](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot)
|
|
84
|
+
26. API deployed as serverless function to [Vercel](https://vercel.com/) (optional)
|
|
79
85
|
|
|
80
86
|
### Application Features
|
|
81
87
|
|
|
82
|
-
Beyond development tooling, projects generated with this template include the code, documentation, and configuration of a fully functioning
|
|
83
|
-
|
|
84
|
-
1.
|
|
85
|
-
2.
|
|
86
|
-
3.
|
|
87
|
-
4.
|
|
88
|
-
5.
|
|
89
|
-
6.
|
|
90
|
-
7.
|
|
91
|
-
8.
|
|
92
|
-
9.
|
|
88
|
+
Beyond development tooling, projects generated with this template include the code, documentation, and configuration of a fully functioning application and service. This reference implementation serves as a starting point for your own business logic with modern patterns and enterprise practices already in place:
|
|
89
|
+
|
|
90
|
+
1. Usable as library with "Hello" module exposing a simple service
|
|
91
|
+
2. Command-line interface (CLI) with [Typer](https://typer.tiangolo.com/)
|
|
92
|
+
3. Versioned webservice API with [FastAPI](https://fastapi.tiangolo.com/)
|
|
93
|
+
4. [Interactive Jupyter notebook](https://jupyter.org/) and [reactive Marimo notebook](https://marimo.io/)
|
|
94
|
+
5. Simple Web UI with [Streamlit](https://streamlit.io/)
|
|
95
|
+
6. Configuration to run the CLI and API in a Docker container including setup for [Docker Compose](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-docker-compose/)
|
|
96
|
+
7. Validation and settings management with [pydantic](https://docs.pydantic.dev/)
|
|
97
|
+
8. Info command enabling to inspect the runtime, compiled settings, and further info provided dynamically by modules
|
|
98
|
+
9. Health endpoint exposing system health dynamically aggregated from all modules and dependencies
|
|
99
|
+
10. Flexible logging and instrumentation, including support for [Sentry](https://sentry.io/) and [Logfire](https://logfire.dev/)
|
|
100
|
+
11. Modular architecture including auto-registration of services, CLI commands and API routes exposed by modules
|
|
101
|
+
12. Documentation including dynamic badges, setup instructions, contribution guide and security policy
|
|
93
102
|
|
|
94
103
|
Explore [here](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example) for what's generated out of the box.
|
|
95
104
|
|
|
@@ -212,7 +221,7 @@ The following examples run from source - clone this repository using
|
|
|
212
221
|
from dotenv import load_dotenv
|
|
213
222
|
from rich.console import Console
|
|
214
223
|
|
|
215
|
-
from oe_python_template import Service
|
|
224
|
+
from oe_python_template.hello import Service
|
|
216
225
|
|
|
217
226
|
console = Console()
|
|
218
227
|
|
|
@@ -294,13 +303,15 @@ uvx oe-python-template --help
|
|
|
294
303
|
Execute commands:
|
|
295
304
|
|
|
296
305
|
```shell
|
|
297
|
-
uvx oe-python-template hello
|
|
298
|
-
uvx oe-python-template echo --help
|
|
299
|
-
uvx oe-python-template echo "Lorem"
|
|
300
|
-
uvx oe-python-template echo "Lorem" --json
|
|
301
|
-
uvx oe-python-template
|
|
302
|
-
uvx oe-python-template
|
|
303
|
-
uvx oe-python-template
|
|
306
|
+
uvx oe-python-template hello world
|
|
307
|
+
uvx oe-python-template hello echo --help
|
|
308
|
+
uvx oe-python-template hello echo "Lorem"
|
|
309
|
+
uvx oe-python-template hello echo "Lorem" --json
|
|
310
|
+
uvx oe-python-template system info
|
|
311
|
+
uvx oe-python-template system health
|
|
312
|
+
uvx oe-python-template system openapi
|
|
313
|
+
uvx oe-python-template system openapi --output-format=json
|
|
314
|
+
uvx oe-python-template system serve
|
|
304
315
|
```
|
|
305
316
|
|
|
306
317
|
See the [reference documentation of the CLI](https://oe-python-template.readthedocs.io/en/latest/cli_reference.html) for detailed documentation of all CLI commands and options.
|
|
@@ -323,19 +334,21 @@ You can as well run the CLI within Docker.
|
|
|
323
334
|
|
|
324
335
|
```shell
|
|
325
336
|
docker run helmuthva/oe-python-template --help
|
|
326
|
-
docker run helmuthva/oe-python-template hello
|
|
327
|
-
docker run helmuthva/oe-python-template echo --help
|
|
328
|
-
docker run helmuthva/oe-python-template echo "Lorem"
|
|
329
|
-
docker run helmuthva/oe-python-template echo "Lorem" --json
|
|
330
|
-
docker run helmuthva/oe-python-template
|
|
331
|
-
docker run helmuthva/oe-python-template
|
|
332
|
-
docker run helmuthva/oe-python-template
|
|
337
|
+
docker run helmuthva/oe-python-template hello world
|
|
338
|
+
docker run helmuthva/oe-python-template hello echo --help
|
|
339
|
+
docker run helmuthva/oe-python-template hello echo "Lorem"
|
|
340
|
+
docker run helmuthva/oe-python-template hello echo "Lorem" --json
|
|
341
|
+
docker run helmuthva/oe-python-template system info
|
|
342
|
+
docker run helmuthva/oe-python-template system health
|
|
343
|
+
docker run helmuthva/oe-python-template system openapi
|
|
344
|
+
docker run helmuthva/oe-python-template system openapi --output-format=json
|
|
345
|
+
docker run helmuthva/oe-python-template system serve
|
|
333
346
|
```
|
|
334
347
|
|
|
335
348
|
Execute command:
|
|
336
349
|
|
|
337
350
|
```shell
|
|
338
|
-
docker run --env THE_VAR=MY_VALUE helmuthva/oe-python-template echo "Lorem Ipsum"
|
|
351
|
+
docker run --env THE_VAR=MY_VALUE helmuthva/oe-python-template hello echo "Lorem Ipsum"
|
|
339
352
|
```
|
|
340
353
|
|
|
341
354
|
Or use docker compose
|
|
@@ -344,12 +357,14 @@ The .env is passed through from the host to the Docker container.
|
|
|
344
357
|
|
|
345
358
|
```shell
|
|
346
359
|
docker compose run --remove-orphans oe-python-template --help
|
|
347
|
-
docker compose run --remove-orphans oe-python-template hello
|
|
348
|
-
docker compose run --remove-orphans oe-python-template echo --help
|
|
349
|
-
docker compose run --remove-orphans oe-python-template echo "Lorem"
|
|
350
|
-
docker compose run --remove-orphans oe-python-template echo "Lorem" --json
|
|
351
|
-
docker compose run --remove-orphans oe-python-template
|
|
352
|
-
docker compose run --remove-orphans oe-python-template
|
|
360
|
+
docker compose run --remove-orphans oe-python-template hello world
|
|
361
|
+
docker compose run --remove-orphans oe-python-template hello echo --help
|
|
362
|
+
docker compose run --remove-orphans oe-python-template hello echo "Lorem"
|
|
363
|
+
docker compose run --remove-orphans oe-python-template hello echo "Lorem" --json
|
|
364
|
+
docker compose run --remove-orphans oe-python-template system info
|
|
365
|
+
docker compose run --remove-orphans oe-python-template system health
|
|
366
|
+
docker compose run --remove-orphans oe-python-template system openapi
|
|
367
|
+
docker compose run --remove-orphans oe-python-template system openapi --output-format=json
|
|
353
368
|
echo "Running OE Python Template's API container as a daemon ..."
|
|
354
369
|
docker compose up -d
|
|
355
370
|
echo "Waiting for the API server to start ..."
|
|
@@ -358,7 +373,7 @@ echo "Checking health of v1 API ..."
|
|
|
358
373
|
curl http://127.0.0.1:8000/api/v1/healthz
|
|
359
374
|
echo ""
|
|
360
375
|
echo "Saying hello world with v1 API ..."
|
|
361
|
-
curl http://127.0.0.1:8000/api/v1/hello
|
|
376
|
+
curl http://127.0.0.1:8000/api/v1/hello/world
|
|
362
377
|
echo ""
|
|
363
378
|
echo "Swagger docs of v1 API ..."
|
|
364
379
|
curl http://127.0.0.1:8000/api/v1/docs
|
|
@@ -367,7 +382,7 @@ echo "Checking health of v2 API ..."
|
|
|
367
382
|
curl http://127.0.0.1:8000/api/v2/healthz
|
|
368
383
|
echo ""
|
|
369
384
|
echo "Saying hello world with v1 API ..."
|
|
370
|
-
curl http://127.0.0.1:8000/api/v2/hello
|
|
385
|
+
curl http://127.0.0.1:8000/api/v2/hello/world
|
|
371
386
|
echo ""
|
|
372
387
|
echo "Swagger docs of v2 API ..."
|
|
373
388
|
curl http://127.0.0.1:8000/api/v2/docs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "oe-python-template"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.10.0"
|
|
4
4
|
description = "🧠 Copier template to scaffold Python projects compliant with best practices and modern tooling."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Helmut Hoffer von Ankershoffen", email = "helmuthva@gmail.com" }]
|
|
@@ -62,8 +62,19 @@ requires-python = ">=3.11, <4.0"
|
|
|
62
62
|
dependencies = [
|
|
63
63
|
# From Template
|
|
64
64
|
"fastapi[standard,all]>=0.115.12",
|
|
65
|
-
"
|
|
65
|
+
"logfire[system-metrics]>=3.13.1",
|
|
66
|
+
"opentelemetry-instrumentation-fastapi>=0.53b0",
|
|
67
|
+
"opentelemetry-instrumentation-httpx>=0.53b0",
|
|
68
|
+
"opentelemetry-instrumentation-jinja2>=0.53b0",
|
|
69
|
+
"opentelemetry-instrumentation-requests>=0.53b0",
|
|
70
|
+
"opentelemetry-instrumentation-sqlite3>=0.53b0",
|
|
71
|
+
"opentelemetry-instrumentation-tornado>=0.53b0",
|
|
72
|
+
"opentelemetry-instrumentation-urllib>=0.53b0",
|
|
73
|
+
"opentelemetry-instrumentation-urllib3>=0.53b0",
|
|
74
|
+
"psutil>=7.0.0",
|
|
75
|
+
"pydantic>=2.11.3",
|
|
66
76
|
"pydantic-settings>=2.8.1",
|
|
77
|
+
"sentry-sdk>=2.25.1",
|
|
67
78
|
"typer>=0.15.1",
|
|
68
79
|
# Custom
|
|
69
80
|
# Nothing yet
|
|
@@ -92,7 +103,7 @@ packages = ["src/oe_python_template"]
|
|
|
92
103
|
[project.optional-dependencies]
|
|
93
104
|
examples = [
|
|
94
105
|
"streamlit>=1.44.1",
|
|
95
|
-
"marimo>=0.12.
|
|
106
|
+
"marimo>=0.12.8",
|
|
96
107
|
"jupyter>=1.1.1",
|
|
97
108
|
"jinja2>=3.1.6",
|
|
98
109
|
]
|
|
@@ -109,20 +120,20 @@ dev = [
|
|
|
109
120
|
"matplotlib>=3.10.1",
|
|
110
121
|
"mypy>=1.5.0",
|
|
111
122
|
"nox[uv]>=2025.2.9",
|
|
112
|
-
"pip-audit>=2.
|
|
123
|
+
"pip-audit>=2.9.0",
|
|
113
124
|
"pip-licenses @ git+https://github.com/neXenio/pip-licenses.git@master", # https://github.com/raimon49/pip-licenses/pull/224
|
|
114
125
|
"pre-commit>=4.1.0",
|
|
115
|
-
"pyright>=1.1.
|
|
126
|
+
"pyright>=1.1.399",
|
|
116
127
|
"pytest>=8.3.5",
|
|
117
128
|
"pytest-asyncio>=0.26.0",
|
|
118
|
-
"pytest-cov>=6.1.
|
|
119
|
-
"pytest-docker>=3.2.
|
|
129
|
+
"pytest-cov>=6.1.1",
|
|
130
|
+
"pytest-docker>=3.2.1",
|
|
120
131
|
"pytest-env>=1.1.5",
|
|
121
132
|
"pytest-regressions>=2.7.0",
|
|
122
133
|
"pytest-subprocess>=1.5.3",
|
|
123
134
|
"pytest-timeout>=2.3.1",
|
|
124
135
|
"pytest-xdist[psutil]>=3.6.1",
|
|
125
|
-
"ruff>=0.11.
|
|
136
|
+
"ruff>=0.11.5",
|
|
126
137
|
"sphinx>=8.2.3",
|
|
127
138
|
"sphinx-autobuild>=2024.10.3",
|
|
128
139
|
"sphinx-copybutton>=0.5.2",
|
|
@@ -150,7 +161,7 @@ target-version = "py311"
|
|
|
150
161
|
preview = true
|
|
151
162
|
fix = true
|
|
152
163
|
line-length = 120
|
|
153
|
-
extend-exclude = [".fixme", "notebook.py"]
|
|
164
|
+
extend-exclude = [".fixme", "notebook.py", "template/*.py"]
|
|
154
165
|
|
|
155
166
|
[tool.ruff.lint]
|
|
156
167
|
select = ["ALL"]
|
|
@@ -176,7 +187,7 @@ ignore = [
|
|
|
176
187
|
]
|
|
177
188
|
|
|
178
189
|
[tool.ruff.lint.per-file-ignores]
|
|
179
|
-
"tests/**/*.py" = [
|
|
190
|
+
"**/tests/**/*.py" = [
|
|
180
191
|
# we are more relaxed in tests, while sill applying hundreds of rules
|
|
181
192
|
"S101", # asserts allowed in tests...
|
|
182
193
|
"ARG", # unused function args -> fixtures nevertheless are functionally relevant...
|
|
@@ -264,7 +275,7 @@ source = ["src/"]
|
|
|
264
275
|
|
|
265
276
|
|
|
266
277
|
[tool.bumpversion]
|
|
267
|
-
current_version = "0.
|
|
278
|
+
current_version = "0.10.0"
|
|
268
279
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
269
280
|
serialize = ["{major}.{minor}.{patch}"]
|
|
270
281
|
search = "{current_version}"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Webservice API of OE Python Template.
|
|
2
|
+
|
|
3
|
+
- Provides a versioned API
|
|
4
|
+
- Automatically registers APIs of modules and mounts them to the main API.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
from fastapi import FastAPI
|
|
10
|
+
|
|
11
|
+
from .constants import API_VERSIONS
|
|
12
|
+
from .utils import (
|
|
13
|
+
VersionedAPIRouter,
|
|
14
|
+
__author_email__,
|
|
15
|
+
__author_name__,
|
|
16
|
+
__documentation__url__,
|
|
17
|
+
__repository_url__,
|
|
18
|
+
locate_implementations,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
TITLE = "OE Python Template"
|
|
22
|
+
UVICORN_HOST = os.environ.get("UVICORN_HOST", "127.0.0.1")
|
|
23
|
+
UVICORN_PORT = os.environ.get("UVICORN_PORT", "8000")
|
|
24
|
+
CONTACT_NAME = __author_name__
|
|
25
|
+
CONTACT_EMAIL = __author_email__
|
|
26
|
+
CONTACT_URL = __repository_url__
|
|
27
|
+
TERMS_OF_SERVICE_URL = __documentation__url__
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
app = FastAPI(
|
|
31
|
+
root_path="/api",
|
|
32
|
+
title=TITLE,
|
|
33
|
+
contact={
|
|
34
|
+
"name": CONTACT_NAME,
|
|
35
|
+
"email": CONTACT_EMAIL,
|
|
36
|
+
"url": CONTACT_URL,
|
|
37
|
+
},
|
|
38
|
+
terms_of_service=TERMS_OF_SERVICE_URL,
|
|
39
|
+
openapi_tags=[
|
|
40
|
+
{
|
|
41
|
+
"name": version,
|
|
42
|
+
"description": f"API version {version.lstrip('v')}, check link on the right",
|
|
43
|
+
"externalDocs": {
|
|
44
|
+
"description": "sub-docs",
|
|
45
|
+
"url": f"http://{UVICORN_HOST}:{UVICORN_PORT}/api/{version}/docs",
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
for version, _ in API_VERSIONS.items()
|
|
49
|
+
],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Create API instances for each version
|
|
53
|
+
api_instances: dict["str", FastAPI] = {}
|
|
54
|
+
for version, semver in API_VERSIONS.items():
|
|
55
|
+
api_instances[version] = FastAPI(
|
|
56
|
+
version=semver,
|
|
57
|
+
title=TITLE,
|
|
58
|
+
contact={
|
|
59
|
+
"name": CONTACT_NAME,
|
|
60
|
+
"email": CONTACT_EMAIL,
|
|
61
|
+
"url": CONTACT_URL,
|
|
62
|
+
},
|
|
63
|
+
terms_of_service=TERMS_OF_SERVICE_URL,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Register routers with appropriate API versions
|
|
67
|
+
for router in locate_implementations(VersionedAPIRouter):
|
|
68
|
+
router_instance: VersionedAPIRouter = router
|
|
69
|
+
version = router_instance.version
|
|
70
|
+
if version in API_VERSIONS:
|
|
71
|
+
api_instances[version].include_router(router_instance)
|
|
72
|
+
|
|
73
|
+
# Mount all API versions to the main app
|
|
74
|
+
for version in API_VERSIONS:
|
|
75
|
+
app.mount(f"/{version}", api_instances[version])
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""CLI (Command Line Interface) of OE Python Template."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from .constants import MODULES_TO_INSTRUMENT
|
|
8
|
+
from .utils import __version__, boot, console, get_logger, prepare_cli
|
|
9
|
+
|
|
10
|
+
boot(MODULES_TO_INSTRUMENT)
|
|
11
|
+
logger = get_logger(__name__)
|
|
12
|
+
|
|
13
|
+
cli = typer.Typer(help="Command Line Interface of ")
|
|
14
|
+
prepare_cli(cli, f"🧠 OE Python Template v{__version__} - built with love in Berlin 🐻")
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__": # pragma: no cover
|
|
17
|
+
try:
|
|
18
|
+
cli()
|
|
19
|
+
except Exception as e: # noqa: BLE001
|
|
20
|
+
logger.critical("Fatal error occurred: %s", e)
|
|
21
|
+
console.print(f"Fatal error occurred: {e}", style="error")
|
|
22
|
+
sys.exit(1)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Hello module."""
|
|
2
|
+
|
|
3
|
+
from ._api import api_v1, api_v2
|
|
4
|
+
from ._cli import cli
|
|
5
|
+
from ._models import Echo, Utterance
|
|
6
|
+
from ._service import Service
|
|
7
|
+
from ._settings import Settings
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"Echo",
|
|
11
|
+
"Service",
|
|
12
|
+
"Settings",
|
|
13
|
+
"Utterance",
|
|
14
|
+
"api_v1",
|
|
15
|
+
"api_v2",
|
|
16
|
+
"cli",
|
|
17
|
+
]
|