oe-python-template-example 0.0.10__tar.gz → 0.1.1__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_example-0.0.10 → oe_python_template_example-0.1.1}/.copier-answers.yml +1 -1
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.pre-commit-config.yaml +1 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/PKG-INFO +36 -17
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/README.md +35 -16
- oe_python_template_example-0.1.1/VERSION +1 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/_readme_main.md +35 -16
- oe_python_template_example-0.1.1/docs/source/_static/openapi_v1.json +262 -0
- oe_python_template_example-0.1.1/docs/source/_static/openapi_v1.yaml +210 -0
- oe_python_template_example-0.1.1/docs/source/_static/openapi_v2.json +262 -0
- oe_python_template_example-0.1.1/docs/source/_static/openapi_v2.yaml +210 -0
- oe_python_template_example-0.1.1/docs/source/api_v1.rst +5 -0
- oe_python_template_example-0.1.1/docs/source/api_v2.rst +5 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/conf.py +1 -1
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/index.rst +2 -1
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/examples/notebook.py +1 -1
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/noxfile.py +12 -4
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/pyproject.toml +3 -2
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/sonar-project.properties +1 -1
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/src/oe_python_template_example/api.py +83 -5
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/src/oe_python_template_example/cli.py +29 -3
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/tests/api_test.py +54 -20
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/tests/cli_test.py +12 -1
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/uv.lock +12 -1
- oe_python_template_example-0.0.10/VERSION +0 -1
- oe_python_template_example-0.0.10/docs/source/api.rst +0 -5
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.act-env-public +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.devcontainer/Dockerfile +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.devcontainer/devcontainer.json +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.devcontainer/onCreateCommand +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.devcontainer/postAttachCommand +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.devcontainer/postCreateCommand +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.env.example +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.github/workflows/docker-image-build-publish.yml +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.github/workflows/package-build-publish-release.yml +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.github/workflows/test-and-report.yml +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.gitignore +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.python-version +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.readthedocs.yml +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.secrets.baseline +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.vscode/extensions.json +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/.vscode/settings.json +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/CHANGELOG.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/CODEOWNERS +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/CONTRIBUTING.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/Dockerfile +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/LICENSE +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/RELEASE_NOTES.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/SERVICE_CONNECTIONS.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/_readme_footer.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/_readme_header.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/bin/git-cliff +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/bump +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/codecov.yml +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/compose.yaml +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/Makefile +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/make.bat +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/_static/.keep +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/_static/openapi.json +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/_static/openapi.yaml +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/contributing.rst +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/latexmkrc +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/main.rst +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/reference.rst +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/docs/source/release-notes.rst +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/examples/__init__.py +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/examples/notebook.ipynb +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/examples/script.py +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/examples/streamlit.py +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/CHANGELOG.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/LICENSE-APACHE +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/LICENSE-MIT +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/README.md +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/completions/_git-cliff +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/completions/_git-cliff.ps1 +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/completions/git-cliff.bash +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/completions/git-cliff.elv +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/completions/git-cliff.fish +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/git-cliff-completions +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/git-cliff-mangen +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0/man/git-cliff.1 +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/git-cliff-2.7.0-x86_64-unknown-linux-gnu.tar.gz +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/github-action-run +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/latexmkrc +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/logo.png +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/renovate.json +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/src/oe_python_template_example/__init__.py +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/src/oe_python_template_example/constants.py +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/src/oe_python_template_example/service.py +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/tests/__init__.py +0 -0
- {oe_python_template_example-0.0.10 → oe_python_template_example-0.1.1}/tests/fixtures/.keep +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: oe-python-template-example
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.1.1
|
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
|
104
|
+
## Scaffolding
|
105
105
|
|
106
|
-
Step 1
|
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
|
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
|
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
|
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
|
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
|
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
|
147
|
+
**Step 7**: Release the first versions
|
147
148
|
```shell
|
148
149
|
./bump
|
149
150
|
```
|
@@ -166,24 +167,36 @@ 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
|
175
|
+
uvx oe-python-template-example serve --port=4711 # serves webservice API on port 4711
|
173
176
|
```
|
174
177
|
|
178
|
+
Notes:
|
179
|
+
* The API is versioned, mounted at ```/api/v1``` resp. ```/api/v2```
|
180
|
+
* While serving the webservice 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 respons of the ```hello-world``` operation.
|
181
|
+
* Interactive documentation is provided at [http://127.0.0.1:8000/api/docs](http://127.0.0.1:8000/api/docs)
|
182
|
+
|
183
|
+
|
175
184
|
The CLI provides extensive help:
|
176
185
|
|
177
186
|
```shell
|
178
187
|
uvx oe-python-template-example --help # all CLI commands
|
179
188
|
uvx oe-python-template-example hello-world --help # help for specific command
|
189
|
+
uvx oe-python-template-example echo --help
|
190
|
+
uvx oe-python-template-example openapi --help
|
191
|
+
uvx oe-python-template-example serve --help
|
180
192
|
```
|
181
193
|
|
182
194
|
|
183
|
-
##
|
195
|
+
## Operational Excellence
|
184
196
|
|
185
|
-
|
186
|
-
|
197
|
+
This project is designed with operational excellence in mind, using modern Python tooling and practices. It includes:
|
198
|
+
|
199
|
+
* Various examples demonstrating usage:
|
187
200
|
- [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
|
188
201
|
- [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
|
189
202
|
- [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 +212,9 @@ uvx oe-python-template-example hello-world --help # help for specific command
|
|
199
212
|
|
200
213
|
## Usage Examples
|
201
214
|
|
215
|
+
The following examples run from source. Clone this repository first using
|
216
|
+
`git clone git@github.com:helmut-hoffer-von-ankershoffen/oe-python-template-example.git`.
|
217
|
+
|
202
218
|
### Minimal Python Script:
|
203
219
|
|
204
220
|
```python
|
@@ -240,7 +256,7 @@ uv run streamlit run examples/streamlit.py # Serve on localhost:8501, o
|
|
240
256
|
... or run within VSCode
|
241
257
|
|
242
258
|
```shell
|
243
|
-
uv sync --all-extras # Install
|
259
|
+
uv sync --all-extras # Install dependencies required for examples such as Juypyter kernel, see pyproject.toml
|
244
260
|
```
|
245
261
|
Install the [Jupyter extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
|
246
262
|
|
@@ -337,7 +353,10 @@ docker compose run oe-python-template-example echo "Lorem" --json
|
|
337
353
|
docker compose run oe-python-template-example openapi
|
338
354
|
docker compose run oe-python-template-example openapi --output-format=json
|
339
355
|
docker compose up
|
340
|
-
curl http://127.0.0.1
|
356
|
+
curl http://127.0.0.1:8000/api/v1/hello-world
|
357
|
+
curl http://127.0.0.1:8000/api/v1/docs
|
358
|
+
curl http://127.0.0.1:8000/api/v2/hello-world
|
359
|
+
curl http://127.0.0.1:8000/api/v2/docs
|
341
360
|
```
|
342
361
|
|
343
362
|
## 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
|
43
|
+
## Scaffolding
|
44
44
|
|
45
|
-
Step 1
|
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
|
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
|
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
|
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
|
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
|
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
|
86
|
+
**Step 7**: Release the first versions
|
86
87
|
```shell
|
87
88
|
./bump
|
88
89
|
```
|
@@ -105,24 +106,36 @@ 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
|
114
|
+
uvx oe-python-template-example serve --port=4711 # serves webservice API on port 4711
|
112
115
|
```
|
113
116
|
|
117
|
+
Notes:
|
118
|
+
* The API is versioned, mounted at ```/api/v1``` resp. ```/api/v2```
|
119
|
+
* While serving the webservice 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 respons of the ```hello-world``` operation.
|
120
|
+
* Interactive documentation is provided at [http://127.0.0.1:8000/api/docs](http://127.0.0.1:8000/api/docs)
|
121
|
+
|
122
|
+
|
114
123
|
The CLI provides extensive help:
|
115
124
|
|
116
125
|
```shell
|
117
126
|
uvx oe-python-template-example --help # all CLI commands
|
118
127
|
uvx oe-python-template-example hello-world --help # help for specific command
|
128
|
+
uvx oe-python-template-example echo --help
|
129
|
+
uvx oe-python-template-example openapi --help
|
130
|
+
uvx oe-python-template-example serve --help
|
119
131
|
```
|
120
132
|
|
121
133
|
|
122
|
-
##
|
134
|
+
## Operational Excellence
|
123
135
|
|
124
|
-
|
125
|
-
|
136
|
+
This project is designed with operational excellence in mind, using modern Python tooling and practices. It includes:
|
137
|
+
|
138
|
+
* Various examples demonstrating usage:
|
126
139
|
- [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
|
127
140
|
- [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
|
128
141
|
- [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 +151,9 @@ uvx oe-python-template-example hello-world --help # help for specific command
|
|
138
151
|
|
139
152
|
## Usage Examples
|
140
153
|
|
154
|
+
The following examples run from source. Clone this repository first using
|
155
|
+
`git clone git@github.com:helmut-hoffer-von-ankershoffen/oe-python-template-example.git`.
|
156
|
+
|
141
157
|
### Minimal Python Script:
|
142
158
|
|
143
159
|
```python
|
@@ -179,7 +195,7 @@ uv run streamlit run examples/streamlit.py # Serve on localhost:8501, o
|
|
179
195
|
... or run within VSCode
|
180
196
|
|
181
197
|
```shell
|
182
|
-
uv sync --all-extras # Install
|
198
|
+
uv sync --all-extras # Install dependencies required for examples such as Juypyter kernel, see pyproject.toml
|
183
199
|
```
|
184
200
|
Install the [Jupyter extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
|
185
201
|
|
@@ -276,7 +292,10 @@ docker compose run oe-python-template-example echo "Lorem" --json
|
|
276
292
|
docker compose run oe-python-template-example openapi
|
277
293
|
docker compose run oe-python-template-example openapi --output-format=json
|
278
294
|
docker compose up
|
279
|
-
curl http://127.0.0.1
|
295
|
+
curl http://127.0.0.1:8000/api/v1/hello-world
|
296
|
+
curl http://127.0.0.1:8000/api/v1/docs
|
297
|
+
curl http://127.0.0.1:8000/api/v2/hello-world
|
298
|
+
curl http://127.0.0.1:8000/api/v2/docs
|
280
299
|
```
|
281
300
|
|
282
301
|
## Extra: Lorem Ipsum
|
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -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
|
8
|
+
## Scaffolding
|
9
9
|
|
10
|
-
Step 1
|
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
|
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
|
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
|
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
|
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
|
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
|
51
|
+
**Step 7**: Release the first versions
|
51
52
|
```shell
|
52
53
|
./bump
|
53
54
|
```
|
@@ -70,24 +71,36 @@ 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
|
79
|
+
uvx oe-python-template-example serve --port=4711 # serves webservice API on port 4711
|
77
80
|
```
|
78
81
|
|
82
|
+
Notes:
|
83
|
+
* The API is versioned, mounted at ```/api/v1``` resp. ```/api/v2```
|
84
|
+
* While serving the webservice 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 respons of the ```hello-world``` operation.
|
85
|
+
* Interactive documentation is provided at [http://127.0.0.1:8000/api/docs](http://127.0.0.1:8000/api/docs)
|
86
|
+
|
87
|
+
|
79
88
|
The CLI provides extensive help:
|
80
89
|
|
81
90
|
```shell
|
82
91
|
uvx oe-python-template-example --help # all CLI commands
|
83
92
|
uvx oe-python-template-example hello-world --help # help for specific command
|
93
|
+
uvx oe-python-template-example echo --help
|
94
|
+
uvx oe-python-template-example openapi --help
|
95
|
+
uvx oe-python-template-example serve --help
|
84
96
|
```
|
85
97
|
|
86
98
|
|
87
|
-
##
|
99
|
+
## Operational Excellence
|
88
100
|
|
89
|
-
|
90
|
-
|
101
|
+
This project is designed with operational excellence in mind, using modern Python tooling and practices. It includes:
|
102
|
+
|
103
|
+
* Various examples demonstrating usage:
|
91
104
|
- [Simple Python script](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example/blob/main/examples/script.py)
|
92
105
|
- [Streamlit web application](https://oe-python-template-example.streamlit.app/) deployed on [Streamlit Community Cloud](https://streamlit.io/cloud)
|
93
106
|
- [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 +116,9 @@ uvx oe-python-template-example hello-world --help # help for specific command
|
|
103
116
|
|
104
117
|
## Usage Examples
|
105
118
|
|
119
|
+
The following examples run from source. Clone this repository first using
|
120
|
+
`git clone git@github.com:helmut-hoffer-von-ankershoffen/oe-python-template-example.git`.
|
121
|
+
|
106
122
|
### Minimal Python Script:
|
107
123
|
|
108
124
|
```python
|
@@ -144,7 +160,7 @@ uv run streamlit run examples/streamlit.py # Serve on localhost:8501, o
|
|
144
160
|
... or run within VSCode
|
145
161
|
|
146
162
|
```shell
|
147
|
-
uv sync --all-extras # Install
|
163
|
+
uv sync --all-extras # Install dependencies required for examples such as Juypyter kernel, see pyproject.toml
|
148
164
|
```
|
149
165
|
Install the [Jupyter extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter)
|
150
166
|
|
@@ -241,7 +257,10 @@ docker compose run oe-python-template-example echo "Lorem" --json
|
|
241
257
|
docker compose run oe-python-template-example openapi
|
242
258
|
docker compose run oe-python-template-example openapi --output-format=json
|
243
259
|
docker compose up
|
244
|
-
curl http://127.0.0.1
|
260
|
+
curl http://127.0.0.1:8000/api/v1/hello-world
|
261
|
+
curl http://127.0.0.1:8000/api/v1/docs
|
262
|
+
curl http://127.0.0.1:8000/api/v2/hello-world
|
263
|
+
curl http://127.0.0.1:8000/api/v2/docs
|
245
264
|
```
|
246
265
|
|
247
266
|
## 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
|
+
}
|