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,878 @@
1
+ """Core models for unified multi-language code analysis and entity representation.
2
+
3
+ This module provides the foundational data structures for code analysis, entities,
4
+ and relationships across all supported programming languages. It serves as the
5
+ central schema definition for the code graph helper system, supporting both
6
+ static analysis and dynamic runtime data.
7
+
8
+ The core models enable:
9
+ - Universal entity representation across programming languages
10
+ - Type-safe relationship modeling between code elements
11
+ - Comprehensive analysis result aggregation
12
+ - Multi-language code complexity measurement
13
+ - Security pattern detection and reporting
14
+
15
+ Key Model Categories:
16
+ Entity Models: CoreCodeEntity, EntityRelation for representing code structure
17
+ Analysis Models: CoreAnalysisResult, CoreFileAnalysisResult for analysis outcomes
18
+ Metrics Models: CoreComplexityMetrics, CodeSecurityPattern for code quality assessment
19
+ Request/Response Models: CodebaseAnalysisRequest, AnalysisResponse for API operations
20
+
21
+ Language Support:
22
+ - Python: Full AST analysis with type hints and decorators
23
+ - JavaScript/TypeScript: ES6+ features and type annotations
24
+ - Java: Classes, interfaces, and annotations
25
+ - C#: Properties, LINQ, and async/await patterns
26
+ - Go: Goroutines, channels, and interfaces
27
+ - Rust: Traits, lifetimes, and ownership patterns
28
+ - C++: Templates, namespaces, and STL containers
29
+
30
+ Example:
31
+ ```python
32
+ from core_models import CoreCodeEntity, EntityType, RelationType, EntityRelation
33
+
34
+ # Create a function entity
35
+ function = CoreCodeEntity(
36
+ id="func_123",
37
+ name="process_data",
38
+ type=EntityType.FUNCTION,
39
+ language="python",
40
+ file_path="src/processor.py",
41
+ line_number=42,
42
+ signature="def process_data(data: List[Dict]) -> Dict:",
43
+ return_type=TypeInfo(name="Dict", module="typing"),
44
+ visibility="public"
45
+ )
46
+
47
+ # Create a relationship
48
+ relation = EntityRelation(
49
+ source_id="module_main",
50
+ target_id="func_123",
51
+ type=RelationType.CALLS,
52
+ weight=0.8
53
+ )
54
+ ```
55
+ """
56
+
57
+ from __future__ import annotations
58
+
59
+ import logging
60
+ from datetime import UTC, datetime
61
+ from enum import StrEnum
62
+ from typing import Any
63
+
64
+ from pydantic import BaseModel, ConfigDict, Field
65
+ from typing_extensions import TypedDict # PEP 728 support for extra_items
66
+
67
+ # Configure logging
68
+ logger = logging.getLogger(__name__)
69
+
70
+
71
+ # TypedDict classes for structured type safety
72
+ class CodeEntityProperties(TypedDict, total=False):
73
+ """Type-safe structure for CoreCodeEntity properties with common language fields."""
74
+
75
+ # Core properties
76
+ decorators: list[str]
77
+ annotations: list[str]
78
+ access_modifiers: list[str]
79
+ language_specific: dict[str, Any]
80
+ is_constructor: bool
81
+ is_destructor: bool
82
+ is_property: bool
83
+ is_method: bool
84
+ is_field: bool
85
+ access_level: str
86
+ modifiers: list[str] | dict[str, Any] # Java uses dict, others use list
87
+ attributes: dict[str, Any]
88
+
89
+ # TypeScript/JavaScript specific
90
+ generic_parameters: list[str]
91
+ extends: str
92
+ implements: list[str]
93
+ is_exported: bool
94
+ type_kind: str
95
+ type_definition: str
96
+ is_union_type: bool
97
+ is_conditional_type: bool
98
+ is_mapped_type: bool
99
+ is_const_enum: bool
100
+ parameters: list[dict[str, Any]]
101
+ return_type: str
102
+ is_arrow_function: bool
103
+ module_path: str
104
+ import_path: str
105
+ type_safety_impact: dict[str, Any]
106
+
107
+ # Rust specific
108
+ is_public: bool
109
+ use_path: str
110
+ impl_type: str
111
+ trait_name: str
112
+ type_name: str
113
+ node_type: str
114
+
115
+ # Python specific
116
+ import_type: str
117
+ alias: str
118
+ module: str
119
+ name: str
120
+ bases: list[str]
121
+ arguments: list[str]
122
+
123
+ # Java specific
124
+ is_static: bool
125
+ is_wildcard: bool
126
+ package_name: str
127
+ file_path: str
128
+ is_constant: bool
129
+
130
+ # C# specific
131
+ namespace_name: str
132
+ using_directive: str
133
+ is_sealed: bool
134
+ interface_type: bool
135
+ is_readonly: bool
136
+ value_type: bool
137
+ enum_type: bool
138
+ is_virtual: bool
139
+ is_override: bool
140
+ property_type: str
141
+ field_type: str
142
+ is_const: bool
143
+
144
+ # Multi-language factory
145
+ file_size: int
146
+ file_extension: str
147
+ minimal_graph: bool
148
+ detected_version: str
149
+
150
+
151
+ class CodeEntityMetadata(TypedDict, total=False):
152
+ """Type-safe structure for CoreCodeEntity metadata."""
153
+
154
+ source_hash: str
155
+ last_modified: str
156
+ analysis_version: str
157
+ confidence_score: float
158
+ tags: list[str]
159
+ category: str
160
+ complexity_score: float
161
+ maintainability_index: float
162
+ test_coverage: float
163
+ documentation_coverage: float
164
+ legacy_fields: dict[str, Any]
165
+
166
+ # Additional analyzer fields
167
+ language: str
168
+ var_type: str
169
+
170
+
171
+ class RelationProperties(TypedDict, total=False):
172
+ """Type-safe structure for EntityRelation properties."""
173
+
174
+ weight: float
175
+ confidence: float
176
+ context: str
177
+ frequency: int
178
+ strength: float
179
+ call_count: int
180
+ import_style: str
181
+ access_pattern: str
182
+ dependency_type: str
183
+ metadata: dict[str, Any]
184
+
185
+ # TypeScript analyzer specific
186
+ coupling_strength: str
187
+ is_type_relationship: bool
188
+
189
+
190
+ class RelationMetadata(TypedDict, total=False):
191
+ """Type-safe structure for EntityRelation metadata."""
192
+
193
+ source_location: str
194
+ target_location: str
195
+ analysis_confidence: float
196
+ detected_by: str
197
+ verification_status: str
198
+ last_verified: str
199
+ flags: list[str]
200
+ tags: list[str]
201
+ legacy_fields: dict[str, Any]
202
+
203
+
204
+ class DependencyMetadata(TypedDict, total=False):
205
+ """Type-safe structure for DependencyInfoModel metadata."""
206
+
207
+ version: str
208
+ resolved_path: str
209
+ package_manager: str
210
+ dependency_scope: str
211
+ is_dev_dependency: bool
212
+ is_optional: bool
213
+ resolution_method: str
214
+ confidence_score: float
215
+ flags: list[str]
216
+
217
+ # TypeScript analyzer specific
218
+ full_path: str
219
+
220
+
221
+ class SecurityMetadata(TypedDict, total=False):
222
+ """Type-safe structure for CodeSecurityPattern metadata."""
223
+
224
+ rule_id: str
225
+ confidence: float
226
+ impact: str
227
+ remediation: str
228
+ references: list[str]
229
+ tags: list[str]
230
+ custom_fields: dict[str, Any]
231
+
232
+ # Analyzer specific
233
+ match_text: str
234
+
235
+
236
+ class AnalysisMetadata(TypedDict, total=False):
237
+ """Type-safe structure for CoreAnalysisResult metadata."""
238
+
239
+ analyzer_version: str
240
+ analysis_mode: str
241
+ configuration: dict[str, Any]
242
+ performance_metrics: dict[str, Any]
243
+ quality_metrics: dict[str, Any]
244
+ tags: list[str]
245
+ flags: list[str]
246
+ custom_fields: dict[str, Any]
247
+
248
+ # Common analyzer fields
249
+ file_path: str
250
+ directory_path: str
251
+ directory: str
252
+ snippet: bool
253
+ error: str
254
+ error_type: str
255
+ error_timestamp: str
256
+ repo_path: str
257
+ total_files: int
258
+ successful_files: int
259
+ failed_files: list[str]
260
+ files_analyzed: int
261
+ error_count: int
262
+ languages: list[str]
263
+ language: str
264
+ detected_language: str
265
+ snippet_language: str
266
+ has_context: bool
267
+
268
+ # Symbolic analyzer fields
269
+ symbolic_analysis: dict[str, Any]
270
+ analyzer: str
271
+ documentation: dict[str, Any]
272
+ original_file: str
273
+
274
+ # TypeScript analyzer fields
275
+ parser_used: str
276
+ typescript_version: str
277
+ type_safety: dict[str, Any]
278
+ complexity: dict[str, Any]
279
+ typescript_specific: dict[str, Any]
280
+ analysis_timestamp: str
281
+
282
+
283
+ class RepositorySummary(TypedDict, total=False):
284
+ """Type-safe structure for repository analysis summary."""
285
+
286
+ total_files: int
287
+ files_by_language: dict[str, int]
288
+ lines_of_code: int
289
+ complexity_distribution: dict[str, int]
290
+ security_findings: dict[str, int]
291
+ quality_score: float
292
+ maintainability_index: float
293
+ test_coverage: float
294
+ documentation_coverage: float
295
+ dependency_count: int
296
+ external_dependencies: int
297
+ analysis_duration_seconds: float
298
+ timestamp: str
299
+
300
+ # Code processor fields
301
+ message: str
302
+
303
+
304
+ class AnalysisPatterns(TypedDict, total=False):
305
+ """Type-safe structure for analysis patterns."""
306
+
307
+ pattern_type: str
308
+ pattern_name: str
309
+ confidence: float
310
+ frequency: int
311
+ instances: list[dict[str, str | int | bool | float]]
312
+ locations: list[str]
313
+ description: str
314
+ category: str
315
+ impact: str
316
+ recommendations: list[str]
317
+ tags: list[str]
318
+
319
+
320
+ class CoreArchitectureAnalysis(TypedDict, total=False):
321
+ """Type-safe structure for architecture analysis results."""
322
+
323
+ layers: list[dict[str, str | int | bool | float]]
324
+ components: list[dict[str, str | int | bool | float]]
325
+ dependencies: list[dict[str, str | int | bool | float]]
326
+ patterns: list[dict[str, str | int | bool | float]]
327
+ metrics: dict[str, str | int | float]
328
+ quality_indicators: dict[str, str | int | float]
329
+ recommendations: list[str]
330
+ analysis_timestamp: str
331
+ # Extended fields used by analysis_orchestrator
332
+ architectural_style: str
333
+ total_modules: int
334
+ total_components: int
335
+ coupling_score: float
336
+ cohesion_score: float
337
+ complexity_score: float
338
+ patterns_detected: list[str]
339
+ dependencies_count: int
340
+ layer_violations: int
341
+
342
+
343
+ class ImpactAnalysis(TypedDict, total=False):
344
+ """Type-safe structure for impact analysis results."""
345
+
346
+ affected_components: list[str]
347
+ risk_level: str
348
+ change_propagation: dict[str, str | int | bool | float]
349
+ test_impact: dict[str, str | int | bool | float]
350
+ performance_impact: dict[str, str | int | bool | float]
351
+ recommendations: list[str]
352
+ confidence_score: float
353
+ analysis_timestamp: str
354
+ # Extended fields used by analysis_orchestrator
355
+ affected_files: int
356
+ breaking_changes: list[str]
357
+ change_complexity: float
358
+ dependencies_affected: list[str]
359
+
360
+
361
+ class StyleScore(TypedDict, total=False):
362
+ """Type-safe structure for style evaluation scores."""
363
+
364
+ overall_score: float
365
+ naming_conventions: float
366
+ code_organization: float
367
+ documentation_quality: float
368
+ consistency_score: float
369
+ best_practices: float
370
+ maintainability: float
371
+ readability: float
372
+ detailed_metrics: dict[str, str | int | float]
373
+
374
+
375
+ class ProcessingTimeBreakdown(TypedDict, total=False):
376
+ """Type-safe structure for processing time breakdown."""
377
+
378
+ total_time_seconds: float
379
+ parsing_time_seconds: float
380
+ analysis_time_seconds: float
381
+ relationship_extraction_seconds: float
382
+ metrics_calculation_seconds: float
383
+ post_processing_seconds: float
384
+ file_io_seconds: float
385
+ memory_usage_mb: float
386
+ cpu_usage_percent: float
387
+ concurrent_workers: int
388
+ files_per_second: float
389
+
390
+
391
+ # Enums
392
+ class EntityType(StrEnum):
393
+ """Universal entity types across all programming languages."""
394
+
395
+ # Core entities (universal)
396
+ MODULE = "module"
397
+ FILE = "file"
398
+ FUNCTION = "function"
399
+ VARIABLE = "variable"
400
+ CONSTANT = "constant"
401
+ IMPORT = "import"
402
+
403
+ # Object-oriented entities
404
+ CLASS = "class"
405
+ INTERFACE = "interface"
406
+ TRAIT = "trait"
407
+ ENUM = "enum"
408
+ STRUCT = "struct"
409
+ UNION = "union"
410
+
411
+ # Functional entities
412
+ CLOSURE = "closure"
413
+ LAMBDA = "lambda"
414
+ GENERATOR = "generator"
415
+
416
+ # Language-specific entities
417
+ NAMESPACE = "namespace"
418
+ PACKAGE = "package"
419
+ ANNOTATION = "annotation"
420
+ DECORATOR = "decorator"
421
+ MACRO = "macro"
422
+ GENERIC = "generic"
423
+ TYPE_ALIAS = "type_alias"
424
+
425
+ # Documentation entities
426
+ COMMENT = "comment"
427
+ DOCSTRING = "docstring"
428
+ TODO = "todo"
429
+
430
+
431
+ class RelationType(StrEnum):
432
+ """Universal relationship types between entities."""
433
+
434
+ # Structural relationships
435
+ CONTAINS = "contains" # Module contains class
436
+ DEFINES = "defines" # Class defines method
437
+ DECLARES = "declares" # Function declares variable
438
+
439
+ # Call relationships
440
+ CALLS = "calls" # Function calls another function
441
+ INVOKES = "invokes" # Class instantiation
442
+ REFERENCES = "references" # Variable reference
443
+
444
+ # Inheritance relationships
445
+ INHERITS = "inherits" # Class inheritance
446
+ IMPLEMENTS = "implements" # Interface implementation
447
+ EXTENDS = "extends" # Trait/mixin extension
448
+
449
+ # Import/dependency relationships
450
+ IMPORTS = "imports" # Module imports
451
+ DEPENDS_ON = "depends_on" # Dependency relationship
452
+ EXPORTS = "exports" # Module exports
453
+
454
+ # Type relationships
455
+ INSTANTIATES = "instantiates" # Variable instantiates type
456
+ CASTS_TO = "casts_to" # Type casting
457
+ GENERIC_OF = "generic_of" # Generic type parameter
458
+
459
+ # Documentation relationships
460
+ DOCUMENTS = "documents" # Comment/docstring relationship
461
+ ANNOTATES = "annotates" # Annotation relationship
462
+
463
+ # Legacy compatibility
464
+ INHERITANCE = "inherits" # Maps to INHERITS
465
+ COMPOSITION = "contains" # Maps to CONTAINS
466
+ DEPENDENCY = "depends_on" # Maps to DEPENDS_ON
467
+ CALL = "calls" # Maps to CALLS
468
+ IMPORT = "imports" # Maps to IMPORTS
469
+ USAGE = "references" # Maps to REFERENCES
470
+
471
+
472
+ # Core Entity Models
473
+ class SourceLocation(BaseModel):
474
+ """Precise location information within source code."""
475
+
476
+ model_config = ConfigDict(frozen=True)
477
+
478
+ file_path: str
479
+ line_start: int = Field(..., ge=1)
480
+ line_end: int = Field(..., ge=1)
481
+ column_start: int = Field(..., ge=0)
482
+ column_end: int = Field(..., ge=0)
483
+
484
+
485
+ class TypeInfo(BaseModel):
486
+ """Type information for entities."""
487
+
488
+ model_config = ConfigDict(frozen=True)
489
+
490
+ name: str
491
+ module: str | None = None
492
+ is_generic: bool = False
493
+ generic_params: list[str] = Field(default_factory=list)
494
+ is_nullable: bool = False
495
+ is_array: bool = False
496
+ array_dimensions: int = 0
497
+
498
+
499
+ class CoreCodeEntity(BaseModel):
500
+ """
501
+ Universal code entity representation for multi-language support.
502
+
503
+ Combines the best features from both previous implementations with language-agnostic design.
504
+ """
505
+
506
+ id: str = Field(..., description="Unique identifier for the entity")
507
+ name: str = Field(..., description="Entity name")
508
+ type: EntityType = Field(..., description="Type of code entity")
509
+ language: str = Field(..., description="Programming language")
510
+
511
+ # Location information (augmented for multi-language)
512
+ file_path: str = Field(..., description="File path where entity is defined")
513
+ line_number: int = Field(..., description="Starting line number")
514
+ end_line_number: int | None = Field(None, description="Ending line number")
515
+ column_start: int | None = Field(None, description="Starting column")
516
+ column_end: int | None = Field(None, description="Ending column")
517
+
518
+ # Type information
519
+ return_type: TypeInfo | None = None
520
+ parameter_types: list[TypeInfo] = Field(default_factory=list)
521
+
522
+ # Modifiers and attributes (language-agnostic)
523
+ visibility: str | None = Field(None, description="public, private, protected, internal")
524
+ is_static: bool = False
525
+ is_abstract: bool = False
526
+ is_final: bool = False
527
+ is_async: bool = False
528
+ is_generic: bool = False
529
+
530
+ # Content and documentation
531
+ code_snippet: str | None = Field(None, description="Code snippet")
532
+ docstring: str | None = Field(None, description="Documentation string")
533
+ signature: str | None = Field(None, description="Function/method signature")
534
+ source_code: str | None = Field(None, description="Full source code")
535
+
536
+ # Language-specific properties (Dict for Pydantic compatibility, matches CodeEntityProperties structure)
537
+ properties: dict[str, Any] = Field(
538
+ default_factory=dict, description="Language-specific metadata"
539
+ )
540
+ metadata: dict[str, Any] = Field(
541
+ default_factory=dict,
542
+ description="Additional metadata (legacy compatibility)",
543
+ )
544
+
545
+ # Timestamps
546
+ created_at: datetime | None = Field(None, description="Creation timestamp")
547
+ updated_at: datetime | None = Field(None, description="Last update timestamp")
548
+
549
+ model_config = ConfigDict(from_attributes=True)
550
+
551
+ def model_post_init(self, __context: Any) -> None:
552
+ """Log entity creation for debugging purposes."""
553
+ logger.debug(
554
+ f"Created CoreCodeEntity: {self.name} ({self.type.value}) in {self.file_path}:{self.line_number}"
555
+ )
556
+
557
+
558
+ class EntityRelation(BaseModel):
559
+ """
560
+ Universal relationship model between two code entities for multi-language support.
561
+
562
+ Combines features from both previous implementations with backward compatibility.
563
+ """
564
+
565
+ # Core relationship
566
+ source_id: str = Field(..., description="ID of the source entity")
567
+ target_id: str = Field(..., description="ID of the target entity")
568
+ type: RelationType = Field(..., description="Type of relationship")
569
+
570
+ # Relationship metadata
571
+ weight: float = Field(default=1.0, ge=0.0, le=1.0, description="Relationship strength")
572
+ properties: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
573
+
574
+ # Context information
575
+ location: SourceLocation | None = None
576
+ context: str | None = None # Code snippet showing relationship
577
+
578
+ # Legacy compatibility fields
579
+ id: str | None = Field(None, description="Unique identifier for the relationship")
580
+ relationship_type: str | None = Field(None, description="Backward compatibility alias")
581
+ line_number: int | None = Field(None, description="Line number where relationship occurs")
582
+ detail: str | None = Field(None, description="Additional relationship details")
583
+ metadata: dict[str, Any] = Field(
584
+ default_factory=dict, description="Additional metadata (legacy)"
585
+ )
586
+ created_at: datetime | None = Field(None, description="Creation timestamp")
587
+
588
+ model_config = ConfigDict(from_attributes=True, populate_by_name=True)
589
+
590
+ def __init__(self, **data: Any) -> None:
591
+ # Handle backward compatibility for relationship_type field
592
+ if "relationship_type" in data and "type" not in data:
593
+ data["type"] = data["relationship_type"]
594
+ elif "type" in data and isinstance(data["type"], str):
595
+ # Convert string to enum if needed
596
+ try:
597
+ data["type"] = RelationType(data["type"])
598
+ except ValueError:
599
+ # If conversion fails, keep as string (will be validated by Pydantic)
600
+ pass
601
+
602
+ # Generate ID if not provided
603
+ if "id" not in data or data["id"] is None:
604
+ source_id = data.get("source_id", "")
605
+ target_id = data.get("target_id", "")
606
+ rel_type = data.get("type", "")
607
+ if hasattr(rel_type, "value"):
608
+ rel_type = rel_type.value
609
+ data["id"] = f"{source_id}-{rel_type}-{target_id}"
610
+
611
+ super().__init__(**data)
612
+
613
+ # Log relationship creation for debugging
614
+ logger.debug(
615
+ f"Created EntityRelation: {self.source_id} -> {self.target_id} ({self.type.value})"
616
+ )
617
+
618
+
619
+ # Analysis Support Models
620
+ class DependencyInfoModel(BaseModel):
621
+ """Information about code dependencies."""
622
+
623
+ module_name: str = Field(..., description="Name of the dependency module")
624
+ import_type: str = Field(..., description="Type of import ('import' or 'from_import')")
625
+ alias: str | None = Field(None, description="Import alias if used")
626
+ line_number: int = Field(0, description="Line number of import")
627
+ is_external: bool = Field(False, description="Whether dependency is external")
628
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
629
+
630
+ def model_post_init(self, __context: Any) -> None:
631
+ """Log dependency creation for debugging purposes."""
632
+ logger.debug(
633
+ f"Created DependencyInfoModel: {self.module_name} ({self.import_type}) - external: {self.is_external}"
634
+ )
635
+
636
+
637
+ class CoreComplexityMetrics(BaseModel):
638
+ """Code complexity measurements for multi-language support."""
639
+
640
+ model_config = ConfigDict(frozen=True)
641
+
642
+ cyclomatic_complexity: float = 0.0
643
+ cognitive_complexity: float = 0.0
644
+ lines_of_code: int = 0
645
+ logical_lines: int = 0
646
+ parameters_count: int = 0
647
+ returns_count: int = 0
648
+ branches_count: int = 0
649
+ nested_depth: int = 0
650
+
651
+ # Extended metrics
652
+ maintainability_index: float = Field(0.0, description="Maintainability index score")
653
+ halstead_volume: float = Field(0.0, description="Halstead volume metric")
654
+ halstead_difficulty: float = Field(0.0, description="Halstead difficulty metric")
655
+ halstead_effort: float = Field(0.0, description="Halstead effort metric")
656
+
657
+ # Legacy compatibility
658
+ function_count: int = Field(0, description="Number of functions")
659
+ class_count: int = Field(0, description="Number of classes")
660
+ comment_lines: int = Field(0, description="Lines of comments")
661
+ blank_lines: int = Field(0, description="Blank lines")
662
+ docstring_coverage: float = Field(0.0, description="Docstring coverage percentage")
663
+
664
+
665
+ class CodeSecurityPattern(BaseModel):
666
+ """Security pattern detection result from code analysis."""
667
+
668
+ type: str = Field(..., description="Type of security pattern")
669
+ severity: str = Field(..., description="Severity level (low, medium, high, critical)")
670
+ line_number: int = Field(..., description="Line number where pattern was found")
671
+ description: str = Field(..., description="Description of the pattern")
672
+ cwe_id: str | None = Field(None, description="Common Weakness Enumeration ID")
673
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
674
+
675
+ def model_post_init(self, __context: Any) -> None:
676
+ """Log security pattern detection for debugging purposes."""
677
+ logger.warning(
678
+ f"SecurityPattern detected: {self.type} (severity: {self.severity}) at line {self.line_number}"
679
+ )
680
+
681
+
682
+ # Analysis Result Models
683
+ class CoreAnalysisResult(BaseModel):
684
+ """Result of code analysis operation."""
685
+
686
+ success: bool = Field(..., description="Whether analysis was successful")
687
+ language: str = Field(..., description="Programming language")
688
+ file_path: str = Field(..., description="Path to analyzed file")
689
+ entities: list[CoreCodeEntity] = Field(default_factory=list, description="Discovered entities")
690
+ relationships: list[EntityRelation] = Field(
691
+ default_factory=list, description="Entity relationships"
692
+ )
693
+ dependencies: list[DependencyInfoModel] = Field(
694
+ default_factory=list, description="Dependencies found"
695
+ )
696
+ complexity_metrics: CoreComplexityMetrics | None = Field(None, description="Complexity metrics")
697
+ security_patterns: list[CodeSecurityPattern] = Field(
698
+ default_factory=list, description="Security patterns"
699
+ )
700
+ error: str | None = Field(None, description="Error message if analysis failed")
701
+ errors: list[str] = Field(default_factory=list, description="Error messages")
702
+ warnings: list[str] = Field(default_factory=list, description="Warning messages")
703
+ parse_time_ms: float = Field(0.0, description="Parse time in milliseconds")
704
+ total_lines: int = Field(0, description="Total lines of code")
705
+ timestamp: datetime | None = Field(None, description="Analysis timestamp")
706
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
707
+
708
+ def model_post_init(self, __context: Any) -> None:
709
+ """Log analysis result creation for debugging purposes."""
710
+ status = "successful" if self.success else "failed"
711
+ logger.info(
712
+ f"CoreAnalysisResult created: {status} for {self.file_path} ({self.language}) - "
713
+ f"entities: {len(self.entities)}, relationships: {len(self.relationships)}"
714
+ )
715
+
716
+
717
+ class CoreFileAnalysisResult(BaseModel):
718
+ """Analysis result for a single file."""
719
+
720
+ file_path: str = Field(..., description="Path to analyzed file")
721
+ language: str = Field(..., description="Programming language")
722
+ analysis_result: CoreAnalysisResult = Field(..., description="Analysis results")
723
+ timestamp: datetime = Field(
724
+ default_factory=lambda: datetime.now(UTC),
725
+ description="Analysis timestamp",
726
+ )
727
+
728
+
729
+ class RepositoryAnalysis(BaseModel):
730
+ """Analysis results for an entire repository."""
731
+
732
+ success: bool = Field(..., description="Whether repository analysis was successful")
733
+ file_results: list[CoreAnalysisResult] = Field(
734
+ default_factory=list, description="File analysis results"
735
+ )
736
+ failed_files: list[dict[str, str]] = Field(
737
+ default_factory=list, description="Files that failed analysis"
738
+ )
739
+ summary: dict[str, Any] = Field(default_factory=dict, description="Analysis summary")
740
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
741
+
742
+ def model_post_init(self, __context: Any) -> None:
743
+ """Log repository analysis completion for debugging purposes."""
744
+ status = "successful" if self.success else "failed"
745
+ total_files = len(self.file_results)
746
+ failed_count = len(self.failed_files)
747
+ logger.info(
748
+ f"RepositoryAnalysis completed: {status} - {total_files} files processed, {failed_count} failed"
749
+ )
750
+
751
+
752
+ class FullAnalysis(BaseModel):
753
+ """Complete analysis results including architecture analysis."""
754
+
755
+ success: bool = Field(..., description="Whether full analysis was successful")
756
+ file_results: list[CoreFileAnalysisResult] = Field(
757
+ default_factory=list, description="File analysis results"
758
+ )
759
+ summary: dict[str, Any] = Field(default_factory=dict, description="Analysis summary")
760
+ patterns: list[dict[str, Any]] = Field(default_factory=list, description="Detected patterns")
761
+ architecture_analysis: dict[str, Any] = Field(
762
+ default_factory=dict, description="Architecture analysis"
763
+ )
764
+ error: str | None = Field(None, description="Error message if analysis failed")
765
+
766
+ def model_post_init(self, __context: Any) -> None:
767
+ """Log full analysis completion for debugging purposes."""
768
+ status = "successful" if self.success else "failed"
769
+ pattern_count = len(self.patterns)
770
+ logger.info(
771
+ f"FullAnalysis completed: {status} - {len(self.file_results)} files, {pattern_count} patterns detected"
772
+ )
773
+
774
+
775
+ class IncrementalAnalysis(BaseModel):
776
+ """Results of incremental code analysis."""
777
+
778
+ success: bool = Field(..., description="Whether incremental analysis was successful")
779
+ changed_files: list[CoreFileAnalysisResult] = Field(
780
+ default_factory=list, description="Changed file results"
781
+ )
782
+ impact_analysis: dict[str, Any] = Field(default_factory=dict, description="Impact analysis")
783
+ error: str | None = Field(None, description="Error message if analysis failed")
784
+
785
+ def model_post_init(self, __context: Any) -> None:
786
+ """Log incremental analysis completion for debugging purposes."""
787
+ status = "successful" if self.success else "failed"
788
+ changed_count = len(self.changed_files)
789
+ logger.info(
790
+ f"IncrementalAnalysis completed: {status} - {changed_count} changed files analyzed"
791
+ )
792
+
793
+
794
+ class SnippetEvaluation(BaseModel):
795
+ """Evaluation results for a code snippet."""
796
+
797
+ success: bool = Field(..., description="Whether snippet evaluation was successful")
798
+ analysis: CoreAnalysisResult | None = Field(None, description="Analysis results")
799
+ compatibility_score: float = Field(0.0, description="Compatibility score")
800
+ style_score: dict[str, Any] = Field(default_factory=dict, description="Style evaluation")
801
+ pattern_matches: list[dict[str, Any]] = Field(
802
+ default_factory=list, description="Pattern matches"
803
+ )
804
+ recommendations: list[str] = Field(default_factory=list, description="Recommendations")
805
+ error: str | None = Field(None, description="Error message if evaluation failed")
806
+ metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
807
+
808
+ def model_post_init(self, __context: Any) -> None:
809
+ """Log snippet evaluation completion for debugging purposes."""
810
+ status = "successful" if self.success else "failed"
811
+ logger.info(
812
+ f"SnippetEvaluation completed: {status} - compatibility: {self.compatibility_score:.2f}"
813
+ )
814
+
815
+
816
+ # Graph and Metrics Models
817
+ class GraphMetrics(BaseModel):
818
+ """Metrics for an entity in the code graph."""
819
+
820
+ entity_id: str = Field(..., description="Entity identifier")
821
+ entity_name: str = Field(..., description="Entity name")
822
+ degree_centrality: float = Field(0.0, description="Degree centrality metric")
823
+ betweenness_centrality: float = Field(0.0, description="Betweenness centrality metric")
824
+ closeness_centrality: float = Field(0.0, description="Closeness centrality metric")
825
+ pagerank: float = Field(0.0, description="PageRank metric")
826
+ importance_score: float = Field(0.0, description="Combined importance score")
827
+
828
+
829
+ class OverallGraphMetrics(BaseModel):
830
+ """Overall statistics for the entire code graph."""
831
+
832
+ node_count: int = Field(0, description="Total number of nodes")
833
+ edge_count: int = Field(0, description="Total number of edges")
834
+ density: float = Field(0.0, description="Graph density")
835
+ average_degree: float = Field(0.0, description="Average degree")
836
+ node_types: dict[str, int] = Field(default_factory=dict, description="Node count by type")
837
+ relationship_types: dict[str, int] = Field(
838
+ default_factory=dict, description="Edge count by type"
839
+ )
840
+ calculation_time_seconds: float = Field(0.0, description="Time taken for calculation")
841
+
842
+
843
+ # Request Models
844
+ class CodebaseAnalysisRequest(BaseModel):
845
+ """Request model for codebase analysis operations."""
846
+
847
+ directory: str = Field(..., description="Directory to analyze")
848
+ languages: list[str] = Field(["python"], description="Programming languages to analyze")
849
+ max_workers: int | None = Field(None, description="Maximum number of worker processes")
850
+ include_tests: bool = Field(False, description="Whether to include test files")
851
+ ignore_patterns: list[str] = Field(default_factory=list, description="File patterns to ignore")
852
+
853
+
854
+ # Response Models
855
+ class AnalysisResponse(BaseModel):
856
+ """Response model for codebase analysis."""
857
+
858
+ status: str = Field(..., description="Analysis status")
859
+ directory: str = Field(..., description="Analyzed directory")
860
+ files_processed: int = Field(..., description="Number of files processed")
861
+ files_failed: int = Field(..., description="Number of files that failed")
862
+ total_entities: int = Field(..., description="Total entities found")
863
+ total_relations: int = Field(..., description="Total relationships found")
864
+ processing_time: ProcessingTimeBreakdown = Field(..., description="Processing time breakdown")
865
+ languages: list[str] = Field(..., description="Languages analyzed")
866
+
867
+ def model_post_init(self, __context: Any) -> None:
868
+ """Log analysis response creation for debugging purposes."""
869
+ success_rate = (
870
+ (self.files_processed - self.files_failed) / self.files_processed * 100
871
+ if self.files_processed > 0
872
+ else 0
873
+ )
874
+ logger.info(
875
+ f"AnalysisResponse created: {self.status} - {self.files_processed} files processed "
876
+ f"({success_rate:.1f}% success rate), {self.total_entities} entities, "
877
+ f"{self.total_relations} relationships"
878
+ )