parsl 2024.3.4__tar.gz → 2024.3.18__tar.gz

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 (454) hide show
  1. {parsl-2024.3.4/parsl.egg-info → parsl-2024.3.18}/PKG-INFO +2 -2
  2. {parsl-2024.3.4 → parsl-2024.3.18}/README.rst +4 -0
  3. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/addresses.py +3 -1
  4. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/config.py +4 -0
  5. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/dflow.py +14 -7
  6. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/taskrecord.py +3 -1
  7. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/executor.py +34 -10
  8. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/interchange.py +43 -10
  9. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/manager_record.py +1 -0
  10. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/process_worker_pool.py +48 -7
  11. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/executor.py +6 -3
  12. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/manager.py +1 -0
  13. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/manager_config.py +3 -4
  14. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/job_status_poller.py +4 -3
  15. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/strategy.py +2 -1
  16. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/launchers.py +6 -6
  17. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/log_utils.py +8 -4
  18. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/db_manager.py +29 -7
  19. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/monitoring.py +15 -54
  20. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/remote.py +29 -0
  21. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/models.py +7 -0
  22. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/workflow_plots.py +3 -0
  23. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/views.py +2 -1
  24. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cluster_provider.py +1 -3
  25. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/slurm/slurm.py +13 -2
  26. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/user_opts.py +5 -2
  27. parsl-2024.3.18/parsl/tests/test_htex/test_drain.py +78 -0
  28. parsl-2024.3.18/parsl/tests/test_monitoring/test_app_names.py +86 -0
  29. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_scale_down_htex_auto_scale.py +3 -11
  30. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/usage_tracking/usage.py +5 -9
  31. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/utils.py +2 -2
  32. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/version.py +1 -1
  33. {parsl-2024.3.4 → parsl-2024.3.18/parsl.egg-info}/PKG-INFO +2 -2
  34. {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/SOURCES.txt +2 -1
  35. parsl-2024.3.4/parsl/configs/bluewaters.py +0 -28
  36. {parsl-2024.3.4 → parsl-2024.3.18}/LICENSE +0 -0
  37. {parsl-2024.3.4 → parsl-2024.3.18}/MANIFEST.in +0 -0
  38. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/__init__.py +0 -0
  39. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/__init__.py +0 -0
  40. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/app.py +0 -0
  41. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/bash.py +0 -0
  42. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/errors.py +0 -0
  43. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/futures.py +0 -0
  44. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/app/python.py +0 -0
  45. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/benchmark/__init__.py +0 -0
  46. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/benchmark/perf.py +0 -0
  47. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/__init__.py +0 -0
  48. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/base.py +0 -0
  49. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/errors.py +0 -0
  50. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/local/__init__.py +0 -0
  51. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/local/local.py +0 -0
  52. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/oauth_ssh/__init__.py +0 -0
  53. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/oauth_ssh/oauth_ssh.py +0 -0
  54. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh/__init__.py +0 -0
  55. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh/ssh.py +0 -0
  56. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh_il/__init__.py +0 -0
  57. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/channels/ssh_il/ssh_il.py +0 -0
  58. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/concurrent/__init__.py +0 -0
  59. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/ASPIRE1.py +0 -0
  60. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/Azure.py +0 -0
  61. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/__init__.py +0 -0
  62. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/ad_hoc.py +0 -0
  63. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/bridges.py +0 -0
  64. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/cc_in2p3.py +0 -0
  65. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/ec2.py +0 -0
  66. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/expanse.py +0 -0
  67. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/frontera.py +0 -0
  68. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/htex_local.py +0 -0
  69. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/illinoiscluster.py +0 -0
  70. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/kubernetes.py +0 -0
  71. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/local_threads.py +0 -0
  72. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/midway.py +0 -0
  73. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/osg.py +0 -0
  74. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/polaris.py +0 -0
  75. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/stampede2.py +0 -0
  76. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/summit.py +0 -0
  77. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/toss3_llnl.py +0 -0
  78. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/vineex_local.py +0 -0
  79. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/configs/wqex_local.py +0 -0
  80. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/curvezmq.py +0 -0
  81. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/__init__.py +0 -0
  82. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/data_manager.py +0 -0
  83. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/file_noop.py +0 -0
  84. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/files.py +0 -0
  85. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/ftp.py +0 -0
  86. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/globus.py +0 -0
  87. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/http.py +0 -0
  88. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/rsync.py +0 -0
  89. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/data_provider/staging.py +0 -0
  90. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/__init__.py +0 -0
  91. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/errors.py +0 -0
  92. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/futures.py +0 -0
  93. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/memoization.py +0 -0
  94. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/rundirs.py +0 -0
  95. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/dataflow/states.py +0 -0
  96. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/errors.py +0 -0
  97. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/__init__.py +0 -0
  98. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/base.py +0 -0
  99. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/errors.py +0 -0
  100. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/__init__.py +0 -0
  101. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/execute_parsl_task.py +0 -0
  102. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/executor.py +0 -0
  103. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/flux/flux_instance_manager.py +0 -0
  104. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/__init__.py +0 -0
  105. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/errors.py +0 -0
  106. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/monitoring_info.py +0 -0
  107. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/mpi_prefix_composer.py +0 -0
  108. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/mpi_resource_management.py +0 -0
  109. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/probe.py +0 -0
  110. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/high_throughput/zmq_pipes.py +0 -0
  111. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/__init__.py +0 -0
  112. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/executor.py +0 -0
  113. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/rpex_master.py +0 -0
  114. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/rpex_resources.py +0 -0
  115. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/radical/rpex_worker.py +0 -0
  116. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/status_handling.py +0 -0
  117. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/__init__.py +0 -0
  118. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/errors.py +0 -0
  119. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/exec_parsl_function.py +0 -0
  120. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/factory.py +0 -0
  121. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/factory_config.py +0 -0
  122. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/taskvine/utils.py +0 -0
  123. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/threads.py +0 -0
  124. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/__init__.py +0 -0
  125. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/errors.py +0 -0
  126. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/exec_parsl_function.py +0 -0
  127. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/executor.py +0 -0
  128. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/parsl_coprocess.py +0 -0
  129. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/executors/workqueue/parsl_coprocess_stub.py +0 -0
  130. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/__init__.py +0 -0
  131. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/error_handlers.py +0 -0
  132. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/errors.py +0 -0
  133. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/jobs/states.py +0 -0
  134. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/__init__.py +0 -0
  135. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/base.py +0 -0
  136. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/launchers/errors.py +0 -0
  137. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/__init__.py +0 -0
  138. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/message_type.py +0 -0
  139. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/queries/__init__.py +0 -0
  140. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/queries/pandas.py +0 -0
  141. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/radios.py +0 -0
  142. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/types.py +0 -0
  143. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/__init__.py +0 -0
  144. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/app.py +0 -0
  145. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/__init__.py +0 -0
  146. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/__init__.py +0 -0
  147. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/task_plots.py +0 -0
  148. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/plots/default/workflow_resource_plots.py +0 -0
  149. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/static/parsl-logo-white.png +0 -0
  150. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/static/parsl-monitor.css +0 -0
  151. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/app.html +0 -0
  152. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/dag.html +0 -0
  153. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/error.html +0 -0
  154. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/layout.html +0 -0
  155. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/resource_usage.html +0 -0
  156. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/task.html +0 -0
  157. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/workflow.html +0 -0
  158. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/templates/workflows_summary.html +0 -0
  159. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/utils.py +0 -0
  160. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/monitoring/visualization/version.py +0 -0
  161. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/multiprocessing.py +0 -0
  162. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/process_loggers.py +0 -0
  163. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/__init__.py +0 -0
  164. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/ad_hoc/__init__.py +0 -0
  165. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/ad_hoc/ad_hoc.py +0 -0
  166. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/aws/__init__.py +0 -0
  167. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/aws/aws.py +0 -0
  168. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/aws/template.py +0 -0
  169. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/azure/__init__.py +0 -0
  170. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/azure/azure.py +0 -0
  171. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/azure/template.py +0 -0
  172. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/base.py +0 -0
  173. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cobalt/__init__.py +0 -0
  174. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cobalt/cobalt.py +0 -0
  175. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/cobalt/template.py +0 -0
  176. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/condor/__init__.py +0 -0
  177. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/condor/condor.py +0 -0
  178. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/condor/template.py +0 -0
  179. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/errors.py +0 -0
  180. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/googlecloud/__init__.py +0 -0
  181. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/googlecloud/googlecloud.py +0 -0
  182. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/grid_engine/__init__.py +0 -0
  183. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/grid_engine/grid_engine.py +0 -0
  184. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/grid_engine/template.py +0 -0
  185. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/kubernetes/__init__.py +0 -0
  186. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/kubernetes/kube.py +0 -0
  187. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/kubernetes/template.py +0 -0
  188. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/local/__init__.py +0 -0
  189. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/local/local.py +0 -0
  190. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/lsf/__init__.py +0 -0
  191. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/lsf/lsf.py +0 -0
  192. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/lsf/template.py +0 -0
  193. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/pbspro/__init__.py +0 -0
  194. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/pbspro/pbspro.py +0 -0
  195. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/pbspro/template.py +0 -0
  196. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/slurm/__init__.py +0 -0
  197. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/slurm/template.py +0 -0
  198. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/torque/__init__.py +0 -0
  199. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/torque/template.py +0 -0
  200. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/providers/torque/torque.py +0 -0
  201. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/py.typed +0 -0
  202. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/__init__.py +0 -0
  203. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/base.py +0 -0
  204. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/concretes.py +0 -0
  205. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/errors.py +0 -0
  206. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/facade.py +0 -0
  207. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/serialize/proxystore.py +0 -0
  208. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/__init__.py +0 -0
  209. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/callables_helper.py +0 -0
  210. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/__init__.py +0 -0
  211. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/ad_hoc_cluster_htex.py +0 -0
  212. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/azure_single_node.py +0 -0
  213. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/bluewaters.py +0 -0
  214. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/bridges.py +0 -0
  215. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/cc_in2p3.py +0 -0
  216. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/comet.py +0 -0
  217. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/cooley_htex.py +0 -0
  218. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/ec2_single_node.py +0 -0
  219. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/ec2_spot.py +0 -0
  220. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/frontera.py +0 -0
  221. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_ad_hoc_cluster.py +0 -0
  222. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local.py +0 -0
  223. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local_alternate.py +0 -0
  224. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local_intask_staging.py +0 -0
  225. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/htex_local_rsync_staging.py +0 -0
  226. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_adhoc.py +0 -0
  227. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_radical.py +0 -0
  228. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_radical_mpi.py +0 -0
  229. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads.py +0 -0
  230. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint.py +0 -0
  231. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint_dfk_exit.py +0 -0
  232. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint_periodic.py +0 -0
  233. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_checkpoint_task_exit.py +0 -0
  234. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_ftp_in_task.py +0 -0
  235. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_globus.py +0 -0
  236. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_http_in_task.py +0 -0
  237. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_monitoring.py +0 -0
  238. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/local_threads_no_cache.py +0 -0
  239. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/midway.py +0 -0
  240. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/nscc_singapore.py +0 -0
  241. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/osg_htex.py +0 -0
  242. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/petrelkube.py +0 -0
  243. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/summit.py +0 -0
  244. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/swan_htex.py +0 -0
  245. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/taskvine_ex.py +0 -0
  246. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/theta.py +0 -0
  247. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/configs/workqueue_ex.py +0 -0
  248. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/conftest.py +0 -0
  249. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/__init__.py +0 -0
  250. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/latency.py +0 -0
  251. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_apps/__init__.py +0 -0
  252. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/__init__.py +0 -0
  253. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_channels.py +0 -0
  254. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_local_channel.py +0 -0
  255. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_scp_1.py +0 -0
  256. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_1.py +0 -0
  257. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_errors.py +0 -0
  258. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_file_transport.py +0 -0
  259. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_channels/test_ssh_interactive.py +0 -0
  260. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_parsl_load_default_config.py +0 -0
  261. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_stress/__init__.py +0 -0
  262. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_stress/test_python_simple.py +0 -0
  263. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/integration/test_stress/test_python_threads.py +0 -0
  264. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/__init__.py +0 -0
  265. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/htex_local.py +0 -0
  266. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_ad_hoc_htex.py +0 -0
  267. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_basic.py +0 -0
  268. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_fan_in_out_htex_remote.py +0 -0
  269. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_log_filter.py +0 -0
  270. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_memory_limits.py +0 -0
  271. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_oauth_ssh.py +0 -0
  272. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_regression_220.py +0 -0
  273. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_udp_simple.py +0 -0
  274. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/manual_tests/test_worker_count.py +0 -0
  275. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/__init__.py +0 -0
  276. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/htex_local.py +0 -0
  277. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/local_threads.py +0 -0
  278. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/test_scale.py +0 -0
  279. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/vineex_condor.py +0 -0
  280. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/vineex_local.py +0 -0
  281. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/wqex_condor.py +0 -0
  282. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/scaling_tests/wqex_local.py +0 -0
  283. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/__init__.py +0 -0
  284. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/site_config_selector.py +0 -0
  285. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/test_provider.py +0 -0
  286. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/site_tests/test_site.py +0 -0
  287. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/__init__.py +0 -0
  288. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_affinity.py +0 -0
  289. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_concurrent.py +0 -0
  290. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_dynamic_executor.py +0 -0
  291. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_ec2.py +0 -0
  292. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_launchers.py +0 -0
  293. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_local_adhoc.py +0 -0
  294. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_mpi/__init__.py +0 -0
  295. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/sites/test_worker_info.py +0 -0
  296. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_aalst_patterns.py +0 -0
  297. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/__init__.py +0 -0
  298. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_apptimeout.py +0 -0
  299. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_basic.py +0 -0
  300. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_error_codes.py +0 -0
  301. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_keyword_overlaps.py +0 -0
  302. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_kwarg_storage.py +0 -0
  303. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_memoize.py +0 -0
  304. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_memoize_ignore_args.py +0 -0
  305. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +0 -0
  306. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_multiline.py +0 -0
  307. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_pipeline.py +0 -0
  308. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_bash_apps/test_stdout.py +0 -0
  309. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_callables.py +0 -0
  310. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_channels/__init__.py +0 -0
  311. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_channels/test_large_output.py +0 -0
  312. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/__init__.py +0 -0
  313. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_periodic.py +0 -0
  314. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_python_checkpoint_1.py +0 -0
  315. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_python_checkpoint_2.py +0 -0
  316. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_python_checkpoint_3.py +0 -0
  317. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_regression_232.py +0 -0
  318. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_regression_233.py +0 -0
  319. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_regression_239.py +0 -0
  320. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_checkpointing/test_task_exit.py +0 -0
  321. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_curvezmq.py +0 -0
  322. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/__init__.py +0 -0
  323. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_file.py +0 -0
  324. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_file_apps.py +0 -0
  325. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_file_staging.py +0 -0
  326. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_data/test_output_chain_filenames.py +0 -0
  327. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/__init__.py +0 -0
  328. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_from_slides.py +0 -0
  329. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_kwargs.py +0 -0
  330. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_tutorial_1.py +0 -0
  331. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_workflow1.py +0 -0
  332. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_workflow2.py +0 -0
  333. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_docs/test_workflow4.py +0 -0
  334. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/__init__.py +0 -0
  335. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_fail.py +0 -0
  336. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_python_walltime.py +0 -0
  337. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_rand_fail.py +0 -0
  338. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_resource_spec.py +0 -0
  339. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_retries.py +0 -0
  340. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_retry_handler.py +0 -0
  341. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_retry_handler_failure.py +0 -0
  342. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_serialization_fail.py +0 -0
  343. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_error_handling/test_wrap_with_logs.py +0 -0
  344. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_flowcontrol/__init__.py +0 -0
  345. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_flux.py +0 -0
  346. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/__init__.py +0 -0
  347. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_basic.py +0 -0
  348. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_connected_blocks.py +0 -0
  349. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_cpu_affinity_explicit.py +0 -0
  350. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_disconnected_blocks.py +0 -0
  351. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_htex.py +0 -0
  352. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_manager_failure.py +0 -0
  353. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_missing_worker.py +0 -0
  354. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_multiple_disconnected_blocks.py +0 -0
  355. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_worker_failure.py +0 -0
  356. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_htex/test_zmq_binding.py +0 -0
  357. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/__init__.py +0 -0
  358. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_basic.py +0 -0
  359. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_db_locks.py +0 -0
  360. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_fuzz_zmq.py +0 -0
  361. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_incomplete_futures.py +0 -0
  362. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_memoization_representation.py +0 -0
  363. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_monitoring/test_viz_colouring.py +0 -0
  364. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/__init__.py +0 -0
  365. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_bad_mpi_config.py +0 -0
  366. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_mode_disabled.py +0 -0
  367. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py +0 -0
  368. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_prefix.py +0 -0
  369. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_mpi_scheduler.py +0 -0
  370. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_mpi_apps/test_resource_spec.py +0 -0
  371. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/__init__.py +0 -0
  372. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_cobalt_deprecation_warning.py +0 -0
  373. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_local_provider.py +0 -0
  374. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_pbspro_template.py +0 -0
  375. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_slurm_instantiate.py +0 -0
  376. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_slurm_template.py +0 -0
  377. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_providers/test_submiterror_deprecation.py +0 -0
  378. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/__init__.py +0 -0
  379. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_arg_input_types.py +0 -0
  380. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_basic.py +0 -0
  381. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_dep_standard_futures.py +0 -0
  382. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_dependencies.py +0 -0
  383. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_depfail_propagation.py +0 -0
  384. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_fail.py +0 -0
  385. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_fibonacci_iterative.py +0 -0
  386. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_fibonacci_recursive.py +0 -0
  387. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_futures.py +0 -0
  388. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_garbage_collect.py +0 -0
  389. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_import_fail.py +0 -0
  390. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_join.py +0 -0
  391. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_lifted.py +0 -0
  392. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_mapred.py +0 -0
  393. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_1.py +0 -0
  394. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_2.py +0 -0
  395. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_4.py +0 -0
  396. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_bad_id_for_memo.py +0 -0
  397. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_ignore_args.py +0 -0
  398. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_memoize_joinapp.py +0 -0
  399. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_outputs.py +0 -0
  400. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_overview.py +0 -0
  401. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_pipeline.py +0 -0
  402. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_simple.py +0 -0
  403. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_timeout.py +0 -0
  404. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_python_apps/test_type5.py +0 -0
  405. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_radical/__init__.py +0 -0
  406. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_radical/test_mpi_funcs.py +0 -0
  407. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/__init__.py +0 -0
  408. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_1480.py +0 -0
  409. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_1606_wait_for_current_tasks.py +0 -0
  410. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_1653.py +0 -0
  411. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_221.py +0 -0
  412. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_226.py +0 -0
  413. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_2652.py +0 -0
  414. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_69a.py +0 -0
  415. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_854.py +0 -0
  416. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_97_parallelism_0.py +0 -0
  417. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_regression/test_98.py +0 -0
  418. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/__init__.py +0 -0
  419. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_block_error_handler.py +0 -0
  420. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_regression_1621.py +0 -0
  421. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_scaling/test_scale_down.py +0 -0
  422. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/__init__.py +0 -0
  423. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_2555_caching_deserializer.py +0 -0
  424. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_basic.py +0 -0
  425. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_htex_code_cache.py +0 -0
  426. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_pack_resource_spec.py +0 -0
  427. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_proxystore_configured.py +0 -0
  428. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_serialization/test_proxystore_impl.py +0 -0
  429. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/__init__.py +0 -0
  430. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/staging_provider.py +0 -0
  431. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_1316.py +0 -0
  432. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_docs_1.py +0 -0
  433. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_docs_2.py +0 -0
  434. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_elaborate_noop_file.py +0 -0
  435. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_ftp.py +0 -0
  436. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_ftp_in_task.py +0 -0
  437. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_globus.py +0 -0
  438. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_staging/test_staging_https.py +0 -0
  439. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_summary.py +0 -0
  440. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_thread_parallelism.py +0 -0
  441. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_threads/__init__.py +0 -0
  442. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_threads/test_configs.py +0 -0
  443. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_threads/test_lazy_errors.py +0 -0
  444. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_utils/__init__.py +0 -0
  445. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/test_utils/test_representation_mixin.py +0 -0
  446. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/tests/utils.py +0 -0
  447. {parsl-2024.3.4 → parsl-2024.3.18}/parsl/usage_tracking/__init__.py +0 -0
  448. {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/dependency_links.txt +0 -0
  449. {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/entry_points.txt +0 -0
  450. {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/requires.txt +0 -0
  451. {parsl-2024.3.4 → parsl-2024.3.18}/parsl.egg-info/top_level.txt +0 -0
  452. {parsl-2024.3.4 → parsl-2024.3.18}/requirements.txt +0 -0
  453. {parsl-2024.3.4 → parsl-2024.3.18}/setup.cfg +0 -0
  454. {parsl-2024.3.4 → parsl-2024.3.18}/setup.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: parsl
3
- Version: 2024.3.4
3
+ Version: 2024.3.18
4
4
  Summary: Simple data dependent workflows in Python
5
5
  Home-page: https://github.com/Parsl/parsl
6
- Download-URL: https://github.com/Parsl/parsl/archive/2024.03.04.tar.gz
6
+ Download-URL: https://github.com/Parsl/parsl/archive/2024.03.18.tar.gz
7
7
  Author: The Parsl Team
8
8
  Author-email: parsl@googlegroups.com
9
9
  License: Apache 2.0
@@ -59,6 +59,10 @@ then explore the `parallel computing patterns <https://parsl.readthedocs.io/en/s
59
59
  .. |NSF-1550528| image:: https://img.shields.io/badge/NSF-1550528-blue.svg
60
60
  :target: https://nsf.gov/awardsearch/showAward?AWD_ID=1550528
61
61
  :alt: NSF award info
62
+ .. |NSF-1550475| image:: https://img.shields.io/badge/NSF-1550475-blue.svg
63
+ :target: https://nsf.gov/awardsearch/showAward?AWD_ID=1550475
64
+ :alt: NSF award info
65
+
62
66
 
63
67
  Quickstart
64
68
  ==========
@@ -81,7 +81,9 @@ def address_by_hostname() -> str:
81
81
  def address_by_interface(ifname: str) -> str:
82
82
  """Returns the IP address of the given interface name, e.g. 'eth0'
83
83
 
84
- This is taken from a Stack Overflow answer: https://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-of-eth0-in-python#24196955
84
+ This is taken from a Stack Overflow answer:
85
+ https://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-of-eth0-in-python#24196955
86
+
85
87
 
86
88
  Parameters
87
89
  ----------
@@ -55,6 +55,8 @@ class Config(RepresentationMixin):
55
55
  or `None`.
56
56
  If 'none' or `None`, dynamic scaling will be disabled. Default is 'simple'. The literal value `None` is
57
57
  deprecated.
58
+ strategy_period : float or int, optional
59
+ How often the scaling strategy should be executed. Default is 5 seconds.
58
60
  max_idletime : float, optional
59
61
  The maximum idle time allowed for an executor before strategy could shut down unused blocks. Default is 120.0 seconds.
60
62
  usage_tracking : bool, optional
@@ -88,6 +90,7 @@ class Config(RepresentationMixin):
88
90
  retry_handler: Optional[Callable[[Exception, TaskRecord], float]] = None,
89
91
  run_dir: str = 'runinfo',
90
92
  strategy: Optional[str] = 'simple',
93
+ strategy_period: Union[float, int] = 5,
91
94
  max_idletime: float = 120.0,
92
95
  monitoring: Optional[MonitoringHub] = None,
93
96
  usage_tracking: bool = False,
@@ -121,6 +124,7 @@ class Config(RepresentationMixin):
121
124
  self.retry_handler = retry_handler
122
125
  self.run_dir = run_dir
123
126
  self.strategy = strategy
127
+ self.strategy_period = strategy_period
124
128
  self.max_idletime = max_idletime
125
129
  self.usage_tracking = usage_tracking
126
130
  self.initialize_logging = initialize_logging
@@ -95,7 +95,7 @@ class DataFlowKernel:
95
95
  self.checkpoint_lock = threading.Lock()
96
96
 
97
97
  self.usage_tracker = UsageTracker(self)
98
- self.usage_tracker.send_message()
98
+ self.usage_tracker.send_start_message()
99
99
 
100
100
  self.task_state_counts_lock = threading.Lock()
101
101
  self.task_state_counts = {state: 0 for state in States}
@@ -178,6 +178,7 @@ class DataFlowKernel:
178
178
  # this must be set before executors are added since add_executors calls
179
179
  # job_status_poller.add_executors.
180
180
  self.job_status_poller = JobStatusPoller(strategy=self.config.strategy,
181
+ strategy_period=self.config.strategy_period,
181
182
  max_idletime=self.config.max_idletime,
182
183
  dfk=self)
183
184
 
@@ -722,7 +723,10 @@ class DataFlowKernel:
722
723
  self._send_task_log_info(task_record)
723
724
 
724
725
  if hasattr(exec_fu, "parsl_executor_task_id"):
725
- logger.info(f"Parsl task {task_id} try {try_id} launched on executor {executor.label} with executor id {exec_fu.parsl_executor_task_id}")
726
+ logger.info(
727
+ f"Parsl task {task_id} try {try_id} launched on executor {executor.label} "
728
+ f"with executor id {exec_fu.parsl_executor_task_id}")
729
+
726
730
  else:
727
731
  logger.info(f"Parsl task {task_id} try {try_id} launched on executor {executor.label}")
728
732
 
@@ -730,7 +734,8 @@ class DataFlowKernel:
730
734
 
731
735
  return exec_fu
732
736
 
733
- def _add_input_deps(self, executor: str, args: Sequence[Any], kwargs: Dict[str, Any], func: Callable) -> Tuple[Sequence[Any], Dict[str, Any], Callable]:
737
+ def _add_input_deps(self, executor: str, args: Sequence[Any], kwargs: Dict[str, Any], func: Callable) -> Tuple[Sequence[Any], Dict[str, Any],
738
+ Callable]:
734
739
  """Look for inputs of the app that are files. Give the data manager
735
740
  the opportunity to replace a file with a data future for that file,
736
741
  for example wrapping the result of a staging action.
@@ -1142,8 +1147,9 @@ class DataFlowKernel:
1142
1147
 
1143
1148
  def atexit_cleanup(self) -> None:
1144
1149
  if not self.cleanup_called:
1145
- logger.info("DFK cleanup because python process is exiting")
1146
- self.cleanup()
1150
+ logger.warning("Python is exiting with a DFK still running. "
1151
+ "You should call parsl.dfk().cleanup() before "
1152
+ "exiting to release any resources")
1147
1153
  else:
1148
1154
  logger.info("python process is exiting, but DFK has already been cleaned up")
1149
1155
 
@@ -1165,7 +1171,8 @@ class DataFlowKernel:
1165
1171
  fut = task_record['app_fu']
1166
1172
  if not fut.done():
1167
1173
  fut.exception()
1168
- # now app future is done, poll until DFK state is final: a DFK state being final and the app future being done do not imply each other.
1174
+ # now app future is done, poll until DFK state is final: a
1175
+ # DFK state being final and the app future being done do not imply each other.
1169
1176
  while task_record['status'] not in FINAL_STATES:
1170
1177
  time.sleep(0.1)
1171
1178
 
@@ -1200,7 +1207,7 @@ class DataFlowKernel:
1200
1207
  self._checkpoint_timer.close()
1201
1208
 
1202
1209
  # Send final stats
1203
- self.usage_tracker.send_message()
1210
+ self.usage_tracker.send_end_message()
1204
1211
  self.usage_tracker.close()
1205
1212
 
1206
1213
  logger.info("Closing job status poller")
@@ -70,7 +70,9 @@ class TaskRecord(TypedDict, total=False):
70
70
  # these three could be more strongly typed perhaps but I'm not thinking about that now
71
71
  func: Callable
72
72
  fn_hash: str
73
- args: Sequence[Any] # in some places we uses a Tuple[Any, ...] and in some places a List[Any]. This is an attempt to correctly type both of those.
73
+ args: Sequence[Any]
74
+ # in some places we uses a Tuple[Any, ...] and in some places a List[Any].
75
+ # This is an attempt to correctly type both of those.
74
76
  kwargs: Dict[str, Any]
75
77
 
76
78
  time_invoked: Optional[datetime.datetime]
@@ -6,6 +6,7 @@ import threading
6
6
  import queue
7
7
  import datetime
8
8
  import pickle
9
+ from dataclasses import dataclass
9
10
  from multiprocessing import Process, Queue
10
11
  from typing import Dict, Sequence
11
12
  from typing import List, Optional, Tuple, Union, Callable
@@ -54,6 +55,7 @@ DEFAULT_LAUNCH_CMD = ("process_worker_pool.py {debug} {max_workers_per_node} "
54
55
  "--hb_period={heartbeat_period} "
55
56
  "{address_probe_timeout_string} "
56
57
  "--hb_threshold={heartbeat_threshold} "
58
+ "--drain_period={drain_period} "
57
59
  "--cpu-affinity {cpu_affinity} "
58
60
  "{enable_mpi_mode} "
59
61
  "--mpi-launcher={mpi_launcher} "
@@ -200,6 +202,14 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
200
202
  Timeout period to be used by the executor components in milliseconds. Increasing poll_periods
201
203
  trades performance for cpu efficiency. Default: 10ms
202
204
 
205
+ drain_period : int
206
+ The number of seconds after start when workers will begin to drain
207
+ and then exit. Set this to a time that is slightly less than the
208
+ maximum walltime of batch jobs to avoid killing tasks while they
209
+ execute. For example, you could set this to the walltime minus a grace
210
+ period for the batch job to start the workers, minus the expected
211
+ maximum length of an individual task.
212
+
203
213
  worker_logdir_root : string
204
214
  In case of a remote file system, specify the path to where logs will be kept.
205
215
 
@@ -239,6 +249,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
239
249
  prefetch_capacity: int = 0,
240
250
  heartbeat_threshold: int = 120,
241
251
  heartbeat_period: int = 30,
252
+ drain_period: Optional[int] = None,
242
253
  poll_period: int = 10,
243
254
  address_probe_timeout: Optional[int] = None,
244
255
  worker_logdir_root: Optional[str] = None,
@@ -302,6 +313,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
302
313
  self.interchange_port_range = interchange_port_range
303
314
  self.heartbeat_threshold = heartbeat_threshold
304
315
  self.heartbeat_period = heartbeat_period
316
+ self.drain_period = drain_period
305
317
  self.poll_period = poll_period
306
318
  self.run_dir = '.'
307
319
  self.worker_logdir_root = worker_logdir_root
@@ -327,7 +339,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
327
339
  def _warn_deprecated(self, old: str, new: str):
328
340
  warnings.warn(
329
341
  f"{old} is deprecated and will be removed in a future release. "
330
- "Please use {new} instead.",
342
+ f"Please use {new} instead.",
331
343
  DeprecationWarning,
332
344
  stacklevel=2
333
345
  )
@@ -375,6 +387,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
375
387
  nodes_per_block=self.provider.nodes_per_block,
376
388
  heartbeat_period=self.heartbeat_period,
377
389
  heartbeat_threshold=self.heartbeat_threshold,
390
+ drain_period=self.drain_period,
378
391
  poll_period=self.poll_period,
379
392
  cert_dir=self.cert_dir,
380
393
  logdir=self.worker_logdir,
@@ -628,8 +641,8 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
628
641
  """Submits work to the outgoing_q.
629
642
 
630
643
  The outgoing_q is an external process listens on this
631
- queue for new work. This method behaves like a
632
- submit call as described here `Python docs: <https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor>`_
644
+ queue for new work. This method behaves like a submit call as described here `Python docs: <https://docs.python.org/3/
645
+ library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor>`_
633
646
 
634
647
  Args:
635
648
  - func (callable) : Callable function
@@ -694,7 +707,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
694
707
  def workers_per_node(self) -> Union[int, float]:
695
708
  return self._workers_per_node
696
709
 
697
- def scale_in(self, blocks, max_idletime=None):
710
+ def scale_in(self, blocks: int, max_idletime: Optional[float] = None) -> List[str]:
698
711
  """Scale in the number of active blocks by specified amount.
699
712
 
700
713
  The scale in method here is very rude. It doesn't give the workers
@@ -721,25 +734,36 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin):
721
734
  List of block IDs scaled in
722
735
  """
723
736
  logger.debug(f"Scale in called, blocks={blocks}")
737
+
738
+ @dataclass
739
+ class BlockInfo:
740
+ tasks: int # sum of tasks in this block
741
+ idle: float # shortest idle time of any manager in this block
742
+
724
743
  managers = self.connected_managers()
725
- block_info = {} # block id -> list( tasks, idle duration )
744
+ block_info: Dict[str, BlockInfo] = {}
726
745
  for manager in managers:
727
746
  if not manager['active']:
728
747
  continue
729
748
  b_id = manager['block_id']
730
749
  if b_id not in block_info:
731
- block_info[b_id] = [0, float('inf')]
732
- block_info[b_id][0] += manager['tasks']
733
- block_info[b_id][1] = min(block_info[b_id][1], manager['idle_duration'])
750
+ block_info[b_id] = BlockInfo(tasks=0, idle=float('inf'))
751
+ block_info[b_id].tasks += manager['tasks']
752
+ block_info[b_id].idle = min(block_info[b_id].idle, manager['idle_duration'])
753
+
754
+ # The scaling policy is that longest idle blocks should be scaled down
755
+ # in preference to least idle (most recently used) blocks.
756
+ # Other policies could be implemented here.
757
+
758
+ sorted_blocks = sorted(block_info.items(), key=lambda item: (-item[1].idle, item[1].tasks))
734
759
 
735
- sorted_blocks = sorted(block_info.items(), key=lambda item: (item[1][1], item[1][0]))
736
760
  logger.debug(f"Scale in selecting from {len(sorted_blocks)} blocks")
737
761
  if max_idletime is None:
738
762
  block_ids_to_kill = [x[0] for x in sorted_blocks[:blocks]]
739
763
  else:
740
764
  block_ids_to_kill = []
741
765
  for x in sorted_blocks:
742
- if x[1][1] > max_idletime and x[1][0] == 0:
766
+ if x[1].idle > max_idletime and x[1].tasks == 0:
743
767
  block_ids_to_kill.append(x[0])
744
768
  if len(block_ids_to_kill) == blocks:
745
769
  break
@@ -28,6 +28,7 @@ from parsl.process_loggers import wrap_with_logs
28
28
 
29
29
 
30
30
  PKL_HEARTBEAT_CODE = pickle.dumps((2 ** 32) - 1)
31
+ PKL_DRAINED_CODE = pickle.dumps((2 ** 32) - 2)
31
32
 
32
33
  LOGGER_NAME = "interchange"
33
34
  logger = logging.getLogger(LOGGER_NAME)
@@ -101,12 +102,12 @@ class Interchange:
101
102
  This is overridden when the worker_ports option is set. Default: (54000, 55000)
102
103
 
103
104
  hub_address : str
104
- The ip address at which the interchange can send info about managers to when monitoring is enabled.
105
- This is passed via dfk and executor automatically. Default: None (meaning monitoring disabled)
105
+ The IP address at which the interchange can send info about managers to when monitoring is enabled.
106
+ Default: None (meaning monitoring disabled)
106
107
 
107
108
  hub_port : str
108
109
  The port at which the interchange can send info about managers to when monitoring is enabled.
109
- This is passed via dfk and executor automatically. Default: None (meaning monitoring disabled)
110
+ Default: None (meaning monitoring disabled)
110
111
 
111
112
  heartbeat_threshold : int
112
113
  Number of seconds since the last heartbeat after which worker is considered lost.
@@ -244,19 +245,19 @@ class Interchange:
244
245
 
245
246
  def _create_monitoring_channel(self) -> Optional[zmq.Socket]:
246
247
  if self.hub_address and self.hub_port:
247
- logger.info("Connecting to monitoring")
248
+ logger.info("Connecting to MonitoringHub")
248
249
  # This is a one-off because monitoring is unencrypted
249
250
  hub_channel = zmq.Context().socket(zmq.DEALER)
250
251
  hub_channel.set_hwm(0)
251
252
  hub_channel.connect("tcp://{}:{}".format(self.hub_address, self.hub_port))
252
- logger.info("Monitoring enabled and connected to hub")
253
+ logger.info("Connected to MonitoringHub")
253
254
  return hub_channel
254
255
  else:
255
256
  return None
256
257
 
257
258
  def _send_monitoring_info(self, hub_channel: Optional[zmq.Socket], manager: ManagerRecord) -> None:
258
259
  if hub_channel:
259
- logger.info("Sending message {} to hub".format(manager))
260
+ logger.info("Sending message {} to MonitoringHub".format(manager))
260
261
 
261
262
  d: Dict = cast(Dict, manager.copy())
262
263
  d['timestamp'] = datetime.datetime.now()
@@ -308,7 +309,8 @@ class Interchange:
308
309
  'worker_count': m['worker_count'],
309
310
  'tasks': len(m['tasks']),
310
311
  'idle_duration': idle_duration,
311
- 'active': m['active']}
312
+ 'active': m['active'],
313
+ 'draining': m['draining']}
312
314
  reply.append(resp)
313
315
 
314
316
  elif command_req.startswith("HOLD_WORKER"):
@@ -385,6 +387,7 @@ class Interchange:
385
387
  self.process_task_outgoing_incoming(interesting_managers, hub_channel, kill_event)
386
388
  self.process_results_incoming(interesting_managers, hub_channel)
387
389
  self.expire_bad_managers(interesting_managers, hub_channel)
390
+ self.expire_drained_managers(interesting_managers, hub_channel)
388
391
  self.process_tasks_to_send(interesting_managers)
389
392
 
390
393
  self.zmq_context.destroy()
@@ -392,7 +395,12 @@ class Interchange:
392
395
  logger.info("Processed {} tasks in {} seconds".format(self.count, delta))
393
396
  logger.warning("Exiting")
394
397
 
395
- def process_task_outgoing_incoming(self, interesting_managers: Set[bytes], hub_channel: Optional[zmq.Socket], kill_event: threading.Event) -> None:
398
+ def process_task_outgoing_incoming(
399
+ self,
400
+ interesting_managers: Set[bytes],
401
+ hub_channel: Optional[zmq.Socket],
402
+ kill_event: threading.Event
403
+ ) -> None:
396
404
  """Process one message from manager on the task_outgoing channel.
397
405
  Note that this message flow is in contradiction to the name of the
398
406
  channel - it is not an outgoing message and it is not a task.
@@ -426,6 +434,7 @@ class Interchange:
426
434
  'max_capacity': 0,
427
435
  'worker_count': 0,
428
436
  'active': True,
437
+ 'draining': False,
429
438
  'tasks': []}
430
439
  self.connected_block_history.append(msg['block_id'])
431
440
 
@@ -464,10 +473,28 @@ class Interchange:
464
473
  self._ready_managers[manager_id]['last_heartbeat'] = time.time()
465
474
  logger.debug("Manager {!r} sent heartbeat via tasks connection".format(manager_id))
466
475
  self.task_outgoing.send_multipart([manager_id, b'', PKL_HEARTBEAT_CODE])
476
+ elif msg['type'] == 'drain':
477
+ self._ready_managers[manager_id]['draining'] = True
478
+ logger.debug(f"Manager {manager_id!r} requested drain")
467
479
  else:
468
480
  logger.error(f"Unexpected message type received from manager: {msg['type']}")
469
481
  logger.debug("leaving task_outgoing section")
470
482
 
483
+ def expire_drained_managers(self, interesting_managers: Set[bytes], hub_channel: Optional[zmq.Socket]) -> None:
484
+
485
+ for manager_id in list(interesting_managers):
486
+ # is it always true that a draining manager will be in interesting managers?
487
+ # i think so because it will have outstanding capacity?
488
+ m = self._ready_managers[manager_id]
489
+ if m['draining'] and len(m['tasks']) == 0:
490
+ logger.info(f"Manager {manager_id!r} is drained - sending drained message to manager")
491
+ self.task_outgoing.send_multipart([manager_id, b'', PKL_DRAINED_CODE])
492
+ interesting_managers.remove(manager_id)
493
+ self._ready_managers.pop(manager_id)
494
+
495
+ m['active'] = False
496
+ self._send_monitoring_info(hub_channel, m)
497
+
471
498
  def process_tasks_to_send(self, interesting_managers: Set[bytes]) -> None:
472
499
  # Check if there are tasks that could be sent to managers
473
500
 
@@ -485,7 +512,7 @@ class Interchange:
485
512
  tasks_inflight = len(m['tasks'])
486
513
  real_capacity = m['max_capacity'] - tasks_inflight
487
514
 
488
- if (real_capacity and m['active']):
515
+ if (real_capacity and m['active'] and not m['draining']):
489
516
  tasks = self.get_tasks(real_capacity)
490
517
  if tasks:
491
518
  self.task_outgoing.send_multipart([manager_id, b'', pickle.dumps(tasks)])
@@ -621,7 +648,13 @@ def start_file_logger(filename: str, level: int = logging.DEBUG, format_string:
621
648
  None.
622
649
  """
623
650
  if format_string is None:
624
- format_string = "%(asctime)s.%(msecs)03d %(name)s:%(lineno)d %(processName)s(%(process)d) %(threadName)s %(funcName)s [%(levelname)s] %(message)s"
651
+ format_string = (
652
+
653
+ "%(asctime)s.%(msecs)03d %(name)s:%(lineno)d "
654
+ "%(processName)s(%(process)d) %(threadName)s "
655
+ "%(funcName)s [%(levelname)s] %(message)s"
656
+
657
+ )
625
658
 
626
659
  global logger
627
660
  logger = logging.getLogger(LOGGER_NAME)
@@ -9,6 +9,7 @@ class ManagerRecord(TypedDict, total=False):
9
9
  worker_count: int
10
10
  max_capacity: int
11
11
  active: bool
12
+ draining: bool
12
13
  hostname: str
13
14
  last_heartbeat: float
14
15
  idle_since: Optional[float]
@@ -36,6 +36,7 @@ from parsl.executors.high_throughput.mpi_resource_management import (
36
36
  from parsl.executors.high_throughput.mpi_prefix_composer import compose_all, VALID_LAUNCHERS
37
37
 
38
38
  HEARTBEAT_CODE = (2 ** 32) - 1
39
+ DRAINED_CODE = (2 ** 32) - 2
39
40
 
40
41
 
41
42
  class Manager:
@@ -73,7 +74,8 @@ class Manager:
73
74
  enable_mpi_mode: bool = False,
74
75
  mpi_launcher: str = "mpiexec",
75
76
  available_accelerators: Sequence[str],
76
- cert_dir: Optional[str]):
77
+ cert_dir: Optional[str],
78
+ drain_period: Optional[int]):
77
79
  """
78
80
  Parameters
79
81
  ----------
@@ -138,6 +140,9 @@ class Manager:
138
140
 
139
141
  cert_dir : str | None
140
142
  Path to the certificate directory.
143
+
144
+ drain_period: int | None
145
+ Number of seconds to drain after TODO: could be a nicer timespec involving m,s,h qualifiers for user friendliness?
141
146
  """
142
147
 
143
148
  logger.info("Manager initializing")
@@ -227,6 +232,14 @@ class Manager:
227
232
  self.heartbeat_period = heartbeat_period
228
233
  self.heartbeat_threshold = heartbeat_threshold
229
234
  self.poll_period = poll_period
235
+
236
+ self.drain_time: float
237
+ if drain_period:
238
+ self.drain_time = self._start_time + drain_period
239
+ logger.info(f"Will request drain at {self.drain_time}")
240
+ else:
241
+ self.drain_time = float('inf')
242
+
230
243
  self.cpu_affinity = cpu_affinity
231
244
 
232
245
  # Define accelerator available, adjust worker count accordingly
@@ -262,10 +275,19 @@ class Manager:
262
275
  """ Send heartbeat to the incoming task queue
263
276
  """
264
277
  msg = {'type': 'heartbeat'}
278
+ # don't need to dumps and encode this every time - could do as a global on import?
265
279
  b_msg = json.dumps(msg).encode('utf-8')
266
280
  self.task_incoming.send(b_msg)
267
281
  logger.debug("Sent heartbeat")
268
282
 
283
+ def drain_to_incoming(self):
284
+ """ Send heartbeat to the incoming task queue
285
+ """
286
+ msg = {'type': 'drain'}
287
+ b_msg = json.dumps(msg).encode('utf-8')
288
+ self.task_incoming.send(b_msg)
289
+ logger.debug("Sent drain")
290
+
269
291
  @wrap_with_logs
270
292
  def pull_tasks(self, kill_event):
271
293
  """ Pull tasks from the incoming tasks zmq pipe onto the internal
@@ -298,6 +320,7 @@ class Manager:
298
320
  # time here are correctly copy-pasted from the relevant if
299
321
  # statements.
300
322
  next_interesting_event_time = min(last_beat + self.heartbeat_period,
323
+ self.drain_time,
301
324
  last_interchange_contact + self.heartbeat_threshold)
302
325
  try:
303
326
  pending_task_count = self.pending_task_queue.qsize()
@@ -312,6 +335,14 @@ class Manager:
312
335
  self.heartbeat_to_incoming()
313
336
  last_beat = time.time()
314
337
 
338
+ if self.drain_time and time.time() > self.drain_time:
339
+ logger.info("Requesting drain")
340
+ self.drain_to_incoming()
341
+ self.drain_time = None
342
+ # This will start the pool draining...
343
+ # Drained exit behaviour does not happen here. It will be
344
+ # driven by the interchange sending a DRAINED_CODE message.
345
+
315
346
  poll_duration_s = max(0, next_interesting_event_time - time.time())
316
347
  socks = dict(poller.poll(timeout=poll_duration_s * 1000))
317
348
 
@@ -322,7 +353,9 @@ class Manager:
322
353
 
323
354
  if tasks == HEARTBEAT_CODE:
324
355
  logger.debug("Got heartbeat from interchange")
325
-
356
+ elif tasks == DRAINED_CODE:
357
+ logger.info("Got fulled drained message from interchange - setting kill flag")
358
+ kill_event.set()
326
359
  else:
327
360
  task_recv_counter += len(tasks)
328
361
  logger.debug("Got executor tasks: {}, cumulative count of tasks: {}".format([t['task_id'] for t in tasks], task_recv_counter))
@@ -413,7 +446,9 @@ class Manager:
413
446
  raise WorkerLost(worker_id, platform.node())
414
447
  except Exception:
415
448
  logger.info("Putting exception for executor task {} in the pending result queue".format(task['task_id']))
416
- result_package = {'type': 'result', 'task_id': task['task_id'], 'exception': serialize(RemoteExceptionWrapper(*sys.exc_info()))}
449
+ result_package = {'type': 'result',
450
+ 'task_id': task['task_id'],
451
+ 'exception': serialize(RemoteExceptionWrapper(*sys.exc_info()))}
417
452
  pkl_package = pickle.dumps(result_package)
418
453
  self.pending_result_queue.put(pkl_package)
419
454
  except KeyError:
@@ -488,9 +523,8 @@ class Manager:
488
523
  self._worker_watchdog_thread.start()
489
524
  self._monitoring_handler_thread.start()
490
525
 
491
- logger.info("Loop start")
526
+ logger.info("Manager threads started")
492
527
 
493
- # TODO : Add mechanism in this loop to stop the worker pool
494
528
  # This might need a multiprocessing event to signal back.
495
529
  self._kill_event.wait()
496
530
  logger.critical("Received kill event, terminating worker processes")
@@ -802,6 +836,8 @@ if __name__ == "__main__":
802
836
  help="Heartbeat period in seconds. Uses manager default unless set")
803
837
  parser.add_argument("--hb_threshold", default=120,
804
838
  help="Heartbeat threshold in seconds. Uses manager default unless set")
839
+ parser.add_argument("--drain_period", default=None,
840
+ help="Drain this pool after specified number of seconds. By default, does not drain.")
805
841
  parser.add_argument("--address_probe_timeout", default=30,
806
842
  help="Timeout to probe for viable address to interchange. Default: 30s")
807
843
  parser.add_argument("--poll", default=10,
@@ -822,7 +858,7 @@ if __name__ == "__main__":
822
858
  required=True,
823
859
  help="Whether/how workers should control CPU affinity.")
824
860
  parser.add_argument("--available-accelerators", type=str, nargs="*",
825
- help="Names of available accelerators")
861
+ help="Names of available accelerators, if not given assumed to be zero accelerators available", default=[])
826
862
  parser.add_argument("--enable_mpi_mode", action='store_true',
827
863
  help="Enable MPI mode")
828
864
  parser.add_argument("--mpi-launcher", type=str, choices=VALID_LAUNCHERS,
@@ -854,6 +890,7 @@ if __name__ == "__main__":
854
890
  logger.info("Prefetch capacity: {}".format(args.prefetch_capacity))
855
891
  logger.info("Heartbeat threshold: {}".format(args.hb_threshold))
856
892
  logger.info("Heartbeat period: {}".format(args.hb_period))
893
+ logger.info("Drain period: {}".format(args.drain_period))
857
894
  logger.info("CPU affinity: {}".format(args.cpu_affinity))
858
895
  logger.info("Accelerators: {}".format(" ".join(args.available_accelerators)))
859
896
  logger.info("enable_mpi_mode: {}".format(args.enable_mpi_mode))
@@ -867,10 +904,14 @@ if __name__ == "__main__":
867
904
  block_id=args.block_id,
868
905
  cores_per_worker=float(args.cores_per_worker),
869
906
  mem_per_worker=None if args.mem_per_worker == 'None' else float(args.mem_per_worker),
870
- max_workers_per_node=args.max_workers_per_node if args.max_workers_per_node == float('inf') else int(args.max_workers_per_node),
907
+ max_workers_per_node=(
908
+ args.max_workers_per_node if args.max_workers_per_node == float('inf')
909
+ else int(args.max_workers_per_node)
910
+ ),
871
911
  prefetch_capacity=int(args.prefetch_capacity),
872
912
  heartbeat_threshold=int(args.hb_threshold),
873
913
  heartbeat_period=int(args.hb_period),
914
+ drain_period=None if args.drain_period == "None" else int(args.drain_period),
874
915
  poll_period=int(args.poll),
875
916
  cpu_affinity=args.cpu_affinity,
876
917
  enable_mpi_mode=args.enable_mpi_mode,
@@ -196,8 +196,9 @@ class TaskVineExecutor(BlockProviderExecutor, putils.RepresentationMixin):
196
196
  if self.manager_config.port == 0 and self.manager_config.project_name is None:
197
197
  self.manager_config.project_name = "parsl-vine-" + str(uuid.uuid4())
198
198
 
199
- # guess the host name if the project name is not given
200
- if not self.manager_config.project_name:
199
+ # guess the host name if the project name is not given and none has been supplied
200
+ # explicitly in the manager config.
201
+ if not self.manager_config.project_name and self.manager_config.address is None:
201
202
  self.manager_config.address = get_any_address()
202
203
 
203
204
  # Factory communication settings are overridden by manager communication settings.
@@ -228,7 +229,9 @@ class TaskVineExecutor(BlockProviderExecutor, putils.RepresentationMixin):
228
229
  # factory logs go with manager logs regardless
229
230
  self.factory_config.scratch_dir = self.manager_config.vine_log_dir
230
231
  logger.debug(f"Function data directory: {self._function_data_dir}, log directory: {log_dir}")
231
- logger.debug(f"TaskVine manager log directory: {self.manager_config.vine_log_dir}, factory log directory: {self.factory_config.scratch_dir}")
232
+ logger.debug(
233
+ f"TaskVine manager log directory: {self.manager_config.vine_log_dir}, "
234
+ f"factory log directory: {self.factory_config.scratch_dir}")
232
235
 
233
236
  def start(self):
234
237
  """Create submit process and collector thread to create, send, and
@@ -376,6 +376,7 @@ def _taskvine_submit_wait(ready_task_queue=None,
376
376
  task_out_file = parsl_file_name_to_vine_file[spec.parsl_name]
377
377
  else:
378
378
  task_out_file = m.declare_file(spec.parsl_name, cache=spec.cache, peer_transfer=True)
379
+ parsl_file_name_to_vine_file[spec.parsl_name] = task_out_file
379
380
  t.add_output(task_out_file, spec.parsl_name)
380
381
 
381
382
  # Submit the task to the TaskVine object
@@ -1,4 +1,3 @@
1
- import socket
2
1
  from dataclasses import dataclass
3
2
  from typing import Optional
4
3
 
@@ -23,9 +22,9 @@ class TaskVineManagerConfig:
23
22
  A value of 0 means TaskVine chooses any available port.
24
23
  Default is VINE_DEFAULT_PORT.
25
24
 
26
- address: str
25
+ address: Optional[str]
27
26
  Address of the local machine.
28
- Default is socket.gethostname().
27
+ If None, socket.gethostname() will be used to determine the address.
29
28
 
30
29
  project_name: Optional[str]
31
30
  If given, TaskVine will periodically report its status and performance
@@ -161,7 +160,7 @@ class TaskVineManagerConfig:
161
160
 
162
161
  # Connection and communication settings
163
162
  port: int = VINE_DEFAULT_PORT
164
- address: str = socket.gethostname()
163
+ address: Optional[str] = None
165
164
  project_name: Optional[str] = None
166
165
  project_password_file: Optional[str] = None
167
166
 
@@ -2,7 +2,7 @@ import logging
2
2
  import parsl
3
3
  import time
4
4
  import zmq
5
- from typing import Dict, List, Sequence, Optional
5
+ from typing import Dict, List, Sequence, Optional, Union
6
6
 
7
7
  from parsl.jobs.states import JobStatus, JobState
8
8
  from parsl.jobs.strategy import Strategy
@@ -106,13 +106,14 @@ class PollItem:
106
106
 
107
107
 
108
108
  class JobStatusPoller(Timer):
109
- def __init__(self, strategy: Optional[str] = None, max_idletime: float = 0.0,
109
+ def __init__(self, *, strategy: Optional[str], max_idletime: float,
110
+ strategy_period: Union[float, int],
110
111
  dfk: Optional["parsl.dataflow.dflow.DataFlowKernel"] = None) -> None:
111
112
  self._poll_items = [] # type: List[PollItem]
112
113
  self.dfk = dfk
113
114
  self._strategy = Strategy(strategy=strategy,
114
115
  max_idletime=max_idletime)
115
- super().__init__(self.poll, interval=5, name="JobStatusPoller")
116
+ super().__init__(self.poll, interval=strategy_period, name="JobStatusPoller")
116
117
 
117
118
  def poll(self) -> None:
118
119
  self._update_state()