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