mdb-engine 0.7.0__py3-none-any.whl → 0.7.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.
mdb_engine/__init__.py CHANGED
@@ -82,19 +82,13 @@ from .repositories import Entity, MongoRepository, Repository, UnitOfWork
82
82
  from .utils import clean_mongo_doc, clean_mongo_docs
83
83
 
84
84
  __version__ = (
85
- "0.6.0" # Secure-by-default WebSocket authentication with encrypted session keys
86
- # - NEW: WebSocket session key generation and management
87
- # - NEW: Envelope encryption for WebSocket session keys
88
- # - NEW: Secure-by-default CSRF protection (csrf_required: true)
89
- # - NEW: WebSocketSessionManager with private collection storage
90
- # - NEW: Session key endpoint (/auth/websocket-session)
91
- # - NEW: Session key integration in login flow
92
- # - ENHANCED: WebSocket authentication with session key support
93
- # - ENHANCED: CSRF middleware session key validation
94
- # - ENHANCED: Multi-app WebSocket routing with session keys
95
- # - BACKWARD COMPATIBLE: Cookie-based authentication fallback
96
- # - UPDATED: All documentation for secure-by-default approach
97
- # - COMPREHENSIVE: Unit and integration tests for session keys
85
+ "0.7.1" # Memory service initialization fix for multi-app setups
86
+ # - FIXED: Memory service initialization in create_multi_app context
87
+ # - FIXED: get_memory_service() now returns service when memory_config.enabled: true
88
+ # - ENHANCED: Explicit memory service initialization in create_multi_app lifespan
89
+ # - ENHANCED: Better error handling and logging for memory service initialization
90
+ # - ADDED: Comprehensive integration tests for memory service in multi-app context
91
+ # - ADDED: Unit tests for memory service initialization edge cases
98
92
  )
99
93
 
100
94
  __all__ = [
mdb_engine/cli/main.py CHANGED
@@ -15,7 +15,7 @@ from .commands.validate import validate
15
15
 
16
16
 
17
17
  @click.group()
18
- @click.version_option(version="0.1.6", prog_name="mdb")
18
+ @click.version_option(version="0.7.1", prog_name="mdb")
19
19
  def cli() -> None:
20
20
  """
21
21
  MDB_ENGINE CLI - Manifest management tool.
mdb_engine/core/engine.py CHANGED
@@ -36,6 +36,11 @@ from typing import TYPE_CHECKING, Any, Optional
36
36
  from motor.motor_asyncio import AsyncIOMotorClient
37
37
  from pymongo.errors import PyMongoError
38
38
 
39
+ try:
40
+ from openai import OpenAIError
41
+ except ImportError:
42
+ OpenAIError = RuntimeError
43
+
39
44
  if TYPE_CHECKING:
40
45
  from fastapi import FastAPI
41
46
 
@@ -2672,7 +2677,7 @@ class MongoDBEngine:
2672
2677
  )
2673
2678
 
2674
2679
  @asynccontextmanager
2675
- async def lifespan(app: FastAPI):
2680
+ async def lifespan(app: FastAPI): # noqa: C901
2676
2681
  """Lifespan context manager for parent app."""
2677
2682
  nonlocal mounted_apps, shared_user_pool_initialized
2678
2683
 
@@ -2911,11 +2916,60 @@ class MongoDBEngine:
2911
2916
  child_app.add_middleware(middleware_class)
2912
2917
  logger.debug(f"Added AppContextMiddleware to child app '{slug}'")
2913
2918
 
2914
- # CRITICAL FIX: Register WebSocket routes on parent app BEFORE mounting
2915
- # This ensures WebSocket routes are checked before mounted app routes
2916
- # Mounted apps create catch-all routes that intercept /app-slug/* paths
2917
2919
  await _register_websocket_routes(app, app_manifest_data, slug, path_prefix)
2918
2920
 
2921
+ memory_config = app_manifest_data.get("memory_config")
2922
+ if memory_config and memory_config.get("enabled", False):
2923
+ if engine._service_initializer: # noqa: SLF001
2924
+ try:
2925
+ await engine._service_initializer.initialize_memory_service( # noqa: SLF001
2926
+ slug, memory_config
2927
+ )
2928
+ logger.info(
2929
+ f"Memory service initialized for mounted app '{slug}' "
2930
+ f"in multi-app context"
2931
+ )
2932
+ except OpenAIError as e:
2933
+ logger.warning(
2934
+ f"Memory service initialization skipped for mounted app "
2935
+ f"'{slug}': OpenAI API error. {e}",
2936
+ extra={"app_slug": slug, "error": str(e)},
2937
+ )
2938
+ except (
2939
+ ImportError,
2940
+ AttributeError,
2941
+ TypeError,
2942
+ ValueError,
2943
+ RuntimeError,
2944
+ ConnectionError,
2945
+ OSError,
2946
+ ) as e:
2947
+ error_msg = str(e).lower()
2948
+ error_type = type(e).__name__
2949
+ is_api_key_error = (
2950
+ "api_key" in error_msg
2951
+ or "api key" in error_msg
2952
+ or "openai" in error_type.lower()
2953
+ )
2954
+ if is_api_key_error:
2955
+ logger.warning(
2956
+ f"Memory service initialization skipped for mounted app "
2957
+ f"'{slug}': Missing API key or configuration. {e}",
2958
+ extra={"app_slug": slug, "error": str(e)},
2959
+ )
2960
+ else:
2961
+ logger.error(
2962
+ f"Failed to initialize memory service for mounted app "
2963
+ f"'{slug}': {e}",
2964
+ exc_info=True,
2965
+ extra={"app_slug": slug, "error": str(e)},
2966
+ )
2967
+ else:
2968
+ logger.warning(
2969
+ f"Memory service requested for '{slug}' but "
2970
+ f"service_initializer is not available"
2971
+ )
2972
+
2919
2973
  # Mount child app at path prefix (AFTER WebSocket routes are registered)
2920
2974
  app.mount(path_prefix, child_app)
2921
2975
 
@@ -26,6 +26,11 @@ from ..observability import get_logger as get_contextual_logger
26
26
  logger = logging.getLogger(__name__)
27
27
  contextual_logger = get_contextual_logger(__name__)
28
28
 
29
+ try:
30
+ from openai import OpenAIError
31
+ except ImportError:
32
+ OpenAIError = RuntimeError
33
+
29
34
 
30
35
  class ServiceInitializer:
31
36
  """
@@ -54,7 +59,9 @@ class ServiceInitializer:
54
59
  self._memory_services: dict[str, Any] = {}
55
60
  self._websocket_configs: dict[str, dict[str, Any]] = {}
56
61
 
57
- async def initialize_memory_service(self, slug: str, memory_config: dict[str, Any]) -> None:
62
+ async def initialize_memory_service(
63
+ self, slug: str, memory_config: dict[str, Any] | None
64
+ ) -> None:
58
65
  """
59
66
  Initialize Mem0 memory service for an app.
60
67
 
@@ -63,8 +70,17 @@ class ServiceInitializer:
63
70
 
64
71
  Args:
65
72
  slug: App slug
66
- memory_config: Memory configuration from manifest (already validated)
73
+ memory_config: Memory configuration from manifest (already validated).
74
+ Can be None or empty dict to skip initialization.
67
75
  """
76
+ # Handle None or empty config
77
+ if not memory_config:
78
+ return
79
+
80
+ # Check if memory is enabled (must be checked before import)
81
+ if not memory_config.get("enabled", False):
82
+ return
83
+
68
84
  # Try to import Memory service (optional dependency)
69
85
  try:
70
86
  from ..memory import Mem0MemoryService, Mem0MemoryServiceError
@@ -145,12 +161,41 @@ class ServiceInitializer:
145
161
  extra={"app_slug": slug, "error": str(e)},
146
162
  exc_info=True,
147
163
  )
148
- except (ImportError, AttributeError, TypeError, ValueError) as e:
149
- contextual_logger.error(
150
- f"Error initializing memory service for app '{slug}': {e}",
164
+ except OpenAIError as e:
165
+ contextual_logger.warning(
166
+ f"Memory service initialization skipped for app '{slug}': "
167
+ f"OpenAI API error. {e}",
151
168
  extra={"app_slug": slug, "error": str(e)},
152
- exc_info=True,
153
169
  )
170
+ except (
171
+ ImportError,
172
+ AttributeError,
173
+ TypeError,
174
+ ValueError,
175
+ RuntimeError,
176
+ ConnectionError,
177
+ OSError,
178
+ ) as e:
179
+ error_msg = str(e).lower()
180
+ error_type = type(e).__name__
181
+ is_api_key_error = (
182
+ "api_key" in error_msg
183
+ or "api key" in error_msg
184
+ or "openai" in error_type.lower()
185
+ or "openai" in error_msg
186
+ )
187
+ if is_api_key_error:
188
+ contextual_logger.warning(
189
+ f"Memory service initialization skipped for app '{slug}': "
190
+ f"Missing API key or configuration. {e}",
191
+ extra={"app_slug": slug, "error": str(e)},
192
+ )
193
+ else:
194
+ contextual_logger.error(
195
+ f"Error initializing memory service for app '{slug}': {e}",
196
+ extra={"app_slug": slug, "error": str(e)},
197
+ exc_info=True,
198
+ )
154
199
 
155
200
  async def register_websockets(self, slug: str, websockets_config: dict[str, Any]) -> None:
156
201
  """
@@ -330,7 +375,18 @@ class ServiceInitializer:
330
375
  extra={"app_slug": slug},
331
376
  )
332
377
  return None
333
- return service
378
+ return service
379
+
380
+ # Service not found - check if it should be initialized but wasn't
381
+ # This can happen in multi-app context if initialization was missed
382
+ # Note: We can't do async initialization here, so we just log a warning
383
+ # The explicit initialization in create_multi_app should handle this
384
+ contextual_logger.debug(
385
+ f"Memory service not found for '{slug}' - "
386
+ f"it may not be initialized yet or memory is disabled",
387
+ extra={"app_slug": slug},
388
+ )
389
+ return None
334
390
  except (KeyError, AttributeError, TypeError) as e:
335
391
  contextual_logger.error(
336
392
  f"Error retrieving memory service for '{slug}': {e}",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdb-engine
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: MongoDB Engine
5
5
  Home-page: https://github.com/ranfysvalle02/mdb-engine
6
6
  Author: Fabian Valle
@@ -1,5 +1,5 @@
1
1
  mdb_engine/README.md,sha256=T3EFGcPopY9LslYW3lxgG3hohWkAOmBNbYG0FDMUJiY,3502
2
- mdb_engine/__init__.py,sha256=vishQ3BF6oGQOmAsrMG1UJ-5C-3FNM49JSHC35MhH0k,3937
2
+ mdb_engine/__init__.py,sha256=d2oenqa95hRBwXIVPmKBE8lo61ojOkxfcuuIzgSxLXc,3655
3
3
  mdb_engine/config.py,sha256=DTAyxfKB8ogyI0v5QR9Y-SJOgXQr_eDBCKxNBSqEyLc,7269
4
4
  mdb_engine/constants.py,sha256=eaotvW57TVOg7rRbLziGrVNoP7adgw_G9iVByHezc_A,7837
5
5
  mdb_engine/dependencies.py,sha256=MJuYQhZ9ZGzXlip1ha5zba9Rvn04HDPWahJFJH81Q2s,14107
@@ -35,7 +35,7 @@ mdb_engine/auth/utils.py,sha256=YkexCo0xV37mpOJUI32cntRHVOUUS7r19TIMPWHcgpA,2734
35
35
  mdb_engine/auth/websocket_sessions.py,sha256=7eFNagY2K3Rp1x7d_cO5JcpT-DrYkc__cmVhl6pAC2M,15081
36
36
  mdb_engine/auth/websocket_tickets.py,sha256=VoIArcnQBtYqXRMs-5m7NSvCJB1dEeHrLl7j7yG-H-A,9887
37
37
  mdb_engine/cli/__init__.py,sha256=PANRi4THmL34d1mawlqxIrnuItXMdqoMTq5Z1zHd7rM,301
38
- mdb_engine/cli/main.py,sha256=Y5ELFhvsr8zxFWv4WScOGNHiLUTdSXAJeUFLpRXCelg,811
38
+ mdb_engine/cli/main.py,sha256=4bWBNgksfRgimolBfivITNvYRMaLTvngeVDcdm7ou6M,811
39
39
  mdb_engine/cli/utils.py,sha256=bNRGJgdzxUjXAOVe1aoxWJ5M_IqtAE-eW4pfAkwiDDM,2760
40
40
  mdb_engine/cli/commands/__init__.py,sha256=ZSzMhKdV9ILD5EbOSxDV9nURHo1e4bQ0c8AWpqsTEqM,115
41
41
  mdb_engine/cli/commands/generate.py,sha256=VEcn7qNQkIPQlLEK3oXUBgYMwD-G0FyomXQcWTtKsbs,17304
@@ -48,12 +48,12 @@ mdb_engine/core/app_registration.py,sha256=w7wjrlNQsEekuDQkG6HM4Z5t00E65baEzncnh
48
48
  mdb_engine/core/app_secrets.py,sha256=bo-syg9UUATibNyXEZs-0TTYWG-JaY-2S0yNSGA12n0,10524
49
49
  mdb_engine/core/connection.py,sha256=XnwuPG34pJ7kJGJ84T0mhj1UZ6_CLz_9qZf6NRYGIS8,8346
50
50
  mdb_engine/core/encryption.py,sha256=RZ5LPF5g28E3ZBn6v1IMw_oas7u9YGFtBcEj8lTi9LM,7515
51
- mdb_engine/core/engine.py,sha256=RBXJUYRbXrt4rhQLSxcRF-FYzf-ZxN9j358sdlw4_pc,182475
51
+ mdb_engine/core/engine.py,sha256=wSJ99FP3NRUejGCXliwi9fW_pVZPpLjdUMG8FsU5Kms,185252
52
52
  mdb_engine/core/index_management.py,sha256=9-r7MIy3JnjQ35sGqsbj8K_I07vAUWtAVgSWC99lJcE,5555
53
53
  mdb_engine/core/manifest.py,sha256=D3OGRjm1It8dmS3IMoxHckHUerhs5PtcQgPz8o5ZL9w,140785
54
54
  mdb_engine/core/ray_integration.py,sha256=csAgICl2g7Plqy4N49MJU1Ca-lr8KZznAouXMMRwhG8,13706
55
55
  mdb_engine/core/seeding.py,sha256=c5IhdwlqUf_4Q5FFTAhPLaHPaUr_Txo3z_DUwZmWsFs,6421
56
- mdb_engine/core/service_initialization.py,sha256=rtb6BaPvFqomwT_s7bdbbvqi5m74llT0LkJFEhVG9Gg,12996
56
+ mdb_engine/core/service_initialization.py,sha256=N4varRswExBYahAgPfcPtNhqszOjm0JQ0u7r7mfFyqM,15018
57
57
  mdb_engine/core/types.py,sha256=u0LDGE4A3txGDlc9PNoQX8jwVYFjJSw4K5LDnpatsNc,11254
58
58
  mdb_engine/database/README.md,sha256=-31mVxBeVQaYsF3AD1-gQbD2NCYVcPjdFoA6sZ6b02Y,19354
59
59
  mdb_engine/database/__init__.py,sha256=rrc3eZFli3K2zrvVdDbMBi8YkmoHYzP6JNT0AUBE5VU,981
@@ -91,9 +91,9 @@ mdb_engine/routing/__init__.py,sha256=reupjHi_RTc2ZBA4AH5XzobAmqy4EQIsfSUcTkFknU
91
91
  mdb_engine/routing/websockets.py,sha256=jgdLsrSOKyBiY4yzE7XYXV1MOChLw2CIWpT6RDL23hk,51649
92
92
  mdb_engine/utils/__init__.py,sha256=lDxQSGqkV4fVw5TWIk6FA6_eey_ZnEtMY0fir3cpAe8,236
93
93
  mdb_engine/utils/mongo.py,sha256=Oqtv4tQdpiiZzrilGLEYQPo8Vmh8WsTQypxQs8Of53s,3369
94
- mdb_engine-0.7.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
95
- mdb_engine-0.7.0.dist-info/METADATA,sha256=dSWF8HOigw-49yf_VBLhr0hA--LKqroswl9uu3MmQik,19695
96
- mdb_engine-0.7.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
97
- mdb_engine-0.7.0.dist-info/entry_points.txt,sha256=INCbYdFbBzJalwPwxliEzLmPfR57IvQ7RAXG_pn8cL8,48
98
- mdb_engine-0.7.0.dist-info/top_level.txt,sha256=PH0UEBwTtgkm2vWvC9He_EOMn7hVn_Wg_Jyc0SmeO8k,11
99
- mdb_engine-0.7.0.dist-info/RECORD,,
94
+ mdb_engine-0.7.1.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
95
+ mdb_engine-0.7.1.dist-info/METADATA,sha256=GXZ-ojykqFCH5RLybnClAHWcNU9da-wXweOyZmH01tM,19695
96
+ mdb_engine-0.7.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
97
+ mdb_engine-0.7.1.dist-info/entry_points.txt,sha256=INCbYdFbBzJalwPwxliEzLmPfR57IvQ7RAXG_pn8cL8,48
98
+ mdb_engine-0.7.1.dist-info/top_level.txt,sha256=PH0UEBwTtgkm2vWvC9He_EOMn7hVn_Wg_Jyc0SmeO8k,11
99
+ mdb_engine-0.7.1.dist-info/RECORD,,