Skip to content

Commit 1ba7094

Browse files
chore(deps): update from template
1 parent 8d22242 commit 1ba7094

11 files changed

Lines changed: 185 additions & 207 deletions

File tree

.copier-answers.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
_commit: v0.7.4
1+
_commit: v0.7.6
22
_src_path: gh:helmut-hoffer-von-ankershoffen/oe-python-template
33
attestations_enabled: true
44
author_email: helmuthva@gmail.com

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
THE_KEY=A value
1+
OE_PYTHON_TEMPLATE_LANGUAGE=de_DE

CONTRIBUTING.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ If you are one of the committers of https://github.com/helmut-hoffer-von-ankersh
3333
src/oe_python_template_example/ # Source code
3434
├── __init__.py # Package initialization
3535
├── constants.py # Constants used throughout the app
36-
├── service.py # Service exposed for use as shared library
36+
├── settings.py # Settings loaded from environment and .env
3737
├── models.py # Models and data structures
38+
├── service.py # Service exposed for use as shared library
3839
├── cli.py # CLI enabling to interact with service from terminal
3940
└── api.py # API exposing service as web service
4041
tests/ # Unit and E2E tests
@@ -154,7 +155,7 @@ Build and run the Docker image with docker compose:
154155

155156
```shell
156157
echo "Building the Docker image with docker compose and running CLI..."
157-
docker compose run --build oe-python-template --help
158+
docker compose run --build oe-python-template-example --help
158159
echo "Building the Docker image with docker compose and running API container as a daemon ..."
159160
docker compose up --build -d
160161
echo "Waiting for the API server to start..."
Lines changed: 31 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1,31 @@
1-
components:
2-
schemas:
3-
Echo:
4-
description: Response model for echo endpoint.
5-
properties:
6-
text:
7-
description: The echo
8-
examples:
9-
- HELLO, WORLD!
10-
minLength: 1
11-
title: Text
12-
type: string
13-
required:
14-
- text
15-
title: Echo
16-
type: object
17-
HTTPValidationError:
18-
properties:
19-
detail:
20-
items:
21-
$ref: '#/components/schemas/ValidationError'
22-
title: Detail
23-
type: array
24-
title: HTTPValidationError
25-
type: object
26-
Health:
27-
description: Health status model.
28-
properties:
29-
reason:
30-
anyOf:
31-
- type: string
32-
- type: 'null'
33-
title: Reason
34-
status:
35-
$ref: '#/components/schemas/HealthStatus'
36-
required:
37-
- status
38-
title: Health
39-
type: object
40-
HealthStatus:
41-
description: Health status enumeration.
42-
enum:
43-
- UP
44-
- DOWN
45-
title: HealthStatus
46-
type: string
47-
ValidationError:
48-
properties:
49-
loc:
50-
items:
51-
anyOf:
52-
- type: string
53-
- type: integer
54-
title: Location
55-
type: array
56-
msg:
57-
title: Message
58-
type: string
59-
type:
60-
title: Error Type
61-
type: string
62-
required:
63-
- loc
64-
- msg
65-
- type
66-
title: ValidationError
67-
type: object
68-
_HelloWorldResponse:
69-
description: Response model for hello-world endpoint.
70-
properties:
71-
message:
72-
description: The hello world message
73-
examples:
74-
- Hello, world!
75-
title: Message
76-
type: string
77-
required:
78-
- message
79-
title: _HelloWorldResponse
80-
type: object
81-
info:
82-
contact:
83-
email: helmuthva@gmail.com
84-
name: Helmut Hoffer von Ankershoffen
85-
url: https://github.com/helmut-hoffer-von-ankershoffen
86-
termsOfService: https://oe-python-template-example.readthedocs.io/en/latest/
87-
title: OE Python Template Example
88-
version: 1.0.0
89-
openapi: 3.1.0
90-
paths:
91-
/echo/{text}:
92-
get:
93-
description: "Echo back the provided text.\n\nArgs:\n text (str): The text\
94-
\ to echo.\n\nReturns:\n Echo: The echo.\n\nRaises:\n 422 Unprocessable\
95-
\ Entity: If text is not provided or empty."
96-
operationId: echo_echo__text__get
97-
parameters:
98-
- in: path
99-
name: text
100-
required: true
101-
schema:
102-
title: Text
103-
type: string
104-
responses:
105-
'200':
106-
content:
107-
application/json:
108-
schema:
109-
$ref: '#/components/schemas/Echo'
110-
description: Successful Response
111-
'422':
112-
content:
113-
application/json:
114-
schema:
115-
$ref: '#/components/schemas/HTTPValidationError'
116-
description: Validation Error
117-
summary: Echo
118-
tags:
119-
- Basics
120-
/health:
121-
get:
122-
description: "Check the health of the service.\n\nThis endpoint returns the\
123-
\ health status of the service.\nThe health status can be either UP or DOWN.\n\
124-
If the service is healthy, the status will be UP.\nIf the service is unhealthy,\
125-
\ the status will be DOWN and a reason will be provided.\nThe response will\
126-
\ have a 200 OK status code if the service is healthy,\nand a 500 Internal\
127-
\ Server Error status code if the service is unhealthy.\n\nReturns:\n Health:\
128-
\ The health status of the service."
129-
operationId: health_health_get
130-
responses:
131-
'200':
132-
content:
133-
application/json:
134-
schema:
135-
$ref: '#/components/schemas/Health'
136-
description: Successful Response
137-
summary: Health
138-
tags:
139-
- Observability
140-
/healthz:
141-
get:
142-
description: "Check the health of the service.\n\nThis endpoint returns the\
143-
\ health status of the service.\nThe health status can be either UP or DOWN.\n\
144-
If the service is healthy, the status will be UP.\nIf the service is unhealthy,\
145-
\ the status will be DOWN and a reason will be provided.\nThe response will\
146-
\ have a 200 OK status code if the service is healthy,\nand a 500 Internal\
147-
\ Server Error status code if the service is unhealthy.\n\nReturns:\n Health:\
148-
\ The health status of the service."
149-
operationId: health_healthz_get
150-
responses:
151-
'200':
152-
content:
153-
application/json:
154-
schema:
155-
$ref: '#/components/schemas/Health'
156-
description: Successful Response
157-
summary: Health
158-
tags:
159-
- Observability
160-
/hello-world:
161-
get:
162-
description: "Return a hello world message.\n\nReturns:\n _HelloWorldResponse:\
163-
\ A response containing the hello world message."
164-
operationId: hello_world_hello_world_get
165-
responses:
166-
'200':
167-
content:
168-
application/json:
169-
schema:
170-
$ref: '#/components/schemas/_HelloWorldResponse'
171-
description: Successful Response
172-
summary: Hello World
173-
tags:
174-
- Basics
1+
Traceback (most recent call last):
2+
File "/Users/helmut/Code/oe-python-template-example/.nox/docs-3-13/bin/oe-python-template-example", line 4, in <module>
3+
from oe_python_template_example.cli import cli
4+
File "/Users/helmut/Code/oe-python-template-example/src/oe_python_template_example/__init__.py", line 8, in <module>
5+
from .models import Echo, Health, HealthStatus, Utterance
6+
File "/Users/helmut/Code/oe-python-template-example/src/oe_python_template_example/models.py", line 5, in <module>
7+
from pydantic import BaseModel, Field
8+
File "<frozen importlib._bootstrap>", line 1412, in _handle_fromlist
9+
File "/Users/helmut/Code/oe-python-template-example/.nox/docs-3-13/lib/python3.13/site-packages/pydantic/__init__.py", line 421, in __getattr__
10+
module = import_module(module_name, package=package)
11+
File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/importlib/__init__.py", line 88, in import_module
12+
return _bootstrap._gcd_import(name[level:], package, level)
13+
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
File "/Users/helmut/Code/oe-python-template-example/.nox/docs-3-13/lib/python3.13/site-packages/pydantic/main.py", line 34, in <module>
15+
from ._internal import (
16+
...<12 lines>...
17+
)
18+
File "/Users/helmut/Code/oe-python-template-example/.nox/docs-3-13/lib/python3.13/site-packages/pydantic/_internal/_generics.py", line 8, in <module>
19+
from contextvars import ContextVar
20+
File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextvars.py", line 1, in <module>
21+
from _contextvars import Context, ContextVar, Token, copy_context
22+
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
23+
File "<frozen importlib._bootstrap>", line 1322, in _find_and_load_unlocked
24+
File "<frozen importlib._bootstrap>", line 1262, in _find_spec
25+
File "<frozen importlib._bootstrap_external>", line 1559, in find_spec
26+
File "<frozen importlib._bootstrap_external>", line 1533, in _get_spec
27+
File "<frozen importlib._bootstrap_external>", line 1666, in find_spec
28+
File "<frozen importlib._bootstrap_external>", line 1621, in _get_spec
29+
File "<frozen importlib._bootstrap_external>", line 859, in spec_from_file_location
30+
File "<frozen importlib._bootstrap_external>", line 190, in _path_abspath
31+
KeyboardInterrupt

pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ requires-python = ">=3.11, <4.0"
6464
dependencies = [
6565
"fastapi[standard,all]>=0.115.12",
6666
"pydantic>=2.10.6",
67-
"python-dotenv>=1.1.0",
67+
"pydantic-settings>=2.8.1",
6868
"typer>=0.15.1",
6969
]
7070

@@ -118,6 +118,7 @@ dev = [
118118
"pytest-docker>=3.2.0",
119119
"pytest-env>=1.1.5",
120120
"pytest-regressions>=2.7.0",
121+
"pytest-subprocess>=1.5.3",
121122
"pytest-xdist[psutil]>=3.6.1",
122123
"ruff>=0.10.0",
123124
"sphinx>=8.2.3",
@@ -137,7 +138,7 @@ dev = [
137138

138139
[tool.uv]
139140
override-dependencies = [ # https://github.com/astral-sh/uv/issues/4422
140-
"rfc3987; sys_platform == 'never'", # GPLv3
141+
"rfc3987; sys_platform == 'never'", # GPLv3
141142
]
142143

143144

@@ -208,7 +209,7 @@ docstring-code-format = true
208209
[tool.ruff.lint.pydocstyle]
209210
convention = "google"
210211

211-
[tool.mypy] # https://mypy.readthedocs.io/en/latest/config_file.html
212+
[tool.mypy] # https://mypy.readthedocs.io/en/latest/config_file.html
212213
junit_xml = "reports/mypy_junit.xml"
213214
plugins = "pydantic.mypy"
214215
strict = true

src/oe_python_template_example/api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from fastapi import Depends, FastAPI, Response, status
1616
from pydantic import BaseModel, Field
1717

18-
from oe_python_template_example import Echo, Health, HealthStatus, Service, Utterance
18+
from . import Echo, Health, HealthStatus, Service, Utterance
1919

2020
TITLE = "OE Python Template Example"
2121
HELLO_WORLD_EXAMPLE = "Hello, world!"
@@ -133,14 +133,14 @@ class _HelloWorldResponse(BaseModel):
133133

134134
@api_v1.get("/hello-world", tags=["Basics"])
135135
@api_v2.get("/hello-world", tags=["Basics"])
136-
async def hello_world() -> _HelloWorldResponse:
136+
async def hello_world(service: Annotated[Service, Depends(get_service)]) -> _HelloWorldResponse:
137137
"""
138138
Return a hello world message.
139139
140140
Returns:
141141
_HelloWorldResponse: A response containing the hello world message.
142142
"""
143-
return _HelloWorldResponse(message=Service.get_hello_world())
143+
return _HelloWorldResponse(message=service.get_hello_world())
144144

145145

146146
@api_v1.get("/echo/{text}", tags=["Basics"])

src/oe_python_template_example/cli.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,24 @@
99
import yaml
1010
from rich.console import Console
1111

12-
from oe_python_template_example import Service, Utterance, __version__
13-
from oe_python_template_example.api import api_v1, api_v2
14-
15-
console = Console()
12+
from . import Service, Utterance, __version__
13+
from .api import api_v1, api_v2
1614

1715
cli = typer.Typer(name="Command Line Interface of OE Python Template Example")
16+
_service = Service()
17+
_console = Console()
18+
19+
20+
@cli.command()
21+
def health() -> None:
22+
"""Indicate if service is healthy."""
23+
_console.print(_service.healthy())
24+
25+
26+
@cli.command()
27+
def info() -> None:
28+
"""Print info about service configuration."""
29+
_console.print(_service.info())
1830

1931

2032
@cli.command()
@@ -32,15 +44,15 @@ def echo(
3244
"""Echo the text."""
3345
echo = Service.echo(Utterance(text=text))
3446
if json:
35-
console.print_json(data={"text": echo.text})
47+
_console.print_json(data={"text": echo.text})
3648
else:
37-
console.print(echo.text)
49+
_console.print(echo.text)
3850

3951

4052
@cli.command()
4153
def hello_world() -> None:
4254
"""Print hello world message and what's in the environment variable THE_VAR."""
43-
console.print(Service.get_hello_world())
55+
_console.print(_service.get_hello_world())
4456

4557

4658
@cli.command()
@@ -50,7 +62,7 @@ def serve(
5062
watch: Annotated[bool, typer.Option(help="Enable auto-reload")] = True,
5163
) -> None:
5264
"""Start the API server."""
53-
console.print(f"Starting API server at http://{host}:{port}")
65+
_console.print(f"Starting API server at http://{host}:{port}")
5466
os.environ["UVICORN_HOST"] = host
5567
os.environ["UVICORN_PORT"] = str(port)
5668
uvicorn.run(
@@ -111,9 +123,9 @@ def openapi(
111123
schema = api_v2.openapi()
112124
match output_format:
113125
case OutputFormat.JSON:
114-
console.print_json(data=schema)
126+
_console.print_json(data=schema)
115127
case OutputFormat.YAML:
116-
console.print(yaml.dump(schema, default_flow_style=False), end="")
128+
_console.print(yaml.dump(schema, default_flow_style=False), end="")
117129

118130

119131
def _apply_cli_settings(cli: typer.Typer, epilog: str) -> None:

0 commit comments

Comments
 (0)