From 5f0a2b3a198330247f9a73de9ab13381699b5505 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Fri, 4 Sep 2026 16:47:38 -0700 Subject: [PATCH 01/10] Updated yaml_files.rst with new 'load_experiment_presets' YAML configuration key. --- docs/source/yaml_files.rst | 45 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/source/yaml_files.rst b/docs/source/yaml_files.rst index 3896eaf5..4dacd485 100644 --- a/docs/source/yaml_files.rst +++ b/docs/source/yaml_files.rst @@ -4,7 +4,8 @@ Yaml Files ``hutch-python`` uses a ``conf.yml`` file for basic configuration. This is a standard yaml file with the following valid keys: ``hutch``, ``db``, ``load``, ``load_level``, ``experiment``, ``obj_config``, -``daq_type``, ``daq_host``, and ``daq_platform``, ``exclude_devices``. +``daq_type``, ``daq_host``, ``daq_platform``, ``exclude_devices``, +``additional_devices``, and ``load_experiment_presets``. hutch @@ -179,7 +180,7 @@ at load time. The list uses the following format: additional_devices ------------- +------------------ The ``additional_devices`` key is optional. This key allows hutch-python to load additional devices that are on a different beamline or in a different hutch/area. The first entry below ``additional_devices`` is a search name, @@ -212,6 +213,46 @@ In the example below hutch-python will load all devices from "tmo_sqr1_search", name: crix_* +load_experiment_presets +----------------------- +The ``load_experiment_presets`` key is optional and expects a Boolean value. +It controls whether hutch-python makes position presets from the active +experiment available to motors and other positioners. + +Position presets are saved locations that can be called by commands such as +``motor.mv_sample()``. Hutch-python supports two types of position presets. + +- Beamline presets are permanent positions shared across experiments. +- Experiment presets are temporary positions associated with the active + experiment. + +.. code-block:: YAML + + load_experiment_presets: false + +When set to ``false``, hutch-python still loads beamline presets. It does not +configure or read the active experiment's preset directory. This can improve +startup performance when the experiment directory contains many preset files. + +When set to ``true``, hutch-python makes both beamline and active experiment +presets available. + +.. code-block:: YAML + + load_experiment_presets: true + +The default is ``true``. Existing configurations that omit this key retain +their current behavior. + +Use the unquoted YAML values ``true`` and ``false``. Quoted values such as +``"false"`` are strings rather than Boolean values and are invalid for this +setting. + +This setting affects only position presets. It does not disable loading the +experiment Python file, questionnaire objects, or other experiment +configuration. + + Full File Example ----------------- From ce716f6db71053752e3d970406efe02ed00188d0 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Fri, 4 Sep 2026 17:39:42 -0700 Subject: [PATCH 02/10] Add option to disable experiment preset loading. --- hutch_python/constants.py | 3 ++- hutch_python/load_conf.py | 33 +++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/hutch_python/constants.py b/hutch_python/constants.py index 053f5d96..e818526a 100644 --- a/hutch_python/constants.py +++ b/hutch_python/constants.py @@ -40,7 +40,8 @@ 'obj_config', 'session_timer', 'exclude_devices', - 'additional_devices' + 'additional_devices', + 'load_experiment_presets' ) NO_LOG_EXCEPTIONS = (KeyboardInterrupt, SystemExit) LOG_DOMAINS = {".pcdsn", ".slac.stanford.edu"} diff --git a/hutch_python/load_conf.py b/hutch_python/load_conf.py index 77de19e5..1095b135 100644 --- a/hutch_python/load_conf.py +++ b/hutch_python/load_conf.py @@ -582,26 +582,43 @@ def load_conf(conf, hutch_dir=None, args=None): all_objects='Namespace of all loaded objects.', ) - # Install Presets + # Install presets if hutch_dir is not None: with safe_load('position presets'): presets_dir = Path(hutch_dir) / 'presets' beamline_presets = presets_dir / 'beamline' + + load_experiment_presets = conf.get('load_experiment_presets', True) + if not isinstance(load_experiment_presets, bool): + logger.error( + 'Invalid load_experiment_presets value %r; expected a ' + 'boolean. ' + 'Experiment presets will be loaded.', + load_experiment_presets, + ) + load_experiment_presets = True + preset_paths = [presets_dir, beamline_presets] - if experiment is not None: + if experiment is not None and load_experiment_presets: experiment_presets = presets_dir / raw_expname preset_paths.append(experiment_presets) + for path in preset_paths: if not path.exists(): path.mkdir() path.chmod(0o777) - if experiment is None: - setup_preset_paths(hutch=beamline_presets, - defer_loading=True) + + if experiment is not None and load_experiment_presets: + setup_preset_paths( + hutch=beamline_presets, + exp=experiment_presets, + defer_loading=True, + ) else: - setup_preset_paths(hutch=beamline_presets, - exp=experiment_presets, - defer_loading=True) + setup_preset_paths( + hutch=beamline_presets, + defer_loading=True, + ) # configure objects if obj_config is not None: From 2b30b0dc440441ab6e74e37839a6ddb0205649c1 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Fri, 4 Sep 2026 18:01:39 -0700 Subject: [PATCH 03/10] Added more comments to the changes. --- hutch_python/_version.py | 24 ++++++++++ hutch_python/load_conf.py | 17 +++++++- hutch_python/tests/test_load_conf.py | 65 +++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 hutch_python/_version.py diff --git a/hutch_python/_version.py b/hutch_python/_version.py new file mode 100644 index 00000000..aed61ea7 --- /dev/null +++ b/hutch_python/_version.py @@ -0,0 +1,24 @@ +# file generated by vcs-versioning +# don't change, don't track in version control +from __future__ import annotations + +__all__ = [ + "__version__", + "__version_tuple__", + "version", + "version_tuple", + "__commit_id__", + "commit_id", +] + +version: str +__version__: str +__version_tuple__: tuple[int | str, ...] +version_tuple: tuple[int | str, ...] +commit_id: str | None +__commit_id__: str | None + +__version__ = version = '0.1.dev1442+ge6a635929.d20260904' +__version_tuple__ = version_tuple = (0, 1, 'dev1442', 'ge6a635929.d20260904') + +__commit_id__ = commit_id = 'ge6a635929' diff --git a/hutch_python/load_conf.py b/hutch_python/load_conf.py index 1095b135..662a6e3d 100644 --- a/hutch_python/load_conf.py +++ b/hutch_python/load_conf.py @@ -582,12 +582,18 @@ def load_conf(conf, hutch_dir=None, args=None): all_objects='Namespace of all loaded objects.', ) - # Install presets + # Configure saved motor positions. Presets are stored as YAML files under + # the hutch launch directory. if hutch_dir is not None: + # Log preset setup failures without stopping the entire session. with safe_load('position presets'): presets_dir = Path(hutch_dir) / 'presets' + + # Beamline presets are permanent and shared by all experiments. beamline_presets = presets_dir / 'beamline' + # Preserve existing behavior unless the YAML configuration file + # explicitly disables experiment presets. load_experiment_presets = conf.get('load_experiment_presets', True) if not isinstance(load_experiment_presets, bool): logger.error( @@ -598,16 +604,24 @@ def load_conf(conf, hutch_dir=None, args=None): ) load_experiment_presets = True + # Preset root and permanent beamline directory are required. preset_paths = [presets_dir, beamline_presets] + + # Experiment presets are motor positions associated with the active + # experiment. Configure them only when an experiment is available + # and experiment preset loading is enabled. if experiment is not None and load_experiment_presets: experiment_presets = presets_dir / raw_expname preset_paths.append(experiment_presets) + # Create any missing preset directories. for path in preset_paths: if not path.exists(): path.mkdir() path.chmod(0o777) + # Make both permanent beamline presets and active experiment + # presets available. if experiment is not None and load_experiment_presets: setup_preset_paths( hutch=beamline_presets, @@ -615,6 +629,7 @@ def load_conf(conf, hutch_dir=None, args=None): defer_loading=True, ) else: + # Make only permanent beamline presets available. setup_preset_paths( hutch=beamline_presets, defer_loading=True, diff --git a/hutch_python/tests/test_load_conf.py b/hutch_python/tests/test_load_conf.py index d79c3fc1..82779c0a 100644 --- a/hutch_python/tests/test_load_conf.py +++ b/hutch_python/tests/test_load_conf.py @@ -31,7 +31,70 @@ def test_file_load(): for elem in should_have: assert not isinstance(objs[elem], SimpleNamespace), err.format(elem) assert 'tst' not in objs # Tree namespace should be disabled - assert len(Presets._paths) == 2 + assert set(Presets._paths) == {'hutch', 'exp'} + + +def test_experiment_presets_disabled(monkeypatch, tmp_path): + # verify that an active experiment does not cause experiment presets to + # be configured when the new setting is disabled. + setup_calls = [] + + def mock_setup_preset_paths(**kwargs): + setup_calls.append(kwargs) + + monkeypatch.setattr( + 'hutch_python.load_conf.setup_preset_paths', + mock_setup_preset_paths, + ) + monkeypatch.setattr( + 'hutch_python.load_conf.get_qs_objs', + lambda expname: {}, + ) + monkeypatch.setattr( + 'hutch_python.load_conf.get_exp_objs', + lambda expname: SimpleNamespace(), + ) + + load_conf( + { + 'hutch': 'tst', + 'experiment': 'tstx010', + 'load_experiment_presets': False, + 'daq_type': 'nodaq', + }, + hutch_dir=tmp_path, + ) + + beamline_path = tmp_path / 'presets' / 'beamline' + experiment_path = tmp_path / 'presets' / 'x010' + + assert setup_calls == [{ + 'hutch': beamline_path, + 'defer_loading': True, + }] + assert beamline_path.is_dir() + assert not experiment_path.exists() + + +def test_presets_without_experiment(monkeypatch, tmp_path): + setup_calls = [] + monkeypatch.setattr( + 'hutch_python.load_conf.setup_preset_paths', + lambda **kwargs: setup_calls.append(kwargs), + ) + + load_conf( + { + 'load_experiment_presets': True, + 'daq_type': 'nodaq', + }, + hutch_dir=tmp_path, + ) + + assert setup_calls == [{ + 'hutch': tmp_path / 'presets' / 'beamline', + 'defer_loading': True, + }] def test_exp_override(): From bceaeac0c8131d6d3404882589a0c851ce82d3aa Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Thu, 10 Sep 2026 12:13:00 -0700 Subject: [PATCH 04/10] Updated .gitignore to ignore hutch-python/_version.py file. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 31847f5c..b46031aa 100644 --- a/.gitignore +++ b/.gitignore @@ -121,3 +121,6 @@ hutch_python/tests/tst/db.txt # unit test artifacts *.sqlite + +# ignore _version.py +_version.py \ No newline at end of file From d48685516f15a515892d769c3ac3f40e65c309b6 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Thu, 10 Sep 2026 12:19:35 -0700 Subject: [PATCH 05/10] Removed generated file _version.py. --- hutch_python/_version.py | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 hutch_python/_version.py diff --git a/hutch_python/_version.py b/hutch_python/_version.py deleted file mode 100644 index aed61ea7..00000000 --- a/hutch_python/_version.py +++ /dev/null @@ -1,24 +0,0 @@ -# file generated by vcs-versioning -# don't change, don't track in version control -from __future__ import annotations - -__all__ = [ - "__version__", - "__version_tuple__", - "version", - "version_tuple", - "__commit_id__", - "commit_id", -] - -version: str -__version__: str -__version_tuple__: tuple[int | str, ...] -version_tuple: tuple[int | str, ...] -commit_id: str | None -__commit_id__: str | None - -__version__ = version = '0.1.dev1442+ge6a635929.d20260904' -__version_tuple__ = version_tuple = (0, 1, 'dev1442', 'ge6a635929.d20260904') - -__commit_id__ = commit_id = 'ge6a635929' From 93884cc1d5422d63d949a98c83872bd9de0535a8 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Thu, 10 Sep 2026 15:40:44 -0700 Subject: [PATCH 06/10] Updated documentation in load_conf.py. --- hutch_python/load_conf.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hutch_python/load_conf.py b/hutch_python/load_conf.py index 662a6e3d..072b88f7 100644 --- a/hutch_python/load_conf.py +++ b/hutch_python/load_conf.py @@ -597,9 +597,8 @@ def load_conf(conf, hutch_dir=None, args=None): load_experiment_presets = conf.get('load_experiment_presets', True) if not isinstance(load_experiment_presets, bool): logger.error( - 'Invalid load_experiment_presets value %r; expected a ' - 'boolean. ' - 'Experiment presets will be loaded.', + 'Invalid load_experiment_presets value %r; expected "true" ' + 'or "false". Experiment presets will be loaded.', load_experiment_presets, ) load_experiment_presets = True From bbe1eb9b21f88f4721cc00cd86fb18b3dd54a071 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Thu, 10 Sep 2026 17:16:58 -0700 Subject: [PATCH 07/10] Ran pre-commit and updated documentation. --- .gitignore | 2 +- docs/source/yaml_files.rst | 2 +- hutch_python/tests/test_load_conf.py | 12 +++--------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index b46031aa..c848ca3a 100644 --- a/.gitignore +++ b/.gitignore @@ -123,4 +123,4 @@ hutch_python/tests/tst/db.txt *.sqlite # ignore _version.py -_version.py \ No newline at end of file +_version.py diff --git a/docs/source/yaml_files.rst b/docs/source/yaml_files.rst index 4dacd485..a284568d 100644 --- a/docs/source/yaml_files.rst +++ b/docs/source/yaml_files.rst @@ -4,7 +4,7 @@ Yaml Files ``hutch-python`` uses a ``conf.yml`` file for basic configuration. This is a standard yaml file with the following valid keys: ``hutch``, ``db``, ``load``, ``load_level``, ``experiment``, ``obj_config``, -``daq_type``, ``daq_host``, ``daq_platform``, ``exclude_devices``, +``daq_type``, ``daq_host``, ``daq_platform``, ``exclude_devices``, ``additional_devices``, and ``load_experiment_presets``. diff --git a/hutch_python/tests/test_load_conf.py b/hutch_python/tests/test_load_conf.py index 82779c0a..409a1850 100644 --- a/hutch_python/tests/test_load_conf.py +++ b/hutch_python/tests/test_load_conf.py @@ -31,17 +31,16 @@ def test_file_load(): for elem in should_have: assert not isinstance(objs[elem], SimpleNamespace), err.format(elem) assert 'tst' not in objs # Tree namespace should be disabled - assert set(Presets._paths) == {'hutch', 'exp'} + assert len(Presets._paths) == 2 def test_experiment_presets_disabled(monkeypatch, tmp_path): - # verify that an active experiment does not cause experiment presets to - # be configured when the new setting is disabled. + # Check that an active experiment doesn't allow experiment presets to + # be configured when the setting is disabled. setup_calls = [] def mock_setup_preset_paths(**kwargs): setup_calls.append(kwargs) - monkeypatch.setattr( 'hutch_python.load_conf.setup_preset_paths', mock_setup_preset_paths, @@ -54,7 +53,6 @@ def mock_setup_preset_paths(**kwargs): 'hutch_python.load_conf.get_exp_objs', lambda expname: SimpleNamespace(), ) - load_conf( { 'hutch': 'tst', @@ -64,10 +62,8 @@ def mock_setup_preset_paths(**kwargs): }, hutch_dir=tmp_path, ) - beamline_path = tmp_path / 'presets' / 'beamline' experiment_path = tmp_path / 'presets' / 'x010' - assert setup_calls == [{ 'hutch': beamline_path, 'defer_loading': True, @@ -82,7 +78,6 @@ def test_presets_without_experiment(monkeypatch, tmp_path): 'hutch_python.load_conf.setup_preset_paths', lambda **kwargs: setup_calls.append(kwargs), ) - load_conf( { 'load_experiment_presets': True, @@ -90,7 +85,6 @@ def test_presets_without_experiment(monkeypatch, tmp_path): }, hutch_dir=tmp_path, ) - assert setup_calls == [{ 'hutch': tmp_path / 'presets' / 'beamline', 'defer_loading': True, From b04cda10310575bfa4967b5628c5ce927dc82d8b Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Fri, 11 Sep 2026 11:11:01 -0700 Subject: [PATCH 08/10] Updated comments in yaml_files.rst --- docs/source/yaml_files.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/yaml_files.rst b/docs/source/yaml_files.rst index a284568d..accf19d5 100644 --- a/docs/source/yaml_files.rst +++ b/docs/source/yaml_files.rst @@ -215,9 +215,8 @@ In the example below hutch-python will load all devices from "tmo_sqr1_search", load_experiment_presets ----------------------- -The ``load_experiment_presets`` key is optional and expects a Boolean value. -It controls whether hutch-python makes position presets from the active -experiment available to motors and other positioners. +The ``load_experiment_presets`` key determines whether hutch-python loads +position presets for the active experiment. It takes a boolean value. Position presets are saved locations that can be called by commands such as ``motor.mv_sample()``. Hutch-python supports two types of position presets. From 8eee5e8f978ff0ac0f5718dcca69dbeffea425ba Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Fri, 11 Sep 2026 14:24:51 -0700 Subject: [PATCH 09/10] Commit changes from pre-commit. --- docs/source/yaml_files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/yaml_files.rst b/docs/source/yaml_files.rst index accf19d5..6acf45b6 100644 --- a/docs/source/yaml_files.rst +++ b/docs/source/yaml_files.rst @@ -215,7 +215,7 @@ In the example below hutch-python will load all devices from "tmo_sqr1_search", load_experiment_presets ----------------------- -The ``load_experiment_presets`` key determines whether hutch-python loads +The ``load_experiment_presets`` key determines whether hutch-python loads position presets for the active experiment. It takes a boolean value. Position presets are saved locations that can be called by commands such as From 974091560048ef6026c3e8e4c4dd3f0bc3a1e9b6 Mon Sep 17 00:00:00 2001 From: Jane Liu Date: Fri, 11 Sep 2026 14:55:47 -0700 Subject: [PATCH 10/10] Add release notes. --- ...ip_loading_experiment_position_presets.rst | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/source/upcoming_release_notes/409-Add_option_to_skip_loading_experiment_position_presets.rst diff --git a/docs/source/upcoming_release_notes/409-Add_option_to_skip_loading_experiment_position_presets.rst b/docs/source/upcoming_release_notes/409-Add_option_to_skip_loading_experiment_position_presets.rst new file mode 100644 index 00000000..c83831e5 --- /dev/null +++ b/docs/source/upcoming_release_notes/409-Add_option_to_skip_loading_experiment_position_presets.rst @@ -0,0 +1,22 @@ +409 Add option to skip loading experiment position presets +################# + +API Changes +----------- +- N/A + +Features +-------- +- Added an option (available in conf.yml) to skip loading experiment motor position presets. + +Bugfixes +-------- +- N/A + +Maintenance +----------- +- N/A + +Contributors +------------ +janeliu-slac