mdb-engine 0.1.6__py3-none-any.whl → 0.2.0__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 (87) hide show
  1. mdb_engine/__init__.py +104 -11
  2. mdb_engine/auth/ARCHITECTURE.md +112 -0
  3. mdb_engine/auth/README.md +648 -11
  4. mdb_engine/auth/__init__.py +136 -29
  5. mdb_engine/auth/audit.py +592 -0
  6. mdb_engine/auth/base.py +252 -0
  7. mdb_engine/auth/casbin_factory.py +264 -69
  8. mdb_engine/auth/config_helpers.py +7 -6
  9. mdb_engine/auth/cookie_utils.py +3 -7
  10. mdb_engine/auth/csrf.py +373 -0
  11. mdb_engine/auth/decorators.py +3 -10
  12. mdb_engine/auth/dependencies.py +47 -50
  13. mdb_engine/auth/helpers.py +3 -3
  14. mdb_engine/auth/integration.py +53 -80
  15. mdb_engine/auth/jwt.py +2 -6
  16. mdb_engine/auth/middleware.py +77 -34
  17. mdb_engine/auth/oso_factory.py +18 -38
  18. mdb_engine/auth/provider.py +270 -171
  19. mdb_engine/auth/rate_limiter.py +504 -0
  20. mdb_engine/auth/restrictions.py +8 -24
  21. mdb_engine/auth/session_manager.py +14 -29
  22. mdb_engine/auth/shared_middleware.py +600 -0
  23. mdb_engine/auth/shared_users.py +759 -0
  24. mdb_engine/auth/token_store.py +14 -28
  25. mdb_engine/auth/users.py +54 -113
  26. mdb_engine/auth/utils.py +213 -15
  27. mdb_engine/cli/commands/generate.py +545 -9
  28. mdb_engine/cli/commands/validate.py +3 -7
  29. mdb_engine/cli/utils.py +3 -3
  30. mdb_engine/config.py +7 -21
  31. mdb_engine/constants.py +65 -0
  32. mdb_engine/core/README.md +117 -6
  33. mdb_engine/core/__init__.py +39 -7
  34. mdb_engine/core/app_registration.py +22 -41
  35. mdb_engine/core/app_secrets.py +290 -0
  36. mdb_engine/core/connection.py +18 -9
  37. mdb_engine/core/encryption.py +223 -0
  38. mdb_engine/core/engine.py +1057 -93
  39. mdb_engine/core/index_management.py +12 -16
  40. mdb_engine/core/manifest.py +459 -150
  41. mdb_engine/core/ray_integration.py +435 -0
  42. mdb_engine/core/seeding.py +10 -18
  43. mdb_engine/core/service_initialization.py +12 -23
  44. mdb_engine/core/types.py +2 -5
  45. mdb_engine/database/README.md +140 -17
  46. mdb_engine/database/__init__.py +17 -6
  47. mdb_engine/database/abstraction.py +25 -37
  48. mdb_engine/database/connection.py +11 -18
  49. mdb_engine/database/query_validator.py +367 -0
  50. mdb_engine/database/resource_limiter.py +204 -0
  51. mdb_engine/database/scoped_wrapper.py +713 -196
  52. mdb_engine/dependencies.py +426 -0
  53. mdb_engine/di/__init__.py +34 -0
  54. mdb_engine/di/container.py +248 -0
  55. mdb_engine/di/providers.py +205 -0
  56. mdb_engine/di/scopes.py +139 -0
  57. mdb_engine/embeddings/README.md +54 -24
  58. mdb_engine/embeddings/__init__.py +31 -24
  59. mdb_engine/embeddings/dependencies.py +37 -154
  60. mdb_engine/embeddings/service.py +11 -25
  61. mdb_engine/exceptions.py +92 -0
  62. mdb_engine/indexes/README.md +30 -13
  63. mdb_engine/indexes/__init__.py +1 -0
  64. mdb_engine/indexes/helpers.py +1 -1
  65. mdb_engine/indexes/manager.py +50 -114
  66. mdb_engine/memory/README.md +2 -2
  67. mdb_engine/memory/__init__.py +1 -2
  68. mdb_engine/memory/service.py +30 -87
  69. mdb_engine/observability/README.md +4 -2
  70. mdb_engine/observability/__init__.py +26 -9
  71. mdb_engine/observability/health.py +8 -9
  72. mdb_engine/observability/metrics.py +32 -12
  73. mdb_engine/repositories/__init__.py +34 -0
  74. mdb_engine/repositories/base.py +325 -0
  75. mdb_engine/repositories/mongo.py +233 -0
  76. mdb_engine/repositories/unit_of_work.py +166 -0
  77. mdb_engine/routing/README.md +1 -1
  78. mdb_engine/routing/__init__.py +1 -3
  79. mdb_engine/routing/websockets.py +25 -60
  80. mdb_engine-0.2.0.dist-info/METADATA +313 -0
  81. mdb_engine-0.2.0.dist-info/RECORD +96 -0
  82. mdb_engine-0.1.6.dist-info/METADATA +0 -213
  83. mdb_engine-0.1.6.dist-info/RECORD +0 -75
  84. {mdb_engine-0.1.6.dist-info → mdb_engine-0.2.0.dist-info}/WHEEL +0 -0
  85. {mdb_engine-0.1.6.dist-info → mdb_engine-0.2.0.dist-info}/entry_points.txt +0 -0
  86. {mdb_engine-0.1.6.dist-info → mdb_engine-0.2.0.dist-info}/licenses/LICENSE +0 -0
  87. {mdb_engine-0.1.6.dist-info → mdb_engine-0.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,435 @@
1
+ """
2
+ Optional Ray Integration for MDB Engine.
3
+
4
+ Provides optional Ray support for distributed processing with app isolation.
5
+ This module gracefully degrades if Ray is not installed.
6
+
7
+ Usage:
8
+ # Check if Ray is available
9
+ from mdb_engine.core.ray_integration import RAY_AVAILABLE
10
+
11
+ if RAY_AVAILABLE:
12
+ from mdb_engine.core.ray_integration import (
13
+ AppRayActor,
14
+ get_ray_actor_handle,
15
+ ray_actor_decorator,
16
+ )
17
+
18
+ # Or use the helper that handles availability
19
+ actor = await get_ray_actor_handle("my_app")
20
+ if actor:
21
+ result = await actor.process.remote(data)
22
+
23
+ This module is part of MDB_ENGINE - MongoDB Engine.
24
+ """
25
+
26
+ import logging
27
+ import os
28
+ from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar
29
+
30
+ if TYPE_CHECKING:
31
+ pass
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+ # --- Ray Availability Check ---
36
+ # This flag allows code to check Ray availability without try/except
37
+ RAY_AVAILABLE = False
38
+ ray = None
39
+
40
+ try:
41
+ import ray as _ray
42
+
43
+ ray = _ray
44
+ RAY_AVAILABLE = True
45
+ logger.debug("Ray is available")
46
+ except ImportError:
47
+ logger.debug("Ray not installed - Ray features will be disabled")
48
+
49
+
50
+ # Type variable for decorator
51
+ T = TypeVar("T")
52
+
53
+
54
+ class AppRayActor:
55
+ """
56
+ Base Ray actor class for app-specific isolated environments.
57
+
58
+ Each app can have its own Ray actor with:
59
+ - Isolated MongoDB connection
60
+ - App-specific configuration
61
+ - Isolated state
62
+
63
+ Subclass this to create app-specific actors:
64
+
65
+ @ray.remote
66
+ class MyAppActor(AppRayActor):
67
+ async def process(self, data):
68
+ db = await self.get_app_db()
69
+ # Process with isolated DB access
70
+ return result
71
+
72
+ Attributes:
73
+ app_slug: Application identifier
74
+ mongo_uri: MongoDB connection URI
75
+ db_name: Database name
76
+ use_in_memory_fallback: Whether to use in-memory DB if MongoDB unavailable
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ app_slug: str,
82
+ mongo_uri: str,
83
+ db_name: str,
84
+ use_in_memory_fallback: bool = False,
85
+ ) -> None:
86
+ """
87
+ Initialize app-specific Ray actor.
88
+
89
+ Args:
90
+ app_slug: Application identifier
91
+ mongo_uri: MongoDB connection URI
92
+ db_name: Database name
93
+ use_in_memory_fallback: Use in-memory DB if MongoDB unavailable
94
+ """
95
+ self.app_slug = app_slug
96
+ self.mongo_uri = mongo_uri
97
+ self.db_name = db_name
98
+ self.use_in_memory_fallback = use_in_memory_fallback
99
+
100
+ # Lazy initialization for engine
101
+ self._engine = None
102
+ self._initialized = False
103
+
104
+ logger.info(f"AppRayActor created for '{app_slug}' " f"(fallback={use_in_memory_fallback})")
105
+
106
+ async def _ensure_initialized(self) -> None:
107
+ """
108
+ Ensure the actor is initialized with database connection.
109
+
110
+ Called lazily on first database access.
111
+ """
112
+ if self._initialized:
113
+ return
114
+
115
+ try:
116
+ from .engine import MongoDBEngine
117
+
118
+ self._engine = MongoDBEngine(
119
+ mongo_uri=self.mongo_uri,
120
+ db_name=self.db_name,
121
+ )
122
+ await self._engine.initialize()
123
+ self._initialized = True
124
+ logger.info(f"AppRayActor engine initialized for '{self.app_slug}'")
125
+
126
+ except (ConnectionError, ValueError, RuntimeError, OSError) as e:
127
+ logger.exception(f"Error initializing engine in Ray actor for '{self.app_slug}': {e}")
128
+ if self.use_in_memory_fallback:
129
+ logger.warning(f"Using in-memory fallback for '{self.app_slug}'")
130
+ self._engine = None
131
+ self._initialized = True
132
+ else:
133
+ raise
134
+
135
+ async def get_app_db(self, app_token: Optional[str] = None) -> Any:
136
+ """
137
+ Get scoped database for this app.
138
+
139
+ Args:
140
+ app_token: Optional app token for authentication
141
+
142
+ Returns:
143
+ ScopedMongoWrapper for this app
144
+
145
+ Raises:
146
+ RuntimeError: If engine not available and no fallback
147
+ """
148
+ await self._ensure_initialized()
149
+
150
+ if not self._engine:
151
+ if self.use_in_memory_fallback:
152
+ raise RuntimeError(f"In-memory fallback not yet implemented for '{self.app_slug}'")
153
+ raise RuntimeError(f"Engine not available for '{self.app_slug}'")
154
+
155
+ # Try to get app token from environment if not provided
156
+ if not app_token:
157
+ env_var_name = f"{self.app_slug.upper()}_SECRET"
158
+ app_token = os.getenv(env_var_name)
159
+
160
+ return self._engine.get_scoped_db(self.app_slug, app_token=app_token)
161
+
162
+ def get_app_slug(self) -> str:
163
+ """Get the app slug."""
164
+ return self.app_slug
165
+
166
+ async def health_check(self) -> dict:
167
+ """
168
+ Health check for the actor.
169
+
170
+ Returns:
171
+ Dict with health status information
172
+ """
173
+ await self._ensure_initialized()
174
+
175
+ return {
176
+ "app_slug": self.app_slug,
177
+ "initialized": self._initialized,
178
+ "engine_available": self._engine is not None,
179
+ "status": "healthy" if self._initialized else "initializing",
180
+ }
181
+
182
+ async def shutdown(self) -> None:
183
+ """Shutdown the actor and release resources."""
184
+ if self._engine:
185
+ await self._engine.shutdown()
186
+ self._engine = None
187
+ self._initialized = False
188
+ logger.info(f"AppRayActor shutdown for '{self.app_slug}'")
189
+
190
+
191
+ async def get_ray_actor_handle(
192
+ app_slug: str,
193
+ namespace: str = "modular_labs",
194
+ mongo_uri: Optional[str] = None,
195
+ db_name: Optional[str] = None,
196
+ create_if_missing: bool = True,
197
+ actor_class: Optional[type] = None,
198
+ ) -> Optional[Any]:
199
+ """
200
+ Get or create a Ray actor handle for an app.
201
+
202
+ This function:
203
+ 1. Checks if Ray is available
204
+ 2. Initializes Ray if not already done
205
+ 3. Tries to get existing actor by name
206
+ 4. Creates new actor if missing and create_if_missing=True
207
+
208
+ Args:
209
+ app_slug: Application identifier
210
+ namespace: Ray namespace (default: "modular_labs")
211
+ mongo_uri: MongoDB URI (default: from MONGODB_URI env var)
212
+ db_name: Database name (default: from MONGODB_DB env var)
213
+ create_if_missing: Create actor if it doesn't exist (default: True)
214
+ actor_class: Custom actor class to use (default: AppRayActor)
215
+
216
+ Returns:
217
+ Ray actor handle, or None if Ray unavailable or actor not found
218
+
219
+ Example:
220
+ # Get or create actor
221
+ actor = await get_ray_actor_handle("my_app")
222
+ if actor:
223
+ result = await actor.process.remote(data)
224
+
225
+ # Get existing actor only
226
+ actor = await get_ray_actor_handle("my_app", create_if_missing=False)
227
+ """
228
+ if not RAY_AVAILABLE:
229
+ logger.debug(f"Ray not available - cannot get actor for '{app_slug}'")
230
+ return None
231
+
232
+ actor_name = f"{app_slug}-actor"
233
+
234
+ # Ensure Ray is initialized
235
+ if not ray.is_initialized():
236
+ ray_address = os.getenv("RAY_ADDRESS")
237
+ if ray_address:
238
+ try:
239
+ ray.init(address=ray_address, namespace=namespace)
240
+ logger.info(f"Ray initialized with address: {ray_address}")
241
+ except (RuntimeError, ConnectionError) as e:
242
+ logger.exception(f"Failed to initialize Ray: {e}")
243
+ return None
244
+ else:
245
+ try:
246
+ # Initialize local Ray instance
247
+ ray.init(namespace=namespace, ignore_reinit_error=True)
248
+ logger.info("Ray initialized locally")
249
+ except RuntimeError as e:
250
+ logger.exception(f"Failed to initialize local Ray: {e}")
251
+ return None
252
+
253
+ # Try to get existing actor
254
+ try:
255
+ handle = ray.get_actor(actor_name, namespace=namespace)
256
+ logger.debug(f"Found existing Ray actor: {actor_name}")
257
+ return handle
258
+ except ValueError:
259
+ # Actor doesn't exist
260
+ if not create_if_missing:
261
+ logger.debug(f"Ray actor '{actor_name}' not found")
262
+ return None
263
+
264
+ # Create new actor
265
+ try:
266
+ # Use provided class or default to AppRayActor
267
+ cls = actor_class or AppRayActor
268
+
269
+ # Make it a Ray remote class if not already
270
+ if not hasattr(cls, "remote"):
271
+ cls = ray.remote(cls)
272
+
273
+ # Get connection parameters
274
+ uri = mongo_uri or os.getenv("MONGODB_URI", "mongodb://localhost:27017")
275
+ db = db_name or os.getenv("MONGODB_DB", "mdb_runtime")
276
+
277
+ handle = cls.options(
278
+ name=actor_name,
279
+ namespace=namespace,
280
+ lifetime="detached",
281
+ get_if_exists=True,
282
+ ).remote(
283
+ app_slug=app_slug,
284
+ mongo_uri=uri,
285
+ db_name=db,
286
+ )
287
+
288
+ logger.info(f"Created Ray actor '{actor_name}' in namespace '{namespace}'")
289
+ return handle
290
+
291
+ except ray.exceptions.RayError as e:
292
+ logger.error(f"Error creating Ray actor for '{app_slug}': {e}", exc_info=True)
293
+ return None
294
+
295
+
296
+ def ray_actor_decorator(
297
+ app_slug: Optional[str] = None,
298
+ namespace: str = "modular_labs",
299
+ isolated: bool = True,
300
+ lifetime: str = "detached",
301
+ max_restarts: int = -1,
302
+ ) -> Callable[[type], type]:
303
+ """
304
+ Decorator for creating Ray actors with app isolation.
305
+
306
+ This decorator:
307
+ 1. Converts a class to a Ray remote class
308
+ 2. Adds app-specific namespace (if isolated=True)
309
+ 3. Provides a convenient spawn() class method
310
+
311
+ Args:
312
+ app_slug: Application identifier. If None, derived from class name
313
+ namespace: Base Ray namespace (default: "modular_labs")
314
+ isolated: Use app-specific namespace for isolation (default: True)
315
+ lifetime: Actor lifetime ("detached" or "non_detached")
316
+ max_restarts: Max automatic restarts (-1 for unlimited)
317
+
318
+ Returns:
319
+ Decorated class
320
+
321
+ Example:
322
+ @ray_actor_decorator(app_slug="my_app", isolated=True)
323
+ class MyAppActor(AppRayActor):
324
+ async def process(self, data):
325
+ db = await self.get_app_db()
326
+ return await db.items.find_one({"id": data["id"]})
327
+
328
+ # Spawn the actor
329
+ actor = MyAppActor.spawn()
330
+ result = await actor.process.remote({"id": "123"})
331
+
332
+ Note:
333
+ If Ray is not available, returns the class unchanged (no-op decorator).
334
+ """
335
+ if not RAY_AVAILABLE:
336
+
337
+ def noop_decorator(cls: type) -> type:
338
+ logger.debug(f"Ray not available - {cls.__name__} not converted to Ray actor")
339
+ return cls
340
+
341
+ return noop_decorator
342
+
343
+ def decorator(cls: type) -> type:
344
+ # Determine app slug from class name if not provided
345
+ actor_app_slug = app_slug
346
+ if actor_app_slug is None:
347
+ # Convert class name to slug: MyAppActor -> my_app
348
+ name = cls.__name__
349
+ if name.endswith("Actor"):
350
+ name = name[:-5]
351
+ # Convert CamelCase to snake_case
352
+ import re
353
+
354
+ actor_app_slug = re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
355
+
356
+ # Determine namespace
357
+ actor_namespace = f"{namespace}_{actor_app_slug}" if isolated else namespace
358
+
359
+ # Convert to Ray remote class
360
+ ray_cls = ray.remote(cls)
361
+
362
+ # Store metadata on the class
363
+ ray_cls._app_slug = actor_app_slug
364
+ ray_cls._namespace = actor_namespace
365
+ ray_cls._isolated = isolated
366
+
367
+ # Add spawn class method
368
+ @classmethod
369
+ def spawn(
370
+ cls,
371
+ *args,
372
+ mongo_uri: Optional[str] = None,
373
+ db_name: Optional[str] = None,
374
+ **kwargs,
375
+ ):
376
+ """
377
+ Spawn an instance of this actor.
378
+
379
+ Args:
380
+ *args: Positional arguments for actor __init__
381
+ mongo_uri: MongoDB URI (default: from env)
382
+ db_name: Database name (default: from env)
383
+ **kwargs: Keyword arguments for actor __init__
384
+
385
+ Returns:
386
+ Ray actor handle
387
+ """
388
+ actor_name = f"{actor_app_slug}-{cls.__name__.lower()}"
389
+
390
+ # Get connection parameters if not in kwargs
391
+ if "mongo_uri" not in kwargs:
392
+ kwargs["mongo_uri"] = mongo_uri or os.getenv(
393
+ "MONGODB_URI", "mongodb://localhost:27017"
394
+ )
395
+ if "db_name" not in kwargs:
396
+ kwargs["db_name"] = db_name or os.getenv("MONGODB_DB", "mdb_runtime")
397
+ if "app_slug" not in kwargs:
398
+ kwargs["app_slug"] = actor_app_slug
399
+
400
+ return cls.options(
401
+ name=actor_name,
402
+ namespace=actor_namespace,
403
+ lifetime=lifetime,
404
+ max_restarts=max_restarts,
405
+ get_if_exists=True,
406
+ ).remote(*args, **kwargs)
407
+
408
+ ray_cls.spawn = spawn
409
+
410
+ logger.debug(
411
+ f"Created Ray actor class '{cls.__name__}' "
412
+ f"(app_slug={actor_app_slug}, namespace={actor_namespace})"
413
+ )
414
+
415
+ return ray_cls
416
+
417
+ return decorator
418
+
419
+
420
+ # Convenience aliases
421
+ if RAY_AVAILABLE:
422
+ # Export ray module for convenience
423
+ get_actor = ray.get_actor
424
+ init_ray = ray.init
425
+ is_initialized = ray.is_initialized
426
+ else:
427
+ # Stub functions when Ray not available
428
+ def get_actor(*args, **kwargs):
429
+ raise RuntimeError("Ray is not available")
430
+
431
+ def init_ray(*args, **kwargs):
432
+ raise RuntimeError("Ray is not available")
433
+
434
+ def is_initialized():
435
+ return False
@@ -10,8 +10,11 @@ import logging
10
10
  from datetime import datetime
11
11
  from typing import Any, Dict, List
12
12
 
13
- from pymongo.errors import (ConnectionFailure, OperationFailure,
14
- ServerSelectionTimeoutError)
13
+ from pymongo.errors import (
14
+ ConnectionFailure,
15
+ OperationFailure,
16
+ ServerSelectionTimeoutError,
17
+ )
15
18
 
16
19
  logger = logging.getLogger(__name__)
17
20
 
@@ -47,9 +50,7 @@ async def seed_initial_data(
47
50
  # Get existing seeding metadata
48
51
  seeding_metadata = await metadata_collection.find_one({"app_slug": app_slug})
49
52
  seeded_collections = (
50
- set(seeding_metadata.get("seeded_collections", []))
51
- if seeding_metadata
52
- else set()
53
+ set(seeding_metadata.get("seeded_collections", [])) if seeding_metadata else set()
53
54
  )
54
55
 
55
56
  for collection_name, documents in initial_data.items():
@@ -90,9 +91,7 @@ async def seed_initial_data(
90
91
  # Try to parse ISO format datetime strings
91
92
  try:
92
93
  # Check if it looks like a datetime string
93
- if "T" in value and (
94
- "Z" in value or "+" in value or "-" in value[-6:]
95
- ):
94
+ if "T" in value and ("Z" in value or "+" in value or "-" in value[-6:]):
96
95
  # Try parsing as ISO format
97
96
  from dateutil.parser import parse as parse_date
98
97
 
@@ -110,10 +109,7 @@ async def seed_initial_data(
110
109
  pass
111
110
 
112
111
  # Add created_at if not present and document doesn't have timestamp fields
113
- if (
114
- "created_at" not in prepared_doc
115
- and "date_created" not in prepared_doc
116
- ):
112
+ if "created_at" not in prepared_doc and "date_created" not in prepared_doc:
117
113
  prepared_doc["created_at"] = datetime.utcnow()
118
114
 
119
115
  prepared_docs.append(prepared_doc)
@@ -144,9 +140,7 @@ async def seed_initial_data(
144
140
  Exception,
145
141
  ) as e:
146
142
  # Type 2: Recoverable - log error and continue with other collections
147
- logger.exception(
148
- f"Failed to seed collection '{collection_name}' for {app_slug}: {e}"
149
- )
143
+ logger.exception(f"Failed to seed collection '{collection_name}' for {app_slug}: {e}")
150
144
  results[collection_name] = 0
151
145
 
152
146
  # Update seeding metadata
@@ -172,8 +166,6 @@ async def seed_initial_data(
172
166
  TypeError,
173
167
  KeyError,
174
168
  ) as e:
175
- logger.warning(
176
- f"Failed to update seeding metadata for {app_slug}: {e}", exc_info=True
177
- )
169
+ logger.warning(f"Failed to update seeding metadata for {app_slug}: {e}", exc_info=True)
178
170
 
179
171
  return results
@@ -13,8 +13,11 @@ This module is part of MDB_ENGINE - MongoDB Engine.
13
13
  import logging
14
14
  from typing import Any, Callable, Dict, List, Optional
15
15
 
16
- from pymongo.errors import (ConnectionFailure, OperationFailure,
17
- ServerSelectionTimeoutError)
16
+ from pymongo.errors import (
17
+ ConnectionFailure,
18
+ OperationFailure,
19
+ ServerSelectionTimeoutError,
20
+ )
18
21
 
19
22
  from ..database import ScopedMongoWrapper
20
23
  from ..observability import get_logger as get_contextual_logger
@@ -50,9 +53,7 @@ class ServiceInitializer:
50
53
  self._memory_services: Dict[str, Any] = {}
51
54
  self._websocket_configs: Dict[str, Dict[str, Any]] = {}
52
55
 
53
- async def initialize_memory_service(
54
- self, slug: str, memory_config: Dict[str, Any]
55
- ) -> None:
56
+ async def initialize_memory_service(self, slug: str, memory_config: Dict[str, Any]) -> None:
56
57
  """
57
58
  Initialize Mem0 memory service for an app.
58
59
 
@@ -79,9 +80,7 @@ class ServiceInitializer:
79
80
  f"Initializing Mem0 memory service for app '{slug}'",
80
81
  extra={
81
82
  "app_slug": slug,
82
- "collection_name": memory_config.get(
83
- "collection_name", f"{slug}_memories"
84
- ),
83
+ "collection_name": memory_config.get("collection_name", f"{slug}_memories"),
85
84
  "enable_graph": memory_config.get("enable_graph", False),
86
85
  "embedding_model_dims": memory_config.get("embedding_model_dims", 1536),
87
86
  "infer": memory_config.get("infer", True),
@@ -152,9 +151,7 @@ class ServiceInitializer:
152
151
  exc_info=True,
153
152
  )
154
153
 
155
- async def register_websockets(
156
- self, slug: str, websockets_config: Dict[str, Any]
157
- ) -> None:
154
+ async def register_websockets(self, slug: str, websockets_config: Dict[str, Any]) -> None:
158
155
  """
159
156
  Register WebSocket endpoints for an app.
160
157
 
@@ -190,9 +187,7 @@ class ServiceInitializer:
190
187
  try:
191
188
  await get_websocket_manager(slug)
192
189
  except (ImportError, AttributeError, RuntimeError) as e:
193
- contextual_logger.warning(
194
- f"Could not initialize WebSocket manager for {slug}: {e}"
195
- )
190
+ contextual_logger.warning(f"Could not initialize WebSocket manager for {slug}: {e}")
196
191
  continue
197
192
  contextual_logger.debug(
198
193
  f"Configured WebSocket endpoint '{endpoint_name}' at path '{path}'",
@@ -221,9 +216,7 @@ class ServiceInitializer:
221
216
  f"Seeded initial data for app '{slug}'",
222
217
  extra={
223
218
  "app_slug": slug,
224
- "collections_seeded": len(
225
- [c for c, count in results.items() if count > 0]
226
- ),
219
+ "collections_seeded": len([c for c, count in results.items() if count > 0]),
227
220
  "total_documents": total_inserted,
228
221
  },
229
222
  )
@@ -276,9 +269,7 @@ class ServiceInitializer:
276
269
  contextual_logger.info(
277
270
  f"Metrics collection configured for {slug}",
278
271
  extra={
279
- "operation_metrics": metrics_config.get(
280
- "collect_operation_metrics", True
281
- ),
272
+ "operation_metrics": metrics_config.get("collect_operation_metrics", True),
282
273
  "performance_metrics": metrics_config.get(
283
274
  "collect_performance_metrics", True
284
275
  ),
@@ -296,9 +287,7 @@ class ServiceInitializer:
296
287
  extra={
297
288
  "level": log_level,
298
289
  "format": log_format,
299
- "include_request_id": logging_config.get(
300
- "include_request_id", True
301
- ),
290
+ "include_request_id": logging_config.get("include_request_id", True),
302
291
  },
303
292
  )
304
293
 
mdb_engine/core/types.py CHANGED
@@ -8,8 +8,7 @@ throughout the codebase.
8
8
  This module is part of MDB_ENGINE - MongoDB Engine.
9
9
  """
10
10
 
11
- from typing import (TYPE_CHECKING, Any, Dict, List, Literal, Optional,
12
- TypedDict, Union)
11
+ from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, TypedDict, Union
13
12
 
14
13
  if TYPE_CHECKING:
15
14
  from ..memory import Mem0MemoryService
@@ -344,9 +343,7 @@ class CORSConfigDict(TypedDict, total=False):
344
343
  enabled: bool
345
344
  allow_origins: List[str]
346
345
  allow_credentials: bool
347
- allow_methods: List[
348
- Literal["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD", "*"]
349
- ]
346
+ allow_methods: List[Literal["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD", "*"]]
350
347
  allow_headers: List[str]
351
348
  expose_headers: List[str]
352
349
  max_age: int