runem 0.0.17__py3-none-any.whl → 0.0.18__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.
- runem/command_line.py +3 -3
- runem/config_parse.py +2 -2
- runem/{job_runner.py → job_execute.py} +12 -6
- runem/job_filter.py +7 -3
- runem/{job_function_python.py → job_wrapper_python.py} +22 -7
- runem/log.py +8 -5
- runem/report.py +35 -9
- runem/runem.py +50 -14
- runem/types.py +3 -2
- {runem-0.0.17.dist-info → runem-0.0.18.dist-info}/METADATA +2 -1
- runem-0.0.18.dist-info/RECORD +25 -0
- runem-0.0.17.dist-info/RECORD +0 -25
- {runem-0.0.17.dist-info → runem-0.0.18.dist-info}/LICENSE +0 -0
- {runem-0.0.17.dist-info → runem-0.0.18.dist-info}/WHEEL +0 -0
- {runem-0.0.17.dist-info → runem-0.0.18.dist-info}/entry_points.txt +0 -0
- {runem-0.0.17.dist-info → runem-0.0.18.dist-info}/top_level.txt +0 -0
runem/command_line.py
CHANGED
@@ -147,7 +147,7 @@ def parse_args(
|
|
147
147
|
|
148
148
|
args = parser.parse_args(argv[1:])
|
149
149
|
|
150
|
-
options: Options =
|
150
|
+
options: Options = initialise_options(config_metadata, args)
|
151
151
|
|
152
152
|
if not _validate_filters(config_metadata, args):
|
153
153
|
sys.exit(1)
|
@@ -214,7 +214,7 @@ def _validate_filters(
|
|
214
214
|
return True
|
215
215
|
|
216
216
|
|
217
|
-
def
|
217
|
+
def initialise_options(
|
218
218
|
config_metadata: ConfigMetadata,
|
219
219
|
args: argparse.Namespace,
|
220
220
|
) -> Options:
|
@@ -227,7 +227,7 @@ def _initialise_options(
|
|
227
227
|
option["name"]: option["default"] for option in config_metadata.options_config
|
228
228
|
}
|
229
229
|
if config_metadata.options_config and args.overrides_on: # pragma: no branch
|
230
|
-
for option_name in args.overrides_on:
|
230
|
+
for option_name in args.overrides_on: # pragma: no branch
|
231
231
|
options[option_name] = True
|
232
232
|
if config_metadata.options_config and args.overrides_off: # pragma: no branch
|
233
233
|
for option_name in args.overrides_off:
|
runem/config_parse.py
CHANGED
@@ -4,7 +4,7 @@ import typing
|
|
4
4
|
from collections import defaultdict
|
5
5
|
|
6
6
|
from runem.config_metadata import ConfigMetadata
|
7
|
-
from runem.
|
7
|
+
from runem.job_wrapper_python import get_job_wrapper
|
8
8
|
from runem.log import log
|
9
9
|
from runem.types import (
|
10
10
|
Config,
|
@@ -79,7 +79,7 @@ def parse_job_config(
|
|
79
79
|
sys.exit(1)
|
80
80
|
|
81
81
|
# try and load the function _before_ we schedule it's execution
|
82
|
-
|
82
|
+
get_job_wrapper(job, cfg_filepath)
|
83
83
|
phase_id: PhaseName = job["when"]["phase"]
|
84
84
|
in_out_jobs_by_phase[phase_id].append(job)
|
85
85
|
|
@@ -2,16 +2,17 @@ import inspect
|
|
2
2
|
import os
|
3
3
|
import pathlib
|
4
4
|
import typing
|
5
|
+
import uuid
|
5
6
|
from datetime import timedelta
|
6
7
|
from timeit import default_timer as timer
|
7
8
|
|
8
9
|
from runem.config_metadata import ConfigMetadata
|
9
|
-
from runem.
|
10
|
+
from runem.job_wrapper_python import get_job_wrapper
|
10
11
|
from runem.log import log
|
11
12
|
from runem.types import FilePathList, FilePathListLookup, JobConfig, JobReturn, JobTags
|
12
13
|
|
13
14
|
|
14
|
-
def
|
15
|
+
def job_execute_inner(
|
15
16
|
job_config: JobConfig,
|
16
17
|
config_metadata: ConfigMetadata,
|
17
18
|
file_lists: FilePathListLookup,
|
@@ -27,7 +28,7 @@ def job_runner_inner(
|
|
27
28
|
function: typing.Callable
|
28
29
|
job_tags: JobTags = set(job_config["when"]["tags"])
|
29
30
|
os.chdir(root_path)
|
30
|
-
function =
|
31
|
+
function = get_job_wrapper(job_config, config_metadata.cfg_filepath)
|
31
32
|
|
32
33
|
# get the files for all files found for this job's tags
|
33
34
|
file_list: FilePathList = []
|
@@ -74,13 +75,18 @@ def job_runner_inner(
|
|
74
75
|
return (timing_data, reports)
|
75
76
|
|
76
77
|
|
77
|
-
def
|
78
|
+
def job_execute(
|
78
79
|
job_config: JobConfig,
|
80
|
+
running_jobs: typing.Dict[str, str],
|
79
81
|
config_metadata: ConfigMetadata,
|
80
82
|
file_lists: FilePathListLookup,
|
81
83
|
) -> typing.Tuple[typing.Tuple[str, timedelta], JobReturn]:
|
82
|
-
"""
|
84
|
+
"""Thin-wrapper around job_execute_inner needed for mocking in tests.
|
83
85
|
|
84
86
|
Needed for faster tests.
|
85
87
|
"""
|
86
|
-
|
88
|
+
this_id: str = str(uuid.uuid4())
|
89
|
+
running_jobs[this_id] = job_config["label"]
|
90
|
+
results = job_execute_inner(job_config, config_metadata, file_lists)
|
91
|
+
del running_jobs[this_id]
|
92
|
+
return results
|
runem/job_filter.py
CHANGED
@@ -77,10 +77,14 @@ def filter_jobs(
|
|
77
77
|
log(f"filtering for tags {printable_set(tags_to_run)}", decorate=True, end="")
|
78
78
|
if tags_to_avoid:
|
79
79
|
if tags_to_run:
|
80
|
-
log(", ", end="")
|
80
|
+
log(", ", decorate=False, end="")
|
81
81
|
else:
|
82
|
-
log(decorate=True)
|
83
|
-
log(
|
82
|
+
log(decorate=True, end="")
|
83
|
+
log(
|
84
|
+
f"excluding jobs with tags {printable_set(tags_to_avoid)}",
|
85
|
+
decorate=False,
|
86
|
+
end="",
|
87
|
+
)
|
84
88
|
if tags_to_run or tags_to_avoid:
|
85
89
|
log(decorate=False)
|
86
90
|
filtered_jobs: PhaseGroupedJobs = defaultdict(list)
|
@@ -20,20 +20,35 @@ def _load_python_function_from_module(
|
|
20
20
|
).absolute()
|
21
21
|
|
22
22
|
# load the function
|
23
|
-
|
24
|
-
|
23
|
+
try:
|
24
|
+
module_spec = module_spec_from_file_location(
|
25
|
+
function_to_load, abs_module_file_path
|
26
|
+
)
|
27
|
+
if not module_spec:
|
28
|
+
raise FileNotFoundError()
|
29
|
+
if not module_spec.loader:
|
30
|
+
raise FunctionNotFound("unable to load module")
|
31
|
+
except FileNotFoundError as err:
|
25
32
|
raise FunctionNotFound(
|
26
33
|
(
|
27
34
|
f"unable to load '{function_to_load}' from '{str(module_file_path)} "
|
28
35
|
f"relative to '{str(cfg_filepath)}"
|
29
36
|
)
|
30
|
-
)
|
37
|
+
) from err
|
31
38
|
|
32
39
|
module = module_from_spec(module_spec)
|
33
|
-
|
34
|
-
if not module_spec.loader:
|
40
|
+
if not module:
|
35
41
|
raise FunctionNotFound("unable to load module")
|
36
|
-
|
42
|
+
sys.modules[module_name] = module
|
43
|
+
try:
|
44
|
+
module_spec.loader.exec_module(module)
|
45
|
+
except FileNotFoundError as err:
|
46
|
+
raise FunctionNotFound(
|
47
|
+
(
|
48
|
+
f"unable to load '{function_to_load}' from '{str(module_file_path)} "
|
49
|
+
f"relative to '{str(cfg_filepath)}"
|
50
|
+
)
|
51
|
+
) from err
|
37
52
|
try:
|
38
53
|
function: JobFunction = getattr(module, function_to_load)
|
39
54
|
except AttributeError as err:
|
@@ -70,7 +85,7 @@ def _find_job_module(cfg_filepath: pathlib.Path, module_file_path: str) -> pathl
|
|
70
85
|
return module_path.relative_to(cfg_filepath.parent.absolute())
|
71
86
|
|
72
87
|
|
73
|
-
def
|
88
|
+
def get_job_wrapper(job_config: JobConfig, cfg_filepath: pathlib.Path) -> JobFunction:
|
74
89
|
"""Given a job-description dynamically loads the job-function so we can call it.
|
75
90
|
|
76
91
|
Side-effects: also re-addressed the job-config.
|
runem/log.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
import typing
|
1
2
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
|
4
|
+
def log(msg: str = "", decorate: bool = True, end: typing.Optional[str] = None) -> None:
|
5
|
+
"""Thin wrapper around 'print', so we can change the output.
|
6
|
+
|
7
|
+
One way we change it is to decorate the output with 'runem'
|
8
|
+
"""
|
6
9
|
if decorate:
|
7
10
|
msg = f"runem: {msg}"
|
8
|
-
print(msg, end=end)
|
11
|
+
print(msg, end=end)
|
runem/report.py
CHANGED
@@ -26,7 +26,10 @@ def _plot_times(
|
|
26
26
|
phase_run_oder: OrderedPhases,
|
27
27
|
timing_data: JobRunTimesByPhase,
|
28
28
|
) -> timedelta:
|
29
|
-
"""Prints a report to terminal on how well we performed.
|
29
|
+
"""Prints a report to terminal on how well we performed.
|
30
|
+
|
31
|
+
Also calculates the wall-clock time-saved for the user.
|
32
|
+
"""
|
30
33
|
labels: typing.List[str] = []
|
31
34
|
times: typing.List[float] = []
|
32
35
|
job_time_sum: timedelta = timedelta() # init to 0
|
@@ -66,12 +69,31 @@ def _plot_times(
|
|
66
69
|
return time_saved
|
67
70
|
|
68
71
|
|
72
|
+
def _print_reports_by_phase(
|
73
|
+
phase_run_oder: OrderedPhases, report_data: JobRunReportByPhase
|
74
|
+
) -> None:
|
75
|
+
"""Logs out the reports by grouped by phase."""
|
76
|
+
for phase in phase_run_oder:
|
77
|
+
report_urls: ReportUrls = report_data[phase]
|
78
|
+
job_report_url_info: ReportUrlInfo
|
79
|
+
for job_report_url_info in report_urls:
|
80
|
+
if not job_report_url_info:
|
81
|
+
continue
|
82
|
+
log(f"report: {str(job_report_url_info[0])}: {str(job_report_url_info[1])}")
|
83
|
+
|
84
|
+
|
69
85
|
def report_on_run(
|
70
86
|
phase_run_oder: OrderedPhases,
|
71
87
|
job_run_metadatas: JobRunMetadatasByPhase,
|
72
88
|
overall_runtime: timedelta,
|
73
|
-
):
|
89
|
+
) -> timedelta:
|
90
|
+
"""Generate high-level reports AND prints out any reports returned by jobs.
|
91
|
+
|
92
|
+
IMPORTANT: returns the wall-clock time saved to the user.
|
93
|
+
"""
|
74
94
|
log("reports:")
|
95
|
+
|
96
|
+
# First, collate all data, timing and reports
|
75
97
|
timing_data: JobRunTimesByPhase = defaultdict(list)
|
76
98
|
report_data: JobRunReportByPhase = defaultdict(list)
|
77
99
|
phase: PhaseName
|
@@ -81,17 +103,21 @@ def report_on_run(
|
|
81
103
|
for timing, reports in job_run_metadatas[phase]:
|
82
104
|
timing_data[phase].append(timing)
|
83
105
|
if reports:
|
106
|
+
# the job returned some report urls, record them against the
|
107
|
+
# job's phase
|
84
108
|
report_data[phase].extend(reports["reportUrls"])
|
109
|
+
|
110
|
+
# Now plot the times on the terminal to give a visual report of the timing.
|
111
|
+
# Also, calculate the time saved by runem, a key selling-point metric
|
85
112
|
time_saved: timedelta = _plot_times(
|
86
113
|
overall_run_time=overall_runtime,
|
87
114
|
phase_run_oder=phase_run_oder,
|
88
115
|
timing_data=timing_data,
|
89
116
|
)
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
log(f"report: {str(job_report_url_info[0])}: {str(job_report_url_info[1])}")
|
117
|
+
|
118
|
+
# Penultimate-ly print out the available reports grouped by run-phase.
|
119
|
+
_print_reports_by_phase(phase_run_oder, report_data)
|
120
|
+
|
121
|
+
# Return the key metric for runem, the wall-clock time saved to the user
|
122
|
+
# TODO: write this to disk
|
97
123
|
return time_saved
|
runem/runem.py
CHANGED
@@ -23,19 +23,23 @@ import multiprocessing
|
|
23
23
|
import os
|
24
24
|
import pathlib
|
25
25
|
import sys
|
26
|
+
import time
|
26
27
|
import typing
|
27
28
|
from collections import defaultdict
|
28
29
|
from datetime import timedelta
|
29
30
|
from itertools import repeat
|
31
|
+
from multiprocessing.managers import DictProxy, ValueProxy
|
30
32
|
from timeit import default_timer as timer
|
31
33
|
|
34
|
+
from halo import Halo
|
35
|
+
|
32
36
|
from runem.command_line import parse_args
|
33
37
|
from runem.config import load_config
|
34
38
|
from runem.config_metadata import ConfigMetadata
|
35
39
|
from runem.config_parse import parse_config
|
36
40
|
from runem.files import find_files
|
41
|
+
from runem.job_execute import job_execute
|
37
42
|
from runem.job_filter import filter_jobs
|
38
|
-
from runem.job_runner import job_runner
|
39
43
|
from runem.log import log
|
40
44
|
from runem.report import report_on_run
|
41
45
|
from runem.types import (
|
@@ -75,6 +79,22 @@ def _determine_run_parameters(argv: typing.List[str]) -> ConfigMetadata:
|
|
75
79
|
return config_metadata
|
76
80
|
|
77
81
|
|
82
|
+
def _progress_updater(
|
83
|
+
label: str, running_jobs: typing.Dict[str, str], is_running: ValueProxy
|
84
|
+
) -> None:
|
85
|
+
spinner = Halo(text="", spinner="dots")
|
86
|
+
spinner.start()
|
87
|
+
|
88
|
+
while is_running.value:
|
89
|
+
running_job_names: typing.List[str] = [
|
90
|
+
f"'{job}'" for job in sorted(list(running_jobs.values()))
|
91
|
+
]
|
92
|
+
printable_jobs: str = ", ".join(running_job_names)
|
93
|
+
spinner.text = f"{label}: {printable_jobs}"
|
94
|
+
time.sleep(0.1)
|
95
|
+
spinner.stop()
|
96
|
+
|
97
|
+
|
78
98
|
def _process_jobs(
|
79
99
|
config_metadata: ConfigMetadata,
|
80
100
|
file_lists: FilePathListLookup,
|
@@ -91,28 +111,44 @@ def _process_jobs(
|
|
91
111
|
it and, for instance, run the longest-running job first with quicker
|
92
112
|
jobs completing around it, then we would work out that schedule here.
|
93
113
|
"""
|
94
|
-
|
114
|
+
num_concurrent_procs: int = (
|
95
115
|
config_metadata.args.procs
|
96
116
|
if config_metadata.args.procs != -1
|
97
117
|
else multiprocessing.cpu_count()
|
98
118
|
)
|
99
|
-
num_concurrent_procs
|
119
|
+
num_concurrent_procs = min(num_concurrent_procs, len(jobs))
|
100
120
|
log(
|
101
121
|
(
|
102
|
-
f"Running '{phase}' with {num_concurrent_procs} workers
|
103
|
-
f"
|
122
|
+
f"Running '{phase}' with {num_concurrent_procs} workers "
|
123
|
+
f"processing {len(jobs)} jobs"
|
104
124
|
)
|
105
125
|
)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
repeat(file_lists),
|
114
|
-
),
|
126
|
+
|
127
|
+
with multiprocessing.Manager() as manager:
|
128
|
+
running_jobs: DictProxy[typing.Any, typing.Any] = manager.dict()
|
129
|
+
is_running: ValueProxy = manager.Value("b", True)
|
130
|
+
|
131
|
+
terminal_writer_process = multiprocessing.Process(
|
132
|
+
target=_progress_updater, args=(phase, running_jobs, is_running)
|
115
133
|
)
|
134
|
+
terminal_writer_process.start()
|
135
|
+
|
136
|
+
try:
|
137
|
+
with multiprocessing.Pool(processes=num_concurrent_procs) as pool:
|
138
|
+
# use starmap so we can pass down the job-configs and the args and the files
|
139
|
+
in_out_job_run_metadatas[phase] = pool.starmap(
|
140
|
+
job_execute,
|
141
|
+
zip(
|
142
|
+
jobs,
|
143
|
+
repeat(running_jobs),
|
144
|
+
repeat(config_metadata),
|
145
|
+
repeat(file_lists),
|
146
|
+
),
|
147
|
+
)
|
148
|
+
finally:
|
149
|
+
# Signal the terminal_writer process to exit
|
150
|
+
is_running.value = False
|
151
|
+
terminal_writer_process.join()
|
116
152
|
|
117
153
|
|
118
154
|
def _process_jobs_by_phase(
|
runem/types.py
CHANGED
@@ -18,8 +18,9 @@ JobPhases = typing.Set[str]
|
|
18
18
|
JobTags = typing.Set[JobTag]
|
19
19
|
PhaseName = str
|
20
20
|
OrderedPhases = typing.Tuple[PhaseName, ...]
|
21
|
-
|
22
|
-
|
21
|
+
ReportName = str
|
22
|
+
ReportUrl = typing.Union[str, pathlib.Path]
|
23
|
+
ReportUrlInfo = typing.Tuple[ReportName, ReportUrl]
|
23
24
|
ReportUrls = typing.List[ReportUrlInfo]
|
24
25
|
|
25
26
|
|
@@ -1,11 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: runem
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.18
|
4
4
|
Summary: Awesome runem created by lursight
|
5
5
|
Home-page: https://github.com/lursight/runem/
|
6
6
|
Author: lursight
|
7
7
|
Description-Content-Type: text/markdown
|
8
8
|
License-File: LICENSE
|
9
|
+
Requires-Dist: halo
|
9
10
|
Requires-Dist: PyYAML
|
10
11
|
Provides-Extra: test
|
11
12
|
Requires-Dist: black ==23.11.0 ; extra == 'test'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
runem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
runem/__main__.py,sha256=dsOiVZegpfK9JOs5n7UmbX5iwwbj7iFkEbLoVeEgAn4,136
|
3
|
+
runem/base.py,sha256=EZfR7FIlwEdU9Vfe47Wk2DOO8GQqpKxxLNKp6YHueZ4,316
|
4
|
+
runem/cli.py,sha256=Hz9j6Iy1SWjW2uZlQZp0eX48NDWD1-QhIqlBzr_qz0s,125
|
5
|
+
runem/command_line.py,sha256=lb1tvYOEVYpB_bUTRL8KxjLFuV4vKn8btFKm-28GMu0,9464
|
6
|
+
runem/config.py,sha256=h0r2WYUlAgdokUS1VU1sjFHgrN_cEq339ph4Kn1IBBM,1937
|
7
|
+
runem/config_metadata.py,sha256=EjCEqx9-2mtMrFf3lJJ8HFhfmScioZKeY_c9Rzajne8,2836
|
8
|
+
runem/config_parse.py,sha256=gso5Lziw8yII5jGSx8fR-IAs7nxUzhzitnRAEXsg5f8,5157
|
9
|
+
runem/files.py,sha256=vAI17m-Y1tRGot6_vDpTuBTkKm8xdByGoh7HCfNkMFU,1900
|
10
|
+
runem/job_execute.py,sha256=x-IGTG5KYnTJtCYm4jP8_WOQ_UM_BAiG5b3UUKp527A,3042
|
11
|
+
runem/job_filter.py,sha256=nltSRK1IKp2fuTCHOZFcii0FBL-R3RKvrnyWXTPjoMw,3478
|
12
|
+
runem/job_wrapper_python.py,sha256=TG9bzDe1dgTnsrXrCPd6LzN8qbMkH4rEv_vXC_zlJc0,4226
|
13
|
+
runem/log.py,sha256=m1lI4V8ygM53pY4Go4eEzvEJY8srVoItxUNhdp_Vrqg,314
|
14
|
+
runem/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
+
runem/report.py,sha256=AyD2yT_8ODo5QRuFkVFIecp6ycT4XElJbleWviZbCfI,4032
|
16
|
+
runem/run_command.py,sha256=6QxH8pb4Lug-d0MCP2lBKq2TJlQloxRlq0hYJM6IScc,4528
|
17
|
+
runem/runem.py,sha256=Q5ryZtArAGuTlHF07aobJkRIzurKIUsMSUPzEksL6LY,8227
|
18
|
+
runem/types.py,sha256=Hw7G7ut7yNaoc3XiDNKeM-cAU-DDu3fDOne13FrutS0,5374
|
19
|
+
runem/utils.py,sha256=3N_kel9LsriiMq7kOjT14XhfxUOgz4hdDg97wlLKm3U,221
|
20
|
+
runem-0.0.18.dist-info/LICENSE,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
21
|
+
runem-0.0.18.dist-info/METADATA,sha256=VzkG4gPaopCtwCnEx1XRGLk9iNWpLPjl4x8BY-JvSSA,15909
|
22
|
+
runem-0.0.18.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
23
|
+
runem-0.0.18.dist-info/entry_points.txt,sha256=nu0g_vBeuPihYtimbtlNusxWovylMppvJ8UxdJlJfvM,46
|
24
|
+
runem-0.0.18.dist-info/top_level.txt,sha256=gK6iqh9OfHDDpErioCC9ul_zx2Q5zWTALtcuGU7Vil4,6
|
25
|
+
runem-0.0.18.dist-info/RECORD,,
|
runem-0.0.17.dist-info/RECORD
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
runem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
runem/__main__.py,sha256=dsOiVZegpfK9JOs5n7UmbX5iwwbj7iFkEbLoVeEgAn4,136
|
3
|
-
runem/base.py,sha256=EZfR7FIlwEdU9Vfe47Wk2DOO8GQqpKxxLNKp6YHueZ4,316
|
4
|
-
runem/cli.py,sha256=Hz9j6Iy1SWjW2uZlQZp0eX48NDWD1-QhIqlBzr_qz0s,125
|
5
|
-
runem/command_line.py,sha256=4h5YL_eyDKH472BxMeQi9ONjxlGKpe4rI7Ny09kY2Y0,9445
|
6
|
-
runem/config.py,sha256=h0r2WYUlAgdokUS1VU1sjFHgrN_cEq339ph4Kn1IBBM,1937
|
7
|
-
runem/config_metadata.py,sha256=EjCEqx9-2mtMrFf3lJJ8HFhfmScioZKeY_c9Rzajne8,2836
|
8
|
-
runem/config_parse.py,sha256=s7Ty7i-KwktFg2LdLWoJaxRXnWCCT19hVGYbwgwBLp8,5160
|
9
|
-
runem/files.py,sha256=vAI17m-Y1tRGot6_vDpTuBTkKm8xdByGoh7HCfNkMFU,1900
|
10
|
-
runem/job_filter.py,sha256=90gY-p29vEb17v8R1CCgBkfQs4oDRTgvBdT9YZBiWSA,3391
|
11
|
-
runem/job_function_python.py,sha256=iNRKQp0Rlkh1VektOxUSa_KqrrY0yB7jDChcRt-s6oQ,3754
|
12
|
-
runem/job_runner.py,sha256=FUnNinHXQJAT-0OCD4rWJ81rwqsPwGAzuejvr3bHIL0,2852
|
13
|
-
runem/log.py,sha256=tzpOW5UOwq6u56v56U4tR1_00FMZIiRYHNg11pG-vv8,275
|
14
|
-
runem/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
-
runem/report.py,sha256=d3wPg_fqefaMTW1EQTU74zo4-qtPiF-MfWPKH3Mokbg,3085
|
16
|
-
runem/run_command.py,sha256=6QxH8pb4Lug-d0MCP2lBKq2TJlQloxRlq0hYJM6IScc,4528
|
17
|
-
runem/runem.py,sha256=_Xr4tITqpgYAI_Ty2ZrWFtq0_5328840NSxHTTUOiYI,7031
|
18
|
-
runem/types.py,sha256=IxUDGHOQZUc86OPjDHDKwrcBFr78v-MNvTpPwUzWoaI,5337
|
19
|
-
runem/utils.py,sha256=3N_kel9LsriiMq7kOjT14XhfxUOgz4hdDg97wlLKm3U,221
|
20
|
-
runem-0.0.17.dist-info/LICENSE,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
21
|
-
runem-0.0.17.dist-info/METADATA,sha256=kt13DdIGd0yuQenTfPPKovO0-xz5K7h5LzjlP_H2czc,15889
|
22
|
-
runem-0.0.17.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
23
|
-
runem-0.0.17.dist-info/entry_points.txt,sha256=nu0g_vBeuPihYtimbtlNusxWovylMppvJ8UxdJlJfvM,46
|
24
|
-
runem-0.0.17.dist-info/top_level.txt,sha256=gK6iqh9OfHDDpErioCC9ul_zx2Q5zWTALtcuGU7Vil4,6
|
25
|
-
runem-0.0.17.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|