Symptom
SimpleRemoteProxy() in autoconnect mode (no port= argument, no DATALAB_XMLRPCPORT environment variable) fails to reach a running DataLab 1.3:
- on a machine that has been running DataLab since ≤ 1.2: the client connects to a stale port left over in the legacy INI file, then raises
ConnectionRefusedError: Unable to connect to DataLab after 5.0s;
- on a fresh DataLab 1.3 installation: the legacy INI file never exists, so the client raises
ConnectionRefusedError: DataLab has not yet been executed or no valid configuration found.
This is the documented headline use case (control DataLab from Spyder or a Jupyter notebook), so the impact is user-visible even though the blast radius is narrow.
Root cause
sigima/client/remote.py::get_cdl_xmlrpc_port() probes these candidates, in order:
| folder |
file |
.DataLab_v3 |
DataLab_v3.ini |
.DataLab_v2 |
DataLab_v2.ini |
.DataLab_v1 |
DataLab_v1.ini |
.DataLab |
DataLab.ini (v0.x legacy) |
But since DataLab 1.3, the configuration is written to a typed INI file:
datalab/config/appinfo.py — TYPED_CONFIG_SUFFIX = "_typed" and get_typed_config_filename() → <basedir>/.DataLab_v1/DataLab_v1_typed.ini
datalab/config/persistence.py — DataLabUserConfig.filename() returns <name>_typed.ini
- the non-typed file is now read-only:
_LegacyConfigReader.save() is a no-op (it exists only for the 1.2 → 1.3 migration)
- the port is written by
datalab/gui/main.py through save_runtime_option(Conf, "rpc_server_port"), i.e. into the typed file
Observed on a real machine (2026-08-19):
| file |
last write |
[main] rpc_server_port |
~/.DataLab_v1/DataLab_v1.ini |
2026-08-17 |
60887 ← stale, still read by Sigima |
~/.DataLab_v1/DataLab_v1_typed.ini |
2026-08-19 |
60766 ← current, ignored |
The section ([main]) and the key (rpc_server_port) are unchanged; only the file name differs.
Proposed fix
Try the typed file before the legacy one, for each version folder. Keep the legacy fallbacks so that a Sigima client still works against DataLab 1.2 and 0.x.
# sigima/client/remote.py
def get_cdl_xmlrpc_port():
"""Return DataLab current XML-RPC port. ..."""
if sys.platform == "win32" and "HOME" in os.environ:
os.environ.pop("HOME") # Avoid getting old WinPython settings dir
config_basedir = get_config_basedir()
# Configuration folders to try, newest major version first. For each folder,
# the typed file (DataLab >= 1.3) takes precedence over the legacy one, which
# is no longer written and may hold a stale port.
config_folders = [".DataLab_v3", ".DataLab_v2", ".DataLab_v1", ".DataLab"]
for folder_name in config_folders:
basename = folder_name.lstrip(".")
for ini_name in (f"{basename}_typed.ini", f"{basename}.ini"):
fname = osp.join(config_basedir, folder_name, ini_name)
if not osp.exists(fname):
continue
ini = cp.ConfigParser()
try:
ini.read(fname)
return ini.get("main", "rpc_server_port")
except (cp.NoSectionError, cp.NoOptionError):
continue
raise ConnectionRefusedError(
"DataLab has not yet been executed or no valid configuration found"
)
Note the behaviour change beyond the file name: a candidate that exists but has no rpc_server_port key must fall through to the next candidate instead of aborting the folder — the current code already does continue, keep it.
Suggested test
In sigima/tests/common/client_unit_test.py (or a new client_port_discovery_unit_test.py), monkeypatch guidata.userconfig.get_config_basedir to a tmp_path and assert:
- typed file only → returns its port;
- both files present with different ports → returns the typed one;
- legacy file only → returns its port (backward compatibility with DataLab ≤ 1.2);
- typed file present but without
rpc_server_port → falls back to the legacy file;
- nothing present → raises
ConnectionRefusedError.
Symptom
SimpleRemoteProxy()in autoconnect mode (noport=argument, noDATALAB_XMLRPCPORTenvironment variable) fails to reach a running DataLab 1.3:ConnectionRefusedError: Unable to connect to DataLab after 5.0s;ConnectionRefusedError: DataLab has not yet been executed or no valid configuration found.This is the documented headline use case (control DataLab from Spyder or a Jupyter notebook), so the impact is user-visible even though the blast radius is narrow.
Root cause
sigima/client/remote.py::get_cdl_xmlrpc_port()probes these candidates, in order:.DataLab_v3DataLab_v3.ini.DataLab_v2DataLab_v2.ini.DataLab_v1DataLab_v1.ini.DataLabDataLab.ini(v0.x legacy)But since DataLab 1.3, the configuration is written to a typed INI file:
datalab/config/appinfo.py—TYPED_CONFIG_SUFFIX = "_typed"andget_typed_config_filename()→<basedir>/.DataLab_v1/DataLab_v1_typed.inidatalab/config/persistence.py—DataLabUserConfig.filename()returns<name>_typed.ini_LegacyConfigReader.save()is a no-op (it exists only for the 1.2 → 1.3 migration)datalab/gui/main.pythroughsave_runtime_option(Conf, "rpc_server_port"), i.e. into the typed fileObserved on a real machine (2026-08-19):
[main] rpc_server_port~/.DataLab_v1/DataLab_v1.ini60887← stale, still read by Sigima~/.DataLab_v1/DataLab_v1_typed.ini60766← current, ignoredThe section (
[main]) and the key (rpc_server_port) are unchanged; only the file name differs.Proposed fix
Try the typed file before the legacy one, for each version folder. Keep the legacy fallbacks so that a Sigima client still works against DataLab 1.2 and 0.x.
Note the behaviour change beyond the file name: a candidate that exists but has no
rpc_server_portkey must fall through to the next candidate instead of aborting the folder — the current code already doescontinue, keep it.Suggested test
In
sigima/tests/common/client_unit_test.py(or a newclient_port_discovery_unit_test.py), monkeypatchguidata.userconfig.get_config_basedirto atmp_pathand assert:rpc_server_port→ falls back to the legacy file;ConnectionRefusedError.