cognee 0.2.3.dev0__py3-none-any.whl → 0.2.4__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.
- cognee/__main__.py +4 -0
- cognee/api/v1/add/add.py +18 -11
- cognee/api/v1/cognify/code_graph_pipeline.py +7 -1
- cognee/api/v1/cognify/cognify.py +22 -115
- cognee/api/v1/cognify/routers/get_cognify_router.py +11 -3
- cognee/api/v1/config/config.py +5 -13
- cognee/api/v1/datasets/routers/get_datasets_router.py +2 -2
- cognee/api/v1/delete/delete.py +1 -1
- cognee/api/v1/exceptions/__init__.py +13 -0
- cognee/api/v1/{delete → exceptions}/exceptions.py +15 -12
- cognee/api/v1/responses/default_tools.py +4 -0
- cognee/api/v1/responses/dispatch_function.py +6 -1
- cognee/api/v1/responses/models.py +1 -1
- cognee/api/v1/search/search.py +6 -7
- cognee/cli/__init__.py +10 -0
- cognee/cli/_cognee.py +180 -0
- cognee/cli/commands/__init__.py +1 -0
- cognee/cli/commands/add_command.py +80 -0
- cognee/cli/commands/cognify_command.py +128 -0
- cognee/cli/commands/config_command.py +225 -0
- cognee/cli/commands/delete_command.py +80 -0
- cognee/cli/commands/search_command.py +149 -0
- cognee/cli/config.py +33 -0
- cognee/cli/debug.py +21 -0
- cognee/cli/echo.py +45 -0
- cognee/cli/exceptions.py +23 -0
- cognee/cli/minimal_cli.py +97 -0
- cognee/cli/reference.py +26 -0
- cognee/cli/suppress_logging.py +12 -0
- cognee/eval_framework/corpus_builder/corpus_builder_executor.py +2 -2
- cognee/eval_framework/eval_config.py +1 -1
- cognee/exceptions/__init__.py +5 -5
- cognee/exceptions/exceptions.py +37 -17
- cognee/infrastructure/data/exceptions/__init__.py +7 -0
- cognee/infrastructure/data/exceptions/exceptions.py +22 -0
- cognee/infrastructure/data/utils/extract_keywords.py +3 -3
- cognee/infrastructure/databases/exceptions/__init__.py +3 -0
- cognee/infrastructure/databases/exceptions/exceptions.py +57 -9
- cognee/infrastructure/databases/graph/get_graph_engine.py +4 -9
- cognee/infrastructure/databases/graph/kuzu/adapter.py +64 -2
- cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +49 -0
- cognee/infrastructure/databases/graph/neptune_driver/exceptions.py +15 -10
- cognee/infrastructure/databases/hybrid/falkordb/FalkorDBAdapter.py +2 -2
- cognee/infrastructure/databases/hybrid/neptune_analytics/NeptuneAnalyticsAdapter.py +4 -5
- cognee/infrastructure/databases/vector/chromadb/ChromaDBAdapter.py +2 -2
- cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +5 -3
- cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +17 -8
- cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +5 -5
- cognee/infrastructure/databases/vector/embeddings/config.py +2 -2
- cognee/infrastructure/databases/vector/embeddings/get_embedding_engine.py +6 -6
- cognee/infrastructure/databases/vector/exceptions/exceptions.py +3 -3
- cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +2 -2
- cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py +4 -3
- cognee/infrastructure/files/utils/get_data_file_path.py +14 -9
- cognee/infrastructure/files/utils/get_file_metadata.py +2 -1
- cognee/infrastructure/llm/LLMGateway.py +14 -5
- cognee/infrastructure/llm/config.py +5 -5
- cognee/infrastructure/llm/exceptions.py +30 -2
- cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py +16 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/extraction/knowledge_graph/extract_content_graph.py +19 -15
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +5 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +6 -6
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +2 -2
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +24 -15
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +6 -4
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +9 -7
- cognee/infrastructure/llm/tokenizer/Gemini/adapter.py +2 -2
- cognee/infrastructure/llm/tokenizer/HuggingFace/adapter.py +3 -3
- cognee/infrastructure/llm/tokenizer/Mistral/adapter.py +3 -3
- cognee/infrastructure/llm/tokenizer/TikToken/adapter.py +6 -6
- cognee/infrastructure/llm/utils.py +7 -7
- cognee/modules/data/exceptions/exceptions.py +18 -5
- cognee/modules/data/methods/__init__.py +2 -0
- cognee/modules/data/methods/create_authorized_dataset.py +19 -0
- cognee/modules/data/methods/delete_data.py +2 -4
- cognee/modules/data/methods/get_authorized_dataset.py +11 -5
- cognee/modules/data/methods/get_authorized_dataset_by_name.py +16 -0
- cognee/modules/data/methods/load_or_create_datasets.py +2 -20
- cognee/modules/data/processing/document_types/exceptions/exceptions.py +2 -2
- cognee/modules/graph/cognee_graph/CogneeGraph.py +6 -4
- cognee/modules/graph/cognee_graph/CogneeGraphElements.py +5 -10
- cognee/modules/graph/exceptions/__init__.py +2 -0
- cognee/modules/graph/exceptions/exceptions.py +25 -3
- cognee/modules/graph/methods/get_formatted_graph_data.py +3 -2
- cognee/modules/ingestion/exceptions/exceptions.py +2 -2
- cognee/modules/ontology/exceptions/exceptions.py +4 -4
- cognee/modules/pipelines/__init__.py +1 -1
- cognee/modules/pipelines/exceptions/exceptions.py +2 -2
- cognee/modules/pipelines/exceptions/tasks.py +18 -0
- cognee/modules/pipelines/layers/__init__.py +1 -0
- cognee/modules/pipelines/layers/check_pipeline_run_qualification.py +59 -0
- cognee/modules/pipelines/layers/pipeline_execution_mode.py +127 -0
- cognee/modules/pipelines/layers/reset_dataset_pipeline_run_status.py +12 -0
- cognee/modules/pipelines/layers/resolve_authorized_user_dataset.py +34 -0
- cognee/modules/pipelines/layers/resolve_authorized_user_datasets.py +55 -0
- cognee/modules/pipelines/layers/setup_and_check_environment.py +41 -0
- cognee/modules/pipelines/layers/validate_pipeline_tasks.py +20 -0
- cognee/modules/pipelines/methods/__init__.py +2 -0
- cognee/modules/pipelines/methods/get_pipeline_runs_by_dataset.py +34 -0
- cognee/modules/pipelines/methods/reset_pipeline_run_status.py +16 -0
- cognee/modules/pipelines/operations/__init__.py +0 -1
- cognee/modules/pipelines/operations/log_pipeline_run_initiated.py +1 -1
- cognee/modules/pipelines/operations/pipeline.py +23 -138
- cognee/modules/retrieval/base_feedback.py +11 -0
- cognee/modules/retrieval/cypher_search_retriever.py +1 -9
- cognee/modules/retrieval/exceptions/exceptions.py +12 -6
- cognee/modules/retrieval/graph_completion_context_extension_retriever.py +9 -2
- cognee/modules/retrieval/graph_completion_cot_retriever.py +13 -6
- cognee/modules/retrieval/graph_completion_retriever.py +89 -5
- cognee/modules/retrieval/graph_summary_completion_retriever.py +2 -0
- cognee/modules/retrieval/natural_language_retriever.py +0 -4
- cognee/modules/retrieval/user_qa_feedback.py +83 -0
- cognee/modules/retrieval/utils/extract_uuid_from_node.py +18 -0
- cognee/modules/retrieval/utils/models.py +40 -0
- cognee/modules/search/exceptions/__init__.py +7 -0
- cognee/modules/search/exceptions/exceptions.py +15 -0
- cognee/modules/search/methods/search.py +47 -7
- cognee/modules/search/types/SearchType.py +1 -0
- cognee/modules/settings/get_settings.py +2 -2
- cognee/modules/users/exceptions/exceptions.py +6 -6
- cognee/shared/CodeGraphEntities.py +1 -0
- cognee/shared/exceptions/exceptions.py +2 -2
- cognee/shared/logging_utils.py +142 -31
- cognee/shared/utils.py +0 -1
- cognee/tasks/completion/exceptions/exceptions.py +3 -3
- cognee/tasks/documents/classify_documents.py +4 -0
- cognee/tasks/documents/exceptions/__init__.py +11 -0
- cognee/tasks/documents/exceptions/exceptions.py +36 -0
- cognee/tasks/documents/extract_chunks_from_documents.py +8 -2
- cognee/tasks/graph/exceptions/__init__.py +12 -0
- cognee/tasks/graph/exceptions/exceptions.py +41 -0
- cognee/tasks/graph/extract_graph_from_data.py +34 -2
- cognee/tasks/ingestion/exceptions/__init__.py +8 -0
- cognee/tasks/ingestion/exceptions/exceptions.py +12 -0
- cognee/tasks/ingestion/resolve_data_directories.py +5 -0
- cognee/tasks/repo_processor/get_local_dependencies.py +2 -0
- cognee/tasks/repo_processor/get_repo_file_dependencies.py +120 -48
- cognee/tasks/storage/add_data_points.py +41 -3
- cognee/tasks/storage/exceptions/__init__.py +9 -0
- cognee/tasks/storage/exceptions/exceptions.py +13 -0
- cognee/tasks/storage/index_data_points.py +1 -1
- cognee/tasks/summarization/exceptions/__init__.py +9 -0
- cognee/tasks/summarization/exceptions/exceptions.py +14 -0
- cognee/tasks/summarization/summarize_text.py +8 -1
- cognee/tests/integration/cli/__init__.py +3 -0
- cognee/tests/integration/cli/test_cli_integration.py +331 -0
- cognee/tests/integration/documents/PdfDocument_test.py +2 -2
- cognee/tests/integration/documents/TextDocument_test.py +2 -4
- cognee/tests/integration/documents/UnstructuredDocument_test.py +5 -8
- cognee/tests/test_delete_by_id.py +1 -1
- cognee/tests/{test_deletion.py → test_delete_hard.py} +0 -37
- cognee/tests/test_delete_soft.py +85 -0
- cognee/tests/test_kuzu.py +2 -2
- cognee/tests/test_neo4j.py +2 -2
- cognee/tests/test_search_db.py +126 -7
- cognee/tests/unit/cli/__init__.py +3 -0
- cognee/tests/unit/cli/test_cli_commands.py +483 -0
- cognee/tests/unit/cli/test_cli_edge_cases.py +625 -0
- cognee/tests/unit/cli/test_cli_main.py +173 -0
- cognee/tests/unit/cli/test_cli_runner.py +62 -0
- cognee/tests/unit/cli/test_cli_utils.py +127 -0
- cognee/tests/unit/modules/graph/cognee_graph_elements_test.py +5 -5
- cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py +3 -3
- cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +3 -3
- cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py +3 -3
- cognee/tests/unit/modules/search/search_methods_test.py +4 -2
- {cognee-0.2.3.dev0.dist-info → cognee-0.2.4.dist-info}/METADATA +7 -5
- {cognee-0.2.3.dev0.dist-info → cognee-0.2.4.dist-info}/RECORD +172 -121
- cognee-0.2.4.dist-info/entry_points.txt +2 -0
- cognee/infrastructure/databases/exceptions/EmbeddingException.py +0 -20
- cognee/infrastructure/databases/graph/networkx/__init__.py +0 -0
- cognee/infrastructure/databases/graph/networkx/adapter.py +0 -1017
- cognee/infrastructure/pipeline/models/Operation.py +0 -60
- cognee/infrastructure/pipeline/models/__init__.py +0 -0
- cognee/notebooks/github_analysis_step_by_step.ipynb +0 -37
- cognee/tests/tasks/descriptive_metrics/networkx_metrics_test.py +0 -7
- {cognee-0.2.3.dev0.dist-info → cognee-0.2.4.dist-info}/WHEEL +0 -0
- {cognee-0.2.3.dev0.dist-info → cognee-0.2.4.dist-info}/licenses/LICENSE +0 -0
- {cognee-0.2.3.dev0.dist-info → cognee-0.2.4.dist-info}/licenses/NOTICE.md +0 -0
cognee/tests/test_search_db.py
CHANGED
|
@@ -4,6 +4,7 @@ import pathlib
|
|
|
4
4
|
from dns.e164 import query
|
|
5
5
|
|
|
6
6
|
import cognee
|
|
7
|
+
from cognee.infrastructure.databases.graph import get_graph_engine
|
|
7
8
|
from cognee.modules.graph.cognee_graph.CogneeGraphElements import Edge
|
|
8
9
|
from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
|
|
9
10
|
from cognee.modules.retrieval.graph_completion_context_extension_retriever import (
|
|
@@ -18,6 +19,7 @@ from cognee.modules.users.methods import get_default_user
|
|
|
18
19
|
from cognee.shared.logging_utils import get_logger
|
|
19
20
|
from cognee.modules.search.types import SearchType
|
|
20
21
|
from cognee.modules.engine.models import NodeSet
|
|
22
|
+
from collections import Counter
|
|
21
23
|
|
|
22
24
|
logger = get_logger()
|
|
23
25
|
|
|
@@ -44,16 +46,16 @@ async def main():
|
|
|
44
46
|
|
|
45
47
|
await cognee.cognify([dataset_name])
|
|
46
48
|
|
|
47
|
-
context_gk = await GraphCompletionRetriever().get_context(
|
|
49
|
+
context_gk, _ = await GraphCompletionRetriever().get_context(
|
|
48
50
|
query="Next to which country is Germany located?"
|
|
49
51
|
)
|
|
50
|
-
context_gk_cot = await GraphCompletionCotRetriever().get_context(
|
|
52
|
+
context_gk_cot, _ = await GraphCompletionCotRetriever().get_context(
|
|
51
53
|
query="Next to which country is Germany located?"
|
|
52
54
|
)
|
|
53
|
-
context_gk_ext = await GraphCompletionContextExtensionRetriever().get_context(
|
|
55
|
+
context_gk_ext, _ = await GraphCompletionContextExtensionRetriever().get_context(
|
|
54
56
|
query="Next to which country is Germany located?"
|
|
55
57
|
)
|
|
56
|
-
context_gk_sum = await GraphSummaryCompletionRetriever().get_context(
|
|
58
|
+
context_gk_sum, _ = await GraphSummaryCompletionRetriever().get_context(
|
|
57
59
|
query="Next to which country is Germany located?"
|
|
58
60
|
)
|
|
59
61
|
|
|
@@ -111,19 +113,34 @@ async def main():
|
|
|
111
113
|
|
|
112
114
|
completion_gk = await cognee.search(
|
|
113
115
|
query_type=SearchType.GRAPH_COMPLETION,
|
|
114
|
-
query_text="
|
|
116
|
+
query_text="Where is germany located, next to which country?",
|
|
117
|
+
save_interaction=True,
|
|
115
118
|
)
|
|
116
119
|
completion_cot = await cognee.search(
|
|
117
120
|
query_type=SearchType.GRAPH_COMPLETION_COT,
|
|
118
|
-
query_text="
|
|
121
|
+
query_text="What is the country next to germany??",
|
|
122
|
+
save_interaction=True,
|
|
119
123
|
)
|
|
120
124
|
completion_ext = await cognee.search(
|
|
121
125
|
query_type=SearchType.GRAPH_COMPLETION_CONTEXT_EXTENSION,
|
|
122
|
-
query_text="
|
|
126
|
+
query_text="What is the name of the country next to germany",
|
|
127
|
+
save_interaction=True,
|
|
123
128
|
)
|
|
129
|
+
|
|
130
|
+
await cognee.search(
|
|
131
|
+
query_type=SearchType.FEEDBACK, query_text="This was not the best answer", last_k=1
|
|
132
|
+
)
|
|
133
|
+
|
|
124
134
|
completion_sum = await cognee.search(
|
|
125
135
|
query_type=SearchType.GRAPH_SUMMARY_COMPLETION,
|
|
126
136
|
query_text="Next to which country is Germany located?",
|
|
137
|
+
save_interaction=True,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
await cognee.search(
|
|
141
|
+
query_type=SearchType.FEEDBACK,
|
|
142
|
+
query_text="This answer was great",
|
|
143
|
+
last_k=1,
|
|
127
144
|
)
|
|
128
145
|
|
|
129
146
|
for name, completion in [
|
|
@@ -141,6 +158,108 @@ async def main():
|
|
|
141
158
|
f"{name}: expected 'netherlands' in result, got: {text!r}"
|
|
142
159
|
)
|
|
143
160
|
|
|
161
|
+
graph_engine = await get_graph_engine()
|
|
162
|
+
graph = await graph_engine.get_graph_data()
|
|
163
|
+
|
|
164
|
+
type_counts = Counter(node_data[1].get("type", {}) for node_data in graph[0])
|
|
165
|
+
|
|
166
|
+
edge_type_counts = Counter(edge_type[2] for edge_type in graph[1])
|
|
167
|
+
|
|
168
|
+
# Assert there are exactly 4 CogneeUserInteraction nodes.
|
|
169
|
+
assert type_counts.get("CogneeUserInteraction", 0) == 4, (
|
|
170
|
+
f"Expected exactly four DCogneeUserInteraction nodes, but found {type_counts.get('CogneeUserInteraction', 0)}"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Assert there is exactly two CogneeUserFeedback nodes.
|
|
174
|
+
assert type_counts.get("CogneeUserFeedback", 0) == 2, (
|
|
175
|
+
f"Expected exactly two CogneeUserFeedback nodes, but found {type_counts.get('CogneeUserFeedback', 0)}"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Assert there is exactly two NodeSet.
|
|
179
|
+
assert type_counts.get("NodeSet", 0) == 2, (
|
|
180
|
+
f"Expected exactly two NodeSet nodes, but found {type_counts.get('NodeSet', 0)}"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# Assert that there are at least 10 'used_graph_element_to_answer' edges.
|
|
184
|
+
assert edge_type_counts.get("used_graph_element_to_answer", 0) >= 10, (
|
|
185
|
+
f"Expected at least ten 'used_graph_element_to_answer' edges, but found {edge_type_counts.get('used_graph_element_to_answer', 0)}"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Assert that there are exactly 2 'gives_feedback_to' edges.
|
|
189
|
+
assert edge_type_counts.get("gives_feedback_to", 0) == 2, (
|
|
190
|
+
f"Expected exactly two 'gives_feedback_to' edges, but found {edge_type_counts.get('gives_feedback_to', 0)}"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Assert that there are at least 6 'belongs_to_set' edges.
|
|
194
|
+
assert edge_type_counts.get("belongs_to_set", 0) == 6, (
|
|
195
|
+
f"Expected at least six 'belongs_to_set' edges, but found {edge_type_counts.get('belongs_to_set', 0)}"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
nodes = graph[0]
|
|
199
|
+
|
|
200
|
+
required_fields_user_interaction = {"question", "answer", "context"}
|
|
201
|
+
required_fields_feedback = {"feedback", "sentiment"}
|
|
202
|
+
|
|
203
|
+
for node_id, data in nodes:
|
|
204
|
+
if data.get("type") == "CogneeUserInteraction":
|
|
205
|
+
assert required_fields_user_interaction.issubset(data.keys()), (
|
|
206
|
+
f"Node {node_id} is missing fields: {required_fields_user_interaction - set(data.keys())}"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
for field in required_fields_user_interaction:
|
|
210
|
+
value = data[field]
|
|
211
|
+
assert isinstance(value, str) and value.strip(), (
|
|
212
|
+
f"Node {node_id} has invalid value for '{field}': {value!r}"
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
if data.get("type") == "CogneeUserFeedback":
|
|
216
|
+
assert required_fields_feedback.issubset(data.keys()), (
|
|
217
|
+
f"Node {node_id} is missing fields: {required_fields_feedback - set(data.keys())}"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
for field in required_fields_feedback:
|
|
221
|
+
value = data[field]
|
|
222
|
+
assert isinstance(value, str) and value.strip(), (
|
|
223
|
+
f"Node {node_id} has invalid value for '{field}': {value!r}"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
await cognee.prune.prune_data()
|
|
227
|
+
await cognee.prune.prune_system(metadata=True)
|
|
228
|
+
|
|
229
|
+
await cognee.add(text_1, dataset_name)
|
|
230
|
+
|
|
231
|
+
await cognee.add([text], dataset_name)
|
|
232
|
+
|
|
233
|
+
await cognee.cognify([dataset_name])
|
|
234
|
+
|
|
235
|
+
await cognee.search(
|
|
236
|
+
query_type=SearchType.GRAPH_COMPLETION,
|
|
237
|
+
query_text="Next to which country is Germany located?",
|
|
238
|
+
save_interaction=True,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
await cognee.search(
|
|
242
|
+
query_type=SearchType.FEEDBACK,
|
|
243
|
+
query_text="This was the best answer I've ever seen",
|
|
244
|
+
last_k=1,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
await cognee.search(
|
|
248
|
+
query_type=SearchType.FEEDBACK,
|
|
249
|
+
query_text="Wow the correctness of this answer blows my mind",
|
|
250
|
+
last_k=1,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
graph = await graph_engine.get_graph_data()
|
|
254
|
+
|
|
255
|
+
edges = graph[1]
|
|
256
|
+
|
|
257
|
+
for from_node, to_node, relationship_name, properties in edges:
|
|
258
|
+
if relationship_name == "used_graph_element_to_answer":
|
|
259
|
+
assert properties["feedback_weight"] >= 6, (
|
|
260
|
+
"Feedback weight calculation is not correct, it should be more then 6."
|
|
261
|
+
)
|
|
262
|
+
|
|
144
263
|
|
|
145
264
|
if __name__ == "__main__":
|
|
146
265
|
import asyncio
|
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for individual CLI commands with proper mocking and coroutine handling.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
import sys
|
|
7
|
+
import argparse
|
|
8
|
+
import asyncio
|
|
9
|
+
from unittest.mock import patch, MagicMock, AsyncMock, ANY
|
|
10
|
+
from cognee.cli.commands.add_command import AddCommand
|
|
11
|
+
from cognee.cli.commands.search_command import SearchCommand
|
|
12
|
+
from cognee.cli.commands.cognify_command import CognifyCommand
|
|
13
|
+
from cognee.cli.commands.delete_command import DeleteCommand
|
|
14
|
+
from cognee.cli.commands.config_command import ConfigCommand
|
|
15
|
+
from cognee.cli.exceptions import CliCommandException, CliCommandInnerException
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Mock asyncio.run to properly handle coroutines
|
|
19
|
+
def _mock_run(coro):
|
|
20
|
+
# Create an event loop and run the coroutine
|
|
21
|
+
loop = asyncio.new_event_loop()
|
|
22
|
+
try:
|
|
23
|
+
return loop.run_until_complete(coro)
|
|
24
|
+
finally:
|
|
25
|
+
loop.close()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestAddCommand:
|
|
29
|
+
"""Test the AddCommand class"""
|
|
30
|
+
|
|
31
|
+
def test_command_properties(self):
|
|
32
|
+
"""Test basic command properties"""
|
|
33
|
+
command = AddCommand()
|
|
34
|
+
assert command.command_string == "add"
|
|
35
|
+
assert "Add data" in command.help_string
|
|
36
|
+
assert command.docs_url is not None
|
|
37
|
+
|
|
38
|
+
def test_configure_parser(self):
|
|
39
|
+
"""Test parser configuration"""
|
|
40
|
+
command = AddCommand()
|
|
41
|
+
parser = argparse.ArgumentParser()
|
|
42
|
+
|
|
43
|
+
command.configure_parser(parser)
|
|
44
|
+
|
|
45
|
+
# Check that required arguments are added
|
|
46
|
+
actions = {action.dest: action for action in parser._actions}
|
|
47
|
+
assert "data" in actions
|
|
48
|
+
assert "dataset_name" in actions
|
|
49
|
+
|
|
50
|
+
# Check data argument accepts multiple values
|
|
51
|
+
assert actions["data"].nargs == "+"
|
|
52
|
+
|
|
53
|
+
@patch("cognee.cli.commands.add_command.asyncio.run", side_effect=_mock_run)
|
|
54
|
+
def test_execute_single_item(self, mock_asyncio_run):
|
|
55
|
+
"""Test execute with single data item"""
|
|
56
|
+
# Mock the cognee module
|
|
57
|
+
mock_cognee = MagicMock()
|
|
58
|
+
mock_cognee.add = AsyncMock()
|
|
59
|
+
|
|
60
|
+
with patch.dict(sys.modules, {"cognee": mock_cognee}):
|
|
61
|
+
command = AddCommand()
|
|
62
|
+
args = argparse.Namespace(data=["test.txt"], dataset_name="test_dataset")
|
|
63
|
+
command.execute(args)
|
|
64
|
+
|
|
65
|
+
mock_asyncio_run.assert_called_once()
|
|
66
|
+
assert asyncio.iscoroutine(mock_asyncio_run.call_args[0][0])
|
|
67
|
+
mock_cognee.add.assert_awaited_once_with(data="test.txt", dataset_name="test_dataset")
|
|
68
|
+
|
|
69
|
+
@patch("cognee.cli.commands.add_command.asyncio.run", side_effect=_mock_run)
|
|
70
|
+
def test_execute_multiple_items(self, mock_asyncio_run):
|
|
71
|
+
"""Test execute with multiple data items"""
|
|
72
|
+
# Mock the cognee module
|
|
73
|
+
mock_cognee = MagicMock()
|
|
74
|
+
mock_cognee.add = AsyncMock()
|
|
75
|
+
|
|
76
|
+
with patch.dict(sys.modules, {"cognee": mock_cognee}):
|
|
77
|
+
command = AddCommand()
|
|
78
|
+
args = argparse.Namespace(data=["test1.txt", "test2.txt"], dataset_name="test_dataset")
|
|
79
|
+
command.execute(args)
|
|
80
|
+
|
|
81
|
+
mock_asyncio_run.assert_called_once()
|
|
82
|
+
assert asyncio.iscoroutine(mock_asyncio_run.call_args[0][0])
|
|
83
|
+
mock_cognee.add.assert_awaited_once_with(
|
|
84
|
+
data=["test1.txt", "test2.txt"], dataset_name="test_dataset"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
@patch("cognee.cli.commands.add_command.asyncio.run")
|
|
88
|
+
def test_execute_with_exception(self, mock_asyncio_run):
|
|
89
|
+
"""Test execute handles exceptions properly"""
|
|
90
|
+
command = AddCommand()
|
|
91
|
+
args = argparse.Namespace(data=["test.txt"], dataset_name="test_dataset")
|
|
92
|
+
|
|
93
|
+
mock_asyncio_run.side_effect = Exception("Test error")
|
|
94
|
+
|
|
95
|
+
with pytest.raises(CliCommandException):
|
|
96
|
+
command.execute(args)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class TestSearchCommand:
|
|
100
|
+
"""Test the SearchCommand class"""
|
|
101
|
+
|
|
102
|
+
def test_command_properties(self):
|
|
103
|
+
"""Test basic command properties"""
|
|
104
|
+
command = SearchCommand()
|
|
105
|
+
assert command.command_string == "search"
|
|
106
|
+
assert "Search and query" in command.help_string
|
|
107
|
+
assert command.docs_url is not None
|
|
108
|
+
|
|
109
|
+
def test_configure_parser(self):
|
|
110
|
+
"""Test parser configuration"""
|
|
111
|
+
command = SearchCommand()
|
|
112
|
+
parser = argparse.ArgumentParser()
|
|
113
|
+
|
|
114
|
+
command.configure_parser(parser)
|
|
115
|
+
|
|
116
|
+
# Check that required arguments are added
|
|
117
|
+
actions = {action.dest: action for action in parser._actions}
|
|
118
|
+
assert "query_text" in actions
|
|
119
|
+
assert "query_type" in actions
|
|
120
|
+
assert "datasets" in actions
|
|
121
|
+
assert "top_k" in actions
|
|
122
|
+
assert "output_format" in actions
|
|
123
|
+
|
|
124
|
+
# Check default values
|
|
125
|
+
assert actions["query_type"].default == "GRAPH_COMPLETION"
|
|
126
|
+
assert actions["top_k"].default == 10
|
|
127
|
+
assert actions["output_format"].default == "pretty"
|
|
128
|
+
|
|
129
|
+
@patch("cognee.cli.commands.search_command.asyncio.run", side_effect=_mock_run)
|
|
130
|
+
def test_execute_basic_search(self, mock_asyncio_run):
|
|
131
|
+
"""Test execute with basic search"""
|
|
132
|
+
# Mock the cognee module and SearchType
|
|
133
|
+
mock_cognee = MagicMock()
|
|
134
|
+
mock_cognee.search = AsyncMock(return_value=["result1", "result2"])
|
|
135
|
+
mock_search_type = MagicMock()
|
|
136
|
+
mock_search_type.__getitem__.return_value = "GRAPH_COMPLETION"
|
|
137
|
+
|
|
138
|
+
with patch.dict(sys.modules, {"cognee": mock_cognee}):
|
|
139
|
+
command = SearchCommand()
|
|
140
|
+
args = argparse.Namespace(
|
|
141
|
+
query_text="test query",
|
|
142
|
+
query_type="GRAPH_COMPLETION",
|
|
143
|
+
datasets=None,
|
|
144
|
+
top_k=10,
|
|
145
|
+
system_prompt=None,
|
|
146
|
+
output_format="pretty",
|
|
147
|
+
)
|
|
148
|
+
command.execute(args)
|
|
149
|
+
|
|
150
|
+
mock_asyncio_run.assert_called_once()
|
|
151
|
+
assert asyncio.iscoroutine(mock_asyncio_run.call_args[0][0])
|
|
152
|
+
mock_cognee.search.assert_awaited_once_with(
|
|
153
|
+
query_text="test query",
|
|
154
|
+
query_type=ANY,
|
|
155
|
+
datasets=None,
|
|
156
|
+
top_k=10,
|
|
157
|
+
system_prompt_path="answer_simple_question.txt",
|
|
158
|
+
)
|
|
159
|
+
# verify the enum’s name separately
|
|
160
|
+
called_enum = mock_cognee.search.await_args.kwargs["query_type"]
|
|
161
|
+
assert called_enum.name == "GRAPH_COMPLETION"
|
|
162
|
+
|
|
163
|
+
@patch("cognee.cli.commands.search_command.asyncio.run")
|
|
164
|
+
def test_execute_with_exception(self, mock_asyncio_run):
|
|
165
|
+
"""Test execute handles exceptions properly"""
|
|
166
|
+
command = SearchCommand()
|
|
167
|
+
args = argparse.Namespace(
|
|
168
|
+
query_text="test query",
|
|
169
|
+
query_type="GRAPH_COMPLETION",
|
|
170
|
+
datasets=None,
|
|
171
|
+
top_k=10,
|
|
172
|
+
system_prompt=None,
|
|
173
|
+
output_format="pretty",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
mock_asyncio_run.side_effect = Exception("Search error")
|
|
177
|
+
|
|
178
|
+
with pytest.raises(CliCommandException):
|
|
179
|
+
command.execute(args)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class TestCognifyCommand:
|
|
183
|
+
"""Test the CognifyCommand class"""
|
|
184
|
+
|
|
185
|
+
def test_command_properties(self):
|
|
186
|
+
"""Test basic command properties"""
|
|
187
|
+
command = CognifyCommand()
|
|
188
|
+
assert command.command_string == "cognify"
|
|
189
|
+
assert "Transform ingested data" in command.help_string
|
|
190
|
+
assert command.docs_url is not None
|
|
191
|
+
|
|
192
|
+
def test_configure_parser(self):
|
|
193
|
+
"""Test parser configuration"""
|
|
194
|
+
command = CognifyCommand()
|
|
195
|
+
parser = argparse.ArgumentParser()
|
|
196
|
+
|
|
197
|
+
command.configure_parser(parser)
|
|
198
|
+
|
|
199
|
+
# Check that arguments are added
|
|
200
|
+
actions = {action.dest: action for action in parser._actions}
|
|
201
|
+
assert "datasets" in actions
|
|
202
|
+
assert "chunk_size" in actions
|
|
203
|
+
assert "ontology_file" in actions
|
|
204
|
+
assert "chunker" in actions
|
|
205
|
+
assert "background" in actions
|
|
206
|
+
assert "verbose" in actions
|
|
207
|
+
|
|
208
|
+
# Check default values
|
|
209
|
+
assert actions["chunker"].default == "TextChunker"
|
|
210
|
+
|
|
211
|
+
@patch("cognee.cli.commands.cognify_command.asyncio.run", side_effect=_mock_run)
|
|
212
|
+
def test_execute_basic_cognify(self, mock_asyncio_run):
|
|
213
|
+
"""Test execute with basic cognify"""
|
|
214
|
+
# Mock the cognee module
|
|
215
|
+
mock_cognee = MagicMock()
|
|
216
|
+
mock_cognee.cognify = AsyncMock(return_value="success")
|
|
217
|
+
|
|
218
|
+
with patch.dict(sys.modules, {"cognee": mock_cognee}):
|
|
219
|
+
command = CognifyCommand()
|
|
220
|
+
args = argparse.Namespace(
|
|
221
|
+
datasets=None,
|
|
222
|
+
chunk_size=None,
|
|
223
|
+
ontology_file=None,
|
|
224
|
+
chunker="TextChunker",
|
|
225
|
+
background=False,
|
|
226
|
+
verbose=False,
|
|
227
|
+
)
|
|
228
|
+
command.execute(args)
|
|
229
|
+
|
|
230
|
+
mock_asyncio_run.assert_called_once()
|
|
231
|
+
assert asyncio.iscoroutine(mock_asyncio_run.call_args[0][0])
|
|
232
|
+
from cognee.modules.chunking.TextChunker import TextChunker
|
|
233
|
+
|
|
234
|
+
mock_cognee.cognify.assert_awaited_once_with(
|
|
235
|
+
datasets=None,
|
|
236
|
+
chunk_size=None,
|
|
237
|
+
ontology_file_path=None,
|
|
238
|
+
chunker=TextChunker,
|
|
239
|
+
run_in_background=False,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
@patch("cognee.cli.commands.cognify_command.asyncio.run")
|
|
243
|
+
def test_execute_with_exception(self, mock_asyncio_run):
|
|
244
|
+
"""Test execute handles exceptions properly"""
|
|
245
|
+
command = CognifyCommand()
|
|
246
|
+
args = argparse.Namespace(
|
|
247
|
+
datasets=None,
|
|
248
|
+
chunk_size=None,
|
|
249
|
+
ontology_file=None,
|
|
250
|
+
chunker="TextChunker",
|
|
251
|
+
background=False,
|
|
252
|
+
verbose=False,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
mock_asyncio_run.side_effect = Exception("Cognify error")
|
|
256
|
+
|
|
257
|
+
with pytest.raises(CliCommandException):
|
|
258
|
+
command.execute(args)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class TestDeleteCommand:
|
|
262
|
+
"""Test the DeleteCommand class"""
|
|
263
|
+
|
|
264
|
+
def test_command_properties(self):
|
|
265
|
+
"""Test basic command properties"""
|
|
266
|
+
command = DeleteCommand()
|
|
267
|
+
assert command.command_string == "delete"
|
|
268
|
+
assert "Delete data" in command.help_string
|
|
269
|
+
assert command.docs_url is not None
|
|
270
|
+
|
|
271
|
+
def test_configure_parser(self):
|
|
272
|
+
"""Test parser configuration"""
|
|
273
|
+
command = DeleteCommand()
|
|
274
|
+
parser = argparse.ArgumentParser()
|
|
275
|
+
|
|
276
|
+
command.configure_parser(parser)
|
|
277
|
+
|
|
278
|
+
# Check that arguments are added
|
|
279
|
+
actions = {action.dest: action for action in parser._actions}
|
|
280
|
+
assert "dataset_name" in actions
|
|
281
|
+
assert "user_id" in actions
|
|
282
|
+
assert "all" in actions
|
|
283
|
+
assert "force" in actions
|
|
284
|
+
|
|
285
|
+
@patch("cognee.cli.commands.delete_command.fmt.confirm")
|
|
286
|
+
@patch("cognee.cli.commands.delete_command.asyncio.run", side_effect=_mock_run)
|
|
287
|
+
def test_execute_delete_dataset_with_confirmation(self, mock_asyncio_run, mock_confirm):
|
|
288
|
+
"""Test execute delete dataset with user confirmation"""
|
|
289
|
+
# Mock the cognee module
|
|
290
|
+
mock_cognee = MagicMock()
|
|
291
|
+
mock_cognee.delete = AsyncMock()
|
|
292
|
+
|
|
293
|
+
with patch.dict(sys.modules, {"cognee": mock_cognee}):
|
|
294
|
+
command = DeleteCommand()
|
|
295
|
+
args = argparse.Namespace(
|
|
296
|
+
dataset_name="test_dataset", user_id=None, all=False, force=False
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
mock_confirm.return_value = True
|
|
300
|
+
|
|
301
|
+
command.execute(args)
|
|
302
|
+
|
|
303
|
+
mock_confirm.assert_called_once_with(f"Delete dataset '{args.dataset_name}'?")
|
|
304
|
+
mock_asyncio_run.assert_called_once()
|
|
305
|
+
assert asyncio.iscoroutine(mock_asyncio_run.call_args[0][0])
|
|
306
|
+
mock_cognee.delete.assert_awaited_once_with(dataset_name="test_dataset", user_id=None)
|
|
307
|
+
|
|
308
|
+
@patch("cognee.cli.commands.delete_command.fmt.confirm")
|
|
309
|
+
def test_execute_delete_cancelled(self, mock_confirm):
|
|
310
|
+
"""Test execute when user cancels deletion"""
|
|
311
|
+
command = DeleteCommand()
|
|
312
|
+
args = argparse.Namespace(dataset_name="test_dataset", user_id=None, all=False, force=False)
|
|
313
|
+
|
|
314
|
+
mock_confirm.return_value = False
|
|
315
|
+
|
|
316
|
+
# Should not raise exception, just return
|
|
317
|
+
command.execute(args)
|
|
318
|
+
|
|
319
|
+
mock_confirm.assert_called_once_with(f"Delete dataset '{args.dataset_name}'?")
|
|
320
|
+
|
|
321
|
+
@patch("cognee.cli.commands.delete_command.asyncio.run", side_effect=_mock_run)
|
|
322
|
+
def test_execute_delete_forced(self, mock_asyncio_run):
|
|
323
|
+
"""Test execute delete with force flag"""
|
|
324
|
+
# Mock the cognee module
|
|
325
|
+
mock_cognee = MagicMock()
|
|
326
|
+
mock_cognee.delete = AsyncMock()
|
|
327
|
+
|
|
328
|
+
with patch.dict(sys.modules, {"cognee": mock_cognee}):
|
|
329
|
+
command = DeleteCommand()
|
|
330
|
+
args = argparse.Namespace(
|
|
331
|
+
dataset_name="test_dataset", user_id=None, all=False, force=True
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
command.execute(args)
|
|
335
|
+
|
|
336
|
+
mock_asyncio_run.assert_called_once()
|
|
337
|
+
assert asyncio.iscoroutine(mock_asyncio_run.call_args[0][0])
|
|
338
|
+
mock_cognee.delete.assert_awaited_once_with(dataset_name="test_dataset", user_id=None)
|
|
339
|
+
|
|
340
|
+
def test_execute_no_delete_target(self):
|
|
341
|
+
"""Test execute when no delete target is specified"""
|
|
342
|
+
command = DeleteCommand()
|
|
343
|
+
args = argparse.Namespace(dataset_name=None, user_id=None, all=False, force=False)
|
|
344
|
+
|
|
345
|
+
# Should not raise exception, just return with error message
|
|
346
|
+
command.execute(args)
|
|
347
|
+
|
|
348
|
+
@patch("cognee.cli.commands.delete_command.asyncio.run")
|
|
349
|
+
def test_execute_with_exception(self, mock_asyncio_run):
|
|
350
|
+
"""Test execute handles exceptions properly"""
|
|
351
|
+
command = DeleteCommand()
|
|
352
|
+
args = argparse.Namespace(dataset_name="test_dataset", user_id=None, all=False, force=True)
|
|
353
|
+
|
|
354
|
+
mock_asyncio_run.side_effect = Exception("Delete error")
|
|
355
|
+
|
|
356
|
+
with pytest.raises(CliCommandException):
|
|
357
|
+
command.execute(args)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class TestConfigCommand:
|
|
361
|
+
"""Test the ConfigCommand class"""
|
|
362
|
+
|
|
363
|
+
def test_command_properties(self):
|
|
364
|
+
"""Test basic command properties"""
|
|
365
|
+
command = ConfigCommand()
|
|
366
|
+
assert command.command_string == "config"
|
|
367
|
+
assert "Manage cognee configuration" in command.help_string
|
|
368
|
+
assert command.docs_url is not None
|
|
369
|
+
|
|
370
|
+
def test_configure_parser(self):
|
|
371
|
+
"""Test parser configuration"""
|
|
372
|
+
command = ConfigCommand()
|
|
373
|
+
parser = argparse.ArgumentParser()
|
|
374
|
+
|
|
375
|
+
command.configure_parser(parser)
|
|
376
|
+
|
|
377
|
+
# Check that subparsers are created
|
|
378
|
+
subparsers_actions = [
|
|
379
|
+
action for action in parser._actions if isinstance(action, argparse._SubParsersAction)
|
|
380
|
+
]
|
|
381
|
+
assert len(subparsers_actions) == 1
|
|
382
|
+
|
|
383
|
+
subparsers = subparsers_actions[0]
|
|
384
|
+
assert "get" in subparsers.choices
|
|
385
|
+
assert "set" in subparsers.choices
|
|
386
|
+
assert "list" in subparsers.choices
|
|
387
|
+
assert "unset" in subparsers.choices
|
|
388
|
+
assert "reset" in subparsers.choices
|
|
389
|
+
|
|
390
|
+
def test_execute_no_action(self):
|
|
391
|
+
"""Test execute when no config action is provided"""
|
|
392
|
+
command = ConfigCommand()
|
|
393
|
+
args = argparse.Namespace()
|
|
394
|
+
|
|
395
|
+
# Should not raise exception, just return with error message
|
|
396
|
+
command.execute(args)
|
|
397
|
+
|
|
398
|
+
@patch("builtins.__import__")
|
|
399
|
+
def test_execute_get_action(self, mock_import):
|
|
400
|
+
"""Test execute get action"""
|
|
401
|
+
# Mock the cognee module
|
|
402
|
+
mock_cognee = MagicMock()
|
|
403
|
+
mock_cognee.config.get = MagicMock(return_value="openai")
|
|
404
|
+
mock_import.return_value = mock_cognee
|
|
405
|
+
|
|
406
|
+
command = ConfigCommand()
|
|
407
|
+
args = argparse.Namespace(config_action="get", key="llm_provider")
|
|
408
|
+
|
|
409
|
+
command.execute(args)
|
|
410
|
+
|
|
411
|
+
@patch("builtins.__import__")
|
|
412
|
+
def test_execute_set_action(self, mock_import):
|
|
413
|
+
"""Test execute set action"""
|
|
414
|
+
# Mock the cognee module
|
|
415
|
+
mock_cognee = MagicMock()
|
|
416
|
+
mock_cognee.config.set = MagicMock()
|
|
417
|
+
mock_import.return_value = mock_cognee
|
|
418
|
+
|
|
419
|
+
command = ConfigCommand()
|
|
420
|
+
args = argparse.Namespace(config_action="set", key="llm_provider", value="anthropic")
|
|
421
|
+
|
|
422
|
+
command.execute(args)
|
|
423
|
+
|
|
424
|
+
@patch("builtins.__import__")
|
|
425
|
+
def test_execute_set_action_json_value(self, mock_import):
|
|
426
|
+
"""Test execute set action with JSON value"""
|
|
427
|
+
# Mock the cognee module
|
|
428
|
+
mock_cognee = MagicMock()
|
|
429
|
+
mock_cognee.config.set = MagicMock()
|
|
430
|
+
mock_import.return_value = mock_cognee
|
|
431
|
+
|
|
432
|
+
command = ConfigCommand()
|
|
433
|
+
args = argparse.Namespace(config_action="set", key="chunk_size", value="1024")
|
|
434
|
+
|
|
435
|
+
command.execute(args)
|
|
436
|
+
|
|
437
|
+
def test_execute_list_action(self):
|
|
438
|
+
"""Test execute list action"""
|
|
439
|
+
command = ConfigCommand()
|
|
440
|
+
args = argparse.Namespace(config_action="list")
|
|
441
|
+
|
|
442
|
+
# Should not raise exception
|
|
443
|
+
command.execute(args)
|
|
444
|
+
|
|
445
|
+
@patch("cognee.cli.commands.config_command.fmt.confirm")
|
|
446
|
+
def test_execute_unset_action(self, mock_confirm):
|
|
447
|
+
"""Test execute unset action"""
|
|
448
|
+
# Mock the cognee module
|
|
449
|
+
mock_cognee = MagicMock()
|
|
450
|
+
mock_cognee.config.set_llm_provider = MagicMock()
|
|
451
|
+
|
|
452
|
+
with patch.dict(sys.modules, {"cognee": mock_cognee}):
|
|
453
|
+
command = ConfigCommand()
|
|
454
|
+
args = argparse.Namespace(config_action="unset", key="llm_provider", force=False)
|
|
455
|
+
|
|
456
|
+
mock_confirm.return_value = True
|
|
457
|
+
|
|
458
|
+
command.execute(args)
|
|
459
|
+
|
|
460
|
+
mock_confirm.assert_called_once()
|
|
461
|
+
|
|
462
|
+
@patch("cognee.cli.commands.config_command.fmt.confirm")
|
|
463
|
+
def test_execute_reset_action(self, mock_confirm):
|
|
464
|
+
"""Test execute reset action"""
|
|
465
|
+
command = ConfigCommand()
|
|
466
|
+
args = argparse.Namespace(config_action="reset", force=False)
|
|
467
|
+
|
|
468
|
+
mock_confirm.return_value = True
|
|
469
|
+
|
|
470
|
+
# Should not raise exception
|
|
471
|
+
command.execute(args)
|
|
472
|
+
|
|
473
|
+
mock_confirm.assert_called_once()
|
|
474
|
+
|
|
475
|
+
def test_execute_with_exception(self):
|
|
476
|
+
"""Test execute handles exceptions properly"""
|
|
477
|
+
# Test with an invalid action that will cause an exception in the main execute method
|
|
478
|
+
command = ConfigCommand()
|
|
479
|
+
args = argparse.Namespace(config_action="invalid_action")
|
|
480
|
+
|
|
481
|
+
# This should not raise CliCommandException, just handle it gracefully
|
|
482
|
+
# The config command handles unknown actions by showing an error message
|
|
483
|
+
command.execute(args)
|