Commit 7e0e473f authored by Benoit Formet's avatar Benoit Formet
Browse files

user_script_load: export to "user" namespace by default+ backup and merge if pre-existing

parent 8550342f
Pipeline #27535 failed with stages
in 52 minutes and 57 seconds
......@@ -31,8 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow to select another curve when the fit dialog is open
- Profile windows are now docks
- Tune the scan status widget to resize the width smaller
- Provide tool to remove curves close to the y1/y2 indicators
- Rework the check of the flint API at startup to reduce pointless warnings
- Provide tool to remove curves close to the y1/y2 indicators
- Rework the check of the flint API at startup to reduce pointless warnings
- Group Lima ROI channels by ROI name in the property tree
- ct:
- ct now works with count_time or counter as first argument.
......@@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
in case positioners or metadata is needed, use `sct` instead.
- ct (and sct) will no longer be added to SCANS queue of the session
- scan numbering: scans that are not saved use a shadow scan number and do not increase the scan numbers used in the hdf5 file.
- user_script:
- `user_load_script` now exports to "user" namespace in session env dict by default.
### Fixed
- Flint:
......
......@@ -478,7 +478,7 @@ class Session:
continue
print(f" - {os.path.join(dirname, filename)}")
def user_script_load(self, scriptname=None, export_global=False):
def user_script_load(self, scriptname=None, export_global="user"):
"""
load a script and export all public (= not starting with _)
objects and functions to current environment or to a namespace.
......@@ -487,9 +487,9 @@ class Session:
Args:
scriptname: the python file to load (script path can be absolute relative to script_homedir)
Optional args:
export_global=False (default): return a namespace
export_global="user" (default): export objects to "user" namespace in session env dict (eg. user.myfunc())
export_global=False: return a namespace
export_global=True: export objects to session env dict
export_global="user": export objects to "user" namespace in session env dict (eg. user.myfunc())
"""
return self._user_script_exec(
scriptname, load=True, export_global=export_global
......@@ -546,6 +546,15 @@ class Session:
except Exception:
sys.excepthook(*sys.exc_info())
def safe_save_to_env_dict(env_dict, key, value):
""" Print warning and backup if env_dict[key] already exists """
if key in env_dict and value is not env_dict[key]:
print(
f"Warning: {key} already exists in session env, backed up to {key}_bak."
)
env_dict[key + "_bak"] = env_dict[key]
env_dict[key] = value
# case: run file
if not load:
return
......@@ -555,7 +564,7 @@ class Session:
for k in globals_dict.keys():
if k.startswith("_"):
continue
self.env_dict[k] = globals_dict[k]
safe_save_to_env_dict(self.env_dict, k, globals_dict[k])
else:
env_dict = dict()
......@@ -568,8 +577,12 @@ class Session:
ns = SimpleNamespace(**env_dict)
if isinstance(export_global, str):
# case: export to given namespace in env dict
self.env_dict[export_global] = ns
if isinstance(self.env_dict.get(export_global), SimpleNamespace):
# case: export and merge to existing namespace in env dict
self.env_dict[export_global].__dict__.update(ns.__dict__)
else:
# case: export to given (non existing) namespace in env dict
safe_save_to_env_dict(self.env_dict, export_global, ns)
else:
# case: export_global is False, return the namespace
return ns
......
......@@ -36,9 +36,9 @@ Argument:
Optional argument:
* `export_global=False` (default): return a namespace
* `export_global="user"` (default): export to a "user" namespace in current environment (and merge if pre-existing)
* `export_global=False`: return a namespace
* `export_global=True`: export to current environment
* `export_global="user"`: export a "user" namespace to current environment ()
Return value:
......@@ -74,57 +74,67 @@ Return value:
## Examples
!!! example "File `/path/to/demo.py`"
!!! example "Script file `/path/to/demo.py`"
```python
```python
import time
# 'time' module is now usable in this file, but also in the session
# 'demo' after loading of the script.
import time
# 'time' module is now usable in this file, but also in the session
# 'demo' after loading of the script.
print("[loading script]: align_spectrometer()")
print("[loading script] align_spectrometer()")
def align_spectrometer(energy=5.0):
print(f"Aligning spectrometer for energy {energy}...")
time.sleep(1)
print(f"Spectrometer is aligned :)")
```
# this function will be usable in the session once this script is loaded
def align_spectrometer(energy=5.0):
print(f"Aligning spectrometer for energy {energy} ...")
time.sleep(1)
print(f"Spectrometer is aligned :)")
```
Example of script loading and usage:
### Example of script loading and usage:
```python
DEMO [1]: demo = user_script_load('demo')
# Export to "user" namespace (default) in global env dict
DEMO [1]: user_script_load('/path/to/demo')
Loading [/path/to/demo.py]...
[loading script]: align_spectrometer()
[loading script] align_spectrometer()
DEMO [2]:
DEMO [2]: demo.align_spectrometer(energy=7.5)
Aligning spectrometer for energy 7.5 ...
DEMO [2]: user.align_spectrometer(energy=7.5)
Aligning spectrometer for energy 7.5 ...
Spectrometer is aligned :)
DEMO [3]:
```
alternative usage:
```python
DEMO [1]: user_script_load('demo', export_global="demo")
# Export to a custom "demo" namespace in global env dict
DEMO [1]: user_script_load('/path/to/demo', export_global="demo")
Loading [/path/to/demo.py]...
[loading script]: align_spectrometer()
[loading script] align_spectrometer()
DEMO [2]:
DEMO [2]: demo.align_spectrometer(energy=7.5)
Aligning spectrometer for energy 7.5 ...
Aligning spectrometer for energy 7.5 ...
Spectrometer is aligned :)
DEMO [3]:
```
or
alternative usage:
```python
DEMO [1]: user_script_load('demo', export_global=True)
# Export to global env dict
DEMO [1]: user_script_load('/path/to/demo', export_global=True)
Loading [/path/to/demo.py]...
[loading script]: align_spectrometer()
[loading script] align_spectrometer()
DEMO [2]:
DEMO [2]: align_spectrometer(energy=7.5)
Aligning spectrometer for energy 7.5 ...
Aligning spectrometer for energy 7.5 ...
Spectrometer is aligned :)
```
```python
# Return a namespace
DEMO [1]: demo = user_script_load('/path/to/demo', export_global=False)
Loading [/path/to/demo.py]...
[loading script] align_spectrometer()
DEMO [2]:
DEMO [2]: demo.align_spectrometer(energy=7.5)
Aligning spectrometer for energy 7.5 ...
Spectrometer is aligned :)
DEMO [3]:
```
......@@ -127,23 +127,41 @@ def test_user_script(session4, capsys):
from tests.conftest import BEACON_DB_PATH
# test user_script_homedir and user_script_list
user_script_homedir(BEACON_DB_PATH)
assert user_script_homedir() == BEACON_DB_PATH
capsys.readouterr()
user_script_list()
assert "sessions/subdir/scripts/simple_script.py" in capsys.readouterr()[0]
# test that user_script_run does not export things
user_script_run("sessions/scripts/script3")
assert "toto" not in session4.env_dict
assert "user" not in session4.env_dict
# test that user_script_load can export to global env dict
user_script_load("sessions/scripts/script3", export_global=True)
assert "toto" in session4.env_dict
# test that user_script_load can return a namespace
expected_symbols = ["ascan", "time", "test1", "a"]
ns = user_script_load("sessions/subdir/scripts/simple_script")
ns = user_script_load("sessions/subdir/scripts/simple_script", export_global=False)
assert list(ns.__dict__) == expected_symbols
session4.env_dict["user"] = 42
user_script_load("sessions/subdir/scripts/simple_script")
# test that user_script_load can export to "user" namespace
assert list(session4.env_dict["user"].__dict__) == expected_symbols
# test backup of pre existing user
assert session4.env_dict["user_bak"] == 42
session4.env_dict["user_ns"] = session4.env_dict["user"]
session4.env_dict["user_ns"].a == 0
user_script_load("sessions/subdir/scripts/simple_script", export_global="user_ns")
assert list(session4.env_dict["user_ns"].__dict__) == expected_symbols
user_script_load("sessions/scripts/script3", export_global="user_ns")
# test that user_script_load can merge to existing namespace
assert session4.env_dict["user_ns"].a == 42
assert session4.env_dict["user_ns"].toto == 42
def test_prdef(session2, capsys):
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment