simple-module-feature-flags 0.0.40__tar.gz → 0.0.42__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_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/PKG-INFO +4 -4
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/invalidation.py +8 -1
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/module.py +6 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/package.json +4 -4
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/pyproject.toml +4 -4
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_feature_flags_tenant_cleanup.py +35 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/.gitignore +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/LICENSE +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/README.md +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/__init__.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/constants.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/contracts/__init__.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/contracts/schemas.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/deps.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/endpoints/__init__.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/endpoints/api.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/endpoints/views.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/locales/de.json +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/locales/en.json +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/models.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/pages/Browse.tsx +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/pages/components/FlagTable.tsx +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/pages/components/ScopeCard.tsx +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/pages/components/TenantPicker.tsx +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/pages/components/ToggleConfirmDialog.tsx +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/pages/types.ts +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/py.typed +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/service.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/tenant_cleanup.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/conftest.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_feature_flags_api.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_feature_flags_audit_links.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_feature_flags_commit_invalidation.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_feature_flags_menu_section.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_feature_flags_service.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_feature_flags_tenancy.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_flag_description_i18n.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests/test_store_outage_fallback.py +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tests-js/feature_flags_Browse.test.tsx +0 -0
- {simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/tsconfig.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: simple_module_feature_flags
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.42
|
|
4
4
|
Summary: Simple feature-flag module with per-tenant overrides and a consumer API for simple_module
|
|
5
5
|
Project-URL: Homepage, https://github.com/antosubash/simple_module_python
|
|
6
6
|
Project-URL: Repository, https://github.com/antosubash/simple_module_python
|
|
@@ -21,9 +21,9 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
22
22
|
Classifier: Typing :: Typed
|
|
23
23
|
Requires-Python: >=3.12
|
|
24
|
-
Requires-Dist: simple-module-core==0.0.
|
|
25
|
-
Requires-Dist: simple-module-db==0.0.
|
|
26
|
-
Requires-Dist: simple-module-hosting==0.0.
|
|
24
|
+
Requires-Dist: simple-module-core==0.0.42
|
|
25
|
+
Requires-Dist: simple-module-db==0.0.42
|
|
26
|
+
Requires-Dist: simple-module-hosting==0.0.42
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
|
|
29
29
|
# simple_module_feature_flags
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""Re-read flag overrides after commit or a remote invalidation."""
|
|
2
2
|
|
|
3
3
|
from fastapi import FastAPI
|
|
4
|
-
from simple_module_core.invalidation import InvalidationBus
|
|
4
|
+
from simple_module_core.invalidation import Invalidation, InvalidationBus
|
|
5
5
|
from simple_module_core.invalidation_refresh import InvalidationRefresh
|
|
6
|
+
from simple_module_core.tenant_events import TENANT_DELETED_CHANNEL
|
|
6
7
|
|
|
7
8
|
from feature_flags.service import FeatureFlagService
|
|
8
9
|
|
|
@@ -10,6 +11,12 @@ CHANNEL = "feature_flags.overrides"
|
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def subscribe(bus: InvalidationBus, app: FastAPI) -> InvalidationRefresh:
|
|
14
|
+
def forget_tenant(message: Invalidation) -> None:
|
|
15
|
+
if message.key is not None:
|
|
16
|
+
app.state.sm.feature_flags.clear_tenant_overrides(message.key)
|
|
17
|
+
|
|
18
|
+
bus.subscribe(TENANT_DELETED_CHANNEL, forget_tenant)
|
|
19
|
+
|
|
13
20
|
async def reload(_key: str | None) -> None:
|
|
14
21
|
async with app.state.sm.db.session_factory() as db:
|
|
15
22
|
await FeatureFlagService(db).hydrate_registry(app.state.sm.feature_flags)
|
{simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/module.py
RENAMED
|
@@ -75,6 +75,12 @@ class FeatureFlagsModule(ModuleBase):
|
|
|
75
75
|
from feature_flags.tenant_cleanup import purge_tenant_data
|
|
76
76
|
|
|
77
77
|
bus.subscribe_durable(TenantDeleted, purge_tenant_data)
|
|
78
|
+
if app is not None:
|
|
79
|
+
|
|
80
|
+
async def forget_tenant(event: TenantDeleted) -> None:
|
|
81
|
+
app.state.sm.feature_flags.clear_tenant_overrides(event.tenant_id)
|
|
82
|
+
|
|
83
|
+
bus.subscribe(TenantDeleted, forget_tenant)
|
|
78
84
|
|
|
79
85
|
def register_invalidations(self, bus: InvalidationBus, app: FastAPI) -> None:
|
|
80
86
|
from feature_flags.invalidation import subscribe
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simple-module-py/feature_flags",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.42",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Frontend assets for the FeatureFlags module",
|
|
6
6
|
"peerDependencies": {
|
|
7
|
+
"@inertiajs/react": "^3.9.1",
|
|
8
|
+
"@simple-module-py/ui": "*",
|
|
7
9
|
"react": "^19.0.0",
|
|
8
|
-
"react-dom": "^19.
|
|
9
|
-
"@inertiajs/react": "^3.7.0",
|
|
10
|
-
"@simple-module-py/ui": "*"
|
|
10
|
+
"react-dom": "^19.3.1"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@simple-module-py/tsconfig": "*"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "simple_module_feature_flags"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.42"
|
|
4
4
|
description = "Simple feature-flag module with per-tenant overrides and a consumer API for simple_module"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -21,9 +21,9 @@ classifiers = [
|
|
|
21
21
|
"Typing :: Typed",
|
|
22
22
|
]
|
|
23
23
|
dependencies = [
|
|
24
|
-
"simple_module_core==0.0.
|
|
25
|
-
"simple_module_db==0.0.
|
|
26
|
-
"simple_module_hosting==0.0.
|
|
24
|
+
"simple_module_core==0.0.42",
|
|
25
|
+
"simple_module_db==0.0.42",
|
|
26
|
+
"simple_module_hosting==0.0.42",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.entry-points.simple_module]
|
|
@@ -32,3 +32,38 @@ async def test_durable_tenant_cleanup_is_scoped_idempotent_and_transactional(db_
|
|
|
32
32
|
(SCOPE_TENANT, "other"),
|
|
33
33
|
(SCOPE_SYSTEM, "deleted"),
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def test_feature_flags_tenant_event_clears_only_deleted_tenant():
|
|
38
|
+
from types import SimpleNamespace
|
|
39
|
+
|
|
40
|
+
from fastapi import FastAPI
|
|
41
|
+
from simple_module_core.feature_flags import FeatureFlagRegistry
|
|
42
|
+
|
|
43
|
+
app = FastAPI()
|
|
44
|
+
registry = FeatureFlagRegistry()
|
|
45
|
+
app.state.sm = SimpleNamespace(feature_flags=registry)
|
|
46
|
+
registry.set_override("unknown.flag", True, tenant_id="deleted")
|
|
47
|
+
registry.set_override("unknown.flag", True, tenant_id="other")
|
|
48
|
+
registry.set_override("unknown.flag", False)
|
|
49
|
+
bus = EventBus()
|
|
50
|
+
FeatureFlagsModule().register_event_handlers(bus, app)
|
|
51
|
+
event = TenantDeleted(tenant_id="deleted", slug="deleted", name="Deleted")
|
|
52
|
+
await bus.publish(event)
|
|
53
|
+
await bus.publish(event)
|
|
54
|
+
assert registry.tenant_override("unknown.flag", "deleted") is None
|
|
55
|
+
assert registry.tenant_override("unknown.flag", "other") is True
|
|
56
|
+
assert registry.system_override("unknown.flag") is False
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def test_feature_flags_remote_tenant_deletion_clears_registry(app):
|
|
60
|
+
from simple_module_core.invalidation import Invalidation
|
|
61
|
+
from simple_module_core.tenant_events import TENANT_DELETED_CHANNEL
|
|
62
|
+
|
|
63
|
+
registry = app.state.sm.feature_flags
|
|
64
|
+
registry.set_override("unknown.flag", True, tenant_id="deleted")
|
|
65
|
+
registry.set_override("unknown.flag", True, tenant_id="other")
|
|
66
|
+
message = Invalidation(channel=TENANT_DELETED_CHANNEL, key="deleted", origin="other")
|
|
67
|
+
await app.state.sm.invalidation.deliver(message.to_wire())
|
|
68
|
+
assert registry.tenant_override("unknown.flag", "deleted") is None
|
|
69
|
+
assert registry.tenant_override("unknown.flag", "other") is True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/__init__.py
RENAMED
|
File without changes
|
{simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/deps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/py.typed
RENAMED
|
File without changes
|
{simple_module_feature_flags-0.0.40 → simple_module_feature_flags-0.0.42}/feature_flags/service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|