hpcflow 0.1.9__py3-none-any.whl → 0.2.0a271__py3-none-any.whl
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/__init__.py +2 -11
- hpcflow/__pyinstaller/__init__.py +5 -0
- hpcflow/__pyinstaller/hook-hpcflow.py +40 -0
- hpcflow/_version.py +1 -1
- hpcflow/app.py +43 -0
- hpcflow/cli.py +2 -462
- hpcflow/data/demo_data_manifest/__init__.py +3 -0
- hpcflow/data/demo_data_manifest/demo_data_manifest.json +6 -0
- hpcflow/data/jinja_templates/test/test_template.txt +8 -0
- hpcflow/data/programs/hello_world/README.md +1 -0
- hpcflow/data/programs/hello_world/hello_world.c +87 -0
- hpcflow/data/programs/hello_world/linux/hello_world +0 -0
- hpcflow/data/programs/hello_world/macos/hello_world +0 -0
- hpcflow/data/programs/hello_world/win/hello_world.exe +0 -0
- hpcflow/data/scripts/__init__.py +1 -0
- hpcflow/data/scripts/bad_script.py +2 -0
- hpcflow/data/scripts/demo_task_1_generate_t1_infile_1.py +8 -0
- hpcflow/data/scripts/demo_task_1_generate_t1_infile_2.py +8 -0
- hpcflow/data/scripts/demo_task_1_parse_p3.py +7 -0
- hpcflow/data/scripts/do_nothing.py +2 -0
- hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
- hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/generate_t1_file_01.py +7 -0
- hpcflow/data/scripts/import_future_script.py +7 -0
- hpcflow/data/scripts/input_file_generator_basic.py +3 -0
- hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
- hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_all_iters_test.py +15 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_env_spec.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_labels.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_sub_param_in_direct_out.py +6 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_group.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +11 -0
- hpcflow/data/scripts/main_script_test_json_and_direct_in_json_out.py +14 -0
- hpcflow/data/scripts/main_script_test_json_in_json_and_direct_out.py +17 -0
- hpcflow/data/scripts/main_script_test_json_in_json_out.py +14 -0
- hpcflow/data/scripts/main_script_test_json_in_json_out_labels.py +16 -0
- hpcflow/data/scripts/main_script_test_json_in_obj.py +12 -0
- hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
- hpcflow/data/scripts/main_script_test_json_out_obj.py +10 -0
- hpcflow/data/scripts/main_script_test_json_sub_param_in_json_out_labels.py +16 -0
- hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
- hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
- hpcflow/data/scripts/output_file_parser_basic.py +3 -0
- hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
- hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/parse_t1_file_01.py +4 -0
- hpcflow/data/scripts/script_exit_test.py +5 -0
- hpcflow/data/template_components/__init__.py +1 -0
- hpcflow/data/template_components/command_files.yaml +26 -0
- hpcflow/data/template_components/environments.yaml +13 -0
- hpcflow/data/template_components/parameters.yaml +14 -0
- hpcflow/data/template_components/task_schemas.yaml +139 -0
- hpcflow/data/workflows/workflow_1.yaml +5 -0
- hpcflow/examples.ipynb +1037 -0
- hpcflow/sdk/__init__.py +149 -0
- hpcflow/sdk/app.py +4266 -0
- hpcflow/sdk/cli.py +1479 -0
- hpcflow/sdk/cli_common.py +385 -0
- hpcflow/sdk/config/__init__.py +5 -0
- hpcflow/sdk/config/callbacks.py +246 -0
- hpcflow/sdk/config/cli.py +388 -0
- hpcflow/sdk/config/config.py +1410 -0
- hpcflow/sdk/config/config_file.py +501 -0
- hpcflow/sdk/config/errors.py +272 -0
- hpcflow/sdk/config/types.py +150 -0
- hpcflow/sdk/core/__init__.py +38 -0
- hpcflow/sdk/core/actions.py +3857 -0
- hpcflow/sdk/core/app_aware.py +25 -0
- hpcflow/sdk/core/cache.py +224 -0
- hpcflow/sdk/core/command_files.py +814 -0
- hpcflow/sdk/core/commands.py +424 -0
- hpcflow/sdk/core/element.py +2071 -0
- hpcflow/sdk/core/enums.py +221 -0
- hpcflow/sdk/core/environment.py +256 -0
- hpcflow/sdk/core/errors.py +1043 -0
- hpcflow/sdk/core/execute.py +207 -0
- hpcflow/sdk/core/json_like.py +809 -0
- hpcflow/sdk/core/loop.py +1320 -0
- hpcflow/sdk/core/loop_cache.py +282 -0
- hpcflow/sdk/core/object_list.py +933 -0
- hpcflow/sdk/core/parameters.py +3371 -0
- hpcflow/sdk/core/rule.py +196 -0
- hpcflow/sdk/core/run_dir_files.py +57 -0
- hpcflow/sdk/core/skip_reason.py +7 -0
- hpcflow/sdk/core/task.py +3792 -0
- hpcflow/sdk/core/task_schema.py +993 -0
- hpcflow/sdk/core/test_utils.py +538 -0
- hpcflow/sdk/core/types.py +447 -0
- hpcflow/sdk/core/utils.py +1207 -0
- hpcflow/sdk/core/validation.py +87 -0
- hpcflow/sdk/core/values.py +477 -0
- hpcflow/sdk/core/workflow.py +4820 -0
- hpcflow/sdk/core/zarr_io.py +206 -0
- hpcflow/sdk/data/__init__.py +13 -0
- hpcflow/sdk/data/config_file_schema.yaml +34 -0
- hpcflow/sdk/data/config_schema.yaml +260 -0
- hpcflow/sdk/data/environments_spec_schema.yaml +21 -0
- hpcflow/sdk/data/files_spec_schema.yaml +5 -0
- hpcflow/sdk/data/parameters_spec_schema.yaml +7 -0
- hpcflow/sdk/data/task_schema_spec_schema.yaml +3 -0
- hpcflow/sdk/data/workflow_spec_schema.yaml +22 -0
- hpcflow/sdk/demo/__init__.py +3 -0
- hpcflow/sdk/demo/cli.py +242 -0
- hpcflow/sdk/helper/__init__.py +3 -0
- hpcflow/sdk/helper/cli.py +137 -0
- hpcflow/sdk/helper/helper.py +300 -0
- hpcflow/sdk/helper/watcher.py +192 -0
- hpcflow/sdk/log.py +288 -0
- hpcflow/sdk/persistence/__init__.py +18 -0
- hpcflow/sdk/persistence/base.py +2817 -0
- hpcflow/sdk/persistence/defaults.py +6 -0
- hpcflow/sdk/persistence/discovery.py +39 -0
- hpcflow/sdk/persistence/json.py +954 -0
- hpcflow/sdk/persistence/pending.py +948 -0
- hpcflow/sdk/persistence/store_resource.py +203 -0
- hpcflow/sdk/persistence/types.py +309 -0
- hpcflow/sdk/persistence/utils.py +73 -0
- hpcflow/sdk/persistence/zarr.py +2388 -0
- hpcflow/sdk/runtime.py +320 -0
- hpcflow/sdk/submission/__init__.py +3 -0
- hpcflow/sdk/submission/enums.py +70 -0
- hpcflow/sdk/submission/jobscript.py +2379 -0
- hpcflow/sdk/submission/schedulers/__init__.py +281 -0
- hpcflow/sdk/submission/schedulers/direct.py +233 -0
- hpcflow/sdk/submission/schedulers/sge.py +376 -0
- hpcflow/sdk/submission/schedulers/slurm.py +598 -0
- hpcflow/sdk/submission/schedulers/utils.py +25 -0
- hpcflow/sdk/submission/shells/__init__.py +52 -0
- hpcflow/sdk/submission/shells/base.py +229 -0
- hpcflow/sdk/submission/shells/bash.py +504 -0
- hpcflow/sdk/submission/shells/os_version.py +115 -0
- hpcflow/sdk/submission/shells/powershell.py +352 -0
- hpcflow/sdk/submission/submission.py +1402 -0
- hpcflow/sdk/submission/types.py +140 -0
- hpcflow/sdk/typing.py +194 -0
- hpcflow/sdk/utils/arrays.py +69 -0
- hpcflow/sdk/utils/deferred_file.py +55 -0
- hpcflow/sdk/utils/hashing.py +16 -0
- hpcflow/sdk/utils/patches.py +31 -0
- hpcflow/sdk/utils/strings.py +69 -0
- hpcflow/tests/api/test_api.py +32 -0
- hpcflow/tests/conftest.py +123 -0
- hpcflow/tests/data/__init__.py +0 -0
- hpcflow/tests/data/benchmark_N_elements.yaml +6 -0
- hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
- hpcflow/tests/data/multi_path_sequences.yaml +29 -0
- hpcflow/tests/data/workflow_1.json +10 -0
- hpcflow/tests/data/workflow_1.yaml +5 -0
- hpcflow/tests/data/workflow_1_slurm.yaml +8 -0
- hpcflow/tests/data/workflow_1_wsl.yaml +8 -0
- hpcflow/tests/data/workflow_test_run_abort.yaml +42 -0
- hpcflow/tests/jinja_templates/test_jinja_templates.py +161 -0
- hpcflow/tests/programs/test_programs.py +180 -0
- hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +12 -0
- hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
- hpcflow/tests/schedulers/slurm/test_slurm_submission.py +14 -0
- hpcflow/tests/scripts/test_input_file_generators.py +282 -0
- hpcflow/tests/scripts/test_main_scripts.py +1361 -0
- hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
- hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
- hpcflow/tests/shells/wsl/test_wsl_submission.py +14 -0
- hpcflow/tests/unit/test_action.py +1066 -0
- hpcflow/tests/unit/test_action_rule.py +24 -0
- hpcflow/tests/unit/test_app.py +132 -0
- hpcflow/tests/unit/test_cache.py +46 -0
- hpcflow/tests/unit/test_cli.py +172 -0
- hpcflow/tests/unit/test_command.py +377 -0
- hpcflow/tests/unit/test_config.py +195 -0
- hpcflow/tests/unit/test_config_file.py +162 -0
- hpcflow/tests/unit/test_element.py +666 -0
- hpcflow/tests/unit/test_element_iteration.py +88 -0
- hpcflow/tests/unit/test_element_set.py +158 -0
- hpcflow/tests/unit/test_group.py +115 -0
- hpcflow/tests/unit/test_input_source.py +1479 -0
- hpcflow/tests/unit/test_input_value.py +398 -0
- hpcflow/tests/unit/test_jobscript_unit.py +757 -0
- hpcflow/tests/unit/test_json_like.py +1247 -0
- hpcflow/tests/unit/test_loop.py +2674 -0
- hpcflow/tests/unit/test_meta_task.py +325 -0
- hpcflow/tests/unit/test_multi_path_sequences.py +259 -0
- hpcflow/tests/unit/test_object_list.py +116 -0
- hpcflow/tests/unit/test_parameter.py +243 -0
- hpcflow/tests/unit/test_persistence.py +664 -0
- hpcflow/tests/unit/test_resources.py +243 -0
- hpcflow/tests/unit/test_run.py +286 -0
- hpcflow/tests/unit/test_run_directories.py +29 -0
- hpcflow/tests/unit/test_runtime.py +9 -0
- hpcflow/tests/unit/test_schema_input.py +372 -0
- hpcflow/tests/unit/test_shell.py +129 -0
- hpcflow/tests/unit/test_slurm.py +39 -0
- hpcflow/tests/unit/test_submission.py +502 -0
- hpcflow/tests/unit/test_task.py +2560 -0
- hpcflow/tests/unit/test_task_schema.py +182 -0
- hpcflow/tests/unit/test_utils.py +616 -0
- hpcflow/tests/unit/test_value_sequence.py +549 -0
- hpcflow/tests/unit/test_values.py +91 -0
- hpcflow/tests/unit/test_workflow.py +827 -0
- hpcflow/tests/unit/test_workflow_template.py +186 -0
- hpcflow/tests/unit/utils/test_arrays.py +40 -0
- hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
- hpcflow/tests/unit/utils/test_hashing.py +65 -0
- hpcflow/tests/unit/utils/test_patches.py +5 -0
- hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
- hpcflow/tests/unit/utils/test_strings.py +97 -0
- hpcflow/tests/workflows/__init__.py +0 -0
- hpcflow/tests/workflows/test_directory_structure.py +31 -0
- hpcflow/tests/workflows/test_jobscript.py +355 -0
- hpcflow/tests/workflows/test_run_status.py +198 -0
- hpcflow/tests/workflows/test_skip_downstream.py +696 -0
- hpcflow/tests/workflows/test_submission.py +140 -0
- hpcflow/tests/workflows/test_workflows.py +564 -0
- hpcflow/tests/workflows/test_zip.py +18 -0
- hpcflow/viz_demo.ipynb +6794 -0
- hpcflow-0.2.0a271.dist-info/LICENSE +375 -0
- hpcflow-0.2.0a271.dist-info/METADATA +65 -0
- hpcflow-0.2.0a271.dist-info/RECORD +237 -0
- {hpcflow-0.1.9.dist-info → hpcflow-0.2.0a271.dist-info}/WHEEL +4 -5
- hpcflow-0.2.0a271.dist-info/entry_points.txt +6 -0
- hpcflow/api.py +0 -458
- hpcflow/archive/archive.py +0 -308
- hpcflow/archive/cloud/cloud.py +0 -47
- hpcflow/archive/cloud/errors.py +0 -9
- hpcflow/archive/cloud/providers/dropbox.py +0 -432
- hpcflow/archive/errors.py +0 -5
- hpcflow/base_db.py +0 -4
- hpcflow/config.py +0 -232
- hpcflow/copytree.py +0 -66
- hpcflow/data/examples/_config.yml +0 -14
- hpcflow/data/examples/damask/demo/1.run.yml +0 -4
- hpcflow/data/examples/damask/demo/2.process.yml +0 -29
- hpcflow/data/examples/damask/demo/geom.geom +0 -2052
- hpcflow/data/examples/damask/demo/load.load +0 -1
- hpcflow/data/examples/damask/demo/material.config +0 -185
- hpcflow/data/examples/damask/inputs/geom.geom +0 -2052
- hpcflow/data/examples/damask/inputs/load.load +0 -1
- hpcflow/data/examples/damask/inputs/material.config +0 -185
- hpcflow/data/examples/damask/profiles/_variable_lookup.yml +0 -21
- hpcflow/data/examples/damask/profiles/damask.yml +0 -4
- hpcflow/data/examples/damask/profiles/damask_process.yml +0 -8
- hpcflow/data/examples/damask/profiles/damask_run.yml +0 -5
- hpcflow/data/examples/damask/profiles/default.yml +0 -6
- hpcflow/data/examples/thinking.yml +0 -177
- hpcflow/errors.py +0 -2
- hpcflow/init_db.py +0 -37
- hpcflow/models.py +0 -2549
- hpcflow/nesting.py +0 -9
- hpcflow/profiles.py +0 -455
- hpcflow/project.py +0 -81
- hpcflow/scheduler.py +0 -323
- hpcflow/utils.py +0 -103
- hpcflow/validation.py +0 -167
- hpcflow/variables.py +0 -544
- hpcflow-0.1.9.dist-info/METADATA +0 -168
- hpcflow-0.1.9.dist-info/RECORD +0 -45
- hpcflow-0.1.9.dist-info/entry_points.txt +0 -8
- hpcflow-0.1.9.dist-info/top_level.txt +0 -1
- /hpcflow/{archive → data/jinja_templates}/__init__.py +0 -0
- /hpcflow/{archive/cloud → data/programs}/__init__.py +0 -0
- /hpcflow/{archive/cloud/providers → data/workflows}/__init__.py +0 -0
hpcflow/sdk/runtime.py
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Information about the Python runtime.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from importlib import import_module
|
|
7
|
+
from logging import Logger
|
|
8
|
+
import os
|
|
9
|
+
import platform
|
|
10
|
+
import re
|
|
11
|
+
import socket
|
|
12
|
+
import sys
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, ClassVar
|
|
15
|
+
|
|
16
|
+
from rich.table import Table
|
|
17
|
+
from rich.console import Console
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RunTimeInfo:
|
|
21
|
+
"""Get useful run-time information, including the executable name used to
|
|
22
|
+
invoke the CLI, in the case a PyInstaller-built executable was used.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
name:
|
|
27
|
+
Application name.
|
|
28
|
+
package_name:
|
|
29
|
+
Application package name.
|
|
30
|
+
version:
|
|
31
|
+
Application version.
|
|
32
|
+
logger:
|
|
33
|
+
Where to write logging versions.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self, name: str, package_name: str, version: str, logger: Logger
|
|
38
|
+
) -> None:
|
|
39
|
+
is_frozen: bool = getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS")
|
|
40
|
+
bundle_dir = (
|
|
41
|
+
sys._MEIPASS
|
|
42
|
+
if is_frozen and hasattr(sys, "_MEIPASS")
|
|
43
|
+
else os.path.dirname(os.path.abspath(__file__))
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
#: Application name.
|
|
47
|
+
self.name = name.split(".")[0] # if name is given as __name__ # TODO: what?
|
|
48
|
+
#: Application package name.
|
|
49
|
+
self.package_name = package_name
|
|
50
|
+
#: Application version.
|
|
51
|
+
self.version = version
|
|
52
|
+
#: Whether this is a frozen application.
|
|
53
|
+
self.is_frozen = is_frozen
|
|
54
|
+
#: Working directory.
|
|
55
|
+
self.working_dir = os.getcwd()
|
|
56
|
+
#: Where to write log messages.
|
|
57
|
+
self.logger = logger
|
|
58
|
+
#: Host that this is running on.
|
|
59
|
+
self.hostname = socket.gethostname()
|
|
60
|
+
|
|
61
|
+
#: Whether this application is inside iPython.
|
|
62
|
+
self.in_ipython = False
|
|
63
|
+
#: Whether this application is being used interactively.
|
|
64
|
+
self.is_interactive = False
|
|
65
|
+
#: Whether this application is being used in test mode.
|
|
66
|
+
self.in_pytest = False # set in `conftest.py`
|
|
67
|
+
#: Whether this application is being run from the CLI.
|
|
68
|
+
self.from_CLI = False # set in CLI
|
|
69
|
+
|
|
70
|
+
if self.is_frozen:
|
|
71
|
+
#: The bundle directory, if frozen.
|
|
72
|
+
self.bundle_dir = Path(bundle_dir)
|
|
73
|
+
else:
|
|
74
|
+
#: The path to Python itself.
|
|
75
|
+
self.python_executable_path = Path(sys.executable)
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
get_ipython # type: ignore
|
|
79
|
+
except NameError:
|
|
80
|
+
pass
|
|
81
|
+
else:
|
|
82
|
+
self.in_ipython = True
|
|
83
|
+
|
|
84
|
+
if hasattr(sys, "ps1"):
|
|
85
|
+
self.is_interactive = True
|
|
86
|
+
|
|
87
|
+
#: The Python version.
|
|
88
|
+
self.python_version = platform.python_version()
|
|
89
|
+
#: Whether the application is in a virtual environment.
|
|
90
|
+
self.is_venv = hasattr(sys, "real_prefix") or sys.base_prefix != sys.prefix
|
|
91
|
+
#: Whether the application is in a Conda virtual environment.
|
|
92
|
+
self.is_conda_venv = "CONDA_PREFIX" in os.environ
|
|
93
|
+
|
|
94
|
+
#: From `sys.prefix`. If running in a virtual environment, this will point to the
|
|
95
|
+
#: environment directory. If not running in a virtual environment, this will
|
|
96
|
+
#: point to the Python installation root.
|
|
97
|
+
self.sys_prefix = getattr(sys, "prefix", None)
|
|
98
|
+
#: From `sys.base_prefix`. This will be equal to `sys_prefix` (`sys.prefix`) if
|
|
99
|
+
#: not running within a virtual environment. However, if running within a virtual
|
|
100
|
+
#: environment, this will be the Python installation directory, and `sys_prefix`
|
|
101
|
+
#: will be equal to the virtual environment directory.
|
|
102
|
+
self.sys_base_prefix = getattr(sys, "base_prefix", None)
|
|
103
|
+
#: The old base prefix, from `sys.real_prefix`. Compatibility version of
|
|
104
|
+
#: :py:attr:`sys_base_prefix`.
|
|
105
|
+
self.sys_real_prefix = getattr(sys, "real_prefix", None)
|
|
106
|
+
#: The Conda prefix, if defined.
|
|
107
|
+
self.conda_prefix = os.environ.get("CONDA_PREFIX")
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
#: The virtual environment path.
|
|
111
|
+
self.venv_path: str | list[str] | None = self.__set_venv_path()
|
|
112
|
+
except ValueError:
|
|
113
|
+
self.venv_path = None
|
|
114
|
+
|
|
115
|
+
self.logger.debug(
|
|
116
|
+
f"is_frozen: {self.is_frozen!r}"
|
|
117
|
+
f"{f' ({self.executable_name!r})' if self.is_frozen else ''}"
|
|
118
|
+
)
|
|
119
|
+
self.logger.debug(
|
|
120
|
+
f"is_venv: {self.is_venv!r}"
|
|
121
|
+
f"{f' ({self.sys_prefix!r})' if self.is_venv else ''}"
|
|
122
|
+
)
|
|
123
|
+
self.logger.debug(
|
|
124
|
+
f"is_conda_venv: {self.is_conda_venv!r}"
|
|
125
|
+
f"{f' ({self.conda_prefix!r})' if self.is_conda_venv else ''}"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
_PLAT_LOOKUP = {"win32": "win", "darwin": "macos"}
|
|
129
|
+
#: CPU architecture, e.g. "AMD64" (on Windows), "x86-64" (Linux, or Intel Macs),
|
|
130
|
+
#: and "arm64" (Mac with Apple silicon).
|
|
131
|
+
self.CPU_arch = platform.machine()
|
|
132
|
+
# Broadly defined operating system, typically: "win", "macos", or "linux".
|
|
133
|
+
self.platform = _PLAT_LOOKUP.get(sys.platform, sys.platform)
|
|
134
|
+
|
|
135
|
+
# TODO: investigate
|
|
136
|
+
# if self.is_venv and self.is_conda_venv:
|
|
137
|
+
# msg = (
|
|
138
|
+
# "Running in a nested virtual environment (conda and non-conda). "
|
|
139
|
+
# "Environments may not be re-activate in the same order in associated, "
|
|
140
|
+
# "subsequent invocations of hpcflow."
|
|
141
|
+
# )
|
|
142
|
+
# warnings.warn(msg)
|
|
143
|
+
|
|
144
|
+
def to_dict(self) -> dict[str, Any]:
|
|
145
|
+
"""
|
|
146
|
+
Serialize this class as a dictionary.
|
|
147
|
+
"""
|
|
148
|
+
out = {
|
|
149
|
+
"name": self.name,
|
|
150
|
+
"package_name": self.package_name,
|
|
151
|
+
"version": self.version,
|
|
152
|
+
"is_frozen": self.is_frozen,
|
|
153
|
+
"working_dir": self.working_dir,
|
|
154
|
+
"logger": self.logger,
|
|
155
|
+
"hostname": self.hostname,
|
|
156
|
+
"python_version": self.python_version,
|
|
157
|
+
"invocation_command": self.invocation_command,
|
|
158
|
+
"in_ipython": self.in_ipython,
|
|
159
|
+
"in_pytest": self.in_pytest,
|
|
160
|
+
"from_CLI": self.from_CLI,
|
|
161
|
+
"CPU_arch": self.CPU_arch,
|
|
162
|
+
"platform": self.platform,
|
|
163
|
+
}
|
|
164
|
+
if self.is_frozen:
|
|
165
|
+
out.update(
|
|
166
|
+
{
|
|
167
|
+
"executable_name": self.executable_name,
|
|
168
|
+
"resolved_executable_name": self.resolved_executable_name,
|
|
169
|
+
"executable_path": self.executable_path,
|
|
170
|
+
"resolved_executable_path": self.resolved_executable_path,
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
174
|
+
out.update(
|
|
175
|
+
{
|
|
176
|
+
"is_interactive": self.is_interactive,
|
|
177
|
+
"script_path": self.script_path,
|
|
178
|
+
"resolved_script_path": self.resolved_script_path,
|
|
179
|
+
"python_executable_path": self.python_executable_path,
|
|
180
|
+
"is_venv": self.is_venv,
|
|
181
|
+
"is_conda_venv": self.is_conda_venv,
|
|
182
|
+
"sys_prefix": self.sys_prefix,
|
|
183
|
+
"sys_base_prefix": self.sys_base_prefix,
|
|
184
|
+
"sys_real_prefix": self.sys_real_prefix,
|
|
185
|
+
"conda_prefix": self.conda_prefix,
|
|
186
|
+
"venv_path": self.venv_path,
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
return out
|
|
190
|
+
|
|
191
|
+
def __repr__(self) -> str:
|
|
192
|
+
out = f"{self.__class__.__name__}("
|
|
193
|
+
out += ", ".join(f"{k}={v!r}" for k, v in self.to_dict().items())
|
|
194
|
+
return out
|
|
195
|
+
|
|
196
|
+
def __set_venv_path(self) -> str | list[str]:
|
|
197
|
+
out: list[str] = []
|
|
198
|
+
if self.sys_prefix is not None:
|
|
199
|
+
out.append(self.sys_prefix)
|
|
200
|
+
elif self.conda_prefix is not None:
|
|
201
|
+
out.append(self.conda_prefix)
|
|
202
|
+
if not out:
|
|
203
|
+
raise ValueError("Not running in a virtual environment!")
|
|
204
|
+
if len(out) == 1:
|
|
205
|
+
return out[0]
|
|
206
|
+
else:
|
|
207
|
+
return out
|
|
208
|
+
|
|
209
|
+
def get_activate_env_command(self):
|
|
210
|
+
"""
|
|
211
|
+
Get the command to activate the virtual environment.
|
|
212
|
+
"""
|
|
213
|
+
pass
|
|
214
|
+
|
|
215
|
+
def get_deactivate_env_command(self):
|
|
216
|
+
"""
|
|
217
|
+
Get the command to deactivate the virtual environment.
|
|
218
|
+
"""
|
|
219
|
+
pass
|
|
220
|
+
|
|
221
|
+
def show(self) -> None:
|
|
222
|
+
"""
|
|
223
|
+
Display the information known by this class as a human-readable table.
|
|
224
|
+
"""
|
|
225
|
+
tab = Table(show_header=False, box=None)
|
|
226
|
+
tab.add_column()
|
|
227
|
+
tab.add_column()
|
|
228
|
+
for k, v in self.to_dict().items():
|
|
229
|
+
tab.add_row(k, str(v))
|
|
230
|
+
|
|
231
|
+
console = Console()
|
|
232
|
+
console.print(tab)
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def executable_path(self) -> Path | None:
|
|
236
|
+
"""Get the path that the user invoked to launch the frozen app, if the app is
|
|
237
|
+
frozen.
|
|
238
|
+
|
|
239
|
+
If the user launches the app via a symbolic link, then this returns that link,
|
|
240
|
+
whereas `executable_path_resolved` returns the actual frozen app path.
|
|
241
|
+
|
|
242
|
+
"""
|
|
243
|
+
return Path(sys.argv[0]) if self.is_frozen else None
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def resolved_executable_path(self) -> Path | None:
|
|
247
|
+
"""Get the resolved path to the frozen app that the user launched, if the app is
|
|
248
|
+
frozen.
|
|
249
|
+
|
|
250
|
+
In a one-file app, this is the path to the bootloader. In the one-folder app, this
|
|
251
|
+
is the path to the executable.
|
|
252
|
+
|
|
253
|
+
References
|
|
254
|
+
----------
|
|
255
|
+
[1] https://pyinstaller.org/en/stable/runtime-information.html#using-sys-executable-and-sys-argv-0
|
|
256
|
+
|
|
257
|
+
"""
|
|
258
|
+
return Path(sys.executable) if self.is_frozen else None
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def executable_name(self) -> str | None:
|
|
262
|
+
"""Get the name of the frozen app executable, if the app is frozen.
|
|
263
|
+
|
|
264
|
+
If the user launches the app via a symbolic link, then this returns the name of
|
|
265
|
+
that link, whereas `resolved_executable_name` returns the actual frozen app file
|
|
266
|
+
name.
|
|
267
|
+
|
|
268
|
+
"""
|
|
269
|
+
return None if (p := self.executable_path) is None else p.name
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def resolved_executable_name(self) -> str | None:
|
|
273
|
+
"""Get the resolved name of the frozen app executable, if the app is frozen."""
|
|
274
|
+
return None if (p := self.resolved_executable_path) is None else p.name
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def script_path(self) -> Path | None:
|
|
278
|
+
"""Get the path to the Python script used to invoked this instance of the app, if
|
|
279
|
+
the app is not frozen."""
|
|
280
|
+
return None if self.is_frozen else Path(sys.argv[0])
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
def resolved_script_path(self) -> Path | None:
|
|
284
|
+
"""Get the resolved path to the Python script used to invoked this instance of the
|
|
285
|
+
app, if the app is not frozen."""
|
|
286
|
+
return None if (p := self.script_path) is None else p.resolve()
|
|
287
|
+
|
|
288
|
+
# For removing a trailing '.cmd' from a filename
|
|
289
|
+
__CMD_TRIM: ClassVar[re.Pattern[str]] = re.compile(r"\.cmd$")
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def invocation_command(self) -> tuple[str, ...]:
|
|
293
|
+
"""Get the command that was used to invoke this instance of the app."""
|
|
294
|
+
if self.is_frozen:
|
|
295
|
+
# (this also works if we are running tests using the frozen app)
|
|
296
|
+
return (str(self.resolved_executable_path),)
|
|
297
|
+
elif self.from_CLI:
|
|
298
|
+
script = str(self.resolved_script_path)
|
|
299
|
+
if os.name == "nt":
|
|
300
|
+
# cannot reproduce locally, but on Windows GHA runners, if pytest is
|
|
301
|
+
# invoked via `hpcflow test`, `resolved_script_path` seems to be the
|
|
302
|
+
# batch script wrapper (ending in .cmd) rather than the Python entry point
|
|
303
|
+
# itself, so trim if off:
|
|
304
|
+
script = self.__CMD_TRIM.sub("", script) # Work with 3.8 too
|
|
305
|
+
# script = script.removesuffix(".cmd")
|
|
306
|
+
if not Path(script).is_file():
|
|
307
|
+
# conda generates an `.exe` file
|
|
308
|
+
script = f"{script}.exe"
|
|
309
|
+
if not Path(script).is_file():
|
|
310
|
+
raise RuntimeError("Cannot locate invocation script.")
|
|
311
|
+
return (str(self.python_executable_path), script)
|
|
312
|
+
else:
|
|
313
|
+
app_module = import_module(self.package_name)
|
|
314
|
+
CLI_path = Path(*app_module.__path__, "cli.py")
|
|
315
|
+
return (str(self.python_executable_path), str(CLI_path))
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def is_apple_silicon(self) -> bool:
|
|
319
|
+
"""Return True if running on Apple silicon."""
|
|
320
|
+
return self.platform == "macos" and self.CPU_arch == "arm64"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Submission enumeration types.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
from hpcflow.sdk.core.enums import _ReportableStateData, _ReportableStateEnum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class JobscriptElementState(_ReportableStateEnum):
|
|
13
|
+
"""Enumeration to convey a particular jobscript element state as reported by the
|
|
14
|
+
scheduler."""
|
|
15
|
+
|
|
16
|
+
#: Waiting for resource allocation.
|
|
17
|
+
pending = _ReportableStateData(
|
|
18
|
+
0,
|
|
19
|
+
"○",
|
|
20
|
+
"yellow",
|
|
21
|
+
"Waiting for resource allocation.",
|
|
22
|
+
)
|
|
23
|
+
#: Waiting for one or more dependencies to finish.
|
|
24
|
+
waiting = _ReportableStateData(
|
|
25
|
+
1,
|
|
26
|
+
"◊",
|
|
27
|
+
"grey46",
|
|
28
|
+
"Waiting for one or more dependencies to finish.",
|
|
29
|
+
)
|
|
30
|
+
#: Executing now.
|
|
31
|
+
running = _ReportableStateData(
|
|
32
|
+
2,
|
|
33
|
+
"●",
|
|
34
|
+
"dodger_blue1",
|
|
35
|
+
"Executing now.",
|
|
36
|
+
)
|
|
37
|
+
#: Previously submitted but is no longer active.
|
|
38
|
+
finished = _ReportableStateData(
|
|
39
|
+
3,
|
|
40
|
+
"■",
|
|
41
|
+
"grey46",
|
|
42
|
+
"Previously submitted but is no longer active.",
|
|
43
|
+
)
|
|
44
|
+
#: Cancelled by the user.
|
|
45
|
+
cancelled = _ReportableStateData(
|
|
46
|
+
4,
|
|
47
|
+
"C",
|
|
48
|
+
"red3",
|
|
49
|
+
"Cancelled by the user.",
|
|
50
|
+
)
|
|
51
|
+
#: The scheduler reports an error state.
|
|
52
|
+
errored = _ReportableStateData(
|
|
53
|
+
5,
|
|
54
|
+
"E",
|
|
55
|
+
"red3",
|
|
56
|
+
"The scheduler reports an error state.",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class SubmissionStatus(Enum):
|
|
61
|
+
"""
|
|
62
|
+
The overall status of a submission.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
#: Not yet submitted.
|
|
66
|
+
PENDING = 0
|
|
67
|
+
#: All jobscripts submitted successfully.
|
|
68
|
+
SUBMITTED = 1
|
|
69
|
+
#: Some jobscripts submitted successfully.
|
|
70
|
+
PARTIALLY_SUBMITTED = 2
|