Skip to content

Commit

Permalink
Enable more user-friendly time durations in config
Browse files Browse the repository at this point in the history
  • Loading branch information
bennybp committed Jan 8, 2025
1 parent 3e86b5d commit ea45f56
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 10 deletions.
9 changes: 9 additions & 0 deletions qcfractal/qcfractal/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from sqlalchemy.engine.url import URL, make_url

from qcfractal.port_util import find_open_port
from qcportal.utils import duration_to_seconds


def update_nested_dict(d, u):
Expand Down Expand Up @@ -315,6 +316,10 @@ class WebAPIConfig(ConfigBase):
None, description="Any additional options to pass directly to the waitress serve function"
)

@validator("jwt_access_token_expires", "jwt_refresh_token_expires", pre=True)
def _convert_durations(cls, v):
return duration_to_seconds(v)

class Config(ConfigCommon):
env_prefix = "QCF_API_"

Expand Down Expand Up @@ -454,6 +459,10 @@ def _check_loglevel(cls, v):
raise ValidationError(f"{v} is not a valid loglevel. Must be DEBUG, INFO, WARNING, ERROR, or CRITICAL")
return v

@validator("service_frequency", "heartbeat_frequency", "access_log_keep", pre=True)
def _convert_durations(cls, v):
return duration_to_seconds(v)

class Config(ConfigCommon):
env_prefix = "QCF_"

Expand Down
65 changes: 65 additions & 0 deletions qcfractal/qcfractal/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import copy

from qcfractal.config import FractalConfig

_base_config = {
"api": {
"secret_key": "abc1234def456",
"jwt_secret_key": "abc123def456",
},
"database": {"username": "qcfractal", "password": "abc123def456"},
}


def test_config_durations_plain(tmp_path):
base_folder = str(tmp_path)

base_config = copy.deepcopy(_base_config)
base_config["service_frequency"] = 3600
base_config["heartbeat_frequency"] = 30
base_config["access_log_keep"] = 100802
base_config["api"]["jwt_access_token_expires"] = 7450
base_config["api"]["jwt_refresh_token_expires"] = 637277
cfg = FractalConfig(base_folder=base_folder, **base_config)

assert cfg.service_frequency == 3600
assert cfg.heartbeat_frequency == 30
assert cfg.access_log_keep == 100802
assert cfg.api.jwt_access_token_expires == 7450
assert cfg.api.jwt_refresh_token_expires == 637277


def test_config_durations_str(tmp_path):
base_folder = str(tmp_path)

base_config = copy.deepcopy(_base_config)
base_config["service_frequency"] = "1h"
base_config["heartbeat_frequency"] = "30s"
base_config["access_log_keep"] = "1d4h2s"
base_config["api"]["jwt_access_token_expires"] = "2h4m10s"
base_config["api"]["jwt_refresh_token_expires"] = "7d9h77s"
cfg = FractalConfig(base_folder=base_folder, **base_config)

assert cfg.service_frequency == 3600
assert cfg.heartbeat_frequency == 30
assert cfg.access_log_keep == 100802
assert cfg.api.jwt_access_token_expires == 7450
assert cfg.api.jwt_refresh_token_expires == 637277


def test_config_durations_dhms(tmp_path):
base_folder = str(tmp_path)

base_config = copy.deepcopy(_base_config)
base_config["service_frequency"] = "1:00:00"
base_config["heartbeat_frequency"] = "30"
base_config["access_log_keep"] = "1:04:00:02"
base_config["api"]["jwt_access_token_expires"] = "2:04:10"
base_config["api"]["jwt_refresh_token_expires"] = "7:09:00:77"
cfg = FractalConfig(base_folder=base_folder, **base_config)

assert cfg.service_frequency == 3600
assert cfg.heartbeat_frequency == 30
assert cfg.access_log_keep == 100802
assert cfg.api.jwt_access_token_expires == 7450
assert cfg.api.jwt_refresh_token_expires == 637277
16 changes: 7 additions & 9 deletions qcfractalcompute/qcfractalcompute/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pydantic import BaseModel, Field, validator
from typing_extensions import Literal

from qcportal.utils import seconds_to_hms
from qcportal.utils import seconds_to_hms, duration_to_seconds


def _make_abs_path(path: Optional[str], base_folder: str, default_filename: Optional[str]) -> Optional[str]:
Expand Down Expand Up @@ -120,10 +120,7 @@ class TorqueExecutorConfig(ExecutorConfig):

@validator("walltime", pre=True)
def walltime_must_be_str(cls, v):
if isinstance(v, int):
return seconds_to_hms(v)
else:
return v
return seconds_to_hms(duration_to_seconds(v))


class LSFExecutorConfig(ExecutorConfig):
Expand All @@ -143,10 +140,7 @@ class LSFExecutorConfig(ExecutorConfig):

@validator("walltime", pre=True)
def walltime_must_be_str(cls, v):
if isinstance(v, int):
return seconds_to_hms(v)
else:
return v
return seconds_to_hms(duration_to_seconds(v))


AllExecutorTypes = Union[
Expand Down Expand Up @@ -226,6 +220,10 @@ def _check_logfile(cls, v, values):
def _check_run_dir(cls, v, values):
return _make_abs_path(v, values["base_folder"], "parsl_run_dir")

@validator("update_frequency", pre=True)
def _convert_durations(cls, v):
return duration_to_seconds(v)


def read_configuration(file_paths: List[str], extra_config: Optional[Dict[str, Any]] = None) -> FractalComputeConfig:
logger = logging.getLogger(__name__)
Expand Down
33 changes: 32 additions & 1 deletion qcfractalcompute/qcfractalcompute/test_manager_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
from __future__ import annotations

import copy

import pytest
import yaml

from qcfractalcompute.config import SlurmExecutorConfig
from qcfractalcompute.config import SlurmExecutorConfig, FractalComputeConfig

_base_config = {
"cluster": "testcluster",
"server": {
"fractal_uri": "http://localhost:7777/",
},
"executors": {},
}


@pytest.mark.parametrize("time_str", ["02:01:59", "72:00:00", "10:00:00"])
Expand Down Expand Up @@ -39,3 +49,24 @@ def test_manager_config_walltime(time_str):
config = yaml.load(config_yaml, yaml.SafeLoader)
executor_config = SlurmExecutorConfig(**config)
assert executor_config.walltime == time_str


def test_manager_config_durations(tmp_path):
base_folder = str(tmp_path)
base_config = copy.deepcopy(_base_config)

base_config["update_frequency"] = "900"
manager_config = FractalComputeConfig(base_folder=base_folder, **base_config)
assert manager_config.update_frequency == 900

base_config["update_frequency"] = 900
manager_config = FractalComputeConfig(base_folder=base_folder, **base_config)
assert manager_config.update_frequency == 900

base_config["update_frequency"] = "3d4h80m09s"
manager_config = FractalComputeConfig(base_folder=base_folder, **base_config)
assert manager_config.update_frequency == 278409

base_config["update_frequency"] = "3:04:80:9"
manager_config = FractalComputeConfig(base_folder=base_folder, **base_config)
assert manager_config.update_frequency == 278409

0 comments on commit ea45f56

Please sign in to comment.