oe-python-template-example 0.0.9__tar.gz → 0.0.10__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.
Files changed (89) hide show
  1. oe_python_template_example-0.0.9/.act-env → oe_python_template_example-0.0.10/.act-env-public +0 -1
  2. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.copier-answers.yml +1 -1
  3. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.gitignore +9 -0
  4. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/Dockerfile +3 -0
  5. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/PKG-INFO +21 -6
  6. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/README.md +20 -5
  7. oe_python_template_example-0.0.10/VERSION +1 -0
  8. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/_readme_main.md +20 -5
  9. oe_python_template_example-0.0.10/compose.yaml +35 -0
  10. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/_static/openapi.json +77 -0
  11. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/_static/openapi.yaml +79 -0
  12. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/conf.py +1 -1
  13. oe_python_template_example-0.0.10/github-action-run +5 -0
  14. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/noxfile.py +2 -1
  15. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/pyproject.toml +2 -2
  16. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/sonar-project.properties +1 -1
  17. oe_python_template_example-0.0.10/src/oe_python_template_example/api.py +168 -0
  18. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/src/oe_python_template_example/cli.py +28 -9
  19. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/src/oe_python_template_example/service.py +10 -0
  20. oe_python_template_example-0.0.10/tests/api_test.py +92 -0
  21. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/tests/cli_test.py +1 -1
  22. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/uv.lock +1 -1
  23. oe_python_template_example-0.0.9/.act-secret +0 -1
  24. oe_python_template_example-0.0.9/VERSION +0 -1
  25. oe_python_template_example-0.0.9/compose.yaml +0 -13
  26. oe_python_template_example-0.0.9/github-action-run +0 -4
  27. oe_python_template_example-0.0.9/src/oe_python_template_example/api.py +0 -87
  28. oe_python_template_example-0.0.9/tests/api_test.py +0 -48
  29. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.devcontainer/Dockerfile +0 -0
  30. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.devcontainer/devcontainer.json +0 -0
  31. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.devcontainer/onCreateCommand +0 -0
  32. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.devcontainer/postAttachCommand +0 -0
  33. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.devcontainer/postCreateCommand +0 -0
  34. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.env.example +0 -0
  35. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.github/workflows/docker-image-build-publish.yml +0 -0
  36. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.github/workflows/package-build-publish-release.yml +0 -0
  37. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.github/workflows/test-and-report.yml +0 -0
  38. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.pre-commit-config.yaml +0 -0
  39. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.python-version +0 -0
  40. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.readthedocs.yml +0 -0
  41. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.secrets.baseline +0 -0
  42. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.vscode/extensions.json +0 -0
  43. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/.vscode/settings.json +0 -0
  44. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/CHANGELOG.md +0 -0
  45. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/CODEOWNERS +0 -0
  46. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/CONTRIBUTING.md +0 -0
  47. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/LICENSE +0 -0
  48. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/RELEASE_NOTES.md +0 -0
  49. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/SERVICE_CONNECTIONS.md +0 -0
  50. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/_readme_footer.md +0 -0
  51. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/_readme_header.md +0 -0
  52. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/bin/git-cliff +0 -0
  53. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/bump +0 -0
  54. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/codecov.yml +0 -0
  55. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/Makefile +0 -0
  56. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/make.bat +0 -0
  57. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/_static/.keep +0 -0
  58. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/api.rst +0 -0
  59. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/contributing.rst +0 -0
  60. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/index.rst +0 -0
  61. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/latexmkrc +0 -0
  62. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/main.rst +0 -0
  63. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/reference.rst +0 -0
  64. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/docs/source/release-notes.rst +0 -0
  65. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/examples/__init__.py +0 -0
  66. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/examples/notebook.ipynb +0 -0
  67. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/examples/notebook.py +0 -0
  68. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/examples/script.py +0 -0
  69. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/examples/streamlit.py +0 -0
  70. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/CHANGELOG.md +0 -0
  71. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/LICENSE-APACHE +0 -0
  72. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/LICENSE-MIT +0 -0
  73. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/README.md +0 -0
  74. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/completions/_git-cliff +0 -0
  75. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/completions/_git-cliff.ps1 +0 -0
  76. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/completions/git-cliff.bash +0 -0
  77. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/completions/git-cliff.elv +0 -0
  78. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/completions/git-cliff.fish +0 -0
  79. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/git-cliff-completions +0 -0
  80. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/git-cliff-mangen +0 -0
  81. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0/man/git-cliff.1 +0 -0
  82. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/git-cliff-2.7.0-x86_64-unknown-linux-gnu.tar.gz +0 -0
  83. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/latexmkrc +0 -0
  84. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/logo.png +0 -0
  85. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/renovate.json +0 -0
  86. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/src/oe_python_template_example/__init__.py +0 -0
  87. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/src/oe_python_template_example/constants.py +0 -0
  88. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/tests/__init__.py +0 -0
  89. {oe_python_template_example-0.0.9 → oe_python_template_example-0.0.10}/tests/fixtures/.keep +0 -0
@@ -1,2 +1 @@
1
1
  GITHUB_WORKFLOW_RUNTIME=ACT
2
- ACTIONS_RUNTIME_TOKEN=TOKEN
@@ -1,4 +1,4 @@
1
- _commit: v0.3.6
1
+ _commit: v0.3.9
2
2
  _src_path: gh:helmut-hoffer-von-ankershoffen/oe-python-template
3
3
  author_email: helmuthva@gmail.com
4
4
  author_github_username: helmut-hoffer-von-ankershoffen
@@ -8,6 +8,15 @@ ENV/
8
8
  env/
9
9
  .envrc
10
10
 
11
+ ## secrets
12
+ .secret
13
+ .secrets
14
+ .secrets.toml
15
+ .secrets.yaml
16
+ .secrets.yml
17
+ .secrets.json
18
+ .act-env-secret
19
+
11
20
  # Python virtual environment
12
21
  venv/
13
22
  .venv/
@@ -35,5 +35,8 @@ RUN --mount=type=cache,target=/root/.cache/uv \
35
35
 
36
36
  ENV OE_PYTHON_TEMPLATE_EXAMPLE_RUNNING_IN_CONTAINER=1
37
37
 
38
+ # API will run on port 8000 by default
39
+ EXPOSE 8000/tcp
40
+
38
41
  # But feel free to add arguments and options as needed when doing a docker run
39
42
  ENTRYPOINT ["uv", "run", "--no-dev", "oe-python-template-example"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oe-python-template-example
3
- Version: 0.0.9
3
+ Version: 0.0.10
4
4
  Summary: 🧠 Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
5
5
  Project-URL: Homepage, https://oe-python-template-example.readthedocs.io/en/latest/
6
6
  Project-URL: Documentation, https://oe-python-template-example.readthedocs.io/en/latest/
@@ -184,7 +184,7 @@ uvx oe-python-template-example hello-world --help # help for specific command
184
184
 
185
185
  * Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
186
186
  * Various Examples:
187
- - [Simple Python script]https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
187
+ - [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
188
188
  - [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
189
189
  - [Jupyter](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/notebook.ipynb) and [Marimo](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/notebook.py) notebook
190
190
  * [Complete reference documenation](https://oe-python-template-example.readthedocs.io/en/latest/reference.html) on Read the Docs
@@ -284,8 +284,12 @@ Execute commands:
284
284
 
285
285
  ```shell
286
286
  uvx oe-python-template-example hello-world
287
- uvx oe-python-template-example hello-world --json
288
- uvx oe-python-template-example echo "Lorem Ipsum"
287
+ uvx oe-python-template-example echo --help
288
+ uvx oe-python-template-example echo "Lorem"
289
+ uvx oe-python-template-example echo "Lorem" --json
290
+ uvx oe-python-template-example openapi
291
+ uvx oe-python-template-example openapi --output-format=json
292
+ uvx oe-python-template-example serve
289
293
  ```
290
294
 
291
295
  ### Environment
@@ -306,8 +310,12 @@ You can as well run the CLI within Docker.
306
310
  ```shell
307
311
  docker run helmuthva/oe-python-template-example --help
308
312
  docker run helmuthva/oe-python-template-example hello-world
309
- docker run helmuthva/oe-python-template-example hello-world --json
313
+ docker run helmuthva/oe-python-template-example echo --help
310
314
  docker run helmuthva/oe-python-template-example echo "Lorem"
315
+ docker run helmuthva/oe-python-template-example echo "Lorem" --json
316
+ docker run helmuthva/oe-python-template-example openapi
317
+ docker run helmuthva/oe-python-template-example openapi --output-format=json
318
+ docker run helmuthva/oe-python-template-example serve
311
319
  ```
312
320
 
313
321
  Execute command:
@@ -321,8 +329,15 @@ Or use docker compose
321
329
  The .env is passed through from the host to the Docker container.
322
330
 
323
331
  ```shell
324
- docker compose up
325
332
  docker compose run oe-python-template-example --help
333
+ docker compose run oe-python-template-example hello-world
334
+ docker compose run oe-python-template-example echo --help
335
+ docker compose run oe-python-template-example echo "Lorem"
336
+ docker compose run oe-python-template-example echo "Lorem" --json
337
+ docker compose run oe-python-template-example openapi
338
+ docker compose run oe-python-template-example openapi --output-format=json
339
+ docker compose up
340
+ curl http://127.0.0.1 8000
326
341
  ```
327
342
 
328
343
  ## Extra: Lorem Ipsum
@@ -123,7 +123,7 @@ uvx oe-python-template-example hello-world --help # help for specific command
123
123
 
124
124
  * Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
125
125
  * Various Examples:
126
- - [Simple Python script]https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
126
+ - [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
127
127
  - [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
128
128
  - [Jupyter](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/notebook.ipynb) and [Marimo](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/notebook.py) notebook
129
129
  * [Complete reference documenation](https://oe-python-template-example.readthedocs.io/en/latest/reference.html) on Read the Docs
@@ -223,8 +223,12 @@ Execute commands:
223
223
 
224
224
  ```shell
225
225
  uvx oe-python-template-example hello-world
226
- uvx oe-python-template-example hello-world --json
227
- uvx oe-python-template-example echo "Lorem Ipsum"
226
+ uvx oe-python-template-example echo --help
227
+ uvx oe-python-template-example echo "Lorem"
228
+ uvx oe-python-template-example echo "Lorem" --json
229
+ uvx oe-python-template-example openapi
230
+ uvx oe-python-template-example openapi --output-format=json
231
+ uvx oe-python-template-example serve
228
232
  ```
229
233
 
230
234
  ### Environment
@@ -245,8 +249,12 @@ You can as well run the CLI within Docker.
245
249
  ```shell
246
250
  docker run helmuthva/oe-python-template-example --help
247
251
  docker run helmuthva/oe-python-template-example hello-world
248
- docker run helmuthva/oe-python-template-example hello-world --json
252
+ docker run helmuthva/oe-python-template-example echo --help
249
253
  docker run helmuthva/oe-python-template-example echo "Lorem"
254
+ docker run helmuthva/oe-python-template-example echo "Lorem" --json
255
+ docker run helmuthva/oe-python-template-example openapi
256
+ docker run helmuthva/oe-python-template-example openapi --output-format=json
257
+ docker run helmuthva/oe-python-template-example serve
250
258
  ```
251
259
 
252
260
  Execute command:
@@ -260,8 +268,15 @@ Or use docker compose
260
268
  The .env is passed through from the host to the Docker container.
261
269
 
262
270
  ```shell
263
- docker compose up
264
271
  docker compose run oe-python-template-example --help
272
+ docker compose run oe-python-template-example hello-world
273
+ docker compose run oe-python-template-example echo --help
274
+ docker compose run oe-python-template-example echo "Lorem"
275
+ docker compose run oe-python-template-example echo "Lorem" --json
276
+ docker compose run oe-python-template-example openapi
277
+ docker compose run oe-python-template-example openapi --output-format=json
278
+ docker compose up
279
+ curl http://127.0.0.1 8000
265
280
  ```
266
281
 
267
282
  ## Extra: Lorem Ipsum
@@ -0,0 +1 @@
1
+ 0.0.10
@@ -88,7 +88,7 @@ uvx oe-python-template-example hello-world --help # help for specific command
88
88
 
89
89
  * Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
90
90
  * Various Examples:
91
- - [Simple Python script]https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
91
+ - [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
92
92
  - [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
93
93
  - [Jupyter](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/notebook.ipynb) and [Marimo](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/notebook.py) notebook
94
94
  * [Complete reference documenation](https://oe-python-template-example.readthedocs.io/en/latest/reference.html) on Read the Docs
@@ -188,8 +188,12 @@ Execute commands:
188
188
 
189
189
  ```shell
190
190
  uvx oe-python-template-example hello-world
191
- uvx oe-python-template-example hello-world --json
192
- uvx oe-python-template-example echo "Lorem Ipsum"
191
+ uvx oe-python-template-example echo --help
192
+ uvx oe-python-template-example echo "Lorem"
193
+ uvx oe-python-template-example echo "Lorem" --json
194
+ uvx oe-python-template-example openapi
195
+ uvx oe-python-template-example openapi --output-format=json
196
+ uvx oe-python-template-example serve
193
197
  ```
194
198
 
195
199
  ### Environment
@@ -210,8 +214,12 @@ You can as well run the CLI within Docker.
210
214
  ```shell
211
215
  docker run helmuthva/oe-python-template-example --help
212
216
  docker run helmuthva/oe-python-template-example hello-world
213
- docker run helmuthva/oe-python-template-example hello-world --json
217
+ docker run helmuthva/oe-python-template-example echo --help
214
218
  docker run helmuthva/oe-python-template-example echo "Lorem"
219
+ docker run helmuthva/oe-python-template-example echo "Lorem" --json
220
+ docker run helmuthva/oe-python-template-example openapi
221
+ docker run helmuthva/oe-python-template-example openapi --output-format=json
222
+ docker run helmuthva/oe-python-template-example serve
215
223
  ```
216
224
 
217
225
  Execute command:
@@ -225,8 +233,15 @@ Or use docker compose
225
233
  The .env is passed through from the host to the Docker container.
226
234
 
227
235
  ```shell
228
- docker compose up
229
236
  docker compose run oe-python-template-example --help
237
+ docker compose run oe-python-template-example hello-world
238
+ docker compose run oe-python-template-example echo --help
239
+ docker compose run oe-python-template-example echo "Lorem"
240
+ docker compose run oe-python-template-example echo "Lorem" --json
241
+ docker compose run oe-python-template-example openapi
242
+ docker compose run oe-python-template-example openapi --output-format=json
243
+ docker compose up
244
+ curl http://127.0.0.1 8000
230
245
  ```
231
246
 
232
247
  ## Extra: Lorem Ipsum
@@ -0,0 +1,35 @@
1
+ services:
2
+ oe-python-template-example:
3
+ build: .
4
+ env_file:
5
+ - path: .env
6
+ required: true
7
+ develop:
8
+ watch:
9
+ - path: src
10
+ action: rebuild
11
+ restart: no
12
+ profiles:
13
+ - manual
14
+ tty: true
15
+ stdin_open: true
16
+ oe-python-template-example-api:
17
+ build: .
18
+ env_file:
19
+ - path: .env
20
+ required: true
21
+ develop:
22
+ watch:
23
+ - path: src
24
+ action: rebuild
25
+ command: serve --host=0.0.0.0 --port=8000 --no-reload
26
+ restart: always
27
+ ports:
28
+ - "8000:8000"
29
+ healthcheck:
30
+ test: [ "CMD", "curl", "-f", "http://127.0.0.1:8000/healthz" ]
31
+ interval: 5s
32
+ timeout: 2s
33
+ retries: 3
34
+ start_period: 5s
35
+ start_interval: 1s
@@ -11,6 +11,50 @@
11
11
  "version": "1.0.0"
12
12
  },
13
13
  "paths": {
14
+ "/health": {
15
+ "get": {
16
+ "tags": [
17
+ "Observability"
18
+ ],
19
+ "summary": "Health",
20
+ "description": "Check the health of the service.\n\nThis endpoint returns the health status of the service.\nThe health status can be either UP or DOWN.\nIf the service is healthy, the status will be UP.\nIf the service is unhealthy, the status will be DOWN and a reason will be provided.\nThe response will have a 200 OK status code if the service is healthy,\nand a 500 Internal Server Error status code if the service is unhealthy.\n\nArgs:\n service (Annotated[Service, Depends): _description_\n response (Response): _description_\n\nReturns:\n Health: The health status of the service.",
21
+ "operationId": "health_health_get",
22
+ "responses": {
23
+ "200": {
24
+ "description": "Successful Response",
25
+ "content": {
26
+ "application/json": {
27
+ "schema": {
28
+ "$ref": "#/components/schemas/Health"
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ },
36
+ "/healthz": {
37
+ "get": {
38
+ "tags": [
39
+ "Observability"
40
+ ],
41
+ "summary": "Health",
42
+ "description": "Check the health of the service.\n\nThis endpoint returns the health status of the service.\nThe health status can be either UP or DOWN.\nIf the service is healthy, the status will be UP.\nIf the service is unhealthy, the status will be DOWN and a reason will be provided.\nThe response will have a 200 OK status code if the service is healthy,\nand a 500 Internal Server Error status code if the service is unhealthy.\n\nArgs:\n service (Annotated[Service, Depends): _description_\n response (Response): _description_\n\nReturns:\n Health: The health status of the service.",
43
+ "operationId": "health_healthz_get",
44
+ "responses": {
45
+ "200": {
46
+ "description": "Successful Response",
47
+ "content": {
48
+ "application/json": {
49
+ "schema": {
50
+ "$ref": "#/components/schemas/Health"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ },
14
58
  "/hello-world": {
15
59
  "get": {
16
60
  "tags": [
@@ -129,6 +173,30 @@
129
173
  "type": "object",
130
174
  "title": "HTTPValidationError"
131
175
  },
176
+ "Health": {
177
+ "properties": {
178
+ "status": {
179
+ "$ref": "#/components/schemas/_HealthStatus"
180
+ },
181
+ "reason": {
182
+ "anyOf": [
183
+ {
184
+ "type": "string"
185
+ },
186
+ {
187
+ "type": "null"
188
+ }
189
+ ],
190
+ "title": "Reason"
191
+ }
192
+ },
193
+ "type": "object",
194
+ "required": [
195
+ "status"
196
+ ],
197
+ "title": "Health",
198
+ "description": "Health status model.\n\nArgs:\n BaseModel (_type_): _description_"
199
+ },
132
200
  "HelloWorldResponse": {
133
201
  "properties": {
134
202
  "message": {
@@ -179,6 +247,15 @@
179
247
  "type"
180
248
  ],
181
249
  "title": "ValidationError"
250
+ },
251
+ "_HealthStatus": {
252
+ "type": "string",
253
+ "enum": [
254
+ "UP",
255
+ "DOWN"
256
+ ],
257
+ "title": "_HealthStatus",
258
+ "description": "Health status enumeration.\n\nArgs:\n StrEnum (_type_): _description_"
182
259
  }
183
260
  }
184
261
  }
@@ -37,6 +37,21 @@ components:
37
37
  type: array
38
38
  title: HTTPValidationError
39
39
  type: object
40
+ Health:
41
+ description: "Health status model.\n\nArgs:\n BaseModel (_type_):
42
+ _description_"
43
+ properties:
44
+ reason:
45
+ anyOf:
46
+ - type: string
47
+ - type: 'null'
48
+ title: Reason
49
+ status:
50
+ $ref: '#/components/schemas/_HealthStatus'
51
+ required:
52
+ - status
53
+ title: Health
54
+ type: object
40
55
  HelloWorldResponse:
41
56
  description: Response model for hello-world endpoint.
42
57
  properties:
@@ -71,6 +86,14 @@ components:
71
86
  - type
72
87
  title: ValidationError
73
88
  type: object
89
+ _HealthStatus:
90
+ description: "Health status enumeration.\n\nArgs:\n StrEnum (_type_):
91
+ _description_"
92
+ enum:
93
+ - UP
94
+ - DOWN
95
+ title: _HealthStatus
96
+ type: string
74
97
  info:
75
98
  contact:
76
99
  email: helmuthva@gmail.com
@@ -113,6 +136,62 @@ Unprocessable\
113
136
  summary: Echo
114
137
  tags:
115
138
  - Basics
139
+ /health:
140
+ get:
141
+ description: "Check the health of the service.\n\nThis endpoint returns
142
+ the\
143
+ \ health status of the service.\nThe health status can be either UP or
144
+ DOWN.\n\
145
+ If the service is healthy, the status will be UP.\nIf the service is
146
+ unhealthy,\
147
+ \ the status will be DOWN and a reason will be provided.\nThe response
148
+ will\
149
+ \ have a 200 OK status code if the service is healthy,\nand a 500
150
+ Internal\
151
+ \ Server Error status code if the service is unhealthy.\n\nArgs:\n
152
+ service\
153
+ \ (Annotated[Service, Depends): _description_\n response (Response):
154
+ _description_\n\
155
+ \nReturns:\n Health: The health status of the service."
156
+ operationId: health_health_get
157
+ responses:
158
+ '200':
159
+ content:
160
+ application/json:
161
+ schema:
162
+ $ref: '#/components/schemas/Health'
163
+ description: Successful Response
164
+ summary: Health
165
+ tags:
166
+ - Observability
167
+ /healthz:
168
+ get:
169
+ description: "Check the health of the service.\n\nThis endpoint returns
170
+ the\
171
+ \ health status of the service.\nThe health status can be either UP or
172
+ DOWN.\n\
173
+ If the service is healthy, the status will be UP.\nIf the service is
174
+ unhealthy,\
175
+ \ the status will be DOWN and a reason will be provided.\nThe response
176
+ will\
177
+ \ have a 200 OK status code if the service is healthy,\nand a 500
178
+ Internal\
179
+ \ Server Error status code if the service is unhealthy.\n\nArgs:\n
180
+ service\
181
+ \ (Annotated[Service, Depends): _description_\n response (Response):
182
+ _description_\n\
183
+ \nReturns:\n Health: The health status of the service."
184
+ operationId: health_healthz_get
185
+ responses:
186
+ '200':
187
+ content:
188
+ application/json:
189
+ schema:
190
+ $ref: '#/components/schemas/Health'
191
+ description: Successful Response
192
+ summary: Health
193
+ tags:
194
+ - Observability
116
195
  /hello-world:
117
196
  get:
118
197
  description: "Return a hello world message.\n\nReturns:\n
@@ -26,7 +26,7 @@ extensions = [
26
26
  project = "oe-python-template-example"
27
27
  author = "Helmut Hoffer von Ankershoffen"
28
28
  copyright = f" (c) 2025-{datetime.now(UTC).year}, {author}" # noqa: A001
29
- version = "0.0.9"
29
+ version = "0.0.10"
30
30
  release = version
31
31
  github_username = "helmut-hoffer-von-ankershoffen"
32
32
  github_repository = "oe-python-template-example"
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+
3
+ # Locally run job test of CI workflow in .github/workflows/test-and-report.yml. Helpful for debugging.
4
+ act -j test --env-file .act-env-public --secret-file .act-env-secret --container-architecture linux/amd64 -P
5
+ ubuntu-latest=catthehacker/ubuntu:act-latest --action-offline-mode --container-daemon-socket -
@@ -117,7 +117,8 @@ def setup_dev(session: nox.Session) -> None:
117
117
  session.run("ruff", "format", ".", external=True)
118
118
  git_dir = Path(".git")
119
119
  if git_dir.is_dir():
120
- session.run("echo", "found .git directory, running pre-commit install and hooks", external=True)
120
+ session.run("echo", "found .git directory", external=True)
121
+ session.run("touch", ".act-env-secret", external=True)
121
122
  session.run("pre-commit", "install", external=True)
122
123
  with Path(".secrets.baseline").open("w", encoding="utf-8") as out:
123
124
  session.run("detect-secrets", "scan", stdout=out, external=True)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "oe-python-template-example"
3
- version = "0.0.9"
3
+ version = "0.0.10"
4
4
  description = "🧠 Example project scaffolded and kept up to date with OE Python Template (oe-python-template)."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -244,7 +244,7 @@ source = ["src/"]
244
244
 
245
245
 
246
246
  [tool.bumpversion]
247
- current_version = "0.0.9"
247
+ current_version = "0.0.10"
248
248
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
249
249
  serialize = ["{major}.{minor}.{patch}"]
250
250
  search = "{current_version}"
@@ -1,6 +1,6 @@
1
1
  sonar.projectKey=helmut-hoffer-von-ankershoffen_oe-python-template-example
2
2
  sonar.organization=helmut-hoffer-von-ankershoffen
3
- sonar.projectVersion=0.0.9
3
+ sonar.projectVersion=0.0.10
4
4
  sonar.projectDescription=🧠 Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
5
5
  sonar.links.homepage=https://oe-python-template-example.readthedocs.io/en/latest/
6
6
  sonar.links.scm=https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example
@@ -0,0 +1,168 @@
1
+ """Webservice API of OE Python Template Example.
2
+
3
+ This module provides a webservice API with several endpoints:
4
+ - A health/healthz endpoint that returns the health status of the service
5
+ - A hello-world endpoint that returns a greeting message
6
+ - An echo endpoint that echoes back the provided text
7
+
8
+ The endpoints use Pydantic models for request and response validation.
9
+ """
10
+
11
+ from collections.abc import Generator
12
+ from enum import StrEnum
13
+ from typing import Annotated
14
+
15
+ from fastapi import Depends, FastAPI, Response, status
16
+ from pydantic import BaseModel, Field
17
+
18
+ from oe_python_template_example import Service
19
+
20
+ HELLO_WORLD_EXAMPLE = "Hello, world!"
21
+
22
+
23
+ def get_service() -> Generator[Service, None, None]:
24
+ """Get the service instance.
25
+
26
+ Yields:
27
+ Service: The service instance.
28
+ """
29
+ service = Service()
30
+ try:
31
+ yield service
32
+ finally:
33
+ # Cleanup code if needed
34
+ pass
35
+
36
+
37
+ app = FastAPI(
38
+ version="1.0.0",
39
+ title="OE Python Template Example",
40
+ contact={
41
+ "name": "Helmut Hoffer von Ankershoffen",
42
+ "email": "helmuthva@gmail.com",
43
+ "url": "https://github.com/helmut-hoffer-von-ankershoffen",
44
+ },
45
+ terms_of_service="https://oe-python-template-example.readthedocs.io/en/latest/",
46
+ )
47
+
48
+
49
+ class _HealthStatus(StrEnum):
50
+ """Health status enumeration.
51
+
52
+ Args:
53
+ StrEnum (_type_): _description_
54
+ """
55
+
56
+ UP = "UP"
57
+ DOWN = "DOWN"
58
+
59
+
60
+ class Health(BaseModel):
61
+ """Health status model.
62
+
63
+ Args:
64
+ BaseModel (_type_): _description_
65
+ """
66
+
67
+ status: _HealthStatus
68
+ reason: str | None = None
69
+
70
+
71
+ class HealthResponse(BaseModel):
72
+ """Response model for health endpoint."""
73
+
74
+ health: str = Field(
75
+ ...,
76
+ description="The hello world message",
77
+ examples=[HELLO_WORLD_EXAMPLE],
78
+ )
79
+
80
+
81
+ @app.get("/healthz", tags=["Observability"])
82
+ @app.get("/health", tags=["Observability"])
83
+ async def health(service: Annotated[Service, Depends(get_service)], response: Response) -> Health:
84
+ """Check the health of the service.
85
+
86
+ This endpoint returns the health status of the service.
87
+ The health status can be either UP or DOWN.
88
+ If the service is healthy, the status will be UP.
89
+ If the service is unhealthy, the status will be DOWN and a reason will be provided.
90
+ The response will have a 200 OK status code if the service is healthy,
91
+ and a 500 Internal Server Error status code if the service is unhealthy.
92
+
93
+ Args:
94
+ service (Annotated[Service, Depends): _description_
95
+ response (Response): _description_
96
+
97
+ Returns:
98
+ Health: The health status of the service.
99
+ """
100
+ if service.healthy():
101
+ health_result = Health(status=_HealthStatus.UP)
102
+ else:
103
+ health_result = Health(status=_HealthStatus.DOWN, reason="Service is unhealthy")
104
+
105
+ if health_result.status == _HealthStatus.DOWN:
106
+ response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
107
+
108
+ return health_result
109
+
110
+
111
+ class HelloWorldResponse(BaseModel):
112
+ """Response model for hello-world endpoint."""
113
+
114
+ message: str = Field(
115
+ ...,
116
+ description="The hello world message",
117
+ examples=[HELLO_WORLD_EXAMPLE],
118
+ )
119
+
120
+
121
+ @app.get("/hello-world", tags=["Basics"])
122
+ async def hello_world() -> HelloWorldResponse:
123
+ """
124
+ Return a hello world message.
125
+
126
+ Returns:
127
+ HelloWorldResponse: A response containing the hello world message.
128
+ """
129
+ return HelloWorldResponse(message=Service.get_hello_world())
130
+
131
+
132
+ class EchoResponse(BaseModel):
133
+ """Response model for echo endpoint."""
134
+
135
+ message: str = Field(
136
+ ...,
137
+ min_length=1,
138
+ description="The message content",
139
+ examples=[HELLO_WORLD_EXAMPLE],
140
+ )
141
+
142
+
143
+ class EchoRequest(BaseModel):
144
+ """Request model for echo endpoint."""
145
+
146
+ text: str = Field(
147
+ ...,
148
+ min_length=1,
149
+ description="The text to echo back",
150
+ examples=[HELLO_WORLD_EXAMPLE],
151
+ )
152
+
153
+
154
+ @app.post("/echo", tags=["Basics"])
155
+ async def echo(request: EchoRequest) -> EchoResponse:
156
+ """
157
+ Echo back the provided text.
158
+
159
+ Args:
160
+ request (EchoRequest): The request containing the text to echo back.
161
+
162
+ Returns:
163
+ EchoResponse: A response containing the echoed text.
164
+
165
+ Raises:
166
+ 422 Unprocessable Entity: If text is not provided or empty.
167
+ """
168
+ return EchoResponse(message=request.text)