oe-python-template-example 0.4.1__py3-none-any.whl → 0.4.3__py3-none-any.whl
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/api.py +2 -2
- oe_python_template_example/cli.py +34 -1
- oe_python_template_example/constants.py +7 -1
- oe_python_template_example/hello/__init__.py +11 -0
- oe_python_template_example/hello/_gui.py +44 -0
- oe_python_template_example/system/__init__.py +12 -1
- oe_python_template_example/system/_cli.py +64 -23
- oe_python_template_example/system/_gui.py +20 -0
- oe_python_template_example/system/_service.py +1 -0
- oe_python_template_example/utils/.vendored/bottle.py +4563 -0
- oe_python_template_example/utils/__init__.py +14 -0
- oe_python_template_example/utils/_constants.py +27 -8
- oe_python_template_example/utils/_gui.py +174 -0
- oe_python_template_example/utils/_notebook.py +61 -0
- oe_python_template_example/utils/boot.py +6 -0
- {oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/METADATA +51 -29
- {oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/RECORD +20 -15
- {oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/WHEEL +0 -0
- {oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/entry_points.txt +0 -0
- {oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/licenses/LICENSE +0 -0
@@ -60,3 +60,17 @@ __all__ = [
|
|
60
60
|
"prepare_cli",
|
61
61
|
"strip_to_none_before_validator",
|
62
62
|
]
|
63
|
+
|
64
|
+
from importlib.util import find_spec
|
65
|
+
|
66
|
+
if find_spec("nicegui"):
|
67
|
+
from ._gui import BasePageBuilder, GUILocalFilePicker, gui_register_pages, gui_run
|
68
|
+
|
69
|
+
__all__ += ["BasePageBuilder", "GUILocalFilePicker", "gui_register_pages", "gui_run"]
|
70
|
+
|
71
|
+
if find_spec("marimo"):
|
72
|
+
from ._notebook import create_marimo_app
|
73
|
+
|
74
|
+
__all__ += [
|
75
|
+
"create_marimo_app",
|
76
|
+
]
|
@@ -14,7 +14,21 @@ __project_path__ = str(Path(__file__).parent.parent.parent)
|
|
14
14
|
__version__ = metadata.version(__project_name__)
|
15
15
|
__is_development_mode__ = "uvx" not in sys.argv[0].lower()
|
16
16
|
__is_running_in_container__ = os.getenv(f"{__project_name__.upper()}_RUNNING_IN_CONTAINER")
|
17
|
-
|
17
|
+
|
18
|
+
# Determine environment we are deployed on
|
19
|
+
ENV_VAR_MAPPINGS = {
|
20
|
+
"ENV": lambda env: env,
|
21
|
+
"VERCEL_ENV": lambda env: env, # See https://vercel.com/docs/environment-variables/system-environment-variables
|
22
|
+
"RAILWAY_ENVIRONMENT": lambda env: env, # See https://docs.railway.com/reference/variables#railway-provided-variables
|
23
|
+
}
|
24
|
+
__env__ = "local" # Default
|
25
|
+
for env_var, mapper in ENV_VAR_MAPPINGS.items():
|
26
|
+
env_value = os.getenv(env_var)
|
27
|
+
if env_value:
|
28
|
+
__env__ = mapper(env_value) # type: ignore[no-untyped-call]
|
29
|
+
break
|
30
|
+
|
31
|
+
# Define environment file paths
|
18
32
|
__env_file__ = [
|
19
33
|
Path.home() / f".{__project_name__}" / ".env",
|
20
34
|
Path.home() / f".{__project_name__}" / f".env.{__env__}",
|
@@ -25,12 +39,18 @@ env_file_path = os.getenv(f"{__project_name__.upper()}_ENV_FILE")
|
|
25
39
|
if env_file_path:
|
26
40
|
__env_file__.insert(2, Path(env_file_path))
|
27
41
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
42
|
+
# Determine __base_url__
|
43
|
+
PLATFORM_URL_MAPPINGS = {
|
44
|
+
"VERCEL_URL": lambda url: f"https://{url}", # See https://vercel.com/docs/environment-variables/system-environment-variables
|
45
|
+
"RAILWAY_PUBLIC_DOMAIN": lambda url: f"https://{url}", # See https://docs.railway.com/reference/variables#railway-provided-variables
|
46
|
+
}
|
47
|
+
__base__url__ = os.getenv(f"{__project_name__.upper()}_BASE_URL")
|
48
|
+
if not __base__url__:
|
49
|
+
for env_var, mappers in PLATFORM_URL_MAPPINGS.items():
|
50
|
+
env_value = os.getenv(env_var)
|
51
|
+
if env_value:
|
52
|
+
__base__url__ = mappers(env_value) # type: ignore[no-untyped-call]
|
53
|
+
break
|
34
54
|
|
35
55
|
|
36
56
|
def get_project_url_by_label(prefix: str) -> str:
|
@@ -47,7 +67,6 @@ def get_project_url_by_label(prefix: str) -> str:
|
|
47
67
|
for url_entry in metadata.metadata(__project_name__).get_all("Project-URL", []):
|
48
68
|
if url_entry.startswith(prefix):
|
49
69
|
return str(url_entry.split(", ", 1)[1])
|
50
|
-
|
51
70
|
return ""
|
52
71
|
|
53
72
|
|
@@ -0,0 +1,174 @@
|
|
1
|
+
import platform
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
from pathlib import Path
|
4
|
+
from types import EllipsisType
|
5
|
+
|
6
|
+
from nicegui import app, events, ui
|
7
|
+
from nicegui import native as native_app
|
8
|
+
|
9
|
+
from ._constants import __project_name__
|
10
|
+
from ._di import locate_subclasses
|
11
|
+
from ._log import get_logger
|
12
|
+
|
13
|
+
logger = get_logger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
class BasePageBuilder(ABC):
|
17
|
+
"""Base class for all page builders."""
|
18
|
+
|
19
|
+
@staticmethod
|
20
|
+
@abstractmethod
|
21
|
+
def register_pages() -> None:
|
22
|
+
"""Register pages."""
|
23
|
+
|
24
|
+
|
25
|
+
def gui_register_pages() -> None:
|
26
|
+
"""Register pages.
|
27
|
+
|
28
|
+
This function is called by the GUI to register all pages.
|
29
|
+
"""
|
30
|
+
page_builders = locate_subclasses(BasePageBuilder)
|
31
|
+
for page_builder in page_builders:
|
32
|
+
page_builder.register_pages()
|
33
|
+
|
34
|
+
|
35
|
+
def gui_run( # noqa: PLR0913, PLR0917
|
36
|
+
native: bool = True,
|
37
|
+
show: bool = False,
|
38
|
+
host: str | None = None,
|
39
|
+
port: int | None = None,
|
40
|
+
title: str = __project_name__,
|
41
|
+
icon: str = "",
|
42
|
+
watch: bool = False,
|
43
|
+
with_api: bool = False,
|
44
|
+
) -> None:
|
45
|
+
"""Start the GUI.
|
46
|
+
|
47
|
+
Args:
|
48
|
+
native: Whether to run the GUI in native mode.
|
49
|
+
show: Whether to show the GUI.
|
50
|
+
host: Host to run the GUI on.
|
51
|
+
port: Port to run the GUI on.
|
52
|
+
title: Title of the GUI.
|
53
|
+
icon: Icon for the GUI.
|
54
|
+
watch: Whether to watch for changes and reload the GUI.
|
55
|
+
with_api: Whether to mount the API.
|
56
|
+
|
57
|
+
Raises:
|
58
|
+
ValueError: If with_notebook is True but notebook_path is None.
|
59
|
+
"""
|
60
|
+
if with_api:
|
61
|
+
from ..api import api # noqa: PLC0415, TID252
|
62
|
+
|
63
|
+
app.mount("/api", api)
|
64
|
+
|
65
|
+
gui_register_pages()
|
66
|
+
ui.run(
|
67
|
+
title=title,
|
68
|
+
favicon=icon,
|
69
|
+
native=native,
|
70
|
+
reload=watch,
|
71
|
+
dark=False,
|
72
|
+
host=host,
|
73
|
+
port=port or native_app.find_open_port(),
|
74
|
+
frameless=False,
|
75
|
+
show_welcome_message=True,
|
76
|
+
show=show,
|
77
|
+
)
|
78
|
+
|
79
|
+
|
80
|
+
class GUILocalFilePicker(ui.dialog):
|
81
|
+
def __init__(
|
82
|
+
self,
|
83
|
+
directory: str,
|
84
|
+
*,
|
85
|
+
upper_limit: str | EllipsisType | None = ...,
|
86
|
+
multiple: bool = False,
|
87
|
+
show_hidden_files: bool = False,
|
88
|
+
) -> None:
|
89
|
+
"""Local File Picker.
|
90
|
+
|
91
|
+
A simple file picker that allows selecting files from the local filesystem where NiceGUI is running.
|
92
|
+
|
93
|
+
Args:
|
94
|
+
directory: The directory to start in.
|
95
|
+
upper_limit: The directory to stop at. None for no limit, default is same as starting directory.
|
96
|
+
multiple: Whether to allow multiple files to be selected.
|
97
|
+
show_hidden_files: Whether to show hidden files.
|
98
|
+
"""
|
99
|
+
super().__init__()
|
100
|
+
|
101
|
+
self.path = Path(directory).expanduser()
|
102
|
+
if upper_limit is None:
|
103
|
+
self.upper_limit = None
|
104
|
+
elif upper_limit is ...:
|
105
|
+
self.upper_limit = Path(directory).expanduser()
|
106
|
+
else:
|
107
|
+
self.upper_limit = Path(upper_limit).expanduser()
|
108
|
+
self.show_hidden_files = show_hidden_files
|
109
|
+
|
110
|
+
with self, ui.card():
|
111
|
+
self.add_drives_toggle()
|
112
|
+
self.grid = (
|
113
|
+
ui.aggrid(
|
114
|
+
{
|
115
|
+
"columnDefs": [{"field": "name", "headerName": "File"}],
|
116
|
+
"rowSelection": "multiple" if multiple else "single",
|
117
|
+
},
|
118
|
+
html_columns=[0],
|
119
|
+
)
|
120
|
+
.classes("w-96")
|
121
|
+
.on("cellDoubleClicked", self.handle_double_click)
|
122
|
+
)
|
123
|
+
with ui.row().classes("w-full justify-end"):
|
124
|
+
ui.button("Cancel", on_click=self.close).props("outline").mark("BUTTON_CANCEL")
|
125
|
+
ui.button("Ok", on_click=self._handle_ok).mark("BUTTON_OK")
|
126
|
+
self.update_grid()
|
127
|
+
|
128
|
+
def add_drives_toggle(self) -> None:
|
129
|
+
if platform.system() == "Windows":
|
130
|
+
import win32api # noqa: PLC0415
|
131
|
+
|
132
|
+
drives = win32api.GetLogicalDriveStrings().split("\000")[:-1]
|
133
|
+
self.drives_toggle = ui.toggle(drives, value=drives[0], on_change=self.update_drive)
|
134
|
+
|
135
|
+
def update_drive(self) -> None:
|
136
|
+
self.path = Path(self.drives_toggle.value).expanduser()
|
137
|
+
self.update_grid()
|
138
|
+
|
139
|
+
def update_grid(self) -> None:
|
140
|
+
paths = list(self.path.glob("*"))
|
141
|
+
if not self.show_hidden_files:
|
142
|
+
paths = [p for p in paths if not p.name.startswith(".")]
|
143
|
+
paths.sort(key=lambda p: p.name.lower())
|
144
|
+
paths.sort(key=lambda p: not p.is_dir())
|
145
|
+
|
146
|
+
self.grid.options["rowData"] = [
|
147
|
+
{
|
148
|
+
"name": f"📁 <strong>{p.name}</strong>" if p.is_dir() else p.name,
|
149
|
+
"path": str(p),
|
150
|
+
}
|
151
|
+
for p in paths
|
152
|
+
]
|
153
|
+
if (self.upper_limit is None and self.path != self.path.parent) or (
|
154
|
+
self.upper_limit is not None and self.path != self.upper_limit
|
155
|
+
):
|
156
|
+
self.grid.options["rowData"].insert(
|
157
|
+
0,
|
158
|
+
{
|
159
|
+
"name": "📁 <strong>..</strong>",
|
160
|
+
"path": str(self.path.parent),
|
161
|
+
},
|
162
|
+
)
|
163
|
+
self.grid.update()
|
164
|
+
|
165
|
+
def handle_double_click(self, e: events.GenericEventArguments) -> None:
|
166
|
+
self.path = Path(e.args["data"]["path"])
|
167
|
+
if self.path.is_dir():
|
168
|
+
self.update_grid()
|
169
|
+
else:
|
170
|
+
self.submit([str(self.path)])
|
171
|
+
|
172
|
+
async def _handle_ok(self) -> None:
|
173
|
+
rows = await self.grid.get_selected_rows()
|
174
|
+
self.submit([r["path"] for r in rows])
|
@@ -0,0 +1,61 @@
|
|
1
|
+
"""System service."""
|
2
|
+
|
3
|
+
from collections.abc import Callable
|
4
|
+
|
5
|
+
import marimo
|
6
|
+
from fastapi import APIRouter, FastAPI
|
7
|
+
|
8
|
+
from ..constants import NOTEBOOK_APP, NOTEBOOK_FOLDER # noqa: TID252
|
9
|
+
from ._health import Health
|
10
|
+
from ._log import get_logger
|
11
|
+
|
12
|
+
logger = get_logger(__name__)
|
13
|
+
|
14
|
+
|
15
|
+
def register_health_endpoint(router: APIRouter) -> Callable[..., Health]:
|
16
|
+
"""Register health endpoint to the given router.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
router: The router to register the health endpoint to.
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
Callable[..., Health]: The health endpoint function.
|
23
|
+
"""
|
24
|
+
|
25
|
+
@router.get("/healthz")
|
26
|
+
def health_endpoint() -> Health:
|
27
|
+
"""Determine health of the app.
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
Health: Health.
|
31
|
+
"""
|
32
|
+
return Health(status=Health.Code.UP)
|
33
|
+
|
34
|
+
return health_endpoint
|
35
|
+
|
36
|
+
|
37
|
+
def create_marimo_app() -> FastAPI:
|
38
|
+
"""Create a FastAPI app with marimo notebook server.
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
FastAPI: FastAPI app with marimo notebook server.
|
42
|
+
|
43
|
+
Raises:
|
44
|
+
ValueError: If the notebook directory does not exist.
|
45
|
+
"""
|
46
|
+
server = marimo.create_asgi_app(include_code=True)
|
47
|
+
if not NOTEBOOK_FOLDER.is_dir():
|
48
|
+
logger.critical(
|
49
|
+
"Directory %s does not exist. Please create the directory and add your notebooks.",
|
50
|
+
NOTEBOOK_FOLDER,
|
51
|
+
)
|
52
|
+
message = f"Directory {NOTEBOOK_FOLDER} does not exist. Please create and add your notebooks."
|
53
|
+
raise ValueError(message)
|
54
|
+
server = server.with_app(path="/", root=str(NOTEBOOK_APP))
|
55
|
+
# .with_dynamic_directory(path="/dashboard", directory=str(self._settings.directory))
|
56
|
+
app = FastAPI()
|
57
|
+
router = APIRouter(tags=["marimo"])
|
58
|
+
register_health_endpoint(router)
|
59
|
+
app.include_router(router)
|
60
|
+
app.mount("/", server.build())
|
61
|
+
return app
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
import os
|
4
4
|
import sys
|
5
|
+
from pathlib import Path
|
5
6
|
|
6
7
|
from ._log import logging_initialize
|
7
8
|
from ._logfire import logfire_initialize
|
@@ -9,6 +10,11 @@ from ._sentry import sentry_initialize
|
|
9
10
|
|
10
11
|
_boot_called = False
|
11
12
|
|
13
|
+
# Import vendored dependencies
|
14
|
+
vendored_dir = Path(__file__).parent.absolute() / ".vendored"
|
15
|
+
if vendored_dir.is_dir() and str(vendored_dir) not in sys.path:
|
16
|
+
sys.path.insert(0, str(vendored_dir))
|
17
|
+
|
12
18
|
|
13
19
|
def boot(modules_to_instrument: list[str]) -> None:
|
14
20
|
"""Boot the application.
|
{oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: oe-python-template-example
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.3
|
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/
|
@@ -50,6 +50,7 @@ Classifier: Typing :: Typed
|
|
50
50
|
Requires-Python: <4.0,>=3.11
|
51
51
|
Requires-Dist: fastapi[all,standard]>=0.115.12
|
52
52
|
Requires-Dist: logfire[system-metrics]>=3.13.1
|
53
|
+
Requires-Dist: nicegui[native]>=2.15.0
|
53
54
|
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.53b0
|
54
55
|
Requires-Dist: opentelemetry-instrumentation-httpx>=0.53b0
|
55
56
|
Requires-Dist: opentelemetry-instrumentation-jinja2>=0.53b0
|
@@ -59,15 +60,15 @@ Requires-Dist: opentelemetry-instrumentation-tornado>=0.53b0
|
|
59
60
|
Requires-Dist: opentelemetry-instrumentation-urllib3>=0.53b0
|
60
61
|
Requires-Dist: opentelemetry-instrumentation-urllib>=0.53b0
|
61
62
|
Requires-Dist: psutil>=7.0.0
|
62
|
-
Requires-Dist: pydantic-settings>=2.
|
63
|
-
Requires-Dist:
|
64
|
-
Requires-Dist: sentry-sdk>=2.25.1
|
63
|
+
Requires-Dist: pydantic-settings>=2.9.1
|
64
|
+
Requires-Dist: sentry-sdk>=2.26.1
|
65
65
|
Requires-Dist: typer>=0.15.1
|
66
66
|
Requires-Dist: uptime>=3.0.1
|
67
67
|
Provides-Extra: examples
|
68
68
|
Requires-Dist: jinja2>=3.1.6; extra == 'examples'
|
69
69
|
Requires-Dist: jupyter>=1.1.1; extra == 'examples'
|
70
|
-
Requires-Dist: marimo>=0.
|
70
|
+
Requires-Dist: marimo>=0.13.0; extra == 'examples'
|
71
|
+
Requires-Dist: matplotlib>=3.10.1; extra == 'examples'
|
71
72
|
Requires-Dist: streamlit>=1.44.1; extra == 'examples'
|
72
73
|
Description-Content-Type: text/markdown
|
73
74
|
|
@@ -151,13 +152,15 @@ Projects generated with this template come with a comprehensive development tool
|
|
151
152
|
17. Changelog and release notes generated with [git-cliff](https://git-cliff.org/)
|
152
153
|
18. Documentation generated with [Sphinx](https://www.sphinx-doc.org/en/master/) including reference documentation for the library, CLI, and API
|
153
154
|
19. Documentation published to [Read The Docs](https://readthedocs.org/) including generation of PDF and single page HTML versions
|
154
|
-
20.
|
155
|
-
21.
|
156
|
-
22.
|
157
|
-
23.
|
158
|
-
24.
|
159
|
-
25.
|
160
|
-
26.
|
155
|
+
20. Documentation including dynamic badges, setup instructions, contribution guide and security policy
|
156
|
+
21. Interactive OpenAPI specification with [Swagger](https://swagger.io/)
|
157
|
+
22. Python package published to [PyPI](https://pypi.org/)
|
158
|
+
23. Multi-stage build of fat and slim (no-extras) Docker images, app running nonroot
|
159
|
+
24. Mult-arch Docker images published to [Docker.io](https://hub.docker.com/) and [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) with [artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds)
|
160
|
+
25. One-click development environments with [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) and [GitHub Codespaces](https://github.com/features/codespaces)
|
161
|
+
26. Settings for use with [VSCode](https://code.visualstudio.com/)
|
162
|
+
27. Settings and custom instructions for use with [GitHub Copilot](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot)
|
163
|
+
28. API deployed as serverless function to [Vercel](https://vercel.com/) (optional)
|
161
164
|
|
162
165
|
### Application Features
|
163
166
|
|
@@ -165,17 +168,20 @@ Beyond development tooling, projects generated with this template include the co
|
|
165
168
|
|
166
169
|
1. Usable as library with "Hello" module exposing a simple service that can say "Hello, world!" and echo utterances.
|
167
170
|
2. Command-line interface (CLI) with [Typer](https://typer.tiangolo.com/)
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
171
|
+
2. Versioned webservice API with [FastAPI](https://fastapi.tiangolo.com/)
|
172
|
+
3. Comfortable command-line interface (CLI) with
|
173
|
+
[Typer](https://typer.tiangolo.com/)
|
174
|
+
4. Cross-platform Graphical User Interface (GUI) with
|
175
|
+
[NiceGUI](https://nicegui.io/) running in native window
|
176
|
+
5. [Interactive Jupyter notebook](https://jupyter.org/) and [reactive Marimo notebook](https://marimo.io/)
|
177
|
+
6. Simple Web UI with [Streamlit](https://streamlit.io/)
|
172
178
|
7. Validation and settings management with [pydantic](https://docs.pydantic.dev/)
|
173
|
-
8.
|
174
|
-
9.
|
175
|
-
10.
|
176
|
-
11.
|
177
|
-
12.
|
178
|
-
13.
|
179
|
+
8. Flexible logging and instrumentation, including support for [Sentry](https://sentry.io/) and [Logfire](https://logfire.dev/)
|
180
|
+
9. Modular architecture including auto-registration of services, CLI commands, API routes and GUI pages exposed by domain modules
|
181
|
+
10. System module providing aggregate health and info to the runtime, compiled settings, and further info provided by domain modules
|
182
|
+
11. Health and Info available via command, webservice API (info passsword protected) and GUI
|
183
|
+
12. Hello service demonstrates use of custom real time metrics collected via Logfire
|
184
|
+
13. Configuration to run the CLI and API in a Docker container including setup for [Docker Compose](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-docker-compose/)
|
179
185
|
|
180
186
|
Explore [here](https://github.com/helmut-hoffer-von-ankershoffen/oe-python-template-example) for what's generated out of the box.
|
181
187
|
|
@@ -242,9 +248,13 @@ pip install oe-python-template-example # add dependency to your project
|
|
242
248
|
Executing the command line interface (CLI) in an isolated Python environment is just as easy:
|
243
249
|
|
244
250
|
```shell
|
245
|
-
uvx oe-python-template-example hello
|
246
|
-
uvx oe-python-template-example
|
247
|
-
uvx oe-python-template-example
|
251
|
+
uvx oe-python-template-example hello world # prints "Hello, world! [..]"
|
252
|
+
uvx oe-python-template-example hello echo "Lorem Ipsum" # echos "Lorem Ipsum"
|
253
|
+
uvx oe-python-template-example gui # opens the graphical user interface (GUI)
|
254
|
+
uvx --with "oe-python-template-example[examples]" oe-python-template-example gui # opens the graphical user interface (GUI) with support for scientific computing
|
255
|
+
uvx oe-python-template-example system serve # serves web API
|
256
|
+
uvx oe-python-template-example system serve --port=4711 # serves web API on port 4711
|
257
|
+
uvx oe-python-template-example system openapi # serves web API on port 4711
|
248
258
|
```
|
249
259
|
|
250
260
|
Notes:
|
@@ -257,10 +267,11 @@ The CLI provides extensive help:
|
|
257
267
|
|
258
268
|
```shell
|
259
269
|
uvx oe-python-template-example --help # all CLI commands
|
260
|
-
uvx oe-python-template-example hello
|
261
|
-
uvx oe-python-template-example echo --help
|
262
|
-
uvx oe-python-template-example
|
263
|
-
uvx oe-python-template-example serve --help
|
270
|
+
uvx oe-python-template-example hello world --help # help for specific command
|
271
|
+
uvx oe-python-template-example hello echo --help
|
272
|
+
uvx oe-python-template-example gui --help
|
273
|
+
uvx oe-python-template-example system serve --help
|
274
|
+
uvx oe-python-template-example system openapi --help
|
264
275
|
```
|
265
276
|
|
266
277
|
|
@@ -388,6 +399,8 @@ uvx oe-python-template-example hello world
|
|
388
399
|
uvx oe-python-template-example hello echo --help
|
389
400
|
uvx oe-python-template-example hello echo "Lorem"
|
390
401
|
uvx oe-python-template-example hello echo "Lorem" --json
|
402
|
+
uvx oe-python-template-example gui
|
403
|
+
uvx --with "oe-python-template-example[examples]" oe-python-template-example gui # opens the graphical user interface (GUI) with support for scientific computing
|
391
404
|
uvx oe-python-template-example system info
|
392
405
|
uvx oe-python-template-example system health
|
393
406
|
uvx oe-python-template-example system openapi
|
@@ -472,6 +485,15 @@ echo "Shutting down the API container ..."
|
|
472
485
|
docker compose down
|
473
486
|
```
|
474
487
|
|
488
|
+
#### Slim
|
489
|
+
|
490
|
+
The default Docker image includes all extras. Additionally a slim image is provided, with no extras. Run as follows
|
491
|
+
|
492
|
+
```shell
|
493
|
+
docker compose run --remove-orphans oe-python-template-example-slim --help
|
494
|
+
```
|
495
|
+
|
496
|
+
|
475
497
|
* See the [reference documentation of the API](https://oe-python-template-example.readthedocs.io/en/latest/api_reference_v1.html) for detailed documentation of all API operations and parameters.
|
476
498
|
|
477
499
|
|
{oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/RECORD
RENAMED
@@ -1,35 +1,40 @@
|
|
1
1
|
oe_python_template_example/__init__.py,sha256=_Z3Xb-x95UODU66avOiwROVaouk_s0ZNB25KFnPoS40,226
|
2
|
-
oe_python_template_example/api.py,sha256=
|
3
|
-
oe_python_template_example/cli.py,sha256=
|
4
|
-
oe_python_template_example/constants.py,sha256=
|
5
|
-
oe_python_template_example/hello/__init__.py,sha256=
|
2
|
+
oe_python_template_example/api.py,sha256=gwUAW_pWUABFtAAiuIg3-X-dG25m1l0rqpnMqlaGEJo,2206
|
3
|
+
oe_python_template_example/cli.py,sha256=fnE06WJFcks5N4LwWlgIDHICciKY1FM944aAdJM6Ju0,1644
|
4
|
+
oe_python_template_example/constants.py,sha256=eRFVkR2qwafucpx5ppJSohr5wpSRm4yh1deLpOTep9A,346
|
5
|
+
oe_python_template_example/hello/__init__.py,sha256=F7aJ_uhTPPnFLT_4GjI2GzjAmKrUhfe4KxqzrljuCVo,485
|
6
6
|
oe_python_template_example/hello/_api.py,sha256=B4gCojmEkvh-ScKPz0rXW70r4gVvg7SX2dfbZpUd2vU,2302
|
7
7
|
oe_python_template_example/hello/_cli.py,sha256=D1RZyz8sk7wpH1a9VDx1QtsNorOr9owxK8N7SxaaMWM,1200
|
8
8
|
oe_python_template_example/hello/_constants.py,sha256=6aRleAIcdgC13TeTzI07YwjoSwqGb2g131dw8aEoM4I,109
|
9
|
+
oe_python_template_example/hello/_gui.py,sha256=cYzag6lLD-zQGgTBcgXRDfbuxjtF927OVrvLAcFfpHs,1470
|
9
10
|
oe_python_template_example/hello/_models.py,sha256=JtI7wGT72u23NOxFa-oeWzdyiMg7PnHL5eg22im2_yQ,574
|
10
11
|
oe_python_template_example/hello/_service.py,sha256=o9sgk-yFX5zRi06sAOdSPqkgT93naxn-JRknwK2Nnvs,3183
|
11
12
|
oe_python_template_example/hello/_settings.py,sha256=Q14SqSvBJYFuofA-tbvBwO30sVygSaXsgaYC7x1uCfo,1562
|
12
|
-
oe_python_template_example/system/__init__.py,sha256=
|
13
|
+
oe_python_template_example/system/__init__.py,sha256=7e2z8HATzy3dAIBXy5PM9rlCC7Rbu8m8NapROdrf3Wk,624
|
13
14
|
oe_python_template_example/system/_api.py,sha256=rE9Aau3IIHXdEkOBUXOwJ7SxN3cZpgtYEuojnSWfT_4,3687
|
14
|
-
oe_python_template_example/system/_cli.py,sha256=
|
15
|
-
oe_python_template_example/system/
|
15
|
+
oe_python_template_example/system/_cli.py,sha256=D19TuXtGGmxzQ-VkmCD7fmuqKQ5TQoJq9O0VzJKvWVE,6960
|
16
|
+
oe_python_template_example/system/_gui.py,sha256=uKI-tlBSJXMaxY79wgdYtMttEyu8BLQC1UQLEPOcoZg,653
|
17
|
+
oe_python_template_example/system/_service.py,sha256=f-EtWEAanajo4S2KeGm26K9_RezYgPza1qVqPRBOFvY,6376
|
16
18
|
oe_python_template_example/system/_settings.py,sha256=MwMAJYifJ6jGImeSh4e9shmIXmiUSuQGHXz_Ts0mSdk,901
|
17
|
-
oe_python_template_example/utils/__init__.py,sha256=
|
19
|
+
oe_python_template_example/utils/__init__.py,sha256=ggcc7xvH6MJ3kP45lfjmp8yZSPDTeQRaQYbZbG0M7yM,1924
|
18
20
|
oe_python_template_example/utils/_api.py,sha256=w3hPQK1pL2gBI4_1qNWNa2b4S_oH-8mY-ckRX0KrCWM,617
|
19
21
|
oe_python_template_example/utils/_cli.py,sha256=J_mFtXZ1gGeovGrE5i3wlokTOBfiTTKEz5magiRP7GA,2091
|
20
22
|
oe_python_template_example/utils/_console.py,sha256=u0-utcdRmVu4rabrYUyNOx8yPxLhxB3E92m22kSCwPQ,293
|
21
|
-
oe_python_template_example/utils/_constants.py,sha256=
|
23
|
+
oe_python_template_example/utils/_constants.py,sha256=FRe5ZNaBwpBPwOHZVWYOlI-ijamfzdBVr8gl7gHMGT0,2932
|
22
24
|
oe_python_template_example/utils/_di.py,sha256=KdjiD4xZ_QSfbddkKWwsPJmG5YrIg6dzuBrlsd-FhxA,2189
|
25
|
+
oe_python_template_example/utils/_gui.py,sha256=RrvhaIi62X0E_lYou5GdB6LpQcCta2MeSvOKemh6ua4,5460
|
23
26
|
oe_python_template_example/utils/_health.py,sha256=35QOWe2r5InrEpGtuVMym9dI5aRHS0HWf4BHBRAUIj0,4102
|
24
27
|
oe_python_template_example/utils/_log.py,sha256=ZW4gs540SdjVK-2KeheLfDY15d_3xpO5FyGn7wTXyaM,3592
|
25
28
|
oe_python_template_example/utils/_logfire.py,sha256=wZYNVowQx7kh3XJoJ59FjUKdrta7tp6cXOJRUT6lDU8,2128
|
29
|
+
oe_python_template_example/utils/_notebook.py,sha256=oBQw9IBcXjuhzd1ECfOEPN4WJHGOm9xiPtrs11GtWG4,1777
|
26
30
|
oe_python_template_example/utils/_process.py,sha256=40R0NZMqJUn0iUPERzohSUpJgU1HcJApIg1HipIxFCw,941
|
27
31
|
oe_python_template_example/utils/_sentry.py,sha256=2sXrDSZSYoDEM87v7CakJ6eGBtcIhDI48PsQCLwOHgg,3319
|
28
32
|
oe_python_template_example/utils/_service.py,sha256=atHAejvBucKXjzhsMSdOBBFa7rRD74zcV70Pp0pl0Tg,1038
|
29
33
|
oe_python_template_example/utils/_settings.py,sha256=owFoaHEzJnVD3EVyOWF4rfIY7g6eLnU6rN0m4VHhCbA,2464
|
30
|
-
oe_python_template_example/utils/boot.py,sha256=
|
31
|
-
oe_python_template_example
|
32
|
-
oe_python_template_example-0.4.
|
33
|
-
oe_python_template_example-0.4.
|
34
|
-
oe_python_template_example-0.4.
|
35
|
-
oe_python_template_example-0.4.
|
34
|
+
oe_python_template_example/utils/boot.py,sha256=Qgq1sjT8d3fcfibnMyx5CVUJ_KKXgFI3ozZUIJbhh4I,2921
|
35
|
+
oe_python_template_example/utils/.vendored/bottle.py,sha256=D9YkHqkgvKkknd3ZQ-tgflUF6F9Kr2_jpzhod5WqfAM,175461
|
36
|
+
oe_python_template_example-0.4.3.dist-info/METADATA,sha256=d-7MUnXzb7WLnxp0YXs6GCxWD85_ziJjvkdba-H3tek,34643
|
37
|
+
oe_python_template_example-0.4.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
38
|
+
oe_python_template_example-0.4.3.dist-info/entry_points.txt,sha256=S2eCPB45b1Wgj_GsDRFAN-e4h7dBA5UPxT8od98erDE,82
|
39
|
+
oe_python_template_example-0.4.3.dist-info/licenses/LICENSE,sha256=5H409K6xzz9U5eUaoAHQExNkoWJRlU0LEj6wL2QJ34s,1113
|
40
|
+
oe_python_template_example-0.4.3.dist-info/RECORD,,
|
{oe_python_template_example-0.4.1.dist-info → oe_python_template_example-0.4.3.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|