parsl 2024.3.18__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.
Files changed (369) hide show
  1. parsl/__init__.py +9 -10
  2. parsl/addresses.py +26 -6
  3. parsl/app/app.py +7 -8
  4. parsl/app/bash.py +15 -8
  5. parsl/app/errors.py +10 -13
  6. parsl/app/futures.py +8 -10
  7. parsl/app/python.py +2 -1
  8. parsl/benchmark/perf.py +2 -1
  9. parsl/concurrent/__init__.py +2 -2
  10. parsl/config.py +53 -10
  11. parsl/configs/ASPIRE1.py +6 -5
  12. parsl/configs/Azure.py +9 -8
  13. parsl/configs/bridges.py +6 -4
  14. parsl/configs/cc_in2p3.py +3 -3
  15. parsl/configs/ec2.py +3 -1
  16. parsl/configs/expanse.py +4 -3
  17. parsl/configs/frontera.py +3 -4
  18. parsl/configs/htex_local.py +3 -4
  19. parsl/configs/illinoiscluster.py +3 -1
  20. parsl/configs/improv.py +34 -0
  21. parsl/configs/kubernetes.py +4 -3
  22. parsl/configs/local_threads.py +5 -1
  23. parsl/configs/midway.py +5 -3
  24. parsl/configs/osg.py +4 -2
  25. parsl/configs/polaris.py +4 -2
  26. parsl/configs/stampede2.py +6 -5
  27. parsl/configs/summit.py +3 -3
  28. parsl/configs/toss3_llnl.py +4 -3
  29. parsl/configs/vineex_local.py +6 -4
  30. parsl/configs/wqex_local.py +5 -3
  31. parsl/curvezmq.py +4 -0
  32. parsl/data_provider/data_manager.py +4 -3
  33. parsl/data_provider/file_noop.py +1 -2
  34. parsl/data_provider/files.py +3 -3
  35. parsl/data_provider/ftp.py +1 -3
  36. parsl/data_provider/globus.py +7 -6
  37. parsl/data_provider/http.py +2 -2
  38. parsl/data_provider/rsync.py +1 -1
  39. parsl/data_provider/staging.py +2 -2
  40. parsl/data_provider/zip.py +135 -0
  41. parsl/dataflow/dependency_resolvers.py +115 -0
  42. parsl/dataflow/dflow.py +259 -223
  43. parsl/dataflow/errors.py +3 -5
  44. parsl/dataflow/futures.py +27 -14
  45. parsl/dataflow/memoization.py +5 -5
  46. parsl/dataflow/rundirs.py +5 -6
  47. parsl/dataflow/taskrecord.py +4 -5
  48. parsl/executors/__init__.py +4 -2
  49. parsl/executors/base.py +45 -15
  50. parsl/executors/errors.py +13 -0
  51. parsl/executors/execute_task.py +37 -0
  52. parsl/executors/flux/execute_parsl_task.py +3 -3
  53. parsl/executors/flux/executor.py +18 -19
  54. parsl/executors/flux/flux_instance_manager.py +26 -27
  55. parsl/executors/high_throughput/errors.py +43 -3
  56. parsl/executors/high_throughput/executor.py +307 -285
  57. parsl/executors/high_throughput/interchange.py +137 -168
  58. parsl/executors/high_throughput/manager_record.py +4 -0
  59. parsl/executors/high_throughput/manager_selector.py +55 -0
  60. parsl/executors/high_throughput/monitoring_info.py +2 -1
  61. parsl/executors/high_throughput/mpi_executor.py +113 -0
  62. parsl/executors/high_throughput/mpi_prefix_composer.py +10 -11
  63. parsl/executors/high_throughput/mpi_resource_management.py +6 -17
  64. parsl/executors/high_throughput/probe.py +9 -7
  65. parsl/executors/high_throughput/process_worker_pool.py +77 -75
  66. parsl/executors/high_throughput/zmq_pipes.py +81 -23
  67. parsl/executors/radical/executor.py +130 -79
  68. parsl/executors/radical/rpex_resources.py +17 -15
  69. parsl/executors/radical/rpex_worker.py +4 -3
  70. parsl/executors/status_handling.py +157 -51
  71. parsl/executors/taskvine/__init__.py +1 -1
  72. parsl/executors/taskvine/errors.py +1 -1
  73. parsl/executors/taskvine/exec_parsl_function.py +2 -2
  74. parsl/executors/taskvine/executor.py +38 -55
  75. parsl/executors/taskvine/factory.py +1 -1
  76. parsl/executors/taskvine/factory_config.py +1 -1
  77. parsl/executors/taskvine/manager.py +17 -13
  78. parsl/executors/taskvine/manager_config.py +7 -2
  79. parsl/executors/threads.py +6 -6
  80. parsl/executors/workqueue/errors.py +1 -1
  81. parsl/executors/workqueue/exec_parsl_function.py +6 -5
  82. parsl/executors/workqueue/executor.py +64 -63
  83. parsl/executors/workqueue/parsl_coprocess.py +1 -1
  84. parsl/jobs/error_handlers.py +2 -2
  85. parsl/jobs/job_status_poller.py +28 -112
  86. parsl/jobs/states.py +7 -2
  87. parsl/jobs/strategy.py +43 -31
  88. parsl/launchers/__init__.py +12 -3
  89. parsl/launchers/errors.py +1 -1
  90. parsl/launchers/launchers.py +0 -6
  91. parsl/log_utils.py +1 -2
  92. parsl/monitoring/db_manager.py +55 -93
  93. parsl/monitoring/errors.py +6 -0
  94. parsl/monitoring/monitoring.py +85 -311
  95. parsl/monitoring/queries/pandas.py +1 -2
  96. parsl/monitoring/radios/base.py +13 -0
  97. parsl/monitoring/radios/filesystem.py +52 -0
  98. parsl/monitoring/radios/htex.py +57 -0
  99. parsl/monitoring/radios/multiprocessing.py +17 -0
  100. parsl/monitoring/radios/udp.py +56 -0
  101. parsl/monitoring/radios/zmq.py +17 -0
  102. parsl/monitoring/remote.py +33 -37
  103. parsl/monitoring/router.py +212 -0
  104. parsl/monitoring/types.py +5 -6
  105. parsl/monitoring/visualization/app.py +4 -2
  106. parsl/monitoring/visualization/models.py +0 -1
  107. parsl/monitoring/visualization/plots/default/workflow_plots.py +8 -4
  108. parsl/monitoring/visualization/plots/default/workflow_resource_plots.py +1 -0
  109. parsl/monitoring/visualization/utils.py +0 -1
  110. parsl/monitoring/visualization/views.py +16 -9
  111. parsl/multiprocessing.py +0 -1
  112. parsl/process_loggers.py +1 -2
  113. parsl/providers/__init__.py +8 -17
  114. parsl/providers/aws/aws.py +2 -3
  115. parsl/providers/azure/azure.py +4 -5
  116. parsl/providers/base.py +2 -18
  117. parsl/providers/cluster_provider.py +3 -9
  118. parsl/providers/condor/condor.py +7 -17
  119. parsl/providers/errors.py +2 -2
  120. parsl/providers/googlecloud/googlecloud.py +2 -1
  121. parsl/providers/grid_engine/grid_engine.py +5 -14
  122. parsl/providers/kubernetes/kube.py +80 -40
  123. parsl/providers/local/local.py +13 -26
  124. parsl/providers/lsf/lsf.py +5 -23
  125. parsl/providers/pbspro/pbspro.py +5 -17
  126. parsl/providers/slurm/slurm.py +81 -39
  127. parsl/providers/torque/torque.py +3 -14
  128. parsl/serialize/__init__.py +8 -3
  129. parsl/serialize/base.py +1 -2
  130. parsl/serialize/concretes.py +5 -4
  131. parsl/serialize/facade.py +3 -3
  132. parsl/serialize/proxystore.py +3 -2
  133. parsl/tests/__init__.py +1 -1
  134. parsl/tests/configs/azure_single_node.py +4 -5
  135. parsl/tests/configs/bridges.py +3 -2
  136. parsl/tests/configs/cc_in2p3.py +1 -3
  137. parsl/tests/configs/comet.py +2 -1
  138. parsl/tests/configs/ec2_single_node.py +1 -2
  139. parsl/tests/configs/ec2_spot.py +1 -2
  140. parsl/tests/configs/flux_local.py +11 -0
  141. parsl/tests/configs/frontera.py +2 -3
  142. parsl/tests/configs/htex_local.py +3 -5
  143. parsl/tests/configs/htex_local_alternate.py +11 -15
  144. parsl/tests/configs/htex_local_intask_staging.py +5 -9
  145. parsl/tests/configs/htex_local_rsync_staging.py +4 -8
  146. parsl/tests/configs/local_radical.py +1 -3
  147. parsl/tests/configs/local_radical_mpi.py +2 -2
  148. parsl/tests/configs/local_threads_checkpoint_periodic.py +8 -10
  149. parsl/tests/configs/local_threads_monitoring.py +0 -1
  150. parsl/tests/configs/midway.py +2 -2
  151. parsl/tests/configs/nscc_singapore.py +3 -3
  152. parsl/tests/configs/osg_htex.py +1 -1
  153. parsl/tests/configs/petrelkube.py +3 -2
  154. parsl/tests/configs/slurm_local.py +24 -0
  155. parsl/tests/configs/summit.py +1 -0
  156. parsl/tests/configs/taskvine_ex.py +4 -7
  157. parsl/tests/configs/user_opts.py +0 -7
  158. parsl/tests/configs/workqueue_ex.py +4 -6
  159. parsl/tests/conftest.py +27 -13
  160. parsl/tests/integration/test_stress/test_python_simple.py +3 -4
  161. parsl/tests/integration/test_stress/test_python_threads.py +3 -5
  162. parsl/tests/manual_tests/htex_local.py +4 -6
  163. parsl/tests/manual_tests/test_basic.py +1 -0
  164. parsl/tests/manual_tests/test_log_filter.py +3 -1
  165. parsl/tests/manual_tests/test_memory_limits.py +6 -8
  166. parsl/tests/manual_tests/test_regression_220.py +2 -1
  167. parsl/tests/manual_tests/test_udp_simple.py +4 -4
  168. parsl/tests/manual_tests/test_worker_count.py +3 -2
  169. parsl/tests/scaling_tests/htex_local.py +2 -4
  170. parsl/tests/scaling_tests/test_scale.py +0 -9
  171. parsl/tests/scaling_tests/vineex_condor.py +1 -2
  172. parsl/tests/scaling_tests/vineex_local.py +1 -2
  173. parsl/tests/site_tests/site_config_selector.py +1 -6
  174. parsl/tests/site_tests/test_provider.py +4 -2
  175. parsl/tests/site_tests/test_site.py +2 -0
  176. parsl/tests/sites/test_affinity.py +7 -7
  177. parsl/tests/sites/test_dynamic_executor.py +3 -4
  178. parsl/tests/sites/test_ec2.py +3 -2
  179. parsl/tests/sites/test_worker_info.py +4 -5
  180. parsl/tests/test_aalst_patterns.py +0 -1
  181. parsl/tests/test_bash_apps/test_apptimeout.py +2 -2
  182. parsl/tests/test_bash_apps/test_basic.py +10 -4
  183. parsl/tests/test_bash_apps/test_error_codes.py +5 -7
  184. parsl/tests/test_bash_apps/test_inputs_default.py +25 -0
  185. parsl/tests/test_bash_apps/test_kwarg_storage.py +1 -1
  186. parsl/tests/test_bash_apps/test_memoize.py +2 -8
  187. parsl/tests/test_bash_apps/test_memoize_ignore_args.py +9 -14
  188. parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +9 -14
  189. parsl/tests/test_bash_apps/test_multiline.py +1 -1
  190. parsl/tests/test_bash_apps/test_pipeline.py +1 -1
  191. parsl/tests/test_bash_apps/test_std_uri.py +123 -0
  192. parsl/tests/test_bash_apps/test_stdout.py +33 -8
  193. parsl/tests/test_callables.py +2 -2
  194. parsl/tests/test_checkpointing/test_periodic.py +21 -39
  195. parsl/tests/test_checkpointing/test_python_checkpoint_1.py +1 -0
  196. parsl/tests/test_checkpointing/test_python_checkpoint_2.py +2 -2
  197. parsl/tests/test_checkpointing/test_python_checkpoint_3.py +0 -1
  198. parsl/tests/test_checkpointing/test_regression_239.py +1 -1
  199. parsl/tests/test_checkpointing/test_task_exit.py +2 -3
  200. parsl/tests/test_docs/test_from_slides.py +5 -2
  201. parsl/tests/test_docs/test_kwargs.py +4 -1
  202. parsl/tests/test_docs/test_tutorial_1.py +1 -2
  203. parsl/tests/test_docs/test_workflow1.py +2 -2
  204. parsl/tests/test_docs/test_workflow2.py +0 -1
  205. parsl/tests/test_error_handling/test_rand_fail.py +2 -2
  206. parsl/tests/test_error_handling/test_resource_spec.py +10 -12
  207. parsl/tests/test_error_handling/test_retries.py +6 -16
  208. parsl/tests/test_error_handling/test_retry_handler.py +1 -0
  209. parsl/tests/test_error_handling/test_retry_handler_failure.py +2 -1
  210. parsl/tests/test_error_handling/test_serialization_fail.py +1 -1
  211. parsl/tests/test_error_handling/test_wrap_with_logs.py +1 -0
  212. parsl/tests/test_execute_task.py +29 -0
  213. parsl/tests/test_flux.py +1 -1
  214. parsl/tests/test_htex/test_basic.py +2 -3
  215. parsl/tests/test_htex/test_block_manager_selector_unit.py +20 -0
  216. parsl/tests/test_htex/test_command_client_timeout.py +66 -0
  217. parsl/tests/test_htex/test_connected_blocks.py +3 -2
  218. parsl/tests/test_htex/test_cpu_affinity_explicit.py +6 -10
  219. parsl/tests/test_htex/test_disconnected_blocks.py +6 -5
  220. parsl/tests/test_htex/test_disconnected_blocks_failing_provider.py +71 -0
  221. parsl/tests/test_htex/test_drain.py +11 -10
  222. parsl/tests/test_htex/test_htex.py +51 -25
  223. parsl/tests/test_htex/test_manager_failure.py +0 -1
  224. parsl/tests/test_htex/test_manager_selector_by_block.py +51 -0
  225. parsl/tests/test_htex/test_managers_command.py +36 -0
  226. parsl/tests/test_htex/test_missing_worker.py +2 -12
  227. parsl/tests/test_htex/test_multiple_disconnected_blocks.py +9 -9
  228. parsl/tests/test_htex/test_resource_spec_validation.py +45 -0
  229. parsl/tests/test_htex/test_zmq_binding.py +29 -8
  230. parsl/tests/test_monitoring/test_app_names.py +5 -5
  231. parsl/tests/test_monitoring/test_basic.py +73 -25
  232. parsl/tests/test_monitoring/test_db_locks.py +6 -4
  233. parsl/tests/test_monitoring/test_fuzz_zmq.py +19 -8
  234. parsl/tests/test_monitoring/test_htex_init_blocks_vs_monitoring.py +80 -0
  235. parsl/tests/test_monitoring/test_incomplete_futures.py +5 -4
  236. parsl/tests/test_monitoring/test_memoization_representation.py +4 -2
  237. parsl/tests/test_monitoring/test_stdouterr.py +134 -0
  238. parsl/tests/test_monitoring/test_viz_colouring.py +1 -0
  239. parsl/tests/test_mpi_apps/test_bad_mpi_config.py +33 -26
  240. parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py +28 -11
  241. parsl/tests/test_mpi_apps/test_mpi_prefix.py +4 -4
  242. parsl/tests/test_mpi_apps/test_mpi_scheduler.py +7 -2
  243. parsl/tests/test_mpi_apps/test_mpiex.py +64 -0
  244. parsl/tests/test_mpi_apps/test_resource_spec.py +42 -49
  245. parsl/tests/test_providers/test_kubernetes_provider.py +102 -0
  246. parsl/tests/test_providers/test_local_provider.py +3 -132
  247. parsl/tests/test_providers/test_pbspro_template.py +2 -3
  248. parsl/tests/test_providers/test_slurm_template.py +2 -3
  249. parsl/tests/test_providers/test_submiterror_deprecation.py +2 -1
  250. parsl/tests/test_python_apps/test_context_manager.py +128 -0
  251. parsl/tests/test_python_apps/test_dep_standard_futures.py +2 -1
  252. parsl/tests/test_python_apps/test_dependencies_deep.py +59 -0
  253. parsl/tests/test_python_apps/test_fail.py +0 -25
  254. parsl/tests/test_python_apps/test_futures.py +2 -1
  255. parsl/tests/test_python_apps/test_inputs_default.py +22 -0
  256. parsl/tests/test_python_apps/test_join.py +0 -1
  257. parsl/tests/test_python_apps/test_lifted.py +11 -7
  258. parsl/tests/test_python_apps/test_memoize_bad_id_for_memo.py +1 -0
  259. parsl/tests/test_python_apps/test_outputs.py +1 -1
  260. parsl/tests/test_python_apps/test_pluggable_future_resolution.py +161 -0
  261. parsl/tests/test_radical/test_mpi_funcs.py +1 -2
  262. parsl/tests/test_regression/test_1480.py +2 -1
  263. parsl/tests/test_regression/test_1653.py +2 -1
  264. parsl/tests/test_regression/test_226.py +1 -0
  265. parsl/tests/test_regression/test_2652.py +1 -0
  266. parsl/tests/test_regression/test_69a.py +0 -1
  267. parsl/tests/test_regression/test_854.py +4 -2
  268. parsl/tests/test_regression/test_97_parallelism_0.py +1 -2
  269. parsl/tests/test_regression/test_98.py +0 -1
  270. parsl/tests/test_scaling/test_block_error_handler.py +9 -4
  271. parsl/tests/test_scaling/test_regression_1621.py +11 -15
  272. parsl/tests/test_scaling/test_regression_3568_scaledown_vs_MISSING.py +84 -0
  273. parsl/tests/test_scaling/test_regression_3696_oscillation.py +103 -0
  274. parsl/tests/test_scaling/test_scale_down.py +2 -5
  275. parsl/tests/test_scaling/test_scale_down_htex_auto_scale.py +5 -8
  276. parsl/tests/test_scaling/test_scale_down_htex_unregistered.py +71 -0
  277. parsl/tests/test_scaling/test_shutdown_scalein.py +73 -0
  278. parsl/tests/test_scaling/test_worker_interchange_bad_messages_3262.py +90 -0
  279. parsl/tests/test_serialization/test_2555_caching_deserializer.py +1 -1
  280. parsl/tests/test_serialization/test_3495_deserialize_managerlost.py +47 -0
  281. parsl/tests/test_serialization/test_basic.py +2 -1
  282. parsl/tests/test_serialization/test_htex_code_cache.py +3 -4
  283. parsl/tests/test_serialization/test_pack_resource_spec.py +2 -1
  284. parsl/tests/test_serialization/test_proxystore_configured.py +10 -6
  285. parsl/tests/test_serialization/test_proxystore_impl.py +5 -3
  286. parsl/tests/test_shutdown/test_kill_monitoring.py +64 -0
  287. parsl/tests/test_staging/staging_provider.py +2 -2
  288. parsl/tests/test_staging/test_1316.py +3 -4
  289. parsl/tests/test_staging/test_docs_1.py +2 -1
  290. parsl/tests/test_staging/test_docs_2.py +2 -1
  291. parsl/tests/test_staging/test_elaborate_noop_file.py +2 -3
  292. parsl/tests/{test_data → test_staging}/test_file.py +6 -6
  293. parsl/tests/{test_data → test_staging}/test_output_chain_filenames.py +3 -0
  294. parsl/tests/test_staging/test_staging_ftp.py +1 -0
  295. parsl/tests/test_staging/test_staging_https.py +5 -2
  296. parsl/tests/test_staging/test_staging_stdout.py +64 -0
  297. parsl/tests/test_staging/test_zip_in.py +39 -0
  298. parsl/tests/test_staging/test_zip_out.py +110 -0
  299. parsl/tests/test_staging/test_zip_to_zip.py +41 -0
  300. parsl/tests/test_summary.py +2 -2
  301. parsl/tests/test_thread_parallelism.py +0 -1
  302. parsl/tests/test_threads/test_configs.py +1 -2
  303. parsl/tests/test_threads/test_lazy_errors.py +2 -2
  304. parsl/tests/test_utils/test_execute_wait.py +35 -0
  305. parsl/tests/test_utils/test_sanitize_dns.py +76 -0
  306. parsl/tests/unit/test_address.py +20 -0
  307. parsl/tests/unit/test_file.py +99 -0
  308. parsl/tests/unit/test_usage_tracking.py +66 -0
  309. parsl/usage_tracking/api.py +65 -0
  310. parsl/usage_tracking/levels.py +6 -0
  311. parsl/usage_tracking/usage.py +104 -62
  312. parsl/utils.py +137 -4
  313. parsl/version.py +1 -1
  314. {parsl-2024.3.18.data → parsl-2025.1.13.data}/scripts/exec_parsl_function.py +6 -5
  315. parsl-2025.1.13.data/scripts/interchange.py +649 -0
  316. {parsl-2024.3.18.data → parsl-2025.1.13.data}/scripts/process_worker_pool.py +77 -75
  317. parsl-2025.1.13.dist-info/METADATA +96 -0
  318. parsl-2025.1.13.dist-info/RECORD +462 -0
  319. {parsl-2024.3.18.dist-info → parsl-2025.1.13.dist-info}/WHEEL +1 -1
  320. parsl/channels/__init__.py +0 -7
  321. parsl/channels/base.py +0 -141
  322. parsl/channels/errors.py +0 -113
  323. parsl/channels/local/local.py +0 -164
  324. parsl/channels/oauth_ssh/oauth_ssh.py +0 -110
  325. parsl/channels/ssh/ssh.py +0 -276
  326. parsl/channels/ssh_il/__init__.py +0 -0
  327. parsl/channels/ssh_il/ssh_il.py +0 -74
  328. parsl/configs/ad_hoc.py +0 -35
  329. parsl/executors/radical/rpex_master.py +0 -42
  330. parsl/monitoring/radios.py +0 -175
  331. parsl/providers/ad_hoc/__init__.py +0 -0
  332. parsl/providers/ad_hoc/ad_hoc.py +0 -248
  333. parsl/providers/cobalt/__init__.py +0 -0
  334. parsl/providers/cobalt/cobalt.py +0 -236
  335. parsl/providers/cobalt/template.py +0 -17
  336. parsl/tests/configs/ad_hoc_cluster_htex.py +0 -35
  337. parsl/tests/configs/cooley_htex.py +0 -37
  338. parsl/tests/configs/htex_ad_hoc_cluster.py +0 -28
  339. parsl/tests/configs/local_adhoc.py +0 -18
  340. parsl/tests/configs/swan_htex.py +0 -43
  341. parsl/tests/configs/theta.py +0 -37
  342. parsl/tests/integration/test_channels/__init__.py +0 -0
  343. parsl/tests/integration/test_channels/test_channels.py +0 -17
  344. parsl/tests/integration/test_channels/test_local_channel.py +0 -42
  345. parsl/tests/integration/test_channels/test_scp_1.py +0 -45
  346. parsl/tests/integration/test_channels/test_ssh_1.py +0 -40
  347. parsl/tests/integration/test_channels/test_ssh_errors.py +0 -46
  348. parsl/tests/integration/test_channels/test_ssh_file_transport.py +0 -41
  349. parsl/tests/integration/test_channels/test_ssh_interactive.py +0 -24
  350. parsl/tests/manual_tests/test_ad_hoc_htex.py +0 -48
  351. parsl/tests/manual_tests/test_fan_in_out_htex_remote.py +0 -88
  352. parsl/tests/manual_tests/test_oauth_ssh.py +0 -13
  353. parsl/tests/sites/test_local_adhoc.py +0 -61
  354. parsl/tests/test_channels/__init__.py +0 -0
  355. parsl/tests/test_channels/test_large_output.py +0 -22
  356. parsl/tests/test_data/__init__.py +0 -0
  357. parsl/tests/test_mpi_apps/test_mpi_mode_disabled.py +0 -51
  358. parsl/tests/test_providers/test_cobalt_deprecation_warning.py +0 -16
  359. parsl-2024.3.18.dist-info/METADATA +0 -98
  360. parsl-2024.3.18.dist-info/RECORD +0 -449
  361. parsl/{channels/local → monitoring/radios}/__init__.py +0 -0
  362. parsl/{channels/oauth_ssh → tests/test_shutdown}/__init__.py +0 -0
  363. parsl/tests/{test_data → test_staging}/test_file_apps.py +0 -0
  364. parsl/tests/{test_data → test_staging}/test_file_staging.py +0 -0
  365. parsl/{channels/ssh → tests/unit}/__init__.py +0 -0
  366. {parsl-2024.3.18.data → parsl-2025.1.13.data}/scripts/parsl_coprocess.py +1 -1
  367. {parsl-2024.3.18.dist-info → parsl-2025.1.13.dist-info}/LICENSE +0 -0
  368. {parsl-2024.3.18.dist-info → parsl-2025.1.13.dist-info}/entry_points.txt +0 -0
  369. {parsl-2024.3.18.dist-info → parsl-2025.1.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,71 @@
1
+ import logging
2
+ import time
3
+
4
+ import pytest
5
+
6
+ import parsl
7
+ from parsl import File, python_app
8
+ from parsl.config import Config
9
+ from parsl.executors import HighThroughputExecutor
10
+ from parsl.jobs.states import TERMINAL_STATES, JobState
11
+ from parsl.launchers import SingleNodeLauncher
12
+ from parsl.providers import LocalProvider
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ _max_blocks = 1
17
+ _min_blocks = 0
18
+
19
+
20
+ def local_config():
21
+ return Config(
22
+ executors=[
23
+ HighThroughputExecutor(
24
+ heartbeat_period=1,
25
+ heartbeat_threshold=2,
26
+ poll_period=100,
27
+ label="htex_local",
28
+ address="127.0.0.1",
29
+ max_workers_per_node=1,
30
+ encrypted=True,
31
+ launch_cmd="sleep inf",
32
+ provider=LocalProvider(
33
+ init_blocks=1,
34
+ max_blocks=_max_blocks,
35
+ min_blocks=_min_blocks,
36
+ launcher=SingleNodeLauncher(),
37
+ ),
38
+ )
39
+ ],
40
+ max_idletime=0.5,
41
+ strategy='htex_auto_scale',
42
+ strategy_period=0.1
43
+ )
44
+
45
+
46
+ # see issue #1885 for details of failures of this test.
47
+ # at the time of issue #1885 this test was failing frequently
48
+ # in CI.
49
+ @pytest.mark.local
50
+ def test_scaledown_with_register(try_assert):
51
+ dfk = parsl.dfk()
52
+ htex = dfk.executors['htex_local']
53
+
54
+ num_managers = len(htex.connected_managers())
55
+ assert num_managers == 0, "Expected 0 managers at start"
56
+
57
+ try_assert(lambda: len(htex.status()),
58
+ fail_msg="Expected 1 block at start")
59
+
60
+ s = htex.status()
61
+ assert s['0'].state == JobState.RUNNING, "Expected block to be in RUNNING"
62
+
63
+ def check_zero_blocks():
64
+ s = htex.status()
65
+ return len(s) == 1 and s['0'].state in TERMINAL_STATES
66
+
67
+ try_assert(
68
+ check_zero_blocks,
69
+ fail_msg="Expected 0 blocks after idle scaledown",
70
+ timeout_ms=15000,
71
+ )
@@ -0,0 +1,73 @@
1
+ import random
2
+ import threading
3
+
4
+ import pytest
5
+
6
+ import parsl
7
+ from parsl.config import Config
8
+ from parsl.executors import HighThroughputExecutor
9
+ from parsl.launchers import SimpleLauncher
10
+ from parsl.providers import LocalProvider
11
+
12
+ # we need some blocks, but it doesn't matter too much how many, as long
13
+ # as they can all start up and get registered within the try_assert
14
+ # timeout later on.
15
+ BLOCK_COUNT = 3
16
+
17
+
18
+ class AccumulatingLocalProvider(LocalProvider):
19
+ def __init__(self, *args, **kwargs):
20
+ # Use a list for submitted job IDs because if there are multiple
21
+ # submissions returning the same job ID, this test should count
22
+ # those...
23
+ self.submit_job_ids = []
24
+
25
+ # ... but there's no requirement, I think, that cancel must be called
26
+ # only once per job id. What matters here is that each job ID is
27
+ # cancelled at least once.
28
+ self.cancel_job_ids = set()
29
+
30
+ super().__init__(*args, **kwargs)
31
+
32
+ def submit(self, *args, **kwargs):
33
+ job_id = super().submit(*args, **kwargs)
34
+ self.submit_job_ids.append(job_id)
35
+ return job_id
36
+
37
+ def cancel(self, job_ids):
38
+ self.cancel_job_ids.update(job_ids)
39
+ return super().cancel(job_ids)
40
+
41
+
42
+ @pytest.mark.local
43
+ def test_shutdown_scalein_blocks(tmpd_cwd, try_assert):
44
+ """
45
+ This test scales up several blocks, and then checks that they are all
46
+ scaled in at DFK shutdown.
47
+ """
48
+ accumulating_provider = AccumulatingLocalProvider(
49
+ init_blocks=BLOCK_COUNT,
50
+ min_blocks=0,
51
+ max_blocks=0,
52
+ launcher=SimpleLauncher(),
53
+ )
54
+
55
+ htex = HighThroughputExecutor(
56
+ label="htex_local",
57
+ cores_per_worker=1,
58
+ provider=accumulating_provider
59
+ )
60
+
61
+ config = Config(
62
+ executors=[htex],
63
+ strategy='none',
64
+ strategy_period=0.1,
65
+ run_dir=str(tmpd_cwd)
66
+ )
67
+
68
+ with parsl.load(config):
69
+ # this will wait for everything to be scaled out fully
70
+ try_assert(lambda: len(htex.connected_managers()) == BLOCK_COUNT)
71
+
72
+ assert len(accumulating_provider.submit_job_ids) == BLOCK_COUNT, f"Exactly {BLOCK_COUNT} blocks should have been launched"
73
+ assert len(accumulating_provider.cancel_job_ids) == BLOCK_COUNT, f"Exactly {BLOCK_COUNT} blocks should have been scaled in"
@@ -0,0 +1,90 @@
1
+ import os
2
+ import signal
3
+ import time
4
+
5
+ import pytest
6
+ import zmq
7
+
8
+ import parsl
9
+ from parsl.config import Config
10
+ from parsl.executors import HighThroughputExecutor
11
+ from parsl.launchers import SimpleLauncher
12
+ from parsl.providers import LocalProvider
13
+
14
+ T_s = 1
15
+
16
+
17
+ def fresh_config():
18
+ htex = HighThroughputExecutor(
19
+ heartbeat_period=1 * T_s,
20
+ heartbeat_threshold=3 * T_s,
21
+ label="htex_local",
22
+ worker_debug=True,
23
+ cores_per_worker=1,
24
+ encrypted=False,
25
+ provider=LocalProvider(
26
+ init_blocks=0,
27
+ min_blocks=0,
28
+ max_blocks=0,
29
+ launcher=SimpleLauncher(),
30
+ ),
31
+ )
32
+ c = Config(
33
+ executors=[htex],
34
+ strategy='none',
35
+ strategy_period=0.5,
36
+ )
37
+ return c, htex
38
+
39
+
40
+ @parsl.python_app
41
+ def app():
42
+ return 7
43
+
44
+
45
+ @pytest.mark.local
46
+ @pytest.mark.parametrize("msg",
47
+ (b'FuzzyByte\rSTREAM', # not JSON
48
+ b'{}', # missing fields
49
+ b'{"type":"heartbeat"}', # regression test #3262
50
+ )
51
+ )
52
+ def test_bad_messages(try_assert, msg):
53
+ """This tests that the interchange is resilient to a few different bad
54
+ messages: malformed messages caused by implementation errors, and
55
+ heartbeat messages from managers that are not registered.
56
+
57
+ The heartbeat test is a regression test for issues #3262, #3632
58
+ """
59
+
60
+ c, htex = fresh_config()
61
+
62
+ with parsl.load(c):
63
+
64
+ # send a bad message into the interchange on the task_outgoing worker
65
+ # channel, and then check that the interchange is still alive enough
66
+ # that we can scale out a block and run a task.
67
+
68
+ (task_port, result_port) = htex.command_client.run("WORKER_PORTS")
69
+
70
+ context = zmq.Context()
71
+ channel_timeout = 10000 # in milliseconds
72
+ task_channel = context.socket(zmq.DEALER)
73
+ task_channel.setsockopt(zmq.LINGER, 0)
74
+ task_channel.setsockopt(zmq.IDENTITY, b'testid')
75
+
76
+ task_channel.set_hwm(0)
77
+ task_channel.setsockopt(zmq.SNDTIMEO, channel_timeout)
78
+ task_channel.connect(f"tcp://localhost:{task_port}")
79
+
80
+ task_channel.send(msg)
81
+
82
+ # If the interchange exits, it's likely that this test will hang rather
83
+ # than raise an error, because the interchange interaction code
84
+ # assumes the interchange is always there.
85
+ # In the case of issue #3262, an exception message goes to stderr, and
86
+ # no error goes to the interchange log file.
87
+ htex.scale_out_facade(1)
88
+ try_assert(lambda: len(htex.connected_managers()) == 1, timeout_ms=10000)
89
+
90
+ assert app().result() == 7
@@ -1,6 +1,6 @@
1
- import parsl
2
1
  import pytest
3
2
 
3
+ import parsl
4
4
  from parsl.tests.configs.htex_local import fresh_config as local_config
5
5
 
6
6
 
@@ -0,0 +1,47 @@
1
+ import os
2
+ import signal
3
+
4
+ import pytest
5
+
6
+ import parsl
7
+ from parsl import Config, HighThroughputExecutor
8
+ from parsl.executors.high_throughput.errors import ManagerLost
9
+
10
+
11
+ @parsl.python_app
12
+ def get_manager_pgid():
13
+ import os
14
+ return os.getpgid(os.getpid())
15
+
16
+
17
+ @parsl.python_app
18
+ def lose_manager():
19
+ import os
20
+ import signal
21
+
22
+ manager_pid = os.getppid()
23
+ os.kill(manager_pid, signal.SIGSTOP)
24
+
25
+
26
+ @pytest.mark.local
27
+ def test_manager_lost_system_failure(tmpd_cwd):
28
+ hte = HighThroughputExecutor(
29
+ label="htex_local",
30
+ address="127.0.0.1",
31
+ max_workers_per_node=2,
32
+ cores_per_worker=1,
33
+ worker_logdir_root=str(tmpd_cwd),
34
+ heartbeat_period=1,
35
+ heartbeat_threshold=3,
36
+ )
37
+ c = Config(executors=[hte], strategy='simple', strategy_period=0.1)
38
+
39
+ with parsl.load(c):
40
+ manager_pgid = get_manager_pgid().result()
41
+ try:
42
+ with pytest.raises(ManagerLost):
43
+ lose_manager().result()
44
+ finally:
45
+ # Allow process to clean itself up
46
+ os.killpg(manager_pgid, signal.SIGCONT)
47
+ os.killpg(manager_pgid, signal.SIGTERM)
@@ -1,5 +1,6 @@
1
1
  import pytest
2
- from parsl.serialize import serialize, deserialize
2
+
3
+ from parsl.serialize import deserialize, serialize
3
4
  from parsl.serialize.concretes import DillSerializer, PickleSerializer
4
5
 
5
6
 
@@ -1,10 +1,9 @@
1
- import parsl
2
- import pytest
3
-
4
1
  from typing import Any
5
2
 
6
- from parsl.serialize.facade import methods_for_code
3
+ import pytest
7
4
 
5
+ import parsl
6
+ from parsl.serialize.facade import methods_for_code
8
7
  from parsl.tests.configs.htex_local import fresh_config as local_config
9
8
 
10
9
 
@@ -1,5 +1,6 @@
1
1
  import pytest
2
- from parsl.serialize import unpack_res_spec_apply_message, pack_res_spec_apply_message
2
+
3
+ from parsl.serialize import pack_res_spec_apply_message, unpack_res_spec_apply_message
3
4
 
4
5
 
5
6
  def double(x: int, y: int = 2) -> int:
@@ -1,19 +1,24 @@
1
1
  import logging
2
- import pytest
3
2
  import uuid
4
3
 
4
+ import pytest
5
+
5
6
  import parsl
6
- from parsl.serialize.facade import additional_methods_for_deserialization, methods_for_data, register_method_for_data
7
+ from parsl.serialize.facade import (
8
+ additional_methods_for_deserialization,
9
+ methods_for_data,
10
+ register_method_for_data,
11
+ )
7
12
  from parsl.tests.configs.htex_local import fresh_config
8
13
 
9
-
10
14
  logger = logging.getLogger(__name__)
11
15
 
12
16
 
13
17
  def local_setup():
14
- from parsl.serialize.proxystore import ProxyStoreSerializer
15
- from proxystore.store import Store, register_store
16
18
  from proxystore.connectors.file import FileConnector
19
+ from proxystore.store import Store, register_store
20
+
21
+ from parsl.serialize.proxystore import ProxyStoreSerializer
17
22
 
18
23
  parsl.load(fresh_config())
19
24
 
@@ -38,7 +43,6 @@ def local_setup():
38
43
 
39
44
  def local_teardown():
40
45
  parsl.dfk().cleanup()
41
- parsl.clear()
42
46
 
43
47
  methods_for_data.clear()
44
48
  methods_for_data.update(previous_methods)
@@ -1,6 +1,7 @@
1
- import pytest
2
1
  import uuid
3
2
 
3
+ import pytest
4
+
4
5
 
5
6
  def policy_example(o):
6
7
  """Example policy will proxy only lists."""
@@ -13,10 +14,11 @@ def test_proxystore_nonglobal():
13
14
  """
14
15
  # import in function, because proxystore is not importable in base parsl
15
16
  # installation.
16
- from parsl.serialize.proxystore import ProxyStoreSerializer
17
+ from proxystore.connectors.file import FileConnector
17
18
  from proxystore.proxy import Proxy
18
19
  from proxystore.store import Store, register_store
19
- from proxystore.connectors.file import FileConnector
20
+
21
+ from parsl.serialize.proxystore import ProxyStoreSerializer
20
22
 
21
23
  store = Store(name='parsl_store_' + str(uuid.uuid4()), connector=FileConnector(store_dir="/tmp"))
22
24
  register_store(store)
@@ -0,0 +1,64 @@
1
+ import os
2
+ import signal
3
+ import time
4
+
5
+ import pytest
6
+
7
+ import parsl
8
+ from parsl.tests.configs.htex_local_alternate import fresh_config
9
+
10
+ # This is a very generous upper bound on expected shutdown time of target
11
+ # process after receiving a signal, measured in seconds.
12
+ PERMITTED_SHUTDOWN_TIME_S = 60
13
+
14
+
15
+ @parsl.python_app
16
+ def simple_app():
17
+ return True
18
+
19
+
20
+ @pytest.mark.local
21
+ def test_no_kills():
22
+ """This tests that we can create a monitoring-enabled DFK and shut it down."""
23
+
24
+ parsl.load(fresh_config())
25
+
26
+ assert parsl.dfk().monitoring is not None, "This test requires monitoring"
27
+
28
+ parsl.dfk().cleanup()
29
+
30
+
31
+ @pytest.mark.local
32
+ @pytest.mark.parametrize("sig", [signal.SIGINT, signal.SIGTERM, signal.SIGKILL, signal.SIGQUIT])
33
+ @pytest.mark.parametrize("process_attr", ["router_proc", "dbm_proc"])
34
+ def test_kill_monitoring_helper_process(sig, process_attr, try_assert):
35
+ """This tests that we can kill a monitoring process and still have successful shutdown.
36
+ SIGINT emulates some racy behaviour when ctrl-C is pressed: that
37
+ monitoring processes receive a ctrl-C too, and so the other processes
38
+ need to be tolerant to monitoring processes arbitrarily exiting.
39
+ """
40
+
41
+ parsl.load(fresh_config())
42
+
43
+ dfk = parsl.dfk()
44
+
45
+ assert dfk.monitoring is not None, "Monitoring required"
46
+
47
+ target_proc = getattr(dfk.monitoring, process_attr)
48
+
49
+ assert target_proc is not None, "prereq: target process must exist"
50
+ assert target_proc.is_alive(), "prereq: target process must be alive"
51
+
52
+ target_pid = target_proc.pid
53
+ assert target_pid is not None, "prereq: target process must have a pid"
54
+
55
+ os.kill(target_pid, sig)
56
+
57
+ try_assert(lambda: not target_proc.is_alive(), timeout_ms=PERMITTED_SHUTDOWN_TIME_S * 1000)
58
+
59
+ # now we have broken one piece of the monitoring system, do some app
60
+ # execution and then shut down.
61
+
62
+ simple_app().result()
63
+
64
+ parsl.dfk().cleanup()
@@ -62,8 +62,8 @@ def make_stage_out_app(executor, dfk):
62
62
 
63
63
 
64
64
  def stage_out_noop(app_fu, inputs=[], _parsl_staging_inhibit=True):
65
- import time
66
65
  import logging
66
+ import time
67
67
  logger = logging.getLogger(__name__)
68
68
  logger.info("stage_out_noop")
69
69
  time.sleep(1)
@@ -75,8 +75,8 @@ def make_stage_in_app(executor, dfk):
75
75
 
76
76
 
77
77
  def stage_in_noop(parent_fut=None, outputs=[], _parsl_staging_inhibit=True):
78
- import time
79
78
  import logging
79
+ import time
80
80
  logger = logging.getLogger(__name__)
81
81
  logger.info("stage_in_noop")
82
82
  time.sleep(1)
@@ -1,8 +1,9 @@
1
+ import time
2
+
1
3
  import pytest
2
4
 
3
5
  import parsl
4
- import time
5
- from parsl import python_app, ThreadPoolExecutor
6
+ from parsl import ThreadPoolExecutor, python_app
6
7
  from parsl.config import Config
7
8
  from parsl.data_provider.files import File
8
9
  from parsl.data_provider.staging import Staging
@@ -60,7 +61,6 @@ def test_1316_local_path_on_execution_side_sp2():
60
61
  assert not file.local_path, "The local_path on the submit side should not be set"
61
62
 
62
63
  parsl.dfk().cleanup()
63
- parsl.clear()
64
64
 
65
65
 
66
66
  @pytest.mark.local
@@ -83,4 +83,3 @@ def test_1316_local_path_setting_preserves_dependency_sp2():
83
83
  assert not file.local_path, "The local_path on the submit side should not be set"
84
84
 
85
85
  parsl.dfk().cleanup()
86
- parsl.clear()
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
 
3
- from parsl import python_app, File
3
+ from parsl import File, python_app
4
4
 
5
5
 
6
6
  @python_app
@@ -12,6 +12,7 @@ def convert(inputs=[], outputs=[]):
12
12
 
13
13
 
14
14
  @pytest.mark.cleannet
15
+ @pytest.mark.staging_required
15
16
  def test():
16
17
  # create an remote Parsl file
17
18
  inp = File('ftp://ftp.iana.org/pub/mirror/rirstats/arin/ARIN-STATS-FORMAT-CHANGE.txt')
@@ -1,5 +1,6 @@
1
1
  import pytest
2
- from parsl import bash_app, File
2
+
3
+ from parsl import File, bash_app
3
4
  from parsl.tests.configs.local_threads import fresh_config as local_config
4
5
 
5
6
 
@@ -6,15 +6,15 @@
6
6
  # of the globus staging provider
7
7
 
8
8
  import logging
9
+
9
10
  import pytest
10
11
 
11
12
  import parsl
12
-
13
13
  from parsl import bash_app, python_app
14
14
  from parsl.config import Config
15
15
  from parsl.data_provider.files import File
16
16
  from parsl.executors.threads import ThreadPoolExecutor
17
- from parsl.tests.test_staging.staging_provider import NoOpTestingFileStaging, NoOpError
17
+ from parsl.tests.test_staging.staging_provider import NoOpError, NoOpTestingFileStaging
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
 
@@ -44,7 +44,6 @@ def storage_access_parsl():
44
44
  yield _setup_config
45
45
 
46
46
  parsl.dfk().cleanup()
47
- parsl.clear()
48
47
 
49
48
 
50
49
  @pytest.mark.local
@@ -22,11 +22,11 @@ def test_files():
22
22
 
23
23
 
24
24
  @pytest.mark.local
25
- def test_open():
26
- with open('test-open.txt', 'w') as tfile:
27
- tfile.write('Hello')
25
+ def test_open(tmpd_cwd):
26
+ fpath = tmpd_cwd / 'test-open.txt'
27
+ fpath.write_text('Hello')
28
28
 
29
- pfile = File('test-open.txt')
29
+ pfile = File(fpath)
30
30
 
31
- with open(str(pfile), 'r') as opfile:
32
- assert (opfile.readlines()[0] == 'Hello')
31
+ with open(pfile) as opfile:
32
+ assert (opfile.read() == 'Hello')
@@ -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(
@@ -15,6 +15,7 @@ def sort_strings(inputs=[], outputs=[]):
15
15
 
16
16
 
17
17
  @pytest.mark.cleannet
18
+ @pytest.mark.staging_required
18
19
  def test_staging_ftp():
19
20
  """Test staging for an ftp file
20
21
 
@@ -1,9 +1,9 @@
1
+ import pytest
2
+
1
3
  import parsl
2
4
  from parsl.app.app import python_app
3
5
  from parsl.data_provider.files import File
4
6
 
5
- import pytest
6
-
7
7
  # This config is for the local test which will adding an executor.
8
8
  # Most tests in this file should be non-local and use the configuration
9
9
  # specificed with --config, not this one.
@@ -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')