Skip to content

Commit 933c9fb

Browse files
feat: Add override context manager to ConnectionConfig
Added `conn.config.override()` method to temporarily change connection- scoped settings. This provides the same functionality as `dj.config.override()` but works in thread-safe mode where global config access is blocked. Example: with conn.config.override(safemode=False, display_limit=50): # settings changed temporarily pass # settings restored Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0bd4301 commit 933c9fb

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

src/datajoint/connection.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import warnings
1313
from contextlib import contextmanager
1414
from pathlib import Path
15-
from typing import Any, Callable
15+
from typing import Any, Callable, Iterator
1616

1717
from . import errors
1818
from .adapters import get_adapter
@@ -175,6 +175,52 @@ def get_store_spec(self, store_name: str) -> dict:
175175
raise errors.DataJointError(f"Store '{store_name}' is not configured.")
176176
return stores[store_name]
177177

178+
@contextmanager
179+
def override(self, **kwargs: Any) -> Iterator["ConnectionConfig"]:
180+
"""
181+
Temporarily override configuration values for this connection.
182+
183+
Parameters
184+
----------
185+
**kwargs : Any
186+
Settings to override.
187+
188+
Yields
189+
------
190+
ConnectionConfig
191+
The config instance with overridden values.
192+
193+
Examples
194+
--------
195+
>>> with conn.config.override(safemode=False, display_limit=50):
196+
... # conn.config.safemode is False here
197+
... pass
198+
>>> # conn.config.safemode is restored
199+
"""
200+
from copy import deepcopy
201+
202+
# Save original values
203+
backup = {}
204+
for key, value in kwargs.items():
205+
if key in self._values:
206+
backup[key] = deepcopy(self._values[key])
207+
elif key in self._DEFAULTS:
208+
backup[key] = None # Marker for "was not set"
209+
210+
try:
211+
# Apply overrides
212+
for key, value in kwargs.items():
213+
self._values[key] = value
214+
yield self
215+
finally:
216+
# Restore original values
217+
for key, original in backup.items():
218+
if original is None:
219+
# Was not set before, remove it
220+
self._values.pop(key, None)
221+
else:
222+
self._values[key] = original
223+
178224

179225
def translate_query_error(client_error: Exception, query: str, adapter) -> Exception:
180226
"""

tests/unit/test_thread_safe.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,42 @@ def test_repr(self):
355355
assert "ConnectionConfig" in r
356356
assert "safemode=False" in r
357357

358+
def test_override_context_manager(self):
359+
"""override temporarily changes values and restores them."""
360+
cfg = ConnectionConfig(safemode=True, display_limit=10)
361+
362+
with cfg.override(safemode=False, display_limit=50):
363+
assert cfg.safemode is False
364+
assert cfg.display_limit == 50
365+
366+
assert cfg.safemode is True
367+
assert cfg.display_limit == 10
368+
369+
def test_override_restores_on_exception(self):
370+
"""override restores values even when exception is raised."""
371+
cfg = ConnectionConfig(safemode=True)
372+
373+
try:
374+
with cfg.override(safemode=False):
375+
assert cfg.safemode is False
376+
raise RuntimeError("test error")
377+
except RuntimeError:
378+
pass
379+
380+
assert cfg.safemode is True
381+
382+
def test_override_with_defaults(self):
383+
"""override works when value was not explicitly set."""
384+
cfg = ConnectionConfig() # Uses defaults
385+
assert cfg.safemode is True # default
386+
387+
with cfg.override(safemode=False):
388+
assert cfg.safemode is False
389+
390+
# Should restore to default (not be in _values)
391+
assert cfg.safemode is True
392+
assert "safemode" not in cfg._values
393+
358394

359395
class TestConnectionConfigAttribute:
360396
"""Tests for Connection.config attribute."""

0 commit comments

Comments
 (0)