parsl 2024.10.21__py3-none-any.whl → 2024.11.4__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.
- parsl/channels/base.py +0 -11
- parsl/channels/errors.py +0 -17
- parsl/channels/local/local.py +3 -16
- parsl/channels/ssh/ssh.py +0 -11
- parsl/dataflow/dflow.py +6 -6
- parsl/executors/high_throughput/executor.py +0 -1
- parsl/executors/high_throughput/interchange.py +8 -5
- parsl/executors/high_throughput/mpi_resource_management.py +0 -12
- parsl/executors/high_throughput/process_worker_pool.py +0 -8
- parsl/monitoring/db_manager.py +1 -1
- parsl/monitoring/monitoring.py +9 -11
- parsl/monitoring/radios.py +5 -16
- parsl/monitoring/remote.py +3 -5
- parsl/monitoring/router.py +4 -7
- parsl/monitoring/types.py +3 -6
- parsl/providers/__init__.py +0 -2
- parsl/providers/base.py +1 -17
- parsl/tests/conftest.py +4 -0
- parsl/tests/site_tests/site_config_selector.py +1 -6
- parsl/tests/test_bash_apps/test_basic.py +3 -0
- parsl/tests/test_bash_apps/test_error_codes.py +4 -0
- parsl/tests/test_bash_apps/test_kwarg_storage.py +1 -0
- parsl/tests/test_bash_apps/test_memoize.py +2 -6
- parsl/tests/test_bash_apps/test_memoize_ignore_args.py +3 -0
- parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +1 -0
- parsl/tests/test_bash_apps/test_multiline.py +1 -0
- parsl/tests/test_bash_apps/test_stdout.py +2 -0
- parsl/tests/{integration/test_channels → test_channels}/test_local_channel.py +4 -8
- parsl/tests/test_docs/test_from_slides.py +3 -0
- parsl/tests/test_docs/test_kwargs.py +3 -0
- parsl/tests/test_monitoring/test_basic.py +13 -1
- parsl/tests/test_python_apps/test_outputs.py +1 -0
- parsl/tests/test_regression/test_226.py +1 -0
- parsl/tests/test_scaling/test_worker_interchange_bad_messages_3262.py +92 -0
- parsl/tests/test_serialization/test_3495_deserialize_managerlost.py +1 -1
- parsl/tests/test_staging/test_docs_1.py +1 -0
- parsl/tests/test_staging/test_output_chain_filenames.py +3 -0
- parsl/tests/test_staging/test_staging_ftp.py +1 -0
- parsl/tests/test_staging/test_staging_https.py +3 -0
- parsl/tests/test_staging/test_staging_stdout.py +2 -0
- parsl/version.py +1 -1
- {parsl-2024.10.21.data → parsl-2024.11.4.data}/scripts/interchange.py +8 -5
- {parsl-2024.10.21.data → parsl-2024.11.4.data}/scripts/process_worker_pool.py +0 -8
- {parsl-2024.10.21.dist-info → parsl-2024.11.4.dist-info}/METADATA +2 -2
- {parsl-2024.10.21.dist-info → parsl-2024.11.4.dist-info}/RECORD +51 -58
- parsl/providers/cobalt/__init__.py +0 -0
- parsl/providers/cobalt/cobalt.py +0 -236
- parsl/providers/cobalt/template.py +0 -17
- parsl/tests/configs/cooley_htex.py +0 -37
- parsl/tests/configs/theta.py +0 -37
- parsl/tests/integration/test_channels/test_channels.py +0 -17
- parsl/tests/manual_tests/test_fan_in_out_htex_remote.py +0 -88
- parsl/tests/test_providers/test_cobalt_deprecation_warning.py +0 -18
- {parsl-2024.10.21.data → parsl-2024.11.4.data}/scripts/exec_parsl_function.py +0 -0
- {parsl-2024.10.21.data → parsl-2024.11.4.data}/scripts/parsl_coprocess.py +0 -0
- {parsl-2024.10.21.dist-info → parsl-2024.11.4.dist-info}/LICENSE +0 -0
- {parsl-2024.10.21.dist-info → parsl-2024.11.4.dist-info}/WHEEL +0 -0
- {parsl-2024.10.21.dist-info → parsl-2024.11.4.dist-info}/entry_points.txt +0 -0
- {parsl-2024.10.21.dist-info → parsl-2024.11.4.dist-info}/top_level.txt +0 -0
@@ -9,9 +9,7 @@ def fail_on_presence(outputs=()):
|
|
9
9
|
return 'if [ -f {0} ] ; then exit 1 ; else touch {0}; fi'.format(outputs[0])
|
10
10
|
|
11
11
|
|
12
|
-
|
13
|
-
# won't work if there's a staging provider.
|
14
|
-
# @pytest.mark.sharedFS_required
|
12
|
+
@pytest.mark.shared_fs
|
15
13
|
def test_bash_memoization(tmpd_cwd, n=2):
|
16
14
|
"""Testing bash memoization
|
17
15
|
"""
|
@@ -29,9 +27,7 @@ def fail_on_presence_kw(outputs=(), foo=None):
|
|
29
27
|
return 'if [ -f {0} ] ; then exit 1 ; else touch {0}; fi'.format(outputs[0])
|
30
28
|
|
31
29
|
|
32
|
-
|
33
|
-
# won't work if there's a staging provider.
|
34
|
-
# @pytest.mark.sharedFS_required
|
30
|
+
@pytest.mark.shared_fs
|
35
31
|
def test_bash_memoization_keywords(tmpd_cwd, n=2):
|
36
32
|
"""Testing bash memoization
|
37
33
|
"""
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
+
import pytest
|
4
|
+
|
3
5
|
import parsl
|
4
6
|
from parsl.app.app import bash_app
|
5
7
|
|
@@ -21,6 +23,7 @@ def no_checkpoint_stdout_app_ignore_args(stdout=None):
|
|
21
23
|
return "echo X"
|
22
24
|
|
23
25
|
|
26
|
+
@pytest.mark.shared_fs
|
24
27
|
def test_memo_stdout(tmpd_cwd):
|
25
28
|
path_x = tmpd_cwd / "test.memo.stdout.x"
|
26
29
|
|
@@ -91,6 +91,7 @@ def test_bad_stderr_file():
|
|
91
91
|
|
92
92
|
|
93
93
|
@pytest.mark.executor_supports_std_stream_tuples
|
94
|
+
@pytest.mark.shared_fs
|
94
95
|
def test_stdout_truncate(tmpd_cwd, caplog):
|
95
96
|
"""Testing truncation of prior content of stdout"""
|
96
97
|
|
@@ -110,6 +111,7 @@ def test_stdout_truncate(tmpd_cwd, caplog):
|
|
110
111
|
assert record.levelno < logging.ERROR
|
111
112
|
|
112
113
|
|
114
|
+
@pytest.mark.shared_fs
|
113
115
|
def test_stdout_append(tmpd_cwd, caplog):
|
114
116
|
"""Testing appending to prior content of stdout (default open() mode)"""
|
115
117
|
|
@@ -1,6 +1,9 @@
|
|
1
|
+
import pytest
|
2
|
+
|
1
3
|
from parsl.channels.local.local import LocalChannel
|
2
4
|
|
3
5
|
|
6
|
+
@pytest.mark.local
|
4
7
|
def test_env():
|
5
8
|
''' Regression testing for issue #27
|
6
9
|
'''
|
@@ -15,9 +18,8 @@ def test_env():
|
|
15
18
|
x = [s for s in stdout if s.startswith("HOME=")]
|
16
19
|
assert x, "HOME not found"
|
17
20
|
|
18
|
-
print("RC:{} \nSTDOUT:{} \nSTDERR:{}".format(rc, stdout, stderr))
|
19
|
-
|
20
21
|
|
22
|
+
@pytest.mark.local
|
21
23
|
def test_env_mod():
|
22
24
|
''' Testing for env update at execute time.
|
23
25
|
'''
|
@@ -34,9 +36,3 @@ def test_env_mod():
|
|
34
36
|
|
35
37
|
x = [s for s in stdout if s.startswith("TEST_ENV=fooo")]
|
36
38
|
assert x, "User set env missing"
|
37
|
-
|
38
|
-
|
39
|
-
if __name__ == "__main__":
|
40
|
-
|
41
|
-
test_env()
|
42
|
-
test_env_mod()
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
+
import pytest
|
4
|
+
|
3
5
|
from parsl.app.app import bash_app, python_app
|
4
6
|
from parsl.data_provider.files import File
|
5
7
|
|
@@ -15,6 +17,7 @@ def cat(inputs=[]):
|
|
15
17
|
return f.readlines()
|
16
18
|
|
17
19
|
|
20
|
+
@pytest.mark.staging_required
|
18
21
|
def test_slides():
|
19
22
|
"""Testing code snippet from slides """
|
20
23
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
"""Functions used to explain kwargs"""
|
2
2
|
from pathlib import Path
|
3
3
|
|
4
|
+
import pytest
|
5
|
+
|
4
6
|
from parsl import File, python_app
|
5
7
|
|
6
8
|
|
@@ -19,6 +21,7 @@ def test_inputs():
|
|
19
21
|
assert reduce_future.result() == 6
|
20
22
|
|
21
23
|
|
24
|
+
@pytest.mark.shared_fs
|
22
25
|
def test_outputs(tmpd_cwd):
|
23
26
|
@python_app()
|
24
27
|
def write_app(message, outputs=()):
|
@@ -42,6 +42,18 @@ def htex_udp_config():
|
|
42
42
|
return c
|
43
43
|
|
44
44
|
|
45
|
+
def htex_filesystem_config():
|
46
|
+
"""This config will force filesystem radio"""
|
47
|
+
from parsl.tests.configs.htex_local_alternate import fresh_config
|
48
|
+
c = fresh_config()
|
49
|
+
assert len(c.executors) == 1
|
50
|
+
|
51
|
+
assert c.executors[0].radio_mode == "htex", "precondition: htex has a radio mode attribute, configured for htex radio"
|
52
|
+
c.executors[0].radio_mode = "filesystem"
|
53
|
+
|
54
|
+
return c
|
55
|
+
|
56
|
+
|
45
57
|
def workqueue_config():
|
46
58
|
from parsl.tests.configs.workqueue_ex import fresh_config
|
47
59
|
c = fresh_config()
|
@@ -61,7 +73,7 @@ def taskvine_config():
|
|
61
73
|
|
62
74
|
|
63
75
|
@pytest.mark.local
|
64
|
-
@pytest.mark.parametrize("fresh_config", [htex_config, htex_udp_config, workqueue_config, taskvine_config])
|
76
|
+
@pytest.mark.parametrize("fresh_config", [htex_config, htex_filesystem_config, htex_udp_config, workqueue_config, taskvine_config])
|
65
77
|
def test_row_counts(tmpd_cwd, fresh_config):
|
66
78
|
# this is imported here rather than at module level because
|
67
79
|
# it isn't available in a plain parsl install, so this module
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import os
|
2
|
+
import signal
|
3
|
+
import time
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
import zmq
|
7
|
+
|
8
|
+
import parsl
|
9
|
+
from parsl.channels import LocalChannel
|
10
|
+
from parsl.config import Config
|
11
|
+
from parsl.executors import HighThroughputExecutor
|
12
|
+
from parsl.launchers import SimpleLauncher
|
13
|
+
from parsl.providers import LocalProvider
|
14
|
+
|
15
|
+
T_s = 1
|
16
|
+
|
17
|
+
|
18
|
+
def fresh_config():
|
19
|
+
htex = HighThroughputExecutor(
|
20
|
+
heartbeat_period=1 * T_s,
|
21
|
+
heartbeat_threshold=3 * T_s,
|
22
|
+
label="htex_local",
|
23
|
+
worker_debug=True,
|
24
|
+
cores_per_worker=1,
|
25
|
+
encrypted=False,
|
26
|
+
provider=LocalProvider(
|
27
|
+
channel=LocalChannel(),
|
28
|
+
init_blocks=0,
|
29
|
+
min_blocks=0,
|
30
|
+
max_blocks=0,
|
31
|
+
launcher=SimpleLauncher(),
|
32
|
+
),
|
33
|
+
)
|
34
|
+
c = Config(
|
35
|
+
executors=[htex],
|
36
|
+
strategy='none',
|
37
|
+
strategy_period=0.5,
|
38
|
+
)
|
39
|
+
return c, htex
|
40
|
+
|
41
|
+
|
42
|
+
@parsl.python_app
|
43
|
+
def app():
|
44
|
+
return 7
|
45
|
+
|
46
|
+
|
47
|
+
@pytest.mark.local
|
48
|
+
@pytest.mark.parametrize("msg",
|
49
|
+
(b'FuzzyByte\rSTREAM', # not JSON
|
50
|
+
b'{}', # missing fields
|
51
|
+
b'{"type":"heartbeat"}', # regression test #3262
|
52
|
+
)
|
53
|
+
)
|
54
|
+
def test_bad_messages(try_assert, msg):
|
55
|
+
"""This tests that the interchange is resilient to a few different bad
|
56
|
+
messages: malformed messages caused by implementation errors, and
|
57
|
+
heartbeat messages from managers that are not registered.
|
58
|
+
|
59
|
+
The heartbeat test is a regression test for issues #3262, #3632
|
60
|
+
"""
|
61
|
+
|
62
|
+
c, htex = fresh_config()
|
63
|
+
|
64
|
+
with parsl.load(c):
|
65
|
+
|
66
|
+
# send a bad message into the interchange on the task_outgoing worker
|
67
|
+
# channel, and then check that the interchange is still alive enough
|
68
|
+
# that we can scale out a block and run a task.
|
69
|
+
|
70
|
+
(task_port, result_port) = htex.command_client.run("WORKER_PORTS")
|
71
|
+
|
72
|
+
context = zmq.Context()
|
73
|
+
channel_timeout = 10000 # in milliseconds
|
74
|
+
task_channel = context.socket(zmq.DEALER)
|
75
|
+
task_channel.setsockopt(zmq.LINGER, 0)
|
76
|
+
task_channel.setsockopt(zmq.IDENTITY, b'testid')
|
77
|
+
|
78
|
+
task_channel.set_hwm(0)
|
79
|
+
task_channel.setsockopt(zmq.SNDTIMEO, channel_timeout)
|
80
|
+
task_channel.connect(f"tcp://localhost:{task_port}")
|
81
|
+
|
82
|
+
task_channel.send(msg)
|
83
|
+
|
84
|
+
# If the interchange exits, it's likely that this test will hang rather
|
85
|
+
# than raise an error, because the interchange interaction code
|
86
|
+
# assumes the interchange is always there.
|
87
|
+
# In the case of issue #3262, an exception message goes to stderr, and
|
88
|
+
# no error goes to the interchange log file.
|
89
|
+
htex.scale_out_facade(1)
|
90
|
+
try_assert(lambda: len(htex.connected_managers()) == 1, timeout_ms=10000)
|
91
|
+
|
92
|
+
assert app().result() == 7
|
@@ -32,7 +32,7 @@ def test_manager_lost_system_failure(tmpd_cwd):
|
|
32
32
|
cores_per_worker=1,
|
33
33
|
worker_logdir_root=str(tmpd_cwd),
|
34
34
|
heartbeat_period=1,
|
35
|
-
heartbeat_threshold=
|
35
|
+
heartbeat_threshold=3,
|
36
36
|
)
|
37
37
|
c = Config(executors=[hte], strategy='simple', strategy_period=0.1)
|
38
38
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
from concurrent.futures import Future
|
2
2
|
|
3
|
+
import pytest
|
4
|
+
|
3
5
|
from parsl import File
|
4
6
|
from parsl.app.app import bash_app
|
5
7
|
|
@@ -14,6 +16,7 @@ def app2(inputs=(), outputs=(), stdout=None, stderr=None, mock=False):
|
|
14
16
|
return f"echo '{inputs[0]}' > {outputs[0]}"
|
15
17
|
|
16
18
|
|
19
|
+
@pytest.mark.shared_fs
|
17
20
|
def test_behavior(tmpd_cwd):
|
18
21
|
expected_path = str(tmpd_cwd / "simple-out.txt")
|
19
22
|
app1_future = app1(
|
@@ -48,6 +48,7 @@ def sort_strings_additional_executor(inputs=(), outputs=()):
|
|
48
48
|
|
49
49
|
|
50
50
|
@pytest.mark.cleannet
|
51
|
+
@pytest.mark.staging_required
|
51
52
|
def test_staging_https_cleannet(tmpd_cwd):
|
52
53
|
unsorted_file = File(_unsorted_url)
|
53
54
|
sorted_file = File(tmpd_cwd / 'sorted.txt')
|
@@ -68,6 +69,7 @@ def test_staging_https_local(tmpd_cwd):
|
|
68
69
|
|
69
70
|
|
70
71
|
@pytest.mark.cleannet
|
72
|
+
@pytest.mark.staging_required
|
71
73
|
def test_staging_https_kwargs(tmpd_cwd):
|
72
74
|
unsorted_file = File(_unsorted_url)
|
73
75
|
sorted_file = File(tmpd_cwd / 'sorted.txt')
|
@@ -78,6 +80,7 @@ def test_staging_https_kwargs(tmpd_cwd):
|
|
78
80
|
|
79
81
|
|
80
82
|
@pytest.mark.cleannet
|
83
|
+
@pytest.mark.staging_required
|
81
84
|
def test_staging_https_args(tmpd_cwd):
|
82
85
|
unsorted_file = File(_unsorted_url)
|
83
86
|
sorted_file = File(tmpd_cwd / 'sorted.txt')
|
@@ -15,6 +15,7 @@ def output_to_stds(*, stdout=parsl.AUTO_LOGNAME, stderr=parsl.AUTO_LOGNAME):
|
|
15
15
|
return "echo hello ; echo goodbye >&2"
|
16
16
|
|
17
17
|
|
18
|
+
@pytest.mark.staging_required
|
18
19
|
def test_stdout_staging_file(tmpd_cwd, caplog):
|
19
20
|
basename = str(tmpd_cwd) + "/stdout.txt"
|
20
21
|
stdout_file = File("file://" + basename)
|
@@ -30,6 +31,7 @@ def test_stdout_staging_file(tmpd_cwd, caplog):
|
|
30
31
|
assert record.levelno < logging.ERROR
|
31
32
|
|
32
33
|
|
34
|
+
@pytest.mark.staging_required
|
33
35
|
def test_stdout_stderr_staging_zip(tmpd_cwd, caplog):
|
34
36
|
zipfile_name = str(tmpd_cwd) + "/staging.zip"
|
35
37
|
stdout_relative_path = "somewhere/test-out.txt"
|
parsl/version.py
CHANGED
@@ -66,7 +66,7 @@ class Interchange:
|
|
66
66
|
If specified the interchange will only listen on this address for connections from workers
|
67
67
|
else, it binds to all addresses.
|
68
68
|
|
69
|
-
client_ports :
|
69
|
+
client_ports : tuple(int, int, int)
|
70
70
|
The ports at which the client can be reached
|
71
71
|
|
72
72
|
worker_ports : tuple(int, int)
|
@@ -104,7 +104,6 @@ class Interchange:
|
|
104
104
|
os.makedirs(self.logdir, exist_ok=True)
|
105
105
|
|
106
106
|
start_file_logger("{}/interchange.log".format(self.logdir), level=logging_level)
|
107
|
-
logger.propagate = False
|
108
107
|
logger.debug("Initializing Interchange process")
|
109
108
|
|
110
109
|
self.client_address = client_address
|
@@ -437,9 +436,13 @@ class Interchange:
|
|
437
436
|
logger.info(f"Manager {manager_id!r} has compatible Parsl version {msg['parsl_v']}")
|
438
437
|
logger.info(f"Manager {manager_id!r} has compatible Python version {msg['python_v'].rsplit('.', 1)[0]}")
|
439
438
|
elif msg['type'] == 'heartbeat':
|
440
|
-
|
441
|
-
|
442
|
-
|
439
|
+
manager = self._ready_managers.get(manager_id)
|
440
|
+
if manager:
|
441
|
+
manager['last_heartbeat'] = time.time()
|
442
|
+
logger.debug("Manager %r sent heartbeat via tasks connection", manager_id)
|
443
|
+
self.task_outgoing.send_multipart([manager_id, b'', PKL_HEARTBEAT_CODE])
|
444
|
+
else:
|
445
|
+
logger.warning("Received heartbeat via tasks connection for not-registered manager %r", manager_id)
|
443
446
|
elif msg['type'] == 'drain':
|
444
447
|
self._ready_managers[manager_id]['draining'] = True
|
445
448
|
logger.debug("Manager %r requested drain", manager_id)
|
@@ -650,14 +650,6 @@ def worker(
|
|
650
650
|
debug: bool,
|
651
651
|
mpi_launcher: str,
|
652
652
|
):
|
653
|
-
"""
|
654
|
-
|
655
|
-
Put request token into queue
|
656
|
-
Get task from task_queue
|
657
|
-
Pop request from queue
|
658
|
-
Put result into result_queue
|
659
|
-
"""
|
660
|
-
|
661
653
|
# override the global logger inherited from the __main__ process (which
|
662
654
|
# usually logs to manager.log) with one specific to this worker.
|
663
655
|
global logger
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: parsl
|
3
|
-
Version: 2024.
|
3
|
+
Version: 2024.11.4
|
4
4
|
Summary: Simple data dependent workflows in Python
|
5
5
|
Home-page: https://github.com/Parsl/parsl
|
6
|
-
Download-URL: https://github.com/Parsl/parsl/archive/2024.
|
6
|
+
Download-URL: https://github.com/Parsl/parsl/archive/2024.11.04.tar.gz
|
7
7
|
Author: The Parsl Team
|
8
8
|
Author-email: parsl@googlegroups.com
|
9
9
|
License: Apache 2.0
|