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,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
@@ -3,7 +3,6 @@ import pytest
3
3
  from parsl import join_app, python_app
4
4
  from parsl.dataflow.errors import JoinError
5
5
 
6
-
7
6
  RESULT_CONSTANT = 3
8
7
 
9
8
 
@@ -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
 
@@ -1,4 +1,5 @@
1
1
  import pytest
2
+
2
3
  from parsl import python_app
3
4
  from parsl.dataflow.memoization import id_for_memo
4
5
 
@@ -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.issue363
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,5 +1,6 @@
1
- from parsl import python_app
2
1
  import pytest
2
+
3
+ from parsl import python_app
3
4
  from parsl.tests.configs.htex_local import fresh_config as local_config
4
5
 
5
6
 
@@ -1,5 +1,6 @@
1
- from parsl import python_app
2
1
  import pytest
2
+
3
+ from parsl import python_app
3
4
  from parsl.tests.configs.htex_local import fresh_config as local_config
4
5
 
5
6
 
@@ -53,6 +53,7 @@ def test_get_dataframe():
53
53
  assert res.equals(data), 'Unexpected dataframe'
54
54
 
55
55
 
56
+ @pytest.mark.shared_fs
56
57
  def test_bash_default_arg():
57
58
  if os.path.exists('std.out'):
58
59
  os.remove('std.out')
@@ -1,4 +1,5 @@
1
1
  import pytest
2
+
2
3
  from parsl.jobs.states import JobState
3
4
 
4
5
 
@@ -6,7 +6,6 @@ import pytest
6
6
  from parsl.app.app import bash_app, python_app
7
7
  from parsl.tests.configs.local_threads import config
8
8
 
9
-
10
9
  local_config = config
11
10
 
12
11
 
@@ -1,8 +1,10 @@
1
- import time
2
1
  import multiprocessing
2
+ import random
3
+ import time
4
+
3
5
  import pytest
6
+
4
7
  from parsl.multiprocessing import MacSafeQueue
5
- import random
6
8
 
7
9
 
8
10
  def consumer(in_q, out_q, delay=0):
@@ -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:
@@ -6,7 +6,6 @@ import argparse
6
6
  import pytest
7
7
 
8
8
  import parsl
9
-
10
9
  from parsl.dataflow.dflow import DataFlowKernel
11
10
  from parsl.tests.configs.local_threads import config
12
11
 
@@ -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
- dfk = parsl.dfk()
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
@@ -0,0 +1,103 @@
1
+ import math
2
+ from unittest.mock import MagicMock
3
+
4
+ import pytest
5
+
6
+ from parsl.executors.high_throughput.executor import HighThroughputExecutor
7
+ from parsl.jobs.states import JobState, JobStatus
8
+ from parsl.jobs.strategy import Strategy
9
+
10
+
11
+ # the parameterize tuple consists of:
12
+ # Input:
13
+ # * number of tasks to mock the load as
14
+ # * number of workers per node
15
+ # Expected output:
16
+ # * the number of blocks we should expect to be launched
17
+ # in this situation
18
+ #
19
+ # This test will configure an executor, then run strategize
20
+ # a few times, asserting that it converges to the correct
21
+ # number of blocks without oscillating.
22
+ @pytest.mark.local
23
+ @pytest.mark.parametrize("ns", [(14, 48, 1), # values from issue #3696
24
+
25
+ (1, 1, 1), # one task needs one block
26
+
27
+ (100, 1, 20), # many one-task blocks, hitting hard-coded max blocks
28
+
29
+ (47, 48, 1), # some edge cases around #3696 values
30
+ (48, 48, 1), # "
31
+ (49, 48, 2), # "
32
+ (149, 50, 3)]) # "
33
+ def test_htex_strategy_does_not_oscillate(ns):
34
+ """Check for oscillations in htex scaling.
35
+ In issue 3696, with a large number of workers per block
36
+ and a smaller number of active tasks, the htex scaling
37
+ strategy oscillates between 0 and 1 active block, rather
38
+ than converging to 1 active block.
39
+ """
40
+
41
+ n_tasks, n_workers, n_blocks = ns
42
+
43
+ s = Strategy(strategy='htex_auto_scale', max_idletime=0)
44
+
45
+ provider = MagicMock()
46
+ executor = MagicMock(spec=HighThroughputExecutor)
47
+
48
+ statuses = {}
49
+
50
+ executor.provider = provider
51
+ executor.outstanding = n_tasks
52
+ executor.status_facade = statuses
53
+ executor.workers_per_node = n_workers
54
+
55
+ provider.parallelism = 1
56
+ provider.init_blocks = 0
57
+ provider.min_blocks = 0
58
+ provider.max_blocks = 20
59
+ provider.nodes_per_block = 1
60
+
61
+ def scale_out(n):
62
+ for _ in range(n):
63
+ statuses[len(statuses)] = JobStatus(state=JobState.PENDING)
64
+
65
+ executor.scale_out_facade.side_effect = scale_out
66
+
67
+ def scale_in(n, max_idletime=None):
68
+ # find n PENDING jobs and set them to CANCELLED
69
+ for k in statuses:
70
+ if n == 0:
71
+ return
72
+ if statuses[k].state == JobState.PENDING:
73
+ statuses[k].state = JobState.CANCELLED
74
+ n -= 1
75
+
76
+ executor.scale_in_facade.side_effect = scale_in
77
+
78
+ s.add_executors([executor])
79
+
80
+ # In issue #3696, this first strategise does initial and load based
81
+ # scale outs, because n_tasks > n_workers*0
82
+ s.strategize([executor])
83
+
84
+ executor.scale_out_facade.assert_called()
85
+ assert len(statuses) == n_blocks, "Should have launched n_blocks"
86
+ assert len([k for k in statuses if statuses[k].state == JobState.PENDING]) == n_blocks
87
+ # there might be several calls to scale_out_facade inside strategy,
88
+ # but the end effect should be that exactly one block is scaled out.
89
+
90
+ executor.scale_in_facade.assert_not_called()
91
+
92
+ # In issue #3696, this second strategize does a scale in, because n_tasks < n_workers*1
93
+ s.strategize([executor])
94
+
95
+ # assert that there should still be n_blocks pending blocks
96
+ assert len([k for k in statuses if statuses[k].state == JobState.PENDING]) == n_blocks
97
+ # this assert fails due to issue #3696
98
+
99
+ # Now check scale in happens with 0 load
100
+ executor.outstanding = 0
101
+ s.strategize([executor])
102
+ executor.scale_in_facade.assert_called()
103
+ assert len([k for k in statuses if statuses[k].state == JobState.PENDING]) == 0
@@ -4,13 +4,11 @@ import time
4
4
  import pytest
5
5
 
6
6
  import parsl
7
-
8
7
  from parsl import File, python_app
9
- from parsl.providers import LocalProvider
10
- from parsl.channels import LocalChannel
11
- from parsl.launchers import SingleNodeLauncher
12
8
  from parsl.config import Config
13
9
  from parsl.executors import HighThroughputExecutor
10
+ from parsl.launchers import SingleNodeLauncher
11
+ from parsl.providers import LocalProvider
14
12
 
15
13
  logger = logging.getLogger(__name__)
16
14
 
@@ -30,7 +28,6 @@ def local_config():
30
28
  max_workers_per_node=1,
31
29
  encrypted=True,
32
30
  provider=LocalProvider(
33
- channel=LocalChannel(),
34
31
  init_blocks=0,
35
32
  max_blocks=_max_blocks,
36
33
  min_blocks=_min_blocks,
@@ -1,15 +1,13 @@
1
+ from threading import Event
2
+
1
3
  import pytest
2
4
 
3
5
  import parsl
4
-
5
6
  from parsl import File, python_app
6
- from parsl.providers import LocalProvider
7
- from parsl.channels import LocalChannel
8
- from parsl.launchers import SingleNodeLauncher
9
7
  from parsl.config import Config
10
8
  from parsl.executors import HighThroughputExecutor
11
-
12
- from threading import Event
9
+ from parsl.launchers import SingleNodeLauncher
10
+ from parsl.providers import LocalProvider
13
11
 
14
12
  _max_blocks = 5
15
13
  _min_blocks = 0
@@ -24,10 +22,9 @@ def local_config():
24
22
  poll_period=100,
25
23
  label="htex_local",
26
24
  address="127.0.0.1",
27
- max_workers=1,
25
+ max_workers_per_node=1,
28
26
  encrypted=True,
29
27
  provider=LocalProvider(
30
- channel=LocalChannel(),
31
28
  init_blocks=0,
32
29
  max_blocks=_max_blocks,
33
30
  min_blocks=_min_blocks,