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.
Files changed (75) hide show
  1. mdb_engine/__init__.py +38 -6
  2. mdb_engine/auth/README.md +534 -11
  3. mdb_engine/auth/__init__.py +129 -28
  4. mdb_engine/auth/audit.py +592 -0
  5. mdb_engine/auth/casbin_factory.py +10 -14
  6. mdb_engine/auth/config_helpers.py +7 -6
  7. mdb_engine/auth/cookie_utils.py +3 -7
  8. mdb_engine/auth/csrf.py +373 -0
  9. mdb_engine/auth/decorators.py +3 -10
  10. mdb_engine/auth/dependencies.py +37 -45
  11. mdb_engine/auth/helpers.py +3 -3
  12. mdb_engine/auth/integration.py +30 -73
  13. mdb_engine/auth/jwt.py +2 -6
  14. mdb_engine/auth/middleware.py +77 -34
  15. mdb_engine/auth/oso_factory.py +16 -36
  16. mdb_engine/auth/provider.py +17 -38
  17. mdb_engine/auth/rate_limiter.py +504 -0
  18. mdb_engine/auth/restrictions.py +8 -24
  19. mdb_engine/auth/session_manager.py +14 -29
  20. mdb_engine/auth/shared_middleware.py +600 -0
  21. mdb_engine/auth/shared_users.py +759 -0
  22. mdb_engine/auth/token_store.py +14 -28
  23. mdb_engine/auth/users.py +54 -113
  24. mdb_engine/auth/utils.py +213 -15
  25. mdb_engine/cli/commands/generate.py +545 -9
  26. mdb_engine/cli/commands/validate.py +3 -7
  27. mdb_engine/cli/utils.py +3 -3
  28. mdb_engine/config.py +7 -21
  29. mdb_engine/constants.py +65 -0
  30. mdb_engine/core/README.md +117 -6
  31. mdb_engine/core/__init__.py +39 -7
  32. mdb_engine/core/app_registration.py +22 -41
  33. mdb_engine/core/app_secrets.py +290 -0
  34. mdb_engine/core/connection.py +18 -9
  35. mdb_engine/core/encryption.py +223 -0
  36. mdb_engine/core/engine.py +758 -95
  37. mdb_engine/core/index_management.py +12 -16
  38. mdb_engine/core/manifest.py +424 -135
  39. mdb_engine/core/ray_integration.py +435 -0
  40. mdb_engine/core/seeding.py +10 -18
  41. mdb_engine/core/service_initialization.py +12 -23
  42. mdb_engine/core/types.py +2 -5
  43. mdb_engine/database/README.md +112 -16
  44. mdb_engine/database/__init__.py +17 -6
  45. mdb_engine/database/abstraction.py +25 -37
  46. mdb_engine/database/connection.py +11 -18
  47. mdb_engine/database/query_validator.py +367 -0
  48. mdb_engine/database/resource_limiter.py +204 -0
  49. mdb_engine/database/scoped_wrapper.py +713 -196
  50. mdb_engine/embeddings/__init__.py +17 -9
  51. mdb_engine/embeddings/dependencies.py +1 -3
  52. mdb_engine/embeddings/service.py +11 -25
  53. mdb_engine/exceptions.py +92 -0
  54. mdb_engine/indexes/README.md +30 -13
  55. mdb_engine/indexes/__init__.py +1 -0
  56. mdb_engine/indexes/helpers.py +1 -1
  57. mdb_engine/indexes/manager.py +50 -114
  58. mdb_engine/memory/README.md +2 -2
  59. mdb_engine/memory/__init__.py +1 -2
  60. mdb_engine/memory/service.py +30 -87
  61. mdb_engine/observability/README.md +4 -2
  62. mdb_engine/observability/__init__.py +26 -9
  63. mdb_engine/observability/health.py +8 -9
  64. mdb_engine/observability/metrics.py +32 -12
  65. mdb_engine/routing/README.md +1 -1
  66. mdb_engine/routing/__init__.py +1 -3
  67. mdb_engine/routing/websockets.py +25 -60
  68. mdb_engine-0.1.7.dist-info/METADATA +285 -0
  69. mdb_engine-0.1.7.dist-info/RECORD +85 -0
  70. mdb_engine-0.1.6.dist-info/METADATA +0 -213
  71. mdb_engine-0.1.6.dist-info/RECORD +0 -75
  72. {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/WHEEL +0 -0
  73. {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/entry_points.txt +0 -0
  74. {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/licenses/LICENSE +0 -0
  75. {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 (create_embedding_dependency,
39
- get_embedding_service_dep,
40
- get_embedding_service_dependency,
41
- get_embedding_service_for_app, get_global_engine,
42
- set_global_engine)
43
- from .service import (AzureOpenAIEmbeddingProvider, BaseEmbeddingProvider,
44
- EmbeddingProvider, EmbeddingService,
45
- EmbeddingServiceError, OpenAIEmbeddingProvider,
46
- get_embedding_service)
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
@@ -134,7 +134,7 @@ class OpenAIEmbeddingProvider(BaseEmbeddingProvider):
134
134
  ConnectionError,
135
135
  OSError,
136
136
  ) as e:
137
- logger.error(f"OpenAI embedding failed: {e}")
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.error(f"Azure OpenAI embedding failed: {e}")
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
- default_model=default_model
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.error(f"EMBED_FAILED: {str(e)}")
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.error(f"Failed to generate embeddings for {source_id}: {e}")
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
@@ -573,7 +573,7 @@ try:
573
573
  collection_name="users",
574
574
  index_definitions=index_definitions
575
575
  )
576
- except Exception as e:
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
- await run_index_creation_for_collection(
617
- db=engine.mongo_db,
618
- slug="my_app",
619
- collection_name="users",
620
- index_definitions=index_definitions
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
- await run_index_creation_for_collection(
640
- db=engine.mongo_db,
641
- slug="my_app",
642
- collection_name=collection_name,
643
- index_definitions=index_definitions
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
@@ -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
 
@@ -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.