parsl 2024.3.11__py3-none-any.whl → 2025.1.13__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/__init__.py +9 -10
- parsl/addresses.py +29 -7
- parsl/app/app.py +7 -8
- parsl/app/bash.py +15 -8
- parsl/app/errors.py +10 -13
- parsl/app/futures.py +8 -10
- parsl/app/python.py +2 -1
- parsl/benchmark/perf.py +2 -1
- parsl/concurrent/__init__.py +2 -2
- parsl/config.py +57 -10
- parsl/configs/ASPIRE1.py +6 -5
- parsl/configs/Azure.py +9 -8
- parsl/configs/bridges.py +6 -4
- parsl/configs/cc_in2p3.py +3 -3
- parsl/configs/ec2.py +3 -1
- parsl/configs/expanse.py +4 -3
- parsl/configs/frontera.py +3 -4
- parsl/configs/htex_local.py +3 -4
- parsl/configs/illinoiscluster.py +3 -1
- parsl/configs/improv.py +34 -0
- parsl/configs/kubernetes.py +4 -3
- parsl/configs/local_threads.py +5 -1
- parsl/configs/midway.py +5 -3
- parsl/configs/osg.py +4 -2
- parsl/configs/polaris.py +4 -2
- parsl/configs/stampede2.py +6 -5
- parsl/configs/summit.py +3 -3
- parsl/configs/toss3_llnl.py +4 -3
- parsl/configs/vineex_local.py +6 -4
- parsl/configs/wqex_local.py +5 -3
- parsl/curvezmq.py +4 -0
- parsl/data_provider/data_manager.py +4 -3
- parsl/data_provider/file_noop.py +1 -2
- parsl/data_provider/files.py +3 -3
- parsl/data_provider/ftp.py +1 -3
- parsl/data_provider/globus.py +7 -6
- parsl/data_provider/http.py +2 -2
- parsl/data_provider/rsync.py +1 -1
- parsl/data_provider/staging.py +2 -2
- parsl/data_provider/zip.py +135 -0
- parsl/dataflow/dependency_resolvers.py +115 -0
- parsl/dataflow/dflow.py +262 -224
- parsl/dataflow/errors.py +3 -5
- parsl/dataflow/futures.py +27 -14
- parsl/dataflow/memoization.py +5 -5
- parsl/dataflow/rundirs.py +5 -6
- parsl/dataflow/taskrecord.py +4 -5
- parsl/executors/__init__.py +4 -2
- parsl/executors/base.py +45 -15
- parsl/executors/errors.py +13 -0
- parsl/executors/execute_task.py +37 -0
- parsl/executors/flux/execute_parsl_task.py +3 -3
- parsl/executors/flux/executor.py +18 -19
- parsl/executors/flux/flux_instance_manager.py +26 -27
- parsl/executors/high_throughput/errors.py +43 -3
- parsl/executors/high_throughput/executor.py +316 -282
- parsl/executors/high_throughput/interchange.py +158 -167
- parsl/executors/high_throughput/manager_record.py +5 -0
- parsl/executors/high_throughput/manager_selector.py +55 -0
- parsl/executors/high_throughput/monitoring_info.py +2 -1
- parsl/executors/high_throughput/mpi_executor.py +113 -0
- parsl/executors/high_throughput/mpi_prefix_composer.py +10 -11
- parsl/executors/high_throughput/mpi_resource_management.py +6 -17
- parsl/executors/high_throughput/probe.py +9 -7
- parsl/executors/high_throughput/process_worker_pool.py +115 -77
- parsl/executors/high_throughput/zmq_pipes.py +81 -23
- parsl/executors/radical/executor.py +130 -79
- parsl/executors/radical/rpex_resources.py +17 -15
- parsl/executors/radical/rpex_worker.py +4 -3
- parsl/executors/status_handling.py +157 -51
- parsl/executors/taskvine/__init__.py +1 -1
- parsl/executors/taskvine/errors.py +1 -1
- parsl/executors/taskvine/exec_parsl_function.py +2 -2
- parsl/executors/taskvine/executor.py +41 -57
- parsl/executors/taskvine/factory.py +1 -1
- parsl/executors/taskvine/factory_config.py +1 -1
- parsl/executors/taskvine/manager.py +18 -13
- parsl/executors/taskvine/manager_config.py +9 -5
- parsl/executors/threads.py +6 -6
- parsl/executors/workqueue/errors.py +1 -1
- parsl/executors/workqueue/exec_parsl_function.py +6 -5
- parsl/executors/workqueue/executor.py +64 -63
- parsl/executors/workqueue/parsl_coprocess.py +1 -1
- parsl/jobs/error_handlers.py +2 -2
- parsl/jobs/job_status_poller.py +30 -113
- parsl/jobs/states.py +7 -2
- parsl/jobs/strategy.py +43 -31
- parsl/launchers/__init__.py +12 -3
- parsl/launchers/errors.py +1 -1
- parsl/launchers/launchers.py +6 -12
- parsl/log_utils.py +9 -6
- parsl/monitoring/db_manager.py +59 -95
- parsl/monitoring/errors.py +6 -0
- parsl/monitoring/monitoring.py +87 -356
- parsl/monitoring/queries/pandas.py +1 -2
- parsl/monitoring/radios/base.py +13 -0
- parsl/monitoring/radios/filesystem.py +52 -0
- parsl/monitoring/radios/htex.py +57 -0
- parsl/monitoring/radios/multiprocessing.py +17 -0
- parsl/monitoring/radios/udp.py +56 -0
- parsl/monitoring/radios/zmq.py +17 -0
- parsl/monitoring/remote.py +33 -37
- parsl/monitoring/router.py +212 -0
- parsl/monitoring/types.py +5 -6
- parsl/monitoring/visualization/app.py +4 -2
- parsl/monitoring/visualization/models.py +0 -1
- parsl/monitoring/visualization/plots/default/workflow_plots.py +11 -4
- parsl/monitoring/visualization/plots/default/workflow_resource_plots.py +1 -0
- parsl/monitoring/visualization/utils.py +0 -1
- parsl/monitoring/visualization/views.py +16 -8
- parsl/multiprocessing.py +0 -1
- parsl/process_loggers.py +1 -2
- parsl/providers/__init__.py +8 -17
- parsl/providers/aws/aws.py +2 -3
- parsl/providers/azure/azure.py +4 -5
- parsl/providers/base.py +2 -18
- parsl/providers/cluster_provider.py +4 -12
- parsl/providers/condor/condor.py +7 -17
- parsl/providers/errors.py +2 -2
- parsl/providers/googlecloud/googlecloud.py +2 -1
- parsl/providers/grid_engine/grid_engine.py +5 -14
- parsl/providers/kubernetes/kube.py +80 -40
- parsl/providers/local/local.py +13 -26
- parsl/providers/lsf/lsf.py +5 -23
- parsl/providers/pbspro/pbspro.py +5 -17
- parsl/providers/slurm/slurm.py +81 -39
- parsl/providers/torque/torque.py +3 -14
- parsl/serialize/__init__.py +8 -3
- parsl/serialize/base.py +1 -2
- parsl/serialize/concretes.py +5 -4
- parsl/serialize/facade.py +3 -3
- parsl/serialize/proxystore.py +3 -2
- parsl/tests/__init__.py +1 -1
- parsl/tests/configs/azure_single_node.py +4 -5
- parsl/tests/configs/bridges.py +3 -2
- parsl/tests/configs/cc_in2p3.py +1 -3
- parsl/tests/configs/comet.py +2 -1
- parsl/tests/configs/ec2_single_node.py +1 -2
- parsl/tests/configs/ec2_spot.py +1 -2
- parsl/tests/configs/flux_local.py +11 -0
- parsl/tests/configs/frontera.py +2 -3
- parsl/tests/configs/htex_local.py +3 -5
- parsl/tests/configs/htex_local_alternate.py +11 -15
- parsl/tests/configs/htex_local_intask_staging.py +5 -9
- parsl/tests/configs/htex_local_rsync_staging.py +4 -8
- parsl/tests/configs/local_radical.py +1 -3
- parsl/tests/configs/local_radical_mpi.py +2 -2
- parsl/tests/configs/local_threads_checkpoint_periodic.py +8 -10
- parsl/tests/configs/local_threads_monitoring.py +0 -1
- parsl/tests/configs/midway.py +2 -2
- parsl/tests/configs/nscc_singapore.py +3 -3
- parsl/tests/configs/osg_htex.py +1 -1
- parsl/tests/configs/petrelkube.py +3 -2
- parsl/tests/configs/slurm_local.py +24 -0
- parsl/tests/configs/summit.py +1 -0
- parsl/tests/configs/taskvine_ex.py +4 -7
- parsl/tests/configs/user_opts.py +2 -8
- parsl/tests/configs/workqueue_ex.py +4 -6
- parsl/tests/conftest.py +27 -13
- parsl/tests/integration/test_stress/test_python_simple.py +3 -4
- parsl/tests/integration/test_stress/test_python_threads.py +3 -5
- parsl/tests/manual_tests/htex_local.py +4 -6
- parsl/tests/manual_tests/test_basic.py +1 -0
- parsl/tests/manual_tests/test_log_filter.py +3 -1
- parsl/tests/manual_tests/test_memory_limits.py +6 -8
- parsl/tests/manual_tests/test_regression_220.py +2 -1
- parsl/tests/manual_tests/test_udp_simple.py +4 -4
- parsl/tests/manual_tests/test_worker_count.py +3 -2
- parsl/tests/scaling_tests/htex_local.py +2 -4
- parsl/tests/scaling_tests/test_scale.py +0 -9
- parsl/tests/scaling_tests/vineex_condor.py +1 -2
- parsl/tests/scaling_tests/vineex_local.py +1 -2
- parsl/tests/site_tests/site_config_selector.py +1 -6
- parsl/tests/site_tests/test_provider.py +4 -2
- parsl/tests/site_tests/test_site.py +2 -0
- parsl/tests/sites/test_affinity.py +7 -7
- parsl/tests/sites/test_dynamic_executor.py +3 -4
- parsl/tests/sites/test_ec2.py +3 -2
- parsl/tests/sites/test_worker_info.py +4 -5
- parsl/tests/test_aalst_patterns.py +0 -1
- parsl/tests/test_bash_apps/test_apptimeout.py +2 -2
- parsl/tests/test_bash_apps/test_basic.py +10 -4
- parsl/tests/test_bash_apps/test_error_codes.py +5 -7
- parsl/tests/test_bash_apps/test_inputs_default.py +25 -0
- parsl/tests/test_bash_apps/test_kwarg_storage.py +1 -1
- parsl/tests/test_bash_apps/test_memoize.py +2 -8
- parsl/tests/test_bash_apps/test_memoize_ignore_args.py +9 -14
- parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +9 -14
- parsl/tests/test_bash_apps/test_multiline.py +1 -1
- parsl/tests/test_bash_apps/test_pipeline.py +1 -1
- parsl/tests/test_bash_apps/test_std_uri.py +123 -0
- parsl/tests/test_bash_apps/test_stdout.py +33 -8
- parsl/tests/test_callables.py +2 -2
- parsl/tests/test_checkpointing/test_periodic.py +21 -39
- parsl/tests/test_checkpointing/test_python_checkpoint_1.py +1 -0
- parsl/tests/test_checkpointing/test_python_checkpoint_2.py +2 -2
- parsl/tests/test_checkpointing/test_python_checkpoint_3.py +0 -1
- parsl/tests/test_checkpointing/test_regression_239.py +1 -1
- parsl/tests/test_checkpointing/test_task_exit.py +2 -3
- parsl/tests/test_docs/test_from_slides.py +5 -2
- parsl/tests/test_docs/test_kwargs.py +4 -1
- parsl/tests/test_docs/test_tutorial_1.py +1 -2
- parsl/tests/test_docs/test_workflow1.py +2 -2
- parsl/tests/test_docs/test_workflow2.py +0 -1
- parsl/tests/test_error_handling/test_rand_fail.py +2 -2
- parsl/tests/test_error_handling/test_resource_spec.py +10 -12
- parsl/tests/test_error_handling/test_retries.py +6 -16
- parsl/tests/test_error_handling/test_retry_handler.py +1 -0
- parsl/tests/test_error_handling/test_retry_handler_failure.py +2 -1
- parsl/tests/test_error_handling/test_serialization_fail.py +1 -1
- parsl/tests/test_error_handling/test_wrap_with_logs.py +1 -0
- parsl/tests/test_execute_task.py +29 -0
- parsl/tests/test_flux.py +1 -1
- parsl/tests/test_htex/test_basic.py +2 -3
- parsl/tests/test_htex/test_block_manager_selector_unit.py +20 -0
- parsl/tests/test_htex/test_command_client_timeout.py +66 -0
- parsl/tests/test_htex/test_connected_blocks.py +3 -2
- parsl/tests/test_htex/test_cpu_affinity_explicit.py +6 -10
- parsl/tests/test_htex/test_disconnected_blocks.py +6 -5
- parsl/tests/test_htex/test_disconnected_blocks_failing_provider.py +71 -0
- parsl/tests/test_htex/test_drain.py +79 -0
- parsl/tests/test_htex/test_htex.py +51 -25
- parsl/tests/test_htex/test_manager_failure.py +0 -1
- parsl/tests/test_htex/test_manager_selector_by_block.py +51 -0
- parsl/tests/test_htex/test_managers_command.py +36 -0
- parsl/tests/test_htex/test_missing_worker.py +2 -12
- parsl/tests/test_htex/test_multiple_disconnected_blocks.py +9 -9
- parsl/tests/test_htex/test_resource_spec_validation.py +45 -0
- parsl/tests/test_htex/test_zmq_binding.py +29 -8
- parsl/tests/test_monitoring/test_app_names.py +86 -0
- parsl/tests/test_monitoring/test_basic.py +73 -25
- parsl/tests/test_monitoring/test_db_locks.py +6 -4
- parsl/tests/test_monitoring/test_fuzz_zmq.py +19 -8
- parsl/tests/test_monitoring/test_htex_init_blocks_vs_monitoring.py +80 -0
- parsl/tests/test_monitoring/test_incomplete_futures.py +5 -4
- parsl/tests/test_monitoring/test_memoization_representation.py +4 -2
- parsl/tests/test_monitoring/test_stdouterr.py +134 -0
- parsl/tests/test_monitoring/test_viz_colouring.py +1 -0
- parsl/tests/test_mpi_apps/test_bad_mpi_config.py +33 -26
- parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py +28 -11
- parsl/tests/test_mpi_apps/test_mpi_prefix.py +4 -4
- parsl/tests/test_mpi_apps/test_mpi_scheduler.py +7 -2
- parsl/tests/test_mpi_apps/test_mpiex.py +64 -0
- parsl/tests/test_mpi_apps/test_resource_spec.py +42 -49
- parsl/tests/test_providers/test_kubernetes_provider.py +102 -0
- parsl/tests/test_providers/test_local_provider.py +3 -132
- parsl/tests/test_providers/test_pbspro_template.py +2 -3
- parsl/tests/test_providers/test_slurm_template.py +2 -3
- parsl/tests/test_providers/test_submiterror_deprecation.py +2 -1
- parsl/tests/test_python_apps/test_context_manager.py +128 -0
- parsl/tests/test_python_apps/test_dep_standard_futures.py +2 -1
- parsl/tests/test_python_apps/test_dependencies_deep.py +59 -0
- parsl/tests/test_python_apps/test_fail.py +0 -25
- parsl/tests/test_python_apps/test_futures.py +2 -1
- parsl/tests/test_python_apps/test_inputs_default.py +22 -0
- parsl/tests/test_python_apps/test_join.py +0 -1
- parsl/tests/test_python_apps/test_lifted.py +11 -7
- parsl/tests/test_python_apps/test_memoize_bad_id_for_memo.py +1 -0
- parsl/tests/test_python_apps/test_outputs.py +1 -1
- parsl/tests/test_python_apps/test_pluggable_future_resolution.py +161 -0
- parsl/tests/test_radical/test_mpi_funcs.py +1 -2
- parsl/tests/test_regression/test_1480.py +2 -1
- parsl/tests/test_regression/test_1653.py +2 -1
- parsl/tests/test_regression/test_226.py +1 -0
- parsl/tests/test_regression/test_2652.py +1 -0
- parsl/tests/test_regression/test_69a.py +0 -1
- parsl/tests/test_regression/test_854.py +4 -2
- parsl/tests/test_regression/test_97_parallelism_0.py +1 -2
- parsl/tests/test_regression/test_98.py +0 -1
- parsl/tests/test_scaling/test_block_error_handler.py +9 -4
- parsl/tests/test_scaling/test_regression_1621.py +11 -15
- parsl/tests/test_scaling/test_regression_3568_scaledown_vs_MISSING.py +84 -0
- parsl/tests/test_scaling/test_regression_3696_oscillation.py +103 -0
- parsl/tests/test_scaling/test_scale_down.py +2 -5
- parsl/tests/test_scaling/test_scale_down_htex_auto_scale.py +6 -18
- parsl/tests/test_scaling/test_scale_down_htex_unregistered.py +71 -0
- parsl/tests/test_scaling/test_shutdown_scalein.py +73 -0
- parsl/tests/test_scaling/test_worker_interchange_bad_messages_3262.py +90 -0
- parsl/tests/test_serialization/test_2555_caching_deserializer.py +1 -1
- parsl/tests/test_serialization/test_3495_deserialize_managerlost.py +47 -0
- parsl/tests/test_serialization/test_basic.py +2 -1
- parsl/tests/test_serialization/test_htex_code_cache.py +3 -4
- parsl/tests/test_serialization/test_pack_resource_spec.py +2 -1
- parsl/tests/test_serialization/test_proxystore_configured.py +10 -6
- parsl/tests/test_serialization/test_proxystore_impl.py +5 -3
- parsl/tests/test_shutdown/test_kill_monitoring.py +64 -0
- parsl/tests/test_staging/staging_provider.py +2 -2
- parsl/tests/test_staging/test_1316.py +3 -4
- parsl/tests/test_staging/test_docs_1.py +2 -1
- parsl/tests/test_staging/test_docs_2.py +2 -1
- parsl/tests/test_staging/test_elaborate_noop_file.py +2 -3
- parsl/tests/{test_data → test_staging}/test_file.py +6 -6
- parsl/tests/{test_data → 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 +5 -2
- parsl/tests/test_staging/test_staging_stdout.py +64 -0
- parsl/tests/test_staging/test_zip_in.py +39 -0
- parsl/tests/test_staging/test_zip_out.py +110 -0
- parsl/tests/test_staging/test_zip_to_zip.py +41 -0
- parsl/tests/test_summary.py +2 -2
- parsl/tests/test_thread_parallelism.py +0 -1
- parsl/tests/test_threads/test_configs.py +1 -2
- parsl/tests/test_threads/test_lazy_errors.py +2 -2
- parsl/tests/test_utils/test_execute_wait.py +35 -0
- parsl/tests/test_utils/test_sanitize_dns.py +76 -0
- parsl/tests/unit/test_address.py +20 -0
- parsl/tests/unit/test_file.py +99 -0
- parsl/tests/unit/test_usage_tracking.py +66 -0
- parsl/usage_tracking/api.py +65 -0
- parsl/usage_tracking/levels.py +6 -0
- parsl/usage_tracking/usage.py +104 -62
- parsl/utils.py +139 -6
- parsl/version.py +1 -1
- {parsl-2024.3.11.data → parsl-2025.1.13.data}/scripts/exec_parsl_function.py +6 -5
- parsl-2025.1.13.data/scripts/interchange.py +649 -0
- {parsl-2024.3.11.data → parsl-2025.1.13.data}/scripts/process_worker_pool.py +115 -77
- parsl-2025.1.13.dist-info/METADATA +96 -0
- parsl-2025.1.13.dist-info/RECORD +462 -0
- {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/WHEEL +1 -1
- parsl/channels/__init__.py +0 -7
- parsl/channels/base.py +0 -141
- parsl/channels/errors.py +0 -113
- parsl/channels/local/local.py +0 -164
- parsl/channels/oauth_ssh/oauth_ssh.py +0 -110
- parsl/channels/ssh/ssh.py +0 -276
- parsl/channels/ssh_il/__init__.py +0 -0
- parsl/channels/ssh_il/ssh_il.py +0 -74
- parsl/configs/ad_hoc.py +0 -35
- parsl/executors/radical/rpex_master.py +0 -42
- parsl/monitoring/radios.py +0 -175
- parsl/providers/ad_hoc/__init__.py +0 -0
- parsl/providers/ad_hoc/ad_hoc.py +0 -248
- parsl/providers/cobalt/__init__.py +0 -0
- parsl/providers/cobalt/cobalt.py +0 -236
- parsl/providers/cobalt/template.py +0 -17
- parsl/tests/configs/ad_hoc_cluster_htex.py +0 -35
- parsl/tests/configs/cooley_htex.py +0 -37
- parsl/tests/configs/htex_ad_hoc_cluster.py +0 -28
- parsl/tests/configs/local_adhoc.py +0 -18
- parsl/tests/configs/swan_htex.py +0 -43
- parsl/tests/configs/theta.py +0 -37
- parsl/tests/integration/test_channels/__init__.py +0 -0
- parsl/tests/integration/test_channels/test_channels.py +0 -17
- parsl/tests/integration/test_channels/test_local_channel.py +0 -42
- parsl/tests/integration/test_channels/test_scp_1.py +0 -45
- parsl/tests/integration/test_channels/test_ssh_1.py +0 -40
- parsl/tests/integration/test_channels/test_ssh_errors.py +0 -46
- parsl/tests/integration/test_channels/test_ssh_file_transport.py +0 -41
- parsl/tests/integration/test_channels/test_ssh_interactive.py +0 -24
- parsl/tests/manual_tests/test_ad_hoc_htex.py +0 -48
- parsl/tests/manual_tests/test_fan_in_out_htex_remote.py +0 -88
- parsl/tests/manual_tests/test_oauth_ssh.py +0 -13
- parsl/tests/sites/test_local_adhoc.py +0 -61
- parsl/tests/test_channels/__init__.py +0 -0
- parsl/tests/test_channels/test_large_output.py +0 -22
- parsl/tests/test_data/__init__.py +0 -0
- parsl/tests/test_mpi_apps/test_mpi_mode_disabled.py +0 -51
- parsl/tests/test_providers/test_cobalt_deprecation_warning.py +0 -16
- parsl-2024.3.11.dist-info/METADATA +0 -98
- parsl-2024.3.11.dist-info/RECORD +0 -447
- parsl/{channels/local → monitoring/radios}/__init__.py +0 -0
- parsl/{channels/oauth_ssh → tests/test_shutdown}/__init__.py +0 -0
- parsl/tests/{test_data → test_staging}/test_file_apps.py +0 -0
- parsl/tests/{test_data → test_staging}/test_file_staging.py +0 -0
- parsl/{channels/ssh → tests/unit}/__init__.py +0 -0
- {parsl-2024.3.11.data → parsl-2025.1.13.data}/scripts/parsl_coprocess.py +1 -1
- {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/LICENSE +0 -0
- {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/entry_points.txt +0 -0
- {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
import inspect
|
2
|
+
from concurrent.futures import Future
|
3
|
+
from typing import Any, Callable, Dict
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
|
7
|
+
import parsl
|
8
|
+
from parsl.executors.base import ParslExecutor
|
9
|
+
|
10
|
+
# N is the number of tasks to chain
|
11
|
+
# With mid-2024 Parsl, N>140 causes Parsl to hang
|
12
|
+
N = 100
|
13
|
+
|
14
|
+
# MAX_STACK is the maximum Python stack depth allowed for either
|
15
|
+
# task submission to an executor or execution of a task.
|
16
|
+
# With mid-2024 Parsl, 2-3 stack entries will be used per
|
17
|
+
# recursively launched parsl task. So this should be smaller than
|
18
|
+
# 2*N, but big enough to allow regular pytest+parsl stuff to
|
19
|
+
# happen.
|
20
|
+
MAX_STACK = 50
|
21
|
+
|
22
|
+
|
23
|
+
def local_config():
|
24
|
+
return parsl.Config(executors=[ImmediateExecutor()])
|
25
|
+
|
26
|
+
|
27
|
+
class ImmediateExecutor(ParslExecutor):
|
28
|
+
def start(self):
|
29
|
+
pass
|
30
|
+
|
31
|
+
def shutdown(self):
|
32
|
+
pass
|
33
|
+
|
34
|
+
def submit(self, func: Callable, resource_specification: Dict[str, Any], *args: Any, **kwargs: Any) -> Future:
|
35
|
+
stack_depth = len(inspect.stack())
|
36
|
+
assert stack_depth < MAX_STACK, "tasks should not be launched deep in the Python stack"
|
37
|
+
fut: Future[None] = Future()
|
38
|
+
res = func(*args, **kwargs)
|
39
|
+
fut.set_result(res)
|
40
|
+
return fut
|
41
|
+
|
42
|
+
|
43
|
+
@parsl.python_app
|
44
|
+
def chain(upstream):
|
45
|
+
stack_depth = len(inspect.stack())
|
46
|
+
assert stack_depth < MAX_STACK, "chained dependencies should not be launched deep in the Python stack"
|
47
|
+
|
48
|
+
|
49
|
+
@pytest.mark.local
|
50
|
+
def test_deep_dependency_stack_depth():
|
51
|
+
|
52
|
+
fut = Future()
|
53
|
+
here = fut
|
54
|
+
|
55
|
+
for _ in range(N):
|
56
|
+
here = chain(here)
|
57
|
+
|
58
|
+
fut.set_result(None)
|
59
|
+
here.result()
|
@@ -41,28 +41,3 @@ def test_fail_sequence(fail_probs):
|
|
41
41
|
|
42
42
|
with pytest.raises(DependencyError):
|
43
43
|
t_final.result()
|
44
|
-
|
45
|
-
|
46
|
-
def test_deps(width=3):
|
47
|
-
"""Random failures in branches of Map -> Map -> reduce"""
|
48
|
-
# App1 App2 ... AppN
|
49
|
-
futs = [random_fail(fail_prob=0.4) for _ in range(width)]
|
50
|
-
|
51
|
-
# App1 App2 ... AppN
|
52
|
-
# | | |
|
53
|
-
# V V V
|
54
|
-
# App1 App2 ... AppN
|
55
|
-
|
56
|
-
futs = [random_fail(fail_prob=0.8, inputs=[f]) for f in futs]
|
57
|
-
|
58
|
-
# App1 App2 ... AppN
|
59
|
-
# | | |
|
60
|
-
# V V V
|
61
|
-
# App1 App2 ... AppN
|
62
|
-
# \ | /
|
63
|
-
# \ | /
|
64
|
-
# App_Final
|
65
|
-
try:
|
66
|
-
random_fail(fail_prob=0, inputs=futs).result()
|
67
|
-
except DependencyError:
|
68
|
-
pass
|
@@ -11,9 +11,10 @@ Same applies to datafutures, and we need to know the behavior wrt.
|
|
11
11
|
2. done() called on 1, vs 2
|
12
12
|
|
13
13
|
"""
|
14
|
-
import pytest
|
15
14
|
from os.path import basename
|
16
15
|
|
16
|
+
import pytest
|
17
|
+
|
17
18
|
from parsl.app.app import python_app
|
18
19
|
from parsl.data_provider.files import File
|
19
20
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
import parsl
|
4
|
+
from parsl import python_app
|
5
|
+
from parsl.executors.threads import ThreadPoolExecutor
|
6
|
+
|
7
|
+
|
8
|
+
def local_config():
|
9
|
+
return parsl.Config(executors=[ThreadPoolExecutor()])
|
10
|
+
|
11
|
+
|
12
|
+
@pytest.mark.local
|
13
|
+
def test_default_inputs():
|
14
|
+
@python_app
|
15
|
+
def identity(inp):
|
16
|
+
return inp
|
17
|
+
|
18
|
+
@python_app
|
19
|
+
def add_inputs(inputs=[identity(1), identity(2)]):
|
20
|
+
return sum(inputs)
|
21
|
+
|
22
|
+
assert add_inputs().result() == 3
|
@@ -1,26 +1,30 @@
|
|
1
|
+
from concurrent.futures import Future
|
2
|
+
from typing import TypeVar
|
3
|
+
|
1
4
|
import pytest
|
2
5
|
|
3
|
-
from concurrent.futures import Future
|
4
6
|
from parsl import python_app
|
5
7
|
|
8
|
+
T = TypeVar('T')
|
9
|
+
|
6
10
|
|
7
11
|
@python_app
|
8
|
-
def returns_a_dict():
|
12
|
+
def returns_a_dict() -> dict:
|
9
13
|
return {"a": "X", "b": "Y"}
|
10
14
|
|
11
15
|
|
12
16
|
@python_app
|
13
|
-
def returns_a_list():
|
17
|
+
def returns_a_list() -> list:
|
14
18
|
return ["X", "Y"]
|
15
19
|
|
16
20
|
|
17
21
|
@python_app
|
18
|
-
def returns_a_tuple():
|
22
|
+
def returns_a_tuple() -> tuple:
|
19
23
|
return ("X", "Y")
|
20
24
|
|
21
25
|
|
22
26
|
@python_app
|
23
|
-
def returns_a_class():
|
27
|
+
def returns_a_class() -> type:
|
24
28
|
from dataclasses import dataclass
|
25
29
|
|
26
30
|
@dataclass
|
@@ -38,7 +42,7 @@ class MyOuterClass():
|
|
38
42
|
|
39
43
|
|
40
44
|
@python_app
|
41
|
-
def returns_a_class_instance():
|
45
|
+
def returns_a_class_instance() -> object:
|
42
46
|
return MyOuterClass()
|
43
47
|
|
44
48
|
|
@@ -110,7 +114,7 @@ def test_returns_a_class():
|
|
110
114
|
|
111
115
|
|
112
116
|
@python_app
|
113
|
-
def passthrough(v):
|
117
|
+
def passthrough(v: T) -> T:
|
114
118
|
return v
|
115
119
|
|
116
120
|
|
@@ -16,7 +16,7 @@ def double(x, outputs=[]):
|
|
16
16
|
whitelist = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'configs', '*threads*')
|
17
17
|
|
18
18
|
|
19
|
-
@pytest.mark.
|
19
|
+
@pytest.mark.shared_fs
|
20
20
|
def test_launch_apps(tmpd_cwd, n=2):
|
21
21
|
outdir = tmpd_cwd / "outputs"
|
22
22
|
outdir.mkdir()
|
@@ -0,0 +1,161 @@
|
|
1
|
+
from concurrent.futures import Future
|
2
|
+
from pathlib import Path
|
3
|
+
from threading import Event
|
4
|
+
from typing import Sequence
|
5
|
+
|
6
|
+
import pytest
|
7
|
+
|
8
|
+
import parsl
|
9
|
+
from parsl.config import Config
|
10
|
+
from parsl.dataflow.dependency_resolvers import DEEP_DEPENDENCY_RESOLVER
|
11
|
+
from parsl.dataflow.errors import DependencyError
|
12
|
+
|
13
|
+
|
14
|
+
def local_config():
|
15
|
+
return Config(dependency_resolver=DEEP_DEPENDENCY_RESOLVER)
|
16
|
+
|
17
|
+
|
18
|
+
@parsl.python_app
|
19
|
+
def a(event):
|
20
|
+
event.wait()
|
21
|
+
return 7
|
22
|
+
|
23
|
+
|
24
|
+
@parsl.python_app
|
25
|
+
def b(x: int):
|
26
|
+
return x + 1
|
27
|
+
|
28
|
+
|
29
|
+
@pytest.mark.local
|
30
|
+
def test_simple_pos_arg():
|
31
|
+
e = Event()
|
32
|
+
s = a(e)
|
33
|
+
f_b = b(s)
|
34
|
+
e.set()
|
35
|
+
|
36
|
+
assert f_b.result() == 8
|
37
|
+
|
38
|
+
|
39
|
+
@parsl.python_app
|
40
|
+
def b_first(x: Sequence[int]):
|
41
|
+
return x[0] + 1
|
42
|
+
|
43
|
+
|
44
|
+
@pytest.mark.local
|
45
|
+
def test_tuple_pos_arg():
|
46
|
+
e = Event()
|
47
|
+
s = (a(e),)
|
48
|
+
f_b = b_first(s)
|
49
|
+
e.set()
|
50
|
+
assert f_b.result() == 8
|
51
|
+
|
52
|
+
|
53
|
+
@pytest.mark.local
|
54
|
+
def test_list_exception():
|
55
|
+
a = Future()
|
56
|
+
a.set_exception(RuntimeError("artificial error"))
|
57
|
+
f_b = b([a])
|
58
|
+
assert isinstance(f_b.exception(), DependencyError)
|
59
|
+
|
60
|
+
|
61
|
+
@parsl.python_app
|
62
|
+
def make_path(s: str):
|
63
|
+
return Path(s)
|
64
|
+
|
65
|
+
|
66
|
+
@parsl.python_app
|
67
|
+
def append_paths(iterable, end_str: str = "end"):
|
68
|
+
type_ = type(iterable)
|
69
|
+
return type_([Path(s, end_str) for s in iterable])
|
70
|
+
|
71
|
+
|
72
|
+
@pytest.mark.local
|
73
|
+
@pytest.mark.parametrize(
|
74
|
+
"type_",
|
75
|
+
[
|
76
|
+
tuple,
|
77
|
+
list,
|
78
|
+
set,
|
79
|
+
],
|
80
|
+
)
|
81
|
+
def test_resolving_iterables(type_):
|
82
|
+
output1 = make_path("test1")
|
83
|
+
output2 = make_path("test2")
|
84
|
+
output3 = append_paths(type_([output1, output2]), end_str="end")
|
85
|
+
assert output3.result() == type_([Path("test1", "end"), Path("test2", "end")])
|
86
|
+
|
87
|
+
|
88
|
+
@parsl.python_app
|
89
|
+
def append_paths_dict(iterable: dict, end_str: str = "end"):
|
90
|
+
return {Path(k, end_str): Path(v, end_str) for k, v in iterable.items()}
|
91
|
+
|
92
|
+
|
93
|
+
@pytest.mark.local
|
94
|
+
def test_resolving_dict():
|
95
|
+
output1 = make_path("test1")
|
96
|
+
output2 = make_path("test2")
|
97
|
+
output3 = append_paths_dict({output1: output2}, end_str="end")
|
98
|
+
assert output3.result() == {Path("test1", "end"): Path("test2", "end")}
|
99
|
+
|
100
|
+
|
101
|
+
@parsl.python_app
|
102
|
+
def extract_deep(struct: list):
|
103
|
+
return struct[0][0][0][0][0]
|
104
|
+
|
105
|
+
|
106
|
+
@pytest.mark.local
|
107
|
+
def test_deeper_list():
|
108
|
+
f = Future()
|
109
|
+
f.set_result(7)
|
110
|
+
f_b = extract_deep([[[[[f]]]]])
|
111
|
+
|
112
|
+
assert f_b.result() == 7
|
113
|
+
|
114
|
+
|
115
|
+
@pytest.mark.local
|
116
|
+
def test_deeper_list_and_tuple():
|
117
|
+
f = Future()
|
118
|
+
f.set_result(7)
|
119
|
+
f_b = extract_deep([([([f],)],)])
|
120
|
+
|
121
|
+
assert f_b.result() == 7
|
122
|
+
|
123
|
+
|
124
|
+
@parsl.python_app
|
125
|
+
def dictionary_checker(d):
|
126
|
+
assert d["a"] == [30, 10]
|
127
|
+
assert d["b"] == 20
|
128
|
+
|
129
|
+
|
130
|
+
@pytest.mark.local
|
131
|
+
def test_dictionary():
|
132
|
+
k1 = Future()
|
133
|
+
k1.set_result("a")
|
134
|
+
k2 = Future()
|
135
|
+
k2.set_result("b")
|
136
|
+
v1 = Future()
|
137
|
+
v1.set_result(10)
|
138
|
+
|
139
|
+
# this .result() will fail if the asserts fail
|
140
|
+
dictionary_checker({k1: [30, v1], k2: 20}).result()
|
141
|
+
|
142
|
+
|
143
|
+
@pytest.mark.local
|
144
|
+
def test_dictionary_later():
|
145
|
+
k1 = Future()
|
146
|
+
k2 = Future()
|
147
|
+
v1 = Future()
|
148
|
+
|
149
|
+
f1 = dictionary_checker({k1: [30, v1], k2: 20})
|
150
|
+
|
151
|
+
assert not f1.done()
|
152
|
+
k1.set_result("a")
|
153
|
+
k2.set_result("b")
|
154
|
+
v1.set_result(10)
|
155
|
+
|
156
|
+
# having set the results, f1 should fairly rapidly complete (but not
|
157
|
+
# instantly) so we can't assert on done() here... but we can
|
158
|
+
# check that f1 does "eventually" complete... meaning that
|
159
|
+
# none of the assertions inside test_dictionary have failed
|
160
|
+
|
161
|
+
assert f1.result() is None
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import parsl
|
2
1
|
import pytest
|
3
2
|
|
3
|
+
import parsl
|
4
4
|
from parsl.tests.configs.local_radical_mpi import fresh_config as local_config
|
5
5
|
|
6
6
|
|
@@ -16,7 +16,6 @@ def some_mpi_func(msg, sleep, comm=None, parsl_resource_specification={}):
|
|
16
16
|
apps = []
|
17
17
|
|
18
18
|
|
19
|
-
@pytest.mark.skip("hangs in CI - waiting for resolution of issue #3029")
|
20
19
|
@pytest.mark.local
|
21
20
|
@pytest.mark.radical
|
22
21
|
def test_radical_mpi(n=7):
|
@@ -1,11 +1,10 @@
|
|
1
1
|
import pytest
|
2
2
|
|
3
3
|
import parsl
|
4
|
-
|
5
4
|
from parsl.config import Config
|
6
5
|
from parsl.executors import HighThroughputExecutor
|
7
|
-
from parsl.providers import LocalProvider
|
8
6
|
from parsl.launchers import SimpleLauncher
|
7
|
+
from parsl.providers import LocalProvider
|
9
8
|
|
10
9
|
|
11
10
|
def local_config() -> Config:
|
@@ -1,11 +1,16 @@
|
|
1
|
+
from functools import partial
|
2
|
+
from unittest.mock import Mock
|
3
|
+
|
1
4
|
import pytest
|
2
5
|
|
3
6
|
from parsl.executors import HighThroughputExecutor
|
7
|
+
from parsl.jobs.error_handlers import (
|
8
|
+
noop_error_handler,
|
9
|
+
simple_error_handler,
|
10
|
+
windowed_error_handler,
|
11
|
+
)
|
12
|
+
from parsl.jobs.states import JobState, JobStatus
|
4
13
|
from parsl.providers import LocalProvider
|
5
|
-
from unittest.mock import Mock
|
6
|
-
from parsl.jobs.states import JobStatus, JobState
|
7
|
-
from parsl.jobs.error_handlers import simple_error_handler, windowed_error_handler, noop_error_handler
|
8
|
-
from functools import partial
|
9
14
|
|
10
15
|
|
11
16
|
@pytest.mark.local
|
@@ -3,12 +3,19 @@ import threading
|
|
3
3
|
import pytest
|
4
4
|
|
5
5
|
import parsl
|
6
|
-
from parsl.channels import LocalChannel
|
7
6
|
from parsl.config import Config
|
8
7
|
from parsl.executors import HighThroughputExecutor
|
9
8
|
from parsl.launchers import SimpleLauncher
|
10
9
|
from parsl.providers import LocalProvider
|
11
10
|
|
11
|
+
# Timing notes:
|
12
|
+
# The configured strategy_period must be much smaller than the delay in
|
13
|
+
# app() so that multiple iterations of the strategy have had a chance
|
14
|
+
# to (mis)behave.
|
15
|
+
# The status polling interval in OneShotLocalProvider must be much bigger
|
16
|
+
# than the above times, so that the job status cached from the provider
|
17
|
+
# will not be updated while the single invocation of app() runs.
|
18
|
+
|
12
19
|
|
13
20
|
@parsl.python_app
|
14
21
|
def app():
|
@@ -35,7 +42,6 @@ def test_one_block(tmpd_cwd):
|
|
35
42
|
one app is invoked. this is a regression test.
|
36
43
|
"""
|
37
44
|
oneshot_provider = OneShotLocalProvider(
|
38
|
-
channel=LocalChannel(),
|
39
45
|
init_blocks=0,
|
40
46
|
min_blocks=0,
|
41
47
|
max_blocks=10,
|
@@ -55,20 +61,10 @@ def test_one_block(tmpd_cwd):
|
|
55
61
|
)
|
56
62
|
],
|
57
63
|
strategy='simple',
|
64
|
+
strategy_period=0.1
|
58
65
|
)
|
59
66
|
|
60
|
-
parsl.load(config)
|
61
|
-
|
62
|
-
|
63
|
-
def poller():
|
64
|
-
import time
|
65
|
-
while True:
|
66
|
-
dfk.job_status_poller.poll()
|
67
|
-
time.sleep(0.1)
|
68
|
-
|
69
|
-
threading.Thread(target=poller, daemon=True).start()
|
70
|
-
app().result()
|
71
|
-
parsl.dfk().cleanup()
|
72
|
-
parsl.clear()
|
67
|
+
with parsl.load(config):
|
68
|
+
app().result()
|
73
69
|
|
74
70
|
assert oneshot_provider.recorded_submits == 1
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import time
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
import parsl
|
6
|
+
from parsl.config import Config
|
7
|
+
from parsl.executors import HighThroughputExecutor
|
8
|
+
from parsl.launchers import WrappedLauncher
|
9
|
+
from parsl.providers import LocalProvider
|
10
|
+
|
11
|
+
|
12
|
+
def local_config():
|
13
|
+
# see the comments inside test_regression for reasoning about why each
|
14
|
+
# of these parameters is set why it is.
|
15
|
+
return Config(
|
16
|
+
max_idletime=1,
|
17
|
+
|
18
|
+
strategy='htex_auto_scale',
|
19
|
+
strategy_period=1,
|
20
|
+
|
21
|
+
executors=[
|
22
|
+
HighThroughputExecutor(
|
23
|
+
label="htex_local",
|
24
|
+
encrypted=True,
|
25
|
+
provider=LocalProvider(
|
26
|
+
init_blocks=1,
|
27
|
+
min_blocks=0,
|
28
|
+
max_blocks=1,
|
29
|
+
launcher=WrappedLauncher(prepend="sleep inf ; "),
|
30
|
+
),
|
31
|
+
)
|
32
|
+
],
|
33
|
+
)
|
34
|
+
|
35
|
+
|
36
|
+
@parsl.python_app
|
37
|
+
def task():
|
38
|
+
return 7
|
39
|
+
|
40
|
+
|
41
|
+
@pytest.mark.local
|
42
|
+
def test_regression(try_assert):
|
43
|
+
# The above config means that we should start scaling out one initial
|
44
|
+
# block, but then scale it back in after a second or so if the executor
|
45
|
+
# is kept idle (which this test does using try_assert).
|
46
|
+
|
47
|
+
# Because of 'sleep inf' in the WrappedLaucher, the block will not ever
|
48
|
+
# register.
|
49
|
+
|
50
|
+
# The bug being tested is about mistreatment of blocks which are scaled in
|
51
|
+
# before they have a chance to register, and the above forces that to
|
52
|
+
# happen.
|
53
|
+
|
54
|
+
# After that scaling in has happened, we should see that we have one block
|
55
|
+
# and it should be in a terminal state. The below try_assert waits for
|
56
|
+
# that to become true.
|
57
|
+
|
58
|
+
# At that time, we should also see htex reporting no blocks registered - as
|
59
|
+
# mentioned above, that is a necessary part of the bug being tested here.
|
60
|
+
|
61
|
+
# Give 10 strategy periods for the above to happen: each step of scale up,
|
62
|
+
# and scale down due to idleness isn't guaranteed to happen in exactly one
|
63
|
+
# scaling step.
|
64
|
+
|
65
|
+
htex = parsl.dfk().executors['htex_local']
|
66
|
+
|
67
|
+
try_assert(lambda: len(htex.status_facade) == 1 and htex.status_facade['0'].terminal,
|
68
|
+
timeout_ms=10000)
|
69
|
+
|
70
|
+
assert htex.connected_blocks() == [], "No block should have connected to interchange"
|
71
|
+
|
72
|
+
# Now we can reconfigure the launcher to let subsequent blocks launch ok,
|
73
|
+
# and run a trivial task. That trivial task will scale up a new block and
|
74
|
+
# run the task successfully.
|
75
|
+
|
76
|
+
# Prior to issue #3568, the bug was that the scale in of the first
|
77
|
+
# block earlier in the test case would have incorrectly been treated as a
|
78
|
+
# failure, and then the block error handler would have treated that failure
|
79
|
+
# as a permanent htex failure, and so the task execution below would raise
|
80
|
+
# a BadStateException rather than attempt to run the task.
|
81
|
+
|
82
|
+
assert htex.provider.launcher.prepend != "", "Pre-req: prepend attribute should exist and be non-empty"
|
83
|
+
htex.provider.launcher.prepend = ""
|
84
|
+
assert task().result() == 7
|