aiecs 1.5.1__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 (302) hide show
  1. aiecs/__init__.py +72 -0
  2. aiecs/__main__.py +41 -0
  3. aiecs/aiecs_client.py +469 -0
  4. aiecs/application/__init__.py +10 -0
  5. aiecs/application/executors/__init__.py +10 -0
  6. aiecs/application/executors/operation_executor.py +363 -0
  7. aiecs/application/knowledge_graph/__init__.py +7 -0
  8. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
  11. aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
  12. aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
  13. aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
  14. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  15. aiecs/application/knowledge_graph/extractors/base.py +100 -0
  16. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
  17. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
  18. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
  19. aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
  20. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
  21. aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
  22. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
  23. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
  24. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  25. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
  26. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
  27. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  28. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
  29. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  30. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  31. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
  32. aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
  33. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
  34. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  35. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  36. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
  37. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
  38. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
  39. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
  40. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
  41. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
  42. aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
  43. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
  44. aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
  45. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
  46. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  47. aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
  48. aiecs/application/knowledge_graph/search/reranker.py +295 -0
  49. aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
  50. aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
  51. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  52. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
  53. aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
  54. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  55. aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
  56. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  57. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
  58. aiecs/common/__init__.py +9 -0
  59. aiecs/common/knowledge_graph/__init__.py +17 -0
  60. aiecs/common/knowledge_graph/runnable.py +484 -0
  61. aiecs/config/__init__.py +16 -0
  62. aiecs/config/config.py +498 -0
  63. aiecs/config/graph_config.py +137 -0
  64. aiecs/config/registry.py +23 -0
  65. aiecs/core/__init__.py +46 -0
  66. aiecs/core/interface/__init__.py +34 -0
  67. aiecs/core/interface/execution_interface.py +152 -0
  68. aiecs/core/interface/storage_interface.py +171 -0
  69. aiecs/domain/__init__.py +289 -0
  70. aiecs/domain/agent/__init__.py +189 -0
  71. aiecs/domain/agent/base_agent.py +697 -0
  72. aiecs/domain/agent/exceptions.py +103 -0
  73. aiecs/domain/agent/graph_aware_mixin.py +559 -0
  74. aiecs/domain/agent/hybrid_agent.py +490 -0
  75. aiecs/domain/agent/integration/__init__.py +26 -0
  76. aiecs/domain/agent/integration/context_compressor.py +222 -0
  77. aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
  78. aiecs/domain/agent/integration/retry_policy.py +219 -0
  79. aiecs/domain/agent/integration/role_config.py +213 -0
  80. aiecs/domain/agent/knowledge_aware_agent.py +646 -0
  81. aiecs/domain/agent/lifecycle.py +296 -0
  82. aiecs/domain/agent/llm_agent.py +300 -0
  83. aiecs/domain/agent/memory/__init__.py +12 -0
  84. aiecs/domain/agent/memory/conversation.py +197 -0
  85. aiecs/domain/agent/migration/__init__.py +14 -0
  86. aiecs/domain/agent/migration/conversion.py +160 -0
  87. aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
  88. aiecs/domain/agent/models.py +317 -0
  89. aiecs/domain/agent/observability.py +407 -0
  90. aiecs/domain/agent/persistence.py +289 -0
  91. aiecs/domain/agent/prompts/__init__.py +29 -0
  92. aiecs/domain/agent/prompts/builder.py +161 -0
  93. aiecs/domain/agent/prompts/formatters.py +189 -0
  94. aiecs/domain/agent/prompts/template.py +255 -0
  95. aiecs/domain/agent/registry.py +260 -0
  96. aiecs/domain/agent/tool_agent.py +257 -0
  97. aiecs/domain/agent/tools/__init__.py +12 -0
  98. aiecs/domain/agent/tools/schema_generator.py +221 -0
  99. aiecs/domain/community/__init__.py +155 -0
  100. aiecs/domain/community/agent_adapter.py +477 -0
  101. aiecs/domain/community/analytics.py +481 -0
  102. aiecs/domain/community/collaborative_workflow.py +642 -0
  103. aiecs/domain/community/communication_hub.py +645 -0
  104. aiecs/domain/community/community_builder.py +320 -0
  105. aiecs/domain/community/community_integration.py +800 -0
  106. aiecs/domain/community/community_manager.py +813 -0
  107. aiecs/domain/community/decision_engine.py +879 -0
  108. aiecs/domain/community/exceptions.py +225 -0
  109. aiecs/domain/community/models/__init__.py +33 -0
  110. aiecs/domain/community/models/community_models.py +268 -0
  111. aiecs/domain/community/resource_manager.py +457 -0
  112. aiecs/domain/community/shared_context_manager.py +603 -0
  113. aiecs/domain/context/__init__.py +58 -0
  114. aiecs/domain/context/context_engine.py +989 -0
  115. aiecs/domain/context/conversation_models.py +354 -0
  116. aiecs/domain/context/graph_memory.py +467 -0
  117. aiecs/domain/execution/__init__.py +12 -0
  118. aiecs/domain/execution/model.py +57 -0
  119. aiecs/domain/knowledge_graph/__init__.py +19 -0
  120. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  121. aiecs/domain/knowledge_graph/models/entity.py +130 -0
  122. aiecs/domain/knowledge_graph/models/evidence.py +194 -0
  123. aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
  124. aiecs/domain/knowledge_graph/models/path.py +179 -0
  125. aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
  126. aiecs/domain/knowledge_graph/models/query.py +272 -0
  127. aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
  128. aiecs/domain/knowledge_graph/models/relation.py +136 -0
  129. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  130. aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
  131. aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
  132. aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
  133. aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
  134. aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
  135. aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
  136. aiecs/domain/task/__init__.py +13 -0
  137. aiecs/domain/task/dsl_processor.py +613 -0
  138. aiecs/domain/task/model.py +62 -0
  139. aiecs/domain/task/task_context.py +268 -0
  140. aiecs/infrastructure/__init__.py +24 -0
  141. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  142. aiecs/infrastructure/graph_storage/base.py +601 -0
  143. aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
  144. aiecs/infrastructure/graph_storage/cache.py +429 -0
  145. aiecs/infrastructure/graph_storage/distributed.py +226 -0
  146. aiecs/infrastructure/graph_storage/error_handling.py +390 -0
  147. aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
  148. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  149. aiecs/infrastructure/graph_storage/in_memory.py +514 -0
  150. aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
  151. aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
  152. aiecs/infrastructure/graph_storage/metrics.py +357 -0
  153. aiecs/infrastructure/graph_storage/migration.py +413 -0
  154. aiecs/infrastructure/graph_storage/pagination.py +471 -0
  155. aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
  156. aiecs/infrastructure/graph_storage/postgres.py +871 -0
  157. aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
  158. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  159. aiecs/infrastructure/graph_storage/sqlite.py +623 -0
  160. aiecs/infrastructure/graph_storage/streaming.py +495 -0
  161. aiecs/infrastructure/messaging/__init__.py +13 -0
  162. aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
  163. aiecs/infrastructure/messaging/websocket_manager.py +298 -0
  164. aiecs/infrastructure/monitoring/__init__.py +34 -0
  165. aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
  166. aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
  167. aiecs/infrastructure/monitoring/structured_logger.py +48 -0
  168. aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
  169. aiecs/infrastructure/persistence/__init__.py +24 -0
  170. aiecs/infrastructure/persistence/context_engine_client.py +187 -0
  171. aiecs/infrastructure/persistence/database_manager.py +333 -0
  172. aiecs/infrastructure/persistence/file_storage.py +754 -0
  173. aiecs/infrastructure/persistence/redis_client.py +220 -0
  174. aiecs/llm/__init__.py +86 -0
  175. aiecs/llm/callbacks/__init__.py +11 -0
  176. aiecs/llm/callbacks/custom_callbacks.py +264 -0
  177. aiecs/llm/client_factory.py +420 -0
  178. aiecs/llm/clients/__init__.py +33 -0
  179. aiecs/llm/clients/base_client.py +193 -0
  180. aiecs/llm/clients/googleai_client.py +181 -0
  181. aiecs/llm/clients/openai_client.py +131 -0
  182. aiecs/llm/clients/vertex_client.py +437 -0
  183. aiecs/llm/clients/xai_client.py +184 -0
  184. aiecs/llm/config/__init__.py +51 -0
  185. aiecs/llm/config/config_loader.py +275 -0
  186. aiecs/llm/config/config_validator.py +236 -0
  187. aiecs/llm/config/model_config.py +151 -0
  188. aiecs/llm/utils/__init__.py +10 -0
  189. aiecs/llm/utils/validate_config.py +91 -0
  190. aiecs/main.py +363 -0
  191. aiecs/scripts/__init__.py +3 -0
  192. aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
  193. aiecs/scripts/aid/__init__.py +19 -0
  194. aiecs/scripts/aid/version_manager.py +215 -0
  195. aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
  196. aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
  197. aiecs/scripts/dependance_check/__init__.py +17 -0
  198. aiecs/scripts/dependance_check/dependency_checker.py +938 -0
  199. aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
  200. aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
  201. aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
  202. aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
  203. aiecs/scripts/dependance_patch/__init__.py +7 -0
  204. aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
  205. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  206. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
  207. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
  208. aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
  209. aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
  210. aiecs/scripts/tools_develop/README.md +449 -0
  211. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  212. aiecs/scripts/tools_develop/__init__.py +21 -0
  213. aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
  214. aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
  215. aiecs/scripts/tools_develop/verify_tools.py +356 -0
  216. aiecs/tasks/__init__.py +1 -0
  217. aiecs/tasks/worker.py +172 -0
  218. aiecs/tools/__init__.py +299 -0
  219. aiecs/tools/apisource/__init__.py +99 -0
  220. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  221. aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
  222. aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
  223. aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
  224. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  225. aiecs/tools/apisource/monitoring/metrics.py +303 -0
  226. aiecs/tools/apisource/providers/__init__.py +115 -0
  227. aiecs/tools/apisource/providers/base.py +664 -0
  228. aiecs/tools/apisource/providers/census.py +401 -0
  229. aiecs/tools/apisource/providers/fred.py +564 -0
  230. aiecs/tools/apisource/providers/newsapi.py +412 -0
  231. aiecs/tools/apisource/providers/worldbank.py +357 -0
  232. aiecs/tools/apisource/reliability/__init__.py +12 -0
  233. aiecs/tools/apisource/reliability/error_handler.py +375 -0
  234. aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
  235. aiecs/tools/apisource/tool.py +850 -0
  236. aiecs/tools/apisource/utils/__init__.py +9 -0
  237. aiecs/tools/apisource/utils/validators.py +338 -0
  238. aiecs/tools/base_tool.py +201 -0
  239. aiecs/tools/docs/__init__.py +121 -0
  240. aiecs/tools/docs/ai_document_orchestrator.py +599 -0
  241. aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
  242. aiecs/tools/docs/content_insertion_tool.py +1333 -0
  243. aiecs/tools/docs/document_creator_tool.py +1317 -0
  244. aiecs/tools/docs/document_layout_tool.py +1166 -0
  245. aiecs/tools/docs/document_parser_tool.py +994 -0
  246. aiecs/tools/docs/document_writer_tool.py +1818 -0
  247. aiecs/tools/knowledge_graph/__init__.py +17 -0
  248. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
  249. aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
  250. aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
  251. aiecs/tools/langchain_adapter.py +542 -0
  252. aiecs/tools/schema_generator.py +275 -0
  253. aiecs/tools/search_tool/__init__.py +100 -0
  254. aiecs/tools/search_tool/analyzers.py +589 -0
  255. aiecs/tools/search_tool/cache.py +260 -0
  256. aiecs/tools/search_tool/constants.py +128 -0
  257. aiecs/tools/search_tool/context.py +216 -0
  258. aiecs/tools/search_tool/core.py +749 -0
  259. aiecs/tools/search_tool/deduplicator.py +123 -0
  260. aiecs/tools/search_tool/error_handler.py +271 -0
  261. aiecs/tools/search_tool/metrics.py +371 -0
  262. aiecs/tools/search_tool/rate_limiter.py +178 -0
  263. aiecs/tools/search_tool/schemas.py +277 -0
  264. aiecs/tools/statistics/__init__.py +80 -0
  265. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
  266. aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
  267. aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
  268. aiecs/tools/statistics/data_loader_tool.py +564 -0
  269. aiecs/tools/statistics/data_profiler_tool.py +658 -0
  270. aiecs/tools/statistics/data_transformer_tool.py +573 -0
  271. aiecs/tools/statistics/data_visualizer_tool.py +495 -0
  272. aiecs/tools/statistics/model_trainer_tool.py +487 -0
  273. aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
  274. aiecs/tools/task_tools/__init__.py +86 -0
  275. aiecs/tools/task_tools/chart_tool.py +732 -0
  276. aiecs/tools/task_tools/classfire_tool.py +922 -0
  277. aiecs/tools/task_tools/image_tool.py +447 -0
  278. aiecs/tools/task_tools/office_tool.py +684 -0
  279. aiecs/tools/task_tools/pandas_tool.py +635 -0
  280. aiecs/tools/task_tools/report_tool.py +635 -0
  281. aiecs/tools/task_tools/research_tool.py +392 -0
  282. aiecs/tools/task_tools/scraper_tool.py +715 -0
  283. aiecs/tools/task_tools/stats_tool.py +688 -0
  284. aiecs/tools/temp_file_manager.py +130 -0
  285. aiecs/tools/tool_executor/__init__.py +37 -0
  286. aiecs/tools/tool_executor/tool_executor.py +881 -0
  287. aiecs/utils/LLM_output_structor.py +445 -0
  288. aiecs/utils/__init__.py +34 -0
  289. aiecs/utils/base_callback.py +47 -0
  290. aiecs/utils/cache_provider.py +695 -0
  291. aiecs/utils/execution_utils.py +184 -0
  292. aiecs/utils/logging.py +1 -0
  293. aiecs/utils/prompt_loader.py +14 -0
  294. aiecs/utils/token_usage_repository.py +323 -0
  295. aiecs/ws/__init__.py +0 -0
  296. aiecs/ws/socket_server.py +52 -0
  297. aiecs-1.5.1.dist-info/METADATA +608 -0
  298. aiecs-1.5.1.dist-info/RECORD +302 -0
  299. aiecs-1.5.1.dist-info/WHEEL +5 -0
  300. aiecs-1.5.1.dist-info/entry_points.txt +10 -0
  301. aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
  302. aiecs-1.5.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,390 @@
1
+ """
2
+ Logic Query Parser
3
+
4
+ This module provides the LogicQueryParser class for parsing Logic Query DSL
5
+ into Abstract Syntax Trees (AST).
6
+
7
+ The parser uses Lark for syntax parsing and implements two-phase error handling:
8
+ - Phase 1: Syntax parsing (fatal errors from Lark)
9
+ - Phase 2: Semantic validation (accumulated errors from AST)
10
+
11
+ Phase: 2.4 - Logic Query Parser
12
+ Version: 1.0
13
+ """
14
+
15
+ from pathlib import Path
16
+ from typing import Union, List, Any, Optional, Dict
17
+ from functools import lru_cache
18
+
19
+ try:
20
+ from lark import (
21
+ Lark,
22
+ LarkError,
23
+ UnexpectedInput,
24
+ UnexpectedToken,
25
+ UnexpectedCharacters,
26
+ )
27
+
28
+ LARK_AVAILABLE = True
29
+ except ImportError:
30
+ LARK_AVAILABLE = False
31
+ Lark = None
32
+ LarkError = Exception
33
+ UnexpectedInput = Exception
34
+ UnexpectedToken = Exception
35
+ UnexpectedCharacters = Exception
36
+
37
+ # AST node types imported for type hints in docstrings
38
+ # from .ast_nodes import ASTNode, QueryNode, FindNode, TraversalNode, FilterNode
39
+ from .query_context import QueryContext
40
+ from .ast_builder import ASTBuilder
41
+ from .error_handler import ParserError, ErrorHandler
42
+
43
+ # Import QueryPlan models
44
+ try:
45
+ from aiecs.domain.knowledge_graph.models.query_plan import QueryPlan
46
+
47
+ QUERY_PLAN_AVAILABLE = True
48
+ except ImportError:
49
+ QUERY_PLAN_AVAILABLE = False
50
+ QueryPlan = None
51
+
52
+
53
+ class LogicQueryParser:
54
+ """
55
+ Logic Query DSL Parser
56
+
57
+ Parses Logic Query DSL strings into Abstract Syntax Trees (AST).
58
+
59
+ This class handles:
60
+ 1. Syntax parsing (via Lark)
61
+ 2. AST building (via Transformer - to be implemented in Task 2.2)
62
+ 3. Two-phase error handling (syntax vs semantic)
63
+
64
+ **Thread Safety**: This class is thread-safe. Each parse() call creates
65
+ a fresh QueryContext internally.
66
+
67
+ Example:
68
+ ```python
69
+ schema = SchemaManager()
70
+ parser = LogicQueryParser(schema)
71
+
72
+ # Parse a query
73
+ result = parser.parse("Find(Person) WHERE age > 30")
74
+
75
+ if isinstance(result, list):
76
+ # Errors occurred
77
+ for error in result:
78
+ print(f"Error at line {error.line}: {error.message}")
79
+ else:
80
+ # Success - got AST
81
+ ast = result
82
+ print(f"Parsed: {ast}")
83
+ ```
84
+ """
85
+
86
+ def __init__(self, schema: Any = None):
87
+ """
88
+ Initialize the parser
89
+
90
+ Args:
91
+ schema: SchemaManager instance for validation (optional for now)
92
+
93
+ Raises:
94
+ ImportError: If lark-parser is not installed
95
+ """
96
+ if not LARK_AVAILABLE:
97
+ raise ImportError(
98
+ "lark-parser is required for LogicQueryParser. "
99
+ "Install with: pip install lark-parser"
100
+ )
101
+
102
+ self.schema = schema
103
+
104
+ # Load grammar from file
105
+ grammar_path = Path(__file__).parent / "grammar.lark"
106
+ with open(grammar_path, "r") as f:
107
+ grammar_text = f.read()
108
+
109
+ # Create Lark parser with LALR algorithm
110
+ self.lark_parser = Lark(
111
+ grammar_text,
112
+ start="query",
113
+ parser="lalr",
114
+ propagate_positions=True, # Track line/column info
115
+ maybe_placeholders=False,
116
+ )
117
+
118
+ # Create AST builder
119
+ self.ast_builder = ASTBuilder()
120
+
121
+ # Create error handler
122
+ self.error_handler = ErrorHandler()
123
+
124
+ def parse(self, query: str) -> Union[Any, List[ParserError]]:
125
+ """
126
+ Parse a query string into an AST
127
+
128
+ This method implements two-phase error handling:
129
+ - Phase 1: Syntax parsing (fatal - stops at first error)
130
+ - Phase 2: Semantic validation (accumulated - returns all errors)
131
+
132
+ Args:
133
+ query: Query string to parse
134
+
135
+ Returns:
136
+ - AST node if successful
137
+ - List of ParserError if errors occurred
138
+
139
+ Example:
140
+ ```python
141
+ result = parser.parse("Find(Person) WHERE age > 30")
142
+ if isinstance(result, list):
143
+ print("Errors:", result)
144
+ else:
145
+ print("AST:", result)
146
+ ```
147
+ """
148
+ # Phase 1: Syntax parsing (fatal errors)
149
+ try:
150
+ parse_tree = self.lark_parser.parse(query)
151
+
152
+ # Transform parse tree to AST
153
+ ast = self.ast_builder.transform(parse_tree)
154
+
155
+ # Phase 2: Semantic validation (if schema is available)
156
+ if self.schema is not None:
157
+ validation_errors = ast.validate(self.schema)
158
+ if validation_errors:
159
+ # Convert validation errors to parser errors
160
+ return [
161
+ self.error_handler.from_validation_error(err, query)
162
+ for err in validation_errors
163
+ ]
164
+
165
+ return ast
166
+
167
+ except (UnexpectedInput, UnexpectedToken, UnexpectedCharacters) as e:
168
+ # Lark syntax error
169
+ return [self.error_handler.from_lark_error(e, query)]
170
+ except LarkError as e:
171
+ # Other Lark errors
172
+ return [self.error_handler.from_lark_error(e, query)]
173
+ except Exception as e:
174
+ # Unexpected errors
175
+ return [
176
+ ParserError(
177
+ line=1,
178
+ column=1,
179
+ message=f"Unexpected error: {str(e)}",
180
+ phase="syntax",
181
+ )
182
+ ]
183
+
184
+ def parse_to_query_plan(self, query: str) -> Any:
185
+ """
186
+ Parse query string and convert to QueryPlan
187
+
188
+ This is the main entry point for parsing and converting queries to executable plans.
189
+ It performs:
190
+ 1. Syntax parsing (Lark)
191
+ 2. AST building (Transformer)
192
+ 3. Semantic validation (if schema available)
193
+ 4. QueryPlan conversion
194
+
195
+ Args:
196
+ query: Query string in Logic Query DSL
197
+
198
+ Returns:
199
+ QueryPlan object if successful, or List[ParserError] if errors occurred
200
+
201
+ Example:
202
+ ```python
203
+ parser = LogicQueryParser(schema=schema_manager)
204
+ result = parser.parse_to_query_plan("Find(Person) WHERE age > 30")
205
+
206
+ if isinstance(result, list):
207
+ # Errors occurred
208
+ for error in result:
209
+ print(f"Error at line {error.line}: {error.message}")
210
+ else:
211
+ # Success - result is a QueryPlan
212
+ for step in result.steps:
213
+ print(f"Step {step.step_id}: {step.description}")
214
+ ```
215
+ """
216
+ if not QUERY_PLAN_AVAILABLE:
217
+ return [
218
+ ParserError(
219
+ line=1,
220
+ column=1,
221
+ message="QueryPlan models not available. Cannot convert to query plan.",
222
+ phase="conversion",
223
+ )
224
+ ]
225
+
226
+ # Step 1: Parse to AST
227
+ ast_result = self.parse(query)
228
+
229
+ # Check for errors
230
+ if isinstance(ast_result, list):
231
+ # Errors occurred during parsing/validation
232
+ return ast_result
233
+
234
+ # Step 2: Create fresh QueryContext for this request (thread-safe)
235
+ context = QueryContext(schema=self.schema)
236
+
237
+ # Step 3: Convert AST to QueryPlan
238
+ try:
239
+ query_plan = ast_result.to_query_plan(context, original_query=query)
240
+ return query_plan
241
+ except Exception as e:
242
+ # Conversion error
243
+ return [
244
+ ParserError(
245
+ line=1,
246
+ column=1,
247
+ message=f"Failed to convert to query plan: {str(e)}",
248
+ phase="conversion",
249
+ )
250
+ ]
251
+
252
+ def parse_tree_to_string(self, parse_tree: Any) -> str:
253
+ """
254
+ Convert parse tree to string representation
255
+
256
+ Args:
257
+ parse_tree: Lark parse tree
258
+
259
+ Returns:
260
+ String representation of the parse tree
261
+ """
262
+ if parse_tree is None:
263
+ return "None"
264
+ return parse_tree.pretty()
265
+
266
+ # ========================================================================
267
+ # Multi-Query Support (Batch Processing)
268
+ # ========================================================================
269
+
270
+ def parse_batch(self, queries: List[str]) -> List[Any]:
271
+ """
272
+ Parse multiple queries in batch
273
+
274
+ This method parses multiple queries independently and returns their
275
+ AST representations. Each query is parsed with its own context.
276
+
277
+ Args:
278
+ queries: List of query strings to parse
279
+
280
+ Returns:
281
+ List of results (QueryNode or List[ParserError] for each query)
282
+
283
+ Example:
284
+ ```python
285
+ parser = LogicQueryParser(schema=schema_manager)
286
+ results = parser.parse_batch([
287
+ "Find(Person) WHERE age > 30",
288
+ "Find(Paper) WHERE year == 2023"
289
+ ])
290
+
291
+ for i, result in enumerate(results):
292
+ if isinstance(result, list):
293
+ print(f"Query {i+1} errors: {result}")
294
+ else:
295
+ print(f"Query {i+1} success: {result}")
296
+ ```
297
+ """
298
+ results = []
299
+ for query in queries:
300
+ result = self.parse(query)
301
+ results.append(result)
302
+ return results
303
+
304
+ def parse_batch_to_query_plans(self, queries: List[str]) -> List[Any]:
305
+ """
306
+ Parse multiple queries and convert to QueryPlans in batch
307
+
308
+ This method parses multiple queries and converts them to QueryPlan
309
+ objects. Each query is processed independently with its own context.
310
+
311
+ Args:
312
+ queries: List of query strings to parse
313
+
314
+ Returns:
315
+ List of results (QueryPlan or List[ParserError] for each query)
316
+
317
+ Example:
318
+ ```python
319
+ parser = LogicQueryParser(schema=schema_manager)
320
+ plans = parser.parse_batch_to_query_plans([
321
+ "Find(Person) WHERE age > 30",
322
+ "Find(Paper) WHERE year == 2023"
323
+ ])
324
+
325
+ for i, plan in enumerate(plans):
326
+ if isinstance(plan, list):
327
+ print(f"Query {i+1} errors: {plan}")
328
+ else:
329
+ print(f"Query {i+1} plan: {plan.plan_id}")
330
+ ```
331
+ """
332
+ results = []
333
+ for query in queries:
334
+ result = self.parse_to_query_plan(query)
335
+ results.append(result)
336
+ return results
337
+
338
+ def parse_batch_with_ids(self, queries: Dict[str, str]) -> Dict[str, Any]:
339
+ """
340
+ Parse multiple queries with custom IDs
341
+
342
+ This method parses multiple queries and returns results keyed by
343
+ custom IDs. Useful for tracking which result corresponds to which query.
344
+
345
+ Args:
346
+ queries: Dictionary mapping query IDs to query strings
347
+
348
+ Returns:
349
+ Dictionary mapping query IDs to results (QueryNode or List[ParserError])
350
+
351
+ Example:
352
+ ```python
353
+ parser = LogicQueryParser(schema=schema_manager)
354
+ results = parser.parse_batch_with_ids({
355
+ "find_people": "Find(Person) WHERE age > 30",
356
+ "find_papers": "Find(Paper) WHERE year == 2023"
357
+ })
358
+
359
+ if isinstance(results["find_people"], list):
360
+ print(f"Errors: {results['find_people']}")
361
+ else:
362
+ print(f"Success: {results['find_people']}")
363
+ ```
364
+ """
365
+ results = {}
366
+ for query_id, query in queries.items():
367
+ result = self.parse(query)
368
+ results[query_id] = result
369
+ return results
370
+
371
+
372
+ # Cached parser instance for performance
373
+ @lru_cache(maxsize=1)
374
+ def get_cached_parser(schema_id: Optional[int] = None) -> LogicQueryParser:
375
+ """
376
+ Get a cached parser instance
377
+
378
+ This is an optional optimization for repeated parsing.
379
+
380
+ Args:
381
+ schema_id: Optional schema identifier for cache key
382
+
383
+ Returns:
384
+ Cached LogicQueryParser instance
385
+
386
+ Note:
387
+ This is optional (Task 2.1.6). The cache is based on schema_id.
388
+ If schema changes, use a different schema_id to get a new parser.
389
+ """
390
+ return LogicQueryParser(schema=None)
@@ -0,0 +1,217 @@
1
+ """
2
+ Query Context for Logic Query Parser
3
+
4
+ This module provides the QueryContext class for managing state during query parsing
5
+ and conversion. The context is used to track variables, errors, and query steps.
6
+
7
+ **IMPORTANT**: QueryContext is NOT thread-safe. Create a new instance for each parse request.
8
+
9
+ Phase: 2.4 - Logic Query Parser
10
+ Version: 1.0
11
+ """
12
+
13
+ from dataclasses import dataclass, field
14
+ from typing import Any, Dict, List
15
+
16
+
17
+ class VariableRedefinitionError(Exception):
18
+ """Raised when attempting to redefine an already-bound variable"""
19
+
20
+
21
+ class UndefinedVariableError(Exception):
22
+ """Raised when attempting to resolve an undefined variable"""
23
+
24
+
25
+ @dataclass
26
+ class QueryContext:
27
+ """
28
+ Context for query parsing and conversion
29
+
30
+ This class manages state during query parsing, including:
31
+ - Schema reference for validation
32
+ - Variable bindings for multi-step queries
33
+ - Error accumulation for validation
34
+ - Query steps for multi-step query construction
35
+
36
+ **Thread Safety**: This class contains mutable state and is NOT thread-safe.
37
+ Create a NEW QueryContext instance for EACH parse request.
38
+
39
+ **Lifecycle**:
40
+ 1. Create: `context = QueryContext(schema)`
41
+ 2. Use: `ast.to_query_plan(context)` or `ast.validate(schema)`
42
+ 3. Discard: Context should not be reused for another query
43
+
44
+ **Concurrency Pattern**:
45
+ ```python
46
+ # ✅ CORRECT: New context per request
47
+ def parse_concurrent(query: str):
48
+ context = QueryContext(schema) # Fresh instance
49
+ return parser.parse(query, context)
50
+
51
+ # ❌ WRONG: Shared context across requests
52
+ shared_context = QueryContext(schema) # DON'T DO THIS
53
+ def parse_concurrent(query: str):
54
+ return parser.parse(query, shared_context) # Race condition!
55
+ ```
56
+
57
+ Attributes:
58
+ schema: Schema manager for validation (immutable reference)
59
+ variables: Variable bindings for multi-step queries (mutable)
60
+ query_steps: Accumulated query steps (mutable)
61
+ errors: Accumulated validation errors (mutable)
62
+
63
+ Example:
64
+ ```python
65
+ schema = SchemaManager()
66
+ context = QueryContext(schema)
67
+
68
+ # Bind a variable
69
+ context.bind_variable("person_id", "123")
70
+
71
+ # Resolve a variable
72
+ person_id = context.resolve_variable("person_id")
73
+
74
+ # Add an error
75
+ context.add_error(ParserError(...))
76
+
77
+ # Clear context for reuse (not recommended)
78
+ context.clear()
79
+ ```
80
+ """
81
+
82
+ # SchemaManager instance (type hint as Any to avoid circular import)
83
+ schema: Any
84
+ variables: Dict[str, Any] = field(default_factory=dict)
85
+ query_steps: List[Any] = field(default_factory=list) # List[QueryStep]
86
+ errors: List[Any] = field(default_factory=list) # List[ParserError]
87
+
88
+ def bind_variable(self, name: str, value: Any) -> None:
89
+ """
90
+ Bind a variable to a value
91
+
92
+ Variables are used in multi-step queries to reference results from
93
+ previous steps.
94
+
95
+ Args:
96
+ name: Variable name (must be unique)
97
+ value: Value to bind to the variable
98
+
99
+ Raises:
100
+ VariableRedefinitionError: If variable is already bound
101
+
102
+ Example:
103
+ ```python
104
+ context.bind_variable("person_id", "123")
105
+ context.bind_variable("person_id", "456") # Raises error
106
+ ```
107
+ """
108
+ if name in self.variables:
109
+ raise VariableRedefinitionError(
110
+ f"Variable '{name}' is already defined with value: {self.variables[name]}"
111
+ )
112
+ self.variables[name] = value
113
+
114
+ def resolve_variable(self, name: str) -> Any:
115
+ """
116
+ Resolve a variable to its value
117
+
118
+ Args:
119
+ name: Variable name to resolve
120
+
121
+ Returns:
122
+ Value bound to the variable
123
+
124
+ Raises:
125
+ UndefinedVariableError: If variable is not bound
126
+
127
+ Example:
128
+ ```python
129
+ context.bind_variable("person_id", "123")
130
+ value = context.resolve_variable("person_id") # Returns "123"
131
+ value = context.resolve_variable("unknown") # Raises error
132
+ ```
133
+ """
134
+ if name not in self.variables:
135
+ raise UndefinedVariableError(
136
+ f"Variable '{name}' is not defined. Available variables: {list(self.variables.keys())}"
137
+ )
138
+ return self.variables[name]
139
+
140
+ def add_error(self, error: Any) -> None:
141
+ """
142
+ Add a validation or parsing error to the context
143
+
144
+ Errors are accumulated during parsing and validation so that
145
+ multiple errors can be reported at once.
146
+
147
+ Args:
148
+ error: ParserError or ValidationError instance
149
+
150
+ Example:
151
+ ```python
152
+ error = ParserError(line=1, column=10, message="Invalid syntax")
153
+ context.add_error(error)
154
+ ```
155
+ """
156
+ self.errors.append(error)
157
+
158
+ def clear(self) -> None:
159
+ """
160
+ Clear all mutable state in the context
161
+
162
+ This method resets variables, query steps, and errors.
163
+
164
+ **WARNING**: Reusing a context is NOT recommended. Create a new
165
+ context for each parse request instead.
166
+
167
+ Example:
168
+ ```python
169
+ context.clear() # Reset all state
170
+ ```
171
+ """
172
+ self.variables.clear()
173
+ self.query_steps.clear()
174
+ self.errors.clear()
175
+
176
+ def has_variable(self, name: str) -> bool:
177
+ """
178
+ Check if a variable is bound
179
+
180
+ Args:
181
+ name: Variable name to check
182
+
183
+ Returns:
184
+ True if variable is bound, False otherwise
185
+
186
+ Example:
187
+ ```python
188
+ context.bind_variable("person_id", "123")
189
+ assert context.has_variable("person_id") == True
190
+ assert context.has_variable("unknown") == False
191
+ ```
192
+ """
193
+ return name in self.variables
194
+
195
+ def has_errors(self) -> bool:
196
+ """
197
+ Check if any errors have been accumulated
198
+
199
+ Returns:
200
+ True if errors exist, False otherwise
201
+
202
+ Example:
203
+ ```python
204
+ if context.has_errors():
205
+ print(f"Found {len(context.errors)} errors")
206
+ ```
207
+ """
208
+ return len(self.errors) > 0
209
+
210
+ def __repr__(self) -> str:
211
+ """String representation for debugging"""
212
+ return (
213
+ f"QueryContext("
214
+ f"variables={len(self.variables)}, "
215
+ f"steps={len(self.query_steps)}, "
216
+ f"errors={len(self.errors)})"
217
+ )