django-cfg 1.5.14__py3-none-any.whl → 1.5.29__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 (118) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/business/accounts/serializers/profile.py +42 -0
  3. django_cfg/apps/business/support/serializers.py +3 -2
  4. django_cfg/apps/integrations/centrifugo/__init__.py +2 -0
  5. django_cfg/apps/integrations/centrifugo/apps.py +2 -1
  6. django_cfg/apps/integrations/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +151 -12
  7. django_cfg/apps/integrations/centrifugo/management/commands/generate_centrifugo_clients.py +2 -2
  8. django_cfg/apps/integrations/centrifugo/services/__init__.py +6 -0
  9. django_cfg/apps/integrations/centrifugo/services/client/__init__.py +6 -1
  10. django_cfg/apps/integrations/centrifugo/services/client/client.py +1 -1
  11. django_cfg/apps/integrations/centrifugo/services/client/direct_client.py +282 -0
  12. django_cfg/apps/integrations/centrifugo/services/logging.py +47 -0
  13. django_cfg/apps/integrations/centrifugo/services/publisher.py +371 -0
  14. django_cfg/apps/integrations/centrifugo/services/token_generator.py +122 -0
  15. django_cfg/apps/integrations/centrifugo/urls.py +8 -0
  16. django_cfg/apps/integrations/centrifugo/views/__init__.py +2 -0
  17. django_cfg/apps/integrations/centrifugo/views/admin_api.py +29 -32
  18. django_cfg/apps/integrations/centrifugo/views/testing_api.py +31 -116
  19. django_cfg/apps/integrations/centrifugo/views/token_api.py +101 -0
  20. django_cfg/apps/integrations/centrifugo/views/wrapper.py +259 -0
  21. django_cfg/apps/integrations/grpc/auth/api_key_auth.py +11 -10
  22. django_cfg/apps/integrations/grpc/management/commands/compile_proto.py +105 -0
  23. django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +56 -1
  24. django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +315 -26
  25. django_cfg/apps/integrations/grpc/management/proto/__init__.py +3 -0
  26. django_cfg/apps/integrations/grpc/management/proto/compiler.py +194 -0
  27. django_cfg/apps/integrations/grpc/managers/grpc_request_log.py +84 -0
  28. django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +126 -3
  29. django_cfg/apps/integrations/grpc/models/grpc_api_key.py +7 -1
  30. django_cfg/apps/integrations/grpc/models/grpc_server_status.py +22 -3
  31. django_cfg/apps/integrations/grpc/services/__init__.py +102 -17
  32. django_cfg/apps/integrations/grpc/services/centrifugo/__init__.py +29 -0
  33. django_cfg/apps/integrations/grpc/services/centrifugo/bridge.py +469 -0
  34. django_cfg/apps/integrations/grpc/services/centrifugo/config.py +167 -0
  35. django_cfg/apps/integrations/grpc/services/centrifugo/demo.py +626 -0
  36. django_cfg/apps/integrations/grpc/services/centrifugo/test_publish.py +229 -0
  37. django_cfg/apps/integrations/grpc/services/centrifugo/transformers.py +89 -0
  38. django_cfg/apps/integrations/grpc/services/client/__init__.py +26 -0
  39. django_cfg/apps/integrations/grpc/services/commands/IMPLEMENTATION.md +456 -0
  40. django_cfg/apps/integrations/grpc/services/commands/README.md +252 -0
  41. django_cfg/apps/integrations/grpc/services/commands/__init__.py +93 -0
  42. django_cfg/apps/integrations/grpc/services/commands/base.py +243 -0
  43. django_cfg/apps/integrations/grpc/services/commands/examples/__init__.py +22 -0
  44. django_cfg/apps/integrations/grpc/services/commands/examples/base_client.py +228 -0
  45. django_cfg/apps/integrations/grpc/services/commands/examples/client.py +272 -0
  46. django_cfg/apps/integrations/grpc/services/commands/examples/config.py +177 -0
  47. django_cfg/apps/integrations/grpc/services/commands/examples/start.py +125 -0
  48. django_cfg/apps/integrations/grpc/services/commands/examples/stop.py +101 -0
  49. django_cfg/apps/integrations/grpc/services/commands/registry.py +170 -0
  50. django_cfg/apps/integrations/grpc/services/discovery/__init__.py +39 -0
  51. django_cfg/apps/integrations/grpc/services/{discovery.py → discovery/discovery.py} +67 -54
  52. django_cfg/apps/integrations/grpc/services/{service_registry.py → discovery/registry.py} +215 -5
  53. django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/__init__.py +3 -1
  54. django_cfg/apps/integrations/grpc/services/interceptors/centrifugo.py +541 -0
  55. django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/metrics.py +3 -3
  56. django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/request_logger.py +10 -13
  57. django_cfg/apps/integrations/grpc/services/management/__init__.py +37 -0
  58. django_cfg/apps/integrations/grpc/services/monitoring/__init__.py +38 -0
  59. django_cfg/apps/integrations/grpc/services/{monitoring_service.py → monitoring/monitoring.py} +2 -2
  60. django_cfg/apps/integrations/grpc/services/{testing_service.py → monitoring/testing.py} +5 -5
  61. django_cfg/apps/integrations/grpc/services/rendering/__init__.py +27 -0
  62. django_cfg/apps/integrations/grpc/services/{chart_generator.py → rendering/charts.py} +1 -1
  63. django_cfg/apps/integrations/grpc/services/routing/__init__.py +59 -0
  64. django_cfg/apps/integrations/grpc/services/routing/config.py +76 -0
  65. django_cfg/apps/integrations/grpc/services/routing/router.py +430 -0
  66. django_cfg/apps/integrations/grpc/services/streaming/__init__.py +117 -0
  67. django_cfg/apps/integrations/grpc/services/streaming/config.py +451 -0
  68. django_cfg/apps/integrations/grpc/services/streaming/service.py +651 -0
  69. django_cfg/apps/integrations/grpc/services/streaming/types.py +367 -0
  70. django_cfg/apps/integrations/grpc/utils/SERVER_LOGGING.md +164 -0
  71. django_cfg/apps/integrations/grpc/utils/__init__.py +58 -1
  72. django_cfg/apps/integrations/grpc/utils/converters.py +565 -0
  73. django_cfg/apps/integrations/grpc/utils/handlers.py +242 -0
  74. django_cfg/apps/integrations/grpc/utils/proto_gen.py +1 -1
  75. django_cfg/apps/integrations/grpc/utils/streaming_logger.py +261 -13
  76. django_cfg/apps/integrations/grpc/views/charts.py +1 -1
  77. django_cfg/apps/integrations/grpc/views/config.py +1 -1
  78. django_cfg/apps/system/dashboard/serializers/config.py +95 -9
  79. django_cfg/apps/system/dashboard/serializers/statistics.py +9 -4
  80. django_cfg/apps/system/frontend/views.py +87 -6
  81. django_cfg/core/base/config_model.py +11 -0
  82. django_cfg/core/builders/middleware_builder.py +5 -0
  83. django_cfg/core/builders/security_builder.py +1 -0
  84. django_cfg/core/generation/integration_generators/api.py +2 -0
  85. django_cfg/management/commands/pool_status.py +153 -0
  86. django_cfg/middleware/pool_cleanup.py +261 -0
  87. django_cfg/models/api/grpc/config.py +2 -2
  88. django_cfg/models/infrastructure/database/config.py +16 -0
  89. django_cfg/models/infrastructure/database/converters.py +2 -0
  90. django_cfg/modules/django_admin/utils/html/composition.py +57 -13
  91. django_cfg/modules/django_admin/utils/html_builder.py +1 -0
  92. django_cfg/modules/django_client/core/generator/typescript/generator.py +26 -0
  93. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +7 -1
  94. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +5 -0
  95. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +11 -0
  96. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +1 -0
  97. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/function.ts.jinja +29 -1
  98. django_cfg/modules/django_client/core/generator/typescript/templates/hooks/hooks.ts.jinja +4 -0
  99. django_cfg/modules/django_client/core/groups/manager.py +25 -18
  100. django_cfg/modules/django_client/core/ir/schema.py +15 -1
  101. django_cfg/modules/django_client/core/parser/base.py +12 -0
  102. django_cfg/modules/django_client/management/commands/generate_client.py +9 -5
  103. django_cfg/modules/django_logging/django_logger.py +58 -19
  104. django_cfg/pyproject.toml +3 -3
  105. django_cfg/static/frontend/admin.zip +0 -0
  106. django_cfg/templates/admin/index.html +0 -39
  107. django_cfg/utils/pool_monitor.py +320 -0
  108. django_cfg/utils/smart_defaults.py +233 -7
  109. {django_cfg-1.5.14.dist-info → django_cfg-1.5.29.dist-info}/METADATA +75 -5
  110. {django_cfg-1.5.14.dist-info → django_cfg-1.5.29.dist-info}/RECORD +118 -74
  111. /django_cfg/apps/integrations/grpc/services/{grpc_client.py → client/client.py} +0 -0
  112. /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/errors.py +0 -0
  113. /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/logging.py +0 -0
  114. /django_cfg/apps/integrations/grpc/services/{config_helper.py → management/config_helper.py} +0 -0
  115. /django_cfg/apps/integrations/grpc/services/{proto_files_manager.py → management/proto_manager.py} +0 -0
  116. {django_cfg-1.5.14.dist-info → django_cfg-1.5.29.dist-info}/WHEEL +0 -0
  117. {django_cfg-1.5.14.dist-info → django_cfg-1.5.29.dist-info}/entry_points.txt +0 -0
  118. {django_cfg-1.5.14.dist-info → django_cfg-1.5.29.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,229 @@
1
+ """
2
+ Test script to verify Centrifugo event publishing.
3
+
4
+ Run this to test that events are being published to Centrifugo channels.
5
+
6
+ Usage:
7
+ # From Django shell:
8
+ >>> from django_cfg.apps.integrations.grpc.services.centrifugo.test_publish import run_test
9
+ >>> await run_test()
10
+
11
+ # Or from async context:
12
+ >>> import asyncio
13
+ >>> from django_cfg.apps.integrations.grpc.services.centrifugo.test_publish import run_test
14
+ >>> asyncio.run(run_test())
15
+ """
16
+
17
+ import asyncio
18
+ import logging
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ async def run_test(verbose: bool = True):
24
+ """
25
+ Run complete Centrifugo integration test.
26
+
27
+ Tests:
28
+ 1. Centrifugo client initialization
29
+ 2. Interceptor simulation (RPC metadata)
30
+ 3. Mixin demo (message data)
31
+
32
+ Args:
33
+ verbose: Show detailed output
34
+
35
+ Returns:
36
+ dict: Test results with success/failure counts
37
+ """
38
+ if verbose:
39
+ # Set logging to DEBUG to see all details
40
+ logging.basicConfig(
41
+ level=logging.DEBUG,
42
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
43
+ )
44
+
45
+ logger.info("=" * 70)
46
+ logger.info("🧪 CENTRIFUGO INTEGRATION TEST")
47
+ logger.info("=" * 70)
48
+
49
+ results = {
50
+ 'client_init': False,
51
+ 'interceptor_test': 0,
52
+ 'mixin_test': {},
53
+ 'total_published': 0,
54
+ 'errors': [],
55
+ }
56
+
57
+ # Test 1: Client initialization
58
+ logger.info("\n📍 Step 1: Testing Centrifugo client initialization")
59
+ logger.info("-" * 70)
60
+ try:
61
+ from django_cfg.apps.integrations.centrifugo import get_centrifugo_client
62
+
63
+ client = get_centrifugo_client()
64
+ logger.info(f"✅ Client initialized: {client.wrapper_url}")
65
+ results['client_init'] = True
66
+ except Exception as e:
67
+ logger.error(f"❌ Client initialization failed: {e}")
68
+ results['errors'].append(f"Client init: {str(e)}")
69
+ return results
70
+
71
+ # Test 2: Test interceptor simulation (raw publish)
72
+ logger.info("\n📍 Step 2: Testing Interceptor-style publishing (RPC metadata)")
73
+ logger.info("-" * 70)
74
+ try:
75
+ from django_cfg.apps.integrations.grpc.services.centrifugo.demo import send_demo_event
76
+
77
+ # Send 3 test events
78
+ for i in range(1, 4):
79
+ success = await send_demo_event(
80
+ channel=f"grpc#demo#TestMethod#meta",
81
+ metadata={
82
+ 'test_number': i,
83
+ 'test_type': 'interceptor_simulation',
84
+ }
85
+ )
86
+ if success:
87
+ results['interceptor_test'] += 1
88
+ results['total_published'] += 1
89
+ logger.info(f" ✅ Event {i}/3 published to grpc#demo#TestMethod#meta")
90
+ else:
91
+ logger.warning(f" ⚠️ Event {i}/3 failed")
92
+
93
+ await asyncio.sleep(0.5)
94
+
95
+ except Exception as e:
96
+ logger.error(f"❌ Interceptor test failed: {e}")
97
+ results['errors'].append(f"Interceptor: {str(e)}")
98
+
99
+ # Test 3: Test mixin (DemoBridgeService)
100
+ logger.info("\n📍 Step 3: Testing Mixin-style publishing (message data)")
101
+ logger.info("-" * 70)
102
+ try:
103
+ from django_cfg.apps.integrations.grpc.services.centrifugo.demo import test_demo_service
104
+
105
+ stats = await test_demo_service(service_id='test-integration', count=3)
106
+ results['mixin_test'] = stats
107
+ results['total_published'] += sum(stats.values())
108
+
109
+ logger.info(f" 📊 Mixin test results: {stats}")
110
+
111
+ except Exception as e:
112
+ logger.error(f"❌ Mixin test failed: {e}")
113
+ results['errors'].append(f"Mixin: {str(e)}")
114
+
115
+ # Summary
116
+ logger.info("\n" + "=" * 70)
117
+ logger.info("📊 TEST SUMMARY")
118
+ logger.info("=" * 70)
119
+ logger.info(f"Client initialized: {'✅ Yes' if results['client_init'] else '❌ No'}")
120
+ logger.info(f"Interceptor events: {results['interceptor_test']}/3")
121
+ logger.info(f"Mixin events: {results['mixin_test']}")
122
+ logger.info(f"Total published: {results['total_published']}")
123
+
124
+ if results['errors']:
125
+ logger.error(f"\n❌ Errors encountered:")
126
+ for error in results['errors']:
127
+ logger.error(f" - {error}")
128
+ else:
129
+ logger.info(f"\n✅ All tests passed successfully!")
130
+
131
+ logger.info("=" * 70)
132
+
133
+ return results
134
+
135
+
136
+ async def check_centrifugo_config():
137
+ """
138
+ Check Centrifugo configuration.
139
+
140
+ Returns:
141
+ dict: Configuration details
142
+ """
143
+ logger.info("🔍 Checking Centrifugo configuration...")
144
+
145
+ try:
146
+ from django_cfg.apps.integrations.centrifugo.services.config_helper import get_centrifugo_config
147
+
148
+ config = get_centrifugo_config()
149
+
150
+ if not config:
151
+ logger.error("❌ Centrifugo not configured in django-cfg")
152
+ return {
153
+ 'enabled': False,
154
+ 'error': 'Not configured',
155
+ }
156
+
157
+ logger.info(f"✅ Centrifugo enabled: {config.enabled}")
158
+ logger.info(f" Wrapper URL: {config.wrapper_url}")
159
+ logger.info(f" Log all calls: {config.log_all_calls}")
160
+ logger.info(f" Log only ACK: {config.log_only_with_ack}")
161
+
162
+ return {
163
+ 'enabled': config.enabled,
164
+ 'wrapper_url': config.wrapper_url,
165
+ 'log_all_calls': config.log_all_calls,
166
+ 'log_only_with_ack': config.log_only_with_ack,
167
+ }
168
+
169
+ except Exception as e:
170
+ logger.error(f"❌ Failed to get config: {e}")
171
+ return {
172
+ 'enabled': False,
173
+ 'error': str(e),
174
+ }
175
+
176
+
177
+ async def test_simple_publish():
178
+ """
179
+ Simple test - publish one event and check logs.
180
+
181
+ Returns:
182
+ bool: True if successful
183
+ """
184
+ logger.info("🧪 Simple publish test...")
185
+
186
+ try:
187
+ from django_cfg.apps.integrations.centrifugo import get_centrifugo_client
188
+ from datetime import datetime, timezone as tz
189
+
190
+ client = get_centrifugo_client()
191
+
192
+ test_data = {
193
+ 'message': 'Hello from test_publish.py',
194
+ 'timestamp': datetime.now(tz.utc).isoformat(),
195
+ 'test': True,
196
+ }
197
+
198
+ logger.info(f"📤 Publishing to channel: test#demo#simple")
199
+
200
+ result = await client.publish(
201
+ channel='test#demo#simple',
202
+ data=test_data
203
+ )
204
+
205
+ logger.info(f"✅ Publish result: {result}")
206
+ logger.info(f" Message ID: {result.message_id}")
207
+ logger.info(f" Published: {result.published}")
208
+
209
+ return result.published
210
+
211
+ except Exception as e:
212
+ logger.error(f"❌ Publish failed: {e}", exc_info=True)
213
+ return False
214
+
215
+
216
+ if __name__ == "__main__":
217
+ # For standalone execution
218
+ print("Running Centrifugo integration test...")
219
+ print("=" * 70)
220
+ results = asyncio.run(run_test(verbose=True))
221
+ print("\nTest completed.")
222
+ print(f"Total events published: {results['total_published']}")
223
+
224
+
225
+ __all__ = [
226
+ 'run_test',
227
+ 'check_centrifugo_config',
228
+ 'test_simple_publish',
229
+ ]
@@ -0,0 +1,89 @@
1
+ """
2
+ Protobuf to JSON Transformers.
3
+
4
+ Utilities for transforming protobuf messages to JSON-serializable dictionaries.
5
+ """
6
+
7
+ from typing import Any, Dict
8
+ from google.protobuf.message import Message
9
+ from google.protobuf.json_format import MessageToDict
10
+
11
+
12
+ def transform_protobuf_to_dict(message: Message) -> Dict[str, Any]:
13
+ """
14
+ Transform protobuf message to JSON-serializable dict.
15
+
16
+ Uses google.protobuf.json_format.MessageToDict with sensible defaults.
17
+
18
+ Args:
19
+ message: Protobuf message instance
20
+
21
+ Returns:
22
+ JSON-serializable dictionary
23
+
24
+ Example:
25
+ ```python
26
+ from .generated import bot_streaming_service_pb2
27
+
28
+ heartbeat = bot_streaming_service_pb2.HeartbeatUpdate(
29
+ cpu_usage=45.2,
30
+ memory_usage=60.1
31
+ )
32
+
33
+ data = transform_protobuf_to_dict(heartbeat)
34
+ # {'cpu_usage': 45.2, 'memory_usage': 60.1, ...}
35
+ ```
36
+ """
37
+ return MessageToDict(
38
+ message,
39
+ preserving_proto_field_name=True,
40
+ use_integers_for_enums=False, # Use string names for enums
41
+ )
42
+
43
+
44
+ def transform_with_enum_mapping(
45
+ message: Message,
46
+ enum_mappings: Dict[str, Dict[int, str]]
47
+ ) -> Dict[str, Any]:
48
+ """
49
+ Transform protobuf with custom enum value mappings.
50
+
51
+ Args:
52
+ message: Protobuf message
53
+ enum_mappings: {field_name: {enum_value: string_name}}
54
+
55
+ Returns:
56
+ Dictionary with custom enum names
57
+
58
+ Example:
59
+ ```python
60
+ transform_with_enum_mapping(
61
+ heartbeat,
62
+ enum_mappings={
63
+ 'status': {
64
+ 0: 'UNSPECIFIED',
65
+ 1: 'STOPPED',
66
+ 2: 'RUNNING',
67
+ 3: 'PAUSED',
68
+ 4: 'ERROR',
69
+ }
70
+ }
71
+ )
72
+ ```
73
+ """
74
+ data = MessageToDict(message, preserving_proto_field_name=True)
75
+
76
+ # Apply custom enum mappings
77
+ for field_name, mapping in enum_mappings.items():
78
+ if field_name in data:
79
+ enum_value = data[field_name]
80
+ if isinstance(enum_value, int):
81
+ data[field_name] = mapping.get(enum_value, str(enum_value))
82
+
83
+ return data
84
+
85
+
86
+ __all__ = [
87
+ "transform_protobuf_to_dict",
88
+ "transform_with_enum_mapping",
89
+ ]
@@ -0,0 +1,26 @@
1
+ """
2
+ gRPC client utilities for django-cfg.
3
+
4
+ This package provides tools for creating and managing gRPC client connections.
5
+
6
+ **Components**:
7
+ - client: GrpcClient for service-to-service communication
8
+
9
+ **Usage Example**:
10
+ ```python
11
+ from django_cfg.apps.integrations.grpc.services.client import GrpcClient
12
+
13
+ client = GrpcClient(host="localhost", port=50051)
14
+ # Use client for gRPC calls
15
+ ```
16
+
17
+ Created: 2025-11-07
18
+ Status: %%PRODUCTION%%
19
+ """
20
+
21
+ # Export when client module is refactored
22
+ # from .client import GrpcClient
23
+
24
+ __all__ = [
25
+ # 'GrpcClient', # Uncomment when ready
26
+ ]