cognee 0.2.3.dev1__py3-none-any.whl → 0.3.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 (252) hide show
  1. cognee/__init__.py +2 -0
  2. cognee/__main__.py +4 -0
  3. cognee/api/client.py +28 -3
  4. cognee/api/health.py +10 -13
  5. cognee/api/v1/add/add.py +20 -6
  6. cognee/api/v1/add/routers/get_add_router.py +12 -37
  7. cognee/api/v1/cloud/routers/__init__.py +1 -0
  8. cognee/api/v1/cloud/routers/get_checks_router.py +23 -0
  9. cognee/api/v1/cognify/code_graph_pipeline.py +14 -3
  10. cognee/api/v1/cognify/cognify.py +67 -105
  11. cognee/api/v1/cognify/routers/get_cognify_router.py +11 -3
  12. cognee/api/v1/datasets/routers/get_datasets_router.py +16 -5
  13. cognee/api/v1/memify/routers/__init__.py +1 -0
  14. cognee/api/v1/memify/routers/get_memify_router.py +100 -0
  15. cognee/api/v1/notebooks/routers/__init__.py +1 -0
  16. cognee/api/v1/notebooks/routers/get_notebooks_router.py +96 -0
  17. cognee/api/v1/responses/default_tools.py +4 -0
  18. cognee/api/v1/responses/dispatch_function.py +6 -1
  19. cognee/api/v1/responses/models.py +1 -1
  20. cognee/api/v1/search/routers/get_search_router.py +20 -1
  21. cognee/api/v1/search/search.py +17 -4
  22. cognee/api/v1/sync/__init__.py +17 -0
  23. cognee/api/v1/sync/routers/__init__.py +3 -0
  24. cognee/api/v1/sync/routers/get_sync_router.py +241 -0
  25. cognee/api/v1/sync/sync.py +877 -0
  26. cognee/api/v1/ui/__init__.py +1 -0
  27. cognee/api/v1/ui/ui.py +529 -0
  28. cognee/api/v1/users/routers/get_auth_router.py +13 -1
  29. cognee/base_config.py +10 -1
  30. cognee/cli/__init__.py +10 -0
  31. cognee/cli/_cognee.py +273 -0
  32. cognee/cli/commands/__init__.py +1 -0
  33. cognee/cli/commands/add_command.py +80 -0
  34. cognee/cli/commands/cognify_command.py +128 -0
  35. cognee/cli/commands/config_command.py +225 -0
  36. cognee/cli/commands/delete_command.py +80 -0
  37. cognee/cli/commands/search_command.py +149 -0
  38. cognee/cli/config.py +33 -0
  39. cognee/cli/debug.py +21 -0
  40. cognee/cli/echo.py +45 -0
  41. cognee/cli/exceptions.py +23 -0
  42. cognee/cli/minimal_cli.py +97 -0
  43. cognee/cli/reference.py +26 -0
  44. cognee/cli/suppress_logging.py +12 -0
  45. cognee/eval_framework/corpus_builder/corpus_builder_executor.py +2 -2
  46. cognee/eval_framework/eval_config.py +1 -1
  47. cognee/infrastructure/databases/graph/config.py +10 -4
  48. cognee/infrastructure/databases/graph/get_graph_engine.py +4 -9
  49. cognee/infrastructure/databases/graph/kuzu/adapter.py +199 -2
  50. cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +138 -0
  51. cognee/infrastructure/databases/relational/__init__.py +2 -0
  52. cognee/infrastructure/databases/relational/get_async_session.py +15 -0
  53. cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +6 -1
  54. cognee/infrastructure/databases/relational/with_async_session.py +25 -0
  55. cognee/infrastructure/databases/vector/chromadb/ChromaDBAdapter.py +1 -1
  56. cognee/infrastructure/databases/vector/config.py +13 -6
  57. cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +6 -4
  58. cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +16 -7
  59. cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +5 -5
  60. cognee/infrastructure/databases/vector/embeddings/config.py +2 -2
  61. cognee/infrastructure/databases/vector/embeddings/embedding_rate_limiter.py +2 -6
  62. cognee/infrastructure/databases/vector/embeddings/get_embedding_engine.py +10 -7
  63. cognee/infrastructure/files/storage/LocalFileStorage.py +9 -0
  64. cognee/infrastructure/files/storage/S3FileStorage.py +5 -0
  65. cognee/infrastructure/files/storage/StorageManager.py +7 -1
  66. cognee/infrastructure/files/storage/storage.py +16 -0
  67. cognee/infrastructure/files/utils/get_data_file_path.py +14 -9
  68. cognee/infrastructure/files/utils/get_file_metadata.py +2 -1
  69. cognee/infrastructure/llm/LLMGateway.py +32 -5
  70. cognee/infrastructure/llm/config.py +6 -4
  71. cognee/infrastructure/llm/prompts/extract_query_time.txt +15 -0
  72. cognee/infrastructure/llm/prompts/generate_event_entity_prompt.txt +25 -0
  73. cognee/infrastructure/llm/prompts/generate_event_graph_prompt.txt +30 -0
  74. cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py +16 -5
  75. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/__init__.py +2 -0
  76. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/extract_event_entities.py +44 -0
  77. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/knowledge_graph/__init__.py +1 -0
  78. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/knowledge_graph/extract_content_graph.py +19 -15
  79. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/knowledge_graph/extract_event_graph.py +46 -0
  80. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +3 -3
  81. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +3 -3
  82. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +2 -2
  83. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +14 -8
  84. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +6 -4
  85. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +28 -4
  86. cognee/infrastructure/llm/tokenizer/Gemini/adapter.py +2 -2
  87. cognee/infrastructure/llm/tokenizer/HuggingFace/adapter.py +3 -3
  88. cognee/infrastructure/llm/tokenizer/Mistral/adapter.py +3 -3
  89. cognee/infrastructure/llm/tokenizer/TikToken/adapter.py +6 -6
  90. cognee/infrastructure/llm/utils.py +7 -7
  91. cognee/infrastructure/utils/run_sync.py +8 -1
  92. cognee/modules/chunking/models/DocumentChunk.py +4 -3
  93. cognee/modules/cloud/exceptions/CloudApiKeyMissingError.py +15 -0
  94. cognee/modules/cloud/exceptions/CloudConnectionError.py +15 -0
  95. cognee/modules/cloud/exceptions/__init__.py +2 -0
  96. cognee/modules/cloud/operations/__init__.py +1 -0
  97. cognee/modules/cloud/operations/check_api_key.py +25 -0
  98. cognee/modules/data/deletion/prune_system.py +1 -1
  99. cognee/modules/data/methods/__init__.py +2 -0
  100. cognee/modules/data/methods/check_dataset_name.py +1 -1
  101. cognee/modules/data/methods/create_authorized_dataset.py +19 -0
  102. cognee/modules/data/methods/get_authorized_dataset.py +11 -5
  103. cognee/modules/data/methods/get_authorized_dataset_by_name.py +16 -0
  104. cognee/modules/data/methods/get_dataset_data.py +1 -1
  105. cognee/modules/data/methods/load_or_create_datasets.py +2 -20
  106. cognee/modules/engine/models/Event.py +16 -0
  107. cognee/modules/engine/models/Interval.py +8 -0
  108. cognee/modules/engine/models/Timestamp.py +13 -0
  109. cognee/modules/engine/models/__init__.py +3 -0
  110. cognee/modules/engine/utils/__init__.py +2 -0
  111. cognee/modules/engine/utils/generate_event_datapoint.py +46 -0
  112. cognee/modules/engine/utils/generate_timestamp_datapoint.py +51 -0
  113. cognee/modules/graph/cognee_graph/CogneeGraph.py +2 -2
  114. cognee/modules/graph/methods/get_formatted_graph_data.py +3 -2
  115. cognee/modules/graph/utils/__init__.py +1 -0
  116. cognee/modules/graph/utils/resolve_edges_to_text.py +71 -0
  117. cognee/modules/memify/__init__.py +1 -0
  118. cognee/modules/memify/memify.py +118 -0
  119. cognee/modules/notebooks/methods/__init__.py +5 -0
  120. cognee/modules/notebooks/methods/create_notebook.py +26 -0
  121. cognee/modules/notebooks/methods/delete_notebook.py +13 -0
  122. cognee/modules/notebooks/methods/get_notebook.py +21 -0
  123. cognee/modules/notebooks/methods/get_notebooks.py +18 -0
  124. cognee/modules/notebooks/methods/update_notebook.py +17 -0
  125. cognee/modules/notebooks/models/Notebook.py +53 -0
  126. cognee/modules/notebooks/models/__init__.py +1 -0
  127. cognee/modules/notebooks/operations/__init__.py +1 -0
  128. cognee/modules/notebooks/operations/run_in_local_sandbox.py +55 -0
  129. cognee/modules/pipelines/__init__.py +1 -1
  130. cognee/modules/pipelines/exceptions/tasks.py +18 -0
  131. cognee/modules/pipelines/layers/__init__.py +1 -0
  132. cognee/modules/pipelines/layers/check_pipeline_run_qualification.py +59 -0
  133. cognee/modules/pipelines/layers/pipeline_execution_mode.py +127 -0
  134. cognee/modules/pipelines/layers/reset_dataset_pipeline_run_status.py +28 -0
  135. cognee/modules/pipelines/layers/resolve_authorized_user_dataset.py +34 -0
  136. cognee/modules/pipelines/layers/resolve_authorized_user_datasets.py +55 -0
  137. cognee/modules/pipelines/layers/setup_and_check_environment.py +41 -0
  138. cognee/modules/pipelines/layers/validate_pipeline_tasks.py +20 -0
  139. cognee/modules/pipelines/methods/__init__.py +2 -0
  140. cognee/modules/pipelines/methods/get_pipeline_runs_by_dataset.py +34 -0
  141. cognee/modules/pipelines/methods/reset_pipeline_run_status.py +16 -0
  142. cognee/modules/pipelines/operations/__init__.py +0 -1
  143. cognee/modules/pipelines/operations/log_pipeline_run_initiated.py +1 -1
  144. cognee/modules/pipelines/operations/pipeline.py +24 -138
  145. cognee/modules/pipelines/operations/run_tasks.py +17 -41
  146. cognee/modules/retrieval/base_feedback.py +11 -0
  147. cognee/modules/retrieval/base_graph_retriever.py +18 -0
  148. cognee/modules/retrieval/base_retriever.py +1 -1
  149. cognee/modules/retrieval/code_retriever.py +8 -0
  150. cognee/modules/retrieval/coding_rules_retriever.py +31 -0
  151. cognee/modules/retrieval/completion_retriever.py +9 -3
  152. cognee/modules/retrieval/context_providers/TripletSearchContextProvider.py +1 -0
  153. cognee/modules/retrieval/cypher_search_retriever.py +1 -9
  154. cognee/modules/retrieval/graph_completion_context_extension_retriever.py +29 -13
  155. cognee/modules/retrieval/graph_completion_cot_retriever.py +30 -13
  156. cognee/modules/retrieval/graph_completion_retriever.py +107 -56
  157. cognee/modules/retrieval/graph_summary_completion_retriever.py +5 -1
  158. cognee/modules/retrieval/insights_retriever.py +14 -3
  159. cognee/modules/retrieval/natural_language_retriever.py +0 -4
  160. cognee/modules/retrieval/summaries_retriever.py +1 -1
  161. cognee/modules/retrieval/temporal_retriever.py +152 -0
  162. cognee/modules/retrieval/user_qa_feedback.py +83 -0
  163. cognee/modules/retrieval/utils/brute_force_triplet_search.py +7 -32
  164. cognee/modules/retrieval/utils/completion.py +10 -3
  165. cognee/modules/retrieval/utils/extract_uuid_from_node.py +18 -0
  166. cognee/modules/retrieval/utils/models.py +40 -0
  167. cognee/modules/search/methods/get_search_type_tools.py +168 -0
  168. cognee/modules/search/methods/no_access_control_search.py +47 -0
  169. cognee/modules/search/methods/search.py +239 -118
  170. cognee/modules/search/types/SearchResult.py +21 -0
  171. cognee/modules/search/types/SearchType.py +3 -0
  172. cognee/modules/search/types/__init__.py +1 -0
  173. cognee/modules/search/utils/__init__.py +2 -0
  174. cognee/modules/search/utils/prepare_search_result.py +41 -0
  175. cognee/modules/search/utils/transform_context_to_graph.py +38 -0
  176. cognee/modules/settings/get_settings.py +2 -2
  177. cognee/modules/sync/__init__.py +1 -0
  178. cognee/modules/sync/methods/__init__.py +23 -0
  179. cognee/modules/sync/methods/create_sync_operation.py +53 -0
  180. cognee/modules/sync/methods/get_sync_operation.py +107 -0
  181. cognee/modules/sync/methods/update_sync_operation.py +248 -0
  182. cognee/modules/sync/models/SyncOperation.py +142 -0
  183. cognee/modules/sync/models/__init__.py +3 -0
  184. cognee/modules/users/__init__.py +0 -1
  185. cognee/modules/users/methods/__init__.py +4 -1
  186. cognee/modules/users/methods/create_user.py +26 -1
  187. cognee/modules/users/methods/get_authenticated_user.py +36 -42
  188. cognee/modules/users/methods/get_default_user.py +3 -1
  189. cognee/modules/users/permissions/methods/get_specific_user_permission_datasets.py +2 -1
  190. cognee/root_dir.py +19 -0
  191. cognee/shared/CodeGraphEntities.py +1 -0
  192. cognee/shared/logging_utils.py +143 -32
  193. cognee/shared/utils.py +0 -1
  194. cognee/tasks/codingagents/coding_rule_associations.py +127 -0
  195. cognee/tasks/graph/extract_graph_from_data.py +6 -2
  196. cognee/tasks/ingestion/save_data_item_to_storage.py +23 -0
  197. cognee/tasks/memify/__init__.py +2 -0
  198. cognee/tasks/memify/extract_subgraph.py +7 -0
  199. cognee/tasks/memify/extract_subgraph_chunks.py +11 -0
  200. cognee/tasks/repo_processor/get_local_dependencies.py +2 -0
  201. cognee/tasks/repo_processor/get_repo_file_dependencies.py +144 -47
  202. cognee/tasks/storage/add_data_points.py +33 -3
  203. cognee/tasks/temporal_graph/__init__.py +1 -0
  204. cognee/tasks/temporal_graph/add_entities_to_event.py +85 -0
  205. cognee/tasks/temporal_graph/enrich_events.py +34 -0
  206. cognee/tasks/temporal_graph/extract_events_and_entities.py +32 -0
  207. cognee/tasks/temporal_graph/extract_knowledge_graph_from_events.py +41 -0
  208. cognee/tasks/temporal_graph/models.py +49 -0
  209. cognee/tests/integration/cli/__init__.py +3 -0
  210. cognee/tests/integration/cli/test_cli_integration.py +331 -0
  211. cognee/tests/integration/documents/PdfDocument_test.py +2 -2
  212. cognee/tests/integration/documents/TextDocument_test.py +2 -4
  213. cognee/tests/integration/documents/UnstructuredDocument_test.py +5 -8
  214. cognee/tests/{test_deletion.py → test_delete_hard.py} +0 -37
  215. cognee/tests/test_delete_soft.py +85 -0
  216. cognee/tests/test_kuzu.py +2 -2
  217. cognee/tests/test_neo4j.py +2 -2
  218. cognee/tests/test_permissions.py +3 -3
  219. cognee/tests/test_relational_db_migration.py +7 -5
  220. cognee/tests/test_search_db.py +136 -23
  221. cognee/tests/test_temporal_graph.py +167 -0
  222. cognee/tests/unit/api/__init__.py +1 -0
  223. cognee/tests/unit/api/test_conditional_authentication_endpoints.py +246 -0
  224. cognee/tests/unit/cli/__init__.py +3 -0
  225. cognee/tests/unit/cli/test_cli_commands.py +483 -0
  226. cognee/tests/unit/cli/test_cli_edge_cases.py +625 -0
  227. cognee/tests/unit/cli/test_cli_main.py +173 -0
  228. cognee/tests/unit/cli/test_cli_runner.py +62 -0
  229. cognee/tests/unit/cli/test_cli_utils.py +127 -0
  230. cognee/tests/unit/modules/retrieval/chunks_retriever_test.py +18 -2
  231. cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py +12 -15
  232. cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +10 -15
  233. cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py +4 -3
  234. cognee/tests/unit/modules/retrieval/insights_retriever_test.py +4 -2
  235. cognee/tests/unit/modules/retrieval/rag_completion_retriever_test.py +18 -2
  236. cognee/tests/unit/modules/retrieval/temporal_retriever_test.py +225 -0
  237. cognee/tests/unit/modules/users/__init__.py +1 -0
  238. cognee/tests/unit/modules/users/test_conditional_authentication.py +277 -0
  239. cognee/tests/unit/processing/utils/utils_test.py +20 -1
  240. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/METADATA +13 -9
  241. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/RECORD +247 -135
  242. cognee-0.3.0.dist-info/entry_points.txt +2 -0
  243. cognee/infrastructure/databases/graph/networkx/adapter.py +0 -1017
  244. cognee/infrastructure/pipeline/models/Operation.py +0 -60
  245. cognee/notebooks/github_analysis_step_by_step.ipynb +0 -37
  246. cognee/tests/tasks/descriptive_metrics/networkx_metrics_test.py +0 -7
  247. cognee/tests/unit/modules/search/search_methods_test.py +0 -223
  248. /cognee/{infrastructure/databases/graph/networkx → api/v1/memify}/__init__.py +0 -0
  249. /cognee/{infrastructure/pipeline/models → tasks/codingagents}/__init__.py +0 -0
  250. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/WHEEL +0 -0
  251. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/licenses/LICENSE +0 -0
  252. {cognee-0.2.3.dev1.dist-info → cognee-0.3.0.dist-info}/licenses/NOTICE.md +0 -0
@@ -0,0 +1,173 @@
1
+ """
2
+ Tests for the main CLI entry point and command discovery.
3
+ """
4
+
5
+ import pytest
6
+ import argparse
7
+ from unittest.mock import patch, MagicMock
8
+ from cognee.cli._cognee import main, _discover_commands, _create_parser
9
+ from cognee.cli.exceptions import CliCommandException, CliCommandInnerException
10
+
11
+
12
+ class TestCliMain:
13
+ """Test the main CLI functionality"""
14
+
15
+ def test_discover_commands(self):
16
+ """Test that all expected commands are discovered"""
17
+ commands = _discover_commands()
18
+
19
+ # Check that we get command classes back
20
+ assert len(commands) > 0
21
+
22
+ # Check that we have the expected commands
23
+ command_strings = []
24
+ for command_class in commands:
25
+ command = command_class()
26
+ command_strings.append(command.command_string)
27
+
28
+ expected_commands = ["add", "search", "cognify", "delete", "config"]
29
+ for expected_command in expected_commands:
30
+ assert expected_command in command_strings
31
+
32
+ def test_create_parser(self):
33
+ """Test parser creation and command installation"""
34
+ parser, installed_commands = _create_parser()
35
+
36
+ # Check parser is created
37
+ assert isinstance(parser, argparse.ArgumentParser)
38
+
39
+ # Check commands are installed
40
+ expected_commands = ["add", "search", "cognify", "delete", "config"]
41
+ for expected_command in expected_commands:
42
+ assert expected_command in installed_commands
43
+
44
+ # Check parser has version argument
45
+ actions = [action.dest for action in parser._actions]
46
+ assert "version" in actions
47
+
48
+ @patch("cognee.cli._cognee._create_parser")
49
+ def test_main_no_command(self, mock_create_parser):
50
+ """Test main function when no command is provided"""
51
+ mock_parser = MagicMock()
52
+ mock_parser.parse_args.return_value = MagicMock(command=None)
53
+ mock_create_parser.return_value = (mock_parser, {})
54
+
55
+ result = main()
56
+
57
+ assert result == -1
58
+ mock_parser.print_help.assert_called_once()
59
+
60
+ @patch("cognee.cli._cognee._create_parser")
61
+ def test_main_with_valid_command(self, mock_create_parser):
62
+ """Test main function with a valid command"""
63
+ mock_command = MagicMock()
64
+ mock_command.execute.return_value = None
65
+
66
+ mock_parser = MagicMock()
67
+ mock_args = MagicMock(command="test")
68
+ mock_parser.parse_args.return_value = mock_args
69
+
70
+ mock_create_parser.return_value = (mock_parser, {"test": mock_command})
71
+
72
+ result = main()
73
+
74
+ assert result == 0
75
+ mock_command.execute.assert_called_once_with(mock_args)
76
+
77
+ @patch("cognee.cli._cognee._create_parser")
78
+ @patch("cognee.cli.debug.is_debug_enabled")
79
+ def test_main_with_command_exception(self, mock_debug, mock_create_parser):
80
+ """Test main function when command raises exception"""
81
+ mock_debug.return_value = False
82
+
83
+ mock_command = MagicMock()
84
+ mock_command.execute.side_effect = CliCommandException("Test error", error_code=2)
85
+
86
+ mock_parser = MagicMock()
87
+ mock_args = MagicMock(command="test")
88
+ mock_parser.parse_args.return_value = mock_args
89
+
90
+ mock_create_parser.return_value = (mock_parser, {"test": mock_command})
91
+
92
+ result = main()
93
+
94
+ assert result == 2
95
+
96
+ @patch("cognee.cli._cognee._create_parser")
97
+ @patch("cognee.cli.debug.is_debug_enabled")
98
+ def test_main_with_generic_exception(self, mock_debug, mock_create_parser):
99
+ """Test main function when command raises generic exception"""
100
+ mock_debug.return_value = False
101
+
102
+ mock_command = MagicMock()
103
+ mock_command.execute.side_effect = Exception("Generic error")
104
+
105
+ mock_parser = MagicMock()
106
+ mock_args = MagicMock(command="test")
107
+ mock_parser.parse_args.return_value = mock_args
108
+
109
+ mock_create_parser.return_value = (mock_parser, {"test": mock_command})
110
+
111
+ result = main()
112
+
113
+ assert result == -1
114
+
115
+ @patch("cognee.cli._cognee._create_parser")
116
+ @patch("cognee.cli.debug.is_debug_enabled")
117
+ def test_main_debug_mode_reraises_exception(self, mock_debug, mock_create_parser):
118
+ """Test main function reraises exceptions in debug mode"""
119
+ mock_debug.return_value = True
120
+
121
+ test_exception = CliCommandException(
122
+ "Test error", error_code=2, raiseable_exception=ValueError("Inner error")
123
+ )
124
+
125
+ mock_command = MagicMock()
126
+ mock_command.execute.side_effect = test_exception
127
+
128
+ mock_parser = MagicMock()
129
+ mock_args = MagicMock(command="test")
130
+ mock_parser.parse_args.return_value = mock_args
131
+
132
+ mock_create_parser.return_value = (mock_parser, {"test": mock_command})
133
+
134
+ with pytest.raises(ValueError, match="Inner error"):
135
+ main()
136
+
137
+ def test_version_argument(self):
138
+ """Test that version argument is properly configured"""
139
+ parser, _ = _create_parser()
140
+
141
+ # Check that version action exists
142
+ version_actions = [action for action in parser._actions if action.dest == "version"]
143
+ assert len(version_actions) == 1
144
+
145
+ version_action = version_actions[0]
146
+ assert "cognee" in version_action.version
147
+
148
+ def test_debug_argument(self):
149
+ """Test that debug argument is properly configured"""
150
+ parser, _ = _create_parser()
151
+
152
+ # Check that debug action exists
153
+ debug_actions = [action for action in parser._actions if action.dest == "debug"]
154
+ assert len(debug_actions) == 1
155
+
156
+
157
+ class TestDebugAction:
158
+ """Test the DebugAction class"""
159
+
160
+ @patch("cognee.cli.debug.enable_debug")
161
+ @patch("cognee.cli.echo.note")
162
+ def test_debug_action_call(self, mock_note, mock_enable_debug):
163
+ """Test that DebugAction enables debug mode"""
164
+ from cognee.cli._cognee import DebugAction
165
+
166
+ action = DebugAction([])
167
+ parser = MagicMock()
168
+ namespace = MagicMock()
169
+
170
+ action(parser, namespace, None)
171
+
172
+ mock_enable_debug.assert_called_once()
173
+ mock_note.assert_called_once_with("Debug mode enabled. Full stack traces will be shown.")
@@ -0,0 +1,62 @@
1
+ """
2
+ Test runner and utilities for CLI tests.
3
+ """
4
+
5
+ import pytest
6
+ import sys
7
+ from pathlib import Path
8
+
9
+
10
+ def run_cli_tests():
11
+ """Run all CLI tests"""
12
+ test_dir = Path(__file__).parent
13
+ integration_dir = test_dir.parent.parent / "integration" / "cli"
14
+
15
+ cli_unit_test_files = [
16
+ "test_cli_main.py",
17
+ "test_cli_commands.py",
18
+ "test_cli_utils.py",
19
+ "test_cli_edge_cases.py",
20
+ ]
21
+
22
+ cli_integration_test_files = ["test_cli_integration.py"]
23
+
24
+ # Run tests with pytest
25
+ args = ["-v", "--tb=short"]
26
+
27
+ # Add unit tests
28
+ for test_file in cli_unit_test_files:
29
+ test_path = test_dir / test_file
30
+ if test_path.exists():
31
+ args.append(str(test_path))
32
+
33
+ # Add integration tests
34
+ for test_file in cli_integration_test_files:
35
+ test_path = integration_dir / test_file
36
+ if test_path.exists():
37
+ args.append(str(test_path))
38
+
39
+ return pytest.main(args)
40
+
41
+
42
+ def run_specific_cli_test(test_file):
43
+ """Run a specific CLI test file"""
44
+ test_dir = Path(__file__).parent
45
+ test_path = test_dir / test_file
46
+
47
+ if not test_path.exists():
48
+ print(f"Test file {test_file} not found")
49
+ return 1
50
+
51
+ return pytest.main(["-v", "--tb=short", str(test_path)])
52
+
53
+
54
+ if __name__ == "__main__":
55
+ if len(sys.argv) > 1:
56
+ # Run specific test file
57
+ exit_code = run_specific_cli_test(sys.argv[1])
58
+ else:
59
+ # Run all CLI tests
60
+ exit_code = run_cli_tests()
61
+
62
+ sys.exit(exit_code)
@@ -0,0 +1,127 @@
1
+ """
2
+ Tests for CLI utility functions and helper modules.
3
+ """
4
+
5
+ from cognee.cli import debug
6
+ from cognee.cli.config import (
7
+ CLI_DESCRIPTION,
8
+ DEFAULT_DOCS_URL,
9
+ COMMAND_DESCRIPTIONS,
10
+ SEARCH_TYPE_CHOICES,
11
+ CHUNKER_CHOICES,
12
+ OUTPUT_FORMAT_CHOICES,
13
+ )
14
+ from cognee.cli._cognee import _discover_commands
15
+
16
+
17
+ class TestCliConfig:
18
+ """Test CLI configuration constants"""
19
+
20
+ def test_cli_description_exists(self):
21
+ """Test that CLI description is defined"""
22
+ assert CLI_DESCRIPTION
23
+ assert isinstance(CLI_DESCRIPTION, str)
24
+ assert "cognee" in CLI_DESCRIPTION.lower()
25
+
26
+ def test_default_docs_url_exists(self):
27
+ """Test that default docs URL is defined"""
28
+ assert DEFAULT_DOCS_URL
29
+ assert isinstance(DEFAULT_DOCS_URL, str)
30
+ assert DEFAULT_DOCS_URL.startswith("https://")
31
+ assert "cognee.ai" in DEFAULT_DOCS_URL
32
+
33
+ def test_command_descriptions_complete(self):
34
+ """Test that all expected commands have descriptions"""
35
+ commands = _discover_commands()
36
+ assert len(commands) > 0
37
+
38
+ expected_commands = []
39
+ for command_class in commands:
40
+ command = command_class()
41
+ expected_commands.append(command.command_string)
42
+
43
+ for command in expected_commands:
44
+ assert command in COMMAND_DESCRIPTIONS
45
+ assert isinstance(COMMAND_DESCRIPTIONS[command], str)
46
+ assert len(COMMAND_DESCRIPTIONS[command]) > 0
47
+
48
+ def test_search_type_choices_valid(self):
49
+ """Test that search type choices are valid"""
50
+ assert isinstance(SEARCH_TYPE_CHOICES, list)
51
+ assert len(SEARCH_TYPE_CHOICES) > 0
52
+
53
+ expected_types = [
54
+ "GRAPH_COMPLETION",
55
+ "RAG_COMPLETION",
56
+ "INSIGHTS",
57
+ "CHUNKS",
58
+ "SUMMARIES",
59
+ "CODE",
60
+ "CYPHER",
61
+ ]
62
+
63
+ for expected_type in expected_types:
64
+ assert expected_type in SEARCH_TYPE_CHOICES
65
+
66
+ def test_chunker_choices_valid(self):
67
+ """Test that chunker choices are valid"""
68
+ assert isinstance(CHUNKER_CHOICES, list)
69
+ assert len(CHUNKER_CHOICES) > 0
70
+ assert "TextChunker" in CHUNKER_CHOICES
71
+ assert "LangchainChunker" in CHUNKER_CHOICES
72
+
73
+ def test_output_format_choices_valid(self):
74
+ """Test that output format choices are valid"""
75
+ assert isinstance(OUTPUT_FORMAT_CHOICES, list)
76
+ assert len(OUTPUT_FORMAT_CHOICES) > 0
77
+
78
+ expected_formats = ["json", "pretty", "simple"]
79
+ for expected_format in expected_formats:
80
+ assert expected_format in OUTPUT_FORMAT_CHOICES
81
+
82
+
83
+ class TestCliReference:
84
+ """Test CLI reference protocol"""
85
+
86
+ def test_supports_cli_command_protocol(self):
87
+ """Test that SupportsCliCommand protocol is properly defined"""
88
+ from cognee.cli.reference import SupportsCliCommand
89
+
90
+ # Test that it's a protocol
91
+ assert hasattr(SupportsCliCommand, "__annotations__")
92
+
93
+ # Test required attributes
94
+ annotations = SupportsCliCommand.__annotations__
95
+ assert "command_string" in annotations
96
+ assert "help_string" in annotations
97
+ assert "description" in annotations
98
+ assert "docs_url" in annotations
99
+
100
+ def test_protocol_methods(self):
101
+ """Test that protocol defines required methods"""
102
+ from cognee.cli.reference import SupportsCliCommand
103
+ import inspect
104
+
105
+ # Get abstract methods
106
+ abstract_methods = []
107
+ for name, method in inspect.getmembers(SupportsCliCommand, predicate=inspect.ismethod):
108
+ if getattr(method, "__isabstractmethod__", False):
109
+ abstract_methods.append(name)
110
+
111
+ # Should have abstract methods for configure_parser and execute
112
+ method_names = [name for name, _ in inspect.getmembers(SupportsCliCommand)]
113
+ assert "configure_parser" in method_names
114
+ assert "execute" in method_names
115
+
116
+
117
+ class TestCliUtilityFunctions:
118
+ """Test utility functions and edge cases"""
119
+
120
+ def test_multiple_debug_enable_calls(self):
121
+ """Test multiple calls to enable_debug"""
122
+ debug.enable_debug()
123
+ debug.enable_debug() # Should not cause issues
124
+ assert debug.is_debug_enabled() is True
125
+
126
+ # Reset for other tests
127
+ debug._debug_enabled = False
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import pytest
3
3
  import pathlib
4
-
4
+ from typing import List
5
5
  import cognee
6
6
  from cognee.low_level import setup
7
7
  from cognee.tasks.storage import add_data_points
@@ -10,6 +10,20 @@ from cognee.modules.chunking.models import DocumentChunk
10
10
  from cognee.modules.data.processing.document_types import TextDocument
11
11
  from cognee.modules.retrieval.exceptions.exceptions import NoDataError
12
12
  from cognee.modules.retrieval.chunks_retriever import ChunksRetriever
13
+ from cognee.infrastructure.engine import DataPoint
14
+ from cognee.modules.data.processing.document_types import Document
15
+ from cognee.modules.engine.models import Entity
16
+
17
+
18
+ class DocumentChunkWithEntities(DataPoint):
19
+ text: str
20
+ chunk_size: int
21
+ chunk_index: int
22
+ cut_type: str
23
+ is_part_of: Document
24
+ contains: List[Entity] = None
25
+
26
+ metadata: dict = {"index_fields": ["text"]}
13
27
 
14
28
 
15
29
  class TestChunksRetriever:
@@ -179,7 +193,9 @@ class TestChunksRetriever:
179
193
  await retriever.get_context("Christina Mayer")
180
194
 
181
195
  vector_engine = get_vector_engine()
182
- await vector_engine.create_collection("DocumentChunk_text", payload_schema=DocumentChunk)
196
+ await vector_engine.create_collection(
197
+ "DocumentChunk_text", payload_schema=DocumentChunkWithEntities
198
+ )
183
199
 
184
200
  context = await retriever.get_context("Christina Mayer")
185
201
  assert len(context) == 0, "Found chunks when none should exist"
@@ -6,6 +6,7 @@ from typing import Optional, Union
6
6
  import cognee
7
7
  from cognee.low_level import setup, DataPoint
8
8
  from cognee.tasks.storage import add_data_points
9
+ from cognee.modules.graph.utils import resolve_edges_to_text
9
10
  from cognee.infrastructure.databases.exceptions import DatabaseNotCreatedError
10
11
  from cognee.modules.retrieval.graph_completion_context_extension_retriever import (
11
12
  GraphCompletionContextExtensionRetriever,
@@ -51,17 +52,15 @@ class TestGraphCompletionWithContextExtensionRetriever:
51
52
 
52
53
  retriever = GraphCompletionContextExtensionRetriever()
53
54
 
54
- context = await retriever.get_context("Who works at Canva?")
55
+ context = await resolve_edges_to_text(await retriever.get_context("Who works at Canva?"))
55
56
 
56
57
  assert "Mike Broski --[works_for]--> Canva" in context, "Failed to get Mike Broski"
57
58
  assert "Christina Mayer --[works_for]--> Canva" in context, "Failed to get Christina Mayer"
58
59
 
59
60
  answer = await retriever.get_completion("Who works at Canva?")
60
61
 
61
- assert isinstance(answer, list), f"Expected list, got {type(answer).__name__}"
62
- assert all(isinstance(item, str) and item.strip() for item in answer), (
63
- "Answer must contain only non-empty strings"
64
- )
62
+ assert isinstance(answer, str), f"Expected string, got {type(answer).__name__}"
63
+ assert answer.strip(), "Answer must contain only non-empty strings"
65
64
 
66
65
  @pytest.mark.asyncio
67
66
  async def test_graph_completion_extension_context_complex(self):
@@ -129,7 +128,9 @@ class TestGraphCompletionWithContextExtensionRetriever:
129
128
 
130
129
  retriever = GraphCompletionContextExtensionRetriever(top_k=20)
131
130
 
132
- context = await retriever.get_context("Who works at Figma?")
131
+ context = await resolve_edges_to_text(
132
+ await retriever.get_context("Who works at Figma and drives Tesla?")
133
+ )
133
134
 
134
135
  print(context)
135
136
 
@@ -139,10 +140,8 @@ class TestGraphCompletionWithContextExtensionRetriever:
139
140
 
140
141
  answer = await retriever.get_completion("Who works at Figma?")
141
142
 
142
- assert isinstance(answer, list), f"Expected list, got {type(answer).__name__}"
143
- assert all(isinstance(item, str) and item.strip() for item in answer), (
144
- "Answer must contain only non-empty strings"
145
- )
143
+ assert isinstance(answer, str), f"Expected string, got {type(answer).__name__}"
144
+ assert answer.strip(), "Answer must contain only non-empty strings"
146
145
 
147
146
  @pytest.mark.asyncio
148
147
  async def test_get_graph_completion_extension_context_on_empty_graph(self):
@@ -168,11 +167,9 @@ class TestGraphCompletionWithContextExtensionRetriever:
168
167
  await setup()
169
168
 
170
169
  context = await retriever.get_context("Who works at Figma?")
171
- assert context == "", "Context should be empty on an empty graph"
170
+ assert context == [], "Context should be empty on an empty graph"
172
171
 
173
172
  answer = await retriever.get_completion("Who works at Figma?")
174
173
 
175
- assert isinstance(answer, list), f"Expected list, got {type(answer).__name__}"
176
- assert all(isinstance(item, str) and item.strip() for item in answer), (
177
- "Answer must contain only non-empty strings"
178
- )
174
+ assert isinstance(answer, str), f"Expected string, got {type(answer).__name__}"
175
+ assert answer.strip(), "Answer must contain only non-empty strings"
@@ -5,6 +5,7 @@ from typing import Optional, Union
5
5
 
6
6
  import cognee
7
7
  from cognee.low_level import setup, DataPoint
8
+ from cognee.modules.graph.utils import resolve_edges_to_text
8
9
  from cognee.tasks.storage import add_data_points
9
10
  from cognee.infrastructure.databases.exceptions import DatabaseNotCreatedError
10
11
  from cognee.modules.retrieval.graph_completion_cot_retriever import GraphCompletionCotRetriever
@@ -47,17 +48,15 @@ class TestGraphCompletionCoTRetriever:
47
48
 
48
49
  retriever = GraphCompletionCotRetriever()
49
50
 
50
- context = await retriever.get_context("Who works at Canva?")
51
+ context = await resolve_edges_to_text(await retriever.get_context("Who works at Canva?"))
51
52
 
52
53
  assert "Mike Broski --[works_for]--> Canva" in context, "Failed to get Mike Broski"
53
54
  assert "Christina Mayer --[works_for]--> Canva" in context, "Failed to get Christina Mayer"
54
55
 
55
56
  answer = await retriever.get_completion("Who works at Canva?")
56
57
 
57
- assert isinstance(answer, list), f"Expected list, got {type(answer).__name__}"
58
- assert all(isinstance(item, str) and item.strip() for item in answer), (
59
- "Answer must contain only non-empty strings"
60
- )
58
+ assert isinstance(answer, str), f"Expected string, got {type(answer).__name__}"
59
+ assert answer.strip(), "Answer must contain only non-empty strings"
61
60
 
62
61
  @pytest.mark.asyncio
63
62
  async def test_graph_completion_cot_context_complex(self):
@@ -124,7 +123,7 @@ class TestGraphCompletionCoTRetriever:
124
123
 
125
124
  retriever = GraphCompletionCotRetriever(top_k=20)
126
125
 
127
- context = await retriever.get_context("Who works at Figma?")
126
+ context = await resolve_edges_to_text(await retriever.get_context("Who works at Figma?"))
128
127
 
129
128
  print(context)
130
129
 
@@ -134,10 +133,8 @@ class TestGraphCompletionCoTRetriever:
134
133
 
135
134
  answer = await retriever.get_completion("Who works at Figma?")
136
135
 
137
- assert isinstance(answer, list), f"Expected list, got {type(answer).__name__}"
138
- assert all(isinstance(item, str) and item.strip() for item in answer), (
139
- "Answer must contain only non-empty strings"
140
- )
136
+ assert isinstance(answer, str), f"Expected string, got {type(answer).__name__}"
137
+ assert answer.strip(), "Answer must contain only non-empty strings"
141
138
 
142
139
  @pytest.mark.asyncio
143
140
  async def test_get_graph_completion_cot_context_on_empty_graph(self):
@@ -163,11 +160,9 @@ class TestGraphCompletionCoTRetriever:
163
160
  await setup()
164
161
 
165
162
  context = await retriever.get_context("Who works at Figma?")
166
- assert context == "", "Context should be empty on an empty graph"
163
+ assert context == [], "Context should be empty on an empty graph"
167
164
 
168
165
  answer = await retriever.get_completion("Who works at Figma?")
169
166
 
170
- assert isinstance(answer, list), f"Expected list, got {type(answer).__name__}"
171
- assert all(isinstance(item, str) and item.strip() for item in answer), (
172
- "Answer must contain only non-empty strings"
173
- )
167
+ assert isinstance(answer, str), f"Expected string, got {type(answer).__name__}"
168
+ assert answer.strip(), "Answer must contain only non-empty strings"
@@ -5,6 +5,7 @@ from typing import Optional, Union
5
5
 
6
6
  import cognee
7
7
  from cognee.low_level import setup, DataPoint
8
+ from cognee.modules.graph.utils import resolve_edges_to_text
8
9
  from cognee.tasks.storage import add_data_points
9
10
  from cognee.infrastructure.databases.exceptions import DatabaseNotCreatedError
10
11
  from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
@@ -67,7 +68,7 @@ class TestGraphCompletionRetriever:
67
68
 
68
69
  retriever = GraphCompletionRetriever()
69
70
 
70
- context = await retriever.get_context("Who works at Canva?")
71
+ context = await resolve_edges_to_text(await retriever.get_context("Who works at Canva?"))
71
72
 
72
73
  # Ensure the top-level sections are present
73
74
  assert "Nodes:" in context, "Missing 'Nodes:' section in context"
@@ -191,7 +192,7 @@ class TestGraphCompletionRetriever:
191
192
 
192
193
  retriever = GraphCompletionRetriever(top_k=20)
193
194
 
194
- context = await retriever.get_context("Who works at Figma?")
195
+ context = await resolve_edges_to_text(await retriever.get_context("Who works at Figma?"))
195
196
 
196
197
  print(context)
197
198
 
@@ -223,4 +224,4 @@ class TestGraphCompletionRetriever:
223
224
  await setup()
224
225
 
225
226
  context = await retriever.get_context("Who works at Figma?")
226
- assert context == "", "Context should be empty on an empty graph"
227
+ assert context == [], "Context should be empty on an empty graph"
@@ -82,7 +82,7 @@ class TestInsightsRetriever:
82
82
 
83
83
  context = await retriever.get_context("Mike")
84
84
 
85
- assert context[0][0]["name"] == "Mike Broski", "Failed to get Mike Broski"
85
+ assert context[0].node1.attributes["name"] == "Mike Broski", "Failed to get Mike Broski"
86
86
 
87
87
  @pytest.mark.asyncio
88
88
  async def test_insights_context_complex(self):
@@ -222,7 +222,9 @@ class TestInsightsRetriever:
222
222
 
223
223
  context = await retriever.get_context("Christina")
224
224
 
225
- assert context[0][0]["name"] == "Christina Mayer", "Failed to get Christina Mayer"
225
+ assert context[0].node1.attributes["name"] == "Christina Mayer", (
226
+ "Failed to get Christina Mayer"
227
+ )
226
228
 
227
229
  @pytest.mark.asyncio
228
230
  async def test_insights_context_on_empty_graph(self):
@@ -1,7 +1,7 @@
1
1
  import os
2
+ from typing import List
2
3
  import pytest
3
4
  import pathlib
4
-
5
5
  import cognee
6
6
  from cognee.low_level import setup
7
7
  from cognee.tasks.storage import add_data_points
@@ -10,6 +10,20 @@ from cognee.modules.chunking.models import DocumentChunk
10
10
  from cognee.modules.data.processing.document_types import TextDocument
11
11
  from cognee.modules.retrieval.exceptions.exceptions import NoDataError
12
12
  from cognee.modules.retrieval.completion_retriever import CompletionRetriever
13
+ from cognee.infrastructure.engine import DataPoint
14
+ from cognee.modules.data.processing.document_types import Document
15
+ from cognee.modules.engine.models import Entity
16
+
17
+
18
+ class DocumentChunkWithEntities(DataPoint):
19
+ text: str
20
+ chunk_size: int
21
+ chunk_index: int
22
+ cut_type: str
23
+ is_part_of: Document
24
+ contains: List[Entity] = None
25
+
26
+ metadata: dict = {"index_fields": ["text"]}
13
27
 
14
28
 
15
29
  class TestRAGCompletionRetriever:
@@ -182,7 +196,9 @@ class TestRAGCompletionRetriever:
182
196
  await retriever.get_context("Christina Mayer")
183
197
 
184
198
  vector_engine = get_vector_engine()
185
- await vector_engine.create_collection("DocumentChunk_text", payload_schema=DocumentChunk)
199
+ await vector_engine.create_collection(
200
+ "DocumentChunk_text", payload_schema=DocumentChunkWithEntities
201
+ )
186
202
 
187
203
  context = await retriever.get_context("Christina Mayer")
188
204
  assert context == "", "Returned context should be empty on an empty graph"