hpcflow-new2 0.2.0a37__tar.gz → 0.2.0a38__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/PKG-INFO +1 -1
- hpcflow_new2-0.2.0a38/hpcflow/_version.py +1 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/__init__.py +12 -4
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/app.py +12 -4
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/config/callbacks.py +18 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/config/config.py +14 -13
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/config/config_file.py +5 -2
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/config/errors.py +3 -2
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/actions.py +1 -1
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/command_files.py +2 -2
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/utils.py +1 -6
- hpcflow_new2-0.2.0a38/hpcflow/sdk/log.py +41 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/runtime.py +14 -13
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/jobscript.py +1 -1
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/pyproject.toml +2 -2
- hpcflow_new2-0.2.0a37/hpcflow/_version.py +0 -1
- hpcflow_new2-0.2.0a37/hpcflow/api/config.py +0 -17
- hpcflow_new2-0.2.0a37/hpcflow/sdk/log.py +0 -26
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/README.md +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/__pyinstaller/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/__pyinstaller/hook-hpcflow.py +0 -0
- /hpcflow_new2-0.2.0a37/hpcflow/api/__init__.py → /hpcflow_new2-0.2.0a38/hpcflow/api.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/cli.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/examples.ipynb +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/api.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/config/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/config/cli.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/commands.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/element.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/environment.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/errors.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/json_like.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/loop.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/object_list.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/parameters.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/task.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/task_schema.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/test_utils.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/validation.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/workflow.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/core/zarr_io.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/config_file_schema.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/config_schema.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/environments_spec_schema.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/files_spec_schema.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/parameters_spec_schema.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/task_schema_spec_schema.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/template_components/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/template_components/command_files.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/template_components/environments.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/template_components/parameters.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/template_components/task_schemas.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/workflow_spec_schema.yaml +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/cli.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/demo_task_1_generate_t1_infile_1.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/demo_task_1_generate_t1_infile_2.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/demo_task_1_parse_p3.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/generate_t1_file_01.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/parse_t1_file_01.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/helper/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/helper/cli.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/helper/helper.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/helper/watcher.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/persistence/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/persistence/base.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/persistence/json.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/persistence/zarr.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/scripting/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/schedulers/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/schedulers/direct.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/schedulers/sge.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/schedulers/slurm.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/shells/__init__.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/shells/base.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/shells/bash.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/shells/os_version.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/shells/powershell.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/submission.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/typing.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_action.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_app.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_cli.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_element.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_element_set.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_input_source.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_input_value.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_json_like.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_loop.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_object_list.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_resolve_elements.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_submission.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_task.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_task_objective.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_task_schema.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_utils.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/tests/unit/test_workflow.py +0 -0
- {hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/viz_demo.ipynb +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.2.0a38"
|
@@ -3,15 +3,23 @@ import logging
|
|
3
3
|
import os
|
4
4
|
import sys
|
5
5
|
|
6
|
-
_SDK_CONSOLE_LOG_LEVEL = os.environ.get("HPCFLOW_SDK_CONSOLE_LOG_LEVEL", "
|
6
|
+
_SDK_CONSOLE_LOG_LEVEL = os.environ.get("HPCFLOW_SDK_CONSOLE_LOG_LEVEL", "WARNING")
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
def get_SDK_logger(name=None):
|
10
|
+
"""Get a logger with prefix of "hpcflow_sdk" instead of "hpcflow.sdk" to ensure the
|
11
|
+
handlers of the SDK logger and app logger are distinct."""
|
12
|
+
name = ".".join(["hpcflow_sdk"] + (name or __name__).split(".")[2:])
|
13
|
+
return logging.getLogger(name)
|
14
|
+
|
15
|
+
|
16
|
+
_SDK_logger = get_SDK_logger()
|
17
|
+
_SDK_logger.setLevel("DEBUG")
|
10
18
|
|
11
19
|
_sh = logging.StreamHandler()
|
12
20
|
_sh.setFormatter(logging.Formatter("%(levelname)s %(name)s: %(message)s"))
|
13
21
|
_sh.setLevel(_SDK_CONSOLE_LOG_LEVEL)
|
14
|
-
|
22
|
+
_SDK_logger.addHandler(_sh)
|
15
23
|
|
16
24
|
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
17
25
|
import multiprocessing
|
@@ -3,7 +3,6 @@
|
|
3
3
|
from functools import wraps
|
4
4
|
from importlib import resources, import_module
|
5
5
|
from pathlib import Path
|
6
|
-
import time
|
7
6
|
from typing import Dict
|
8
7
|
import warnings
|
9
8
|
|
@@ -17,7 +16,7 @@ from hpcflow.sdk.persistence import ALL_STORE_FORMATS, DEFAULT_STORE_FORMAT
|
|
17
16
|
from hpcflow.sdk.submission.shells import ALL_SHELLS
|
18
17
|
from .core.json_like import JSONLike
|
19
18
|
from .core.utils import read_YAML, read_YAML_file
|
20
|
-
from . import api,
|
19
|
+
from . import api, get_SDK_logger
|
21
20
|
from .config import Config
|
22
21
|
from .config.cli import get_config_CLI
|
23
22
|
from .config.errors import ConfigError
|
@@ -62,7 +61,7 @@ from .helper.cli import get_helper_CLI
|
|
62
61
|
from .log import AppLog
|
63
62
|
from .runtime import RunTimeInfo
|
64
63
|
|
65
|
-
SDK_logger =
|
64
|
+
SDK_logger = get_SDK_logger(__name__)
|
66
65
|
|
67
66
|
|
68
67
|
class BaseApp:
|
@@ -139,6 +138,9 @@ class BaseApp:
|
|
139
138
|
api_method.__doc__ = func.__doc__.format(app_name=name)
|
140
139
|
setattr(self, func.__name__, api_method)
|
141
140
|
|
141
|
+
def __repr__(self):
|
142
|
+
return f"{self.__class__.__name__}(name={self.name}, version={self.version})"
|
143
|
+
|
142
144
|
@property
|
143
145
|
def template_components(self):
|
144
146
|
if not self.is_template_components_loaded:
|
@@ -339,15 +341,21 @@ class BaseApp:
|
|
339
341
|
return self._config
|
340
342
|
|
341
343
|
def _load_config(self, config_dir, config_invocation_key, **overrides):
|
342
|
-
self.logger.
|
344
|
+
self.logger.info("Loading configuration.")
|
343
345
|
self._config = Config(
|
344
346
|
app=self,
|
345
347
|
options=self.config_options,
|
346
348
|
config_dir=config_dir,
|
347
349
|
config_invocation_key=config_invocation_key,
|
348
350
|
logger=self.config_logger,
|
351
|
+
variables={"app_name": self.name, "app_version": self.version},
|
349
352
|
**overrides,
|
350
353
|
)
|
354
|
+
self.log.update_console_level(self.config.get("log_console_level"))
|
355
|
+
self.log.add_file_logger(
|
356
|
+
path=self.config.get("log_file_path"),
|
357
|
+
level=self.config.get("log_file_level"),
|
358
|
+
)
|
351
359
|
self.logger.info(f"Configuration loaded from: {self.config.config_file_path}")
|
352
360
|
|
353
361
|
def load_config(self, config_dir=None, config_invocation_key=None, **overrides):
|
@@ -1,9 +1,27 @@
|
|
1
1
|
"""Module that defines built-in callback functions for configuration item values."""
|
2
2
|
|
3
3
|
|
4
|
+
import re
|
4
5
|
import fsspec
|
5
6
|
|
6
7
|
|
8
|
+
def callback_vars(config, value):
|
9
|
+
"""Substitute configuration variables."""
|
10
|
+
|
11
|
+
def vars_repl(match_obj):
|
12
|
+
var_name = match_obj.groups()[0]
|
13
|
+
return config._variables[var_name]
|
14
|
+
|
15
|
+
vars_join = "|".join(list(config._variables.keys()))
|
16
|
+
vars_regex = f"\<\<({vars_join})\>\>"
|
17
|
+
value = re.sub(
|
18
|
+
pattern=vars_regex,
|
19
|
+
repl=vars_repl,
|
20
|
+
string=value,
|
21
|
+
)
|
22
|
+
return value
|
23
|
+
|
24
|
+
|
7
25
|
def callback_file_paths(config, file_path):
|
8
26
|
if isinstance(file_path, list):
|
9
27
|
return [config._resolve_path(i) for i in file_path]
|
@@ -9,7 +9,7 @@ import uuid
|
|
9
9
|
from dataclasses import dataclass, field
|
10
10
|
from hashlib import new
|
11
11
|
from pathlib import Path
|
12
|
-
from typing import
|
12
|
+
from typing import Dict, List, Optional, Tuple, Union
|
13
13
|
|
14
14
|
from fsspec.registry import known_implementations as fsspec_protocols
|
15
15
|
from platformdirs import user_data_dir
|
@@ -20,6 +20,7 @@ from hpcflow.sdk.log import AppLog
|
|
20
20
|
|
21
21
|
from .callbacks import (
|
22
22
|
callback_bool,
|
23
|
+
callback_vars,
|
23
24
|
callback_file_paths,
|
24
25
|
set_callback_file_paths,
|
25
26
|
check_load_data_files,
|
@@ -47,7 +48,7 @@ DEFAULT_CONFIG_FILE = {
|
|
47
48
|
"config": {
|
48
49
|
"machine": socket.gethostname(),
|
49
50
|
"telemetry": True,
|
50
|
-
"log_file_path": "logs
|
51
|
+
"log_file_path": "logs/<<app_name>>_v<<app_version>>.log",
|
51
52
|
"environment_sources": [],
|
52
53
|
"task_schema_sources": [],
|
53
54
|
"command_file_sources": [],
|
@@ -104,13 +105,14 @@ class Config:
|
|
104
105
|
logger,
|
105
106
|
uid=None,
|
106
107
|
callbacks=None,
|
108
|
+
variables=None,
|
107
109
|
**overrides,
|
108
110
|
):
|
109
|
-
|
110
111
|
self._app = app
|
111
112
|
self._options = options
|
112
113
|
self._overrides = overrides
|
113
114
|
self._logger = logger
|
115
|
+
self._variables = variables or {}
|
114
116
|
|
115
117
|
# Callbacks are run on get:
|
116
118
|
self._get_callbacks = {
|
@@ -118,7 +120,10 @@ class Config:
|
|
118
120
|
"environment_sources": (callback_file_paths,),
|
119
121
|
"parameter_sources": (callback_file_paths,),
|
120
122
|
"command_file_sources": (callback_file_paths,),
|
121
|
-
"log_file_path": (
|
123
|
+
"log_file_path": (
|
124
|
+
callback_vars,
|
125
|
+
callback_file_paths,
|
126
|
+
),
|
122
127
|
"telemetry": (callback_bool,),
|
123
128
|
**(callbacks or {}),
|
124
129
|
}
|
@@ -318,7 +323,10 @@ class Config:
|
|
318
323
|
self._logger.debug(
|
319
324
|
f"Invoking `config.get` callback ({cb.__name__!r}) for item {name!r}={value!r}"
|
320
325
|
)
|
321
|
-
|
326
|
+
try:
|
327
|
+
value = cb(self, value)
|
328
|
+
except Exception as err:
|
329
|
+
raise ConfigItemCallbackError(name, cb, err)
|
322
330
|
return value
|
323
331
|
|
324
332
|
def get(
|
@@ -361,10 +369,7 @@ class Config:
|
|
361
369
|
)
|
362
370
|
|
363
371
|
if callback:
|
364
|
-
|
365
|
-
val = self._get_callback_value(name, val)
|
366
|
-
except Exception as err:
|
367
|
-
raise ConfigItemCallbackError(name, err)
|
372
|
+
val = self._get_callback_value(name, val)
|
368
373
|
|
369
374
|
if as_str:
|
370
375
|
if isinstance(val, (list, tuple, set)):
|
@@ -382,7 +387,6 @@ class Config:
|
|
382
387
|
return value
|
383
388
|
|
384
389
|
def set(self, name, value, is_json=False, callback=True):
|
385
|
-
|
386
390
|
self._logger.debug(f"Attempting to set config item {name!r} to {value!r}.")
|
387
391
|
|
388
392
|
if name not in self._configurable_keys:
|
@@ -396,7 +400,6 @@ class Config:
|
|
396
400
|
file_val = self._get_callback_value(name, file_val_raw)
|
397
401
|
|
398
402
|
if callback_val != current_val:
|
399
|
-
|
400
403
|
was_in_modified = False
|
401
404
|
was_in_unset = False
|
402
405
|
prev_modified_val = None
|
@@ -426,7 +429,6 @@ class Config:
|
|
426
429
|
cb(self, callback_val)
|
427
430
|
|
428
431
|
except ConfigValidationError as err:
|
429
|
-
|
430
432
|
# revert:
|
431
433
|
if modified_updated:
|
432
434
|
if was_in_modified:
|
@@ -445,7 +447,6 @@ class Config:
|
|
445
447
|
print(f"value is already: {callback_val!r}")
|
446
448
|
|
447
449
|
def unset(self, name):
|
448
|
-
|
449
450
|
if name not in self._configurable_keys:
|
450
451
|
raise ConfigNonConfigurableError(name=name)
|
451
452
|
if name in self._unset_keys or not self._file.is_item_set(name):
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import copy
|
4
|
+
import fnmatch
|
4
5
|
import io
|
5
6
|
import logging
|
6
7
|
import os
|
@@ -45,7 +46,9 @@ class ConfigFile:
|
|
45
46
|
for c_name_i, c_dat_i in self.data["configs"].items():
|
46
47
|
is_match = True
|
47
48
|
for match_k, match_v in c_dat_i["invocation"]["match"].items():
|
48
|
-
|
49
|
+
# test for a matching glob pattern:
|
50
|
+
k_value = getattr(self.config._app.run_time_info, match_k)
|
51
|
+
if not fnmatch.filter(names=[k_value], pat=match_v):
|
49
52
|
is_match = False
|
50
53
|
break
|
51
54
|
if is_match:
|
@@ -180,7 +183,7 @@ class ConfigFile:
|
|
180
183
|
raise ConfigDefaultValidationError(err) from None
|
181
184
|
|
182
185
|
yaml = YAML(typ="rt")
|
183
|
-
with config_path.open("w") as handle:
|
186
|
+
with config_path.open("w", newline="\n") as handle:
|
184
187
|
yaml.dump(default_config, handle)
|
185
188
|
|
186
189
|
def _load_file_data(self):
|
@@ -39,9 +39,10 @@ class ConfigFileValidationError(ConfigError):
|
|
39
39
|
|
40
40
|
|
41
41
|
class ConfigItemCallbackError(ConfigError):
|
42
|
-
def __init__(self, name, err, message=None):
|
42
|
+
def __init__(self, name, callback, err, message=None):
|
43
43
|
self.message = message or (
|
44
|
-
f"Callback function for configuration item {name!r}
|
44
|
+
f"Callback function {callback.__name__!r} for configuration item {name!r} "
|
45
|
+
f"failed with exception: \n\n{err!r}"
|
45
46
|
)
|
46
47
|
super().__init__(self.message)
|
47
48
|
|
@@ -411,7 +411,7 @@ class ElementActionRun:
|
|
411
411
|
app_package_name=self.app.package_name,
|
412
412
|
app_name=self.app.name,
|
413
413
|
cfg_dir=self.app.config.config_directory,
|
414
|
-
cfg_invoc_key=self.app.config.
|
414
|
+
cfg_invoc_key=self.app.config.config_invocation_key,
|
415
415
|
script_main_func=script_main_func,
|
416
416
|
)
|
417
417
|
|
@@ -167,7 +167,7 @@ class InputFileGenerator(JSONLike):
|
|
167
167
|
app_package_name=self.app.package_name,
|
168
168
|
app_name=self.app.name,
|
169
169
|
cfg_dir=self.app.config.config_directory,
|
170
|
-
cfg_invoc_key=self.app.config.
|
170
|
+
cfg_invoc_key=self.app.config.config_invocation_key,
|
171
171
|
script_main_func=script_main_func,
|
172
172
|
file_path=self.input_file.name.value(),
|
173
173
|
)
|
@@ -259,7 +259,7 @@ class OutputFileParser(JSONLike):
|
|
259
259
|
app_package_name=self.app.package_name,
|
260
260
|
app_name=self.app.name,
|
261
261
|
cfg_dir=self.app.config.config_directory,
|
262
|
-
cfg_invoc_key=self.app.config.
|
262
|
+
cfg_invoc_key=self.app.config.config_invocation_key,
|
263
263
|
script_main_func=script_main_func,
|
264
264
|
param_name=f"outputs.{self.output.typ}",
|
265
265
|
)
|
@@ -10,10 +10,8 @@ import re
|
|
10
10
|
import socket
|
11
11
|
import string
|
12
12
|
from datetime import datetime, timezone
|
13
|
-
from typing import Mapping
|
13
|
+
from typing import Mapping
|
14
14
|
|
15
|
-
import zarr
|
16
|
-
import numpy.typing as npt
|
17
15
|
from ruamel.yaml import YAML
|
18
16
|
import sentry_sdk
|
19
17
|
|
@@ -116,7 +114,6 @@ def group_by_dict_key_values(lst, *keys):
|
|
116
114
|
grouped = [[lst[0]]]
|
117
115
|
for lst_item in lst[1:]:
|
118
116
|
for group_idx, group in enumerate(grouped):
|
119
|
-
|
120
117
|
try:
|
121
118
|
is_vals_equal = all(lst_item[k] == group[0][k] for k in keys)
|
122
119
|
|
@@ -162,7 +159,6 @@ def get_in_container(cont, path, cast_indices=False):
|
|
162
159
|
|
163
160
|
|
164
161
|
def set_in_container(cont, path, value, ensure_path=False):
|
165
|
-
|
166
162
|
if ensure_path:
|
167
163
|
num_path = len(path)
|
168
164
|
for idx in range(1, num_path):
|
@@ -291,7 +287,6 @@ def check_in_object_list(spec_name, spec_pos=1, obj_list_pos=2):
|
|
291
287
|
def decorator(func):
|
292
288
|
@wraps(func)
|
293
289
|
def wrap(*args, **kwargs):
|
294
|
-
|
295
290
|
spec = args[spec_pos]
|
296
291
|
obj_list = args[obj_list_pos]
|
297
292
|
if spec[spec_name] not in obj_list:
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
|
4
|
+
class AppLog:
|
5
|
+
DEFAULT_LOG_CONSOLE_LEVEL = "WARNING"
|
6
|
+
DEFAULT_LOG_FILE_LEVEL = "INFO"
|
7
|
+
|
8
|
+
def __init__(self, app, log_console_level=None):
|
9
|
+
self.app = app
|
10
|
+
self.logger = logging.getLogger(app.package_name)
|
11
|
+
self.logger.setLevel(logging.DEBUG)
|
12
|
+
self.console_handler = self._add_console_logger(
|
13
|
+
level=log_console_level or AppLog.DEFAULT_LOG_CONSOLE_LEVEL
|
14
|
+
)
|
15
|
+
|
16
|
+
def _add_console_logger(self, level, fmt=None):
|
17
|
+
fmt = fmt or "%(levelname)s %(name)s: %(message)s"
|
18
|
+
handler = logging.StreamHandler()
|
19
|
+
handler.setFormatter(logging.Formatter(fmt))
|
20
|
+
handler.setLevel(level)
|
21
|
+
self.logger.addHandler(handler)
|
22
|
+
return handler
|
23
|
+
|
24
|
+
def update_console_level(self, new_level):
|
25
|
+
if new_level:
|
26
|
+
self.console_handler.setLevel(new_level.upper())
|
27
|
+
|
28
|
+
def add_file_logger(self, path, level=None, fmt=None, max_bytes=None):
|
29
|
+
fmt = fmt or f"%(asctime)s %(levelname)s %(name)s: %(message)s"
|
30
|
+
level = level or AppLog.DEFAULT_LOG_FILE_LEVEL
|
31
|
+
max_bytes = max_bytes or int(10e6)
|
32
|
+
|
33
|
+
if not path.parent.is_dir():
|
34
|
+
self.logger.info(f"Generating log file parent directory: {path.parent!r}")
|
35
|
+
path.parent.mkdir(exist_ok=True, parents=True)
|
36
|
+
|
37
|
+
handler = logging.handlers.RotatingFileHandler(filename=path, maxBytes=max_bytes)
|
38
|
+
handler.setFormatter(logging.Formatter(fmt))
|
39
|
+
handler.setLevel(level.upper())
|
40
|
+
self.logger.addHandler(handler)
|
41
|
+
return handler
|
@@ -41,11 +41,13 @@ class RunTimeInfo(PrettyPrinter):
|
|
41
41
|
self.is_frozen = is_frozen
|
42
42
|
self.working_dir = os.getcwd()
|
43
43
|
self.logger = logger
|
44
|
-
self.
|
44
|
+
self.hostname = socket.gethostname()
|
45
45
|
|
46
46
|
path_exec = Path(sys.executable)
|
47
47
|
path_argv = Path(sys.argv[0])
|
48
48
|
|
49
|
+
self.in_ipython = False
|
50
|
+
|
49
51
|
if self.is_frozen:
|
50
52
|
self.bundle_dir = Path(bundle_dir)
|
51
53
|
self.executable_path = path_argv
|
@@ -57,6 +59,12 @@ class RunTimeInfo(PrettyPrinter):
|
|
57
59
|
self.resolved_script_path = path_argv.absolute()
|
58
60
|
self.python_executable_path = path_exec
|
59
61
|
|
62
|
+
try:
|
63
|
+
get_ipython
|
64
|
+
self.in_ipython = True
|
65
|
+
except NameError:
|
66
|
+
pass
|
67
|
+
|
60
68
|
self.python_version = platform.python_version()
|
61
69
|
self.is_venv = hasattr(sys, "real_prefix") or sys.base_prefix != sys.prefix
|
62
70
|
self.is_conda_venv = "CONDA_PREFIX" in os.environ
|
@@ -101,6 +109,7 @@ class RunTimeInfo(PrettyPrinter):
|
|
101
109
|
"is_conda_venv",
|
102
110
|
"executable_name",
|
103
111
|
"python_version",
|
112
|
+
"in_ipython",
|
104
113
|
):
|
105
114
|
sentry_sdk.set_tag(f"rti.{k}", v)
|
106
115
|
|
@@ -108,9 +117,10 @@ class RunTimeInfo(PrettyPrinter):
|
|
108
117
|
out = {
|
109
118
|
"is_frozen": self.is_frozen,
|
110
119
|
"python_version": self.python_version,
|
111
|
-
"
|
120
|
+
"hostname": self.hostname,
|
112
121
|
"working_dir": self.working_dir,
|
113
122
|
"invocation_command": self.get_invocation_command(),
|
123
|
+
"in_ipython": self.in_ipython,
|
114
124
|
}
|
115
125
|
if self.is_frozen:
|
116
126
|
out.update(
|
@@ -140,8 +150,7 @@ class RunTimeInfo(PrettyPrinter):
|
|
140
150
|
|
141
151
|
def __repr__(self):
|
142
152
|
out = f"{self.__class__.__name__}("
|
143
|
-
for k, v in self._get_members().items()
|
144
|
-
out += f"{k}={v!r}"
|
153
|
+
out += ", ".join(f"{k}={v!r}" for k, v in self._get_members().items())
|
145
154
|
return out
|
146
155
|
|
147
156
|
def _set_venv_path(self):
|
@@ -168,16 +177,8 @@ class RunTimeInfo(PrettyPrinter):
|
|
168
177
|
if self.is_frozen:
|
169
178
|
return [str(self.resolved_executable_path)]
|
170
179
|
else:
|
171
|
-
in_ipython
|
172
|
-
try:
|
173
|
-
get_ipython
|
174
|
-
in_ipython = True
|
175
|
-
except NameError:
|
176
|
-
pass
|
177
|
-
|
178
|
-
if in_ipython:
|
180
|
+
if self.in_ipython:
|
179
181
|
app_module = import_module(self.package_name)
|
180
|
-
|
181
182
|
CLI_path = Path(*app_module.__path__, "cli.py")
|
182
183
|
command = [str(self.python_executable_path), str(CLI_path)]
|
183
184
|
|
@@ -682,7 +682,7 @@ class Jobscript(JSONLike):
|
|
682
682
|
"env_setup": env_setup,
|
683
683
|
"app_invoc": app_invoc,
|
684
684
|
"config_dir": str(self.app.config.config_directory),
|
685
|
-
"config_invoc_key": self.app.config.
|
685
|
+
"config_invoc_key": self.app.config.config_invocation_key,
|
686
686
|
"workflow_path": self.workflow.path,
|
687
687
|
"sub_idx": self.submission.index,
|
688
688
|
"js_idx": self.index,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
[tool.poetry]
|
3
3
|
name = "hpcflow-new2"
|
4
|
-
version = "0.2.
|
4
|
+
version = "0.2.0a38"
|
5
5
|
|
6
6
|
description = "Computational workflow management"
|
7
7
|
authors = ["aplowman <adam.plowman@manchester.ac.uk>"]
|
@@ -57,7 +57,7 @@ hook-dirs = "hpcflow.__pyinstaller:get_hook_dirs"
|
|
57
57
|
|
58
58
|
[tool.commitizen]
|
59
59
|
name = "cz_conventional_commits"
|
60
|
-
version = "0.2.
|
60
|
+
version = "0.2.0a38"
|
61
61
|
tag_format = "v$version"
|
62
62
|
version_files = [
|
63
63
|
"pyproject.toml:version",
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "0.2.0a37"
|
@@ -1,17 +0,0 @@
|
|
1
|
-
from hpcflow.config import Config
|
2
|
-
|
3
|
-
|
4
|
-
def get_config_file_contents():
|
5
|
-
return Config.config_file_contents
|
6
|
-
|
7
|
-
|
8
|
-
def show_config_file_contents():
|
9
|
-
print(get_config_file_contents())
|
10
|
-
|
11
|
-
|
12
|
-
def show_config():
|
13
|
-
print(Config.to_string(exclude=["config_file_contents"]))
|
14
|
-
|
15
|
-
|
16
|
-
def check():
|
17
|
-
Config.check_data_files()
|
@@ -1,26 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
|
3
|
-
|
4
|
-
class AppLog:
|
5
|
-
|
6
|
-
DEFAULT_LOG_LEVEL_CONSOLE = "WARNING"
|
7
|
-
DEFAULT_LOG_LEVEL_FILE = "INFO"
|
8
|
-
DEFAULT_LOG_FILE_PATH = "app.log"
|
9
|
-
|
10
|
-
def __init__(self, app, log_console_level=None):
|
11
|
-
self.app = app
|
12
|
-
self.logger = logging.getLogger(app.package_name)
|
13
|
-
self.logger.setLevel(logging.DEBUG)
|
14
|
-
self.console_handler = self._add_console_logger(
|
15
|
-
level=log_console_level or AppLog.DEFAULT_LOG_LEVEL_CONSOLE
|
16
|
-
)
|
17
|
-
# print(f"log_console_level: {log_console_level}")
|
18
|
-
|
19
|
-
def _add_console_logger(self, level, fmt=None):
|
20
|
-
if not fmt:
|
21
|
-
fmt = "%(levelname)s %(name)s: %(message)s"
|
22
|
-
handler = logging.StreamHandler()
|
23
|
-
handler.setFormatter(logging.Formatter(fmt))
|
24
|
-
handler.setLevel(level)
|
25
|
-
self.logger.addHandler(handler)
|
26
|
-
return handler
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/environments_spec_schema.yaml
RENAMED
File without changes
|
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/parameters_spec_schema.yaml
RENAMED
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/task_schema_spec_schema.yaml
RENAMED
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/template_components/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/data/template_components/parameters.yaml
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/demo_task_1_parse_p3.py
RENAMED
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/generate_t1_file_01.py
RENAMED
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/demo/scripts/parse_t1_file_01.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{hpcflow_new2-0.2.0a37 → hpcflow_new2-0.2.0a38}/hpcflow/sdk/submission/schedulers/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|