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
@@ -1,19 +1,20 @@
1
- import parsl
2
- import pytest
3
1
  import time
4
2
 
5
- from parsl.providers import LocalProvider
6
- from parsl.channels import LocalChannel
7
- from parsl.launchers import SimpleLauncher
3
+ import pytest
8
4
 
5
+ import parsl
9
6
  from parsl.config import Config
10
7
  from parsl.executors import HighThroughputExecutor
8
+ from parsl.launchers import SimpleLauncher
9
+ from parsl.providers import LocalProvider
11
10
 
12
11
  # this constant is used to scale some durations that happen
13
12
  # based around the expected drain period: the drain period
14
13
  # is TIME_CONST seconds, and the single executed task will
15
14
  # last twice that many number of seconds.
16
- TIME_CONST = 1
15
+ TIME_CONST = 4
16
+
17
+ CONNECTED_MANAGERS_POLL_MS = 100
17
18
 
18
19
 
19
20
  def local_config():
@@ -26,7 +27,6 @@ def local_config():
26
27
  cores_per_worker=1,
27
28
  encrypted=True,
28
29
  provider=LocalProvider(
29
- channel=LocalChannel(),
30
30
  init_blocks=1,
31
31
  min_blocks=0,
32
32
  max_blocks=0,
@@ -35,6 +35,7 @@ def local_config():
35
35
  )
36
36
  ],
37
37
  strategy='none',
38
+ strategy_period=0.1
38
39
  )
39
40
 
40
41
 
@@ -51,7 +52,7 @@ def test_drain(try_assert):
51
52
 
52
53
  # wait till we have a block running...
53
54
 
54
- try_assert(lambda: len(htex.connected_managers()) == 1)
55
+ try_assert(lambda: len(htex.connected_managers()) == 1, check_period_ms=CONNECTED_MANAGERS_POLL_MS)
55
56
 
56
57
  managers = htex.connected_managers()
57
58
  assert managers[0]['active'], "The manager should be active"
@@ -62,7 +63,7 @@ def test_drain(try_assert):
62
63
  time.sleep(TIME_CONST)
63
64
 
64
65
  # this assert should happen *very fast* after the above delay...
65
- try_assert(lambda: htex.connected_managers()[0]['draining'], timeout_ms=500)
66
+ try_assert(lambda: htex.connected_managers()[0]['draining'], timeout_ms=500, check_period_ms=CONNECTED_MANAGERS_POLL_MS)
66
67
 
67
68
  # and the test task should still be running...
68
69
  assert not fut.done(), "The test task should still be running"
@@ -75,4 +76,4 @@ def test_drain(try_assert):
75
76
  # connected managers.
76
77
  # As with the above draining assert, this should happen very fast after
77
78
  # the task ends.
78
- try_assert(lambda: len(htex.connected_managers()) == 0, timeout_ms=500)
79
+ try_assert(lambda: len(htex.connected_managers()) == 0, timeout_ms=500, check_period_ms=CONNECTED_MANAGERS_POLL_MS)
@@ -1,12 +1,12 @@
1
+ import logging
1
2
  import pathlib
2
- import warnings
3
+ from subprocess import Popen, TimeoutExpired
4
+ from typing import Optional, Sequence
3
5
  from unittest import mock
4
6
 
5
7
  import pytest
6
8
 
7
- from parsl import curvezmq
8
- from parsl import HighThroughputExecutor
9
- from parsl.multiprocessing import ForkProcess
9
+ from parsl import HighThroughputExecutor, curvezmq
10
10
 
11
11
  _MOCK_BASE = "parsl.executors.high_throughput.executor"
12
12
 
@@ -72,51 +72,77 @@ def test_htex_start_encrypted(
72
72
  @pytest.mark.local
73
73
  @pytest.mark.parametrize("started", (True, False))
74
74
  @pytest.mark.parametrize("timeout_expires", (True, False))
75
- @mock.patch(f"{_MOCK_BASE}.logger")
76
75
  def test_htex_shutdown(
77
- mock_logger: mock.MagicMock,
78
76
  started: bool,
79
77
  timeout_expires: bool,
80
78
  htex: HighThroughputExecutor,
79
+ caplog
81
80
  ):
82
- mock_ix_proc = mock.Mock(spec=ForkProcess)
81
+ mock_ix_proc = mock.Mock(spec=Popen)
83
82
 
84
83
  if started:
85
84
  htex.interchange_proc = mock_ix_proc
86
- mock_ix_proc.is_alive.return_value = True
85
+
86
+ # This will, in the absence of any exit trigger, block forever if
87
+ # no timeout is given and if the interchange does not terminate.
88
+ # Raise an exception to report that, rather than actually block,
89
+ # and hope that nothing is catching that exception.
90
+
91
+ # this function implements the behaviour if the interchange has
92
+ # not received a termination call
93
+ def proc_wait_alive(timeout):
94
+ if timeout:
95
+ raise TimeoutExpired(cmd="mock-interchange", timeout=timeout)
96
+ else:
97
+ raise RuntimeError("This wait call would hang forever")
98
+
99
+ def proc_wait_terminated(timeout):
100
+ return 0
101
+
102
+ mock_ix_proc.wait.side_effect = proc_wait_alive
87
103
 
88
104
  if not timeout_expires:
89
105
  # Simulate termination of the Interchange process
90
106
  def kill_interchange(*args, **kwargs):
91
- mock_ix_proc.is_alive.return_value = False
107
+ mock_ix_proc.wait.side_effect = proc_wait_terminated
92
108
 
93
109
  mock_ix_proc.terminate.side_effect = kill_interchange
94
110
 
95
- htex.shutdown()
111
+ with caplog.at_level(logging.INFO):
112
+ htex.shutdown()
96
113
 
97
- mock_logs = mock_logger.info.call_args_list
98
114
  if started:
99
115
  assert mock_ix_proc.terminate.called
100
- assert mock_ix_proc.join.called
101
- assert {"timeout": 10} == mock_ix_proc.join.call_args[1]
116
+ assert mock_ix_proc.wait.called
117
+ assert {"timeout": 10} == mock_ix_proc.wait.call_args[1]
102
118
  if timeout_expires:
103
- assert "Unable to terminate Interchange" in mock_logs[1][0][0]
119
+ assert "Unable to terminate Interchange" in caplog.text
104
120
  assert mock_ix_proc.kill.called
105
- assert "Attempting" in mock_logs[0][0][0]
106
- assert "Finished" in mock_logs[-1][0][0]
121
+ assert "Attempting HighThroughputExecutor shutdown" in caplog.text
122
+ assert "Finished HighThroughputExecutor shutdown" in caplog.text
107
123
  else:
108
124
  assert not mock_ix_proc.terminate.called
109
- assert not mock_ix_proc.join.called
110
- assert "has not started" in mock_logs[0][0][0]
125
+ assert not mock_ix_proc.wait.called
126
+ assert "HighThroughputExecutor has not started" in caplog.text
111
127
 
112
128
 
113
129
  @pytest.mark.local
114
- def test_max_workers_per_node():
115
- with pytest.warns(DeprecationWarning) as record:
116
- htex = HighThroughputExecutor(max_workers_per_node=1, max_workers=2)
130
+ @pytest.mark.parametrize("cmd", (None, "custom-launch-cmd"))
131
+ def test_htex_worker_pool_launch_cmd(cmd: Optional[str]):
132
+ if cmd:
133
+ htex = HighThroughputExecutor(launch_cmd=cmd)
134
+ assert htex.launch_cmd == cmd
135
+ else:
136
+ htex = HighThroughputExecutor()
137
+ assert htex.launch_cmd.startswith("process_worker_pool.py")
117
138
 
118
- warning_msg = "max_workers is deprecated"
119
- assert any(warning_msg in str(warning.message) for warning in record)
120
139
 
121
- # Ensure max_workers_per_node takes precedence
122
- assert htex.max_workers_per_node == htex.max_workers == 1
140
+ @pytest.mark.local
141
+ @pytest.mark.parametrize("cmd", (None, ["custom", "launch", "cmd"]))
142
+ def test_htex_interchange_launch_cmd(cmd: Optional[Sequence[str]]):
143
+ if cmd:
144
+ htex = HighThroughputExecutor(interchange_launch_cmd=cmd)
145
+ assert htex.interchange_launch_cmd == cmd
146
+ else:
147
+ htex = HighThroughputExecutor()
148
+ assert htex.interchange_launch_cmd == ["interchange.py"]
@@ -20,7 +20,6 @@ def load_config():
20
20
  yield
21
21
 
22
22
  parsl.dfk().cleanup()
23
- parsl.clear()
24
23
 
25
24
 
26
25
  @python_app
@@ -0,0 +1,51 @@
1
+ import time
2
+
3
+ import pytest
4
+
5
+ import parsl
6
+ from parsl.app.app import bash_app, python_app
7
+ from parsl.config import Config
8
+ from parsl.executors import HighThroughputExecutor
9
+ from parsl.executors.high_throughput.manager_selector import (
10
+ BlockIdManagerSelector,
11
+ ManagerSelector,
12
+ )
13
+ from parsl.launchers import WrappedLauncher
14
+ from parsl.providers import LocalProvider
15
+ from parsl.usage_tracking.levels import LEVEL_1
16
+
17
+ BLOCK_COUNT = 2
18
+
19
+
20
+ @parsl.python_app
21
+ def get_worker_pid():
22
+ import os
23
+ return os.environ.get('PARSL_WORKER_BLOCK_ID')
24
+
25
+
26
+ @pytest.mark.local
27
+ def test_block_id_selection(try_assert):
28
+ htex = HighThroughputExecutor(
29
+ label="htex_local",
30
+ max_workers_per_node=1,
31
+ manager_selector=BlockIdManagerSelector(),
32
+ provider=LocalProvider(
33
+ init_blocks=BLOCK_COUNT,
34
+ max_blocks=BLOCK_COUNT,
35
+ min_blocks=BLOCK_COUNT,
36
+ ),
37
+ )
38
+
39
+ config = Config(
40
+ executors=[htex],
41
+ usage_tracking=LEVEL_1,
42
+ )
43
+
44
+ with parsl.load(config):
45
+ blockids = []
46
+ try_assert(lambda: len(htex.connected_managers()) == BLOCK_COUNT, timeout_ms=20000)
47
+ for i in range(10):
48
+ future = get_worker_pid()
49
+ blockids.append(future.result())
50
+
51
+ assert all(blockid == "1" for blockid in blockids)
@@ -0,0 +1,36 @@
1
+ import logging
2
+ import sys
3
+
4
+ import pytest
5
+
6
+ import parsl
7
+ from parsl.app.app import python_app
8
+ from parsl.tests.configs.htex_local import fresh_config
9
+
10
+
11
+ def local_config():
12
+ config = fresh_config()
13
+ config.executors[0].poll_period = 1
14
+ config.executors[0].max_workers_per_node = 1
15
+ return config
16
+
17
+
18
+ @python_app
19
+ def dummy():
20
+ pass
21
+
22
+
23
+ @pytest.mark.local
24
+ def test_connected_managers():
25
+
26
+ # Run dummy function to ensure a manager is online
27
+ x = dummy()
28
+ assert x.result() is None
29
+ executor = parsl.dfk().executors['htex_local']
30
+ manager_info_list = executor.connected_managers()
31
+ assert len(manager_info_list) == 1
32
+ manager_info = manager_info_list[0]
33
+ assert 'python_version' in manager_info
34
+ assert 'parsl_version' in manager_info
35
+ assert manager_info['parsl_version'] == parsl.__version__
36
+ assert manager_info['python_version'] == f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
@@ -5,18 +5,12 @@ from parsl.app.app import python_app
5
5
  from parsl.tests.configs.htex_local import fresh_config
6
6
 
7
7
 
8
- def local_setup():
8
+ def local_config():
9
9
  config = fresh_config()
10
10
  config.executors[0].poll_period = 1
11
11
  config.executors[0].max_workers_per_node = 1
12
12
  config.executors[0].launch_cmd = "executable_that_hopefully_does_not_exist_1030509.py"
13
- parsl.load(config)
14
-
15
-
16
- def local_teardown():
17
-
18
- parsl.dfk().cleanup()
19
- parsl.clear()
13
+ return config
20
14
 
21
15
 
22
16
  @python_app
@@ -37,7 +31,3 @@ def test_that_it_fails():
37
31
  raise Exception("The app somehow ran without a valid worker")
38
32
 
39
33
  assert parsl.dfk().config.executors[0]._executor_bad_state.is_set()
40
-
41
- # htex needs shutting down explicitly because dfk.cleanup() will not
42
- # do that, as it is in bad state
43
- parsl.dfk().config.executors[0].shutdown()
@@ -1,11 +1,13 @@
1
1
  import logging
2
- import parsl
2
+
3
3
  import pytest
4
- from parsl.executors import HighThroughputExecutor
4
+
5
+ import parsl
5
6
  from parsl import Config
6
- from parsl.providers import LocalProvider
7
+ from parsl.executors import HighThroughputExecutor
7
8
  from parsl.executors.errors import BadStateException
8
- from parsl.jobs.states import JobStatus, JobState
9
+ from parsl.jobs.states import JobState, JobStatus
10
+ from parsl.providers import LocalProvider
9
11
 
10
12
 
11
13
  def local_config():
@@ -19,16 +21,14 @@ def local_config():
19
21
  poll_period=100,
20
22
  max_workers_per_node=1,
21
23
  provider=LocalProvider(
22
- worker_init="conda deactivate; export PATH=''; which python; exit 0",
23
- init_blocks=2,
24
- max_blocks=4,
25
- min_blocks=0,
24
+ worker_init="exit 0",
25
+ init_blocks=2
26
26
  ),
27
27
  )
28
28
  ],
29
29
  run_dir="/tmp/test_htex",
30
30
  max_idletime=0.5,
31
- strategy='htex_auto_scale',
31
+ strategy='none',
32
32
  )
33
33
 
34
34
 
@@ -0,0 +1,45 @@
1
+ import queue
2
+ from unittest import mock
3
+
4
+ import pytest
5
+
6
+ from parsl.executors import HighThroughputExecutor
7
+ from parsl.executors.errors import InvalidResourceSpecification
8
+
9
+
10
+ def double(x):
11
+ return x * 2
12
+
13
+
14
+ @pytest.mark.local
15
+ def test_submit_calls_validate():
16
+
17
+ htex = HighThroughputExecutor()
18
+ htex.outgoing_q = mock.Mock(spec=queue.Queue)
19
+ htex.validate_resource_spec = mock.Mock(spec=htex.validate_resource_spec)
20
+
21
+ res_spec = {}
22
+ htex.submit(double, res_spec, (5,), {})
23
+ htex.validate_resource_spec.assert_called()
24
+
25
+
26
+ @pytest.mark.local
27
+ def test_resource_spec_validation():
28
+ htex = HighThroughputExecutor()
29
+ ret_val = htex.validate_resource_spec({})
30
+ assert ret_val is None
31
+
32
+
33
+ @pytest.mark.local
34
+ def test_resource_spec_validation_one_key():
35
+ htex = HighThroughputExecutor()
36
+ ret_val = htex.validate_resource_spec({"priority": 2})
37
+ assert ret_val is None
38
+
39
+
40
+ @pytest.mark.local
41
+ def test_resource_spec_validation_bad_keys():
42
+ htex = HighThroughputExecutor()
43
+
44
+ with pytest.raises(InvalidResourceSpecification):
45
+ htex.validate_resource_spec({"num_nodes": 2})
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  import pathlib
2
3
  from typing import Optional
3
4
  from unittest import mock
@@ -8,6 +9,24 @@ import zmq
8
9
 
9
10
  from parsl import curvezmq
10
11
  from parsl.executors.high_throughput.interchange import Interchange
12
+ from parsl.executors.high_throughput.manager_selector import RandomManagerSelector
13
+
14
+
15
+ def make_interchange(*, interchange_address: Optional[str], cert_dir: Optional[str]) -> Interchange:
16
+ return Interchange(interchange_address=interchange_address,
17
+ cert_dir=cert_dir,
18
+ client_address="127.0.0.1",
19
+ client_ports=(50055, 50056, 50057),
20
+ worker_ports=None,
21
+ worker_port_range=(54000, 55000),
22
+ hub_address=None,
23
+ hub_zmq_port=None,
24
+ heartbeat_threshold=60,
25
+ logdir=".",
26
+ logging_level=logging.INFO,
27
+ manager_selector=RandomManagerSelector(),
28
+ poll_period=10,
29
+ run_id="test_run_id")
11
30
 
12
31
 
13
32
  @pytest.fixture
@@ -31,7 +50,7 @@ def test_interchange_curvezmq_sockets(
31
50
  mock_socket: mock.MagicMock, cert_dir: Optional[str], encrypted: bool
32
51
  ):
33
52
  address = "127.0.0.1"
34
- ix = Interchange(interchange_address=address, cert_dir=cert_dir)
53
+ ix = make_interchange(interchange_address=address, cert_dir=cert_dir)
35
54
  assert isinstance(ix.zmq_context, curvezmq.ServerContext)
36
55
  assert ix.zmq_context.encrypted is encrypted
37
56
  assert mock_socket.call_count == 5
@@ -40,7 +59,7 @@ def test_interchange_curvezmq_sockets(
40
59
  @pytest.mark.local
41
60
  @pytest.mark.parametrize("encrypted", (True, False), indirect=True)
42
61
  def test_interchange_binding_no_address(cert_dir: Optional[str]):
43
- ix = Interchange(cert_dir=cert_dir)
62
+ ix = make_interchange(interchange_address=None, cert_dir=cert_dir)
44
63
  assert ix.interchange_address == "*"
45
64
 
46
65
 
@@ -49,17 +68,18 @@ def test_interchange_binding_no_address(cert_dir: Optional[str]):
49
68
  def test_interchange_binding_with_address(cert_dir: Optional[str]):
50
69
  # Using loopback address
51
70
  address = "127.0.0.1"
52
- ix = Interchange(interchange_address=address, cert_dir=cert_dir)
71
+ ix = make_interchange(interchange_address=address, cert_dir=cert_dir)
53
72
  assert ix.interchange_address == address
54
73
 
55
74
 
75
+ @pytest.mark.skip("This behaviour is possibly unexpected. See issue #3037")
56
76
  @pytest.mark.local
57
77
  @pytest.mark.parametrize("encrypted", (True, False), indirect=True)
58
78
  def test_interchange_binding_with_non_ipv4_address(cert_dir: Optional[str]):
59
79
  # Confirm that a ipv4 address is required
60
80
  address = "localhost"
61
81
  with pytest.raises(zmq.error.ZMQError):
62
- Interchange(interchange_address=address, cert_dir=cert_dir)
82
+ make_interchange(interchange_address=address, cert_dir=cert_dir)
63
83
 
64
84
 
65
85
  @pytest.mark.local
@@ -67,8 +87,8 @@ def test_interchange_binding_with_non_ipv4_address(cert_dir: Optional[str]):
67
87
  def test_interchange_binding_bad_address(cert_dir: Optional[str]):
68
88
  """Confirm that we raise a ZMQError when a bad address is supplied"""
69
89
  address = "550.0.0.0"
70
- with pytest.raises(zmq.error.ZMQError):
71
- Interchange(interchange_address=address, cert_dir=cert_dir)
90
+ with pytest.raises(ValueError):
91
+ make_interchange(interchange_address=address, cert_dir=cert_dir)
72
92
 
73
93
 
74
94
  @pytest.mark.local
@@ -76,11 +96,12 @@ def test_interchange_binding_bad_address(cert_dir: Optional[str]):
76
96
  def test_limited_interface_binding(cert_dir: Optional[str]):
77
97
  """When address is specified the worker_port would be bound to it rather than to 0.0.0.0"""
78
98
  address = "127.0.0.1"
79
- ix = Interchange(interchange_address=address, cert_dir=cert_dir)
99
+ ix = make_interchange(interchange_address=address, cert_dir=cert_dir)
80
100
  ix.worker_result_port
81
101
  proc = psutil.Process()
82
102
  conns = proc.connections(kind="tcp")
83
103
 
84
104
  matched_conns = [conn for conn in conns if conn.laddr.port == ix.worker_result_port]
85
105
  assert len(matched_conns) == 1
86
- assert matched_conns[0].laddr.ip == address
106
+ # laddr.ip can return ::ffff:127.0.0.1 when using IPv6
107
+ assert address in matched_conns[0].laddr.ip
@@ -2,10 +2,11 @@
2
2
  """
3
3
 
4
4
  import os
5
- import parsl
6
- import pytest
7
5
  import time
8
6
 
7
+ import pytest
8
+
9
+ import parsl
9
10
  from parsl.tests.configs.htex_local_alternate import fresh_config
10
11
 
11
12
 
@@ -61,13 +62,12 @@ def test_app_name(get_app, expected_name, expected_result, tmpd_cwd):
61
62
  assert app().result() == expected_result
62
63
 
63
64
  parsl.dfk().cleanup()
64
- parsl.clear()
65
65
 
66
66
  engine = sqlalchemy.create_engine(c.monitoring.logging_endpoint)
67
67
  with engine.begin() as connection:
68
68
 
69
69
  def count_rows(table: str):
70
- result = connection.execute(f"SELECT COUNT(*) FROM {table}")
70
+ result = connection.execute(sqlalchemy.text(f"SELECT COUNT(*) FROM {table}"))
71
71
  (c, ) = result.first()
72
72
  return c
73
73
 
@@ -81,6 +81,6 @@ def test_app_name(get_app, expected_name, expected_result, tmpd_cwd):
81
81
  assert count_rows("try") == 1
82
82
 
83
83
  # ... and has the expected name.
84
- result = connection.execute("SELECT task_func_name FROM task")
84
+ result = connection.execute(sqlalchemy.text("SELECT task_func_name FROM task"))
85
85
  (c, ) = result.first()
86
86
  assert c == expected_name
@@ -1,10 +1,13 @@
1
- import logging
2
1
  import os
3
- import parsl
4
- import pytest
5
2
  import time
6
3
 
7
- logger = logging.getLogger(__name__)
4
+ import pytest
5
+
6
+ import parsl
7
+ from parsl import HighThroughputExecutor
8
+ from parsl.config import Config
9
+ from parsl.executors.taskvine import TaskVineExecutor, TaskVineManagerConfig
10
+ from parsl.monitoring import MonitoringHub
8
11
 
9
12
 
10
13
  @parsl.python_app
@@ -18,34 +21,79 @@ def this_app():
18
21
  return 5
19
22
 
20
23
 
24
+ # The below fresh configs are for use in parametrization, and should return
25
+ # a configuration that is suitably configured for monitoring.
26
+
27
+ def htex_config():
28
+ """This config will use htex's default htex-specific monitoring radio mode"""
29
+ from parsl.tests.configs.htex_local_alternate import fresh_config
30
+ return fresh_config()
31
+
32
+
33
+ def htex_udp_config():
34
+ """This config will force UDP"""
35
+ from parsl.tests.configs.htex_local_alternate import fresh_config
36
+ c = fresh_config()
37
+ assert len(c.executors) == 1
38
+
39
+ assert c.executors[0].radio_mode == "htex", "precondition: htex has a radio mode attribute, configured for htex radio"
40
+ c.executors[0].radio_mode = "udp"
41
+
42
+ return c
43
+
44
+
45
+ def htex_filesystem_config():
46
+ """This config will force filesystem radio"""
47
+ from parsl.tests.configs.htex_local_alternate import fresh_config
48
+ c = fresh_config()
49
+ assert len(c.executors) == 1
50
+
51
+ assert c.executors[0].radio_mode == "htex", "precondition: htex has a radio mode attribute, configured for htex radio"
52
+ c.executors[0].radio_mode = "filesystem"
53
+
54
+ return c
55
+
56
+
57
+ def workqueue_config():
58
+ from parsl.tests.configs.workqueue_ex import fresh_config
59
+ c = fresh_config()
60
+ c.monitoring = MonitoringHub(
61
+ hub_address="localhost",
62
+ resource_monitoring_interval=1)
63
+ return c
64
+
65
+
66
+ def taskvine_config():
67
+ c = Config(executors=[TaskVineExecutor(manager_config=TaskVineManagerConfig(port=9000),
68
+ worker_launch_method='provider')],
69
+
70
+ monitoring=MonitoringHub(hub_address="localhost",
71
+ resource_monitoring_interval=1))
72
+ return c
73
+
74
+
21
75
  @pytest.mark.local
22
- def test_row_counts():
76
+ @pytest.mark.parametrize("fresh_config", [htex_config, htex_filesystem_config, htex_udp_config, workqueue_config, taskvine_config])
77
+ def test_row_counts(tmpd_cwd, fresh_config):
23
78
  # this is imported here rather than at module level because
24
79
  # it isn't available in a plain parsl install, so this module
25
80
  # would otherwise fail to import and break even a basic test
26
81
  # run.
27
82
  import sqlalchemy
28
83
  from sqlalchemy import text
29
- from parsl.tests.configs.htex_local_alternate import fresh_config
30
84
 
31
- if os.path.exists("runinfo/monitoring.db"):
32
- logger.info("Monitoring database already exists - deleting")
33
- os.remove("runinfo/monitoring.db")
85
+ db_url = f"sqlite:///{tmpd_cwd}/monitoring.db"
34
86
 
35
- logger.info("loading parsl")
36
- parsl.load(fresh_config())
87
+ config = fresh_config()
88
+ config.run_dir = tmpd_cwd
89
+ config.monitoring.logging_endpoint = db_url
37
90
 
38
- logger.info("invoking and waiting for result")
39
- assert this_app().result() == 5
40
-
41
- logger.info("cleaning up parsl")
42
- parsl.dfk().cleanup()
43
- parsl.clear()
91
+ with parsl.load(config):
92
+ assert this_app().result() == 5
44
93
 
45
94
  # at this point, we should find one row in the monitoring database.
46
95
 
47
- logger.info("checking database content")
48
- engine = sqlalchemy.create_engine("sqlite:///runinfo/monitoring.db")
96
+ engine = sqlalchemy.create_engine(db_url)
49
97
  with engine.begin() as connection:
50
98
 
51
99
  result = connection.execute(text("SELECT COUNT(*) FROM workflow"))
@@ -67,10 +115,12 @@ def test_row_counts():
67
115
  (c, ) = result.first()
68
116
  assert c == 0
69
117
 
70
- # Two entries: one showing manager active, one inactive
71
- result = connection.execute(text("SELECT COUNT(*) FROM node"))
72
- (c, ) = result.first()
73
- assert c == 2
118
+ if isinstance(config.executors[0], HighThroughputExecutor):
119
+ # The node table is specific to the HighThroughputExecutor
120
+ # Two entries: one showing manager active, one inactive
121
+ result = connection.execute(text("SELECT COUNT(*) FROM node"))
122
+ (c, ) = result.first()
123
+ assert c == 2
74
124
 
75
125
  # There should be one block polling status
76
126
  # local provider has a status_polling_interval of 5s
@@ -81,5 +131,3 @@ def test_row_counts():
81
131
  result = connection.execute(text("SELECT COUNT(*) FROM resource"))
82
132
  (c, ) = result.first()
83
133
  assert c >= 1
84
-
85
- logger.info("all done")