Skip to content

Commit 042dbf2

Browse files
fix: Make conn() with credentials update singleton connection
- conn(host, user, password) now updates the singleton connection instead of creating a separate connection - Remove irrelevant safemode=False from spec examples - thread_safe is set via DJ_THREAD_SAFE env var or config file Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b251e86 commit 042dbf2

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

docs/design/thread-safe-mode.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import datajoint as dj
1818
# Configure credentials (no connection yet)
1919
dj.config.database.user = "user"
2020
dj.config.database.password = "password"
21-
dj.config.safemode = False
2221

2322
# First call to conn() or Schema() creates the singleton connection
2423
dj.conn() # Creates connection using dj.config credentials
@@ -29,6 +28,11 @@ class Mouse(dj.Manual):
2928
definition = "..."
3029
```
3130

31+
Alternatively, pass credentials directly to `conn()`:
32+
```python
33+
dj.conn(host="localhost", user="user", password="password")
34+
```
35+
3236
Internally:
3337
- `dj.config` → delegates to `_global_config` (with thread-safety check)
3438
- `dj.conn()` → returns `_singleton_connection` (created lazily)
@@ -45,7 +49,6 @@ inst = dj.Instance(
4549
user="user",
4650
password="password",
4751
)
48-
inst.config.safemode = False
4952
schema = inst.Schema("my_schema")
5053

5154
@schema
@@ -107,7 +110,6 @@ dj.conn() # ThreadSafetyError
107110
dj.Schema("name") # ThreadSafetyError
108111

109112
inst = dj.Instance(host="h", user="u", password="p") # OK
110-
inst.config.safemode = False # OK
111113
inst.Schema("name") # OK
112114
```
113115

@@ -147,10 +149,6 @@ inst = dj.Instance(
147149
password="password",
148150
)
149151

150-
# Configure
151-
inst.config.safemode = False
152-
inst.config.stores = {"raw": {"protocol": "file", "location": "/data"}}
153-
154152
# Create schema
155153
schema = inst.Schema("my_schema")
156154

@@ -162,7 +160,7 @@ class Mouse(dj.Manual):
162160

163161
# Use tables
164162
Mouse().insert1({"mouse_id": 1})
165-
Mouse().delete() # Uses inst.config.safemode
163+
Mouse().fetch()
166164
```
167165

168166
## Implementation

src/datajoint/__init__.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,18 @@ def conn(
103103
"""
104104
Return a persistent connection object.
105105
106-
When called without arguments, returns the singleton connection.
107-
When connection parameters are provided, creates a new Connection.
106+
When called without arguments, returns the singleton connection using
107+
credentials from dj.config. When connection parameters are provided,
108+
updates the singleton connection with the new credentials.
108109
109110
Parameters
110111
----------
111112
host : str, optional
112-
Database hostname.
113+
Database hostname. If provided, updates singleton.
113114
user : str, optional
114-
Database username.
115+
Database username. If provided, updates singleton.
115116
password : str, optional
116-
Database password.
117+
Database password. If provided, updates singleton.
117118
reset : bool, optional
118119
If True, reset existing connection. Default False.
119120
use_tls : bool or dict, optional
@@ -127,15 +128,38 @@ def conn(
127128
Raises
128129
------
129130
ThreadSafetyError
130-
If thread_safe mode is enabled and using singleton.
131+
If thread_safe mode is enabled.
131132
"""
132-
# If any connection params provided, use legacy behavior
133-
if host is not None or user is not None or password is not None or reset:
134-
from .connection import conn as _legacy_conn
133+
from .instance import _singleton_connection, _check_thread_safe, _global_config
134+
import datajoint.instance as instance_module
135135

136-
return _legacy_conn(host, user, password, reset=reset, use_tls=use_tls)
136+
_check_thread_safe()
137+
138+
# If credentials provided or reset requested, (re)create the singleton
139+
if host is not None or user is not None or password is not None or reset:
140+
# Use provided values or fall back to config
141+
host = host if host is not None else _global_config.database.host
142+
user = user if user is not None else _global_config.database.user
143+
password = password if password is not None else _global_config.database.password
144+
if password is not None and hasattr(password, 'get_secret_value'):
145+
password = password.get_secret_value()
146+
port = _global_config.database.port
147+
use_tls = use_tls if use_tls is not None else _global_config.database.use_tls
148+
149+
if user is None:
150+
from .errors import DataJointError
151+
raise DataJointError(
152+
"Database user not configured. Set dj.config['database.user'] or pass user= argument."
153+
)
154+
if password is None:
155+
from .errors import DataJointError
156+
raise DataJointError(
157+
"Database password not configured. Set dj.config['database.password'] or pass password= argument."
158+
)
159+
160+
instance_module._singleton_connection = Connection(host, user, password, port, use_tls)
161+
instance_module._singleton_connection._config = _global_config
137162

138-
# Otherwise use singleton connection
139163
return _get_singleton_connection()
140164

141165

0 commit comments

Comments
 (0)