simple-module-hosting 0.0.17__tar.gz → 0.0.19__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.
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/PKG-INFO +3 -3
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/pyproject.toml +3 -3
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_phase_helpers.py +14 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/app_builder.py +10 -1
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/bootstrap_settings.py +9 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_app.py +89 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/.gitignore +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/LICENSE +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/README.md +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/__init__.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/__main__.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_error_handlers.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_host_services.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_hydrate_step.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_inertia_setup.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_inertia_shared.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_observability.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/health.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/host_cli.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/host_settings.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/i18n_deps.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/i18n_manifest.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/i18n_middleware.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/inertia_deps.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/inertia_utils.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/logging.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/manifest.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/middleware.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/migrations.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/permissions.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/py.typed +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/redirects.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/settings.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_check_migrations.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_health.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_host_cli.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_hosting_permissions.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_i18n_manifest.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_inertia_i18n_shared_props.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_lifespan_order.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_locale_middleware.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_logging.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_manifest.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_middleware_order.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_redirects.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_session_cookie_security.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_settings_i18n.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_settings_secrets.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_strict_discovery_wiring.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_tenant_middleware.py +0 -0
- {simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/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.
|
|
3
|
+
Version: 0.0.19
|
|
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.
|
|
30
|
-
Requires-Dist: simple-module-db==0.0.
|
|
29
|
+
Requires-Dist: simple-module-core==0.0.19
|
|
30
|
+
Requires-Dist: simple-module-db==0.0.19
|
|
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.
|
|
3
|
+
version = "0.0.19"
|
|
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.
|
|
30
|
-
"simple_module_db==0.0.
|
|
29
|
+
"simple_module_core==0.0.19",
|
|
30
|
+
"simple_module_db==0.0.19",
|
|
31
31
|
"starlette>=0.44",
|
|
32
32
|
"tomlkit>=0.13",
|
|
33
33
|
"uvicorn[standard]>=0.34",
|
|
@@ -105,6 +105,20 @@ def install_middleware(
|
|
|
105
105
|
app.add_middleware(CorrelationIdMiddleware)
|
|
106
106
|
|
|
107
107
|
|
|
108
|
+
def attach_public_routes(app: FastAPI, settings: Settings, registry) -> None:
|
|
109
|
+
"""Seed host-level public paths and publish the registry for AuthMiddleware.
|
|
110
|
+
|
|
111
|
+
Modules contribute method-aware rules through their ``register_public_routes``
|
|
112
|
+
hook (already applied to *registry* by the caller). This adds the host escape
|
|
113
|
+
hatch — ``SM_AUTH_PUBLIC_PATHS`` prefixes — then exposes the registry at
|
|
114
|
+
``app.state.public_routes``, where ``auth.middleware.AuthMiddleware`` reads it
|
|
115
|
+
on every request.
|
|
116
|
+
"""
|
|
117
|
+
for prefix in settings.auth_public_paths:
|
|
118
|
+
registry.add_prefix(prefix)
|
|
119
|
+
app.state.public_routes = registry
|
|
120
|
+
|
|
121
|
+
|
|
108
122
|
def mount_module_static_dirs(app: FastAPI, modules: list) -> None:
|
|
109
123
|
"""Mount each module's declared static directories.
|
|
110
124
|
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/app_builder.py
RENAMED
|
@@ -18,6 +18,7 @@ from simple_module_core.feature_flags import FeatureFlagRegistry
|
|
|
18
18
|
from simple_module_core.health import HealthRegistry
|
|
19
19
|
from simple_module_core.menu import MenuRegistry
|
|
20
20
|
from simple_module_core.permissions import PermissionRegistry
|
|
21
|
+
from simple_module_core.public_routes import PublicRouteRegistry
|
|
21
22
|
from simple_module_core.services import Services
|
|
22
23
|
from simple_module_db.listeners import register_listeners
|
|
23
24
|
from simple_module_db.session import init_db
|
|
@@ -25,6 +26,7 @@ from simple_module_db.session import init_db
|
|
|
25
26
|
from simple_module_hosting._host_services import _HostServices
|
|
26
27
|
from simple_module_hosting._inertia_setup import setup_inertia
|
|
27
28
|
from simple_module_hosting._phase_helpers import (
|
|
29
|
+
attach_public_routes,
|
|
28
30
|
check_settings_registration,
|
|
29
31
|
install_middleware,
|
|
30
32
|
mount_module_static_dirs,
|
|
@@ -162,6 +164,7 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
|
|
162
164
|
ff_registry = FeatureFlagRegistry()
|
|
163
165
|
event_bus = EventBus()
|
|
164
166
|
health_registry = HealthRegistry()
|
|
167
|
+
public_route_registry = PublicRouteRegistry()
|
|
165
168
|
|
|
166
169
|
@asynccontextmanager
|
|
167
170
|
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
|
@@ -232,13 +235,18 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
|
|
232
235
|
mod.register_feature_flags(ff_registry)
|
|
233
236
|
_register_event_handlers(mod, event_bus, app)
|
|
234
237
|
mod.register_health_checks(health_registry)
|
|
238
|
+
mod.register_public_routes(public_route_registry)
|
|
239
|
+
|
|
240
|
+
attach_public_routes(app, settings, public_route_registry)
|
|
235
241
|
|
|
236
242
|
logger.info(
|
|
237
|
-
"Registered %d menu items, %d permissions, %d feature flags,
|
|
243
|
+
"Registered %d menu items, %d permissions, %d feature flags, "
|
|
244
|
+
"%d health checks, %d public routes",
|
|
238
245
|
len(menu_registry.all_items),
|
|
239
246
|
len(perm_registry.all_permissions),
|
|
240
247
|
len(ff_registry.all_flags),
|
|
241
248
|
len(health_registry.all_checks),
|
|
249
|
+
len(public_route_registry.routes),
|
|
242
250
|
)
|
|
243
251
|
|
|
244
252
|
# ── Phase 6: Initialize database ───────────────────────
|
|
@@ -281,6 +289,7 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
|
|
281
289
|
permissions=perm_registry,
|
|
282
290
|
feature_flags=ff_registry,
|
|
283
291
|
health_registry=health_registry,
|
|
292
|
+
public_routes=public_route_registry,
|
|
284
293
|
i18n_registry=i18n_registry,
|
|
285
294
|
inertia_config=inertia_config,
|
|
286
295
|
modules=tuple(modules),
|
|
@@ -37,6 +37,15 @@ class BootstrapSettings(BaseSettings):
|
|
|
37
37
|
|
|
38
38
|
modules_enabled: list[str] | None = None
|
|
39
39
|
|
|
40
|
+
auth_public_paths: list[str] = []
|
|
41
|
+
"""Host-level anonymous-access path prefixes (``SM_AUTH_PUBLIC_PATHS``).
|
|
42
|
+
|
|
43
|
+
An escape hatch for exposing a route without a session when no module owns
|
|
44
|
+
it. Each entry is treated as a prefix rule and seeded into the
|
|
45
|
+
``PublicRouteRegistry`` at boot. Modules should prefer the
|
|
46
|
+
``register_public_routes`` hook, which is method-aware.
|
|
47
|
+
"""
|
|
48
|
+
|
|
40
49
|
@property
|
|
41
50
|
def is_development(self) -> bool:
|
|
42
51
|
return self.environment == "development"
|
|
@@ -65,6 +65,95 @@ class TestCreateApp:
|
|
|
65
65
|
paths = {getattr(r, "path", None) for r in app.routes}
|
|
66
66
|
assert "/modules/fakestatic/static" in paths
|
|
67
67
|
|
|
68
|
+
async def test_module_register_public_routes_is_wired(
|
|
69
|
+
self,
|
|
70
|
+
settings: Settings,
|
|
71
|
+
monkeypatch,
|
|
72
|
+
):
|
|
73
|
+
"""register_public_routes() contributions land on app.state.public_routes."""
|
|
74
|
+
from simple_module_core import ModuleBase, ModuleMeta
|
|
75
|
+
from simple_module_hosting import app_builder
|
|
76
|
+
|
|
77
|
+
class FakePublicMod(ModuleBase):
|
|
78
|
+
meta = ModuleMeta(name="FakePublic")
|
|
79
|
+
|
|
80
|
+
def register_public_routes(self, registry):
|
|
81
|
+
registry.add_prefix("/api/fakepublic/stac")
|
|
82
|
+
registry.add_regex(r"/api/fakepublic/datasets/[^/]+/tilejson$", methods={"GET"})
|
|
83
|
+
|
|
84
|
+
real_discover = app_builder.discover_modules
|
|
85
|
+
|
|
86
|
+
def fake_discover(enabled=None, *, strict=False):
|
|
87
|
+
return [*real_discover(enabled=enabled, strict=strict), FakePublicMod()]
|
|
88
|
+
|
|
89
|
+
monkeypatch.setattr(app_builder, "discover_modules", fake_discover)
|
|
90
|
+
|
|
91
|
+
app = create_app(settings)
|
|
92
|
+
registry = app.state.public_routes
|
|
93
|
+
assert registry is app.state.sm.public_routes
|
|
94
|
+
assert registry.matches("GET", "/api/fakepublic/stac/collections")
|
|
95
|
+
assert registry.matches("GET", "/api/fakepublic/datasets/7/tilejson")
|
|
96
|
+
assert not registry.matches("PATCH", "/api/fakepublic/datasets/7/tilejson")
|
|
97
|
+
|
|
98
|
+
async def test_host_public_paths_setting_is_seeded(self, settings: Settings):
|
|
99
|
+
"""SM_AUTH_PUBLIC_PATHS prefixes land on the registry as prefix rules."""
|
|
100
|
+
with_paths = settings.model_copy(
|
|
101
|
+
update={"auth_public_paths": ["/api/hostpublic", "/status"]}
|
|
102
|
+
)
|
|
103
|
+
app = create_app(with_paths)
|
|
104
|
+
registry = app.state.public_routes
|
|
105
|
+
assert registry.matches("GET", "/api/hostpublic/anything")
|
|
106
|
+
assert registry.matches("POST", "/status")
|
|
107
|
+
assert not registry.matches("GET", "/api/private")
|
|
108
|
+
|
|
109
|
+
async def test_module_public_route_reachable_anonymously(
|
|
110
|
+
self,
|
|
111
|
+
settings: Settings,
|
|
112
|
+
monkeypatch,
|
|
113
|
+
):
|
|
114
|
+
"""End-to-end: an unauthenticated GET to a module-declared public route
|
|
115
|
+
returns 200, while a sibling gated route under the same prefix 401s.
|
|
116
|
+
|
|
117
|
+
This is the repro from issue #191 — a read-only anonymous API
|
|
118
|
+
(STAC / OGC) consumed without a session cookie.
|
|
119
|
+
"""
|
|
120
|
+
from simple_module_core import ModuleBase, ModuleMeta
|
|
121
|
+
from simple_module_hosting import app_builder
|
|
122
|
+
|
|
123
|
+
class FakeGisMod(ModuleBase):
|
|
124
|
+
meta = ModuleMeta(name="FakeGis", route_prefix="/api/fakegis")
|
|
125
|
+
|
|
126
|
+
def register_routes(self, api_router, view_router):
|
|
127
|
+
@api_router.get("/stac")
|
|
128
|
+
async def stac():
|
|
129
|
+
return {"type": "Catalog"}
|
|
130
|
+
|
|
131
|
+
@api_router.get("/secret")
|
|
132
|
+
async def secret():
|
|
133
|
+
return {"private": True}
|
|
134
|
+
|
|
135
|
+
def register_public_routes(self, registry):
|
|
136
|
+
registry.add_prefix("/api/fakegis/stac")
|
|
137
|
+
|
|
138
|
+
real_discover = app_builder.discover_modules
|
|
139
|
+
|
|
140
|
+
def fake_discover(enabled=None, *, strict=False):
|
|
141
|
+
return [*real_discover(enabled=enabled, strict=strict), FakeGisMod()]
|
|
142
|
+
|
|
143
|
+
monkeypatch.setattr(app_builder, "discover_modules", fake_discover)
|
|
144
|
+
|
|
145
|
+
app = create_app(settings)
|
|
146
|
+
transport = httpx.ASGITransport(app=app)
|
|
147
|
+
async with httpx.AsyncClient(
|
|
148
|
+
transport=transport, base_url="http://testserver", follow_redirects=False
|
|
149
|
+
) as client:
|
|
150
|
+
public = await client.get("/api/fakegis/stac")
|
|
151
|
+
gated = await client.get("/api/fakegis/secret")
|
|
152
|
+
|
|
153
|
+
assert public.status_code == 200
|
|
154
|
+
assert public.json() == {"type": "Catalog"}
|
|
155
|
+
assert gated.status_code == 401
|
|
156
|
+
|
|
68
157
|
async def test_app_state_has_sm_services(
|
|
69
158
|
self, monkeypatch: pytest.MonkeyPatch, tmp_path
|
|
70
159
|
) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/__init__.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/_hydrate_step.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/health.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/host_cli.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/host_settings.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/i18n_deps.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/i18n_manifest.py
RENAMED
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/inertia_deps.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/inertia_utils.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/logging.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/manifest.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/middleware.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/migrations.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/permissions.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/py.typed
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/redirects.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/simple_module_hosting/settings.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_check_migrations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_hosting_permissions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_locale_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_middleware_order.py
RENAMED
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_session_cookie_security.py
RENAMED
|
File without changes
|
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_settings_secrets.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_strict_discovery_wiring.py
RENAMED
|
File without changes
|
{simple_module_hosting-0.0.17 → simple_module_hosting-0.0.19}/tests/test_tenant_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|