coding-client 1.21.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. coding_client/__init__.py +1 -0
  2. coding_client/api/__init__.py +19 -0
  3. coding_client/api/exception_handlers.py +158 -0
  4. coding_client/api/logging_setup.py +44 -0
  5. coding_client/api/metrics.py +40 -0
  6. coding_client/api/openapi_config.py +124 -0
  7. coding_client/api/request_logging.py +60 -0
  8. coding_client/api/validation.py +150 -0
  9. coding_client/auth/__init__.py +78 -0
  10. coding_client/auth/_default_tenant.py +132 -0
  11. coding_client/auth/_header_trust.py +98 -0
  12. coding_client/auth/_onbehalf.py +315 -0
  13. coding_client/auth/_trusted_networks.py +94 -0
  14. coding_client/auth/dependencies.py +61 -0
  15. coding_client/auth/middleware.py +445 -0
  16. coding_client/auth/models.py +83 -0
  17. coding_client/auth/outbound.py +137 -0
  18. coding_client/auth/rbac.py +21 -0
  19. coding_client/auth/rbac_coding.py +5 -0
  20. coding_client/auth/tenant.py +650 -0
  21. coding_client/auth/websocket.py +148 -0
  22. coding_client/clients/__init__.py +24 -0
  23. coding_client/clients/base.py +131 -0
  24. coding_client/clients/coding_ai.py +33 -0
  25. coding_client/clients/coding_analysis.py +36 -0
  26. coding_client/clients/coding_containers.py +45 -0
  27. coding_client/clients/coding_github.py +127 -0
  28. coding_client/clients/coding_realtime.py +127 -0
  29. coding_client/clients/coding_security.py +51 -0
  30. coding_client/clients/coding_testing.py +31 -0
  31. coding_client/clients/coding_workspaces.py +265 -0
  32. coding_client/config/__init__.py +12 -0
  33. coding_client/config/base_settings.py +61 -0
  34. coding_client/config/yaml_config_loader.py +172 -0
  35. coding_client/db/__init__.py +42 -0
  36. coding_client/db/db_types.py +122 -0
  37. coding_client/db/exceptions.py +59 -0
  38. coding_client/db/postgres_connection.py +572 -0
  39. coding_client/db/tenant_query_helper.py +417 -0
  40. coding_client/db_init.py +49 -0
  41. coding_client/exceptions/__init__.py +67 -0
  42. coding_client/exceptions/api_exceptions.py +395 -0
  43. coding_client/exceptions/pydantic_ai_exceptions.py +533 -0
  44. coding_client/interfaces/__init__.py +22 -0
  45. coding_client/interfaces/cache_interface.py +179 -0
  46. coding_client/interfaces/container_interface.py +49 -0
  47. coding_client/interfaces/docker_interface.py +283 -0
  48. coding_client/interfaces/graph_interface.py +28 -0
  49. coding_client/interfaces/security_interface.py +72 -0
  50. coding_client/interfaces/webhook_interface.py +67 -0
  51. coding_client/llm/__init__.py +54 -0
  52. coding_client/llm/base_agent.py +195 -0
  53. coding_client/llm/context.py +121 -0
  54. coding_client/llm/responses.py +102 -0
  55. coding_client/llm/routing.py +82 -0
  56. coding_client/llm/settings.py +102 -0
  57. coding_client/models/__init__.py +62 -0
  58. coding_client/models/agent.py +38 -0
  59. coding_client/models/ai_test_failure.py +745 -0
  60. coding_client/models/analysis.py +330 -0
  61. coding_client/models/architecture.py +685 -0
  62. coding_client/models/bug.py +128 -0
  63. coding_client/models/code_graph.py +317 -0
  64. coding_client/models/container.py +241 -0
  65. coding_client/models/core.py +878 -0
  66. coding_client/models/docker_container.py +104 -0
  67. coding_client/models/github.py +293 -0
  68. coding_client/models/logging.py +29 -0
  69. coding_client/models/package_manager.py +257 -0
  70. coding_client/models/pr_validation.py +440 -0
  71. coding_client/models/pydantic_ai.py +395 -0
  72. coding_client/models/repo_scanner.py +249 -0
  73. coding_client/models/responses.py +431 -0
  74. coding_client/models/security.py +185 -0
  75. coding_client/models/static_analysis.py +508 -0
  76. coding_client/models/system.py +48 -0
  77. coding_client/models/test_executor.py +204 -0
  78. coding_client/models/testing.py +673 -0
  79. coding_client/models/testing_config.py +200 -0
  80. coding_client/models/validation.py +127 -0
  81. coding_client/models_init.py +272 -0
  82. coding_client/telemetry.py +195 -0
  83. coding_client/testing.py +180 -0
  84. coding_client/types/__init__.py +130 -0
  85. coding_client/types/constraint_types.py +276 -0
  86. coding_client/types/core_types.py +112 -0
  87. coding_client/types/state_machine.py +443 -0
  88. coding_client/utils/__init__.py +86 -0
  89. coding_client/utils/archive_utils.py +387 -0
  90. coding_client/utils/ast_debug.py +45 -0
  91. coding_client/utils/async_timeout.py +364 -0
  92. coding_client/utils/constants.py +518 -0
  93. coding_client/utils/content_processing.py +326 -0
  94. coding_client/utils/database.py +916 -0
  95. coding_client/utils/encoding_helper.py +222 -0
  96. coding_client/utils/enum_helpers.py +166 -0
  97. coding_client/utils/file_operations.py +177 -0
  98. coding_client/utils/filesystem_ops.py +528 -0
  99. coding_client/utils/http_client.py +562 -0
  100. coding_client/utils/path_utils.py +471 -0
  101. coding_client/utils/profiling.py +421 -0
  102. coding_client/utils/response_builder.py +240 -0
  103. coding_client/utils/retry_helper.py +712 -0
  104. coding_client/utils/security_validation.py +423 -0
  105. coding_client-1.21.2.dist-info/METADATA +234 -0
  106. coding_client-1.21.2.dist-info/RECORD +109 -0
  107. coding_client-1.21.2.dist-info/WHEEL +5 -0
  108. coding_client-1.21.2.dist-info/licenses/LICENSE +201 -0
  109. coding_client-1.21.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,395 @@
1
+ """PydanticAI models for intelligent test failure analysis."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from datetime import UTC, datetime
7
+ from enum import StrEnum
8
+ from typing import Any
9
+
10
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class PydanticAIAnalysisType(StrEnum):
16
+ """Types of test failure analysis."""
17
+
18
+ FAILURE_ANALYSIS = "failure_analysis"
19
+ CODE_QUALITY = "code_quality"
20
+ PERFORMANCE = "performance"
21
+ SECURITY = "security"
22
+ DEPENDENCY = "dependency"
23
+ RACE_CONDITION = "race_condition"
24
+ MEMORY_LEAK = "memory_leak"
25
+ TIMEOUT = "timeout"
26
+ COMPILATION_ERROR = "compilation_error"
27
+ RUNTIME_ERROR = "runtime_error"
28
+
29
+
30
+ class FailureSeverity(StrEnum):
31
+ """Severity levels for test failures."""
32
+
33
+ CRITICAL = "critical"
34
+ HIGH = "high"
35
+ MEDIUM = "medium"
36
+ LOW = "low"
37
+ INFO = "info"
38
+
39
+
40
+ class FailureCategory(StrEnum):
41
+ """Categories of test failures."""
42
+
43
+ SYNTAX_ERROR = "syntax_error"
44
+ TYPE_ERROR = "type_error"
45
+ LOGIC_ERROR = "logic_error"
46
+ RUNTIME_ERROR = "runtime_error"
47
+ ASSERTION_ERROR = "assertion_error"
48
+ TIMEOUT_ERROR = "timeout_error"
49
+ MEMORY_ERROR = "memory_error"
50
+ DEPENDENCY_ERROR = "dependency_error"
51
+ CONFIGURATION_ERROR = "configuration_error"
52
+ ENVIRONMENT_ERROR = "environment_error"
53
+ UNKNOWN = "unknown"
54
+
55
+
56
+ class PydanticAITestFailureContext(BaseModel):
57
+ """Context information for test failure analysis."""
58
+
59
+ model_config = ConfigDict(
60
+ str_strip_whitespace=True,
61
+ validate_assignment=True,
62
+ extra="forbid",
63
+ frozen=False,
64
+ )
65
+
66
+ test_id: str = Field(..., description="Unique test execution ID")
67
+ language: str = Field(..., description="Programming language being tested")
68
+ test_type: str = Field(..., description="Type of test (unit, integration, etc.)")
69
+ exit_code: int = Field(..., description="Test process exit code")
70
+ stdout: str = Field(default="", description="Standard output from test execution")
71
+ stderr: str = Field(default="", description="Standard error from test execution")
72
+ execution_time_ms: float = Field(..., description="Test execution time in milliseconds")
73
+ container_name: str | None = Field(None, description="Container name where test ran")
74
+ source_code: str | None = Field(None, description="Source code being tested")
75
+ test_code: str | None = Field(None, description="Test code that failed")
76
+ dependencies: dict[str, str] = Field(default_factory=dict, description="Project dependencies")
77
+ environment: dict[str, str] = Field(default_factory=dict, description="Environment variables")
78
+ resource_usage: dict[str, Any] | None = Field(None, description="Resource usage during test")
79
+ created_at: datetime = Field(
80
+ default_factory=lambda: datetime.now(UTC),
81
+ description="When context was created",
82
+ )
83
+
84
+ @field_validator("execution_time_ms")
85
+ @classmethod
86
+ def validate_execution_time(cls, v: float) -> float:
87
+ """Validate execution time is non-negative."""
88
+ if v < 0:
89
+ raise ValueError("Execution time cannot be negative")
90
+ return v
91
+
92
+ @field_validator("exit_code")
93
+ @classmethod
94
+ def validate_exit_code(cls, v: int) -> int:
95
+ """Validate exit code is reasonable."""
96
+ if v < 0 or v > 255:
97
+ logger.warning(f"Unusual exit code: {v}")
98
+ return v
99
+
100
+
101
+ class FailureAnalysisResult(BaseModel):
102
+ """Result of intelligent test failure analysis."""
103
+
104
+ model_config = ConfigDict(
105
+ str_strip_whitespace=True,
106
+ validate_assignment=True,
107
+ extra="forbid",
108
+ frozen=False,
109
+ protected_namespaces=(),
110
+ )
111
+
112
+ analysis_id: str = Field(..., description="Unique analysis result ID")
113
+ test_id: str = Field(..., description="Test ID that was analyzed")
114
+ analysis_type: PydanticAIAnalysisType = Field(..., description="Type of analysis performed")
115
+ category: FailureCategory = Field(..., description="Category of failure")
116
+ severity: FailureSeverity = Field(..., description="Severity of the failure")
117
+ confidence: float = Field(..., ge=0.0, le=1.0, description="Confidence in analysis (0-1)")
118
+ root_cause: str = Field(..., description="Identified root cause of failure")
119
+ symptoms: list[str] = Field(default_factory=list, description="Observable symptoms")
120
+ potential_causes: list[str] = Field(
121
+ default_factory=list, description="Potential causes considered"
122
+ )
123
+ recommendations: list[str] = Field(default_factory=list, description="Recommended actions")
124
+ code_fixes: list[str] = Field(default_factory=list, description="Suggested code fixes")
125
+ related_issues: list[str] = Field(
126
+ default_factory=list, description="Related issues or patterns"
127
+ )
128
+ analysis_duration_ms: float = Field(..., description="Time taken for analysis")
129
+ ai_model_provider: str = Field(..., description="AI model provider used")
130
+ ai_model_name: str = Field(..., description="Specific model used for analysis")
131
+ raw_response: str | None = Field(None, description="Raw AI response for debugging")
132
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
133
+ created_at: datetime = Field(
134
+ default_factory=lambda: datetime.now(UTC),
135
+ description="When analysis was completed",
136
+ )
137
+
138
+ @field_validator("confidence")
139
+ @classmethod
140
+ def validate_confidence(cls, v: float) -> float:
141
+ """Validate confidence is between 0 and 1."""
142
+ if not 0.0 <= v <= 1.0:
143
+ raise ValueError("Confidence must be between 0.0 and 1.0")
144
+ return v
145
+
146
+
147
+ class CodeQualityIssue(BaseModel):
148
+ """Code quality issue identified during analysis."""
149
+
150
+ model_config = ConfigDict(
151
+ str_strip_whitespace=True,
152
+ validate_assignment=True,
153
+ extra="forbid",
154
+ frozen=False,
155
+ )
156
+
157
+ issue_id: str = Field(..., description="Unique issue identifier")
158
+ category: str = Field(..., description="Issue category (style, bug, performance, etc.)")
159
+ severity: FailureSeverity = Field(..., description="Issue severity")
160
+ message: str = Field(..., description="Issue description")
161
+ file_path: str | None = Field(None, description="File where issue was found")
162
+ line_number: int | None = Field(None, description="Line number of issue")
163
+ column_number: int | None = Field(None, description="Column number of issue")
164
+ code_snippet: str | None = Field(None, description="Code snippet showing issue")
165
+ suggested_fix: str | None = Field(None, description="Suggested fix for issue")
166
+ fix_confidence: float | None = Field(None, ge=0.0, le=1.0, description="Confidence in fix")
167
+ rule_id: str | None = Field(None, description="Rule ID that triggered issue")
168
+ tool_name: str | None = Field(None, description="Tool that detected issue")
169
+
170
+ @field_validator("line_number")
171
+ @classmethod
172
+ def validate_line_number(cls, v: int | None) -> int | None:
173
+ """Validate line number is positive."""
174
+ if v is not None and v <= 0:
175
+ raise ValueError("Line number must be positive")
176
+ return v
177
+
178
+
179
+ class PerformanceAnalysis(BaseModel):
180
+ """Performance analysis results."""
181
+
182
+ model_config = ConfigDict(
183
+ str_strip_whitespace=True,
184
+ validate_assignment=True,
185
+ extra="forbid",
186
+ frozen=False,
187
+ )
188
+
189
+ analysis_id: str = Field(..., description="Unique analysis identifier")
190
+ execution_time_ms: float = Field(..., description="Execution time in milliseconds")
191
+ memory_usage_mb: float | None = Field(None, description="Memory usage in MB")
192
+ cpu_usage_percent: float | None = Field(None, description="CPU usage percentage")
193
+ bottlenecks: list[str] = Field(default_factory=list, description="Identified bottlenecks")
194
+ optimization_suggestions: list[str] = Field(
195
+ default_factory=list, description="Optimization suggestions"
196
+ )
197
+ performance_score: float | None = Field(
198
+ None, ge=0.0, le=10.0, description="Performance score (0-10)"
199
+ )
200
+ baseline_comparison: dict[str, Any] | None = Field(None, description="Comparison with baseline")
201
+
202
+ @field_validator("performance_score")
203
+ @classmethod
204
+ def validate_performance_score(cls, v: float | None) -> float | None:
205
+ """Validate performance score is between 0 and 10."""
206
+ if v is not None and not 0.0 <= v <= 10.0:
207
+ raise ValueError("Performance score must be between 0.0 and 10.0")
208
+ return v
209
+
210
+
211
+ class SecurityAnalysis(BaseModel):
212
+ """Security analysis results."""
213
+
214
+ model_config = ConfigDict(
215
+ str_strip_whitespace=True,
216
+ validate_assignment=True,
217
+ extra="forbid",
218
+ frozen=False,
219
+ )
220
+
221
+ analysis_id: str = Field(..., description="Unique analysis identifier")
222
+ vulnerabilities: list[str] = Field(
223
+ default_factory=list, description="Identified vulnerabilities"
224
+ )
225
+ security_score: float | None = Field(None, ge=0.0, le=10.0, description="Security score (0-10)")
226
+ risk_level: FailureSeverity = Field(..., description="Overall risk level")
227
+ recommendations: list[str] = Field(default_factory=list, description="Security recommendations")
228
+ cve_references: list[str] = Field(default_factory=list, description="Related CVE references")
229
+ compliance_issues: list[str] = Field(default_factory=list, description="Compliance issues")
230
+
231
+ @field_validator("security_score")
232
+ @classmethod
233
+ def validate_security_score(cls, v: float | None) -> float | None:
234
+ """Validate security score is between 0 and 10."""
235
+ if v is not None and not 0.0 <= v <= 10.0:
236
+ raise ValueError("Security score must be between 0.0 and 10.0")
237
+ return v
238
+
239
+
240
+ class AIAnalysisRequest(BaseModel):
241
+ """Request for AI-powered test failure analysis."""
242
+
243
+ model_config = ConfigDict(
244
+ str_strip_whitespace=True,
245
+ validate_assignment=True,
246
+ extra="forbid",
247
+ frozen=False,
248
+ protected_namespaces=(),
249
+ )
250
+
251
+ context: PydanticAITestFailureContext = Field(..., description="Test failure context")
252
+ analysis_types: list[PydanticAIAnalysisType] = Field(
253
+ default_factory=list, description="Types of analysis to perform"
254
+ )
255
+ ai_model_provider: str = Field(default="openai", description="AI model provider to use")
256
+ ai_model_name: str = Field(default="gpt-4", description="Specific model to use")
257
+ max_tokens: int = Field(default=2000, description="Maximum tokens for AI response")
258
+ temperature: float = Field(default=0.1, ge=0.0, le=2.0, description="Model temperature")
259
+ timeout_seconds: int = Field(default=30, description="Request timeout in seconds")
260
+ include_code_fixes: bool = Field(default=True, description="Include code fix suggestions")
261
+ include_performance_analysis: bool = Field(
262
+ default=True, description="Include performance analysis"
263
+ )
264
+ include_security_analysis: bool = Field(default=True, description="Include security analysis")
265
+ metadata: dict[str, Any] = Field(
266
+ default_factory=dict, description="Additional request metadata"
267
+ )
268
+
269
+ @field_validator("temperature")
270
+ @classmethod
271
+ def validate_temperature(cls, v: float) -> float:
272
+ """Validate temperature is between 0 and 2."""
273
+ if not 0.0 <= v <= 2.0:
274
+ raise ValueError("Temperature must be between 0.0 and 2.0")
275
+ return v
276
+
277
+ @field_validator("max_tokens")
278
+ @classmethod
279
+ def validate_max_tokens(cls, v: int) -> int:
280
+ """Validate max tokens is reasonable."""
281
+ if v <= 0 or v > 32000:
282
+ raise ValueError("Max tokens must be between 1 and 32000")
283
+ return v
284
+
285
+
286
+ class AIAnalysisResponse(BaseModel):
287
+ """Response from AI-powered test failure analysis."""
288
+
289
+ model_config = ConfigDict(
290
+ str_strip_whitespace=True,
291
+ validate_assignment=True,
292
+ extra="forbid",
293
+ frozen=False,
294
+ protected_namespaces=(),
295
+ )
296
+
297
+ request_id: str = Field(..., description="Unique request identifier")
298
+ success: bool = Field(..., description="Whether analysis was successful")
299
+ failure_analysis: FailureAnalysisResult | None = Field(
300
+ None, description="Main failure analysis"
301
+ )
302
+ code_quality_issues: list[CodeQualityIssue] = Field(
303
+ default_factory=list, description="Code quality issues"
304
+ )
305
+ performance_analysis: PerformanceAnalysis | None = Field(
306
+ None, description="Performance analysis"
307
+ )
308
+ security_analysis: SecurityAnalysis | None = Field(None, description="Security analysis")
309
+ total_analysis_time_ms: float = Field(..., description="Total analysis time")
310
+ ai_model_usage: dict[str, Any] = Field(
311
+ default_factory=dict, description="Model usage statistics"
312
+ )
313
+ error_message: str | None = Field(None, description="Error message if analysis failed")
314
+ warnings: list[str] = Field(default_factory=list, description="Analysis warnings")
315
+ metadata: dict[str, Any] = Field(
316
+ default_factory=dict, description="Additional response metadata"
317
+ )
318
+ created_at: datetime = Field(
319
+ default_factory=lambda: datetime.now(UTC),
320
+ description="When response was created",
321
+ )
322
+
323
+
324
+ class AgentConfiguration(BaseModel):
325
+ """Configuration for PydanticAI agents."""
326
+
327
+ model_config = ConfigDict(
328
+ str_strip_whitespace=True,
329
+ validate_assignment=True,
330
+ extra="forbid",
331
+ frozen=False,
332
+ protected_namespaces=(),
333
+ )
334
+
335
+ agent_id: str = Field(..., description="Unique agent identifier")
336
+ ai_model_provider: str = Field(..., description="AI model provider")
337
+ ai_model_name: str = Field(..., description="Model name")
338
+ api_key: str | None = Field(None, description="API key for model provider")
339
+ base_url: str | None = Field(None, description="Base URL for API")
340
+ max_retries: int = Field(default=3, description="Maximum retry attempts")
341
+ timeout_seconds: int = Field(default=30, description="Request timeout")
342
+ rate_limit_rpm: int = Field(default=100, description="Rate limit requests per minute")
343
+ rate_limit_tpm: int = Field(default=10000, description="Rate limit tokens per minute")
344
+ temperature: float = Field(default=0.1, ge=0.0, le=2.0, description="Model temperature")
345
+ max_tokens: int = Field(default=2000, description="Maximum tokens per request")
346
+ system_prompt: str | None = Field(None, description="System prompt for agent")
347
+ enabled: bool = Field(default=True, description="Whether agent is enabled")
348
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional configuration")
349
+
350
+ @field_validator("temperature")
351
+ @classmethod
352
+ def validate_temperature(cls, v: float) -> float:
353
+ """Validate temperature is between 0 and 2."""
354
+ if not 0.0 <= v <= 2.0:
355
+ raise ValueError("Temperature must be between 0.0 and 2.0")
356
+ return v
357
+
358
+
359
+ class AgentMetrics(BaseModel):
360
+ """Metrics for PydanticAI agent performance."""
361
+
362
+ model_config = ConfigDict(
363
+ str_strip_whitespace=True,
364
+ validate_assignment=True,
365
+ extra="forbid",
366
+ frozen=False,
367
+ )
368
+
369
+ agent_id: str = Field(..., description="Agent identifier")
370
+ total_requests: int = Field(default=0, description="Total requests processed")
371
+ successful_requests: int = Field(default=0, description="Successful requests")
372
+ failed_requests: int = Field(default=0, description="Failed requests")
373
+ average_response_time_ms: float = Field(default=0.0, description="Average response time")
374
+ total_tokens_used: int = Field(default=0, description="Total tokens used")
375
+ total_cost_usd: float = Field(default=0.0, description="Total cost in USD")
376
+ last_request_at: datetime | None = Field(None, description="Last request timestamp")
377
+ error_rate: float = Field(default=0.0, description="Error rate (0-1)")
378
+ uptime_percent: float = Field(default=100.0, description="Uptime percentage")
379
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metrics")
380
+
381
+ @field_validator("error_rate")
382
+ @classmethod
383
+ def validate_error_rate(cls, v: float) -> float:
384
+ """Validate error rate is between 0 and 1."""
385
+ if not 0.0 <= v <= 1.0:
386
+ raise ValueError("Error rate must be between 0.0 and 1.0")
387
+ return v
388
+
389
+ @field_validator("uptime_percent")
390
+ @classmethod
391
+ def validate_uptime_percent(cls, v: float) -> float:
392
+ """Validate uptime percentage is between 0 and 100."""
393
+ if not 0.0 <= v <= 100.0:
394
+ raise ValueError("Uptime percentage must be between 0.0 and 100.0")
395
+ return v
@@ -0,0 +1,249 @@
1
+ """Repository scanner models for comprehensive code analysis operations.
2
+
3
+ This module provides data models for the repository scanning and analysis API endpoint,
4
+ supporting various types of code analysis including dependency scanning, import analysis,
5
+ and code validation. The models ensure consistent request/response structures for
6
+ comprehensive code analysis operations in containerized environments.
7
+
8
+ The repository scanner supports:
9
+ - Dependency analysis with validation and security checking
10
+ - Import statement analysis and resolution
11
+ - Code validation across multiple file types
12
+ - Full repository scanning with configurable options
13
+ - Detailed error reporting and issue tracking
14
+
15
+ Key Model Categories:
16
+ Request Models: ScanRequest with configurable action types and options
17
+ Response Models: Specialized responses for different scan types
18
+ Data Models: DependencyValidation, ImportInfo, ValidationError for scan results
19
+ Union Types: ScanResponseUnion for type-safe response handling
20
+
21
+ Scan Types:
22
+ - DEPENDENCIES: Analyze package dependencies and versions
23
+ - IMPORTS: Scan import statements and module usage
24
+ - VALIDATION: Validate code syntax and structure
25
+ - FULL_SCAN: Comprehensive analysis combining all scan types
26
+
27
+ Example:
28
+ ```python
29
+ from repo_scanner_models import RepoScannerScanRequest, RepoScanAction, RepoScannerDependencyScanResponse
30
+
31
+ # Create scan request
32
+ request = RepoScannerScanRequest(
33
+ container_name="my-analysis-container",
34
+ action=RepoScanAction.DEPENDENCIES,
35
+ target_files=["src/main.py", "app/models.py"],
36
+ options={"include_dev_dependencies": True}
37
+ )
38
+
39
+ # Process scan response
40
+ response = RepoScannerDependencyScanResponse(
41
+ container_name="my-analysis-container",
42
+ action="dependencies",
43
+ scan_duration=2.5,
44
+ file_count=15,
45
+ request_id="scan-123",
46
+ dependencies=[
47
+ DependencyValidation(
48
+ name="fastapi",
49
+ version="0.104.1",
50
+ source="pip",
51
+ valid=True
52
+ )
53
+ ],
54
+ dependency_count=42,
55
+ invalid_dependencies=[]
56
+ )
57
+ ```
58
+ """
59
+
60
+ from __future__ import annotations
61
+
62
+ from enum import StrEnum
63
+ from typing import Any
64
+
65
+ from pydantic import BaseModel, Field
66
+
67
+ from .responses import LegacyBaseResponse
68
+
69
+ # ================================================================================================
70
+ # REQUEST MODELS
71
+ # ================================================================================================
72
+
73
+
74
+ class RepoScanAction(StrEnum):
75
+ """Available scan action types."""
76
+
77
+ DEPENDENCIES = "dependencies"
78
+ IMPORTS = "imports"
79
+ VALIDATION = "validation"
80
+ FULL_SCAN = "full_scan"
81
+
82
+
83
+ class RepoScannerScanRequest(BaseModel):
84
+ """Request model for repository scanning operations."""
85
+
86
+ container_name: str = Field(
87
+ description="Name of the Docker container to scan",
88
+ examples=["my-repo-container-123"],
89
+ )
90
+
91
+ action: RepoScanAction = Field(
92
+ description="Type of scan to perform",
93
+ examples=[RepoScanAction.DEPENDENCIES],
94
+ )
95
+
96
+ target_files: list[str] | None = Field(
97
+ default=None,
98
+ description="Specific files to scan (optional, defaults to all Python files)",
99
+ examples=[["src/main.py", "app/models.py"]],
100
+ )
101
+
102
+ options: dict[str, Any] | None = Field(
103
+ default=None,
104
+ description="Additional scan options and parameters",
105
+ examples=[{"max_files": 100, "include_tests": True}],
106
+ )
107
+
108
+
109
+ # ================================================================================================
110
+ # RESPONSE MODELS
111
+ # ================================================================================================
112
+
113
+
114
+ class DependencyValidation(BaseModel):
115
+ """Information about a single dependency."""
116
+
117
+ name: str = Field(description="Package name", examples=["fastapi"])
118
+ version: str = Field(description="Package version", examples=["0.104.1"])
119
+ source: str = Field(description="Source of dependency info", examples=["pip"])
120
+ valid: bool = Field(description="Whether the dependency is valid", examples=[True])
121
+
122
+
123
+ class RepoScannerImportInfo(BaseModel):
124
+ """Information about a single import statement."""
125
+
126
+ type: str = Field(description="Type of import", examples=["from_import"])
127
+ module: str = Field(description="Module name", examples=["fastapi"])
128
+ name: str = Field(description="Imported name", examples=["FastAPI"])
129
+ alias: str | None = Field(default=None, description="Import alias", examples=["app"])
130
+ file: str = Field(description="File containing the import", examples=["src/main.py"])
131
+ line: int = Field(description="Line number", examples=[1])
132
+
133
+
134
+ class ScannerValidationError(BaseModel):
135
+ """Code validation error information."""
136
+
137
+ type: str = Field(..., description="Error type", examples=["SyntaxError"])
138
+ message: str = Field(..., description="Error message", examples=["invalid syntax"])
139
+ line: int | None = Field(None, description="Line number", examples=[10])
140
+ offset: int | None = Field(None, description="Character offset", examples=[5])
141
+
142
+
143
+ class ValidationWarning(BaseModel):
144
+ """Code validation warning information."""
145
+
146
+ type: str = Field(..., description="Warning type", examples=["LongLine"])
147
+ message: str = Field(
148
+ ...,
149
+ description="Warning message",
150
+ examples=["Line too long (130 characters)"],
151
+ )
152
+ line: int = Field(..., description="Line number", examples=[15])
153
+
154
+
155
+ class RepoScannerValidationResult(BaseModel):
156
+ """Validation result for a single file."""
157
+
158
+ file: str = Field(description="File path", examples=["src/main.py"])
159
+ valid: bool = Field(description="Whether the file is valid", examples=[True])
160
+ syntax_valid: bool | None = Field(
161
+ default=None, description="Whether syntax is valid", examples=[True]
162
+ )
163
+ errors: list[ScannerValidationError] = Field(default=[], description="Validation errors")
164
+ warnings: list[ValidationWarning] = Field(default=[], description="Validation warnings")
165
+ line_count: int = Field(description="Number of lines in file", examples=[150])
166
+
167
+
168
+ class BaseScanResponse(LegacyBaseResponse):
169
+ """Base response model for all scan operations."""
170
+
171
+ container_name: str = Field(description="Container name that was scanned")
172
+ action: str = Field(description="Type of scan performed")
173
+ scan_duration: float = Field(description="Scan duration in seconds", examples=[2.5])
174
+ file_count: int = Field(description="Number of files processed", examples=[25])
175
+ request_id: str = Field(description="Unique request identifier")
176
+
177
+
178
+ class RepoScannerDependencyScanResponse(BaseScanResponse):
179
+ """Response model for dependency scan operations."""
180
+
181
+ dependencies: list[DependencyValidation] = Field(
182
+ default=[], description="List of discovered dependencies"
183
+ )
184
+
185
+ dependency_count: int = Field(description="Total number of dependencies found", examples=[42])
186
+
187
+ invalid_dependencies: list[dict[str, Any]] = Field(
188
+ default=[], description="List of invalid or problematic dependencies"
189
+ )
190
+
191
+
192
+ class RepoScannerImportScanResponse(BaseScanResponse):
193
+ """Response model for import scan operations."""
194
+
195
+ imports: list[RepoScannerImportInfo] = Field(
196
+ default=[], description="List of discovered import statements"
197
+ )
198
+
199
+ import_count: int = Field(description="Total number of imports found", examples=[156])
200
+
201
+ invalid_imports: list[dict[str, Any]] = Field(
202
+ default=[], description="List of invalid or problematic imports"
203
+ )
204
+
205
+
206
+ class RepoScannerValidationScanResponse(BaseScanResponse):
207
+ """Response model for code validation operations."""
208
+
209
+ validation_results: list[RepoScannerValidationResult] = Field(
210
+ default=[], description="Detailed validation results for each file"
211
+ )
212
+
213
+ valid_files: int = Field(..., description="Number of valid files", examples=[20])
214
+
215
+ invalid_files: int = Field(..., description="Number of invalid files", examples=[2])
216
+
217
+
218
+ class RepoScannerScanResponse(BaseScanResponse):
219
+ """Response model for full scan operations."""
220
+
221
+ results: dict[str, Any] = Field(
222
+ ...,
223
+ description="Combined results from all scan types",
224
+ examples=[
225
+ {
226
+ "dependencies": {"dependency_count": 42, "dependencies": []},
227
+ "imports": {"import_count": 156, "imports": []},
228
+ "validation": {"valid_files": 20, "invalid_files": 2},
229
+ "summary": {
230
+ "total_dependencies": 42,
231
+ "total_imports": 156,
232
+ "valid_files": 20,
233
+ "invalid_files": 2,
234
+ },
235
+ }
236
+ ],
237
+ )
238
+
239
+
240
+ # ================================================================================================
241
+ # UNION RESPONSE TYPE
242
+ # ================================================================================================
243
+
244
+ ScanResponseUnion = (
245
+ RepoScannerDependencyScanResponse
246
+ | RepoScannerImportScanResponse
247
+ | RepoScannerValidationScanResponse
248
+ | RepoScannerScanResponse
249
+ )