simple-module-core 0.0.16__tar.gz → 0.0.17__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 (47) hide show
  1. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/PKG-INFO +1 -1
  2. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/pyproject.toml +1 -1
  3. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_module.py +33 -0
  4. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_diagnostics.py +48 -0
  5. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/.gitignore +0 -0
  6. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/LICENSE +0 -0
  7. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/README.md +0 -0
  8. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/__init__.py +0 -0
  9. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/__main__.py +0 -0
  10. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/__init__.py +0 -0
  11. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_coupling.py +0 -0
  12. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_i18n.py +0 -0
  13. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_inertia_api.py +0 -0
  14. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_js_workspace.py +0 -0
  15. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_migration.py +0 -0
  16. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_pages.py +0 -0
  17. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_runner.py +0 -0
  18. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/diagnostics/_types.py +0 -0
  19. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/discovery.py +0 -0
  20. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/dotenv.py +0 -0
  21. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/environments.py +0 -0
  22. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/events.py +0 -0
  23. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/exceptions.py +0 -0
  24. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/feature_flags.py +0 -0
  25. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/health.py +0 -0
  26. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/i18n.py +0 -0
  27. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/menu.py +0 -0
  28. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/module.py +0 -0
  29. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/permissions.py +0 -0
  30. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/py.typed +0 -0
  31. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/services.py +0 -0
  32. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/simple_module_core/versioning.py +0 -0
  33. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_discovery.py +0 -0
  34. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_dotenv.py +0 -0
  35. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_environments.py +0 -0
  36. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_events.py +0 -0
  37. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_feature_flags.py +0 -0
  38. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_feature_flags_decorator.py +0 -0
  39. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_health_registry.py +0 -0
  40. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_i18n.py +0 -0
  41. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_i18n_diagnostics.py +0 -0
  42. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_menu.py +0 -0
  43. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_module_base.py +0 -0
  44. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_module_diagnostics.py +0 -0
  45. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_permissions.py +0 -0
  46. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_services.py +0 -0
  47. {simple_module_core-0.0.16 → simple_module_core-0.0.17}/tests/test_versioning.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simple_module_core
3
- Version: 0.0.16
3
+ Version: 0.0.17
4
4
  Summary: Module-system primitives for the simple_module framework — ModuleBase, discovery, diagnostics, events
5
5
  Project-URL: Homepage, https://github.com/antosubash/simple_module_python
6
6
  Project-URL: Repository, https://github.com/antosubash/simple_module_python
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "simple_module_core"
3
- version = "0.0.16"
3
+ version = "0.0.17"
4
4
  description = "Module-system primitives for the simple_module framework — ModuleBase, discovery, diagnostics, events"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -26,6 +26,7 @@ class ModuleDiagnostics:
26
26
  diagnostics.extend(self._check_empty_modules(modules))
27
27
  diagnostics.extend(self._check_missing_meta(modules))
28
28
  diagnostics.extend(self._check_views_without_menu(modules))
29
+ diagnostics.extend(self._check_auth_provider_conflict(modules))
29
30
  diagnostics.extend(check_framework_module_coupling(modules))
30
31
 
31
32
  # File-based checks (need to find module source directories)
@@ -162,6 +163,38 @@ class ModuleDiagnostics:
162
163
  )
163
164
  return diags
164
165
 
166
+ def _check_auth_provider_conflict(self, modules: list[ModuleBase]) -> list[Diagnostic]:
167
+ """SM020/SM021: exactly one auth provider module must be installed."""
168
+ providers = [m for m in modules if getattr(m, "_is_auth_provider", False)]
169
+ diags: list[Diagnostic] = []
170
+ if len(providers) > 1:
171
+ names = ", ".join(m.meta.name for m in providers)
172
+ diags.append(
173
+ Diagnostic(
174
+ level=DiagnosticLevel.ERROR,
175
+ code="SM020",
176
+ message=f"Multiple auth provider modules installed: {names}",
177
+ module_name=providers[0].meta.name,
178
+ suggestion=(
179
+ "Install only one auth provider (e.g. 'users' OR 'keycloak', not both)"
180
+ ),
181
+ )
182
+ )
183
+ elif len(providers) == 0:
184
+ diags.append(
185
+ Diagnostic(
186
+ level=DiagnosticLevel.WARNING,
187
+ code="SM021",
188
+ message="No auth provider module installed",
189
+ module_name="(none)",
190
+ suggestion=(
191
+ "Install an auth provider module "
192
+ "(e.g. 'simple-module-users' or 'simple-module-keycloak')"
193
+ ),
194
+ )
195
+ )
196
+ return diags
197
+
165
198
  def _check_missing_meta(self, modules: list[ModuleBase]) -> list[Diagnostic]:
166
199
  diags: list[Diagnostic] = []
167
200
  for mod in modules:
@@ -72,3 +72,51 @@ class TestPrintDiagnostics:
72
72
  captured = capsys.readouterr()
73
73
  assert captured.out == ""
74
74
  assert captured.err == ""
75
+
76
+
77
+ class TestAuthProviderDiagnostics:
78
+ def test_sm020_multiple_auth_providers(self):
79
+ from simple_module_core.diagnostics._module import ModuleDiagnostics
80
+ from simple_module_core.module import ModuleBase, ModuleMeta
81
+
82
+ class FakeUsers(ModuleBase):
83
+ meta = ModuleMeta(name="Users")
84
+ _is_auth_provider = True
85
+
86
+ class FakeKeycloak(ModuleBase):
87
+ meta = ModuleMeta(name="Keycloak")
88
+ _is_auth_provider = True
89
+
90
+ diags = ModuleDiagnostics()
91
+ results = diags._check_auth_provider_conflict([FakeUsers(), FakeKeycloak()])
92
+ assert len(results) == 1
93
+ assert results[0].code == "SM020"
94
+ assert results[0].level == DiagnosticLevel.ERROR
95
+
96
+ def test_sm021_no_auth_provider(self):
97
+ from simple_module_core.diagnostics._module import ModuleDiagnostics
98
+ from simple_module_core.module import ModuleBase, ModuleMeta
99
+
100
+ class FakeDashboard(ModuleBase):
101
+ meta = ModuleMeta(name="Dashboard")
102
+
103
+ diags = ModuleDiagnostics()
104
+ results = diags._check_auth_provider_conflict([FakeDashboard()])
105
+ assert len(results) == 1
106
+ assert results[0].code == "SM021"
107
+ assert results[0].level == DiagnosticLevel.WARNING
108
+
109
+ def test_single_provider_passes(self):
110
+ from simple_module_core.diagnostics._module import ModuleDiagnostics
111
+ from simple_module_core.module import ModuleBase, ModuleMeta
112
+
113
+ class FakeUsers(ModuleBase):
114
+ meta = ModuleMeta(name="Users")
115
+ _is_auth_provider = True
116
+
117
+ class FakeDashboard(ModuleBase):
118
+ meta = ModuleMeta(name="Dashboard")
119
+
120
+ diags = ModuleDiagnostics()
121
+ results = diags._check_auth_provider_conflict([FakeUsers(), FakeDashboard()])
122
+ assert results == []