django-cfg 1.4.120__py3-none-any.whl → 1.5.1__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.

Potentially problematic release.


This version of django-cfg might be problematic. Click here for more details.

Files changed (80) hide show
  1. django_cfg/__init__.py +8 -4
  2. django_cfg/apps/centrifugo/admin/centrifugo_log.py +33 -71
  3. django_cfg/apps/grpc/__init__.py +9 -0
  4. django_cfg/apps/grpc/admin/__init__.py +11 -0
  5. django_cfg/apps/grpc/admin/config.py +89 -0
  6. django_cfg/apps/grpc/admin/grpc_request_log.py +252 -0
  7. django_cfg/apps/grpc/apps.py +28 -0
  8. django_cfg/apps/grpc/auth/__init__.py +9 -0
  9. django_cfg/apps/grpc/auth/jwt_auth.py +295 -0
  10. django_cfg/apps/grpc/interceptors/__init__.py +19 -0
  11. django_cfg/apps/grpc/interceptors/errors.py +241 -0
  12. django_cfg/apps/grpc/interceptors/logging.py +270 -0
  13. django_cfg/apps/grpc/interceptors/metrics.py +306 -0
  14. django_cfg/apps/grpc/interceptors/request_logger.py +515 -0
  15. django_cfg/apps/grpc/management/__init__.py +1 -0
  16. django_cfg/apps/grpc/management/commands/__init__.py +0 -0
  17. django_cfg/apps/grpc/management/commands/rungrpc.py +302 -0
  18. django_cfg/apps/grpc/managers/__init__.py +10 -0
  19. django_cfg/apps/grpc/managers/grpc_request_log.py +310 -0
  20. django_cfg/apps/grpc/migrations/0001_initial.py +69 -0
  21. django_cfg/apps/grpc/migrations/0002_rename_django_cfg__service_4c4a8e_idx_django_cfg__service_584308_idx_and_more.py +38 -0
  22. django_cfg/apps/grpc/migrations/__init__.py +0 -0
  23. django_cfg/apps/grpc/models/__init__.py +9 -0
  24. django_cfg/apps/grpc/models/grpc_request_log.py +219 -0
  25. django_cfg/apps/grpc/serializers/__init__.py +23 -0
  26. django_cfg/apps/grpc/serializers/health.py +18 -0
  27. django_cfg/apps/grpc/serializers/requests.py +18 -0
  28. django_cfg/apps/grpc/serializers/services.py +50 -0
  29. django_cfg/apps/grpc/serializers/stats.py +22 -0
  30. django_cfg/apps/grpc/services/__init__.py +16 -0
  31. django_cfg/apps/grpc/services/base.py +375 -0
  32. django_cfg/apps/grpc/services/discovery.py +415 -0
  33. django_cfg/apps/grpc/urls.py +23 -0
  34. django_cfg/apps/grpc/utils/__init__.py +13 -0
  35. django_cfg/apps/grpc/utils/proto_gen.py +423 -0
  36. django_cfg/apps/grpc/views/__init__.py +9 -0
  37. django_cfg/apps/grpc/views/monitoring.py +497 -0
  38. django_cfg/apps/maintenance/admin/api_key_admin.py +7 -8
  39. django_cfg/apps/maintenance/admin/site_admin.py +5 -4
  40. django_cfg/apps/payments/admin/balance_admin.py +26 -36
  41. django_cfg/apps/payments/admin/payment_admin.py +65 -85
  42. django_cfg/apps/payments/admin/withdrawal_admin.py +65 -100
  43. django_cfg/apps/tasks/admin/task_log.py +20 -47
  44. django_cfg/apps/urls.py +7 -1
  45. django_cfg/config.py +106 -0
  46. django_cfg/core/base/config_model.py +6 -0
  47. django_cfg/core/builders/apps_builder.py +3 -0
  48. django_cfg/core/generation/integration_generators/grpc_generator.py +318 -0
  49. django_cfg/core/generation/orchestrator.py +10 -0
  50. django_cfg/models/api/grpc/__init__.py +59 -0
  51. django_cfg/models/api/grpc/config.py +364 -0
  52. django_cfg/modules/base.py +15 -0
  53. django_cfg/modules/django_admin/base/pydantic_admin.py +2 -2
  54. django_cfg/modules/django_admin/utils/__init__.py +41 -3
  55. django_cfg/modules/django_admin/utils/badges/__init__.py +13 -0
  56. django_cfg/modules/django_admin/utils/{badges.py → badges/status_badges.py} +3 -3
  57. django_cfg/modules/django_admin/utils/displays/__init__.py +13 -0
  58. django_cfg/modules/django_admin/utils/{displays.py → displays/data_displays.py} +2 -2
  59. django_cfg/modules/django_admin/utils/html/__init__.py +26 -0
  60. django_cfg/modules/django_admin/utils/html/badges.py +47 -0
  61. django_cfg/modules/django_admin/utils/html/base.py +167 -0
  62. django_cfg/modules/django_admin/utils/html/code.py +87 -0
  63. django_cfg/modules/django_admin/utils/html/composition.py +198 -0
  64. django_cfg/modules/django_admin/utils/html/formatting.py +231 -0
  65. django_cfg/modules/django_admin/utils/html/keyvalue.py +219 -0
  66. django_cfg/modules/django_admin/utils/html/markdown_integration.py +108 -0
  67. django_cfg/modules/django_admin/utils/html/progress.py +127 -0
  68. django_cfg/modules/django_admin/utils/html_builder.py +55 -408
  69. django_cfg/modules/django_admin/utils/markdown/__init__.py +21 -0
  70. django_cfg/modules/django_unfold/navigation.py +28 -0
  71. django_cfg/pyproject.toml +3 -5
  72. django_cfg/registry/modules.py +6 -0
  73. {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/METADATA +10 -1
  74. {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/RECORD +79 -30
  75. django_cfg/modules/django_admin/utils/CODE_BLOCK_DOCS.md +0 -396
  76. /django_cfg/modules/django_admin/utils/{mermaid_plugin.py → markdown/mermaid_plugin.py} +0 -0
  77. /django_cfg/modules/django_admin/utils/{markdown_renderer.py → markdown/renderer.py} +0 -0
  78. {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/WHEEL +0 -0
  79. {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/entry_points.txt +0 -0
  80. {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,318 @@
1
+ """
2
+ gRPC framework generator.
3
+
4
+ Handles gRPC server, authentication, and proto configuration.
5
+ Size: ~250 lines (focused on gRPC framework)
6
+ """
7
+
8
+ import logging
9
+ from typing import TYPE_CHECKING, Any, Dict, List
10
+
11
+ if TYPE_CHECKING:
12
+ from ...base.config_model import DjangoConfig
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class GRPCSettingsGenerator:
18
+ """
19
+ Generates gRPC framework settings.
20
+
21
+ Responsibilities:
22
+ - Configure gRPC server settings
23
+ - Setup authentication and interceptors
24
+ - Configure proto generation
25
+ - Auto-detect if gRPC should be enabled
26
+ - Resolve handlers hook from ROOT_URLCONF
27
+
28
+ Example:
29
+ ```python
30
+ generator = GRPCSettingsGenerator(config)
31
+ settings = generator.generate()
32
+ ```
33
+ """
34
+
35
+ def __init__(self, config: "DjangoConfig"):
36
+ """
37
+ Initialize generator with configuration.
38
+
39
+ Args:
40
+ config: DjangoConfig instance
41
+ """
42
+ self.config = config
43
+
44
+ def generate(self) -> Dict[str, Any]:
45
+ """
46
+ Generate gRPC framework settings.
47
+
48
+ Returns:
49
+ Dictionary with gRPC configuration
50
+
51
+ Example:
52
+ >>> generator = GRPCSettingsGenerator(config)
53
+ >>> settings = generator.generate()
54
+ """
55
+ # Check if gRPC should be enabled
56
+ if not self._should_enable_grpc():
57
+ logger.debug("⏭️ gRPC disabled")
58
+ return {}
59
+
60
+ try:
61
+ return self._generate_grpc_settings()
62
+ except ImportError as e:
63
+ logger.warning(f"Failed to import gRPC dependencies: {e}")
64
+ logger.info("💡 Install with: pip install django-cfg[grpc]")
65
+ return {}
66
+ except Exception as e:
67
+ logger.error(f"Failed to generate gRPC settings: {e}")
68
+ return {}
69
+
70
+ def _should_enable_grpc(self) -> bool:
71
+ """
72
+ Check if gRPC should be enabled.
73
+
74
+ Returns:
75
+ True if gRPC should be enabled
76
+ """
77
+ # Check if grpc config exists and is enabled
78
+ if not hasattr(self.config, "grpc") or not self.config.grpc:
79
+ return False
80
+
81
+ if not self.config.grpc.enabled:
82
+ return False
83
+
84
+ # Check if gRPC feature is available
85
+ from django_cfg.config import is_feature_available
86
+ if not is_feature_available("grpc"):
87
+ logger.warning("gRPC enabled but dependencies not installed")
88
+ logger.info("💡 Install with: pip install django-cfg[grpc]")
89
+ return False
90
+
91
+ return True
92
+
93
+ def _generate_grpc_settings(self) -> Dict[str, Any]:
94
+ """
95
+ Generate gRPC-specific settings.
96
+
97
+ Returns:
98
+ Dictionary with gRPC configuration
99
+ """
100
+ settings = {}
101
+
102
+ # Generate GRPC_FRAMEWORK settings
103
+ grpc_framework = self._build_grpc_framework_settings()
104
+ if grpc_framework:
105
+ settings["GRPC_FRAMEWORK"] = grpc_framework
106
+
107
+ # Generate server-specific settings
108
+ grpc_server = self._build_grpc_server_settings()
109
+ if grpc_server:
110
+ settings["GRPC_SERVER"] = grpc_server
111
+
112
+ # Generate auth-specific settings
113
+ grpc_auth = self._build_grpc_auth_settings()
114
+ if grpc_auth:
115
+ settings["GRPC_AUTH"] = grpc_auth
116
+
117
+ # Generate proto-specific settings
118
+ grpc_proto = self._build_grpc_proto_settings()
119
+ if grpc_proto:
120
+ settings["GRPC_PROTO"] = grpc_proto
121
+
122
+ logger.info("✅ gRPC framework enabled")
123
+ logger.info(f" - Server: {self.config.grpc.server.host}:{self.config.grpc.server.port}")
124
+ logger.info(f" - Workers: {self.config.grpc.server.max_workers}")
125
+ logger.info(f" - Auth: {'enabled' if self.config.grpc.auth.enabled else 'disabled'}")
126
+ logger.info(f" - Reflection: {'enabled' if self.config.grpc.server.enable_reflection else 'disabled'}")
127
+
128
+ return settings
129
+
130
+ def _build_grpc_framework_settings(self) -> Dict[str, Any]:
131
+ """
132
+ Build GRPC_FRAMEWORK settings dictionary.
133
+
134
+ Returns:
135
+ Dictionary with framework-level gRPC settings
136
+ """
137
+ grpc_config = self.config.grpc
138
+
139
+ # Resolve handlers hook (replace {ROOT_URLCONF} placeholder)
140
+ handlers_hook = self._resolve_handlers_hook(grpc_config.handlers_hook)
141
+
142
+ # Build interceptors list
143
+ interceptors = self._build_interceptors()
144
+
145
+ framework_settings = {
146
+ "ROOT_HANDLERS_HOOK": handlers_hook,
147
+ "SERVER_INTERCEPTORS": interceptors,
148
+ }
149
+
150
+ # Add auto-registration settings
151
+ if grpc_config.auto_register_apps:
152
+ framework_settings["AUTO_REGISTER_APPS"] = grpc_config.enabled_apps
153
+
154
+ # Add custom services
155
+ if grpc_config.custom_services:
156
+ framework_settings["CUSTOM_SERVICES"] = grpc_config.custom_services
157
+
158
+ return framework_settings
159
+
160
+ def _build_grpc_server_settings(self) -> Dict[str, Any]:
161
+ """
162
+ Build GRPC_SERVER settings dictionary.
163
+
164
+ Returns:
165
+ Dictionary with server configuration
166
+ """
167
+ server_config = self.config.grpc.server
168
+
169
+ server_settings = {
170
+ "host": server_config.host,
171
+ "port": server_config.port,
172
+ "max_workers": server_config.max_workers,
173
+ "enable_reflection": server_config.enable_reflection,
174
+ "enable_health_check": server_config.enable_health_check,
175
+ "max_send_message_length": server_config.max_send_message_length,
176
+ "max_receive_message_length": server_config.max_receive_message_length,
177
+ "keepalive_time_ms": server_config.keepalive_time_ms,
178
+ "keepalive_timeout_ms": server_config.keepalive_timeout_ms,
179
+ }
180
+
181
+ # Add optional compression
182
+ if server_config.compression:
183
+ server_settings["compression"] = server_config.compression
184
+
185
+ # Add custom interceptors from config
186
+ if server_config.interceptors:
187
+ server_settings["custom_interceptors"] = server_config.interceptors
188
+
189
+ return server_settings
190
+
191
+ def _build_grpc_auth_settings(self) -> Dict[str, Any]:
192
+ """
193
+ Build GRPC_AUTH settings dictionary.
194
+
195
+ Returns:
196
+ Dictionary with authentication configuration
197
+ """
198
+ auth_config = self.config.grpc.auth
199
+
200
+ auth_settings = {
201
+ "enabled": auth_config.enabled,
202
+ "require_auth": auth_config.require_auth,
203
+ "token_header": auth_config.token_header,
204
+ "token_prefix": auth_config.token_prefix,
205
+ "jwt_algorithm": auth_config.jwt_algorithm,
206
+ "jwt_verify_exp": auth_config.jwt_verify_exp,
207
+ "jwt_leeway": auth_config.jwt_leeway,
208
+ "public_methods": auth_config.public_methods,
209
+ }
210
+
211
+ # Use JWT secret from auth config or fall back to Django SECRET_KEY
212
+ if auth_config.jwt_secret_key:
213
+ auth_settings["jwt_secret_key"] = auth_config.jwt_secret_key
214
+ else:
215
+ # Will be resolved from Django settings at runtime
216
+ auth_settings["jwt_secret_key"] = None # Signal to use Django SECRET_KEY
217
+
218
+ return auth_settings
219
+
220
+ def _build_grpc_proto_settings(self) -> Dict[str, Any]:
221
+ """
222
+ Build GRPC_PROTO settings dictionary.
223
+
224
+ Returns:
225
+ Dictionary with proto generation configuration
226
+ """
227
+ proto_config = self.config.grpc.proto
228
+
229
+ proto_settings = {
230
+ "auto_generate": proto_config.auto_generate,
231
+ "output_dir": proto_config.output_dir,
232
+ "package_prefix": proto_config.package_prefix,
233
+ "include_services": proto_config.include_services,
234
+ "field_naming": proto_config.field_naming,
235
+ }
236
+
237
+ return proto_settings
238
+
239
+ def _build_interceptors(self) -> List[str]:
240
+ """
241
+ Build list of server interceptors.
242
+
243
+ Interceptors are added in order:
244
+ 1. Request logger interceptor (always enabled for monitoring)
245
+ 2. Logging interceptor (if dev mode)
246
+ 3. Auth interceptor (if auth enabled)
247
+ 4. Metrics interceptor (if dev mode)
248
+ 5. Custom interceptors (from config)
249
+
250
+ Returns:
251
+ List of interceptor class paths
252
+ """
253
+ interceptors = []
254
+
255
+ # Check if we're in dev mode
256
+ is_dev = self.config.env_mode in ("local", "development", "dev")
257
+
258
+ # Add request logger interceptor (always enabled for DB logging)
259
+ interceptors.append(
260
+ "django_cfg.apps.grpc.interceptors.RequestLoggerInterceptor"
261
+ )
262
+
263
+ # Add logging interceptor in dev mode
264
+ if is_dev:
265
+ interceptors.append(
266
+ "django_cfg.apps.grpc.interceptors.LoggingInterceptor"
267
+ )
268
+
269
+ # Add auth interceptor if enabled
270
+ if self.config.grpc.auth.enabled:
271
+ interceptors.append(
272
+ "django_cfg.apps.grpc.auth.JWTAuthInterceptor"
273
+ )
274
+
275
+ # Add metrics interceptor in dev mode
276
+ if is_dev:
277
+ interceptors.append(
278
+ "django_cfg.apps.grpc.interceptors.MetricsInterceptor"
279
+ )
280
+
281
+ # Add custom interceptors from server config
282
+ if self.config.grpc.server.interceptors:
283
+ interceptors.extend(self.config.grpc.server.interceptors)
284
+
285
+ return interceptors
286
+
287
+ def _resolve_handlers_hook(self, handlers_hook: str) -> str:
288
+ """
289
+ Resolve handlers hook path.
290
+
291
+ Replaces {ROOT_URLCONF} placeholder with actual ROOT_URLCONF value.
292
+
293
+ Args:
294
+ handlers_hook: Handler hook path (may contain {ROOT_URLCONF})
295
+
296
+ Returns:
297
+ Resolved handler hook path
298
+
299
+ Example:
300
+ >>> self._resolve_handlers_hook("{ROOT_URLCONF}.grpc_handlers")
301
+ 'myproject.urls.grpc_handlers'
302
+ """
303
+ if "{ROOT_URLCONF}" in handlers_hook:
304
+ # Get ROOT_URLCONF from config
305
+ root_urlconf = getattr(self.config, "root_urlconf", None)
306
+ if not root_urlconf:
307
+ # Fall back to default Django pattern
308
+ root_urlconf = f"{self.config.project_name}.urls"
309
+ logger.debug(
310
+ f"ROOT_URLCONF not set, using default: {root_urlconf}"
311
+ )
312
+
313
+ handlers_hook = handlers_hook.replace("{ROOT_URLCONF}", root_urlconf)
314
+
315
+ return handlers_hook
316
+
317
+
318
+ __all__ = ["GRPCSettingsGenerator"]
@@ -78,6 +78,7 @@ class SettingsOrchestrator:
78
78
  settings.update(self._generate_third_party_settings())
79
79
  settings.update(self._generate_api_settings())
80
80
  settings.update(self._generate_tasks_settings())
81
+ settings.update(self._generate_grpc_settings())
81
82
  settings.update(self._generate_django_q2_settings())
82
83
  settings.update(self._generate_tailwind_settings())
83
84
 
@@ -224,6 +225,15 @@ class SettingsOrchestrator:
224
225
  except Exception as e:
225
226
  raise ConfigurationError(f"Failed to generate tasks settings: {e}") from e
226
227
 
228
+ def _generate_grpc_settings(self) -> Dict[str, Any]:
229
+ """Generate gRPC framework settings."""
230
+ try:
231
+ from .integration_generators.grpc_generator import GRPCSettingsGenerator
232
+ generator = GRPCSettingsGenerator(self.config)
233
+ return generator.generate()
234
+ except Exception as e:
235
+ raise ConfigurationError(f"Failed to generate gRPC settings: {e}") from e
236
+
227
237
  def _generate_django_q2_settings(self) -> Dict[str, Any]:
228
238
  """Generate Django-Q2 task scheduling settings."""
229
239
  if not hasattr(self.config, "django_q2") or not self.config.django_q2:
@@ -0,0 +1,59 @@
1
+ """
2
+ gRPC configuration models.
3
+
4
+ Type-safe Pydantic v2 models for gRPC server, authentication, and proto generation.
5
+
6
+ Requires: pip install django-cfg[grpc]
7
+
8
+ Example:
9
+ >>> from django_cfg.models.api.grpc import GRPCConfig, GRPCServerConfig
10
+ >>> config = GRPCConfig(
11
+ ... enabled=True,
12
+ ... server=GRPCServerConfig(port=50051)
13
+ ... )
14
+ """
15
+
16
+ from typing import TYPE_CHECKING
17
+
18
+ if TYPE_CHECKING:
19
+ from .config import (
20
+ GRPCAuthConfig,
21
+ GRPCConfig,
22
+ GRPCProtoConfig,
23
+ GRPCServerConfig,
24
+ )
25
+
26
+ __all__ = [
27
+ "GRPCConfig",
28
+ "GRPCServerConfig",
29
+ "GRPCAuthConfig",
30
+ "GRPCProtoConfig",
31
+ ]
32
+
33
+
34
+ def __getattr__(name: str):
35
+ """Lazy import with helpful error message."""
36
+ if name in __all__:
37
+ try:
38
+ from .config import (
39
+ GRPCAuthConfig,
40
+ GRPCConfig,
41
+ GRPCProtoConfig,
42
+ GRPCServerConfig,
43
+ )
44
+
45
+ return {
46
+ "GRPCConfig": GRPCConfig,
47
+ "GRPCServerConfig": GRPCServerConfig,
48
+ "GRPCAuthConfig": GRPCAuthConfig,
49
+ "GRPCProtoConfig": GRPCProtoConfig,
50
+ }[name]
51
+
52
+ except ImportError as e:
53
+ raise ImportError(
54
+ f"gRPC support requires additional dependencies. "
55
+ f"Install with: pip install django-cfg[grpc]\n"
56
+ f"Missing module: {e.name}"
57
+ ) from e
58
+
59
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")