mdb-engine 0.1.6__py3-none-any.whl → 0.1.7__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.
- mdb_engine/__init__.py +38 -6
- mdb_engine/auth/README.md +534 -11
- mdb_engine/auth/__init__.py +129 -28
- mdb_engine/auth/audit.py +592 -0
- mdb_engine/auth/casbin_factory.py +10 -14
- mdb_engine/auth/config_helpers.py +7 -6
- mdb_engine/auth/cookie_utils.py +3 -7
- mdb_engine/auth/csrf.py +373 -0
- mdb_engine/auth/decorators.py +3 -10
- mdb_engine/auth/dependencies.py +37 -45
- mdb_engine/auth/helpers.py +3 -3
- mdb_engine/auth/integration.py +30 -73
- mdb_engine/auth/jwt.py +2 -6
- mdb_engine/auth/middleware.py +77 -34
- mdb_engine/auth/oso_factory.py +16 -36
- mdb_engine/auth/provider.py +17 -38
- mdb_engine/auth/rate_limiter.py +504 -0
- mdb_engine/auth/restrictions.py +8 -24
- mdb_engine/auth/session_manager.py +14 -29
- mdb_engine/auth/shared_middleware.py +600 -0
- mdb_engine/auth/shared_users.py +759 -0
- mdb_engine/auth/token_store.py +14 -28
- mdb_engine/auth/users.py +54 -113
- mdb_engine/auth/utils.py +213 -15
- mdb_engine/cli/commands/generate.py +545 -9
- mdb_engine/cli/commands/validate.py +3 -7
- mdb_engine/cli/utils.py +3 -3
- mdb_engine/config.py +7 -21
- mdb_engine/constants.py +65 -0
- mdb_engine/core/README.md +117 -6
- mdb_engine/core/__init__.py +39 -7
- mdb_engine/core/app_registration.py +22 -41
- mdb_engine/core/app_secrets.py +290 -0
- mdb_engine/core/connection.py +18 -9
- mdb_engine/core/encryption.py +223 -0
- mdb_engine/core/engine.py +758 -95
- mdb_engine/core/index_management.py +12 -16
- mdb_engine/core/manifest.py +424 -135
- mdb_engine/core/ray_integration.py +435 -0
- mdb_engine/core/seeding.py +10 -18
- mdb_engine/core/service_initialization.py +12 -23
- mdb_engine/core/types.py +2 -5
- mdb_engine/database/README.md +112 -16
- mdb_engine/database/__init__.py +17 -6
- mdb_engine/database/abstraction.py +25 -37
- mdb_engine/database/connection.py +11 -18
- mdb_engine/database/query_validator.py +367 -0
- mdb_engine/database/resource_limiter.py +204 -0
- mdb_engine/database/scoped_wrapper.py +713 -196
- mdb_engine/embeddings/__init__.py +17 -9
- mdb_engine/embeddings/dependencies.py +1 -3
- mdb_engine/embeddings/service.py +11 -25
- mdb_engine/exceptions.py +92 -0
- mdb_engine/indexes/README.md +30 -13
- mdb_engine/indexes/__init__.py +1 -0
- mdb_engine/indexes/helpers.py +1 -1
- mdb_engine/indexes/manager.py +50 -114
- mdb_engine/memory/README.md +2 -2
- mdb_engine/memory/__init__.py +1 -2
- mdb_engine/memory/service.py +30 -87
- mdb_engine/observability/README.md +4 -2
- mdb_engine/observability/__init__.py +26 -9
- mdb_engine/observability/health.py +8 -9
- mdb_engine/observability/metrics.py +32 -12
- mdb_engine/routing/README.md +1 -1
- mdb_engine/routing/__init__.py +1 -3
- mdb_engine/routing/websockets.py +25 -60
- mdb_engine-0.1.7.dist-info/METADATA +285 -0
- mdb_engine-0.1.7.dist-info/RECORD +85 -0
- mdb_engine-0.1.6.dist-info/METADATA +0 -213
- mdb_engine-0.1.6.dist-info/RECORD +0 -75
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/WHEEL +0 -0
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/entry_points.txt +0 -0
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/licenses/LICENSE +0 -0
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/top_level.txt +0 -0
|
@@ -35,15 +35,23 @@ Example EmbeddingService usage:
|
|
|
35
35
|
return {"embeddings": embeddings}
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
|
-
from .dependencies import (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
from .dependencies import (
|
|
39
|
+
create_embedding_dependency,
|
|
40
|
+
get_embedding_service_dep,
|
|
41
|
+
get_embedding_service_dependency,
|
|
42
|
+
get_embedding_service_for_app,
|
|
43
|
+
get_global_engine,
|
|
44
|
+
set_global_engine,
|
|
45
|
+
)
|
|
46
|
+
from .service import (
|
|
47
|
+
AzureOpenAIEmbeddingProvider,
|
|
48
|
+
BaseEmbeddingProvider,
|
|
49
|
+
EmbeddingProvider,
|
|
50
|
+
EmbeddingService,
|
|
51
|
+
EmbeddingServiceError,
|
|
52
|
+
OpenAIEmbeddingProvider,
|
|
53
|
+
get_embedding_service,
|
|
54
|
+
)
|
|
47
55
|
|
|
48
56
|
__all__ = [
|
|
49
57
|
"EmbeddingService",
|
|
@@ -147,9 +147,7 @@ def create_embedding_dependency(app_slug: str, engine: Optional[Any] = None):
|
|
|
147
147
|
"embedding dependencies are installed.",
|
|
148
148
|
)
|
|
149
149
|
else:
|
|
150
|
-
raise RuntimeError(
|
|
151
|
-
f"Embedding service not available for app '{app_slug}'"
|
|
152
|
-
)
|
|
150
|
+
raise RuntimeError(f"Embedding service not available for app '{app_slug}'")
|
|
153
151
|
return embedding_service
|
|
154
152
|
|
|
155
153
|
return _get_embedding_service
|
mdb_engine/embeddings/service.py
CHANGED
|
@@ -134,7 +134,7 @@ class OpenAIEmbeddingProvider(BaseEmbeddingProvider):
|
|
|
134
134
|
ConnectionError,
|
|
135
135
|
OSError,
|
|
136
136
|
) as e:
|
|
137
|
-
logger.
|
|
137
|
+
logger.exception(f"OpenAI embedding failed: {e}")
|
|
138
138
|
raise EmbeddingServiceError(f"OpenAI embedding failed: {str(e)}") from e
|
|
139
139
|
|
|
140
140
|
|
|
@@ -217,10 +217,8 @@ class AzureOpenAIEmbeddingProvider(BaseEmbeddingProvider):
|
|
|
217
217
|
ConnectionError,
|
|
218
218
|
OSError,
|
|
219
219
|
) as e:
|
|
220
|
-
logger.
|
|
221
|
-
raise EmbeddingServiceError(
|
|
222
|
-
f"Azure OpenAI embedding failed: {str(e)}"
|
|
223
|
-
) from e
|
|
220
|
+
logger.exception(f"Azure OpenAI embedding failed: {e}")
|
|
221
|
+
raise EmbeddingServiceError(f"Azure OpenAI embedding failed: {str(e)}") from e
|
|
224
222
|
|
|
225
223
|
|
|
226
224
|
def _detect_provider_from_env() -> str:
|
|
@@ -281,24 +279,16 @@ class EmbeddingProvider:
|
|
|
281
279
|
else:
|
|
282
280
|
# Auto-detect provider from environment variables
|
|
283
281
|
provider_type = _detect_provider_from_env()
|
|
284
|
-
default_model = (config or {}).get(
|
|
285
|
-
"default_embedding_model", "text-embedding-3-small"
|
|
286
|
-
)
|
|
282
|
+
default_model = (config or {}).get("default_embedding_model", "text-embedding-3-small")
|
|
287
283
|
|
|
288
284
|
if provider_type == "azure":
|
|
289
|
-
self.embedding_provider = AzureOpenAIEmbeddingProvider(
|
|
290
|
-
default_model=default_model
|
|
291
|
-
)
|
|
285
|
+
self.embedding_provider = AzureOpenAIEmbeddingProvider(default_model=default_model)
|
|
292
286
|
logger.info(
|
|
293
287
|
f"Auto-detected Azure OpenAI embedding provider (model: {default_model})"
|
|
294
288
|
)
|
|
295
289
|
else:
|
|
296
|
-
self.embedding_provider = OpenAIEmbeddingProvider(
|
|
297
|
-
|
|
298
|
-
)
|
|
299
|
-
logger.info(
|
|
300
|
-
f"Auto-detected OpenAI embedding provider (model: {default_model})"
|
|
301
|
-
)
|
|
290
|
+
self.embedding_provider = OpenAIEmbeddingProvider(default_model=default_model)
|
|
291
|
+
logger.info(f"Auto-detected OpenAI embedding provider (model: {default_model})")
|
|
302
292
|
|
|
303
293
|
# Store config for potential future use
|
|
304
294
|
self.config = config or {}
|
|
@@ -341,7 +331,7 @@ class EmbeddingProvider:
|
|
|
341
331
|
return vectors
|
|
342
332
|
|
|
343
333
|
except (AttributeError, TypeError, ValueError, RuntimeError, KeyError) as e:
|
|
344
|
-
logger.
|
|
334
|
+
logger.exception(f"EMBED_FAILED: {str(e)}")
|
|
345
335
|
raise EmbeddingServiceError(f"Embedding failed: {str(e)}") from e
|
|
346
336
|
|
|
347
337
|
|
|
@@ -573,7 +563,7 @@ class EmbeddingService:
|
|
|
573
563
|
ConnectionError,
|
|
574
564
|
OSError,
|
|
575
565
|
) as e:
|
|
576
|
-
logger.
|
|
566
|
+
logger.exception(f"Failed to generate embeddings for {source_id}: {e}")
|
|
577
567
|
raise EmbeddingServiceError(f"Embedding generation failed: {str(e)}") from e
|
|
578
568
|
|
|
579
569
|
if len(vectors) != len(chunks):
|
|
@@ -614,9 +604,7 @@ class EmbeddingService:
|
|
|
614
604
|
result = await collection.insert_many(documents_to_insert)
|
|
615
605
|
inserted_count = len(result.inserted_ids)
|
|
616
606
|
|
|
617
|
-
logger.info(
|
|
618
|
-
f"Successfully inserted {inserted_count} documents for source: {source_id}"
|
|
619
|
-
)
|
|
607
|
+
logger.info(f"Successfully inserted {inserted_count} documents for source: {source_id}")
|
|
620
608
|
|
|
621
609
|
return {
|
|
622
610
|
"chunks_created": len(chunks),
|
|
@@ -632,9 +620,7 @@ class EmbeddingService:
|
|
|
632
620
|
KeyError,
|
|
633
621
|
ConnectionError,
|
|
634
622
|
) as e:
|
|
635
|
-
logger.error(
|
|
636
|
-
f"Failed to store documents for {source_id}: {e}", exc_info=True
|
|
637
|
-
)
|
|
623
|
+
logger.error(f"Failed to store documents for {source_id}: {e}", exc_info=True)
|
|
638
624
|
raise EmbeddingServiceError(f"Storage failed: {str(e)}") from e
|
|
639
625
|
|
|
640
626
|
async def process_text(
|
mdb_engine/exceptions.py
CHANGED
|
@@ -165,3 +165,95 @@ class ConfigurationError(MongoDBEngineError):
|
|
|
165
165
|
super().__init__(message, context=context)
|
|
166
166
|
self.config_key = config_key
|
|
167
167
|
self.config_value = config_value
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class QueryValidationError(MongoDBEngineError):
|
|
171
|
+
"""
|
|
172
|
+
Raised when a query fails validation checks.
|
|
173
|
+
|
|
174
|
+
This exception is raised when a query contains dangerous operators,
|
|
175
|
+
exceeds complexity limits, or violates security policies.
|
|
176
|
+
|
|
177
|
+
Attributes:
|
|
178
|
+
message: Error message
|
|
179
|
+
query_type: Type of query that failed (filter, pipeline, etc.)
|
|
180
|
+
operator: Dangerous operator that was found (if applicable)
|
|
181
|
+
path: JSON path where the issue was found (if applicable)
|
|
182
|
+
context: Additional context information
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
def __init__(
|
|
186
|
+
self,
|
|
187
|
+
message: str,
|
|
188
|
+
query_type: Optional[str] = None,
|
|
189
|
+
operator: Optional[str] = None,
|
|
190
|
+
path: Optional[str] = None,
|
|
191
|
+
context: Optional[Dict[str, Any]] = None,
|
|
192
|
+
) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Initialize the query validation error.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
message: Error message
|
|
198
|
+
query_type: Type of query that failed (filter, pipeline, etc.)
|
|
199
|
+
operator: Dangerous operator that was found (if applicable)
|
|
200
|
+
path: JSON path where the issue was found (if applicable)
|
|
201
|
+
context: Additional context information
|
|
202
|
+
"""
|
|
203
|
+
context = context or {}
|
|
204
|
+
if query_type:
|
|
205
|
+
context["query_type"] = query_type
|
|
206
|
+
if operator:
|
|
207
|
+
context["operator"] = operator
|
|
208
|
+
if path:
|
|
209
|
+
context["path"] = path
|
|
210
|
+
super().__init__(message, context=context)
|
|
211
|
+
self.query_type = query_type
|
|
212
|
+
self.operator = operator
|
|
213
|
+
self.path = path
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class ResourceLimitExceeded(MongoDBEngineError):
|
|
217
|
+
"""
|
|
218
|
+
Raised when a resource limit is exceeded.
|
|
219
|
+
|
|
220
|
+
This exception is raised when queries exceed timeouts, result sizes,
|
|
221
|
+
or other resource limits.
|
|
222
|
+
|
|
223
|
+
Attributes:
|
|
224
|
+
message: Error message
|
|
225
|
+
limit_type: Type of limit that was exceeded (timeout, size, etc.)
|
|
226
|
+
limit_value: The limit value that was exceeded
|
|
227
|
+
actual_value: The actual value that exceeded the limit
|
|
228
|
+
context: Additional context information
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def __init__(
|
|
232
|
+
self,
|
|
233
|
+
message: str,
|
|
234
|
+
limit_type: Optional[str] = None,
|
|
235
|
+
limit_value: Optional[Any] = None,
|
|
236
|
+
actual_value: Optional[Any] = None,
|
|
237
|
+
context: Optional[Dict[str, Any]] = None,
|
|
238
|
+
) -> None:
|
|
239
|
+
"""
|
|
240
|
+
Initialize the resource limit exceeded error.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
message: Error message
|
|
244
|
+
limit_type: Type of limit that was exceeded (timeout, size, etc.)
|
|
245
|
+
limit_value: The limit value that was exceeded
|
|
246
|
+
actual_value: The actual value that exceeded the limit
|
|
247
|
+
context: Additional context information
|
|
248
|
+
"""
|
|
249
|
+
context = context or {}
|
|
250
|
+
if limit_type:
|
|
251
|
+
context["limit_type"] = limit_type
|
|
252
|
+
if limit_value is not None:
|
|
253
|
+
context["limit_value"] = limit_value
|
|
254
|
+
if actual_value is not None:
|
|
255
|
+
context["actual_value"] = actual_value
|
|
256
|
+
super().__init__(message, context=context)
|
|
257
|
+
self.limit_type = limit_type
|
|
258
|
+
self.limit_value = limit_value
|
|
259
|
+
self.actual_value = actual_value
|
mdb_engine/indexes/README.md
CHANGED
|
@@ -573,7 +573,7 @@ try:
|
|
|
573
573
|
collection_name="users",
|
|
574
574
|
index_definitions=index_definitions
|
|
575
575
|
)
|
|
576
|
-
except
|
|
576
|
+
except (PyMongoError, ValueError, TypeError) as e:
|
|
577
577
|
logger.error(f"Failed to create indexes: {e}", exc_info=True)
|
|
578
578
|
raise
|
|
579
579
|
```
|
|
@@ -613,12 +613,20 @@ index_definitions = [
|
|
|
613
613
|
}
|
|
614
614
|
]
|
|
615
615
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
616
|
+
# Get scoped database and collection
|
|
617
|
+
db = engine.get_scoped_db("my_app")
|
|
618
|
+
collection = db.users
|
|
619
|
+
|
|
620
|
+
# Use collection.index_manager for index operations
|
|
621
|
+
index_manager = collection.index_manager
|
|
622
|
+
for index_def in index_definitions:
|
|
623
|
+
if index_def["type"] == "regular":
|
|
624
|
+
await index_manager.create_index(
|
|
625
|
+
keys=list(index_def["keys"].items()),
|
|
626
|
+
name=index_def.get("name"),
|
|
627
|
+
**index_def.get("options", {})
|
|
628
|
+
)
|
|
629
|
+
# Handle other index types similarly...
|
|
622
630
|
```
|
|
623
631
|
|
|
624
632
|
### Multiple Collections
|
|
@@ -635,13 +643,22 @@ collections_with_indexes = {
|
|
|
635
643
|
]
|
|
636
644
|
}
|
|
637
645
|
|
|
646
|
+
# Get scoped database
|
|
647
|
+
db = engine.get_scoped_db("my_app")
|
|
648
|
+
|
|
649
|
+
# Use collection.index_manager for each collection
|
|
638
650
|
for collection_name, index_definitions in collections_with_indexes.items():
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
651
|
+
collection = getattr(db, collection_name)
|
|
652
|
+
index_manager = collection.index_manager
|
|
653
|
+
|
|
654
|
+
for index_def in index_definitions:
|
|
655
|
+
if index_def["type"] == "regular":
|
|
656
|
+
await index_manager.create_index(
|
|
657
|
+
keys=list(index_def["keys"].items()),
|
|
658
|
+
name=index_def.get("name"),
|
|
659
|
+
**index_def.get("options", {})
|
|
660
|
+
)
|
|
661
|
+
# Handle other index types similarly...
|
|
645
662
|
```
|
|
646
663
|
|
|
647
664
|
## Related Modules
|
mdb_engine/indexes/__init__.py
CHANGED
|
@@ -8,6 +8,7 @@ This module is part of MDB_ENGINE - MongoDB Engine.
|
|
|
8
8
|
|
|
9
9
|
# Re-export index managers from database module for convenience
|
|
10
10
|
from ..database.scoped_wrapper import AsyncAtlasIndexManager, AutoIndexManager
|
|
11
|
+
|
|
11
12
|
# Export high-level management functions
|
|
12
13
|
from .manager import normalize_json_def, run_index_creation_for_collection
|
|
13
14
|
|
mdb_engine/indexes/helpers.py
CHANGED
|
@@ -12,7 +12,7 @@ logger = logging.getLogger(__name__)
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def normalize_keys(
|
|
15
|
-
keys: Union[Dict[str, Any], List[Tuple[str, Any]]]
|
|
15
|
+
keys: Union[Dict[str, Any], List[Tuple[str, Any]]],
|
|
16
16
|
) -> List[Tuple[str, Any]]:
|
|
17
17
|
"""
|
|
18
18
|
Normalize index keys to a consistent format.
|