cognee 0.5.0__py3-none-any.whl → 0.5.0.dev0__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/api/client.py +5 -1
- cognee/api/v1/add/add.py +1 -2
- cognee/api/v1/cognify/code_graph_pipeline.py +119 -0
- cognee/api/v1/cognify/cognify.py +16 -24
- cognee/api/v1/cognify/routers/__init__.py +1 -0
- cognee/api/v1/cognify/routers/get_code_pipeline_router.py +90 -0
- cognee/api/v1/cognify/routers/get_cognify_router.py +1 -3
- cognee/api/v1/datasets/routers/get_datasets_router.py +3 -3
- cognee/api/v1/ontologies/ontologies.py +37 -12
- cognee/api/v1/ontologies/routers/get_ontology_router.py +25 -27
- cognee/api/v1/search/search.py +0 -4
- cognee/api/v1/ui/ui.py +68 -38
- cognee/context_global_variables.py +16 -61
- cognee/eval_framework/answer_generation/answer_generation_executor.py +0 -10
- cognee/eval_framework/answer_generation/run_question_answering_module.py +1 -1
- cognee/eval_framework/corpus_builder/task_getters/get_cascade_graph_tasks.py +2 -0
- cognee/eval_framework/corpus_builder/task_getters/get_default_tasks_by_indices.py +4 -4
- cognee/eval_framework/eval_config.py +2 -2
- cognee/eval_framework/modal_run_eval.py +28 -16
- cognee/infrastructure/databases/graph/config.py +0 -3
- cognee/infrastructure/databases/graph/get_graph_engine.py +0 -1
- cognee/infrastructure/databases/graph/graph_db_interface.py +0 -15
- cognee/infrastructure/databases/graph/kuzu/adapter.py +0 -228
- cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +1 -80
- cognee/infrastructure/databases/utils/__init__.py +0 -3
- cognee/infrastructure/databases/utils/get_or_create_dataset_database.py +48 -62
- cognee/infrastructure/databases/vector/config.py +0 -2
- cognee/infrastructure/databases/vector/create_vector_engine.py +0 -1
- cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +6 -8
- cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +7 -9
- cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +10 -11
- cognee/infrastructure/databases/vector/embeddings/embedding_rate_limiter.py +544 -0
- cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +0 -2
- cognee/infrastructure/databases/vector/vector_db_interface.py +0 -35
- cognee/infrastructure/files/storage/s3_config.py +0 -2
- cognee/infrastructure/llm/LLMGateway.py +2 -5
- cognee/infrastructure/llm/config.py +0 -35
- cognee/infrastructure/llm/extraction/knowledge_graph/extract_content_graph.py +2 -2
- cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py +8 -23
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +16 -17
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +37 -40
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +36 -39
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +1 -19
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +9 -11
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +21 -23
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +34 -42
- cognee/modules/cognify/config.py +0 -2
- cognee/modules/data/deletion/prune_system.py +2 -52
- cognee/modules/data/methods/delete_dataset.py +0 -26
- cognee/modules/engine/models/__init__.py +0 -1
- cognee/modules/graph/cognee_graph/CogneeGraph.py +37 -85
- cognee/modules/graph/cognee_graph/CogneeGraphElements.py +3 -8
- cognee/modules/memify/memify.py +7 -1
- cognee/modules/pipelines/operations/pipeline.py +2 -18
- cognee/modules/retrieval/__init__.py +1 -1
- cognee/modules/retrieval/code_retriever.py +232 -0
- cognee/modules/retrieval/graph_completion_context_extension_retriever.py +0 -4
- cognee/modules/retrieval/graph_completion_cot_retriever.py +0 -4
- cognee/modules/retrieval/graph_completion_retriever.py +0 -10
- cognee/modules/retrieval/graph_summary_completion_retriever.py +0 -4
- cognee/modules/retrieval/temporal_retriever.py +0 -4
- cognee/modules/retrieval/utils/brute_force_triplet_search.py +10 -42
- cognee/modules/run_custom_pipeline/run_custom_pipeline.py +1 -8
- cognee/modules/search/methods/get_search_type_tools.py +8 -54
- cognee/modules/search/methods/no_access_control_search.py +0 -4
- cognee/modules/search/methods/search.py +0 -21
- cognee/modules/search/types/SearchType.py +1 -1
- cognee/modules/settings/get_settings.py +0 -19
- cognee/modules/users/methods/get_authenticated_user.py +2 -2
- cognee/modules/users/models/DatasetDatabase.py +3 -15
- cognee/shared/logging_utils.py +0 -4
- cognee/tasks/code/enrich_dependency_graph_checker.py +35 -0
- cognee/tasks/code/get_local_dependencies_checker.py +20 -0
- cognee/tasks/code/get_repo_dependency_graph_checker.py +35 -0
- cognee/tasks/documents/__init__.py +1 -0
- cognee/tasks/documents/check_permissions_on_dataset.py +26 -0
- cognee/tasks/graph/extract_graph_from_data.py +10 -9
- cognee/tasks/repo_processor/__init__.py +2 -0
- cognee/tasks/repo_processor/get_local_dependencies.py +335 -0
- cognee/tasks/repo_processor/get_non_code_files.py +158 -0
- cognee/tasks/repo_processor/get_repo_file_dependencies.py +243 -0
- cognee/tasks/storage/add_data_points.py +2 -142
- cognee/tests/test_cognee_server_start.py +4 -2
- cognee/tests/test_conversation_history.py +1 -23
- cognee/tests/test_delete_bmw_example.py +60 -0
- cognee/tests/test_search_db.py +1 -37
- cognee/tests/unit/api/test_ontology_endpoint.py +89 -77
- cognee/tests/unit/infrastructure/mock_embedding_engine.py +7 -3
- cognee/tests/unit/infrastructure/test_embedding_rate_limiting_realistic.py +5 -0
- cognee/tests/unit/modules/graph/cognee_graph_elements_test.py +2 -2
- cognee/tests/unit/modules/graph/cognee_graph_test.py +0 -406
- {cognee-0.5.0.dist-info → cognee-0.5.0.dev0.dist-info}/METADATA +89 -76
- {cognee-0.5.0.dist-info → cognee-0.5.0.dev0.dist-info}/RECORD +97 -118
- {cognee-0.5.0.dist-info → cognee-0.5.0.dev0.dist-info}/WHEEL +1 -1
- cognee/api/v1/ui/node_setup.py +0 -360
- cognee/api/v1/ui/npm_utils.py +0 -50
- cognee/eval_framework/Dockerfile +0 -29
- cognee/infrastructure/databases/dataset_database_handler/__init__.py +0 -3
- cognee/infrastructure/databases/dataset_database_handler/dataset_database_handler_interface.py +0 -80
- cognee/infrastructure/databases/dataset_database_handler/supported_dataset_database_handlers.py +0 -18
- cognee/infrastructure/databases/dataset_database_handler/use_dataset_database_handler.py +0 -10
- cognee/infrastructure/databases/graph/kuzu/KuzuDatasetDatabaseHandler.py +0 -81
- cognee/infrastructure/databases/graph/neo4j_driver/Neo4jAuraDevDatasetDatabaseHandler.py +0 -168
- cognee/infrastructure/databases/utils/get_graph_dataset_database_handler.py +0 -10
- cognee/infrastructure/databases/utils/get_vector_dataset_database_handler.py +0 -10
- cognee/infrastructure/databases/utils/resolve_dataset_database_connection_info.py +0 -30
- cognee/infrastructure/databases/vector/lancedb/LanceDBDatasetDatabaseHandler.py +0 -50
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/__init__.py +0 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/adapter.py +0 -153
- cognee/memify_pipelines/create_triplet_embeddings.py +0 -53
- cognee/modules/engine/models/Triplet.py +0 -9
- cognee/modules/retrieval/register_retriever.py +0 -10
- cognee/modules/retrieval/registered_community_retrievers.py +0 -1
- cognee/modules/retrieval/triplet_retriever.py +0 -182
- cognee/shared/rate_limiting.py +0 -30
- cognee/tasks/memify/get_triplet_datapoints.py +0 -289
- cognee/tests/integration/retrieval/test_triplet_retriever.py +0 -84
- cognee/tests/integration/tasks/test_add_data_points.py +0 -139
- cognee/tests/integration/tasks/test_get_triplet_datapoints.py +0 -69
- cognee/tests/test_dataset_database_handler.py +0 -137
- cognee/tests/test_dataset_delete.py +0 -76
- cognee/tests/test_edge_centered_payload.py +0 -170
- cognee/tests/test_pipeline_cache.py +0 -164
- cognee/tests/unit/infrastructure/llm/test_llm_config.py +0 -46
- cognee/tests/unit/modules/memify_tasks/test_get_triplet_datapoints.py +0 -214
- cognee/tests/unit/modules/retrieval/test_brute_force_triplet_search.py +0 -608
- cognee/tests/unit/modules/retrieval/triplet_retriever_test.py +0 -83
- cognee/tests/unit/tasks/storage/test_add_data_points.py +0 -288
- {cognee-0.5.0.dist-info → cognee-0.5.0.dev0.dist-info}/entry_points.txt +0 -0
- {cognee-0.5.0.dist-info → cognee-0.5.0.dev0.dist-info}/licenses/LICENSE +0 -0
- {cognee-0.5.0.dist-info → cognee-0.5.0.dev0.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import uuid
|
|
3
3
|
from fastapi.testclient import TestClient
|
|
4
|
-
from unittest.mock import Mock
|
|
4
|
+
from unittest.mock import patch, Mock, AsyncMock
|
|
5
5
|
from types import SimpleNamespace
|
|
6
|
+
import importlib
|
|
6
7
|
from cognee.api.client import app
|
|
7
|
-
from cognee.modules.users.methods import get_authenticated_user
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
@pytest.fixture(scope="session")
|
|
11
|
-
def test_client():
|
|
12
|
-
# Keep a single TestClient (and event loop) for the whole module.
|
|
13
|
-
# Re-creating TestClient repeatedly can break async DB connections (asyncpg loop mismatch).
|
|
14
|
-
with TestClient(app) as c:
|
|
15
|
-
yield c
|
|
9
|
+
gau_mod = importlib.import_module("cognee.modules.users.methods.get_authenticated_user")
|
|
16
10
|
|
|
17
11
|
|
|
18
12
|
@pytest.fixture
|
|
19
|
-
def client(
|
|
20
|
-
|
|
21
|
-
return mock_default_user
|
|
22
|
-
|
|
23
|
-
app.dependency_overrides[get_authenticated_user] = override_get_authenticated_user
|
|
24
|
-
yield test_client
|
|
25
|
-
app.dependency_overrides.pop(get_authenticated_user, None)
|
|
13
|
+
def client():
|
|
14
|
+
return TestClient(app)
|
|
26
15
|
|
|
27
16
|
|
|
28
17
|
@pytest.fixture
|
|
@@ -36,15 +25,16 @@ def mock_user():
|
|
|
36
25
|
def mock_default_user():
|
|
37
26
|
"""Mock default user for testing."""
|
|
38
27
|
return SimpleNamespace(
|
|
39
|
-
id=
|
|
40
|
-
email="default@example.com",
|
|
41
|
-
is_active=True,
|
|
42
|
-
tenant_id=str(uuid.uuid4()),
|
|
28
|
+
id=uuid.uuid4(), email="default@example.com", is_active=True, tenant_id=uuid.uuid4()
|
|
43
29
|
)
|
|
44
30
|
|
|
45
31
|
|
|
46
|
-
|
|
32
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
33
|
+
def test_upload_ontology_success(mock_get_default_user, client, mock_default_user):
|
|
47
34
|
"""Test successful ontology upload"""
|
|
35
|
+
import json
|
|
36
|
+
|
|
37
|
+
mock_get_default_user.return_value = mock_default_user
|
|
48
38
|
ontology_content = (
|
|
49
39
|
b"<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'></rdf:RDF>"
|
|
50
40
|
)
|
|
@@ -53,7 +43,7 @@ def test_upload_ontology_success(client):
|
|
|
53
43
|
response = client.post(
|
|
54
44
|
"/api/v1/ontologies",
|
|
55
45
|
files=[("ontology_file", ("test.owl", ontology_content, "application/xml"))],
|
|
56
|
-
data={"ontology_key": unique_key, "description": "Test"},
|
|
46
|
+
data={"ontology_key": json.dumps([unique_key]), "description": json.dumps(["Test"])},
|
|
57
47
|
)
|
|
58
48
|
|
|
59
49
|
assert response.status_code == 200
|
|
@@ -62,8 +52,10 @@ def test_upload_ontology_success(client):
|
|
|
62
52
|
assert "uploaded_at" in data["uploaded_ontologies"][0]
|
|
63
53
|
|
|
64
54
|
|
|
65
|
-
|
|
55
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
56
|
+
def test_upload_ontology_invalid_file(mock_get_default_user, client, mock_default_user):
|
|
66
57
|
"""Test 400 response for non-.owl files"""
|
|
58
|
+
mock_get_default_user.return_value = mock_default_user
|
|
67
59
|
unique_key = f"test_ontology_{uuid.uuid4().hex[:8]}"
|
|
68
60
|
response = client.post(
|
|
69
61
|
"/api/v1/ontologies",
|
|
@@ -73,10 +65,14 @@ def test_upload_ontology_invalid_file(client):
|
|
|
73
65
|
assert response.status_code == 400
|
|
74
66
|
|
|
75
67
|
|
|
76
|
-
|
|
68
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
69
|
+
def test_upload_ontology_missing_data(mock_get_default_user, client, mock_default_user):
|
|
77
70
|
"""Test 400 response for missing file or key"""
|
|
71
|
+
import json
|
|
72
|
+
|
|
73
|
+
mock_get_default_user.return_value = mock_default_user
|
|
78
74
|
# Missing file
|
|
79
|
-
response = client.post("/api/v1/ontologies", data={"ontology_key": "test"})
|
|
75
|
+
response = client.post("/api/v1/ontologies", data={"ontology_key": json.dumps(["test"])})
|
|
80
76
|
assert response.status_code == 400
|
|
81
77
|
|
|
82
78
|
# Missing key
|
|
@@ -86,25 +82,33 @@ def test_upload_ontology_missing_data(client):
|
|
|
86
82
|
assert response.status_code == 400
|
|
87
83
|
|
|
88
84
|
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
86
|
+
def test_upload_ontology_unauthorized(mock_get_default_user, client, mock_default_user):
|
|
87
|
+
"""Test behavior when default user is provided (no explicit authentication)"""
|
|
88
|
+
import json
|
|
89
|
+
|
|
91
90
|
unique_key = f"test_ontology_{uuid.uuid4().hex[:8]}"
|
|
91
|
+
mock_get_default_user.return_value = mock_default_user
|
|
92
92
|
response = client.post(
|
|
93
93
|
"/api/v1/ontologies",
|
|
94
94
|
files=[("ontology_file", ("test.owl", b"<rdf></rdf>", "application/xml"))],
|
|
95
|
-
data={"ontology_key": unique_key},
|
|
95
|
+
data={"ontology_key": json.dumps([unique_key])},
|
|
96
96
|
)
|
|
97
97
|
|
|
98
|
+
# The current system provides a default user when no explicit authentication is given
|
|
99
|
+
# This test verifies the system works with conditional authentication
|
|
98
100
|
assert response.status_code == 200
|
|
99
101
|
data = response.json()
|
|
100
102
|
assert data["uploaded_ontologies"][0]["ontology_key"] == unique_key
|
|
101
103
|
assert "uploaded_at" in data["uploaded_ontologies"][0]
|
|
102
104
|
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
107
|
+
def test_upload_multiple_ontologies(mock_get_default_user, client, mock_default_user):
|
|
108
|
+
"""Test uploading multiple ontology files in single request"""
|
|
106
109
|
import io
|
|
107
110
|
|
|
111
|
+
# Create mock files
|
|
108
112
|
file1_content = b"<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'></rdf:RDF>"
|
|
109
113
|
file2_content = b"<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'></rdf:RDF>"
|
|
110
114
|
|
|
@@ -112,16 +116,24 @@ def test_upload_multiple_ontologies_in_single_request_is_rejected(client):
|
|
|
112
116
|
("ontology_file", ("vehicles.owl", io.BytesIO(file1_content), "application/xml")),
|
|
113
117
|
("ontology_file", ("manufacturers.owl", io.BytesIO(file2_content), "application/xml")),
|
|
114
118
|
]
|
|
115
|
-
data = {
|
|
119
|
+
data = {
|
|
120
|
+
"ontology_key": '["vehicles", "manufacturers"]',
|
|
121
|
+
"descriptions": '["Base vehicles", "Car manufacturers"]',
|
|
122
|
+
}
|
|
116
123
|
|
|
117
124
|
response = client.post("/api/v1/ontologies", files=files, data=data)
|
|
118
125
|
|
|
119
|
-
assert response.status_code ==
|
|
120
|
-
|
|
126
|
+
assert response.status_code == 200
|
|
127
|
+
result = response.json()
|
|
128
|
+
assert "uploaded_ontologies" in result
|
|
129
|
+
assert len(result["uploaded_ontologies"]) == 2
|
|
130
|
+
assert result["uploaded_ontologies"][0]["ontology_key"] == "vehicles"
|
|
131
|
+
assert result["uploaded_ontologies"][1]["ontology_key"] == "manufacturers"
|
|
121
132
|
|
|
122
133
|
|
|
123
|
-
|
|
124
|
-
|
|
134
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
135
|
+
def test_upload_endpoint_accepts_arrays(mock_get_default_user, client, mock_default_user):
|
|
136
|
+
"""Test that upload endpoint accepts array parameters"""
|
|
125
137
|
import io
|
|
126
138
|
import json
|
|
127
139
|
|
|
@@ -130,16 +142,18 @@ def test_upload_endpoint_rejects_array_style_fields(client):
|
|
|
130
142
|
files = [("ontology_file", ("single.owl", io.BytesIO(file_content), "application/xml"))]
|
|
131
143
|
data = {
|
|
132
144
|
"ontology_key": json.dumps(["single_key"]),
|
|
133
|
-
"
|
|
145
|
+
"descriptions": json.dumps(["Single ontology"]),
|
|
134
146
|
}
|
|
135
147
|
|
|
136
148
|
response = client.post("/api/v1/ontologies", files=files, data=data)
|
|
137
149
|
|
|
138
|
-
assert response.status_code ==
|
|
139
|
-
|
|
150
|
+
assert response.status_code == 200
|
|
151
|
+
result = response.json()
|
|
152
|
+
assert result["uploaded_ontologies"][0]["ontology_key"] == "single_key"
|
|
140
153
|
|
|
141
154
|
|
|
142
|
-
|
|
155
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
156
|
+
def test_cognify_with_multiple_ontologies(mock_get_default_user, client, mock_default_user):
|
|
143
157
|
"""Test cognify endpoint accepts multiple ontology keys"""
|
|
144
158
|
payload = {
|
|
145
159
|
"datasets": ["test_dataset"],
|
|
@@ -153,11 +167,13 @@ def test_cognify_with_multiple_ontologies(client):
|
|
|
153
167
|
assert response.status_code in [200, 400, 409] # May fail for other reasons, not type
|
|
154
168
|
|
|
155
169
|
|
|
156
|
-
|
|
157
|
-
|
|
170
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
171
|
+
def test_complete_multifile_workflow(mock_get_default_user, client, mock_default_user):
|
|
172
|
+
"""Test complete workflow: upload multiple ontologies → cognify with multiple keys"""
|
|
158
173
|
import io
|
|
174
|
+
import json
|
|
159
175
|
|
|
160
|
-
# Step 1: Upload
|
|
176
|
+
# Step 1: Upload multiple ontologies
|
|
161
177
|
file1_content = b"""<?xml version="1.0"?>
|
|
162
178
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
163
179
|
xmlns:owl="http://www.w3.org/2002/07/owl#">
|
|
@@ -170,21 +186,17 @@ def test_complete_multifile_workflow(client):
|
|
|
170
186
|
<owl:Class rdf:ID="Manufacturer"/>
|
|
171
187
|
</rdf:RDF>"""
|
|
172
188
|
|
|
173
|
-
|
|
174
|
-
"/
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
189
|
+
files = [
|
|
190
|
+
("ontology_file", ("vehicles.owl", io.BytesIO(file1_content), "application/xml")),
|
|
191
|
+
("ontology_file", ("manufacturers.owl", io.BytesIO(file2_content), "application/xml")),
|
|
192
|
+
]
|
|
193
|
+
data = {
|
|
194
|
+
"ontology_key": json.dumps(["vehicles", "manufacturers"]),
|
|
195
|
+
"descriptions": json.dumps(["Vehicle ontology", "Manufacturer ontology"]),
|
|
196
|
+
}
|
|
179
197
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
files=[
|
|
183
|
-
("ontology_file", ("manufacturers.owl", io.BytesIO(file2_content), "application/xml"))
|
|
184
|
-
],
|
|
185
|
-
data={"ontology_key": "manufacturers", "description": "Manufacturer ontology"},
|
|
186
|
-
)
|
|
187
|
-
assert upload_response_2.status_code == 200
|
|
198
|
+
upload_response = client.post("/api/v1/ontologies", files=files, data=data)
|
|
199
|
+
assert upload_response.status_code == 200
|
|
188
200
|
|
|
189
201
|
# Step 2: Verify ontologies are listed
|
|
190
202
|
list_response = client.get("/api/v1/ontologies")
|
|
@@ -205,41 +217,41 @@ def test_complete_multifile_workflow(client):
|
|
|
205
217
|
assert cognify_response.status_code != 400 # Not a validation error
|
|
206
218
|
|
|
207
219
|
|
|
208
|
-
|
|
209
|
-
|
|
220
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
221
|
+
def test_multifile_error_handling(mock_get_default_user, client, mock_default_user):
|
|
222
|
+
"""Test error handling for invalid multifile uploads"""
|
|
210
223
|
import io
|
|
211
224
|
import json
|
|
212
225
|
|
|
213
|
-
#
|
|
226
|
+
# Test mismatched array lengths
|
|
214
227
|
file_content = b"<rdf:RDF></rdf:RDF>"
|
|
215
228
|
files = [("ontology_file", ("test.owl", io.BytesIO(file_content), "application/xml"))]
|
|
216
229
|
data = {
|
|
217
|
-
"ontology_key": json.dumps(["key1", "key2"]),
|
|
218
|
-
"
|
|
230
|
+
"ontology_key": json.dumps(["key1", "key2"]), # 2 keys, 1 file
|
|
231
|
+
"descriptions": json.dumps(["desc1"]),
|
|
219
232
|
}
|
|
220
233
|
|
|
221
234
|
response = client.post("/api/v1/ontologies", files=files, data=data)
|
|
222
235
|
assert response.status_code == 400
|
|
223
|
-
assert "
|
|
236
|
+
assert "Number of keys must match number of files" in response.json()["error"]
|
|
224
237
|
|
|
225
|
-
#
|
|
226
|
-
|
|
227
|
-
"/
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
238
|
+
# Test duplicate keys
|
|
239
|
+
files = [
|
|
240
|
+
("ontology_file", ("test1.owl", io.BytesIO(file_content), "application/xml")),
|
|
241
|
+
("ontology_file", ("test2.owl", io.BytesIO(file_content), "application/xml")),
|
|
242
|
+
]
|
|
243
|
+
data = {
|
|
244
|
+
"ontology_key": json.dumps(["duplicate", "duplicate"]),
|
|
245
|
+
"descriptions": json.dumps(["desc1", "desc2"]),
|
|
246
|
+
}
|
|
232
247
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
data={"ontology_key": "duplicate", "description": "desc2"},
|
|
237
|
-
)
|
|
238
|
-
assert response_2.status_code == 400
|
|
239
|
-
assert "already exists" in response_2.json()["error"]
|
|
248
|
+
response = client.post("/api/v1/ontologies", files=files, data=data)
|
|
249
|
+
assert response.status_code == 400
|
|
250
|
+
assert "Duplicate ontology keys not allowed" in response.json()["error"]
|
|
240
251
|
|
|
241
252
|
|
|
242
|
-
|
|
253
|
+
@patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
|
|
254
|
+
def test_cognify_missing_ontology_key(mock_get_default_user, client, mock_default_user):
|
|
243
255
|
"""Test cognify with non-existent ontology key"""
|
|
244
256
|
payload = {
|
|
245
257
|
"datasets": ["test_dataset"],
|
|
@@ -4,7 +4,10 @@ from typing import List
|
|
|
4
4
|
from cognee.infrastructure.databases.vector.embeddings.LiteLLMEmbeddingEngine import (
|
|
5
5
|
LiteLLMEmbeddingEngine,
|
|
6
6
|
)
|
|
7
|
-
from cognee.
|
|
7
|
+
from cognee.infrastructure.databases.vector.embeddings.embedding_rate_limiter import (
|
|
8
|
+
embedding_rate_limit_async,
|
|
9
|
+
embedding_sleep_and_retry_async,
|
|
10
|
+
)
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
class MockEmbeddingEngine(LiteLLMEmbeddingEngine):
|
|
@@ -31,6 +34,8 @@ class MockEmbeddingEngine(LiteLLMEmbeddingEngine):
|
|
|
31
34
|
self.fail_every_n_requests = fail_every_n_requests
|
|
32
35
|
self.add_delay = add_delay
|
|
33
36
|
|
|
37
|
+
@embedding_sleep_and_retry_async()
|
|
38
|
+
@embedding_rate_limit_async
|
|
34
39
|
async def embed_text(self, text: List[str]) -> List[List[float]]:
|
|
35
40
|
"""
|
|
36
41
|
Mock implementation that returns fixed embeddings and can
|
|
@@ -47,5 +52,4 @@ class MockEmbeddingEngine(LiteLLMEmbeddingEngine):
|
|
|
47
52
|
raise Exception(f"Mock failure on request #{self.request_count}")
|
|
48
53
|
|
|
49
54
|
# Return mock embeddings of the correct dimension
|
|
50
|
-
|
|
51
|
-
return [[0.1] * self.dimensions for _ in text]
|
|
55
|
+
return [[0.1] * self.dimensions for _ in text]
|
|
@@ -6,6 +6,9 @@ import logging
|
|
|
6
6
|
from cognee.infrastructure.llm.config import (
|
|
7
7
|
get_llm_config,
|
|
8
8
|
)
|
|
9
|
+
from cognee.infrastructure.databases.vector.embeddings.embedding_rate_limiter import (
|
|
10
|
+
EmbeddingRateLimiter,
|
|
11
|
+
)
|
|
9
12
|
from cognee.tests.unit.infrastructure.mock_embedding_engine import MockEmbeddingEngine
|
|
10
13
|
|
|
11
14
|
# Configure logging
|
|
@@ -30,6 +33,7 @@ async def test_embedding_rate_limiting_realistic():
|
|
|
30
33
|
|
|
31
34
|
# Clear the config and rate limiter caches to ensure our settings are applied
|
|
32
35
|
get_llm_config.cache_clear()
|
|
36
|
+
EmbeddingRateLimiter.reset_instance()
|
|
33
37
|
|
|
34
38
|
# Create a fresh config instance and verify settings
|
|
35
39
|
config = get_llm_config()
|
|
@@ -166,6 +170,7 @@ async def test_with_mock_failures():
|
|
|
166
170
|
|
|
167
171
|
# Clear caches
|
|
168
172
|
get_llm_config.cache_clear()
|
|
173
|
+
EmbeddingRateLimiter.reset_instance()
|
|
169
174
|
|
|
170
175
|
# Create a mock engine configured to fail every 3rd request
|
|
171
176
|
engine = MockEmbeddingEngine()
|
|
@@ -9,7 +9,7 @@ def test_node_initialization():
|
|
|
9
9
|
"""Test that a Node is initialized correctly."""
|
|
10
10
|
node = Node("node1", {"attr1": "value1"}, dimension=2)
|
|
11
11
|
assert node.id == "node1"
|
|
12
|
-
assert node.attributes == {"attr1": "value1", "vector_distance":
|
|
12
|
+
assert node.attributes == {"attr1": "value1", "vector_distance": np.inf}
|
|
13
13
|
assert len(node.status) == 2
|
|
14
14
|
assert np.all(node.status == 1)
|
|
15
15
|
|
|
@@ -96,7 +96,7 @@ def test_edge_initialization():
|
|
|
96
96
|
edge = Edge(node1, node2, {"weight": 10}, directed=False, dimension=2)
|
|
97
97
|
assert edge.node1 == node1
|
|
98
98
|
assert edge.node2 == node2
|
|
99
|
-
assert edge.attributes == {"vector_distance":
|
|
99
|
+
assert edge.attributes == {"vector_distance": np.inf, "weight": 10}
|
|
100
100
|
assert edge.directed is False
|
|
101
101
|
assert len(edge.status) == 2
|
|
102
102
|
assert np.all(edge.status == 1)
|