graph-dependency-analyzer 0.2.0__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 (86) hide show
  1. graph_dependency_analyzer-0.2.0.dist-info/METADATA +158 -0
  2. graph_dependency_analyzer-0.2.0.dist-info/RECORD +86 -0
  3. graph_dependency_analyzer-0.2.0.dist-info/WHEEL +5 -0
  4. graph_dependency_analyzer-0.2.0.dist-info/entry_points.txt +2 -0
  5. graph_dependency_analyzer-0.2.0.dist-info/top_level.txt +1 -0
  6. src/__init__.py +0 -0
  7. src/application/__init__.py +0 -0
  8. src/application/dtos/__init__.py +0 -0
  9. src/application/dtos/affected_component.py +59 -0
  10. src/application/dtos/batch_processing_result.py +17 -0
  11. src/application/dtos/impact_analysis_response.py +56 -0
  12. src/application/dtos/impact_query_request.py +38 -0
  13. src/application/dtos/index_batch_request.py +53 -0
  14. src/application/dtos/index_batch_response.py +72 -0
  15. src/application/dtos/index_result.py +20 -0
  16. src/application/dtos/repository_index_result.py +79 -0
  17. src/application/exceptions.py +41 -0
  18. src/application/services/__init__.py +0 -0
  19. src/application/services/file_scanner_service.py +258 -0
  20. src/application/services/progress_tracker.py +132 -0
  21. src/application/use_cases/__init__.py +0 -0
  22. src/application/use_cases/clear_all_data_use_case.py +180 -0
  23. src/application/use_cases/index_batch_use_case.py +153 -0
  24. src/application/use_cases/index_repository_use_case.py +683 -0
  25. src/application/use_cases/indexing_orchestrator.py +181 -0
  26. src/application/use_cases/list_repositories_use_case.py +84 -0
  27. src/cli.py +512 -0
  28. src/config/__init__.py +5 -0
  29. src/config/container.py +211 -0
  30. src/config/logging_config.py +123 -0
  31. src/config/settings.py +165 -0
  32. src/domain/__init__.py +0 -0
  33. src/domain/entities/__init__.py +20 -0
  34. src/domain/entities/ast_node.py +32 -0
  35. src/domain/entities/code_chunk.py +45 -0
  36. src/domain/entities/code_file.py +44 -0
  37. src/domain/entities/dependency_graph.py +110 -0
  38. src/domain/entities/repository.py +46 -0
  39. src/domain/exceptions.py +36 -0
  40. src/domain/repositories/__init__.py +22 -0
  41. src/domain/repositories/i_code_parser.py +50 -0
  42. src/domain/repositories/i_dependency_extractor.py +35 -0
  43. src/domain/repositories/i_embedding_provider.py +31 -0
  44. src/domain/repositories/i_graph_repository.py +78 -0
  45. src/domain/repositories/i_vector_repository.py +55 -0
  46. src/domain/services/__init__.py +8 -0
  47. src/domain/services/dependency_extractor.py +962 -0
  48. src/domain/services/semantic_chunk_builder.py +719 -0
  49. src/domain/value_objects/__init__.py +12 -0
  50. src/domain/value_objects/chunk_type.py +24 -0
  51. src/domain/value_objects/dependency_type.py +22 -0
  52. src/domain/value_objects/node_type.py +22 -0
  53. src/domain/value_objects/qualified_name.py +78 -0
  54. src/infrastructure/__init__.py +0 -0
  55. src/infrastructure/exceptions.py +41 -0
  56. src/infrastructure/external_apis/__init__.py +0 -0
  57. src/infrastructure/external_apis/ollama_embedding_provider.py +134 -0
  58. src/infrastructure/external_apis/openai_embedding_provider.py +231 -0
  59. src/infrastructure/parsing/__init__.py +20 -0
  60. src/infrastructure/parsing/config_file_parser.py +347 -0
  61. src/infrastructure/parsing/gradle_dependency_parser.py +159 -0
  62. src/infrastructure/parsing/groovy_parser.py +198 -0
  63. src/infrastructure/parsing/maven_dependency_parser.py +147 -0
  64. src/infrastructure/parsing/microfrontend_config_parser.py +242 -0
  65. src/infrastructure/parsing/npm_package_dependency_parser.py +255 -0
  66. src/infrastructure/parsing/python_parser.py +211 -0
  67. src/infrastructure/parsing/sql_schema_parser.py +658 -0
  68. src/infrastructure/parsing/tree_sitter_java_parser.py +434 -0
  69. src/infrastructure/parsing/tree_sitter_typescript_parser.py +600 -0
  70. src/infrastructure/persistence/__init__.py +0 -0
  71. src/infrastructure/persistence/graph_export_repository.py +443 -0
  72. src/infrastructure/persistence/neo4j_dependency_repository.py +657 -0
  73. src/infrastructure/persistence/qdrant_vector_repository.py +357 -0
  74. src/infrastructure/persistence/repository_relationship_repository.py +1312 -0
  75. src/presentation/__init__.py +0 -0
  76. src/presentation/api/__init__.py +0 -0
  77. src/presentation/api/rest/__init__.py +0 -0
  78. src/presentation/api/rest/exception_handlers.py +174 -0
  79. src/presentation/api/rest/main.py +80 -0
  80. src/presentation/api/rest/routers/__init__.py +5 -0
  81. src/presentation/api/rest/routers/admin.py +103 -0
  82. src/presentation/api/rest/routers/analysis.py +980 -0
  83. src/presentation/api/rest/routers/export.py +442 -0
  84. src/presentation/api/rest/routers/health.py +117 -0
  85. src/presentation/api/rest/routers/indexing.py +148 -0
  86. src/presentation/api/rest/routers/relationships.py +1089 -0
File without changes
File without changes
File without changes
@@ -0,0 +1,174 @@
1
+ """
2
+ FastAPI Exception Handlers (Task 9.3)
3
+
4
+ Global exception handlers for the REST API.
5
+ """
6
+ from fastapi import Request, status
7
+ from fastapi.responses import JSONResponse
8
+ from fastapi.exceptions import RequestValidationError
9
+ import structlog
10
+
11
+ from src.application.exceptions import (
12
+ ApplicationException,
13
+ EmptyRepositoryListError,
14
+ NoValidRepositoriesError,
15
+ RepositoryNotFoundError
16
+ )
17
+ from src.infrastructure.exceptions import (
18
+ InfrastructureException,
19
+ OpenAIAPIError,
20
+ QdrantConnectionError,
21
+ Neo4jConnectionError
22
+ )
23
+ from src.domain.exceptions import DomainException
24
+
25
+ logger = structlog.get_logger(__name__)
26
+
27
+
28
+ async def application_exception_handler(
29
+ request: Request,
30
+ exc: ApplicationException
31
+ ) -> JSONResponse:
32
+ """
33
+ Handle application layer exceptions.
34
+
35
+ Returns HTTP 400 for user errors.
36
+ """
37
+ logger.warning(
38
+ "application_error",
39
+ error_type=type(exc).__name__,
40
+ message=exc.message,
41
+ details=exc.details,
42
+ path=request.url.path
43
+ )
44
+
45
+ return JSONResponse(
46
+ status_code=status.HTTP_400_BAD_REQUEST,
47
+ content={
48
+ "error": type(exc).__name__,
49
+ "message": exc.message,
50
+ "details": exc.details
51
+ }
52
+ )
53
+
54
+
55
+ async def infrastructure_exception_handler(
56
+ request: Request,
57
+ exc: InfrastructureException
58
+ ) -> JSONResponse:
59
+ """
60
+ Handle infrastructure layer exceptions.
61
+
62
+ Returns HTTP 500 for system errors.
63
+ Logs full details but returns generic message to client.
64
+ """
65
+ logger.error(
66
+ "infrastructure_error",
67
+ error_type=type(exc).__name__,
68
+ message=exc.message,
69
+ details=exc.details,
70
+ path=request.url.path,
71
+ exc_info=True
72
+ )
73
+
74
+ return JSONResponse(
75
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
76
+ content={
77
+ "error": "InternalServerError",
78
+ "message": "An internal error occurred. Please try again later."
79
+ }
80
+ )
81
+
82
+
83
+ async def domain_exception_handler(
84
+ request: Request,
85
+ exc: DomainException
86
+ ) -> JSONResponse:
87
+ """
88
+ Handle domain layer exceptions.
89
+
90
+ Returns HTTP 400 for domain rule violations.
91
+ """
92
+ logger.warning(
93
+ "domain_error",
94
+ error_type=type(exc).__name__,
95
+ message=exc.message,
96
+ details=exc.details,
97
+ path=request.url.path
98
+ )
99
+
100
+ return JSONResponse(
101
+ status_code=status.HTTP_400_BAD_REQUEST,
102
+ content={
103
+ "error": type(exc).__name__,
104
+ "message": exc.message,
105
+ "details": exc.details
106
+ }
107
+ )
108
+
109
+
110
+ async def validation_exception_handler(
111
+ request: Request,
112
+ exc: RequestValidationError
113
+ ) -> JSONResponse:
114
+ """
115
+ Handle Pydantic validation errors.
116
+
117
+ Returns HTTP 422 for validation failures.
118
+ """
119
+ logger.warning(
120
+ "validation_error",
121
+ errors=exc.errors(),
122
+ body=exc.body,
123
+ path=request.url.path
124
+ )
125
+
126
+ return JSONResponse(
127
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
128
+ content={
129
+ "error": "ValidationError",
130
+ "message": "Request validation failed",
131
+ "details": exc.errors()
132
+ }
133
+ )
134
+
135
+
136
+ async def unhandled_exception_handler(
137
+ request: Request,
138
+ exc: Exception
139
+ ) -> JSONResponse:
140
+ """
141
+ Handle any unhandled exceptions.
142
+
143
+ Returns HTTP 500 with generic message.
144
+ Logs full stack trace.
145
+ """
146
+ logger.error(
147
+ "unhandled_error",
148
+ error_type=type(exc).__name__,
149
+ message=str(exc),
150
+ path=request.url.path,
151
+ exc_info=True
152
+ )
153
+
154
+ return JSONResponse(
155
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
156
+ content={
157
+ "error": "InternalServerError",
158
+ "message": "An unexpected error occurred. Please contact support."
159
+ }
160
+ )
161
+
162
+
163
+ def register_exception_handlers(app):
164
+ """
165
+ Register all exception handlers with FastAPI app.
166
+
167
+ Args:
168
+ app: FastAPI application instance
169
+ """
170
+ app.add_exception_handler(ApplicationException, application_exception_handler)
171
+ app.add_exception_handler(InfrastructureException, infrastructure_exception_handler)
172
+ app.add_exception_handler(DomainException, domain_exception_handler)
173
+ app.add_exception_handler(RequestValidationError, validation_exception_handler)
174
+ app.add_exception_handler(Exception, unhandled_exception_handler)
@@ -0,0 +1,80 @@
1
+ """
2
+ FastAPI Application (Task 9.2)
3
+
4
+ Main FastAPI application with all routers and middleware.
5
+ """
6
+ from fastapi import FastAPI
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ import structlog
9
+
10
+ from src.config.container import get_container
11
+ from src.presentation.api.rest.routers import health, indexing, analysis, admin, export, relationships
12
+ from src.presentation.api.rest.exception_handlers import register_exception_handlers
13
+
14
+ logger = structlog.get_logger(__name__)
15
+
16
+
17
+ def create_app() -> FastAPI:
18
+ """
19
+ Create and configure FastAPI application.
20
+
21
+ Returns:
22
+ Configured FastAPI instance with all routers and middleware
23
+ """
24
+ app = FastAPI(
25
+ title="Knowledge Graph Indexing API",
26
+ description="API for indexing Java repositories and performing impact analysis",
27
+ version="1.0.0",
28
+ docs_url="/docs",
29
+ redoc_url="/redoc"
30
+ )
31
+
32
+ # Configure CORS
33
+ app.add_middleware(
34
+ CORSMiddleware,
35
+ allow_origins=["*"], # Configure appropriately for production
36
+ allow_credentials=True,
37
+ allow_methods=["*"],
38
+ allow_headers=["*"],
39
+ )
40
+
41
+ # Configure dependency injection
42
+ container = get_container()
43
+ container.wire(modules=[
44
+ "src.presentation.api.rest.routers.indexing",
45
+ "src.presentation.api.rest.routers.analysis",
46
+ "src.presentation.api.rest.routers.admin",
47
+ "src.presentation.api.rest.routers.export",
48
+ "src.presentation.api.rest.routers.relationships",
49
+ ])
50
+
51
+ # Register exception handlers
52
+ register_exception_handlers(app)
53
+
54
+ # Register routers
55
+ app.include_router(health.router)
56
+ app.include_router(indexing.router)
57
+ app.include_router(analysis.router)
58
+ app.include_router(admin.router)
59
+ app.include_router(export.router)
60
+ app.include_router(relationships.router)
61
+
62
+ logger.info("fastapi_application_created", container_wired=True)
63
+
64
+ return app
65
+
66
+
67
+ # Create application instance
68
+ app = create_app()
69
+
70
+
71
+ @app.on_event("startup")
72
+ async def startup_event():
73
+ """Application startup event handler."""
74
+ logger.info("application_starting")
75
+
76
+
77
+ @app.on_event("shutdown")
78
+ async def shutdown_event():
79
+ """Application shutdown event handler."""
80
+ logger.info("application_shutting_down")
@@ -0,0 +1,5 @@
1
+ """
2
+ REST API Routers Module.
3
+
4
+ Contains all FastAPI router implementations.
5
+ """
@@ -0,0 +1,103 @@
1
+ """
2
+ Admin Router
3
+
4
+ REST API endpoints for administrative operations.
5
+
6
+ ⚠️ WARNING: These endpoints perform DESTRUCTIVE operations!
7
+ Use with caution in production environments.
8
+ """
9
+ from fastapi import APIRouter, Depends, HTTPException, status
10
+ from pydantic import BaseModel
11
+ import structlog
12
+
13
+ from dependency_injector.wiring import inject, Provide
14
+
15
+ from src.application.use_cases.clear_all_data_use_case import ClearAllDataUseCase
16
+ from src.config.container import Container
17
+
18
+ logger = structlog.get_logger(__name__)
19
+
20
+ router = APIRouter(prefix="/admin", tags=["admin"])
21
+
22
+
23
+ class ClearAllResponse(BaseModel):
24
+ """Response model for clear all operation."""
25
+ message: str
26
+ neo4j: dict
27
+ qdrant: dict
28
+
29
+
30
+ @router.delete(
31
+ "/clear-all",
32
+ response_model=ClearAllResponse,
33
+ status_code=status.HTTP_200_OK,
34
+ responses={
35
+ 200: {"description": "All data cleared successfully"},
36
+ 500: {"description": "Internal server error"}
37
+ }
38
+ )
39
+ @inject
40
+ async def clear_all_data(
41
+ use_case: ClearAllDataUseCase = Depends(Provide[Container.clear_all_data_use_case])
42
+ ) -> ClearAllResponse:
43
+ """
44
+ Clear all data from Qdrant and Neo4j.
45
+
46
+ ⚠️ **DESTRUCTIVE OPERATION** - Deletes:
47
+ - All nodes and relationships in Neo4j
48
+ - All vectors in Qdrant collection
49
+
50
+ This operation is **irreversible**. All indexed repositories will be lost.
51
+
52
+ Use case:
53
+ - Clean environment before re-indexing
54
+ - Reset system to initial state
55
+ - Testing and development
56
+
57
+ Returns:
58
+ ClearAllResponse with deletion metrics
59
+
60
+ Raises:
61
+ HTTP 500: Internal error during deletion
62
+ """
63
+ logger.warning("clear_all_requested", operation="DESTRUCTIVE")
64
+
65
+ try:
66
+ results = await use_case.execute()
67
+
68
+ # Check if both operations succeeded
69
+ neo4j_success = results["neo4j"]["success"]
70
+ qdrant_success = results["qdrant"]["success"]
71
+
72
+ if neo4j_success and qdrant_success:
73
+ message = "All data cleared successfully"
74
+ elif neo4j_success:
75
+ message = "Neo4j cleared, but Qdrant failed"
76
+ elif qdrant_success:
77
+ message = "Qdrant cleared, but Neo4j failed"
78
+ else:
79
+ message = "Both operations failed"
80
+
81
+ logger.warning(
82
+ "clear_all_completed",
83
+ message=message,
84
+ neo4j_success=neo4j_success,
85
+ qdrant_success=qdrant_success
86
+ )
87
+
88
+ return ClearAllResponse(
89
+ message=message,
90
+ neo4j=results["neo4j"],
91
+ qdrant=results["qdrant"]
92
+ )
93
+
94
+ except Exception as e:
95
+ logger.error(
96
+ "clear_all_failed",
97
+ error=str(e),
98
+ error_type=type(e).__name__
99
+ )
100
+ raise HTTPException(
101
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
102
+ detail=f"Failed to clear data: {str(e)}"
103
+ )