Skip to content

Commit

Permalink
Merge branch 'v1_feature_branch' into hextof-lab-loader
Browse files Browse the repository at this point in the history
  • Loading branch information
zain-sohail authored Jan 28, 2025
2 parents 788d189 + 8ff0040 commit 69e4595
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 74 deletions.
1 change: 1 addition & 0 deletions .cspell/custom-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ datestring
ddir
delaxes
delayeds
delenv
Desy
Deutsches
dfield
Expand Down
15 changes: 12 additions & 3 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,21 @@ jobs:
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
echo "folder=sed/$VERSION" >> $GITHUB_OUTPUT
rm docs-repo/sed/stable
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/stable
echo "folder=sed/$VERSION" >> $GITHUB_OUTPUT
if [[ $VERSION == *a* ]]; then
rm -rf docs-repo/sed/latest
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/latest
else
rm -rf docs-repo/sed/stable
rm -rf docs-repo/sed/latest
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/stable
ln -s -r docs-repo/sed/$VERSION docs-repo/sed/latest
fi
elif [[ $GITHUB_REF == refs/heads/main ]]; then
rm -rf docs-repo/sed/latest
echo "folder=sed/latest" >> $GITHUB_OUTPUT
else
rm -rf docs-repo/sed/develop
echo "folder=sed/develop" >> $GITHUB_OUTPUT
fi
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![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/))
[![Documentation Status](https://github.com/OpenCOMPES/sed/actions/workflows/documentation.yml/badge.svg)](https://opencompes.github.io/docs/sed/stable/)
[![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)
![](https://github.com/OpenCOMPES/sed/actions/workflows/linting.yml/badge.svg?branch=main)
![](https://github.com/OpenCOMPES/sed/actions/workflows/testing_multiversion.yml/badge.svg?branch=main)
Expand Down Expand Up @@ -58,11 +58,11 @@ pip install sed-processor

# Documentation
Comprehensive documentation including several workflow examples can be found here:
https://opencompes.github.io/docs/sed/latest/
https://opencompes.github.io/docs/sed/stable/


# Contributing
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)
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)

We would like to thank our contributors!

Expand Down
4 changes: 2 additions & 2 deletions docs/user_guide/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ The config module contains a mechanism to collect configuration parameters from
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:

* ``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.
* ``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.
* ``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`
* ``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.
* ``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`
* ``default_config``: The default configuration shipped with the package. Typically, all parameters here should be overwritten by any of the other configuration files.

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).
Expand Down
10 changes: 9 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,16 @@ authors = [
]
readme = "README.md"
keywords = ["sed", "mpes", "flash", "arpes"]
license = {text = "MIT"}
license = { file = "LICENSE" }
requires-python = ">=3.9,<3.13"
classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
dependencies = [
"bokeh>=2.4.2",
"dask>=2021.12.0,<2024.8",
Expand Down
58 changes: 37 additions & 21 deletions src/sed/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@

import yaml
from platformdirs import user_config_path
from pydantic import ValidationError

from sed.core.config_model import ConfigModel
from sed.core.logging import setup_logging

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

USER_CONFIG_PATH = user_config_path(appname="sed", appauthor="OpenCOMPES", ensure_exists=True)
SYSTEM_CONFIG_PATH = (
Path(os.environ["ALLUSERSPROFILE"]).joinpath("sed")
if platform.system() == "Windows"
else Path("/etc/").joinpath("sed")
)
ENV_DIR = Path(".env")

# Configure logging
logger = setup_logging("config")
Expand Down Expand Up @@ -48,11 +55,11 @@ def parse_config(
user_config (dict | str, optional): user-based config dictionary
or file path. The loaded dictionary is completed with the user-based values,
taking preference over system and default values.
Defaults to the file ".sed/config.yaml" in the current user's home directory.
Defaults to the file ".config/sed/config_v1.yaml" in the current user's home directory.
system_config (dict | str, optional): system-wide config dictionary
or file path. The loaded dictionary is completed with the system-wide values,
taking preference over default values. Defaults to the file "/etc/sed/config.yaml"
on linux, and "%ALLUSERSPROFILE%/sed/config.yaml" on windows.
taking preference over default values. Defaults to the file "/etc/sed/config_v1.yaml"
on linux, and "%ALLUSERSPROFILE%/sed/config_v1.yaml" on windows.
default_config (dict | str, optional): default config dictionary
or file path. The loaded dictionary is completed with the default values.
Defaults to *package_dir*/config/default.yaml".
Expand All @@ -61,6 +68,7 @@ def parse_config(
Raises:
TypeError: Raised if the provided file is neither *json* nor *yaml*.
FileNotFoundError: Raised if the provided file is not found.
ValueError: Raised if there is a validation error in the config file.
Returns:
dict: Loaded and completed config dict, possibly verified by pydantic config model.
Expand Down Expand Up @@ -91,9 +99,7 @@ def parse_config(
user_dict = copy.deepcopy(user_config)
else:
if user_config is None:
user_config = str(
Path.home().joinpath(".sed").joinpath("config.yaml"),
)
user_config = str(USER_CONFIG_PATH.joinpath("config_v1.yaml"))
if Path(user_config).exists():
user_dict = load_config(user_config)
if verbose:
Expand All @@ -104,14 +110,7 @@ def parse_config(
system_dict = copy.deepcopy(system_config)
else:
if system_config is None:
if platform.system() in ["Linux", "Darwin"]:
system_config = str(
Path("/etc/").joinpath("sed").joinpath("config.yaml"),
)
elif platform.system() == "Windows":
system_config = str(
Path(os.environ["ALLUSERSPROFILE"]).joinpath("sed").joinpath("config.yaml"),
)
system_config = str(SYSTEM_CONFIG_PATH.joinpath("config_v1.yaml"))
if Path(system_config).exists():
system_dict = load_config(system_config)
if verbose:
Expand Down Expand Up @@ -146,9 +145,19 @@ def parse_config(

if not verify_config:
return config_dict
# Run the config through the ConfigModel to ensure it is valid
config_model = ConfigModel(**config_dict)
return config_model.model_dump(exclude_unset=True, exclude_none=True)

try:
# Run the config through the ConfigModel to ensure it is valid
config_model = ConfigModel(**config_dict)
return config_model.model_dump(exclude_unset=True, exclude_none=True)
except ValidationError as e:
error_msg = (
"Invalid configuration file detected. The following validation errors were found:\n"
)
for error in e.errors():
error_msg += f"\n- {' -> '.join(str(loc) for loc in error['loc'])}: {error['msg']}"
logger.error(error_msg)
raise ValueError(error_msg) from e


def load_config(config_path: str) -> dict:
Expand Down Expand Up @@ -269,31 +278,38 @@ def read_env_var(var_name: str) -> str | None:
1. OS environment variables
2. .env file in current directory
3. .env file in user config directory
4. .env file in system config directory
Args:
var_name (str): Name of the environment variable to read
Returns:
str | None: Value of the environment variable or None if not found
"""
# First check OS environment variables
# 1. check OS environment variables
value = os.getenv(var_name)
if value is not None:
logger.debug(f"Found {var_name} in OS environment variables")
return value

# Then check .env in current directory
local_vars = _parse_env_file(Path(".env"))
# 2. check .env in current directory
local_vars = _parse_env_file(ENV_DIR)
if var_name in local_vars:
logger.debug(f"Found {var_name} in ./.env file")
return local_vars[var_name]

# Finally check .env in user config directory
# 3. check .env in user config directory
user_vars = _parse_env_file(USER_CONFIG_PATH / ".env")
if var_name in user_vars:
logger.debug(f"Found {var_name} in user config .env file")
return user_vars[var_name]

# 4. check .env in system config directory
system_vars = _parse_env_file(SYSTEM_CONFIG_PATH / ".env")
if var_name in system_vars:
logger.debug(f"Found {var_name} in system config .env file")
return system_vars[var_name]

logger.debug(f"Environment variable {var_name} not found in any location")
return None

Expand Down
Loading

0 comments on commit 69e4595

Please sign in to comment.