cognee 0.5.0.dev0__py3-none-any.whl → 0.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. cognee/api/client.py +1 -5
  2. cognee/api/v1/add/add.py +2 -1
  3. cognee/api/v1/cognify/cognify.py +24 -16
  4. cognee/api/v1/cognify/routers/__init__.py +0 -1
  5. cognee/api/v1/cognify/routers/get_cognify_router.py +3 -1
  6. cognee/api/v1/datasets/routers/get_datasets_router.py +3 -3
  7. cognee/api/v1/ontologies/ontologies.py +12 -37
  8. cognee/api/v1/ontologies/routers/get_ontology_router.py +27 -25
  9. cognee/api/v1/search/search.py +8 -0
  10. cognee/api/v1/ui/node_setup.py +360 -0
  11. cognee/api/v1/ui/npm_utils.py +50 -0
  12. cognee/api/v1/ui/ui.py +38 -68
  13. cognee/context_global_variables.py +61 -16
  14. cognee/eval_framework/Dockerfile +29 -0
  15. cognee/eval_framework/answer_generation/answer_generation_executor.py +10 -0
  16. cognee/eval_framework/answer_generation/run_question_answering_module.py +1 -1
  17. cognee/eval_framework/corpus_builder/task_getters/get_cascade_graph_tasks.py +0 -2
  18. cognee/eval_framework/corpus_builder/task_getters/get_default_tasks_by_indices.py +4 -4
  19. cognee/eval_framework/eval_config.py +2 -2
  20. cognee/eval_framework/modal_run_eval.py +16 -28
  21. cognee/infrastructure/databases/dataset_database_handler/__init__.py +3 -0
  22. cognee/infrastructure/databases/dataset_database_handler/dataset_database_handler_interface.py +80 -0
  23. cognee/infrastructure/databases/dataset_database_handler/supported_dataset_database_handlers.py +18 -0
  24. cognee/infrastructure/databases/dataset_database_handler/use_dataset_database_handler.py +10 -0
  25. cognee/infrastructure/databases/graph/config.py +3 -0
  26. cognee/infrastructure/databases/graph/get_graph_engine.py +1 -0
  27. cognee/infrastructure/databases/graph/graph_db_interface.py +15 -0
  28. cognee/infrastructure/databases/graph/kuzu/KuzuDatasetDatabaseHandler.py +81 -0
  29. cognee/infrastructure/databases/graph/kuzu/adapter.py +228 -0
  30. cognee/infrastructure/databases/graph/neo4j_driver/Neo4jAuraDevDatasetDatabaseHandler.py +168 -0
  31. cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +80 -1
  32. cognee/infrastructure/databases/utils/__init__.py +3 -0
  33. cognee/infrastructure/databases/utils/get_graph_dataset_database_handler.py +10 -0
  34. cognee/infrastructure/databases/utils/get_or_create_dataset_database.py +62 -48
  35. cognee/infrastructure/databases/utils/get_vector_dataset_database_handler.py +10 -0
  36. cognee/infrastructure/databases/utils/resolve_dataset_database_connection_info.py +30 -0
  37. cognee/infrastructure/databases/vector/config.py +2 -0
  38. cognee/infrastructure/databases/vector/create_vector_engine.py +1 -0
  39. cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +8 -6
  40. cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +9 -7
  41. cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +11 -10
  42. cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +2 -0
  43. cognee/infrastructure/databases/vector/lancedb/LanceDBDatasetDatabaseHandler.py +50 -0
  44. cognee/infrastructure/databases/vector/vector_db_interface.py +35 -0
  45. cognee/infrastructure/files/storage/s3_config.py +2 -0
  46. cognee/infrastructure/llm/LLMGateway.py +5 -2
  47. cognee/infrastructure/llm/config.py +35 -0
  48. cognee/infrastructure/llm/extraction/knowledge_graph/extract_content_graph.py +2 -2
  49. cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py +23 -8
  50. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +17 -16
  51. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/__init__.py +5 -0
  52. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/adapter.py +153 -0
  53. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +40 -37
  54. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +39 -36
  55. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +19 -1
  56. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +11 -9
  57. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +23 -21
  58. cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +42 -34
  59. cognee/memify_pipelines/create_triplet_embeddings.py +53 -0
  60. cognee/modules/cognify/config.py +2 -0
  61. cognee/modules/data/deletion/prune_system.py +52 -2
  62. cognee/modules/data/methods/delete_dataset.py +26 -0
  63. cognee/modules/engine/models/Triplet.py +9 -0
  64. cognee/modules/engine/models/__init__.py +1 -0
  65. cognee/modules/graph/cognee_graph/CogneeGraph.py +85 -37
  66. cognee/modules/graph/cognee_graph/CogneeGraphElements.py +8 -3
  67. cognee/modules/memify/memify.py +1 -7
  68. cognee/modules/pipelines/operations/pipeline.py +18 -2
  69. cognee/modules/retrieval/__init__.py +1 -1
  70. cognee/modules/retrieval/graph_completion_context_extension_retriever.py +4 -0
  71. cognee/modules/retrieval/graph_completion_cot_retriever.py +4 -0
  72. cognee/modules/retrieval/graph_completion_retriever.py +10 -0
  73. cognee/modules/retrieval/graph_summary_completion_retriever.py +4 -0
  74. cognee/modules/retrieval/register_retriever.py +10 -0
  75. cognee/modules/retrieval/registered_community_retrievers.py +1 -0
  76. cognee/modules/retrieval/temporal_retriever.py +4 -0
  77. cognee/modules/retrieval/triplet_retriever.py +182 -0
  78. cognee/modules/retrieval/utils/brute_force_triplet_search.py +42 -10
  79. cognee/modules/run_custom_pipeline/run_custom_pipeline.py +8 -1
  80. cognee/modules/search/methods/get_search_type_tools.py +54 -8
  81. cognee/modules/search/methods/no_access_control_search.py +4 -0
  82. cognee/modules/search/methods/search.py +46 -18
  83. cognee/modules/search/types/SearchType.py +1 -1
  84. cognee/modules/settings/get_settings.py +19 -0
  85. cognee/modules/users/methods/get_authenticated_user.py +2 -2
  86. cognee/modules/users/models/DatasetDatabase.py +15 -3
  87. cognee/shared/logging_utils.py +4 -0
  88. cognee/shared/rate_limiting.py +30 -0
  89. cognee/tasks/documents/__init__.py +0 -1
  90. cognee/tasks/graph/extract_graph_from_data.py +9 -10
  91. cognee/tasks/memify/get_triplet_datapoints.py +289 -0
  92. cognee/tasks/storage/add_data_points.py +142 -2
  93. cognee/tests/integration/retrieval/test_triplet_retriever.py +84 -0
  94. cognee/tests/integration/tasks/test_add_data_points.py +139 -0
  95. cognee/tests/integration/tasks/test_get_triplet_datapoints.py +69 -0
  96. cognee/tests/test_cognee_server_start.py +2 -4
  97. cognee/tests/test_conversation_history.py +23 -1
  98. cognee/tests/test_dataset_database_handler.py +137 -0
  99. cognee/tests/test_dataset_delete.py +76 -0
  100. cognee/tests/test_edge_centered_payload.py +170 -0
  101. cognee/tests/test_pipeline_cache.py +164 -0
  102. cognee/tests/test_search_db.py +37 -1
  103. cognee/tests/unit/api/test_ontology_endpoint.py +77 -89
  104. cognee/tests/unit/infrastructure/llm/test_llm_config.py +46 -0
  105. cognee/tests/unit/infrastructure/mock_embedding_engine.py +3 -7
  106. cognee/tests/unit/infrastructure/test_embedding_rate_limiting_realistic.py +0 -5
  107. cognee/tests/unit/modules/graph/cognee_graph_elements_test.py +2 -2
  108. cognee/tests/unit/modules/graph/cognee_graph_test.py +406 -0
  109. cognee/tests/unit/modules/memify_tasks/test_get_triplet_datapoints.py +214 -0
  110. cognee/tests/unit/modules/retrieval/test_brute_force_triplet_search.py +608 -0
  111. cognee/tests/unit/modules/retrieval/triplet_retriever_test.py +83 -0
  112. cognee/tests/unit/modules/search/test_search.py +100 -0
  113. cognee/tests/unit/tasks/storage/test_add_data_points.py +288 -0
  114. {cognee-0.5.0.dev0.dist-info → cognee-0.5.1.dist-info}/METADATA +76 -89
  115. {cognee-0.5.0.dev0.dist-info → cognee-0.5.1.dist-info}/RECORD +119 -97
  116. {cognee-0.5.0.dev0.dist-info → cognee-0.5.1.dist-info}/WHEEL +1 -1
  117. cognee/api/v1/cognify/code_graph_pipeline.py +0 -119
  118. cognee/api/v1/cognify/routers/get_code_pipeline_router.py +0 -90
  119. cognee/infrastructure/databases/vector/embeddings/embedding_rate_limiter.py +0 -544
  120. cognee/modules/retrieval/code_retriever.py +0 -232
  121. cognee/tasks/code/enrich_dependency_graph_checker.py +0 -35
  122. cognee/tasks/code/get_local_dependencies_checker.py +0 -20
  123. cognee/tasks/code/get_repo_dependency_graph_checker.py +0 -35
  124. cognee/tasks/documents/check_permissions_on_dataset.py +0 -26
  125. cognee/tasks/repo_processor/__init__.py +0 -2
  126. cognee/tasks/repo_processor/get_local_dependencies.py +0 -335
  127. cognee/tasks/repo_processor/get_non_code_files.py +0 -158
  128. cognee/tasks/repo_processor/get_repo_file_dependencies.py +0 -243
  129. cognee/tests/test_delete_bmw_example.py +0 -60
  130. {cognee-0.5.0.dev0.dist-info → cognee-0.5.1.dist-info}/entry_points.txt +0 -0
  131. {cognee-0.5.0.dev0.dist-info → cognee-0.5.1.dist-info}/licenses/LICENSE +0 -0
  132. {cognee-0.5.0.dev0.dist-info → cognee-0.5.1.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 patch, Mock, AsyncMock
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
- gau_mod = importlib.import_module("cognee.modules.users.methods.get_authenticated_user")
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
- return TestClient(app)
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(), email="default@example.com", is_active=True, tenant_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
- @patch.object(gau_mod, "get_default_user", new_callable=AsyncMock)
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": json.dumps([unique_key]), "description": json.dumps(["Test"])},
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
- @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):
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
- @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):
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": json.dumps(["test"])})
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
- @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
-
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": json.dumps([unique_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
- @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"""
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 == 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"
119
+ assert response.status_code == 400
120
+ assert "Only one ontology_file is allowed" in response.json()["error"]
132
121
 
133
122
 
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"""
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
- "descriptions": json.dumps(["Single ontology"]),
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 == 200
151
- result = response.json()
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
- @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):
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
- @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"""
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 multiple ontologies
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
- 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
- }
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
- upload_response = client.post("/api/v1/ontologies", files=files, data=data)
199
- assert upload_response.status_code == 200
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
- @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"""
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
- # Test mismatched array lengths
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"]), # 2 keys, 1 file
231
- "descriptions": json.dumps(["desc1"]),
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 "Number of keys must match number of files" in response.json()["error"]
223
+ assert "ontology_key must be a string" in response.json()["error"]
237
224
 
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
- }
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
- 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"]
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
- @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):
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.infrastructure.databases.vector.embeddings.embedding_rate_limiter import (
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
- return [[0.1] * self.dimensions for _ in text]
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": np.inf}
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": np.inf, "weight": 10}
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)