django-cfg 1.4.11__py3-none-any.whl → 1.4.14__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 (109) hide show
  1. django_cfg/apps/urls.py +120 -108
  2. django_cfg/core/generation/integration_generators/api.py +2 -1
  3. django_cfg/core/integration/url_integration.py +5 -10
  4. django_cfg/models/django/openapi.py +15 -128
  5. django_cfg/modules/django_client/core/archive/manager.py +2 -2
  6. django_cfg/modules/django_client/core/config/config.py +20 -0
  7. django_cfg/modules/django_client/core/config/service.py +1 -1
  8. django_cfg/modules/django_client/core/generator/__init__.py +4 -4
  9. django_cfg/modules/django_client/core/generator/base.py +71 -0
  10. django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
  11. django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
  12. django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
  13. django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
  14. django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
  15. django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
  16. django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
  17. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/api_wrapper.py.jinja +25 -2
  18. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/client/main_client.py.jinja +24 -6
  19. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/client/main_client_file.py.jinja +1 -0
  20. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/client/operation_method.py.jinja +3 -1
  21. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/client/sub_client.py.jinja +8 -1
  22. django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
  23. django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
  24. django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
  25. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/main_init.py.jinja +2 -0
  26. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/models/enum_class.py.jinja +3 -1
  27. django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/models/schema_class.py.jinja +3 -1
  28. django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
  29. django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
  30. django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
  31. django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
  32. django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
  33. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
  34. django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
  35. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +539 -0
  36. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
  37. django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
  38. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
  39. django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
  40. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/client/app_client.ts.jinja +1 -1
  41. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/client/client.ts.jinja +77 -1
  42. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/client/main_client_file.ts.jinja +1 -0
  43. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/client/sub_client.ts.jinja +3 -3
  44. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
  45. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
  46. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/main_index.ts.jinja +73 -11
  47. django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
  48. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
  49. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
  50. django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
  51. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/utils/errors.ts.jinja +3 -1
  52. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/utils/logger.ts.jinja +9 -1
  53. django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
  54. django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/utils/storage.ts.jinja +54 -10
  55. django_cfg/modules/django_client/management/commands/generate_client.py +5 -0
  56. django_cfg/modules/django_client/pytest.ini +30 -0
  57. django_cfg/modules/django_client/spectacular/__init__.py +3 -2
  58. django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
  59. django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
  60. django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
  61. django_cfg/modules/django_unfold/callbacks/main.py +6 -6
  62. django_cfg/modules/django_unfold/dashboard.py +6 -6
  63. django_cfg/pyproject.toml +1 -1
  64. {django_cfg-1.4.11.dist-info → django_cfg-1.4.14.dist-info}/METADATA +1 -1
  65. {django_cfg-1.4.11.dist-info → django_cfg-1.4.14.dist-info}/RECORD +100 -78
  66. django_cfg/dashboard/DEBUG_README.md +0 -105
  67. django_cfg/dashboard/REFACTORING_SUMMARY.md +0 -237
  68. django_cfg/modules/django_client/core/generator/python.py +0 -751
  69. django_cfg/modules/django_client/core/generator/typescript.py +0 -872
  70. django_cfg/modules/django_drf_theme/CHANGELOG.md +0 -210
  71. django_cfg/modules/django_drf_theme/EXAMPLE.md +0 -465
  72. django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +0 -232
  73. django_cfg/modules/django_drf_theme/README.md +0 -207
  74. django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +0 -274
  75. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/__init__.py.jinja +0 -0
  76. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/app_init.py.jinja +0 -0
  77. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/client/app_client.py.jinja +0 -0
  78. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/client/flat_client.py.jinja +0 -0
  79. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/client_file.py.jinja +0 -0
  80. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/models/app_models.py.jinja +0 -0
  81. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/models/enums.py.jinja +0 -0
  82. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/models/models.py.jinja +0 -0
  83. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/utils/logger.py.jinja +0 -0
  84. /django_cfg/modules/django_client/core/generator/{templates/python → python/templates}/utils/schema.py.jinja +0 -0
  85. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/app_index.ts.jinja +0 -0
  86. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/client/flat_client.ts.jinja +0 -0
  87. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/client/operation.ts.jinja +0 -0
  88. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/client_file.ts.jinja +0 -0
  89. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/index.ts.jinja +0 -0
  90. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/models/app_models.ts.jinja +0 -0
  91. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/models/enums.ts.jinja +0 -0
  92. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/models/models.ts.jinja +0 -0
  93. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/utils/http.ts.jinja +0 -0
  94. /django_cfg/modules/django_client/core/generator/{templates/typescript → typescript/templates}/utils/schema.ts.jinja +0 -0
  95. /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
  96. /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
  97. /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
  98. /django_cfg/{dashboard → modules/django_dashboard}/management/__init__.py +0 -0
  99. /django_cfg/{dashboard → modules/django_dashboard}/management/commands/__init__.py +0 -0
  100. /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
  101. /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
  102. /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
  103. /django_cfg/{dashboard → modules/django_dashboard}/sections/documentation.py +0 -0
  104. /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
  105. /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
  106. /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
  107. {django_cfg-1.4.11.dist-info → django_cfg-1.4.14.dist-info}/WHEEL +0 -0
  108. {django_cfg-1.4.11.dist-info → django_cfg-1.4.14.dist-info}/entry_points.txt +0 -0
  109. {django_cfg-1.4.11.dist-info → django_cfg-1.4.14.dist-info}/licenses/LICENSE +0 -0
django_cfg/apps/urls.py CHANGED
@@ -5,130 +5,142 @@ Built-in API endpoints for django_cfg functionality.
5
5
  """
6
6
 
7
7
  from django.urls import path, include
8
- from typing import List, Dict
9
- from django.urls import URLPattern
8
+ from typing import List
10
9
 
11
10
 
12
- def _register_group_urls(patterns: List[URLPattern], groups: Dict) -> None:
11
+ def get_enabled_cfg_apps() -> List[str]:
13
12
  """
14
- Auto-register URLs from OpenAPI groups using convention.
15
-
16
- Convention: cfg_{app} → /cfg/{app}/
17
-
18
- Args:
19
- patterns: URL patterns list to append to
20
- groups: OpenAPI groups dict
21
- """
22
- for group_name in groups.keys():
23
- # Only django-cfg apps (convention: cfg_*)
24
- if not group_name.startswith('cfg_'):
25
- continue
26
-
27
- # Extract app name: cfg_payments → payments
28
- app_name = group_name[4:]
29
-
30
- # Register main URLs: /cfg/{app}/
31
- try:
32
- patterns.append(
33
- path(f'cfg/{app_name}/', include(f'django_cfg.apps.{app_name}.urls'))
34
- )
35
- except ImportError:
36
- pass # URL module doesn't exist
37
-
38
- # Register admin URLs: /cfg/{app}/admin/ (if exists)
39
- try:
40
- patterns.append(
41
- path(f'cfg/{app_name}/admin/', include(f'django_cfg.apps.{app_name}.urls_admin'))
42
- )
43
- except ImportError:
44
- pass # Admin URL module doesn't exist
45
-
46
-
47
- def _register_apps_fallback(patterns: List[URLPattern]) -> None:
48
- """
49
- Fallback: Register apps when OpenAPI is disabled.
50
-
51
- Uses BaseCfgModule checks to determine which apps are enabled.
52
-
53
- Args:
54
- patterns: URL patterns list to append to
13
+ Get list of enabled django-cfg apps based on configuration.
14
+
15
+ Returns:
16
+ List of enabled app paths (e.g., ['django_cfg.apps.accounts', ...])
55
17
  """
56
18
  from django_cfg.modules.base import BaseCfgModule
19
+
57
20
  base_module = BaseCfgModule()
58
-
59
- # Business logic apps
60
- if base_module.is_support_enabled():
61
- patterns.append(path('cfg/support/', include('django_cfg.apps.support.urls')))
62
-
21
+ enabled_apps = []
22
+
63
23
  if base_module.is_accounts_enabled():
64
- patterns.append(path('cfg/accounts/', include('django_cfg.apps.accounts.urls')))
65
-
24
+ enabled_apps.append("django_cfg.apps.accounts")
25
+
26
+ if base_module.is_support_enabled():
27
+ enabled_apps.append("django_cfg.apps.support")
28
+
66
29
  if base_module.is_newsletter_enabled():
67
- patterns.append(path('cfg/newsletter/', include('django_cfg.apps.newsletter.urls')))
68
-
30
+ enabled_apps.append("django_cfg.apps.newsletter")
31
+
69
32
  if base_module.is_leads_enabled():
70
- patterns.append(path('cfg/leads/', include('django_cfg.apps.leads.urls')))
71
-
33
+ enabled_apps.append("django_cfg.apps.leads")
34
+
72
35
  if base_module.is_knowbase_enabled():
73
- patterns.append(path('cfg/knowbase/', include('django_cfg.apps.knowbase.urls')))
74
-
36
+ enabled_apps.append("django_cfg.apps.knowbase")
37
+
75
38
  if base_module.is_agents_enabled():
76
- patterns.append(path('cfg/agents/', include('django_cfg.apps.agents.urls')))
77
-
39
+ enabled_apps.append("django_cfg.apps.agents")
40
+
78
41
  if base_module.should_enable_tasks():
79
- patterns.append(path('cfg/tasks/', include('django_cfg.apps.tasks.urls')))
80
- patterns.append(path('cfg/tasks/admin/', include('django_cfg.apps.tasks.urls_admin')))
81
-
42
+ enabled_apps.append("django_cfg.apps.tasks")
43
+
82
44
  if base_module.is_payments_enabled():
83
- patterns.append(path('cfg/payments/', include('django_cfg.apps.payments.urls')))
84
- patterns.append(path('cfg/payments/admin/', include('django_cfg.apps.payments.urls_admin')))
85
-
86
- # Standalone apps
87
- if base_module.is_maintenance_enabled():
88
- patterns.append(
89
- path('admin/django_cfg_maintenance/', include('django_cfg.apps.maintenance.urls_admin'))
90
- )
91
-
92
- if base_module.is_rpc_enabled():
93
- patterns.append(path('rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls')))
94
- patterns.append(path('admin/rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls_admin')))
45
+ enabled_apps.append("django_cfg.apps.payments")
46
+
47
+ return enabled_apps
95
48
 
96
49
 
97
- def get_django_cfg_urlpatterns() -> List[URLPattern]:
50
+ def get_default_cfg_group():
98
51
  """
99
- Get Django CFG URL patterns based on OpenAPI groups.
100
-
52
+ Returns default OpenAPIGroupConfig for enabled django-cfg apps.
53
+
54
+ Only includes apps that are enabled in the current configuration.
55
+
56
+ This can be imported and added to your project's OpenAPIClientConfig groups:
57
+
58
+ ```python
59
+ from django_cfg.apps.urls import get_default_cfg_group
60
+
61
+ openapi_client = OpenAPIClientConfig(
62
+ groups=[
63
+ get_default_cfg_group(),
64
+ # ... your custom groups
65
+ ]
66
+ )
67
+ ```
68
+
101
69
  Returns:
102
- List of URL patterns for django_cfg
70
+ OpenAPIGroupConfig with enabled django-cfg apps
103
71
  """
104
- patterns = [
105
- # Core APIs (always enabled)
106
- path('health/', include('django_cfg.apps.api.health.urls')),
107
- path('endpoints/', include('django_cfg.apps.api.endpoints.urls')),
108
- path('commands/', include('django_cfg.apps.api.commands.urls')),
109
-
110
- # OpenAPI schemas (if enabled)
111
- # Provides /openapi/{group}/schema/
112
- path('openapi/', include('django_cfg.modules.django_client.urls')),
113
- ]
114
-
72
+ from django_cfg.modules.django_client.core.config import OpenAPIGroupConfig
73
+
74
+ return OpenAPIGroupConfig(
75
+ name="cfg",
76
+ apps=get_enabled_cfg_apps(),
77
+ title="Django-CFG API",
78
+ description="Authentication (OTP), Support, Newsletter, Leads, Knowledge Base, AI Agents, Tasks, Payments",
79
+ version="1.0.0",
80
+ )
81
+
82
+
83
+ def _safe_include(pattern_path: str, module_path: str):
84
+ """Helper to safely include URL module if it exists."""
115
85
  try:
116
- # Auto-register from OpenAPI groups (preferred)
117
- from django_cfg.modules.django_client.core import get_openapi_service
118
- service = get_openapi_service()
119
-
120
- if service and service.is_enabled():
121
- _register_group_urls(patterns, service.get_groups())
122
- else:
123
- # Fallback: Use BaseCfgModule when OpenAPI disabled
124
- _register_apps_fallback(patterns)
125
-
126
- except Exception:
127
- # Last resort fallback
128
- _register_apps_fallback(patterns)
129
-
130
- return patterns
131
-
132
-
133
- # Generate URL patterns dynamically
134
- urlpatterns = get_django_cfg_urlpatterns()
86
+ return path(pattern_path, include(module_path))
87
+ except ImportError:
88
+ return None
89
+
90
+
91
+ # Core API endpoints (always enabled)
92
+ # Note: All prefixes are explicit here (cfg/, health/, etc.)
93
+ urlpatterns = [
94
+ path('cfg/health/', include('django_cfg.apps.api.health.urls')),
95
+ path('cfg/endpoints/', include('django_cfg.apps.api.endpoints.urls')),
96
+ path('cfg/commands/', include('django_cfg.apps.api.commands.urls')),
97
+ path('cfg/openapi/', include('django_cfg.modules.django_client.urls')),
98
+ ]
99
+
100
+ # Django-CFG apps - conditionally registered based on config
101
+ # Map app paths to URL patterns (with cfg/ prefix from add_django_cfg_urls)
102
+ APP_URL_MAP = {
103
+ "django_cfg.apps.accounts": [
104
+ ("cfg/accounts/", "django_cfg.apps.accounts.urls"),
105
+ ],
106
+ "django_cfg.apps.support": [
107
+ ("cfg/support/", "django_cfg.apps.support.urls"),
108
+ ],
109
+ "django_cfg.apps.newsletter": [
110
+ ("cfg/newsletter/", "django_cfg.apps.newsletter.urls"),
111
+ ],
112
+ "django_cfg.apps.leads": [
113
+ ("cfg/leads/", "django_cfg.apps.leads.urls"),
114
+ ],
115
+ "django_cfg.apps.knowbase": [
116
+ ("cfg/knowbase/", "django_cfg.apps.knowbase.urls"),
117
+ ],
118
+ "django_cfg.apps.agents": [
119
+ ("cfg/agents/", "django_cfg.apps.agents.urls"),
120
+ ],
121
+ "django_cfg.apps.tasks": [
122
+ ("cfg/tasks/", "django_cfg.apps.tasks.urls"),
123
+ ("cfg/tasks/admin/", "django_cfg.apps.tasks.urls_admin"),
124
+ ],
125
+ "django_cfg.apps.payments": [
126
+ ("cfg/payments/", "django_cfg.apps.payments.urls"),
127
+ ("cfg/payments/admin/", "django_cfg.apps.payments.urls_admin"),
128
+ ],
129
+ }
130
+
131
+ # Register URLs for enabled apps only
132
+ enabled_apps = get_enabled_cfg_apps()
133
+ cfg_app_urls = []
134
+
135
+ for app_path in enabled_apps:
136
+ if app_path in APP_URL_MAP:
137
+ for url_pattern, url_module in APP_URL_MAP[app_path]:
138
+ cfg_app_urls.append(_safe_include(url_pattern, url_module))
139
+
140
+ # Maintenance (special case - admin only)
141
+ from django_cfg.modules.base import BaseCfgModule
142
+ if BaseCfgModule().is_maintenance_enabled():
143
+ cfg_app_urls.append(_safe_include('admin/django_cfg_maintenance/', 'django_cfg.apps.maintenance.urls_admin'))
144
+
145
+ # Add only successfully imported URLs
146
+ urlpatterns.extend([url for url in cfg_app_urls if url is not None])
@@ -152,9 +152,10 @@ class APIFrameworksGenerator:
152
152
  },
153
153
  "COMPONENT_SPLIT_REQUEST": True,
154
154
  "COMPONENT_SPLIT_PATCH": True,
155
- # Auto-fix enum naming collisions
155
+ # Postprocessing hooks
156
156
  "POSTPROCESSING_HOOKS": [
157
157
  "django_cfg.modules.django_client.spectacular.auto_fix_enum_names",
158
+ "django_cfg.modules.django_client.spectacular.mark_async_operations",
158
159
  ],
159
160
  }
160
161
 
@@ -10,18 +10,17 @@ from django_cfg.core.environment import EnvironmentDetector
10
10
  from django.conf import settings
11
11
 
12
12
 
13
- def add_django_cfg_urls(urlpatterns: List[URLPattern], cfg_prefix: str = "cfg/") -> List[URLPattern]:
13
+ def add_django_cfg_urls(urlpatterns: List[URLPattern]) -> List[URLPattern]:
14
14
  """
15
15
  Automatically add django_cfg URLs and all integrations to the main URL configuration.
16
16
 
17
17
  This function adds:
18
- - Django CFG management URLs (cfg/)
18
+ - Django CFG management URLs
19
19
  - Django Client URLs (if available)
20
20
  - Startup information display (based on config)
21
21
 
22
22
  Args:
23
23
  urlpatterns: Existing URL patterns list
24
- cfg_prefix: URL prefix for django_cfg endpoints (default: "cfg/")
25
24
 
26
25
  Returns:
27
26
  Updated URL patterns list with all URLs added
@@ -35,17 +34,13 @@ def add_django_cfg_urls(urlpatterns: List[URLPattern], cfg_prefix: str = "cfg/")
35
34
  path("admin/", admin.site.urls),
36
35
  ]
37
36
 
38
- # Automatically adds:
39
- # - path("cfg/", include("django_cfg.apps.urls"))
40
- # - Django Client URLs (if available)
41
- # - Startup info display (based on config.startup_info_mode)
37
+ # Automatically adds django_cfg URLs with proper prefixes
42
38
  urlpatterns = add_django_cfg_urls(urlpatterns)
43
39
  """
44
40
  # Add django_cfg API URLs
45
- # Note: Django Client URLs are included in django_cfg.apps.urls
46
- # at /cfg/openapi/{group}/schema/ to avoid conflicts
41
+ # Note: URL prefixes (cfg/, health/, etc.) are defined in django_cfg.apps.urls
47
42
  new_patterns = urlpatterns + [
48
- path(cfg_prefix, include("django_cfg.apps.urls")),
43
+ path("", include("django_cfg.apps.urls")),
49
44
  ]
50
45
 
51
46
  # Add django-browser-reload URLs in development (if installed)
@@ -8,11 +8,11 @@ This replaces django-revolution with a cleaner, faster, type-safe implementation
8
8
  """
9
9
 
10
10
  from typing import Dict, Any, Optional
11
- from pydantic import BaseModel, Field
11
+ from pydantic import Field
12
12
  from django_cfg.modules.django_client.core.config import OpenAPIConfig, OpenAPIGroupConfig
13
13
 
14
14
 
15
- class ExtendedOpenAPIConfig(OpenAPIConfig):
15
+ class OpenAPIClientConfig(OpenAPIConfig):
16
16
  """
17
17
  Extended OpenAPI configuration with DRF parameters for django-cfg integration.
18
18
 
@@ -21,9 +21,9 @@ class ExtendedOpenAPIConfig(OpenAPIConfig):
21
21
 
22
22
  Example:
23
23
  ```python
24
- from django_cfg import ExtendedOpenAPIConfig, OpenAPIGroupConfig
24
+ from django_cfg import OpenAPIClientConfig, OpenAPIGroupConfig
25
25
 
26
- config = ExtendedOpenAPIConfig(
26
+ config = OpenAPIClientConfig(
27
27
  enabled=True,
28
28
  groups=[
29
29
  OpenAPIGroupConfig(
@@ -57,8 +57,8 @@ class ExtendedOpenAPIConfig(OpenAPIConfig):
57
57
  description="Schema path prefix for DRF Spectacular"
58
58
  )
59
59
  drf_enable_browsable_api: bool = Field(
60
- default=False,
61
- description="Enable DRF browsable API"
60
+ default=True,
61
+ description="Enable DRF browsable API with Tailwind theme"
62
62
  )
63
63
  drf_enable_throttling: bool = Field(
64
64
  default=False,
@@ -104,6 +104,8 @@ class ExtendedOpenAPIConfig(OpenAPIConfig):
104
104
  def get_groups_with_defaults(self) -> Dict[str, OpenAPIGroupConfig]:
105
105
  """
106
106
  Get groups with django-cfg default groups automatically added.
107
+
108
+ Automatically adds the 'cfg' group with all django-cfg apps if not explicitly defined.
107
109
 
108
110
  Returns:
109
111
  Dict of groups including default django-cfg groups
@@ -111,128 +113,13 @@ class ExtendedOpenAPIConfig(OpenAPIConfig):
111
113
  # Convert list to dict for compatibility
112
114
  groups_dict = {group.name: group for group in self.groups}
113
115
 
114
- # Add default django-cfg groups if enabled
115
- try:
116
- from django_cfg.modules.base import BaseCfgModule
117
- base_module = BaseCfgModule()
118
-
119
- support_enabled = base_module.is_support_enabled()
120
- accounts_enabled = base_module.is_accounts_enabled()
121
- newsletter_enabled = base_module.is_newsletter_enabled()
122
- leads_enabled = base_module.is_leads_enabled()
123
- knowbase_enabled = base_module.is_knowbase_enabled()
124
- agents_enabled = base_module.is_agents_enabled()
125
- tasks_enabled = base_module.should_enable_tasks()
126
- payments_enabled = base_module.is_payments_enabled()
127
-
128
- # Collect all enabled django-cfg apps for unified group
129
- enabled_cfg_apps = []
130
- if support_enabled:
131
- enabled_cfg_apps.append("django_cfg.apps.support")
132
- if accounts_enabled:
133
- enabled_cfg_apps.append("django_cfg.apps.accounts")
134
- if newsletter_enabled:
135
- enabled_cfg_apps.append("django_cfg.apps.newsletter")
136
- if leads_enabled:
137
- enabled_cfg_apps.append("django_cfg.apps.leads")
138
- if knowbase_enabled:
139
- enabled_cfg_apps.append("django_cfg.apps.knowbase")
140
- if agents_enabled:
141
- enabled_cfg_apps.append("django_cfg.apps.agents")
142
- if tasks_enabled:
143
- enabled_cfg_apps.append("django_cfg.apps.tasks")
144
- if payments_enabled:
145
- enabled_cfg_apps.append("django_cfg.apps.payments")
146
-
147
- # Add unified 'cfg' group with all enabled apps
148
- if enabled_cfg_apps and 'cfg' not in groups_dict:
149
- groups_dict['cfg'] = OpenAPIGroupConfig(
150
- name="cfg",
151
- apps=enabled_cfg_apps,
152
- title="Django-CFG API",
153
- description="All django-cfg built-in applications",
154
- )
155
-
156
- # Skip individual cfg_* groups - use unified 'cfg' instead
157
- return groups_dict
158
-
159
- # Add Support group if enabled
160
- if support_enabled and 'cfg_support' not in groups_dict:
161
- groups_dict['cfg_support'] = OpenAPIGroupConfig(
162
- name="cfg_support",
163
- apps=["django_cfg.apps.support"],
164
- title="Support API",
165
- description="Support tickets and messages API",
166
- )
167
-
168
- # Add Accounts group if enabled
169
- if accounts_enabled and 'cfg_accounts' not in groups_dict:
170
- groups_dict['cfg_accounts'] = OpenAPIGroupConfig(
171
- name="cfg_accounts",
172
- apps=["django_cfg.apps.accounts"],
173
- title="Accounts API",
174
- description="User management, OTP, profiles, and activity tracking API",
175
- )
176
-
177
- # Add Newsletter group if enabled
178
- if newsletter_enabled and 'cfg_newsletter' not in groups_dict:
179
- groups_dict['cfg_newsletter'] = OpenAPIGroupConfig(
180
- name="cfg_newsletter",
181
- apps=["django_cfg.apps.newsletter"],
182
- title="Newsletter API",
183
- description="Email campaigns, subscriptions, and newsletter management API",
184
- )
185
-
186
- # Add Leads group if enabled
187
- if leads_enabled and 'cfg_leads' not in groups_dict:
188
- groups_dict['cfg_leads'] = OpenAPIGroupConfig(
189
- name="cfg_leads",
190
- apps=["django_cfg.apps.leads"],
191
- title="Leads API",
192
- description="Lead collection, contact forms, and CRM integration API",
193
- )
194
-
195
- # Add Knowbase group if enabled
196
- if knowbase_enabled and 'cfg_knowbase' not in groups_dict:
197
- groups_dict['cfg_knowbase'] = OpenAPIGroupConfig(
198
- name="cfg_knowbase",
199
- apps=["django_cfg.apps.knowbase"],
200
- title="Knowbase API",
201
- description="Knowledge base, AI chat, embeddings, and search API",
202
- )
203
-
204
- # Add Agents group if enabled
205
- if agents_enabled and 'cfg_agents' not in groups_dict:
206
- groups_dict['cfg_agents'] = OpenAPIGroupConfig(
207
- name="cfg_agents",
208
- apps=["django_cfg.apps.agents"],
209
- title="Agents API",
210
- description="Agent definitions, executions, workflows, and tools API",
211
- )
212
-
213
- # Add Tasks group if enabled
214
- if tasks_enabled and 'cfg_tasks' not in groups_dict:
215
- groups_dict['cfg_tasks'] = OpenAPIGroupConfig(
216
- name="cfg_tasks",
217
- apps=["django_cfg.apps.tasks"],
218
- title="Tasks API",
219
- description="Tasks, workflows, and automation API",
220
- )
221
-
222
- # Add Payments group if enabled
223
- if payments_enabled and 'cfg_payments' not in groups_dict:
224
- groups_dict['cfg_payments'] = OpenAPIGroupConfig(
225
- name="cfg_payments",
226
- apps=["django_cfg.apps.payments"],
227
- title="Payments API",
228
- description="Payments, subscriptions, and billing API",
229
- )
230
-
231
- except Exception:
232
- pass
116
+ # Add default 'cfg' group if not explicitly defined
117
+ if 'cfg' not in groups_dict:
118
+ try:
119
+ from django_cfg.apps.urls import get_default_cfg_group
120
+ groups_dict['cfg'] = get_default_cfg_group()
121
+ except Exception:
122
+ pass
233
123
 
234
124
  return groups_dict
235
125
 
236
-
237
- # Alias for easier import
238
- OpenAPIClientConfig = ExtendedOpenAPIConfig
@@ -57,12 +57,12 @@ class ArchiveManager:
57
57
 
58
58
  if python_dir and python_dir.exists():
59
59
  dest = archive_path / "python"
60
- shutil.copytree(python_dir, dest)
60
+ shutil.copytree(python_dir, dest, dirs_exist_ok=True)
61
61
  copied["python"] = str(dest)
62
62
 
63
63
  if typescript_dir and typescript_dir.exists():
64
64
  dest = archive_path / "typescript"
65
- shutil.copytree(typescript_dir, dest)
65
+ shutil.copytree(typescript_dir, dest, dirs_exist_ok=True)
66
66
  copied["typescript"] = str(dest)
67
67
 
68
68
  # Create metadata
@@ -76,6 +76,26 @@ class OpenAPIConfig(BaseModel):
76
76
  description="Generate TypeScript client",
77
77
  )
78
78
 
79
+ generate_package_files: bool = Field(
80
+ default=False,
81
+ description="Generate package.json (TypeScript) and pyproject.toml (Python)",
82
+ )
83
+
84
+ generate_zod_schemas: bool = Field(
85
+ default=False,
86
+ description="Generate Zod schemas for runtime validation (TypeScript only)",
87
+ )
88
+
89
+ generate_fetchers: bool = Field(
90
+ default=False,
91
+ description="Generate typed fetcher functions (TypeScript only, requires Zod schemas)",
92
+ )
93
+
94
+ generate_swr_hooks: bool = Field(
95
+ default=False,
96
+ description="Generate SWR hooks for React (TypeScript only, requires fetchers)",
97
+ )
98
+
79
99
  client_structure: Literal["flat", "namespaced"] = Field(
80
100
  default="namespaced",
81
101
  description=(
@@ -59,7 +59,7 @@ class DjangoOpenAPI:
59
59
  if not self.config:
60
60
  return {}
61
61
 
62
- # Use get_groups_with_defaults if available (ExtendedOpenAPIConfig)
62
+ # Use get_groups_with_defaults if available (OpenAPIClientConfig)
63
63
  if hasattr(self.config, 'get_groups_with_defaults'):
64
64
  return self.config.get_groups_with_defaults()
65
65
 
@@ -22,10 +22,10 @@ Usage:
22
22
  from pathlib import Path
23
23
  from typing import Literal
24
24
 
25
- from django_cfg.modules.django_client.core.generator.base import GeneratedFile
26
- from django_cfg.modules.django_client.core.generator.python import PythonGenerator
27
- from django_cfg.modules.django_client.core.generator.typescript import TypeScriptGenerator
28
- from django_cfg.modules.django_client.core.ir import IRContext
25
+ from .base import GeneratedFile
26
+ from .python import PythonGenerator
27
+ from .typescript import TypeScriptGenerator
28
+ from ..ir import IRContext
29
29
 
30
30
  __all__ = [
31
31
  "PythonGenerator",
@@ -48,6 +48,11 @@ class BaseGenerator(ABC):
48
48
  client_structure: str = "namespaced",
49
49
  openapi_schema: dict | None = None,
50
50
  tag_prefix: str = "",
51
+ package_config: dict | None = None,
52
+ generate_package_files: bool = False,
53
+ generate_zod_schemas: bool = False,
54
+ generate_fetchers: bool = False,
55
+ generate_swr_hooks: bool = False,
51
56
  ):
52
57
  """
53
58
  Initialize generator with IR context.
@@ -57,11 +62,21 @@ class BaseGenerator(ABC):
57
62
  client_structure: Client structure ("flat" or "namespaced")
58
63
  openapi_schema: OpenAPI schema dict (for embedding in client)
59
64
  tag_prefix: Prefix to add to all tag names (e.g., "cfg_")
65
+ package_config: Package configuration (name, version, author, etc.)
66
+ generate_package_files: Whether to generate package.json/pyproject.toml
67
+ generate_zod_schemas: Whether to generate Zod schemas (TypeScript only)
68
+ generate_fetchers: Whether to generate typed fetchers (TypeScript only)
69
+ generate_swr_hooks: Whether to generate SWR hooks (TypeScript only, React)
60
70
  """
61
71
  self.context = context
62
72
  self.client_structure = client_structure
63
73
  self.openapi_schema = openapi_schema
64
74
  self.tag_prefix = tag_prefix
75
+ self.package_config = package_config or {}
76
+ self.generate_package_files = generate_package_files
77
+ self.generate_zod_schemas = generate_zod_schemas
78
+ self.generate_fetchers = generate_fetchers
79
+ self.generate_swr_hooks = generate_swr_hooks
65
80
 
66
81
  # ===== Namespaced Structure Helpers =====
67
82
 
@@ -765,3 +780,59 @@ class BaseGenerator(ABC):
765
780
  lines.append(" ".join(current_line))
766
781
 
767
782
  return lines
783
+
784
+ def format_enum_description(self, text: str) -> str:
785
+ """
786
+ Format enum description by splitting bullet points.
787
+
788
+ Enum descriptions from OpenAPI often have the format:
789
+ "* `value1` - Desc1 * `value2` - Desc2"
790
+
791
+ This method splits them into separate lines:
792
+ "* `value1` - Desc1\n* `value2` - Desc2"
793
+
794
+ Args:
795
+ text: Enum description text
796
+
797
+ Returns:
798
+ Formatted description with proper line breaks
799
+ """
800
+ if not text:
801
+ return text
802
+
803
+ # Split by " * `" pattern (preserving the first *)
804
+ import re
805
+ # Replace " * `" with newline + "* `"
806
+ formatted = re.sub(r'\s+\*\s+`', '\n* `', text.strip())
807
+
808
+ return formatted
809
+
810
+ def sanitize_enum_name(self, name: str) -> str:
811
+ """
812
+ Sanitize enum name by converting to PascalCase.
813
+
814
+ Examples:
815
+ "OrderDetail.status" -> "OrderDetailStatus"
816
+ "Currency.currency_type" -> "CurrencyCurrencyType"
817
+ "CurrencyList.currency_type" -> "CurrencyListCurrencyType"
818
+ "User.role" -> "UserRole"
819
+
820
+ Args:
821
+ name: Original enum name (may contain dots, underscores)
822
+
823
+ Returns:
824
+ Sanitized PascalCase name
825
+ """
826
+ # Replace dots with underscores, then split and convert to PascalCase
827
+ parts = name.replace('.', '_').split('_')
828
+ result = []
829
+ for word in parts:
830
+ if not word:
831
+ continue
832
+ # If word is already PascalCase/camelCase, keep it as is
833
+ # Otherwise capitalize first letter only
834
+ if word[0].isupper():
835
+ result.append(word)
836
+ else:
837
+ result.append(word[0].upper() + word[1:] if len(word) > 1 else word.upper())
838
+ return ''.join(result)
@@ -0,0 +1,16 @@
1
+ """
2
+ Python Generator - Generates Python client (Pydantic 2 + httpx).
3
+
4
+ This generator creates a complete Python API client from IR:
5
+ - Pydantic 2 models (Request/Response/Patch splits)
6
+ - Enum classes from x-enum-varnames
7
+ - httpx.AsyncClient for async HTTP
8
+ - Django CSRF/session handling
9
+ - Type-safe (MyPy strict mode compatible)
10
+
11
+ Reference: https://docs.pydantic.dev/latest/
12
+ """
13
+
14
+ from .generator import PythonGenerator
15
+
16
+ __all__ = ['PythonGenerator']