Skip to content

Commit 69e4595

Browse files
authored
Merge branch 'v1_feature_branch' into hextof-lab-loader
2 parents 788d189 + 8ff0040 commit 69e4595

File tree

7 files changed

+118
-74
lines changed

7 files changed

+118
-74
lines changed

.cspell/custom-dictionary.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ datestring
8282
ddir
8383
delaxes
8484
delayeds
85+
delenv
8586
Desy
8687
Deutsches
8788
dfield

.github/workflows/documentation.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,21 @@ jobs:
107107
run: |
108108
if [[ $GITHUB_REF == refs/tags/* ]]; then
109109
VERSION=${GITHUB_REF#refs/tags/}
110-
echo "folder=sed/$VERSION" >> $GITHUB_OUTPUT
111-
rm docs-repo/sed/stable
112-
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/stable
110+
echo "folder=sed/$VERSION" >> $GITHUB_OUTPUT
111+
if [[ $VERSION == *a* ]]; then
112+
rm -rf docs-repo/sed/latest
113+
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/latest
114+
else
115+
rm -rf docs-repo/sed/stable
116+
rm -rf docs-repo/sed/latest
117+
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/stable
118+
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/latest
119+
fi
113120
elif [[ $GITHUB_REF == refs/heads/main ]]; then
121+
rm -rf docs-repo/sed/latest
114122
echo "folder=sed/latest" >> $GITHUB_OUTPUT
115123
else
124+
rm -rf docs-repo/sed/develop
116125
echo "folder=sed/develop" >> $GITHUB_OUTPUT
117126
fi
118127

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[![Documentation Status](https://github.com/OpenCOMPES/sed/actions/workflows/documentation.yml/badge.svg)]([https://opencompes.github.io/sed/](https://opencompes.github.io/docs/sed/latest/))
1+
[![Documentation Status](https://github.com/OpenCOMPES/sed/actions/workflows/documentation.yml/badge.svg)](https://opencompes.github.io/docs/sed/stable/)
22
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
33
![](https://github.com/OpenCOMPES/sed/actions/workflows/linting.yml/badge.svg?branch=main)
44
![](https://github.com/OpenCOMPES/sed/actions/workflows/testing_multiversion.yml/badge.svg?branch=main)
@@ -58,11 +58,11 @@ pip install sed-processor
5858

5959
# Documentation
6060
Comprehensive documentation including several workflow examples can be found here:
61-
https://opencompes.github.io/docs/sed/latest/
61+
https://opencompes.github.io/docs/sed/stable/
6262

6363

6464
# Contributing
65-
Users are welcome to contribute to the development of **sed-processor**. Information how to contribute, including how to install developer versions can be found in the [documentation](https://opencompes.github.io/docs/sed/latest/misc/contribution.html)
65+
Users are welcome to contribute to the development of **sed-processor**. Information how to contribute, including how to install developer versions can be found in the [documentation](https://opencompes.github.io/docs/sed/stable/misc/contribution.html)
6666

6767
We would like to thank our contributors!
6868

docs/user_guide/config.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ The config module contains a mechanism to collect configuration parameters from
44
It will load an (optional) provided config file, or alternatively use a passed python dictionary as initial config dictionary, and subsequently look for the following additional config files to load:
55

66
* ``folder_config``: A config file of name :file:`sed_config.yaml` in the current working directory. This is mostly intended to pass calibration parameters of the workflow between different notebook instances.
7-
* ``user_config``: A config file provided by the user, stored as :file:`.sed/config.yaml` in the current user's home directly. This is intended to give a user the option for individual configuration modifications of system settings.
8-
* ``system_config``: A config file provided by the system administrator, stored as :file:`/etc/sed/config.yaml` on Linux-based systems, and :file:`%ALLUSERSPROFILE%/sed/config.yaml` on Windows. This should provide all necessary default parameters for using the sed processor with a given setup. For an example for an mpes setup, see :ref:`example_config`
7+
* ``user_config``: A config file provided by the user, stored as :file:`.config/sed/config_v1.yaml` in the current user's home directly. This is intended to give a user the option for individual configuration modifications of system settings.
8+
* ``system_config``: A config file provided by the system administrator, stored as :file:`/etc/sed/config_v1.yaml` on Linux-based systems, and :file:`%ALLUSERSPROFILE%/sed/config_v1.yaml` on Windows. This should provide all necessary default parameters for using the sed processor with a given setup. For an example for an mpes setup, see :ref:`example_config`
99
* ``default_config``: The default configuration shipped with the package. Typically, all parameters here should be overwritten by any of the other configuration files.
1010

1111
The config mechanism returns the combined dictionary, and reports the loaded configuration files. In order to disable or overwrite any of the configuration files, they can be also given as optional parameters (path to a file, or python dictionary).

pyproject.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,16 @@ authors = [
1818
]
1919
readme = "README.md"
2020
keywords = ["sed", "mpes", "flash", "arpes"]
21-
license = {text = "MIT"}
21+
license = { file = "LICENSE" }
2222
requires-python = ">=3.9,<3.13"
23+
classifiers = [
24+
"Programming Language :: Python :: 3.9",
25+
"Programming Language :: Python :: 3.10",
26+
"Programming Language :: Python :: 3.11",
27+
"Programming Language :: Python :: 3.12",
28+
"License :: OSI Approved :: MIT License",
29+
"Operating System :: OS Independent",
30+
]
2331
dependencies = [
2432
"bokeh>=2.4.2",
2533
"dask>=2021.12.0,<2024.8",

src/sed/core/config.py

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,20 @@
1111

1212
import yaml
1313
from platformdirs import user_config_path
14+
from pydantic import ValidationError
1415

1516
from sed.core.config_model import ConfigModel
1617
from sed.core.logging import setup_logging
1718

1819
package_dir = os.path.dirname(find_spec("sed").origin)
1920

2021
USER_CONFIG_PATH = user_config_path(appname="sed", appauthor="OpenCOMPES", ensure_exists=True)
22+
SYSTEM_CONFIG_PATH = (
23+
Path(os.environ["ALLUSERSPROFILE"]).joinpath("sed")
24+
if platform.system() == "Windows"
25+
else Path("/etc/").joinpath("sed")
26+
)
27+
ENV_DIR = Path(".env")
2128

2229
# Configure logging
2330
logger = setup_logging("config")
@@ -48,11 +55,11 @@ def parse_config(
4855
user_config (dict | str, optional): user-based config dictionary
4956
or file path. The loaded dictionary is completed with the user-based values,
5057
taking preference over system and default values.
51-
Defaults to the file ".sed/config.yaml" in the current user's home directory.
58+
Defaults to the file ".config/sed/config_v1.yaml" in the current user's home directory.
5259
system_config (dict | str, optional): system-wide config dictionary
5360
or file path. The loaded dictionary is completed with the system-wide values,
54-
taking preference over default values. Defaults to the file "/etc/sed/config.yaml"
55-
on linux, and "%ALLUSERSPROFILE%/sed/config.yaml" on windows.
61+
taking preference over default values. Defaults to the file "/etc/sed/config_v1.yaml"
62+
on linux, and "%ALLUSERSPROFILE%/sed/config_v1.yaml" on windows.
5663
default_config (dict | str, optional): default config dictionary
5764
or file path. The loaded dictionary is completed with the default values.
5865
Defaults to *package_dir*/config/default.yaml".
@@ -61,6 +68,7 @@ def parse_config(
6168
Raises:
6269
TypeError: Raised if the provided file is neither *json* nor *yaml*.
6370
FileNotFoundError: Raised if the provided file is not found.
71+
ValueError: Raised if there is a validation error in the config file.
6472
6573
Returns:
6674
dict: Loaded and completed config dict, possibly verified by pydantic config model.
@@ -91,9 +99,7 @@ def parse_config(
9199
user_dict = copy.deepcopy(user_config)
92100
else:
93101
if user_config is None:
94-
user_config = str(
95-
Path.home().joinpath(".sed").joinpath("config.yaml"),
96-
)
102+
user_config = str(USER_CONFIG_PATH.joinpath("config_v1.yaml"))
97103
if Path(user_config).exists():
98104
user_dict = load_config(user_config)
99105
if verbose:
@@ -104,14 +110,7 @@ def parse_config(
104110
system_dict = copy.deepcopy(system_config)
105111
else:
106112
if system_config is None:
107-
if platform.system() in ["Linux", "Darwin"]:
108-
system_config = str(
109-
Path("/etc/").joinpath("sed").joinpath("config.yaml"),
110-
)
111-
elif platform.system() == "Windows":
112-
system_config = str(
113-
Path(os.environ["ALLUSERSPROFILE"]).joinpath("sed").joinpath("config.yaml"),
114-
)
113+
system_config = str(SYSTEM_CONFIG_PATH.joinpath("config_v1.yaml"))
115114
if Path(system_config).exists():
116115
system_dict = load_config(system_config)
117116
if verbose:
@@ -146,9 +145,19 @@ def parse_config(
146145

147146
if not verify_config:
148147
return config_dict
149-
# Run the config through the ConfigModel to ensure it is valid
150-
config_model = ConfigModel(**config_dict)
151-
return config_model.model_dump(exclude_unset=True, exclude_none=True)
148+
149+
try:
150+
# Run the config through the ConfigModel to ensure it is valid
151+
config_model = ConfigModel(**config_dict)
152+
return config_model.model_dump(exclude_unset=True, exclude_none=True)
153+
except ValidationError as e:
154+
error_msg = (
155+
"Invalid configuration file detected. The following validation errors were found:\n"
156+
)
157+
for error in e.errors():
158+
error_msg += f"\n- {' -> '.join(str(loc) for loc in error['loc'])}: {error['msg']}"
159+
logger.error(error_msg)
160+
raise ValueError(error_msg) from e
152161

153162

154163
def load_config(config_path: str) -> dict:
@@ -269,31 +278,38 @@ def read_env_var(var_name: str) -> str | None:
269278
1. OS environment variables
270279
2. .env file in current directory
271280
3. .env file in user config directory
281+
4. .env file in system config directory
272282
273283
Args:
274284
var_name (str): Name of the environment variable to read
275285
276286
Returns:
277287
str | None: Value of the environment variable or None if not found
278288
"""
279-
# First check OS environment variables
289+
# 1. check OS environment variables
280290
value = os.getenv(var_name)
281291
if value is not None:
282292
logger.debug(f"Found {var_name} in OS environment variables")
283293
return value
284294

285-
# Then check .env in current directory
286-
local_vars = _parse_env_file(Path(".env"))
295+
# 2. check .env in current directory
296+
local_vars = _parse_env_file(ENV_DIR)
287297
if var_name in local_vars:
288298
logger.debug(f"Found {var_name} in ./.env file")
289299
return local_vars[var_name]
290300

291-
# Finally check .env in user config directory
301+
# 3. check .env in user config directory
292302
user_vars = _parse_env_file(USER_CONFIG_PATH / ".env")
293303
if var_name in user_vars:
294304
logger.debug(f"Found {var_name} in user config .env file")
295305
return user_vars[var_name]
296306

307+
# 4. check .env in system config directory
308+
system_vars = _parse_env_file(SYSTEM_CONFIG_PATH / ".env")
309+
if var_name in system_vars:
310+
logger.debug(f"Found {var_name} in system config .env file")
311+
return system_vars[var_name]
312+
297313
logger.debug(f"Environment variable {var_name} not found in any location")
298314
return None
299315

0 commit comments

Comments
 (0)