django-cfg 1.3.9__py3-none-any.whl → 1.3.11__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 (187) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/payments/admin/networks_admin.py +12 -1
  3. django_cfg/apps/payments/admin/payments_admin.py +13 -0
  4. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +62 -14
  5. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  6. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  7. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  8. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  9. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  10. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  11. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  12. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +33 -3
  13. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  14. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +96 -45
  15. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  16. django_cfg/apps/payments/config/__init__.py +14 -15
  17. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  18. django_cfg/apps/payments/config/helpers.py +8 -13
  19. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  20. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  21. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  22. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  23. django_cfg/apps/payments/models/payments.py +94 -0
  24. django_cfg/apps/payments/services/core/base.py +4 -4
  25. django_cfg/apps/payments/services/core/payment_service.py +265 -38
  26. django_cfg/apps/payments/services/providers/base.py +209 -3
  27. django_cfg/apps/payments/services/providers/models/__init__.py +2 -0
  28. django_cfg/apps/payments/services/providers/models/base.py +25 -2
  29. django_cfg/apps/payments/services/providers/nowpayments/models.py +2 -2
  30. django_cfg/apps/payments/services/providers/nowpayments/provider.py +57 -9
  31. django_cfg/apps/payments/services/providers/registry.py +5 -5
  32. django_cfg/apps/payments/services/types/requests.py +19 -7
  33. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  34. django_cfg/apps/payments/static/payments/js/api-client.js +6 -1
  35. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  36. django_cfg/apps/payments/static/payments/js/payment-form.js +35 -26
  37. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  38. django_cfg/apps/payments/urls.py +3 -2
  39. django_cfg/apps/payments/views/api/currencies.py +3 -0
  40. django_cfg/apps/payments/views/serializers/currencies.py +18 -5
  41. django_cfg/apps/tasks/admin/tasks_admin.py +2 -2
  42. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  43. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  44. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  45. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  46. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  47. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  48. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  49. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  50. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  51. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  52. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  53. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  54. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  55. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  56. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  57. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  58. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  59. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  60. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  61. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  62. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  63. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  64. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  65. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  66. django_cfg/apps/tasks/urls.py +2 -2
  67. django_cfg/apps/tasks/urls_admin.py +2 -2
  68. django_cfg/apps/tasks/utils/__init__.py +1 -0
  69. django_cfg/apps/tasks/utils/simulator.py +356 -0
  70. django_cfg/apps/tasks/views/__init__.py +16 -0
  71. django_cfg/apps/tasks/views/api.py +569 -0
  72. django_cfg/apps/tasks/views/dashboard.py +58 -0
  73. django_cfg/core/integration/__init__.py +21 -0
  74. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  75. django_cfg/models/constance.py +0 -11
  76. django_cfg/models/payments.py +137 -3
  77. django_cfg/modules/django_tasks.py +54 -21
  78. django_cfg/registry/core.py +4 -9
  79. django_cfg/template_archive/django_sample.zip +0 -0
  80. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -2
  81. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/RECORD +84 -152
  82. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  83. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  84. django_cfg/apps/payments/config/constance/fields.py +0 -69
  85. django_cfg/apps/payments/config/constance/settings.py +0 -160
  86. django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +0 -26
  87. django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +0 -28
  88. django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +0 -30
  89. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  90. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  91. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  92. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  93. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  94. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  95. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  96. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  97. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  98. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  99. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  100. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  101. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  102. django_cfg/apps/tasks/views.py +0 -461
  103. django_cfg/management/commands/app_agent_diagnose.py +0 -470
  104. django_cfg/management/commands/app_agent_generate.py +0 -342
  105. django_cfg/management/commands/app_agent_info.py +0 -308
  106. django_cfg/management/commands/auto_generate.py +0 -486
  107. django_cfg/modules/django_app_agent/__init__.py +0 -87
  108. django_cfg/modules/django_app_agent/agents/__init__.py +0 -40
  109. django_cfg/modules/django_app_agent/agents/base/__init__.py +0 -24
  110. django_cfg/modules/django_app_agent/agents/base/agent.py +0 -354
  111. django_cfg/modules/django_app_agent/agents/base/context.py +0 -236
  112. django_cfg/modules/django_app_agent/agents/base/executor.py +0 -430
  113. django_cfg/modules/django_app_agent/agents/generation/__init__.py +0 -12
  114. django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +0 -15
  115. django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +0 -147
  116. django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +0 -99
  117. django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +0 -32
  118. django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +0 -290
  119. django_cfg/modules/django_app_agent/agents/interfaces.py +0 -376
  120. django_cfg/modules/django_app_agent/core/__init__.py +0 -33
  121. django_cfg/modules/django_app_agent/core/config.py +0 -300
  122. django_cfg/modules/django_app_agent/core/exceptions.py +0 -359
  123. django_cfg/modules/django_app_agent/models/__init__.py +0 -71
  124. django_cfg/modules/django_app_agent/models/base.py +0 -283
  125. django_cfg/modules/django_app_agent/models/context.py +0 -496
  126. django_cfg/modules/django_app_agent/models/enums.py +0 -481
  127. django_cfg/modules/django_app_agent/models/requests.py +0 -500
  128. django_cfg/modules/django_app_agent/models/responses.py +0 -585
  129. django_cfg/modules/django_app_agent/pytest.ini +0 -6
  130. django_cfg/modules/django_app_agent/services/__init__.py +0 -42
  131. django_cfg/modules/django_app_agent/services/app_generator/__init__.py +0 -30
  132. django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +0 -133
  133. django_cfg/modules/django_app_agent/services/app_generator/context.py +0 -40
  134. django_cfg/modules/django_app_agent/services/app_generator/main.py +0 -202
  135. django_cfg/modules/django_app_agent/services/app_generator/structure.py +0 -316
  136. django_cfg/modules/django_app_agent/services/app_generator/validation.py +0 -125
  137. django_cfg/modules/django_app_agent/services/base.py +0 -437
  138. django_cfg/modules/django_app_agent/services/context_builder/__init__.py +0 -34
  139. django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +0 -141
  140. django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +0 -276
  141. django_cfg/modules/django_app_agent/services/context_builder/main.py +0 -272
  142. django_cfg/modules/django_app_agent/services/context_builder/models.py +0 -40
  143. django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +0 -85
  144. django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +0 -31
  145. django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +0 -311
  146. django_cfg/modules/django_app_agent/services/project_scanner/main.py +0 -221
  147. django_cfg/modules/django_app_agent/services/project_scanner/models.py +0 -59
  148. django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +0 -94
  149. django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +0 -28
  150. django_cfg/modules/django_app_agent/services/questioning_service/main.py +0 -273
  151. django_cfg/modules/django_app_agent/services/questioning_service/models.py +0 -111
  152. django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +0 -251
  153. django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +0 -347
  154. django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +0 -356
  155. django_cfg/modules/django_app_agent/services/report_service.py +0 -332
  156. django_cfg/modules/django_app_agent/services/template_manager/__init__.py +0 -18
  157. django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +0 -236
  158. django_cfg/modules/django_app_agent/services/template_manager/main.py +0 -159
  159. django_cfg/modules/django_app_agent/services/template_manager/models.py +0 -36
  160. django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +0 -100
  161. django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +0 -105
  162. django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +0 -31
  163. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +0 -44
  164. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +0 -81
  165. django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +0 -107
  166. django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +0 -139
  167. django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +0 -91
  168. django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +0 -195
  169. django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +0 -35
  170. django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +0 -211
  171. django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +0 -200
  172. django_cfg/modules/django_app_agent/services/validation_service/__init__.py +0 -25
  173. django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +0 -333
  174. django_cfg/modules/django_app_agent/services/validation_service/main.py +0 -242
  175. django_cfg/modules/django_app_agent/services/validation_service/models.py +0 -66
  176. django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +0 -352
  177. django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +0 -272
  178. django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +0 -203
  179. django_cfg/modules/django_app_agent/ui/__init__.py +0 -25
  180. django_cfg/modules/django_app_agent/ui/cli.py +0 -419
  181. django_cfg/modules/django_app_agent/ui/rich_components.py +0 -622
  182. django_cfg/modules/django_app_agent/utils/__init__.py +0 -38
  183. django_cfg/modules/django_app_agent/utils/logging.py +0 -360
  184. django_cfg/modules/django_app_agent/utils/validation.py +0 -417
  185. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  186. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  187. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.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"])