Skip to content

Datalab SimpleRemoteProxy - get_cdl_xmlrpc_port() reads the wrong INI file (DataLab ≥ 1.3) #54

Description

@ThomasMalletCodra

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.pyTYPED_CONFIG_SUFFIX = "_typed" and get_typed_config_filename()<basedir>/.DataLab_v1/DataLab_v1_typed.ini
  • datalab/config/persistence.pyDataLabUserConfig.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:

  1. typed file only → returns its port;
  2. both files present with different ports → returns the typed one;
  3. legacy file only → returns its port (backward compatibility with DataLab ≤ 1.2);
  4. typed file present but without rpc_server_port → falls back to the legacy file;
  5. nothing present → raises ConnectionRefusedError.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions