oe-python-template-example 0.0.10__tar.gz → 0.1.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.
Files changed (90) hide show
  1. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.copier-answers.yml +1 -1
  2. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.pre-commit-config.yaml +1 -0
  3. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/PKG-INFO +38 -17
  4. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/README.md +37 -16
  5. oe_python_template_example-0.1.0/VERSION +1 -0
  6. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/_readme_main.md +37 -16
  7. oe_python_template_example-0.1.0/docs/source/_static/openapi_v1.json +262 -0
  8. oe_python_template_example-0.1.0/docs/source/_static/openapi_v1.yaml +210 -0
  9. oe_python_template_example-0.1.0/docs/source/_static/openapi_v2.json +262 -0
  10. oe_python_template_example-0.1.0/docs/source/_static/openapi_v2.yaml +210 -0
  11. oe_python_template_example-0.1.0/docs/source/api_v1.rst +5 -0
  12. oe_python_template_example-0.1.0/docs/source/api_v2.rst +5 -0
  13. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/conf.py +1 -1
  14. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/index.rst +2 -1
  15. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/examples/notebook.py +1 -1
  16. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/noxfile.py +12 -4
  17. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/pyproject.toml +3 -2
  18. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/sonar-project.properties +1 -1
  19. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/src/oe_python_template_example/api.py +74 -5
  20. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/src/oe_python_template_example/cli.py +26 -3
  21. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/tests/api_test.py +54 -20
  22. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/tests/cli_test.py +12 -1
  23. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/uv.lock +12 -1
  24. oe_python_template_example-0.0.10/VERSION +0 -1
  25. oe_python_template_example-0.0.10/docs/source/api.rst +0 -5
  26. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.act-env-public +0 -0
  27. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.devcontainer/Dockerfile +0 -0
  28. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.devcontainer/devcontainer.json +0 -0
  29. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.devcontainer/onCreateCommand +0 -0
  30. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.devcontainer/postAttachCommand +0 -0
  31. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.devcontainer/postCreateCommand +0 -0
  32. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.env.example +0 -0
  33. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.github/workflows/docker-image-build-publish.yml +0 -0
  34. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.github/workflows/package-build-publish-release.yml +0 -0
  35. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.github/workflows/test-and-report.yml +0 -0
  36. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.gitignore +0 -0
  37. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.python-version +0 -0
  38. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.readthedocs.yml +0 -0
  39. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.secrets.baseline +0 -0
  40. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.vscode/extensions.json +0 -0
  41. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/.vscode/settings.json +0 -0
  42. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/CHANGELOG.md +0 -0
  43. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/CODEOWNERS +0 -0
  44. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/CONTRIBUTING.md +0 -0
  45. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/Dockerfile +0 -0
  46. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/LICENSE +0 -0
  47. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/RELEASE_NOTES.md +0 -0
  48. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/SERVICE_CONNECTIONS.md +0 -0
  49. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/_readme_footer.md +0 -0
  50. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/_readme_header.md +0 -0
  51. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/bin/git-cliff +0 -0
  52. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/bump +0 -0
  53. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/codecov.yml +0 -0
  54. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/compose.yaml +0 -0
  55. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/Makefile +0 -0
  56. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/make.bat +0 -0
  57. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/_static/.keep +0 -0
  58. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/_static/openapi.json +0 -0
  59. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/_static/openapi.yaml +0 -0
  60. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/contributing.rst +0 -0
  61. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/latexmkrc +0 -0
  62. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/main.rst +0 -0
  63. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/reference.rst +0 -0
  64. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/docs/source/release-notes.rst +0 -0
  65. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/examples/__init__.py +0 -0
  66. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/examples/notebook.ipynb +0 -0
  67. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/examples/script.py +0 -0
  68. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/examples/streamlit.py +0 -0
  69. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/CHANGELOG.md +0 -0
  70. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/LICENSE-APACHE +0 -0
  71. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/LICENSE-MIT +0 -0
  72. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/README.md +0 -0
  73. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/completions/_git-cliff +0 -0
  74. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/completions/_git-cliff.ps1 +0 -0
  75. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/completions/git-cliff.bash +0 -0
  76. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/completions/git-cliff.elv +0 -0
  77. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/completions/git-cliff.fish +0 -0
  78. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/git-cliff-completions +0 -0
  79. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/git-cliff-mangen +0 -0
  80. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0/man/git-cliff.1 +0 -0
  81. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/git-cliff-2.7.0-x86_64-unknown-linux-gnu.tar.gz +0 -0
  82. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/github-action-run +0 -0
  83. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/latexmkrc +0 -0
  84. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/logo.png +0 -0
  85. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/renovate.json +0 -0
  86. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/src/oe_python_template_example/__init__.py +0 -0
  87. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/src/oe_python_template_example/constants.py +0 -0
  88. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/src/oe_python_template_example/service.py +0 -0
  89. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/tests/__init__.py +0 -0
  90. {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.0}/tests/fixtures/.keep +0 -0
@@ -1,4 +1,4 @@
1
- _commit: v0.3.9
1
+ _commit: v0.4.2
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
@@ -14,6 +14,7 @@ repos:
14
14
  hooks:
15
15
  - id: python-check-blanket-noqa
16
16
  - id: python-check-blanket-type-ignore
17
+ exclude: "^examples/notebook.py$"
17
18
  - id: python-check-mock-methods
18
19
  - id: python-no-eval
19
20
  - id: python-no-log-warn
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oe-python-template-example
3
- Version: 0.0.10
3
+ Version: 0.1.0
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/
@@ -101,9 +101,9 @@ Use Cases:
101
101
  2) Consistent update of already scaffolded projects to benefit from new and improved features.
102
102
  3) Dummy CLI application and service demonstrating example usage of the generated directory structure and build pipeline
103
103
 
104
- ## Scaffolding Instructions
104
+ ## Scaffolding
105
105
 
106
- Step 1: Install uv package manager and copier
106
+ **Step 1**: Install uv package manager and copier
107
107
  ```shell
108
108
  if [[ "$OSTYPE" == "darwin"* ]]; then # Install dependencies for macOS X
109
109
  if ! command -v brew &> /dev/null; then ## Install Homebrew if not present
@@ -119,31 +119,32 @@ fi
119
119
  uv tool install copier # Install copier as global tool
120
120
  ```
121
121
 
122
- Step 2: Now create an empty repo on GitHub and clone it to your local machine in a directory of your choice. Change to that directory.
122
+ **Step 2**: Now create an empty repository on GitHubm, clone to your local machine, and change into it's directory.
123
123
 
124
- Step 3: Scaffold the project
124
+ **Step 3**: Scaffold the project
125
125
  ```shell
126
126
  copier copy gh:helmut-hoffer-von-ankershoffen/oe-python-template .
127
127
  ```
128
- Step 4: Setup the local environment
128
+ **Step 4**: Setup the local environment
129
129
 
130
130
  ```shell
131
131
  uv run nox -s setup_dev
132
132
  ```
133
133
 
134
- Step 5: Perform inital commit and push
134
+ **Step 5**: Perform initial commit and push
135
135
  ```shell
136
136
  git add .
137
137
  git commit -m "feat: Initial commit"
138
+ git push
138
139
  ```
139
140
 
140
141
  Visit your GitHub repository and check the Actions tab. The CI workflow should fail at the SonarQube step,
141
142
  as this external service is not yet configured for our new repository.
142
143
 
143
- Step 6: Follow the instructions in SERVICE_CONNECTIONS.md to setup the connections to external services
144
- such as Cloudcov, SonarQube Cloud, Read The Docs, Docker.io, GHCR.io and Streamlit Community Cloud.
144
+ **Step 6**: Follow the [SERVICE_INSTRUCTIONS.md](instructions) to wire up
145
+ external services such as Cloudcov, SonarQube Cloud, Read The Docs, Docker.io, GHCR.io and Streamlit Community Cloud.
145
146
 
146
- Step 7: Release the first versions
147
+ **Step 7**: Release the first versions
147
148
  ```shell
148
149
  ./bump
149
150
  ```
@@ -166,24 +167,38 @@ If you don't have uv installed follow [these instructions](https://docs.astral.s
166
167
  pip install oe-python-template-example # add dependency to your project
167
168
  ```
168
169
 
169
- Executing the command line interface (CLI) is just as easy:
170
+ Executing the command line interface (CLI) in an isolated Python environment is just as easy:
170
171
 
171
172
  ```shell
172
- uvx oe-python-template-example
173
+ uvx oe-python-template-example hello-world # prints "Hello, world! [..]"
174
+ uvx oe-python-template-example serve # serves webservice API
173
175
  ```
174
176
 
177
+ When serving the API, go to [http://127.0.0.1:8000/api/v1/hello-world](http://127.0.0.1:8000/api/v1/hello-world) to see the result.
178
+
179
+ The API is versioned and provides interactive documentation at [http://127.0.0.1:8000/api/v1/docs](http://127.0.0.1:8000/api/v1/docs) resp. [http://127.0.0.1:8000/api/v2/docs](http://127.0.0.1:8000/api/v2/docs)
180
+
181
+
182
+ ```shell
183
+
184
+ When running the webservice API, goto http://127.0.0.1:8000/api/v1/docs
185
+
175
186
  The CLI provides extensive help:
176
187
 
177
188
  ```shell
178
189
  uvx oe-python-template-example --help # all CLI commands
179
190
  uvx oe-python-template-example hello-world --help # help for specific command
191
+ uvx oe-python-template-example echo --help
192
+ uvx oe-python-template-example openapi --help
193
+ uvx oe-python-template-example serve --help
180
194
  ```
181
195
 
182
196
 
183
- ## Highlights
197
+ ## Operational Excellence
198
+
199
+ This project is designed with operational excellence in mind, using modern Python tooling and practices. It includes:
184
200
 
185
- * Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
186
- * Various Examples:
201
+ * Various examples demonstrating usage:
187
202
  - [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
188
203
  - [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
189
204
  - [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
@@ -199,6 +214,9 @@ uvx oe-python-template-example hello-world --help # help for specific command
199
214
 
200
215
  ## Usage Examples
201
216
 
217
+ The following examples run from source. Clone this repository first using
218
+ `git clone git@github.com:helmut-hoffer-von-ankershoffen/oe-python-template-example.git`.
219
+
202
220
  ### Minimal Python Script:
203
221
 
204
222
  ```python
@@ -240,7 +258,7 @@ uv run streamlit run examples/streamlit.py # Serve on localhost:8501, o
240
258
  ... or run within VSCode
241
259
 
242
260
  ```shell
243
- uv sync --all-extras # Install ipykernel dependency part of the examples extra, see pyproject.toml
261
+ uv sync --all-extras # Install dependencies required for examples such as Juypyter kernel, see pyproject.toml
244
262
  ```
245
263
  Install the [Jupyter extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
246
264
 
@@ -337,7 +355,10 @@ docker compose run oe-python-template-example echo "Lorem" --json
337
355
  docker compose run oe-python-template-example openapi
338
356
  docker compose run oe-python-template-example openapi --output-format=json
339
357
  docker compose up
340
- curl http://127.0.0.1 8000
358
+ curl http://127.0.0.1:8000/api/v1/hello-world
359
+ curl http://127.0.0.1:8000/api/v1/docs
360
+ curl http://127.0.0.1:8000/api/v2/hello-world
361
+ curl http://127.0.0.1:8000/api/v2/docs
341
362
  ```
342
363
 
343
364
  ## Extra: Lorem Ipsum
@@ -40,9 +40,9 @@ Use Cases:
40
40
  2) Consistent update of already scaffolded projects to benefit from new and improved features.
41
41
  3) Dummy CLI application and service demonstrating example usage of the generated directory structure and build pipeline
42
42
 
43
- ## Scaffolding Instructions
43
+ ## Scaffolding
44
44
 
45
- Step 1: Install uv package manager and copier
45
+ **Step 1**: Install uv package manager and copier
46
46
  ```shell
47
47
  if [[ "$OSTYPE" == "darwin"* ]]; then # Install dependencies for macOS X
48
48
  if ! command -v brew &> /dev/null; then ## Install Homebrew if not present
@@ -58,31 +58,32 @@ fi
58
58
  uv tool install copier # Install copier as global tool
59
59
  ```
60
60
 
61
- Step 2: Now create an empty repo on GitHub and clone it to your local machine in a directory of your choice. Change to that directory.
61
+ **Step 2**: Now create an empty repository on GitHubm, clone to your local machine, and change into it's directory.
62
62
 
63
- Step 3: Scaffold the project
63
+ **Step 3**: Scaffold the project
64
64
  ```shell
65
65
  copier copy gh:helmut-hoffer-von-ankershoffen/oe-python-template .
66
66
  ```
67
- Step 4: Setup the local environment
67
+ **Step 4**: Setup the local environment
68
68
 
69
69
  ```shell
70
70
  uv run nox -s setup_dev
71
71
  ```
72
72
 
73
- Step 5: Perform inital commit and push
73
+ **Step 5**: Perform initial commit and push
74
74
  ```shell
75
75
  git add .
76
76
  git commit -m "feat: Initial commit"
77
+ git push
77
78
  ```
78
79
 
79
80
  Visit your GitHub repository and check the Actions tab. The CI workflow should fail at the SonarQube step,
80
81
  as this external service is not yet configured for our new repository.
81
82
 
82
- Step 6: Follow the instructions in SERVICE_CONNECTIONS.md to setup the connections to external services
83
- such as Cloudcov, SonarQube Cloud, Read The Docs, Docker.io, GHCR.io and Streamlit Community Cloud.
83
+ **Step 6**: Follow the [SERVICE_INSTRUCTIONS.md](instructions) to wire up
84
+ external services such as Cloudcov, SonarQube Cloud, Read The Docs, Docker.io, GHCR.io and Streamlit Community Cloud.
84
85
 
85
- Step 7: Release the first versions
86
+ **Step 7**: Release the first versions
86
87
  ```shell
87
88
  ./bump
88
89
  ```
@@ -105,24 +106,38 @@ If you don't have uv installed follow [these instructions](https://docs.astral.s
105
106
  pip install oe-python-template-example # add dependency to your project
106
107
  ```
107
108
 
108
- Executing the command line interface (CLI) is just as easy:
109
+ Executing the command line interface (CLI) in an isolated Python environment is just as easy:
109
110
 
110
111
  ```shell
111
- uvx oe-python-template-example
112
+ uvx oe-python-template-example hello-world # prints "Hello, world! [..]"
113
+ uvx oe-python-template-example serve # serves webservice API
112
114
  ```
113
115
 
116
+ When serving the API, go to [http://127.0.0.1:8000/api/v1/hello-world](http://127.0.0.1:8000/api/v1/hello-world) to see the result.
117
+
118
+ The API is versioned and provides interactive documentation at [http://127.0.0.1:8000/api/v1/docs](http://127.0.0.1:8000/api/v1/docs) resp. [http://127.0.0.1:8000/api/v2/docs](http://127.0.0.1:8000/api/v2/docs)
119
+
120
+
121
+ ```shell
122
+
123
+ When running the webservice API, goto http://127.0.0.1:8000/api/v1/docs
124
+
114
125
  The CLI provides extensive help:
115
126
 
116
127
  ```shell
117
128
  uvx oe-python-template-example --help # all CLI commands
118
129
  uvx oe-python-template-example hello-world --help # help for specific command
130
+ uvx oe-python-template-example echo --help
131
+ uvx oe-python-template-example openapi --help
132
+ uvx oe-python-template-example serve --help
119
133
  ```
120
134
 
121
135
 
122
- ## Highlights
136
+ ## Operational Excellence
137
+
138
+ This project is designed with operational excellence in mind, using modern Python tooling and practices. It includes:
123
139
 
124
- * Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
125
- * Various Examples:
140
+ * Various examples demonstrating usage:
126
141
  - [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
127
142
  - [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
128
143
  - [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
@@ -138,6 +153,9 @@ uvx oe-python-template-example hello-world --help # help for specific command
138
153
 
139
154
  ## Usage Examples
140
155
 
156
+ The following examples run from source. Clone this repository first using
157
+ `git clone git@github.com:helmut-hoffer-von-ankershoffen/oe-python-template-example.git`.
158
+
141
159
  ### Minimal Python Script:
142
160
 
143
161
  ```python
@@ -179,7 +197,7 @@ uv run streamlit run examples/streamlit.py # Serve on localhost:8501, o
179
197
  ... or run within VSCode
180
198
 
181
199
  ```shell
182
- uv sync --all-extras # Install ipykernel dependency part of the examples extra, see pyproject.toml
200
+ uv sync --all-extras # Install dependencies required for examples such as Juypyter kernel, see pyproject.toml
183
201
  ```
184
202
  Install the [Jupyter extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
185
203
 
@@ -276,7 +294,10 @@ docker compose run oe-python-template-example echo "Lorem" --json
276
294
  docker compose run oe-python-template-example openapi
277
295
  docker compose run oe-python-template-example openapi --output-format=json
278
296
  docker compose up
279
- curl http://127.0.0.1 8000
297
+ curl http://127.0.0.1:8000/api/v1/hello-world
298
+ curl http://127.0.0.1:8000/api/v1/docs
299
+ curl http://127.0.0.1:8000/api/v2/hello-world
300
+ curl http://127.0.0.1:8000/api/v2/docs
280
301
  ```
281
302
 
282
303
  ## Extra: Lorem Ipsum
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -5,9 +5,9 @@ Use Cases:
5
5
  2) Consistent update of already scaffolded projects to benefit from new and improved features.
6
6
  3) Dummy CLI application and service demonstrating example usage of the generated directory structure and build pipeline
7
7
 
8
- ## Scaffolding Instructions
8
+ ## Scaffolding
9
9
 
10
- Step 1: Install uv package manager and copier
10
+ **Step 1**: Install uv package manager and copier
11
11
  ```shell
12
12
  if [[ "$OSTYPE" == "darwin"* ]]; then # Install dependencies for macOS X
13
13
  if ! command -v brew &> /dev/null; then ## Install Homebrew if not present
@@ -23,31 +23,32 @@ fi
23
23
  uv tool install copier # Install copier as global tool
24
24
  ```
25
25
 
26
- Step 2: Now create an empty repo on GitHub and clone it to your local machine in a directory of your choice. Change to that directory.
26
+ **Step 2**: Now create an empty repository on GitHubm, clone to your local machine, and change into it's directory.
27
27
 
28
- Step 3: Scaffold the project
28
+ **Step 3**: Scaffold the project
29
29
  ```shell
30
30
  copier copy gh:helmut-hoffer-von-ankershoffen/oe-python-template .
31
31
  ```
32
- Step 4: Setup the local environment
32
+ **Step 4**: Setup the local environment
33
33
 
34
34
  ```shell
35
35
  uv run nox -s setup_dev
36
36
  ```
37
37
 
38
- Step 5: Perform inital commit and push
38
+ **Step 5**: Perform initial commit and push
39
39
  ```shell
40
40
  git add .
41
41
  git commit -m "feat: Initial commit"
42
+ git push
42
43
  ```
43
44
 
44
45
  Visit your GitHub repository and check the Actions tab. The CI workflow should fail at the SonarQube step,
45
46
  as this external service is not yet configured for our new repository.
46
47
 
47
- Step 6: Follow the instructions in SERVICE_CONNECTIONS.md to setup the connections to external services
48
- such as Cloudcov, SonarQube Cloud, Read The Docs, Docker.io, GHCR.io and Streamlit Community Cloud.
48
+ **Step 6**: Follow the [SERVICE_INSTRUCTIONS.md](instructions) to wire up
49
+ external services such as Cloudcov, SonarQube Cloud, Read The Docs, Docker.io, GHCR.io and Streamlit Community Cloud.
49
50
 
50
- Step 7: Release the first versions
51
+ **Step 7**: Release the first versions
51
52
  ```shell
52
53
  ./bump
53
54
  ```
@@ -70,24 +71,38 @@ If you don't have uv installed follow [these instructions](https://docs.astral.s
70
71
  pip install oe-python-template-example # add dependency to your project
71
72
  ```
72
73
 
73
- Executing the command line interface (CLI) is just as easy:
74
+ Executing the command line interface (CLI) in an isolated Python environment is just as easy:
74
75
 
75
76
  ```shell
76
- uvx oe-python-template-example
77
+ uvx oe-python-template-example hello-world # prints "Hello, world! [..]"
78
+ uvx oe-python-template-example serve # serves webservice API
77
79
  ```
78
80
 
81
+ When serving the API, go to [http://127.0.0.1:8000/api/v1/hello-world](http://127.0.0.1:8000/api/v1/hello-world) to see the result.
82
+
83
+ The API is versioned and provides interactive documentation at [http://127.0.0.1:8000/api/v1/docs](http://127.0.0.1:8000/api/v1/docs) resp. [http://127.0.0.1:8000/api/v2/docs](http://127.0.0.1:8000/api/v2/docs)
84
+
85
+
86
+ ```shell
87
+
88
+ When running the webservice API, goto http://127.0.0.1:8000/api/v1/docs
89
+
79
90
  The CLI provides extensive help:
80
91
 
81
92
  ```shell
82
93
  uvx oe-python-template-example --help # all CLI commands
83
94
  uvx oe-python-template-example hello-world --help # help for specific command
95
+ uvx oe-python-template-example echo --help
96
+ uvx oe-python-template-example openapi --help
97
+ uvx oe-python-template-example serve --help
84
98
  ```
85
99
 
86
100
 
87
- ## Highlights
101
+ ## Operational Excellence
102
+
103
+ This project is designed with operational excellence in mind, using modern Python tooling and practices. It includes:
88
104
 
89
- * Example project scaffolded and kept up to date with OE Python Template (oe-python-template).
90
- * Various Examples:
105
+ * Various examples demonstrating usage:
91
106
  - [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
92
107
  - [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
93
108
  - [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
@@ -103,6 +118,9 @@ uvx oe-python-template-example hello-world --help # help for specific command
103
118
 
104
119
  ## Usage Examples
105
120
 
121
+ The following examples run from source. Clone this repository first using
122
+ `git clone git@github.com:helmut-hoffer-von-ankershoffen/oe-python-template-example.git`.
123
+
106
124
  ### Minimal Python Script:
107
125
 
108
126
  ```python
@@ -144,7 +162,7 @@ uv run streamlit run examples/streamlit.py # Serve on localhost:8501, o
144
162
  ... or run within VSCode
145
163
 
146
164
  ```shell
147
- uv sync --all-extras # Install ipykernel dependency part of the examples extra, see pyproject.toml
165
+ uv sync --all-extras # Install dependencies required for examples such as Juypyter kernel, see pyproject.toml
148
166
  ```
149
167
  Install the [Jupyter extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
150
168
 
@@ -241,7 +259,10 @@ docker compose run oe-python-template-example echo "Lorem" --json
241
259
  docker compose run oe-python-template-example openapi
242
260
  docker compose run oe-python-template-example openapi --output-format=json
243
261
  docker compose up
244
- curl http://127.0.0.1 8000
262
+ curl http://127.0.0.1:8000/api/v1/hello-world
263
+ curl http://127.0.0.1:8000/api/v1/docs
264
+ curl http://127.0.0.1:8000/api/v2/hello-world
265
+ curl http://127.0.0.1:8000/api/v2/docs
245
266
  ```
246
267
 
247
268
  ## Extra: Lorem Ipsum
@@ -0,0 +1,262 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "OE Python Template Example",
5
+ "termsOfService": "https://oe-python-template-example.readthedocs.io/en/latest/",
6
+ "contact": {
7
+ "name": "Helmut Hoffer von Ankershoffen",
8
+ "url": "https://github.com/helmut-hoffer-von-ankershoffen",
9
+ "email": "helmuthva@gmail.com"
10
+ },
11
+ "version": "1.0.0"
12
+ },
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
+ },
58
+ "/hello-world": {
59
+ "get": {
60
+ "tags": [
61
+ "Basics"
62
+ ],
63
+ "summary": "Hello World",
64
+ "description": "Return a hello world message.\n\nReturns:\n HelloWorldResponse: A response containing the hello world message.",
65
+ "operationId": "hello_world_hello_world_get",
66
+ "responses": {
67
+ "200": {
68
+ "description": "Successful Response",
69
+ "content": {
70
+ "application/json": {
71
+ "schema": {
72
+ "$ref": "#/components/schemas/HelloWorldResponse"
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ },
80
+ "/echo": {
81
+ "post": {
82
+ "tags": [
83
+ "Basics"
84
+ ],
85
+ "summary": "Echo",
86
+ "description": "Echo back the provided text.\n\nArgs:\n request (EchoRequest): The request containing the text to echo back.\n\nReturns:\n EchoResponse: A response containing the echoed text.\n\nRaises:\n 422 Unprocessable Entity: If text is not provided or empty.",
87
+ "operationId": "echo_echo_post",
88
+ "requestBody": {
89
+ "content": {
90
+ "application/json": {
91
+ "schema": {
92
+ "$ref": "#/components/schemas/EchoRequest"
93
+ }
94
+ }
95
+ },
96
+ "required": true
97
+ },
98
+ "responses": {
99
+ "200": {
100
+ "description": "Successful Response",
101
+ "content": {
102
+ "application/json": {
103
+ "schema": {
104
+ "$ref": "#/components/schemas/EchoResponse"
105
+ }
106
+ }
107
+ }
108
+ },
109
+ "422": {
110
+ "description": "Validation Error",
111
+ "content": {
112
+ "application/json": {
113
+ "schema": {
114
+ "$ref": "#/components/schemas/HTTPValidationError"
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ },
123
+ "components": {
124
+ "schemas": {
125
+ "EchoRequest": {
126
+ "properties": {
127
+ "text": {
128
+ "type": "string",
129
+ "minLength": 1,
130
+ "title": "Text",
131
+ "description": "The text to echo back",
132
+ "examples": [
133
+ "Hello, world!"
134
+ ]
135
+ }
136
+ },
137
+ "type": "object",
138
+ "required": [
139
+ "text"
140
+ ],
141
+ "title": "EchoRequest",
142
+ "description": "Request model for echo endpoint."
143
+ },
144
+ "EchoResponse": {
145
+ "properties": {
146
+ "message": {
147
+ "type": "string",
148
+ "minLength": 1,
149
+ "title": "Message",
150
+ "description": "The message content",
151
+ "examples": [
152
+ "Hello, world!"
153
+ ]
154
+ }
155
+ },
156
+ "type": "object",
157
+ "required": [
158
+ "message"
159
+ ],
160
+ "title": "EchoResponse",
161
+ "description": "Response model for echo endpoint."
162
+ },
163
+ "HTTPValidationError": {
164
+ "properties": {
165
+ "detail": {
166
+ "items": {
167
+ "$ref": "#/components/schemas/ValidationError"
168
+ },
169
+ "type": "array",
170
+ "title": "Detail"
171
+ }
172
+ },
173
+ "type": "object",
174
+ "title": "HTTPValidationError"
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
+ },
200
+ "HelloWorldResponse": {
201
+ "properties": {
202
+ "message": {
203
+ "type": "string",
204
+ "title": "Message",
205
+ "description": "The hello world message",
206
+ "examples": [
207
+ "Hello, world!"
208
+ ]
209
+ }
210
+ },
211
+ "type": "object",
212
+ "required": [
213
+ "message"
214
+ ],
215
+ "title": "HelloWorldResponse",
216
+ "description": "Response model for hello-world endpoint."
217
+ },
218
+ "ValidationError": {
219
+ "properties": {
220
+ "loc": {
221
+ "items": {
222
+ "anyOf": [
223
+ {
224
+ "type": "string"
225
+ },
226
+ {
227
+ "type": "integer"
228
+ }
229
+ ]
230
+ },
231
+ "type": "array",
232
+ "title": "Location"
233
+ },
234
+ "msg": {
235
+ "type": "string",
236
+ "title": "Message"
237
+ },
238
+ "type": {
239
+ "type": "string",
240
+ "title": "Error Type"
241
+ }
242
+ },
243
+ "type": "object",
244
+ "required": [
245
+ "loc",
246
+ "msg",
247
+ "type"
248
+ ],
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_"
259
+ }
260
+ }
261
+ }
262
+ }