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.
- django_cfg/__init__.py +8 -4
- django_cfg/apps/centrifugo/admin/centrifugo_log.py +33 -71
- django_cfg/apps/grpc/__init__.py +9 -0
- django_cfg/apps/grpc/admin/__init__.py +11 -0
- django_cfg/apps/grpc/admin/config.py +89 -0
- django_cfg/apps/grpc/admin/grpc_request_log.py +252 -0
- django_cfg/apps/grpc/apps.py +28 -0
- django_cfg/apps/grpc/auth/__init__.py +9 -0
- django_cfg/apps/grpc/auth/jwt_auth.py +295 -0
- django_cfg/apps/grpc/interceptors/__init__.py +19 -0
- django_cfg/apps/grpc/interceptors/errors.py +241 -0
- django_cfg/apps/grpc/interceptors/logging.py +270 -0
- django_cfg/apps/grpc/interceptors/metrics.py +306 -0
- django_cfg/apps/grpc/interceptors/request_logger.py +515 -0
- django_cfg/apps/grpc/management/__init__.py +1 -0
- django_cfg/apps/grpc/management/commands/__init__.py +0 -0
- django_cfg/apps/grpc/management/commands/rungrpc.py +302 -0
- django_cfg/apps/grpc/managers/__init__.py +10 -0
- django_cfg/apps/grpc/managers/grpc_request_log.py +310 -0
- django_cfg/apps/grpc/migrations/0001_initial.py +69 -0
- django_cfg/apps/grpc/migrations/0002_rename_django_cfg__service_4c4a8e_idx_django_cfg__service_584308_idx_and_more.py +38 -0
- django_cfg/apps/grpc/migrations/__init__.py +0 -0
- django_cfg/apps/grpc/models/__init__.py +9 -0
- django_cfg/apps/grpc/models/grpc_request_log.py +219 -0
- django_cfg/apps/grpc/serializers/__init__.py +23 -0
- django_cfg/apps/grpc/serializers/health.py +18 -0
- django_cfg/apps/grpc/serializers/requests.py +18 -0
- django_cfg/apps/grpc/serializers/services.py +50 -0
- django_cfg/apps/grpc/serializers/stats.py +22 -0
- django_cfg/apps/grpc/services/__init__.py +16 -0
- django_cfg/apps/grpc/services/base.py +375 -0
- django_cfg/apps/grpc/services/discovery.py +415 -0
- django_cfg/apps/grpc/urls.py +23 -0
- django_cfg/apps/grpc/utils/__init__.py +13 -0
- django_cfg/apps/grpc/utils/proto_gen.py +423 -0
- django_cfg/apps/grpc/views/__init__.py +9 -0
- django_cfg/apps/grpc/views/monitoring.py +497 -0
- django_cfg/apps/maintenance/admin/api_key_admin.py +7 -8
- django_cfg/apps/maintenance/admin/site_admin.py +5 -4
- django_cfg/apps/payments/admin/balance_admin.py +26 -36
- django_cfg/apps/payments/admin/payment_admin.py +65 -85
- django_cfg/apps/payments/admin/withdrawal_admin.py +65 -100
- django_cfg/apps/tasks/admin/task_log.py +20 -47
- django_cfg/apps/urls.py +7 -1
- django_cfg/config.py +106 -0
- django_cfg/core/base/config_model.py +6 -0
- django_cfg/core/builders/apps_builder.py +3 -0
- django_cfg/core/generation/integration_generators/grpc_generator.py +318 -0
- django_cfg/core/generation/orchestrator.py +10 -0
- django_cfg/models/api/grpc/__init__.py +59 -0
- django_cfg/models/api/grpc/config.py +364 -0
- django_cfg/modules/base.py +15 -0
- django_cfg/modules/django_admin/base/pydantic_admin.py +2 -2
- django_cfg/modules/django_admin/utils/__init__.py +41 -3
- django_cfg/modules/django_admin/utils/badges/__init__.py +13 -0
- django_cfg/modules/django_admin/utils/{badges.py → badges/status_badges.py} +3 -3
- django_cfg/modules/django_admin/utils/displays/__init__.py +13 -0
- django_cfg/modules/django_admin/utils/{displays.py → displays/data_displays.py} +2 -2
- django_cfg/modules/django_admin/utils/html/__init__.py +26 -0
- django_cfg/modules/django_admin/utils/html/badges.py +47 -0
- django_cfg/modules/django_admin/utils/html/base.py +167 -0
- django_cfg/modules/django_admin/utils/html/code.py +87 -0
- django_cfg/modules/django_admin/utils/html/composition.py +198 -0
- django_cfg/modules/django_admin/utils/html/formatting.py +231 -0
- django_cfg/modules/django_admin/utils/html/keyvalue.py +219 -0
- django_cfg/modules/django_admin/utils/html/markdown_integration.py +108 -0
- django_cfg/modules/django_admin/utils/html/progress.py +127 -0
- django_cfg/modules/django_admin/utils/html_builder.py +55 -408
- django_cfg/modules/django_admin/utils/markdown/__init__.py +21 -0
- django_cfg/modules/django_unfold/navigation.py +28 -0
- django_cfg/pyproject.toml +3 -5
- django_cfg/registry/modules.py +6 -0
- {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/METADATA +10 -1
- {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/RECORD +79 -30
- django_cfg/modules/django_admin/utils/CODE_BLOCK_DOCS.md +0 -396
- /django_cfg/modules/django_admin/utils/{mermaid_plugin.py → markdown/mermaid_plugin.py} +0 -0
- /django_cfg/modules/django_admin/utils/{markdown_renderer.py → markdown/renderer.py} +0 -0
- {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.120.dist-info → django_cfg-1.5.1.dist-info}/entry_points.txt +0 -0
- {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}")
|