simple-module-hosting 0.0.20__tar.gz → 0.0.22__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 (56) hide show
  1. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/PKG-INFO +3 -3
  2. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/pyproject.toml +3 -3
  3. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/_inertia_setup.py +30 -0
  4. simple_module_hosting-0.0.22/tests/test_branding_head.py +32 -0
  5. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/.gitignore +0 -0
  6. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/LICENSE +0 -0
  7. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/README.md +0 -0
  8. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/__init__.py +0 -0
  9. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/__main__.py +0 -0
  10. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/_error_handlers.py +0 -0
  11. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/_host_services.py +0 -0
  12. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/_hydrate_step.py +0 -0
  13. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/_inertia_shared.py +0 -0
  14. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/_observability.py +0 -0
  15. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/_phase_helpers.py +0 -0
  16. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/app_builder.py +0 -0
  17. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/bootstrap_settings.py +0 -0
  18. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/health.py +0 -0
  19. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/host_cli.py +0 -0
  20. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/host_settings.py +0 -0
  21. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/i18n_deps.py +0 -0
  22. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/i18n_manifest.py +0 -0
  23. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/i18n_middleware.py +0 -0
  24. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/inertia_deps.py +0 -0
  25. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/inertia_utils.py +0 -0
  26. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/logging.py +0 -0
  27. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/manifest.py +0 -0
  28. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/middleware.py +0 -0
  29. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/migrations.py +0 -0
  30. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/permissions.py +0 -0
  31. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/py.typed +0 -0
  32. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/redirects.py +0 -0
  33. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/settings.py +0 -0
  34. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/simple_module_hosting/shared_props.py +0 -0
  35. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_app.py +0 -0
  36. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_check_migrations.py +0 -0
  37. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_health.py +0 -0
  38. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_host_cli.py +0 -0
  39. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_hosting_permissions.py +0 -0
  40. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_i18n_manifest.py +0 -0
  41. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_inertia_i18n_shared_props.py +0 -0
  42. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_inertia_manifest.py +0 -0
  43. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_inertia_shared_providers.py +0 -0
  44. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_lifespan_order.py +0 -0
  45. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_locale_middleware.py +0 -0
  46. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_logging.py +0 -0
  47. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_manifest.py +0 -0
  48. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_middleware_order.py +0 -0
  49. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_redirects.py +0 -0
  50. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_session_cookie_security.py +0 -0
  51. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_settings_i18n.py +0 -0
  52. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_settings_secrets.py +0 -0
  53. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_static_caching.py +0 -0
  54. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_strict_discovery_wiring.py +0 -0
  55. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_tenant_middleware.py +0 -0
  56. {simple_module_hosting-0.0.20 → simple_module_hosting-0.0.22}/tests/test_translator_dep.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simple_module_hosting
3
- Version: 0.0.20
3
+ Version: 0.0.22
4
4
  Summary: FastAPI + Inertia.js host runtime for simple_module — app_builder, middleware stack, CLI (sm / simple-module), scaffolding
5
5
  Project-URL: Homepage, https://github.com/antosubash/simple_module_python
6
6
  Project-URL: Repository, https://github.com/antosubash/simple_module_python
@@ -26,8 +26,8 @@ Requires-Dist: fastapi-inertia>=1.0
26
26
  Requires-Dist: fastapi>=0.115
27
27
  Requires-Dist: httpx>=0.27
28
28
  Requires-Dist: jinja2>=3.1
29
- Requires-Dist: simple-module-core==0.0.20
30
- Requires-Dist: simple-module-db==0.0.20
29
+ Requires-Dist: simple-module-core==0.0.22
30
+ Requires-Dist: simple-module-db==0.0.22
31
31
  Requires-Dist: starlette>=0.44
32
32
  Requires-Dist: tomlkit>=0.13
33
33
  Requires-Dist: uvicorn[standard]>=0.34
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "simple_module_hosting"
3
- version = "0.0.20"
3
+ version = "0.0.22"
4
4
  description = "FastAPI + Inertia.js host runtime for simple_module — app_builder, middleware stack, CLI (sm / simple-module), scaffolding"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -26,8 +26,8 @@ dependencies = [
26
26
  "fastapi-inertia>=1.0",
27
27
  "httpx>=0.27",
28
28
  "jinja2>=3.1",
29
- "simple_module_core==0.0.20",
30
- "simple_module_db==0.0.20",
29
+ "simple_module_core==0.0.22",
30
+ "simple_module_db==0.0.22",
31
31
  "starlette>=0.44",
32
32
  "tomlkit>=0.13",
33
33
  "uvicorn[standard]>=0.34",
@@ -10,6 +10,7 @@ from pathlib import Path
10
10
 
11
11
  from fastapi import FastAPI
12
12
  from inertia import InertiaConfig, inertia_dependency_factory
13
+ from starlette.requests import Request
13
14
 
14
15
  from simple_module_hosting.settings import Settings
15
16
 
@@ -19,6 +20,33 @@ _INERTIA_VERSION = "1.0"
19
20
  _ROOT_TEMPLATE_FILENAME = "index.html"
20
21
  _ENTRYPOINT_FILENAME = "main.tsx"
21
22
  _ROOT_DIRECTORY = "."
23
+
24
+ # Fallback app name when the (optional) branding module isn't installed. Mirrors
25
+ # branding's own default so the unbranded title is identical everywhere.
26
+ _DEFAULT_APP_NAME = "SimpleModule"
27
+
28
+
29
+ def branding_head(request: Request) -> dict:
30
+ """Branding metadata for the root template's ``<head>``.
31
+
32
+ Reads the optional branding module's settings off ``app.state`` by name
33
+ (duck-typed, never imported) so the static ``<title>`` and ``theme-color``
34
+ are already branded *before* React hydrates. Degrades to the framework
35
+ default when branding isn't installed. Only plain settings strings are
36
+ surfaced here — the favicon is applied client-side by ``BrandingHead`` via
37
+ Inertia's ``<Head>``, keeping file_storage's download-route shape out of
38
+ framework code.
39
+ """
40
+ services = getattr(request.app.state, "branding", None)
41
+ settings = getattr(services, "settings", None)
42
+ if settings is None:
43
+ return {"app_name": _DEFAULT_APP_NAME, "theme_color": None}
44
+ return {
45
+ "app_name": getattr(settings, "app_name", "") or _DEFAULT_APP_NAME,
46
+ "theme_color": getattr(settings, "primary_color", "") or None,
47
+ }
48
+
49
+
22
50
  # Built assets are served from the "/static" mount under "dist/", so production
23
51
  # asset URLs are prefixed with "static/dist".
24
52
  _ASSETS_PREFIX = "static/dist"
@@ -120,6 +148,8 @@ def setup_inertia(
120
148
  return None
121
149
 
122
150
  templates = Jinja2Templates(directory=directories)
151
+ # Expose branding metadata to the root template (pre-hydration head tags).
152
+ templates.env.globals["branding_head"] = branding_head
123
153
 
124
154
  # fastapi-inertia only switches to the asset manifest when environment
125
155
  # equals the literal string "production". Anything else (staging, qa,
@@ -0,0 +1,32 @@
1
+ """Tests for the root-template branding head metadata helper."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from types import SimpleNamespace
6
+
7
+ from simple_module_hosting._inertia_setup import branding_head
8
+
9
+
10
+ def _request(branding: object | None) -> SimpleNamespace:
11
+ state = SimpleNamespace()
12
+ if branding is not None:
13
+ state.branding = branding
14
+ return SimpleNamespace(app=SimpleNamespace(state=state))
15
+
16
+
17
+ def test_defaults_when_branding_not_installed() -> None:
18
+ meta = branding_head(_request(None))
19
+ assert meta == {"app_name": "SimpleModule", "theme_color": None}
20
+
21
+
22
+ def test_reads_app_name_and_theme_color() -> None:
23
+ settings = SimpleNamespace(app_name="Acme", primary_color="#1a7dd1")
24
+ meta = branding_head(_request(SimpleNamespace(settings=settings)))
25
+ assert meta["app_name"] == "Acme"
26
+ assert meta["theme_color"] == "#1a7dd1"
27
+
28
+
29
+ def test_blank_values_fall_back() -> None:
30
+ settings = SimpleNamespace(app_name="", primary_color="")
31
+ meta = branding_head(_request(SimpleNamespace(settings=settings)))
32
+ assert meta == {"app_name": "SimpleModule", "theme_color": None}