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.
- django_cfg/apps/agents/management/commands/create_agent.py +1 -1
- django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
- django_cfg/apps/newsletter/serializers.py +40 -3
- django_cfg/apps/newsletter/views/campaigns.py +12 -3
- django_cfg/apps/newsletter/views/emails.py +14 -3
- django_cfg/apps/newsletter/views/subscriptions.py +12 -2
- django_cfg/apps/payments/views/api/currencies.py +49 -6
- django_cfg/apps/payments/views/api/webhooks.py +72 -7
- django_cfg/apps/payments/views/overview/serializers.py +34 -1
- django_cfg/apps/payments/views/overview/views.py +2 -1
- django_cfg/apps/payments/views/serializers/payments.py +6 -6
- django_cfg/apps/urls.py +106 -45
- django_cfg/core/base/config_model.py +2 -2
- django_cfg/core/constants.py +1 -1
- django_cfg/core/generation/integration_generators/__init__.py +1 -1
- django_cfg/core/generation/integration_generators/api.py +73 -49
- django_cfg/core/integration/display/startup.py +30 -22
- django_cfg/core/integration/url_integration.py +15 -16
- django_cfg/management/commands/check_endpoints.py +11 -160
- django_cfg/management/commands/check_settings.py +13 -348
- django_cfg/management/commands/clear_constance.py +13 -201
- django_cfg/management/commands/create_token.py +13 -321
- django_cfg/management/commands/generate_clients.py +23 -0
- django_cfg/management/commands/list_urls.py +13 -306
- django_cfg/management/commands/migrate_all.py +13 -126
- django_cfg/management/commands/migrator.py +13 -396
- django_cfg/management/commands/rundramatiq.py +15 -247
- django_cfg/management/commands/rundramatiq_simulator.py +12 -429
- django_cfg/management/commands/runserver_ngrok.py +15 -160
- django_cfg/management/commands/script.py +12 -488
- django_cfg/management/commands/show_config.py +12 -215
- django_cfg/management/commands/show_urls.py +12 -342
- django_cfg/management/commands/superuser.py +15 -295
- django_cfg/management/commands/task_clear.py +14 -217
- django_cfg/management/commands/task_status.py +13 -248
- django_cfg/management/commands/test_email.py +15 -86
- django_cfg/management/commands/test_telegram.py +14 -61
- django_cfg/management/commands/test_twilio.py +15 -105
- django_cfg/management/commands/tree.py +13 -383
- django_cfg/management/commands/validate_openapi.py +10 -0
- django_cfg/middleware/README.md +1 -1
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/__init__.py +2 -2
- django_cfg/models/api/drf/spectacular.py +6 -6
- django_cfg/models/django/__init__.py +2 -2
- django_cfg/models/django/openapi.py +162 -0
- django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
- django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
- django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
- django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
- django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
- django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
- django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
- django_cfg/modules/django_admin/management/commands/script.py +496 -0
- django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
- django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
- django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
- django_cfg/modules/django_admin/management/commands/tree.py +390 -0
- django_cfg/modules/django_client/__init__.py +20 -0
- django_cfg/modules/django_client/apps.py +35 -0
- django_cfg/modules/django_client/core/__init__.py +56 -0
- django_cfg/modules/django_client/core/archive/__init__.py +11 -0
- django_cfg/modules/django_client/core/archive/manager.py +134 -0
- django_cfg/modules/django_client/core/cli/__init__.py +12 -0
- django_cfg/modules/django_client/core/cli/main.py +235 -0
- django_cfg/modules/django_client/core/config/__init__.py +18 -0
- django_cfg/modules/django_client/core/config/config.py +208 -0
- django_cfg/modules/django_client/core/config/group.py +101 -0
- django_cfg/modules/django_client/core/config/service.py +209 -0
- django_cfg/modules/django_client/core/generator/__init__.py +115 -0
- django_cfg/modules/django_client/core/generator/base.py +838 -0
- django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
- django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
- django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
- django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
- django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
- django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
- django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
- django_cfg/modules/django_client/core/generator/python/templates/__init__.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +153 -0
- django_cfg/modules/django_client/core/generator/python/templates/app_init.py.jinja +6 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/app_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/flat_client.py.jinja +38 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +68 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/main_client_file.py.jinja +14 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/operation_method.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sub_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client_file.py.jinja +13 -0
- django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +52 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/app_models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/enum_class.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +8 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/schema_class.py.jinja +21 -0
- django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/logger.py.jinja +255 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/schema.py.jinja +12 -0
- django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
- django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
- django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
- django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
- django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
- django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +536 -0
- django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
- django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
- django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/app_index.ts.jinja +2 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/app_client.ts.jinja +18 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +403 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/flat_client.ts.jinja +109 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/main_client_file.ts.jinja +10 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/operation.ts.jinja +61 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/sub_client.ts.jinja +15 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client_file.ts.jinja +9 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/index.ts.jinja +5 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +268 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/app_models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/enums.ts.jinja +4 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/errors.ts.jinja +116 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/http.ts.jinja +98 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/logger.ts.jinja +259 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/schema.ts.jinja +7 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/storage.ts.jinja +158 -0
- django_cfg/modules/django_client/core/groups/__init__.py +13 -0
- django_cfg/modules/django_client/core/groups/detector.py +178 -0
- django_cfg/modules/django_client/core/groups/manager.py +314 -0
- django_cfg/modules/django_client/core/ir/__init__.py +57 -0
- django_cfg/modules/django_client/core/ir/context.py +387 -0
- django_cfg/modules/django_client/core/ir/operation.py +518 -0
- django_cfg/modules/django_client/core/ir/schema.py +353 -0
- django_cfg/modules/django_client/core/parser/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/base.py +648 -0
- django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/models/base.py +212 -0
- django_cfg/modules/django_client/core/parser/models/components.py +160 -0
- django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
- django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
- django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
- django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
- django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
- django_cfg/modules/django_client/core/validation/__init__.py +22 -0
- django_cfg/modules/django_client/core/validation/checker.py +134 -0
- django_cfg/modules/django_client/core/validation/fixer.py +216 -0
- django_cfg/modules/django_client/core/validation/reporter.py +480 -0
- django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
- django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
- django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
- django_cfg/modules/django_client/core/validation/safety.py +266 -0
- django_cfg/modules/django_client/management/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +427 -0
- django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
- django_cfg/modules/django_client/pytest.ini +30 -0
- django_cfg/modules/django_client/spectacular/__init__.py +10 -0
- django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
- django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
- django_cfg/modules/django_client/urls.py +72 -0
- django_cfg/{dashboard → modules/django_dashboard}/DEBUG_README.md +2 -2
- django_cfg/{dashboard → modules/django_dashboard}/REFACTORING_SUMMARY.md +1 -1
- django_cfg/modules/django_dashboard/management/__init__.py +0 -0
- django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
- django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
- django_cfg/modules/django_dashboard/sections/documentation.py +391 -0
- django_cfg/modules/django_email/management/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/test_email.py +93 -0
- django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
- django_cfg/modules/django_logging/django_logger.py +6 -6
- django_cfg/modules/django_ngrok/management/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
- django_cfg/modules/django_tasks/management/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
- django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
- django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
- django_cfg/modules/django_telegram/management/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
- django_cfg/modules/django_twilio/management/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
- django_cfg/modules/django_unfold/callbacks/main.py +21 -10
- django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
- django_cfg/pyproject.toml +2 -6
- django_cfg/registry/third_party.py +5 -7
- django_cfg/routing/callbacks.py +1 -1
- django_cfg/static/admin/css/prose-unfold.css +666 -0
- django_cfg/templates/admin/index.html +8 -0
- django_cfg/templates/admin/index_new.html +13 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
- django_cfg/templates/admin/sections/documentation_section.html +172 -0
- django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/METADATA +2 -2
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/RECORD +224 -74
- django_cfg/management/commands/generate.py +0 -107
- /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
- /django_cfg/{dashboard → modules/django_admin}/management/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_admin}/management/commands/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/licenses/LICENSE +0 -0
@@ -1,390 +1,20 @@
|
|
1
1
|
"""
|
2
|
-
|
2
|
+
Django-CFG wrapper for tree command.
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
import os
|
8
|
-
import subprocess
|
9
|
-
from pathlib import Path
|
10
|
-
from typing import List, Optional
|
11
|
-
|
12
|
-
from django.core.management.base import BaseCommand, CommandError
|
13
|
-
from django.conf import settings
|
14
|
-
from django_cfg.modules.django_logging import get_logger
|
15
|
-
|
16
|
-
|
17
|
-
from django_cfg.core.state import get_current_config
|
18
|
-
from django_cfg.utils.path_resolution import PathResolver
|
4
|
+
This is a simple alias for django_admin.management.commands.tree.
|
5
|
+
All logic is in django_admin module.
|
19
6
|
|
7
|
+
Usage:
|
8
|
+
python manage.py tree
|
9
|
+
"""
|
20
10
|
|
21
|
-
|
11
|
+
from django_cfg.modules.django_admin.management.commands.tree import Command as TreeCommand
|
22
12
|
|
23
|
-
class Command(BaseCommand):
|
24
|
-
"""Display Django project structure in tree format."""
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
is_destructive = False
|
14
|
+
class Command(TreeCommand):
|
15
|
+
"""
|
16
|
+
Alias for tree command.
|
30
17
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
"""Add command arguments."""
|
35
|
-
parser.add_argument(
|
36
|
-
'--depth', '-L',
|
37
|
-
type=int,
|
38
|
-
default=5,
|
39
|
-
help='Maximum depth to display (default: 5)'
|
40
|
-
)
|
41
|
-
parser.add_argument(
|
42
|
-
'--all', '-a',
|
43
|
-
action='store_true',
|
44
|
-
help='Show all files including hidden ones'
|
45
|
-
)
|
46
|
-
parser.add_argument(
|
47
|
-
'--dirs-only', '-d',
|
48
|
-
action='store_true',
|
49
|
-
help='Show directories only'
|
50
|
-
)
|
51
|
-
parser.add_argument(
|
52
|
-
'--no-ignore', '-n',
|
53
|
-
action='store_true',
|
54
|
-
help='Do not ignore common directories (node_modules, .git, etc.)'
|
55
|
-
)
|
56
|
-
parser.add_argument(
|
57
|
-
'--custom-ignore',
|
58
|
-
type=str,
|
59
|
-
help='Custom ignore pattern (pipe-separated, e.g., "*.pyc|temp|logs")'
|
60
|
-
)
|
61
|
-
parser.add_argument(
|
62
|
-
'--include-docs',
|
63
|
-
action='store_true',
|
64
|
-
help='Legacy option - @docs directories are now included by default'
|
65
|
-
)
|
66
|
-
parser.add_argument(
|
67
|
-
'--include-docker',
|
68
|
-
action='store_true',
|
69
|
-
help='Include Docker configuration and volumes'
|
70
|
-
)
|
71
|
-
parser.add_argument(
|
72
|
-
'--include-logs',
|
73
|
-
action='store_true',
|
74
|
-
help='Include log files and directories'
|
75
|
-
)
|
76
|
-
parser.add_argument(
|
77
|
-
'--output', '-o',
|
78
|
-
type=str,
|
79
|
-
help='Output to file instead of stdout'
|
80
|
-
)
|
81
|
-
parser.add_argument(
|
82
|
-
'--format',
|
83
|
-
choices=['tree', 'json', 'xml'],
|
84
|
-
default='tree',
|
85
|
-
help='Output format (default: tree)'
|
86
|
-
)
|
87
|
-
|
88
|
-
def handle(self, *args, **options):
|
89
|
-
"""Execute the command."""
|
90
|
-
logger.info("Starting tree command")
|
91
|
-
try:
|
92
|
-
# Get django-cfg configuration
|
93
|
-
config = get_current_config()
|
94
|
-
|
95
|
-
# Determine base directory
|
96
|
-
base_dir = self.get_base_directory(config)
|
97
|
-
|
98
|
-
self.stdout.write(
|
99
|
-
self.style.SUCCESS(f"📁 Django Project Structure: {base_dir}")
|
100
|
-
)
|
101
|
-
|
102
|
-
# Try to get environment info
|
103
|
-
try:
|
104
|
-
env_info = getattr(config, 'env_mode', 'unknown')
|
105
|
-
self.stdout.write(
|
106
|
-
self.style.HTTP_INFO(f"🔧 Environment: {env_info}")
|
107
|
-
)
|
108
|
-
except Exception:
|
109
|
-
pass
|
110
|
-
|
111
|
-
self.stdout.write("")
|
112
|
-
|
113
|
-
# Check if tree command is available
|
114
|
-
if not self.is_tree_available():
|
115
|
-
self.stdout.write(
|
116
|
-
self.style.WARNING("⚠️ 'tree' command not found. Using fallback implementation.")
|
117
|
-
)
|
118
|
-
self.display_fallback_tree(base_dir, options)
|
119
|
-
else:
|
120
|
-
self.display_tree(base_dir, options)
|
121
|
-
|
122
|
-
except Exception as e:
|
123
|
-
raise CommandError(f"Failed to display project tree: {e}")
|
124
|
-
|
125
|
-
def get_base_directory(self, config) -> Path:
|
126
|
-
"""Get the base directory for the Django project tree."""
|
127
|
-
try:
|
128
|
-
# First try to use PathResolver to find the actual Django project root
|
129
|
-
return PathResolver.find_project_root()
|
130
|
-
except Exception:
|
131
|
-
try:
|
132
|
-
# Try to get from config
|
133
|
-
if hasattr(config, 'base_dir') and config.base_dir:
|
134
|
-
return Path(config.base_dir)
|
135
|
-
|
136
|
-
# Fallback to Django BASE_DIR
|
137
|
-
if hasattr(settings, 'BASE_DIR'):
|
138
|
-
return Path(settings.BASE_DIR)
|
139
|
-
|
140
|
-
# Last resort: current working directory
|
141
|
-
return Path.cwd()
|
142
|
-
|
143
|
-
except Exception as e:
|
144
|
-
self.stdout.write(
|
145
|
-
self.style.WARNING(f"Could not determine base directory: {e}")
|
146
|
-
)
|
147
|
-
return Path.cwd()
|
148
|
-
|
149
|
-
def is_tree_available(self) -> bool:
|
150
|
-
"""Check if tree command is available."""
|
151
|
-
try:
|
152
|
-
subprocess.run(['tree', '--version'],
|
153
|
-
capture_output=True,
|
154
|
-
check=True)
|
155
|
-
return True
|
156
|
-
except (subprocess.CalledProcessError, FileNotFoundError):
|
157
|
-
return False
|
158
|
-
|
159
|
-
def build_ignore_pattern(self, options) -> str:
|
160
|
-
"""Build ignore pattern for tree command."""
|
161
|
-
if options['no_ignore']:
|
162
|
-
return ""
|
163
|
-
|
164
|
-
# Default ignore patterns
|
165
|
-
default_ignores = [
|
166
|
-
'node_modules',
|
167
|
-
'.git',
|
168
|
-
'.venv',
|
169
|
-
'venv',
|
170
|
-
'.env',
|
171
|
-
'.DS_Store',
|
172
|
-
'__pycache__',
|
173
|
-
'*.pyc',
|
174
|
-
'*.pyo',
|
175
|
-
'*.pyd',
|
176
|
-
'.pytest_cache',
|
177
|
-
'.coverage',
|
178
|
-
'htmlcov',
|
179
|
-
'coverage',
|
180
|
-
'.tox',
|
181
|
-
'dist',
|
182
|
-
'build',
|
183
|
-
'*.egg-info',
|
184
|
-
'staticfiles',
|
185
|
-
'media',
|
186
|
-
'@old*',
|
187
|
-
'parsers',
|
188
|
-
'openapi',
|
189
|
-
'modules',
|
190
|
-
'django_cfg',
|
191
|
-
# Package manager files
|
192
|
-
'package-lock.json',
|
193
|
-
'pnpm-lock.yaml',
|
194
|
-
'poetry.lock',
|
195
|
-
'yarn.lock',
|
196
|
-
# Empty/system directories
|
197
|
-
'db',
|
198
|
-
'static'
|
199
|
-
]
|
200
|
-
|
201
|
-
# Conditionally add patterns based on options
|
202
|
-
# Note: @docs folders are now included by default to show documentation
|
203
|
-
|
204
|
-
if not options.get('include_docker'):
|
205
|
-
default_ignores.extend([
|
206
|
-
'docker',
|
207
|
-
'devops'
|
208
|
-
])
|
209
|
-
|
210
|
-
if not options.get('include_logs'):
|
211
|
-
default_ignores.extend([
|
212
|
-
'logs',
|
213
|
-
'*.log',
|
214
|
-
'log'
|
215
|
-
])
|
216
|
-
|
217
|
-
# Add custom ignores
|
218
|
-
if options['custom_ignore']:
|
219
|
-
custom_ignores = options['custom_ignore'].split('|')
|
220
|
-
default_ignores.extend(custom_ignores)
|
221
|
-
|
222
|
-
return '|'.join(default_ignores)
|
223
|
-
|
224
|
-
def display_tree(self, base_dir: Path, options):
|
225
|
-
"""Display tree using system tree command."""
|
226
|
-
try:
|
227
|
-
# Build tree command
|
228
|
-
cmd = ['tree']
|
229
|
-
|
230
|
-
# Add ignore pattern
|
231
|
-
ignore_pattern = self.build_ignore_pattern(options)
|
232
|
-
if ignore_pattern:
|
233
|
-
cmd.extend(['-I', ignore_pattern])
|
234
|
-
|
235
|
-
# Add options
|
236
|
-
cmd.append('--dirsfirst') # Directories first
|
237
|
-
|
238
|
-
if options['depth']:
|
239
|
-
cmd.extend(['-L', str(options['depth'])])
|
240
|
-
|
241
|
-
if options['dirs_only']:
|
242
|
-
cmd.append('-d')
|
243
|
-
|
244
|
-
if options['all']:
|
245
|
-
cmd.append('-a')
|
246
|
-
|
247
|
-
# Add format options
|
248
|
-
if options['format'] == 'json':
|
249
|
-
cmd.append('-J')
|
250
|
-
elif options['format'] == 'xml':
|
251
|
-
cmd.append('-X')
|
252
|
-
|
253
|
-
# Add base directory
|
254
|
-
cmd.append(str(base_dir))
|
255
|
-
|
256
|
-
# Execute command
|
257
|
-
if options['output']:
|
258
|
-
with open(options['output'], 'w') as f:
|
259
|
-
result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, text=True)
|
260
|
-
if result.returncode == 0:
|
261
|
-
self.stdout.write(
|
262
|
-
self.style.SUCCESS(f"✅ Tree output saved to: {options['output']}")
|
263
|
-
)
|
264
|
-
else:
|
265
|
-
self.stdout.write(
|
266
|
-
self.style.ERROR(f"❌ Tree command failed: {result.stderr}")
|
267
|
-
)
|
268
|
-
else:
|
269
|
-
result = subprocess.run(cmd, text=True)
|
270
|
-
if result.returncode != 0:
|
271
|
-
self.stdout.write(
|
272
|
-
self.style.ERROR("❌ Tree command failed")
|
273
|
-
)
|
274
|
-
|
275
|
-
except Exception as e:
|
276
|
-
self.stdout.write(
|
277
|
-
self.style.ERROR(f"❌ Failed to execute tree command: {e}")
|
278
|
-
)
|
279
|
-
self.display_fallback_tree(base_dir, options)
|
280
|
-
|
281
|
-
def display_fallback_tree(self, base_dir: Path, options):
|
282
|
-
"""Fallback tree implementation using Python."""
|
283
|
-
self.stdout.write("🐍 Using Python fallback implementation:")
|
284
|
-
self.stdout.write("")
|
285
|
-
|
286
|
-
ignore_patterns = self.build_ignore_pattern(options).split('|') if not options['no_ignore'] else []
|
287
|
-
|
288
|
-
def should_ignore(path: Path) -> bool:
|
289
|
-
"""Check if path should be ignored."""
|
290
|
-
name = path.name
|
291
|
-
for pattern in ignore_patterns:
|
292
|
-
if pattern.startswith('*'):
|
293
|
-
if name.endswith(pattern[1:]):
|
294
|
-
return True
|
295
|
-
elif pattern.endswith('*'):
|
296
|
-
if name.startswith(pattern[:-1]):
|
297
|
-
return True
|
298
|
-
elif pattern == name:
|
299
|
-
return True
|
300
|
-
return False
|
301
|
-
|
302
|
-
def print_tree(directory: Path, prefix: str = "", depth: int = 0):
|
303
|
-
"""Recursively print directory tree."""
|
304
|
-
if options['depth'] and depth >= options['depth']:
|
305
|
-
return
|
306
|
-
|
307
|
-
try:
|
308
|
-
items = []
|
309
|
-
for item in directory.iterdir():
|
310
|
-
if not options['all'] and item.name.startswith('.'):
|
311
|
-
continue
|
312
|
-
if should_ignore(item):
|
313
|
-
continue
|
314
|
-
items.append(item)
|
315
|
-
|
316
|
-
# Sort: directories first, then files
|
317
|
-
items.sort(key=lambda x: (not x.is_dir(), x.name.lower()))
|
318
|
-
|
319
|
-
for i, item in enumerate(items):
|
320
|
-
is_last = i == len(items) - 1
|
321
|
-
current_prefix = "└── " if is_last else "├── "
|
322
|
-
|
323
|
-
if item.is_dir():
|
324
|
-
self.stdout.write(f"{prefix}{current_prefix}📁 {item.name}/")
|
325
|
-
if not options['dirs_only']:
|
326
|
-
next_prefix = prefix + (" " if is_last else "│ ")
|
327
|
-
print_tree(item, next_prefix, depth + 1)
|
328
|
-
elif not options['dirs_only']:
|
329
|
-
# Add file type emoji
|
330
|
-
emoji = self.get_file_emoji(item)
|
331
|
-
self.stdout.write(f"{prefix}{current_prefix}{emoji} {item.name}")
|
332
|
-
|
333
|
-
except PermissionError:
|
334
|
-
self.stdout.write(f"{prefix}❌ Permission denied")
|
335
|
-
|
336
|
-
print_tree(base_dir)
|
337
|
-
|
338
|
-
def get_file_emoji(self, file_path: Path) -> str:
|
339
|
-
"""Get emoji for file type."""
|
340
|
-
suffix = file_path.suffix.lower()
|
341
|
-
|
342
|
-
emoji_map = {
|
343
|
-
'.py': '🐍',
|
344
|
-
'.js': '📜',
|
345
|
-
'.ts': '📘',
|
346
|
-
'.html': '🌐',
|
347
|
-
'.css': '🎨',
|
348
|
-
'.scss': '🎨',
|
349
|
-
'.json': '📋',
|
350
|
-
'.yaml': '📄',
|
351
|
-
'.yml': '📄',
|
352
|
-
'.toml': '⚙️',
|
353
|
-
'.ini': '⚙️',
|
354
|
-
'.cfg': '⚙️',
|
355
|
-
'.conf': '⚙️',
|
356
|
-
'.md': '📝',
|
357
|
-
'.txt': '📄',
|
358
|
-
'.log': '📊',
|
359
|
-
'.sql': '🗄️',
|
360
|
-
'.db': '🗄️',
|
361
|
-
'.sqlite': '🗄️',
|
362
|
-
'.sqlite3': '🗄️',
|
363
|
-
'.png': '🖼️',
|
364
|
-
'.jpg': '🖼️',
|
365
|
-
'.jpeg': '🖼️',
|
366
|
-
'.gif': '🖼️',
|
367
|
-
'.svg': '🖼️',
|
368
|
-
'.ico': '🖼️',
|
369
|
-
'.pdf': '📕',
|
370
|
-
'.zip': '📦',
|
371
|
-
'.tar': '📦',
|
372
|
-
'.gz': '📦',
|
373
|
-
'.requirements': '📋',
|
374
|
-
'requirements.txt': '📋',
|
375
|
-
'Dockerfile': '🐳',
|
376
|
-
'docker-compose.yml': '🐳',
|
377
|
-
'manage.py': '⚙️',
|
378
|
-
'setup.py': '⚙️',
|
379
|
-
'pyproject.toml': '📦',
|
380
|
-
'poetry.lock': '🔒',
|
381
|
-
'Pipfile': '📦',
|
382
|
-
'Pipfile.lock': '🔒',
|
383
|
-
}
|
384
|
-
|
385
|
-
# Check full filename first
|
386
|
-
if file_path.name in emoji_map:
|
387
|
-
return emoji_map[file_path.name]
|
388
|
-
|
389
|
-
# Then check extension
|
390
|
-
return emoji_map.get(suffix, '📄')
|
18
|
+
Simply inherits from TreeCommand without any changes.
|
19
|
+
"""
|
20
|
+
pass
|
@@ -0,0 +1,10 @@
|
|
1
|
+
"""
|
2
|
+
Alias for validate_openapi command.
|
3
|
+
|
4
|
+
This is an alias that delegates to the actual implementation in
|
5
|
+
django_cfg.modules.django_client.management.commands.validate_openapi
|
6
|
+
|
7
|
+
For backward compatibility and discoverability.
|
8
|
+
"""
|
9
|
+
|
10
|
+
from django_cfg.modules.django_client.management.commands.validate_openapi import Command # noqa: F401
|
django_cfg/middleware/README.md
CHANGED
@@ -47,7 +47,7 @@ The middleware intelligently detects API requests using:
|
|
47
47
|
3. **REST methods** (POST, PUT, PATCH, DELETE) on non-admin paths
|
48
48
|
|
49
49
|
4. **Configured API prefixes**
|
50
|
-
- Django
|
50
|
+
- Django Client API: `/{api_prefix}/` (from config)
|
51
51
|
- Django CFG API: `/cfg/` (always)
|
52
52
|
|
53
53
|
### 📊 Statistics
|
@@ -103,9 +103,9 @@ class UserActivityMiddleware(MiddlewareMixin, BaseCfgModule):
|
|
103
103
|
try:
|
104
104
|
config = self.get_config()
|
105
105
|
if config:
|
106
|
-
# Check Django
|
107
|
-
if hasattr(config, '
|
108
|
-
api_prefix = f"/{getattr(config.
|
106
|
+
# Check Django Client (OpenAPI) API prefix
|
107
|
+
if hasattr(config, 'openapi_client') and config.openapi_client:
|
108
|
+
api_prefix = f"/{getattr(config.openapi_client, 'api_prefix', 'api')}/"
|
109
109
|
if path.startswith(api_prefix):
|
110
110
|
return True
|
111
111
|
|
django_cfg/models/__init__.py
CHANGED
@@ -38,7 +38,7 @@ from .api.drf.redoc import RedocUISettings
|
|
38
38
|
# Django-specific
|
39
39
|
from .django.environment import EnvironmentConfig
|
40
40
|
from .django.constance import ConstanceConfig, ConstanceField
|
41
|
-
from .django.
|
41
|
+
from .django.openapi import OpenAPIClientConfig
|
42
42
|
|
43
43
|
# Services
|
44
44
|
from .services.email import EmailConfig
|
@@ -80,7 +80,7 @@ __all__ = [
|
|
80
80
|
"EnvironmentConfig",
|
81
81
|
"ConstanceConfig",
|
82
82
|
"ConstanceField",
|
83
|
-
"
|
83
|
+
"OpenAPIClientConfig",
|
84
84
|
"UnfoldConfig",
|
85
85
|
# Services
|
86
86
|
"EmailConfig",
|
@@ -54,8 +54,8 @@ class SpectacularConfig(BaseModel):
|
|
54
54
|
description="Post-processing hooks"
|
55
55
|
)
|
56
56
|
|
57
|
-
# NOTE: Enum generation settings are handled by django-
|
58
|
-
# Only override if you need different values than
|
57
|
+
# NOTE: Enum generation settings are handled by django-client (OpenAPI)
|
58
|
+
# Only override if you need different values than django-client defaults
|
59
59
|
|
60
60
|
# Enum overrides
|
61
61
|
enum_name_overrides: Dict[str, str] = Field(
|
@@ -69,7 +69,7 @@ class SpectacularConfig(BaseModel):
|
|
69
69
|
"""
|
70
70
|
Get django-cfg Spectacular extensions.
|
71
71
|
|
72
|
-
NOTE: This extends
|
72
|
+
NOTE: This extends django-client's base settings, not replaces them.
|
73
73
|
Only include settings that are unique to django-cfg or critical fixes.
|
74
74
|
|
75
75
|
Args:
|
@@ -77,13 +77,13 @@ class SpectacularConfig(BaseModel):
|
|
77
77
|
"""
|
78
78
|
settings = {
|
79
79
|
# django-cfg specific UI enhancements
|
80
|
-
"REDOC_UI_SETTINGS": self.redoc_ui_settings.to_dict(), #
|
80
|
+
"REDOC_UI_SETTINGS": self.redoc_ui_settings.to_dict(), # django-client doesn't have custom Redoc settings
|
81
81
|
|
82
82
|
# django-cfg specific processing extensions
|
83
83
|
"ENUM_NAME_OVERRIDES": self.enum_name_overrides, # Custom enum overrides
|
84
84
|
|
85
|
-
# CRITICAL: Ensure enum generation is always enabled (fix
|
86
|
-
# These settings ensure proper enum generation even if
|
85
|
+
# CRITICAL: Ensure enum generation is always enabled (fix django-client gaps)
|
86
|
+
# These settings ensure proper enum generation even if django-client config changes
|
87
87
|
"GENERATE_ENUM_FROM_CHOICES": True,
|
88
88
|
"ENUM_GENERATE_CHOICE_FROM_PATH": True,
|
89
89
|
"ENUM_NAME_SUFFIX": "Enum",
|
@@ -6,11 +6,11 @@ Django integrations and extensions.
|
|
6
6
|
|
7
7
|
from .environment import EnvironmentConfig
|
8
8
|
from .constance import ConstanceConfig, ConstanceField
|
9
|
-
from .
|
9
|
+
from .openapi import OpenAPIClientConfig
|
10
10
|
|
11
11
|
__all__ = [
|
12
12
|
"EnvironmentConfig",
|
13
13
|
"ConstanceConfig",
|
14
14
|
"ConstanceField",
|
15
|
-
"
|
15
|
+
"OpenAPIClientConfig",
|
16
16
|
]
|
@@ -0,0 +1,162 @@
|
|
1
|
+
"""
|
2
|
+
Django Client (OpenAPI) Configuration with DRF Integration
|
3
|
+
|
4
|
+
Extended configuration model that integrates openapi_client for automatic
|
5
|
+
TypeScript and Python client generation from Django REST Framework endpoints.
|
6
|
+
|
7
|
+
This replaces django-revolution with a cleaner, faster, type-safe implementation.
|
8
|
+
"""
|
9
|
+
|
10
|
+
from typing import Dict, Any, Optional
|
11
|
+
from pydantic import Field
|
12
|
+
from django_cfg.modules.django_client.core.config import OpenAPIConfig, OpenAPIGroupConfig
|
13
|
+
|
14
|
+
|
15
|
+
class OpenAPIClientConfig(OpenAPIConfig):
|
16
|
+
"""
|
17
|
+
Extended OpenAPI configuration with DRF parameters for django-cfg integration.
|
18
|
+
|
19
|
+
This extends the base OpenAPIConfig to include DRF-specific
|
20
|
+
parameters and django-cfg integration helpers.
|
21
|
+
|
22
|
+
Example:
|
23
|
+
```python
|
24
|
+
from django_cfg import OpenAPIClientConfig, OpenAPIGroupConfig
|
25
|
+
|
26
|
+
config = OpenAPIClientConfig(
|
27
|
+
enabled=True,
|
28
|
+
groups=[
|
29
|
+
OpenAPIGroupConfig(
|
30
|
+
name='api',
|
31
|
+
apps=['users', 'posts'],
|
32
|
+
title='Main API',
|
33
|
+
version='v1',
|
34
|
+
),
|
35
|
+
],
|
36
|
+
drf_title='My API',
|
37
|
+
drf_description='REST API for my project',
|
38
|
+
)
|
39
|
+
```
|
40
|
+
"""
|
41
|
+
|
42
|
+
# DRF Configuration parameters for automatic DRF setup
|
43
|
+
drf_title: str = Field(
|
44
|
+
default="API",
|
45
|
+
description="API title for DRF Spectacular"
|
46
|
+
)
|
47
|
+
drf_description: str = Field(
|
48
|
+
default="RESTful API",
|
49
|
+
description="API description for DRF Spectacular"
|
50
|
+
)
|
51
|
+
drf_version: str = Field(
|
52
|
+
default="1.0.0",
|
53
|
+
description="API version for DRF Spectacular"
|
54
|
+
)
|
55
|
+
drf_schema_path_prefix: Optional[str] = Field(
|
56
|
+
default=None, # Will default to "/api/" if None
|
57
|
+
description="Schema path prefix for DRF Spectacular"
|
58
|
+
)
|
59
|
+
drf_enable_browsable_api: bool = Field(
|
60
|
+
default=False,
|
61
|
+
description="Enable DRF browsable API"
|
62
|
+
)
|
63
|
+
drf_enable_throttling: bool = Field(
|
64
|
+
default=False,
|
65
|
+
description="Enable DRF throttling"
|
66
|
+
)
|
67
|
+
drf_serve_include_schema: bool = Field(
|
68
|
+
default=False,
|
69
|
+
description="Include schema in Spectacular UI"
|
70
|
+
)
|
71
|
+
|
72
|
+
# Django-cfg specific integration
|
73
|
+
api_prefix: str = Field(
|
74
|
+
default="api",
|
75
|
+
description="API prefix for URL routing (e.g., 'api' -> /api/...)"
|
76
|
+
)
|
77
|
+
|
78
|
+
def get_drf_schema_path_prefix(self) -> str:
|
79
|
+
"""Get the schema path prefix, defaulting to api_prefix if not set."""
|
80
|
+
if self.drf_schema_path_prefix:
|
81
|
+
return self.drf_schema_path_prefix
|
82
|
+
return f"/{self.api_prefix}/"
|
83
|
+
|
84
|
+
def get_drf_config_kwargs(self) -> Dict[str, Any]:
|
85
|
+
"""
|
86
|
+
Get kwargs for DRF configuration from this config.
|
87
|
+
|
88
|
+
Returns:
|
89
|
+
Dict of parameters for DRF + Spectacular setup
|
90
|
+
"""
|
91
|
+
return {
|
92
|
+
"title": self.drf_title,
|
93
|
+
"description": self.drf_description,
|
94
|
+
"version": self.drf_version,
|
95
|
+
"schema_path_prefix": self.get_drf_schema_path_prefix(),
|
96
|
+
"enable_browsable_api": self.drf_enable_browsable_api,
|
97
|
+
"enable_throttling": self.drf_enable_throttling,
|
98
|
+
"serve_include_schema": self.drf_serve_include_schema,
|
99
|
+
# REQUIRED by django-client for correct Request/Response split
|
100
|
+
"component_split_request": True,
|
101
|
+
"component_split_patch": True,
|
102
|
+
}
|
103
|
+
|
104
|
+
def get_groups_with_defaults(self) -> Dict[str, OpenAPIGroupConfig]:
|
105
|
+
"""
|
106
|
+
Get groups with django-cfg default groups automatically added.
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
Dict of groups including default django-cfg groups
|
110
|
+
"""
|
111
|
+
# Convert list to dict for compatibility
|
112
|
+
groups_dict = {group.name: group for group in self.groups}
|
113
|
+
|
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
|
+
return groups_dict
|
157
|
+
|
158
|
+
except Exception:
|
159
|
+
pass
|
160
|
+
|
161
|
+
return groups_dict
|
162
|
+
|