django-cfg 1.4.10__py3-none-any.whl → 1.4.13__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.
Files changed (225) hide show
  1. django_cfg/apps/agents/management/commands/create_agent.py +1 -1
  2. django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
  3. django_cfg/apps/newsletter/serializers.py +40 -3
  4. django_cfg/apps/newsletter/views/campaigns.py +12 -3
  5. django_cfg/apps/newsletter/views/emails.py +14 -3
  6. django_cfg/apps/newsletter/views/subscriptions.py +12 -2
  7. django_cfg/apps/payments/views/api/currencies.py +49 -6
  8. django_cfg/apps/payments/views/api/webhooks.py +72 -7
  9. django_cfg/apps/payments/views/overview/serializers.py +34 -1
  10. django_cfg/apps/payments/views/overview/views.py +2 -1
  11. django_cfg/apps/payments/views/serializers/payments.py +6 -6
  12. django_cfg/apps/urls.py +106 -45
  13. django_cfg/core/base/config_model.py +2 -2
  14. django_cfg/core/constants.py +1 -1
  15. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  16. django_cfg/core/generation/integration_generators/api.py +73 -49
  17. django_cfg/core/integration/display/startup.py +30 -22
  18. django_cfg/core/integration/url_integration.py +15 -16
  19. django_cfg/management/commands/check_endpoints.py +11 -160
  20. django_cfg/management/commands/check_settings.py +13 -348
  21. django_cfg/management/commands/clear_constance.py +13 -201
  22. django_cfg/management/commands/create_token.py +13 -321
  23. django_cfg/management/commands/generate_clients.py +23 -0
  24. django_cfg/management/commands/list_urls.py +13 -306
  25. django_cfg/management/commands/migrate_all.py +13 -126
  26. django_cfg/management/commands/migrator.py +13 -396
  27. django_cfg/management/commands/rundramatiq.py +15 -247
  28. django_cfg/management/commands/rundramatiq_simulator.py +12 -429
  29. django_cfg/management/commands/runserver_ngrok.py +15 -160
  30. django_cfg/management/commands/script.py +12 -488
  31. django_cfg/management/commands/show_config.py +12 -215
  32. django_cfg/management/commands/show_urls.py +12 -342
  33. django_cfg/management/commands/superuser.py +15 -295
  34. django_cfg/management/commands/task_clear.py +14 -217
  35. django_cfg/management/commands/task_status.py +13 -248
  36. django_cfg/management/commands/test_email.py +15 -86
  37. django_cfg/management/commands/test_telegram.py +14 -61
  38. django_cfg/management/commands/test_twilio.py +15 -105
  39. django_cfg/management/commands/tree.py +13 -383
  40. django_cfg/management/commands/validate_openapi.py +10 -0
  41. django_cfg/middleware/README.md +1 -1
  42. django_cfg/middleware/user_activity.py +3 -3
  43. django_cfg/models/__init__.py +2 -2
  44. django_cfg/models/api/drf/spectacular.py +6 -6
  45. django_cfg/models/django/__init__.py +2 -2
  46. django_cfg/models/django/openapi.py +162 -0
  47. django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
  48. django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
  49. django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
  50. django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
  51. django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
  52. django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
  53. django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
  54. django_cfg/modules/django_admin/management/commands/script.py +496 -0
  55. django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
  56. django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
  57. django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
  58. django_cfg/modules/django_admin/management/commands/tree.py +390 -0
  59. django_cfg/modules/django_client/__init__.py +20 -0
  60. django_cfg/modules/django_client/apps.py +35 -0
  61. django_cfg/modules/django_client/core/__init__.py +56 -0
  62. django_cfg/modules/django_client/core/archive/__init__.py +11 -0
  63. django_cfg/modules/django_client/core/archive/manager.py +134 -0
  64. django_cfg/modules/django_client/core/cli/__init__.py +12 -0
  65. django_cfg/modules/django_client/core/cli/main.py +235 -0
  66. django_cfg/modules/django_client/core/config/__init__.py +18 -0
  67. django_cfg/modules/django_client/core/config/config.py +208 -0
  68. django_cfg/modules/django_client/core/config/group.py +101 -0
  69. django_cfg/modules/django_client/core/config/service.py +209 -0
  70. django_cfg/modules/django_client/core/generator/__init__.py +115 -0
  71. django_cfg/modules/django_client/core/generator/base.py +838 -0
  72. django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
  73. django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
  74. django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
  75. django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
  76. django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
  77. django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
  78. django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
  79. django_cfg/modules/django_client/core/generator/python/templates/__init__.py.jinja +9 -0
  80. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +153 -0
  81. django_cfg/modules/django_client/core/generator/python/templates/app_init.py.jinja +6 -0
  82. django_cfg/modules/django_client/core/generator/python/templates/client/app_client.py.jinja +18 -0
  83. django_cfg/modules/django_client/core/generator/python/templates/client/flat_client.py.jinja +38 -0
  84. django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +68 -0
  85. django_cfg/modules/django_client/core/generator/python/templates/client/main_client_file.py.jinja +14 -0
  86. django_cfg/modules/django_client/core/generator/python/templates/client/operation_method.py.jinja +9 -0
  87. django_cfg/modules/django_client/core/generator/python/templates/client/sub_client.py.jinja +18 -0
  88. django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
  89. django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
  90. django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
  91. django_cfg/modules/django_client/core/generator/python/templates/client_file.py.jinja +13 -0
  92. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +52 -0
  93. django_cfg/modules/django_client/core/generator/python/templates/models/app_models.py.jinja +17 -0
  94. django_cfg/modules/django_client/core/generator/python/templates/models/enum_class.py.jinja +17 -0
  95. django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +8 -0
  96. django_cfg/modules/django_client/core/generator/python/templates/models/models.py.jinja +17 -0
  97. django_cfg/modules/django_client/core/generator/python/templates/models/schema_class.py.jinja +21 -0
  98. django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
  99. django_cfg/modules/django_client/core/generator/python/templates/utils/logger.py.jinja +255 -0
  100. django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
  101. django_cfg/modules/django_client/core/generator/python/templates/utils/schema.py.jinja +12 -0
  102. django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
  103. django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
  104. django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
  105. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
  106. django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
  107. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +536 -0
  108. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
  109. django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
  110. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
  111. django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
  112. django_cfg/modules/django_client/core/generator/typescript/templates/app_index.ts.jinja +2 -0
  113. django_cfg/modules/django_client/core/generator/typescript/templates/client/app_client.ts.jinja +18 -0
  114. django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +403 -0
  115. django_cfg/modules/django_client/core/generator/typescript/templates/client/flat_client.ts.jinja +109 -0
  116. django_cfg/modules/django_client/core/generator/typescript/templates/client/main_client_file.ts.jinja +10 -0
  117. django_cfg/modules/django_client/core/generator/typescript/templates/client/operation.ts.jinja +61 -0
  118. django_cfg/modules/django_client/core/generator/typescript/templates/client/sub_client.ts.jinja +15 -0
  119. django_cfg/modules/django_client/core/generator/typescript/templates/client_file.ts.jinja +9 -0
  120. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
  121. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
  122. django_cfg/modules/django_client/core/generator/typescript/templates/index.ts.jinja +5 -0
  123. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +268 -0
  124. django_cfg/modules/django_client/core/generator/typescript/templates/models/app_models.ts.jinja +8 -0
  125. django_cfg/modules/django_client/core/generator/typescript/templates/models/enums.ts.jinja +4 -0
  126. django_cfg/modules/django_client/core/generator/typescript/templates/models/models.ts.jinja +8 -0
  127. django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
  128. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
  129. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
  130. django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
  131. django_cfg/modules/django_client/core/generator/typescript/templates/utils/errors.ts.jinja +116 -0
  132. django_cfg/modules/django_client/core/generator/typescript/templates/utils/http.ts.jinja +98 -0
  133. django_cfg/modules/django_client/core/generator/typescript/templates/utils/logger.ts.jinja +259 -0
  134. django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
  135. django_cfg/modules/django_client/core/generator/typescript/templates/utils/schema.ts.jinja +7 -0
  136. django_cfg/modules/django_client/core/generator/typescript/templates/utils/storage.ts.jinja +158 -0
  137. django_cfg/modules/django_client/core/groups/__init__.py +13 -0
  138. django_cfg/modules/django_client/core/groups/detector.py +178 -0
  139. django_cfg/modules/django_client/core/groups/manager.py +314 -0
  140. django_cfg/modules/django_client/core/ir/__init__.py +57 -0
  141. django_cfg/modules/django_client/core/ir/context.py +387 -0
  142. django_cfg/modules/django_client/core/ir/operation.py +518 -0
  143. django_cfg/modules/django_client/core/ir/schema.py +353 -0
  144. django_cfg/modules/django_client/core/parser/__init__.py +74 -0
  145. django_cfg/modules/django_client/core/parser/base.py +648 -0
  146. django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
  147. django_cfg/modules/django_client/core/parser/models/base.py +212 -0
  148. django_cfg/modules/django_client/core/parser/models/components.py +160 -0
  149. django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
  150. django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
  151. django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
  152. django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
  153. django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
  154. django_cfg/modules/django_client/core/validation/__init__.py +22 -0
  155. django_cfg/modules/django_client/core/validation/checker.py +134 -0
  156. django_cfg/modules/django_client/core/validation/fixer.py +216 -0
  157. django_cfg/modules/django_client/core/validation/reporter.py +480 -0
  158. django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
  159. django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
  160. django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
  161. django_cfg/modules/django_client/core/validation/safety.py +266 -0
  162. django_cfg/modules/django_client/management/__init__.py +3 -0
  163. django_cfg/modules/django_client/management/commands/__init__.py +3 -0
  164. django_cfg/modules/django_client/management/commands/generate_client.py +427 -0
  165. django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
  166. django_cfg/modules/django_client/pytest.ini +30 -0
  167. django_cfg/modules/django_client/spectacular/__init__.py +10 -0
  168. django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
  169. django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
  170. django_cfg/modules/django_client/urls.py +72 -0
  171. django_cfg/{dashboard → modules/django_dashboard}/DEBUG_README.md +2 -2
  172. django_cfg/{dashboard → modules/django_dashboard}/REFACTORING_SUMMARY.md +1 -1
  173. django_cfg/modules/django_dashboard/management/__init__.py +0 -0
  174. django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
  175. django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
  176. django_cfg/modules/django_dashboard/sections/documentation.py +391 -0
  177. django_cfg/modules/django_email/management/__init__.py +0 -0
  178. django_cfg/modules/django_email/management/commands/__init__.py +0 -0
  179. django_cfg/modules/django_email/management/commands/test_email.py +93 -0
  180. django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
  181. django_cfg/modules/django_logging/django_logger.py +6 -6
  182. django_cfg/modules/django_ngrok/management/__init__.py +0 -0
  183. django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
  184. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
  185. django_cfg/modules/django_tasks/management/__init__.py +0 -0
  186. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  187. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
  188. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
  189. django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
  190. django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
  191. django_cfg/modules/django_telegram/management/__init__.py +0 -0
  192. django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
  193. django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
  194. django_cfg/modules/django_twilio/management/__init__.py +0 -0
  195. django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
  196. django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
  197. django_cfg/modules/django_unfold/callbacks/main.py +21 -10
  198. django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
  199. django_cfg/pyproject.toml +2 -6
  200. django_cfg/registry/third_party.py +5 -7
  201. django_cfg/routing/callbacks.py +1 -1
  202. django_cfg/static/admin/css/prose-unfold.css +666 -0
  203. django_cfg/templates/admin/index.html +8 -0
  204. django_cfg/templates/admin/index_new.html +13 -0
  205. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
  206. django_cfg/templates/admin/sections/documentation_section.html +172 -0
  207. django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
  208. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/METADATA +2 -2
  209. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/RECORD +224 -74
  210. django_cfg/management/commands/generate.py +0 -107
  211. /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
  212. /django_cfg/{dashboard → modules/django_admin}/management/__init__.py +0 -0
  213. /django_cfg/{dashboard → modules/django_admin}/management/commands/__init__.py +0 -0
  214. /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
  215. /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
  216. /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
  217. /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
  218. /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
  219. /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
  220. /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
  221. /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
  222. /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
  223. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/WHEEL +0 -0
  224. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/entry_points.txt +0 -0
  225. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,20 @@
1
+ """
2
+ Django Client - Django integration for openapi_client.
3
+
4
+ Provides Django management commands and URL integration.
5
+ """
6
+
7
+ # Django AppConfig
8
+ default_app_config = 'django_cfg.modules.django_client.apps.DjangoClientConfig'
9
+
10
+ # Re-export everything from openapi_client
11
+ from django_cfg.modules.django_client.core import * # noqa
12
+
13
+ # Django-specific
14
+ from .management.commands.generate_client import Command as GenerateClientCommand
15
+ from .urls import get_openapi_urls
16
+
17
+ __all__ = [
18
+ "GenerateClientCommand",
19
+ "get_openapi_urls",
20
+ ]
@@ -0,0 +1,35 @@
1
+ """
2
+ Django Client AppConfig.
3
+
4
+ Initializes OpenAPI service with configuration from Django settings.
5
+ """
6
+
7
+ from django.apps import AppConfig
8
+ from django.conf import settings
9
+
10
+
11
+ class DjangoClientConfig(AppConfig):
12
+ """AppConfig for django_client."""
13
+
14
+ name = 'django_cfg.modules.django_client'
15
+ verbose_name = 'Django OpenAPI Client'
16
+ default_auto_field = 'django.db.models.BigAutoField'
17
+
18
+ def ready(self):
19
+ """Initialize OpenAPI service on app startup."""
20
+ # Import here to avoid AppRegistryNotReady
21
+ from django_cfg.modules.django_client.core import get_openapi_service
22
+ from django_cfg.core.state.registry import get_current_config
23
+
24
+ # Get config from django-cfg
25
+ django_config = get_current_config()
26
+ if not django_config or not hasattr(django_config, 'openapi_client'):
27
+ return
28
+
29
+ config = django_config.openapi_client
30
+
31
+ if config and config.enabled:
32
+ # Initialize service with config
33
+ service = get_openapi_service()
34
+ service.set_config(config)
35
+ print(f"✅ Django Client initialized with {len(config.groups)} groups")
@@ -0,0 +1,56 @@
1
+ """
2
+ OpenAPI Client Generator.
3
+
4
+ Universal, pure Python OpenAPI client generator.
5
+ No Django dependencies - can be used standalone or with any framework.
6
+ """
7
+
8
+ __version__ = "1.0.0"
9
+
10
+ # Configuration
11
+ from .config import (
12
+ OpenAPIConfig,
13
+ OpenAPIGroupConfig,
14
+ DjangoOpenAPI,
15
+ OpenAPIError,
16
+ get_openapi_service,
17
+ )
18
+
19
+ # Groups
20
+ from .groups import GroupManager, GroupDetector
21
+
22
+ # Archive
23
+ from .archive import ArchiveManager
24
+
25
+ # IR Models
26
+ from .ir import (
27
+ IRContext,
28
+ IROperationObject,
29
+ IRSchemaObject,
30
+ )
31
+
32
+ # Parsers
33
+ from .parser import parse_openapi, OpenAPI30Parser, OpenAPI31Parser
34
+
35
+ # Generators
36
+ from .generator import PythonGenerator, TypeScriptGenerator
37
+
38
+ __all__ = [
39
+ "__version__",
40
+ "OpenAPIConfig",
41
+ "OpenAPIGroupConfig",
42
+ "DjangoOpenAPI",
43
+ "OpenAPIError",
44
+ "get_openapi_service",
45
+ "GroupManager",
46
+ "GroupDetector",
47
+ "ArchiveManager",
48
+ "IRContext",
49
+ "IROperationObject",
50
+ "IRSchemaObject",
51
+ "parse_openapi",
52
+ "OpenAPI30Parser",
53
+ "OpenAPI31Parser",
54
+ "PythonGenerator",
55
+ "TypeScriptGenerator",
56
+ ]
@@ -0,0 +1,11 @@
1
+ """
2
+ Archive management for django-client.
3
+
4
+ Simplified versioning without heavy dependencies.
5
+ """
6
+
7
+ from .manager import ArchiveManager
8
+
9
+ __all__ = [
10
+ "ArchiveManager",
11
+ ]
@@ -0,0 +1,134 @@
1
+ """
2
+ Simple Archive Manager.
3
+
4
+ Lightweight client archiving without complex dependencies.
5
+ """
6
+
7
+ import shutil
8
+ import json
9
+ from datetime import datetime
10
+ from pathlib import Path
11
+ from typing import Optional, Dict
12
+
13
+
14
+ class ArchiveManager:
15
+ """
16
+ Simple archive manager for generated clients.
17
+
18
+ Creates timestamped copies + 'latest' symlink.
19
+ """
20
+
21
+ def __init__(self, base_dir: Path):
22
+ """
23
+ Initialize archive manager.
24
+
25
+ Args:
26
+ base_dir: Base directory for archives
27
+ """
28
+ self.base_dir = Path(base_dir)
29
+ self.archive_dir = self.base_dir / "archive"
30
+ self.archive_dir.mkdir(parents=True, exist_ok=True)
31
+
32
+ def archive_clients(
33
+ self,
34
+ group_name: str,
35
+ python_dir: Optional[Path] = None,
36
+ typescript_dir: Optional[Path] = None,
37
+ ) -> Dict:
38
+ """
39
+ Archive generated clients.
40
+
41
+ Args:
42
+ group_name: Name of the group
43
+ python_dir: Python client directory
44
+ typescript_dir: TypeScript client directory
45
+
46
+ Returns:
47
+ Archive result dictionary
48
+ """
49
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
50
+
51
+ # Create timestamped directory
52
+ archive_path = self.archive_dir / timestamp / group_name
53
+ archive_path.mkdir(parents=True, exist_ok=True)
54
+
55
+ # Copy clients
56
+ copied = {}
57
+
58
+ if python_dir and python_dir.exists():
59
+ dest = archive_path / "python"
60
+ shutil.copytree(python_dir, dest, dirs_exist_ok=True)
61
+ copied["python"] = str(dest)
62
+
63
+ if typescript_dir and typescript_dir.exists():
64
+ dest = archive_path / "typescript"
65
+ shutil.copytree(typescript_dir, dest, dirs_exist_ok=True)
66
+ copied["typescript"] = str(dest)
67
+
68
+ # Create metadata
69
+ metadata = {
70
+ "group": group_name,
71
+ "timestamp": timestamp,
72
+ "datetime": datetime.now().isoformat(),
73
+ "clients": copied,
74
+ }
75
+
76
+ metadata_file = archive_path / "metadata.json"
77
+ metadata_file.write_text(json.dumps(metadata, indent=2))
78
+
79
+ # Create/update 'latest' symlink
80
+ latest_link = self.archive_dir / "latest" / group_name
81
+ latest_link.parent.mkdir(parents=True, exist_ok=True)
82
+
83
+ if latest_link.exists() or latest_link.is_symlink():
84
+ latest_link.unlink()
85
+
86
+ try:
87
+ latest_link.symlink_to(archive_path, target_is_directory=True)
88
+ except OSError:
89
+ # Fallback: copy instead of symlink (Windows)
90
+ if latest_link.exists():
91
+ shutil.rmtree(latest_link)
92
+ shutil.copytree(archive_path, latest_link)
93
+
94
+ return {
95
+ "success": True,
96
+ "archive_path": str(archive_path),
97
+ "timestamp": timestamp,
98
+ "clients": list(copied.keys()),
99
+ }
100
+
101
+ def list_archives(self, group_name: Optional[str] = None) -> list:
102
+ """
103
+ List available archives.
104
+
105
+ Args:
106
+ group_name: Optional group filter
107
+
108
+ Returns:
109
+ List of archive info dictionaries
110
+ """
111
+ archives = []
112
+
113
+ for timestamp_dir in sorted(self.archive_dir.iterdir()):
114
+ if timestamp_dir.name == "latest":
115
+ continue
116
+
117
+ if not timestamp_dir.is_dir():
118
+ continue
119
+
120
+ for group_dir in timestamp_dir.iterdir():
121
+ if group_name and group_dir.name != group_name:
122
+ continue
123
+
124
+ metadata_file = group_dir / "metadata.json"
125
+ if metadata_file.exists():
126
+ metadata = json.loads(metadata_file.read_text())
127
+ archives.append(metadata)
128
+
129
+ return archives
130
+
131
+
132
+ __all__ = [
133
+ "ArchiveManager",
134
+ ]
@@ -0,0 +1,12 @@
1
+ """
2
+ CLI Module for django-client.
3
+
4
+ Interactive command-line interface with rich output.
5
+ """
6
+
7
+ from .main import main, run_cli
8
+
9
+ __all__ = [
10
+ "main",
11
+ "run_cli",
12
+ ]
@@ -0,0 +1,235 @@
1
+ """
2
+ Django Client CLI - Command-line interface with click.
3
+
4
+ Provides intuitive CLI for client generation.
5
+ """
6
+
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import Optional, List
10
+
11
+ try:
12
+ import click
13
+ CLICK_AVAILABLE = True
14
+ except ImportError:
15
+ CLICK_AVAILABLE = False
16
+ click = None
17
+
18
+ try:
19
+ from rich.console import Console
20
+ from rich.table import Table
21
+ RICH_AVAILABLE = True
22
+ except ImportError:
23
+ RICH_AVAILABLE = False
24
+ Console = None
25
+
26
+
27
+ console = Console() if RICH_AVAILABLE else None
28
+
29
+
30
+ def print_message(message: str, style: str = ""):
31
+ """Print message with optional styling."""
32
+ if console:
33
+ console.print(message, style=style)
34
+ else:
35
+ print(message)
36
+
37
+
38
+ def print_error(message: str):
39
+ """Print error message."""
40
+ if console:
41
+ console.print(f"❌ {message}", style="bold red")
42
+ else:
43
+ print(f"ERROR: {message}")
44
+
45
+
46
+ def print_success(message: str):
47
+ """Print success message."""
48
+ if console:
49
+ console.print(f"✅ {message}", style="bold green")
50
+ else:
51
+ print(f"SUCCESS: {message}")
52
+
53
+
54
+ def print_info(message: str):
55
+ """Print info message."""
56
+ if console:
57
+ console.print(f"ℹ️ {message}", style="bold blue")
58
+ else:
59
+ print(f"INFO: {message}")
60
+
61
+
62
+ def print_warning(message: str):
63
+ """Print warning message."""
64
+ if console:
65
+ console.print(f"⚠️ {message}", style="bold yellow")
66
+ else:
67
+ print(f"WARNING: {message}")
68
+
69
+
70
+ @click.group(invoke_without_command=True)
71
+ @click.option('--version', is_flag=True, help='Show version')
72
+ @click.pass_context
73
+ def cli(ctx, version):
74
+ """
75
+ Django Client - Universal OpenAPI Client Generator.
76
+
77
+ Fast, pure Python implementation with TypeScript and Python support.
78
+ """
79
+ if version:
80
+ print_message("Django Client v1.0.0", style="bold cyan")
81
+ ctx.exit(0)
82
+
83
+ if ctx.invoked_subcommand is None:
84
+ click.echo(ctx.get_help())
85
+
86
+
87
+ @cli.command()
88
+ @click.option('--groups', '-g', multiple=True, help='Specific groups to generate')
89
+ @click.option('--python/--no-python', default=True, help='Generate Python client')
90
+ @click.option('--typescript/--no-typescript', default=True, help='Generate TypeScript client')
91
+ @click.option('--dry-run', is_flag=True, help='Validate without generating files')
92
+ @click.option('--config', type=click.Path(exists=True), help='Path to config file')
93
+ def generate(groups, python, typescript, dry_run, config):
94
+ """Generate API clients for configured groups."""
95
+ try:
96
+ if dry_run:
97
+ print_info("DRY RUN MODE - No files will be generated")
98
+
99
+ groups_list = list(groups) if groups else None
100
+ print_info(f"Generating clients for groups: {groups_list or 'all'}")
101
+
102
+ if python:
103
+ print_message(" → Python client", style="cyan")
104
+ if typescript:
105
+ print_message(" → TypeScript client", style="cyan")
106
+
107
+ # TODO: Actual generation logic
108
+
109
+ if not dry_run:
110
+ print_success("Client generation completed!")
111
+ else:
112
+ print_info("Dry run completed - no files generated")
113
+
114
+ except Exception as e:
115
+ print_error(f"Generation failed: {e}")
116
+ sys.exit(1)
117
+
118
+
119
+ @cli.command('list-groups')
120
+ @click.option('--config', type=click.Path(exists=True), help='Path to config file')
121
+ def list_groups(config):
122
+ """List configured application groups."""
123
+ try:
124
+ from django_cfg.modules.django_client.core import get_openapi_service
125
+
126
+ service = get_openapi_service()
127
+
128
+ if not service.config:
129
+ print_warning("No configuration found")
130
+ return
131
+
132
+ groups = service.get_groups()
133
+
134
+ if not groups:
135
+ print_warning("No groups configured")
136
+ return
137
+
138
+ print_info(f"Configured groups ({len(groups)}):")
139
+
140
+ if console:
141
+ table = Table(title="Application Groups")
142
+ table.add_column("Group", style="cyan", no_wrap=True)
143
+ table.add_column("Title", style="green")
144
+ table.add_column("Apps", style="yellow")
145
+
146
+ for name, group_config in groups.items():
147
+ table.add_row(
148
+ name,
149
+ group_config.title,
150
+ str(len(group_config.apps))
151
+ )
152
+
153
+ console.print(table)
154
+ else:
155
+ for name, group_config in groups.items():
156
+ print(f"\n • {name}")
157
+ print(f" Title: {group_config.title}")
158
+ print(f" Apps: {len(group_config.apps)} pattern(s)")
159
+
160
+ except Exception as e:
161
+ print_error(f"Failed to list groups: {e}")
162
+ sys.exit(1)
163
+
164
+
165
+ @cli.command()
166
+ @click.option('--config', type=click.Path(exists=True), help='Path to config file')
167
+ def validate(config):
168
+ """Validate configuration."""
169
+ try:
170
+ from django_cfg.modules.django_client.core import get_openapi_service
171
+
172
+ print_info("Validating configuration...")
173
+
174
+ service = get_openapi_service()
175
+
176
+ if not service.config:
177
+ print_error("No configuration found")
178
+ sys.exit(1)
179
+
180
+ service.validate_config()
181
+ print_success("Configuration is valid!")
182
+
183
+ except Exception as e:
184
+ print_error(f"Validation failed: {e}")
185
+ sys.exit(1)
186
+
187
+
188
+ @cli.command()
189
+ @click.option('--config', type=click.Path(exists=True), help='Path to config file')
190
+ def status(config):
191
+ """Show current status and configuration."""
192
+ try:
193
+ from django_cfg.modules.django_client.core import get_openapi_service
194
+
195
+ service = get_openapi_service()
196
+
197
+ if not service.config:
198
+ print_warning("No configuration found")
199
+ return
200
+
201
+ status_info = service.get_status()
202
+
203
+ print_info("Django Client Status:")
204
+ print(f"\n Enabled: {status_info.get('enabled', False)}")
205
+ print(f" Groups: {status_info.get('groups', 0)}")
206
+ print(f" Output: {status_info.get('output_dir', 'N/A')}")
207
+ print(f" Python: {status_info.get('generate_python', False)}")
208
+ print(f" TypeScript: {status_info.get('generate_typescript', False)}")
209
+
210
+ if status_info.get('group_names'):
211
+ print(f"\n Configured groups:")
212
+ for name in status_info['group_names']:
213
+ print(f" • {name}")
214
+
215
+ except Exception as e:
216
+ print_error(f"Failed to get status: {e}")
217
+ sys.exit(1)
218
+
219
+
220
+ def main():
221
+ """Main entry point."""
222
+ if not CLICK_AVAILABLE:
223
+ print("ERROR: click is required. Install with: pip install click")
224
+ sys.exit(1)
225
+
226
+ cli()
227
+
228
+
229
+ def run_cli():
230
+ """Run CLI (alias for main)."""
231
+ main()
232
+
233
+
234
+ if __name__ == "__main__":
235
+ main()
@@ -0,0 +1,18 @@
1
+ """
2
+ Django Client Configuration.
3
+
4
+ Configuration models and service for OpenAPI client generation.
5
+ """
6
+
7
+ from .config import OpenAPIConfig
8
+ from .group import OpenAPIGroupConfig
9
+ from .service import DjangoOpenAPI, OpenAPIError, get_openapi_service, reset_service
10
+
11
+ __all__ = [
12
+ "OpenAPIConfig",
13
+ "OpenAPIGroupConfig",
14
+ "DjangoOpenAPI",
15
+ "OpenAPIError",
16
+ "get_openapi_service",
17
+ "reset_service",
18
+ ]