django-cfg 1.3.9__py3-none-any.whl → 1.3.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 (188) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/inlines.py +11 -5
  3. django_cfg/apps/payments/admin/networks_admin.py +12 -1
  4. django_cfg/apps/payments/admin/payments_admin.py +13 -0
  5. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +62 -14
  6. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  7. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  8. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  9. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  10. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  11. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  12. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  13. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +33 -3
  14. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  15. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +96 -45
  16. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  17. django_cfg/apps/payments/config/__init__.py +14 -15
  18. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  19. django_cfg/apps/payments/config/helpers.py +8 -13
  20. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  21. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  22. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  23. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  24. django_cfg/apps/payments/models/payments.py +94 -0
  25. django_cfg/apps/payments/services/core/base.py +4 -4
  26. django_cfg/apps/payments/services/core/payment_service.py +265 -38
  27. django_cfg/apps/payments/services/providers/base.py +209 -3
  28. django_cfg/apps/payments/services/providers/models/__init__.py +2 -0
  29. django_cfg/apps/payments/services/providers/models/base.py +25 -2
  30. django_cfg/apps/payments/services/providers/nowpayments/models.py +2 -2
  31. django_cfg/apps/payments/services/providers/nowpayments/provider.py +57 -9
  32. django_cfg/apps/payments/services/providers/registry.py +5 -5
  33. django_cfg/apps/payments/services/types/requests.py +19 -7
  34. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  35. django_cfg/apps/payments/static/payments/js/api-client.js +6 -1
  36. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  37. django_cfg/apps/payments/static/payments/js/payment-form.js +35 -26
  38. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  39. django_cfg/apps/payments/urls.py +3 -2
  40. django_cfg/apps/payments/views/api/currencies.py +3 -0
  41. django_cfg/apps/payments/views/serializers/currencies.py +18 -5
  42. django_cfg/apps/tasks/admin/tasks_admin.py +2 -2
  43. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  44. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  45. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  46. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  47. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  48. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  49. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  50. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  51. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  52. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  53. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  54. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  55. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  56. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  57. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  58. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  59. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  60. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  61. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  62. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  63. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  64. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  65. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  66. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  67. django_cfg/apps/tasks/urls.py +2 -2
  68. django_cfg/apps/tasks/urls_admin.py +2 -2
  69. django_cfg/apps/tasks/utils/__init__.py +1 -0
  70. django_cfg/apps/tasks/utils/simulator.py +356 -0
  71. django_cfg/apps/tasks/views/__init__.py +16 -0
  72. django_cfg/apps/tasks/views/api.py +569 -0
  73. django_cfg/apps/tasks/views/dashboard.py +58 -0
  74. django_cfg/core/integration/__init__.py +21 -0
  75. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  76. django_cfg/models/constance.py +0 -11
  77. django_cfg/models/payments.py +137 -3
  78. django_cfg/modules/django_tasks.py +54 -21
  79. django_cfg/registry/core.py +4 -9
  80. django_cfg/template_archive/django_sample.zip +0 -0
  81. {django_cfg-1.3.9.dist-info → django_cfg-1.3.13.dist-info}/METADATA +2 -2
  82. {django_cfg-1.3.9.dist-info → django_cfg-1.3.13.dist-info}/RECORD +85 -153
  83. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  84. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  85. django_cfg/apps/payments/config/constance/fields.py +0 -69
  86. django_cfg/apps/payments/config/constance/settings.py +0 -160
  87. django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +0 -26
  88. django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +0 -28
  89. django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +0 -30
  90. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  91. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  92. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  93. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  94. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  95. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  96. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  97. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  98. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  99. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  100. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  101. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  102. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  103. django_cfg/apps/tasks/views.py +0 -461
  104. django_cfg/management/commands/app_agent_diagnose.py +0 -470
  105. django_cfg/management/commands/app_agent_generate.py +0 -342
  106. django_cfg/management/commands/app_agent_info.py +0 -308
  107. django_cfg/management/commands/auto_generate.py +0 -486
  108. django_cfg/modules/django_app_agent/__init__.py +0 -87
  109. django_cfg/modules/django_app_agent/agents/__init__.py +0 -40
  110. django_cfg/modules/django_app_agent/agents/base/__init__.py +0 -24
  111. django_cfg/modules/django_app_agent/agents/base/agent.py +0 -354
  112. django_cfg/modules/django_app_agent/agents/base/context.py +0 -236
  113. django_cfg/modules/django_app_agent/agents/base/executor.py +0 -430
  114. django_cfg/modules/django_app_agent/agents/generation/__init__.py +0 -12
  115. django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +0 -15
  116. django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +0 -147
  117. django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +0 -99
  118. django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +0 -32
  119. django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +0 -290
  120. django_cfg/modules/django_app_agent/agents/interfaces.py +0 -376
  121. django_cfg/modules/django_app_agent/core/__init__.py +0 -33
  122. django_cfg/modules/django_app_agent/core/config.py +0 -300
  123. django_cfg/modules/django_app_agent/core/exceptions.py +0 -359
  124. django_cfg/modules/django_app_agent/models/__init__.py +0 -71
  125. django_cfg/modules/django_app_agent/models/base.py +0 -283
  126. django_cfg/modules/django_app_agent/models/context.py +0 -496
  127. django_cfg/modules/django_app_agent/models/enums.py +0 -481
  128. django_cfg/modules/django_app_agent/models/requests.py +0 -500
  129. django_cfg/modules/django_app_agent/models/responses.py +0 -585
  130. django_cfg/modules/django_app_agent/pytest.ini +0 -6
  131. django_cfg/modules/django_app_agent/services/__init__.py +0 -42
  132. django_cfg/modules/django_app_agent/services/app_generator/__init__.py +0 -30
  133. django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +0 -133
  134. django_cfg/modules/django_app_agent/services/app_generator/context.py +0 -40
  135. django_cfg/modules/django_app_agent/services/app_generator/main.py +0 -202
  136. django_cfg/modules/django_app_agent/services/app_generator/structure.py +0 -316
  137. django_cfg/modules/django_app_agent/services/app_generator/validation.py +0 -125
  138. django_cfg/modules/django_app_agent/services/base.py +0 -437
  139. django_cfg/modules/django_app_agent/services/context_builder/__init__.py +0 -34
  140. django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +0 -141
  141. django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +0 -276
  142. django_cfg/modules/django_app_agent/services/context_builder/main.py +0 -272
  143. django_cfg/modules/django_app_agent/services/context_builder/models.py +0 -40
  144. django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +0 -85
  145. django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +0 -31
  146. django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +0 -311
  147. django_cfg/modules/django_app_agent/services/project_scanner/main.py +0 -221
  148. django_cfg/modules/django_app_agent/services/project_scanner/models.py +0 -59
  149. django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +0 -94
  150. django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +0 -28
  151. django_cfg/modules/django_app_agent/services/questioning_service/main.py +0 -273
  152. django_cfg/modules/django_app_agent/services/questioning_service/models.py +0 -111
  153. django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +0 -251
  154. django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +0 -347
  155. django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +0 -356
  156. django_cfg/modules/django_app_agent/services/report_service.py +0 -332
  157. django_cfg/modules/django_app_agent/services/template_manager/__init__.py +0 -18
  158. django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +0 -236
  159. django_cfg/modules/django_app_agent/services/template_manager/main.py +0 -159
  160. django_cfg/modules/django_app_agent/services/template_manager/models.py +0 -36
  161. django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +0 -100
  162. django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +0 -105
  163. django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +0 -31
  164. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +0 -44
  165. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +0 -81
  166. django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +0 -107
  167. django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +0 -139
  168. django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +0 -91
  169. django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +0 -195
  170. django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +0 -35
  171. django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +0 -211
  172. django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +0 -200
  173. django_cfg/modules/django_app_agent/services/validation_service/__init__.py +0 -25
  174. django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +0 -333
  175. django_cfg/modules/django_app_agent/services/validation_service/main.py +0 -242
  176. django_cfg/modules/django_app_agent/services/validation_service/models.py +0 -66
  177. django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +0 -352
  178. django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +0 -272
  179. django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +0 -203
  180. django_cfg/modules/django_app_agent/ui/__init__.py +0 -25
  181. django_cfg/modules/django_app_agent/ui/cli.py +0 -419
  182. django_cfg/modules/django_app_agent/ui/rich_components.py +0 -622
  183. django_cfg/modules/django_app_agent/utils/__init__.py +0 -38
  184. django_cfg/modules/django_app_agent/utils/logging.py +0 -360
  185. django_cfg/modules/django_app_agent/utils/validation.py +0 -417
  186. {django_cfg-1.3.9.dist-info → django_cfg-1.3.13.dist-info}/WHEEL +0 -0
  187. {django_cfg-1.3.9.dist-info → django_cfg-1.3.13.dist-info}/entry_points.txt +0 -0
  188. {django_cfg-1.3.9.dist-info → django_cfg-1.3.13.dist-info}/licenses/LICENSE +0 -0
@@ -1,333 +0,0 @@
1
- """
2
- Django Best Practices Validator.
3
-
4
- This module validates Django-specific patterns, conventions,
5
- and best practices in generated code.
6
- """
7
-
8
- from typing import List, Dict, Any, Optional
9
- import ast
10
- import re
11
-
12
- from pydantic import BaseModel, Field
13
-
14
- from ...models.responses import GeneratedFile
15
- from ..base import ServiceDependencies
16
- from .models import ValidationIssue
17
-
18
-
19
- class DjangoValidator(BaseModel):
20
- """Validates Django best practices and conventions."""
21
-
22
- django_rules: Dict[str, Dict[str, Any]] = Field(
23
- default_factory=lambda: {
24
- "model_meta_class": {
25
- "description": "Models should have proper Meta class",
26
- "severity": "warning"
27
- },
28
- "model_string_representation": {
29
- "description": "Models should have __str__ method",
30
- "severity": "warning"
31
- },
32
- "admin_registration": {
33
- "description": "Admin classes should be properly registered",
34
- "severity": "info"
35
- },
36
- "url_naming": {
37
- "description": "URL patterns should have names",
38
- "severity": "warning"
39
- },
40
- "view_docstrings": {
41
- "description": "Views should have docstrings",
42
- "severity": "info"
43
- },
44
- "form_validation": {
45
- "description": "Forms should have proper validation",
46
- "severity": "warning"
47
- }
48
- },
49
- description="Django validation rules"
50
- )
51
-
52
- async def validate_django_practices(
53
- self,
54
- file: GeneratedFile,
55
- dependencies: ServiceDependencies
56
- ) -> List[ValidationIssue]:
57
- """Validate Django best practices for a single file."""
58
- issues = []
59
-
60
- if file.file_type != "python":
61
- return issues
62
-
63
- try:
64
- tree = ast.parse(file.content)
65
-
66
- # Determine file type and apply appropriate validations
67
- if "models.py" in file.path:
68
- issues.extend(self._validate_models(file, tree, dependencies))
69
- elif "admin.py" in file.path:
70
- issues.extend(self._validate_admin(file, tree, dependencies))
71
- elif "views.py" in file.path:
72
- issues.extend(self._validate_views(file, tree, dependencies))
73
- elif "urls.py" in file.path:
74
- issues.extend(self._validate_urls(file, tree, dependencies))
75
- elif "forms.py" in file.path:
76
- issues.extend(self._validate_forms(file, tree, dependencies))
77
- elif "serializers.py" in file.path:
78
- issues.extend(self._validate_serializers(file, tree, dependencies))
79
-
80
- except SyntaxError:
81
- # Skip Django validation if syntax is invalid
82
- pass
83
- except Exception as e:
84
- dependencies.log_error(f"Django validation failed for {file.path}", e)
85
-
86
- return issues
87
-
88
- def _validate_models(
89
- self,
90
- file: GeneratedFile,
91
- tree: ast.AST,
92
- dependencies: ServiceDependencies
93
- ) -> List[ValidationIssue]:
94
- """Validate Django model best practices."""
95
- issues = []
96
-
97
- for node in ast.walk(tree):
98
- if isinstance(node, ast.ClassDef):
99
- # Check if it's a model class
100
- is_model = any(
101
- isinstance(base, ast.Attribute) and
102
- isinstance(base.value, ast.Name) and
103
- base.value.id == "models" and
104
- base.attr == "Model"
105
- for base in node.bases
106
- ) or any(
107
- isinstance(base, ast.Name) and
108
- "Model" in base.id
109
- for base in node.bases
110
- )
111
-
112
- if is_model:
113
- issues.extend(self._check_model_class(file, node))
114
-
115
- return issues
116
-
117
- def _check_model_class(
118
- self,
119
- file: GeneratedFile,
120
- node: ast.ClassDef
121
- ) -> List[ValidationIssue]:
122
- """Check individual model class for best practices."""
123
- issues = []
124
-
125
- # Check for __str__ method
126
- has_str_method = any(
127
- isinstance(item, ast.FunctionDef) and item.name == "__str__"
128
- for item in node.body
129
- )
130
-
131
- if not has_str_method:
132
- issues.append(ValidationIssue(
133
- severity="warning",
134
- category="django",
135
- message=f"Model '{node.name}' should have a __str__ method",
136
- file_path=file.path,
137
- line_number=node.lineno,
138
- rule_id="model_str_method",
139
- suggestion=f"Add a __str__ method to {node.name} that returns a meaningful string representation"
140
- ))
141
-
142
- # Check for Meta class
143
- has_meta_class = any(
144
- isinstance(item, ast.ClassDef) and item.name == "Meta"
145
- for item in node.body
146
- )
147
-
148
- if not has_meta_class:
149
- issues.append(ValidationIssue(
150
- severity="info",
151
- category="django",
152
- message=f"Model '{node.name}' could benefit from a Meta class",
153
- file_path=file.path,
154
- line_number=node.lineno,
155
- rule_id="model_meta_class",
156
- suggestion=f"Consider adding a Meta class to {node.name} for verbose_name, ordering, etc."
157
- ))
158
-
159
- return issues
160
-
161
- def _validate_admin(
162
- self,
163
- file: GeneratedFile,
164
- tree: ast.AST,
165
- dependencies: ServiceDependencies
166
- ) -> List[ValidationIssue]:
167
- """Validate Django admin best practices."""
168
- issues = []
169
-
170
- # Check for admin registrations
171
- has_registrations = False
172
-
173
- for node in ast.walk(tree):
174
- if isinstance(node, ast.Call):
175
- # Check for admin.site.register() calls
176
- if (isinstance(node.func, ast.Attribute) and
177
- isinstance(node.func.value, ast.Attribute) and
178
- isinstance(node.func.value.value, ast.Name) and
179
- node.func.value.value.id == "admin" and
180
- node.func.value.attr == "site" and
181
- node.func.attr == "register"):
182
- has_registrations = True
183
- elif isinstance(node, ast.FunctionDef):
184
- # Check for @admin.register decorator
185
- for decorator in node.decorator_list:
186
- if (isinstance(decorator, ast.Call) and
187
- isinstance(decorator.func, ast.Attribute) and
188
- isinstance(decorator.func.value, ast.Name) and
189
- decorator.func.value.id == "admin" and
190
- decorator.func.attr == "register"):
191
- has_registrations = True
192
-
193
- if not has_registrations:
194
- issues.append(ValidationIssue(
195
- severity="info",
196
- category="django",
197
- message="No admin registrations found",
198
- file_path=file.path,
199
- line_number=1,
200
- rule_id="admin_registration",
201
- suggestion="Register models with admin.site.register() or @admin.register decorator"
202
- ))
203
-
204
- return issues
205
-
206
- def _validate_views(
207
- self,
208
- file: GeneratedFile,
209
- tree: ast.AST,
210
- dependencies: ServiceDependencies
211
- ) -> List[ValidationIssue]:
212
- """Validate Django view best practices."""
213
- issues = []
214
-
215
- for node in ast.walk(tree):
216
- if isinstance(node, (ast.FunctionDef, ast.ClassDef)):
217
- # Check for docstrings
218
- if not ast.get_docstring(node):
219
- issues.append(ValidationIssue(
220
- severity="info",
221
- category="django",
222
- message=f"View '{node.name}' should have a docstring",
223
- file_path=file.path,
224
- line_number=node.lineno,
225
- rule_id="view_docstring",
226
- suggestion=f"Add a docstring to {node.name} explaining its purpose"
227
- ))
228
-
229
- return issues
230
-
231
- def _validate_urls(
232
- self,
233
- file: GeneratedFile,
234
- tree: ast.AST,
235
- dependencies: ServiceDependencies
236
- ) -> List[ValidationIssue]:
237
- """Validate Django URL patterns best practices."""
238
- issues = []
239
-
240
- # Check for named URL patterns
241
- content = file.content
242
- path_patterns = re.findall(r'path\([^)]+\)', content)
243
-
244
- for pattern in path_patterns:
245
- if 'name=' not in pattern:
246
- issues.append(ValidationIssue(
247
- severity="warning",
248
- category="django",
249
- message="URL pattern should have a name",
250
- file_path=file.path,
251
- line_number=1, # Would need more sophisticated line tracking
252
- rule_id="url_naming",
253
- suggestion="Add name='...' parameter to path() for reverse URL lookup"
254
- ))
255
-
256
- return issues
257
-
258
- def _validate_forms(
259
- self,
260
- file: GeneratedFile,
261
- tree: ast.AST,
262
- dependencies: ServiceDependencies
263
- ) -> List[ValidationIssue]:
264
- """Validate Django form best practices."""
265
- issues = []
266
-
267
- for node in ast.walk(tree):
268
- if isinstance(node, ast.ClassDef):
269
- # Check if it's a form class
270
- is_form = any(
271
- isinstance(base, ast.Attribute) and
272
- base.attr in ["Form", "ModelForm"]
273
- for base in node.bases
274
- )
275
-
276
- if is_form:
277
- # Check for clean methods
278
- has_clean_methods = any(
279
- isinstance(item, ast.FunctionDef) and
280
- (item.name.startswith("clean_") or item.name == "clean")
281
- for item in node.body
282
- )
283
-
284
- if not has_clean_methods:
285
- issues.append(ValidationIssue(
286
- severity="info",
287
- category="django",
288
- message=f"Form '{node.name}' could benefit from validation methods",
289
- file_path=file.path,
290
- line_number=node.lineno,
291
- rule_id="form_validation",
292
- suggestion=f"Consider adding clean_* methods to {node.name} for field validation"
293
- ))
294
-
295
- return issues
296
-
297
- def _validate_serializers(
298
- self,
299
- file: GeneratedFile,
300
- tree: ast.AST,
301
- dependencies: ServiceDependencies
302
- ) -> List[ValidationIssue]:
303
- """Validate DRF serializer best practices."""
304
- issues = []
305
-
306
- for node in ast.walk(tree):
307
- if isinstance(node, ast.ClassDef):
308
- # Check if it's a serializer class
309
- is_serializer = any(
310
- isinstance(base, ast.Attribute) and
311
- "Serializer" in base.attr
312
- for base in node.bases
313
- )
314
-
315
- if is_serializer:
316
- # Check for Meta class in ModelSerializer
317
- has_meta = any(
318
- isinstance(item, ast.ClassDef) and item.name == "Meta"
319
- for item in node.body
320
- )
321
-
322
- if "ModelSerializer" in str(node.bases) and not has_meta:
323
- issues.append(ValidationIssue(
324
- severity="warning",
325
- category="django",
326
- message=f"ModelSerializer '{node.name}' should have a Meta class",
327
- file_path=file.path,
328
- line_number=node.lineno,
329
- rule_id="serializer_meta",
330
- suggestion=f"Add Meta class to {node.name} with model and fields"
331
- ))
332
-
333
- return issues
@@ -1,242 +0,0 @@
1
- """
2
- Main Validation Service for Django App Agent Module.
3
-
4
- This service orchestrates comprehensive code validation including
5
- syntax, Django best practices, security, and quality analysis.
6
- """
7
-
8
- from typing import List, Dict, Any, Optional
9
- import asyncio
10
-
11
- from pydantic import BaseModel, Field
12
-
13
- from ...core.config import AgentConfig
14
- from ...models.responses import GeneratedFile, QualityMetrics
15
- from ..base import BaseService, ServiceDependencies
16
- from .models import ValidationRequest, ValidationResult, ValidationIssue
17
- from .syntax_validator import SyntaxValidator
18
- from .django_validator import DjangoValidator
19
- from .security_validator import SecurityValidator
20
- from .quality_validator import QualityValidator
21
-
22
-
23
- class ValidationService(BaseService[ValidationRequest, ValidationResult]):
24
- """
25
- Comprehensive code validation and quality analysis service.
26
-
27
- Provides validation for:
28
- - Python syntax and AST analysis
29
- - Django best practices and conventions
30
- - Security vulnerabilities and patterns
31
- - Code quality metrics and standards
32
- - Performance considerations
33
- - Type hint completeness
34
- """
35
-
36
- def __init__(self, config: AgentConfig):
37
- """Initialize validation service."""
38
- super().__init__("validation", config)
39
- self.config = config
40
-
41
- # Initialize validators
42
- self.syntax_validator = SyntaxValidator()
43
- self.django_validator = DjangoValidator()
44
- self.security_validator = SecurityValidator()
45
- self.quality_validator = QualityValidator()
46
-
47
- async def process(
48
- self,
49
- request: ValidationRequest,
50
- dependencies: ServiceDependencies
51
- ) -> ValidationResult:
52
- """
53
- Process comprehensive code validation.
54
-
55
- Args:
56
- request: Validation request with files and rules
57
- dependencies: Service dependencies
58
-
59
- Returns:
60
- ValidationResult with issues and quality metrics
61
- """
62
- dependencies.log_operation(
63
- "Starting code validation",
64
- files_count=len(request.files),
65
- validation_rules=request.validation_rules,
66
- strict_mode=request.strict_mode
67
- )
68
-
69
- all_issues = []
70
-
71
- try:
72
- # Validate each file
73
- for file in request.files:
74
- file_issues = await self._validate_file(file, request, dependencies)
75
- all_issues.extend(file_issues)
76
-
77
- # Calculate quality metrics
78
- quality_metrics = await self.quality_validator.calculate_quality_metrics(
79
- request.files, dependencies
80
- )
81
-
82
- # Determine if validation passed
83
- error_count = len([issue for issue in all_issues if issue.severity == "error"])
84
- is_valid = error_count == 0 or not request.strict_mode
85
-
86
- # Create summary
87
- summary = self._create_validation_summary(all_issues, quality_metrics)
88
-
89
- result = ValidationResult(
90
- is_valid=is_valid,
91
- quality_metrics=quality_metrics,
92
- issues=all_issues,
93
- summary=summary
94
- )
95
-
96
- dependencies.log_operation(
97
- "Validation completed",
98
- is_valid=is_valid,
99
- total_issues=len(all_issues),
100
- error_count=error_count,
101
- warning_count=result.warning_count,
102
- info_count=result.info_count,
103
- overall_quality_score=quality_metrics.overall_score
104
- )
105
-
106
- return result
107
-
108
- except Exception as e:
109
- dependencies.log_error("Validation process failed", e)
110
- raise
111
-
112
- async def _validate_file(
113
- self,
114
- file: GeneratedFile,
115
- request: ValidationRequest,
116
- dependencies: ServiceDependencies
117
- ) -> List[ValidationIssue]:
118
- """Validate a single file with all applicable validators."""
119
- issues = []
120
-
121
- dependencies.log_operation(f"Validating file: {file.path}")
122
-
123
- # Run validators based on requested rules
124
- validation_tasks = []
125
-
126
- if "syntax" in request.validation_rules:
127
- validation_tasks.append(
128
- self.syntax_validator.validate_syntax(file, dependencies)
129
- )
130
-
131
- if "django_best_practices" in request.validation_rules:
132
- validation_tasks.append(
133
- self.django_validator.validate_django_practices(file, dependencies)
134
- )
135
-
136
- if "security" in request.validation_rules:
137
- validation_tasks.append(
138
- self.security_validator.validate_security(file, dependencies)
139
- )
140
-
141
- if "quality" in request.validation_rules:
142
- validation_tasks.append(
143
- self.quality_validator.validate_quality(file, dependencies)
144
- )
145
-
146
- # Run all validations concurrently
147
- if validation_tasks:
148
- validation_results = await asyncio.gather(*validation_tasks, return_exceptions=True)
149
-
150
- for result in validation_results:
151
- if isinstance(result, Exception):
152
- dependencies.log_error(f"Validator failed for {file.path}", result)
153
- issues.append(ValidationIssue(
154
- severity="error",
155
- category="validation",
156
- message=f"Validation failed: {result}",
157
- file_path=file.path,
158
- line_number=1,
159
- rule_id="validation_error"
160
- ))
161
- else:
162
- issues.extend(result)
163
-
164
- return issues
165
-
166
- def _create_validation_summary(
167
- self,
168
- issues: List[ValidationIssue],
169
- quality_metrics: QualityMetrics
170
- ) -> Dict[str, Any]:
171
- """Create validation summary statistics."""
172
- # Group issues by category and severity
173
- by_category = {}
174
- by_severity = {"error": 0, "warning": 0, "info": 0}
175
-
176
- for issue in issues:
177
- # Count by category
178
- if issue.category not in by_category:
179
- by_category[issue.category] = 0
180
- by_category[issue.category] += 1
181
-
182
- # Count by severity
183
- if issue.severity in by_severity:
184
- by_severity[issue.severity] += 1
185
-
186
- # Calculate pass rates
187
- total_checks = len(issues) if issues else 1
188
- error_rate = by_severity["error"] / total_checks * 100
189
- warning_rate = by_severity["warning"] / total_checks * 100
190
-
191
- return {
192
- "total_issues": len(issues),
193
- "issues_by_severity": by_severity,
194
- "issues_by_category": by_category,
195
- "error_rate_percentage": error_rate,
196
- "warning_rate_percentage": warning_rate,
197
- "quality_score": quality_metrics.overall_score,
198
- "type_safety_score": quality_metrics.type_safety_score,
199
- "documentation_coverage": quality_metrics.documentation_coverage,
200
- "maintainability_score": quality_metrics.maintainability_score,
201
- "recommendations": self._generate_recommendations(issues, quality_metrics)
202
- }
203
-
204
- def _generate_recommendations(
205
- self,
206
- issues: List[ValidationIssue],
207
- quality_metrics: QualityMetrics
208
- ) -> List[str]:
209
- """Generate actionable recommendations based on validation results."""
210
- recommendations = []
211
-
212
- # Analyze issue patterns
213
- error_count = len([i for i in issues if i.severity == "error"])
214
- warning_count = len([i for i in issues if i.severity == "warning"])
215
-
216
- if error_count > 0:
217
- recommendations.append(f"Fix {error_count} critical error(s) before deployment")
218
-
219
- if warning_count > 5:
220
- recommendations.append(f"Address {warning_count} warning(s) to improve code quality")
221
-
222
- # Quality-based recommendations
223
- if quality_metrics.type_safety_score < 7.0:
224
- recommendations.append("Add type hints to improve type safety")
225
-
226
- if quality_metrics.documentation_coverage < 6.0:
227
- recommendations.append("Add docstrings to classes and functions")
228
-
229
- if quality_metrics.code_complexity > 7.0:
230
- recommendations.append("Reduce code complexity by breaking down large functions")
231
-
232
- # Security recommendations
233
- security_issues = [i for i in issues if i.category == "security"]
234
- if security_issues:
235
- recommendations.append("Review and address security-related issues")
236
-
237
- # Django-specific recommendations
238
- django_issues = [i for i in issues if i.category == "django"]
239
- if len(django_issues) > 3:
240
- recommendations.append("Follow Django best practices more consistently")
241
-
242
- return recommendations[:5] # Limit to top 5 recommendations
@@ -1,66 +0,0 @@
1
- """
2
- Data Models for Validation Service.
3
-
4
- This module defines the data structures used by the validation service
5
- for requests, responses, and validation issues.
6
- """
7
-
8
- from typing import List, Dict, Any, Optional
9
- from pydantic import BaseModel, Field, ConfigDict
10
-
11
- from ...models.responses import QualityMetrics, GeneratedFile
12
-
13
-
14
- class ValidationRequest(BaseModel):
15
- """Request for code validation."""
16
-
17
- model_config = ConfigDict(extra='forbid', validate_assignment=True)
18
-
19
- files: List[GeneratedFile] = Field(description="Files to validate")
20
- validation_rules: List[str] = Field(
21
- default_factory=lambda: ["syntax", "django_best_practices", "security", "quality"],
22
- description="Validation rules to apply"
23
- )
24
- strict_mode: bool = Field(default=False, description="Whether to use strict validation")
25
- custom_rules: Dict[str, Any] = Field(default_factory=dict, description="Custom validation rules")
26
-
27
-
28
- class ValidationIssue(BaseModel):
29
- """Represents a validation issue."""
30
-
31
- model_config = ConfigDict(extra='forbid', validate_assignment=True)
32
-
33
- severity: str = Field(description="Issue severity: error, warning, info")
34
- category: str = Field(description="Issue category: syntax, security, quality, etc.")
35
- message: str = Field(description="Issue description message")
36
- file_path: str = Field(description="Path to the file with the issue")
37
- line_number: Optional[int] = Field(default=None, description="Line number of the issue")
38
- column: Optional[int] = Field(default=None, description="Column number of the issue")
39
- rule_id: str = Field(default="", description="Validation rule identifier")
40
- suggestion: Optional[str] = Field(default=None, description="Suggested fix for the issue")
41
-
42
-
43
- class ValidationResult(BaseModel):
44
- """Result of code validation."""
45
-
46
- model_config = ConfigDict(extra='forbid', validate_assignment=True)
47
-
48
- is_valid: bool = Field(description="Whether the code passed validation")
49
- quality_metrics: QualityMetrics = Field(description="Calculated quality metrics")
50
- issues: List[ValidationIssue] = Field(default_factory=list, description="List of validation issues")
51
- summary: Dict[str, Any] = Field(default_factory=dict, description="Validation summary")
52
-
53
- @property
54
- def error_count(self) -> int:
55
- """Count of error-level issues."""
56
- return len([i for i in self.issues if i.severity == "error"])
57
-
58
- @property
59
- def warning_count(self) -> int:
60
- """Count of warning-level issues."""
61
- return len([i for i in self.issues if i.severity == "warning"])
62
-
63
- @property
64
- def info_count(self) -> int:
65
- """Count of info-level issues."""
66
- return len([i for i in self.issues if i.severity == "info"])