parsl 2025.5.19__tar.gz → 2025.6.2__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 (475) hide show
  1. {parsl-2025.5.19/parsl.egg-info → parsl-2025.6.2}/PKG-INFO +2 -2
  2. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/addresses.py +2 -3
  3. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/executor.py +12 -10
  4. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/interchange.py +70 -48
  5. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/workqueue/executor.py +6 -4
  6. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/base.py +0 -3
  7. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/pbspro/pbspro.py +22 -4
  8. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/slurm/slurm.py +47 -14
  9. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/conftest.py +15 -4
  10. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_resource_spec.py +2 -2
  11. parsl-2025.6.2/parsl/tests/test_htex/test_priority_queue.py +70 -0
  12. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_resource_spec_validation.py +7 -0
  13. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_zmq_binding.py +12 -2
  14. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_basic.py +23 -4
  15. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_radical/test_mpi_funcs.py +6 -0
  16. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_scale_down.py +1 -0
  17. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/unit/test_address.py +1 -0
  18. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/usage_tracking/usage.py +1 -0
  19. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/version.py +1 -1
  20. {parsl-2025.5.19 → parsl-2025.6.2/parsl.egg-info}/PKG-INFO +2 -2
  21. {parsl-2025.5.19 → parsl-2025.6.2}/parsl.egg-info/SOURCES.txt +1 -0
  22. {parsl-2025.5.19 → parsl-2025.6.2}/parsl.egg-info/requires.txt +1 -0
  23. {parsl-2025.5.19 → parsl-2025.6.2}/requirements.txt +1 -0
  24. {parsl-2025.5.19 → parsl-2025.6.2}/LICENSE +0 -0
  25. {parsl-2025.5.19 → parsl-2025.6.2}/MANIFEST.in +0 -0
  26. {parsl-2025.5.19 → parsl-2025.6.2}/README.rst +0 -0
  27. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/__init__.py +0 -0
  28. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/app/__init__.py +0 -0
  29. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/app/app.py +0 -0
  30. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/app/bash.py +0 -0
  31. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/app/errors.py +0 -0
  32. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/app/futures.py +0 -0
  33. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/app/python.py +0 -0
  34. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/benchmark/__init__.py +0 -0
  35. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/benchmark/perf.py +0 -0
  36. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/concurrent/__init__.py +0 -0
  37. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/config.py +0 -0
  38. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/ASPIRE1.py +0 -0
  39. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/Azure.py +0 -0
  40. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/__init__.py +0 -0
  41. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/bridges.py +0 -0
  42. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/cc_in2p3.py +0 -0
  43. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/ec2.py +0 -0
  44. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/expanse.py +0 -0
  45. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/frontera.py +0 -0
  46. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/gc_multisite.py +0 -0
  47. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/gc_tutorial.py +0 -0
  48. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/htex_local.py +0 -0
  49. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/illinoiscluster.py +0 -0
  50. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/improv.py +0 -0
  51. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/kubernetes.py +0 -0
  52. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/local_threads.py +0 -0
  53. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/midway.py +0 -0
  54. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/osg.py +0 -0
  55. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/polaris.py +0 -0
  56. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/stampede2.py +0 -0
  57. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/summit.py +0 -0
  58. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/toss3_llnl.py +0 -0
  59. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/vineex_local.py +0 -0
  60. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/configs/wqex_local.py +0 -0
  61. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/curvezmq.py +0 -0
  62. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/__init__.py +0 -0
  63. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/data_manager.py +0 -0
  64. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/file_noop.py +0 -0
  65. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/files.py +0 -0
  66. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/ftp.py +0 -0
  67. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/globus.py +0 -0
  68. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/http.py +0 -0
  69. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/rsync.py +0 -0
  70. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/staging.py +0 -0
  71. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/data_provider/zip.py +0 -0
  72. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/__init__.py +0 -0
  73. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/dependency_resolvers.py +0 -0
  74. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/dflow.py +0 -0
  75. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/errors.py +0 -0
  76. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/futures.py +0 -0
  77. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/memoization.py +0 -0
  78. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/rundirs.py +0 -0
  79. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/states.py +0 -0
  80. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/dataflow/taskrecord.py +0 -0
  81. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/errors.py +0 -0
  82. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/__init__.py +0 -0
  83. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/base.py +0 -0
  84. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/errors.py +0 -0
  85. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/execute_task.py +0 -0
  86. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/flux/__init__.py +0 -0
  87. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/flux/execute_parsl_task.py +0 -0
  88. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/flux/executor.py +0 -0
  89. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/flux/flux_instance_manager.py +0 -0
  90. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/globus_compute.py +0 -0
  91. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/__init__.py +0 -0
  92. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/errors.py +0 -0
  93. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/manager_record.py +0 -0
  94. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/manager_selector.py +0 -0
  95. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/monitoring_info.py +0 -0
  96. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/mpi_executor.py +0 -0
  97. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/mpi_prefix_composer.py +0 -0
  98. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/mpi_resource_management.py +0 -0
  99. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/probe.py +0 -0
  100. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/process_worker_pool.py +0 -0
  101. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/high_throughput/zmq_pipes.py +0 -0
  102. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/radical/__init__.py +0 -0
  103. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/radical/executor.py +0 -0
  104. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/radical/rpex_resources.py +0 -0
  105. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/radical/rpex_worker.py +0 -0
  106. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/status_handling.py +0 -0
  107. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/__init__.py +0 -0
  108. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/errors.py +0 -0
  109. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/exec_parsl_function.py +0 -0
  110. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/executor.py +0 -0
  111. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/factory.py +0 -0
  112. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/factory_config.py +0 -0
  113. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/manager.py +0 -0
  114. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/manager_config.py +0 -0
  115. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/taskvine/utils.py +0 -0
  116. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/threads.py +0 -0
  117. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/workqueue/__init__.py +0 -0
  118. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/workqueue/errors.py +0 -0
  119. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/workqueue/exec_parsl_function.py +0 -0
  120. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/workqueue/parsl_coprocess.py +0 -0
  121. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/executors/workqueue/parsl_coprocess_stub.py +0 -0
  122. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/jobs/__init__.py +0 -0
  123. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/jobs/error_handlers.py +0 -0
  124. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/jobs/errors.py +0 -0
  125. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/jobs/job_status_poller.py +0 -0
  126. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/jobs/states.py +0 -0
  127. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/jobs/strategy.py +0 -0
  128. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/launchers/__init__.py +0 -0
  129. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/launchers/base.py +0 -0
  130. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/launchers/errors.py +0 -0
  131. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/launchers/launchers.py +0 -0
  132. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/log_utils.py +0 -0
  133. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/__init__.py +0 -0
  134. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/db_manager.py +0 -0
  135. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/errors.py +0 -0
  136. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/message_type.py +0 -0
  137. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/monitoring.py +0 -0
  138. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/queries/__init__.py +0 -0
  139. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/queries/pandas.py +0 -0
  140. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/__init__.py +0 -0
  141. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/filesystem.py +0 -0
  142. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/filesystem_router.py +0 -0
  143. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/htex.py +0 -0
  144. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/multiprocessing.py +0 -0
  145. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/udp.py +0 -0
  146. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/udp_router.py +0 -0
  147. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/zmq.py +0 -0
  148. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/radios/zmq_router.py +0 -0
  149. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/remote.py +0 -0
  150. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/types.py +0 -0
  151. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/__init__.py +0 -0
  152. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/app.py +0 -0
  153. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/models.py +0 -0
  154. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/plots/__init__.py +0 -0
  155. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/plots/default/__init__.py +0 -0
  156. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/plots/default/task_plots.py +0 -0
  157. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/plots/default/workflow_plots.py +0 -0
  158. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/plots/default/workflow_resource_plots.py +0 -0
  159. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/static/parsl-logo-white.png +0 -0
  160. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/static/parsl-monitor.css +0 -0
  161. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/app.html +0 -0
  162. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/dag.html +0 -0
  163. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/error.html +0 -0
  164. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/layout.html +0 -0
  165. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/resource_usage.html +0 -0
  166. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/task.html +0 -0
  167. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/workflow.html +0 -0
  168. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/templates/workflows_summary.html +0 -0
  169. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/utils.py +0 -0
  170. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/version.py +0 -0
  171. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/monitoring/visualization/views.py +0 -0
  172. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/multiprocessing.py +0 -0
  173. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/process_loggers.py +0 -0
  174. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/__init__.py +0 -0
  175. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/aws/__init__.py +0 -0
  176. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/aws/aws.py +0 -0
  177. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/aws/template.py +0 -0
  178. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/azure/__init__.py +0 -0
  179. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/azure/azure.py +0 -0
  180. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/azure/template.py +0 -0
  181. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/base.py +0 -0
  182. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/cluster_provider.py +0 -0
  183. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/condor/__init__.py +0 -0
  184. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/condor/condor.py +0 -0
  185. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/condor/template.py +0 -0
  186. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/errors.py +0 -0
  187. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/googlecloud/__init__.py +0 -0
  188. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/googlecloud/googlecloud.py +0 -0
  189. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/grid_engine/__init__.py +0 -0
  190. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/grid_engine/grid_engine.py +0 -0
  191. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/grid_engine/template.py +0 -0
  192. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/kubernetes/__init__.py +0 -0
  193. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/kubernetes/kube.py +0 -0
  194. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/kubernetes/template.py +0 -0
  195. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/local/__init__.py +0 -0
  196. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/local/local.py +0 -0
  197. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/lsf/__init__.py +0 -0
  198. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/lsf/lsf.py +0 -0
  199. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/lsf/template.py +0 -0
  200. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/pbspro/__init__.py +0 -0
  201. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/pbspro/template.py +0 -0
  202. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/slurm/__init__.py +0 -0
  203. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/slurm/template.py +0 -0
  204. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/torque/__init__.py +0 -0
  205. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/torque/template.py +0 -0
  206. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/providers/torque/torque.py +0 -0
  207. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/py.typed +0 -0
  208. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/serialize/__init__.py +0 -0
  209. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/serialize/base.py +0 -0
  210. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/serialize/concretes.py +0 -0
  211. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/serialize/errors.py +0 -0
  212. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/serialize/facade.py +0 -0
  213. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/serialize/proxystore.py +0 -0
  214. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/__init__.py +0 -0
  215. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/callables_helper.py +0 -0
  216. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/__init__.py +0 -0
  217. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/azure_single_node.py +0 -0
  218. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/bluewaters.py +0 -0
  219. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/bridges.py +0 -0
  220. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/cc_in2p3.py +0 -0
  221. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/comet.py +0 -0
  222. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/ec2_single_node.py +0 -0
  223. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/ec2_spot.py +0 -0
  224. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/flux_local.py +0 -0
  225. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/frontera.py +0 -0
  226. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/globus_compute.py +0 -0
  227. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/htex_local.py +0 -0
  228. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/htex_local_alternate.py +0 -0
  229. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/htex_local_intask_staging.py +0 -0
  230. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/htex_local_rsync_staging.py +0 -0
  231. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_radical.py +0 -0
  232. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_radical_mpi.py +0 -0
  233. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads.py +0 -0
  234. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_checkpoint.py +0 -0
  235. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_checkpoint_dfk_exit.py +0 -0
  236. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_checkpoint_periodic.py +0 -0
  237. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_checkpoint_task_exit.py +0 -0
  238. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_ftp_in_task.py +0 -0
  239. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_globus.py +0 -0
  240. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_http_in_task.py +0 -0
  241. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_monitoring.py +0 -0
  242. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/local_threads_no_cache.py +0 -0
  243. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/midway.py +0 -0
  244. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/nscc_singapore.py +0 -0
  245. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/osg_htex.py +0 -0
  246. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/petrelkube.py +0 -0
  247. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/slurm_local.py +0 -0
  248. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/summit.py +0 -0
  249. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/taskvine_ex.py +0 -0
  250. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/user_opts.py +0 -0
  251. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/configs/workqueue_ex.py +0 -0
  252. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/integration/__init__.py +0 -0
  253. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/integration/latency.py +0 -0
  254. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/integration/test_apps/__init__.py +0 -0
  255. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/integration/test_parsl_load_default_config.py +0 -0
  256. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/integration/test_stress/__init__.py +0 -0
  257. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/integration/test_stress/test_python_simple.py +0 -0
  258. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/integration/test_stress/test_python_threads.py +0 -0
  259. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/__init__.py +0 -0
  260. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/htex_local.py +0 -0
  261. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/test_basic.py +0 -0
  262. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/test_log_filter.py +0 -0
  263. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/test_memory_limits.py +0 -0
  264. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/test_regression_220.py +0 -0
  265. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/test_udp_simple.py +0 -0
  266. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/manual_tests/test_worker_count.py +0 -0
  267. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/__init__.py +0 -0
  268. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/htex_local.py +0 -0
  269. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/local_threads.py +0 -0
  270. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/test_scale.py +0 -0
  271. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/vineex_condor.py +0 -0
  272. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/vineex_local.py +0 -0
  273. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/wqex_condor.py +0 -0
  274. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/scaling_tests/wqex_local.py +0 -0
  275. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/site_tests/__init__.py +0 -0
  276. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/site_tests/site_config_selector.py +0 -0
  277. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/site_tests/test_provider.py +0 -0
  278. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/site_tests/test_site.py +0 -0
  279. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/__init__.py +0 -0
  280. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/test_affinity.py +0 -0
  281. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/test_concurrent.py +0 -0
  282. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/test_dynamic_executor.py +0 -0
  283. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/test_ec2.py +0 -0
  284. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/test_launchers.py +0 -0
  285. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/test_mpi/__init__.py +0 -0
  286. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/sites/test_worker_info.py +0 -0
  287. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_aalst_patterns.py +0 -0
  288. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/__init__.py +0 -0
  289. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_apptimeout.py +0 -0
  290. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_basic.py +0 -0
  291. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_error_codes.py +0 -0
  292. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_inputs_default.py +0 -0
  293. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_keyword_overlaps.py +0 -0
  294. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_kwarg_storage.py +0 -0
  295. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_memoize.py +0 -0
  296. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_memoize_ignore_args.py +0 -0
  297. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +0 -0
  298. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_multiline.py +0 -0
  299. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_pipeline.py +0 -0
  300. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_std_uri.py +0 -0
  301. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_bash_apps/test_stdout.py +0 -0
  302. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_callables.py +0 -0
  303. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/__init__.py +0 -0
  304. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/test_periodic.py +0 -0
  305. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/test_python_checkpoint_1.py +0 -0
  306. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/test_python_checkpoint_2.py +0 -0
  307. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/test_regression_232.py +0 -0
  308. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/test_regression_233.py +0 -0
  309. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/test_regression_239.py +0 -0
  310. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_checkpointing/test_task_exit.py +0 -0
  311. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_curvezmq.py +0 -0
  312. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_docs/__init__.py +0 -0
  313. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_docs/test_from_slides.py +0 -0
  314. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_docs/test_kwargs.py +0 -0
  315. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_docs/test_tutorial_1.py +0 -0
  316. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_docs/test_workflow1.py +0 -0
  317. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_docs/test_workflow2.py +0 -0
  318. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_docs/test_workflow4.py +0 -0
  319. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/__init__.py +0 -0
  320. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_fail.py +0 -0
  321. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_python_walltime.py +0 -0
  322. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_rand_fail.py +0 -0
  323. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_retries.py +0 -0
  324. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_retry_handler.py +0 -0
  325. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_retry_handler_failure.py +0 -0
  326. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_serialization_fail.py +0 -0
  327. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_error_handling/test_wrap_with_logs.py +0 -0
  328. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_execute_task.py +0 -0
  329. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_flowcontrol/__init__.py +0 -0
  330. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_flux.py +0 -0
  331. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/__init__.py +0 -0
  332. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_basic.py +0 -0
  333. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_block_manager_selector_unit.py +0 -0
  334. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_command_client_timeout.py +0 -0
  335. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_connected_blocks.py +0 -0
  336. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_cpu_affinity_explicit.py +0 -0
  337. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_disconnected_blocks.py +0 -0
  338. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_disconnected_blocks_failing_provider.py +0 -0
  339. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_drain.py +0 -0
  340. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_htex.py +0 -0
  341. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_interchange_exit_bad_registration.py +0 -0
  342. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_manager_failure.py +0 -0
  343. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_manager_selector_by_block.py +0 -0
  344. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_managers_command.py +0 -0
  345. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_missing_worker.py +0 -0
  346. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_multiple_disconnected_blocks.py +0 -0
  347. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_htex/test_worker_failure.py +0 -0
  348. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/__init__.py +0 -0
  349. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_app_names.py +0 -0
  350. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_db_locks.py +0 -0
  351. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_exit_helper.py +0 -0
  352. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_fuzz_zmq.py +0 -0
  353. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_htex_init_blocks_vs_monitoring.py +0 -0
  354. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_incomplete_futures.py +0 -0
  355. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_memoization_representation.py +0 -0
  356. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_radio_zmq.py +0 -0
  357. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_stdouterr.py +0 -0
  358. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_monitoring/test_viz_colouring.py +0 -0
  359. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_mpi_apps/__init__.py +0 -0
  360. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_mpi_apps/test_bad_mpi_config.py +0 -0
  361. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py +0 -0
  362. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_mpi_apps/test_mpi_prefix.py +0 -0
  363. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_mpi_apps/test_mpi_scheduler.py +0 -0
  364. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_mpi_apps/test_mpiex.py +0 -0
  365. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_mpi_apps/test_resource_spec.py +0 -0
  366. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_providers/__init__.py +0 -0
  367. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_providers/test_kubernetes_provider.py +0 -0
  368. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_providers/test_local_provider.py +0 -0
  369. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_providers/test_pbspro_template.py +0 -0
  370. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_providers/test_slurm_instantiate.py +0 -0
  371. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_providers/test_slurm_template.py +0 -0
  372. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_providers/test_submiterror_deprecation.py +0 -0
  373. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/__init__.py +0 -0
  374. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_arg_input_types.py +0 -0
  375. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_basic.py +0 -0
  376. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_context_manager.py +0 -0
  377. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_dep_standard_futures.py +0 -0
  378. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_dependencies.py +0 -0
  379. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_dependencies_deep.py +0 -0
  380. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_depfail_propagation.py +0 -0
  381. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_fail.py +0 -0
  382. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_fibonacci_iterative.py +0 -0
  383. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_fibonacci_recursive.py +0 -0
  384. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_futures.py +0 -0
  385. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_garbage_collect.py +0 -0
  386. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_import_fail.py +0 -0
  387. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_inputs_default.py +0 -0
  388. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_join.py +0 -0
  389. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_lifted.py +0 -0
  390. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_mapred.py +0 -0
  391. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_memoize_1.py +0 -0
  392. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_memoize_2.py +0 -0
  393. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_memoize_4.py +0 -0
  394. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_memoize_bad_id_for_memo.py +0 -0
  395. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_memoize_ignore_args.py +0 -0
  396. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_memoize_joinapp.py +0 -0
  397. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_outputs.py +0 -0
  398. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_overview.py +0 -0
  399. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_pipeline.py +0 -0
  400. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_pluggable_future_resolution.py +0 -0
  401. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_simple.py +0 -0
  402. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_timeout.py +0 -0
  403. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_python_apps/test_type5.py +0 -0
  404. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_radical/__init__.py +0 -0
  405. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/__init__.py +0 -0
  406. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_1480.py +0 -0
  407. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_1606_wait_for_current_tasks.py +0 -0
  408. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_1653.py +0 -0
  409. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_221.py +0 -0
  410. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_226.py +0 -0
  411. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_2652.py +0 -0
  412. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_69a.py +0 -0
  413. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_854.py +0 -0
  414. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_97_parallelism_0.py +0 -0
  415. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_regression/test_98.py +0 -0
  416. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/__init__.py +0 -0
  417. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_block_error_handler.py +0 -0
  418. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_regression_1621.py +0 -0
  419. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_regression_3568_scaledown_vs_MISSING.py +0 -0
  420. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_regression_3696_oscillation.py +0 -0
  421. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_scale_down_htex_auto_scale.py +0 -0
  422. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_scale_down_htex_unregistered.py +0 -0
  423. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_shutdown_scalein.py +0 -0
  424. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_scaling/test_worker_interchange_bad_messages_3262.py +0 -0
  425. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/__init__.py +0 -0
  426. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/test_2555_caching_deserializer.py +0 -0
  427. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/test_3495_deserialize_managerlost.py +0 -0
  428. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/test_basic.py +0 -0
  429. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/test_htex_code_cache.py +0 -0
  430. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/test_pack_resource_spec.py +0 -0
  431. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/test_proxystore_configured.py +0 -0
  432. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_serialization/test_proxystore_impl.py +0 -0
  433. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_shutdown/__init__.py +0 -0
  434. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_shutdown/test_kill_monitoring.py +0 -0
  435. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/__init__.py +0 -0
  436. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/staging_provider.py +0 -0
  437. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_1316.py +0 -0
  438. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_docs_1.py +0 -0
  439. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_docs_2.py +0 -0
  440. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_elaborate_noop_file.py +0 -0
  441. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_file.py +0 -0
  442. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_file_apps.py +0 -0
  443. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_file_staging.py +0 -0
  444. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_output_chain_filenames.py +0 -0
  445. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_staging_ftp.py +0 -0
  446. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_staging_ftp_in_task.py +0 -0
  447. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_staging_globus.py +0 -0
  448. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_staging_https.py +0 -0
  449. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_staging_stdout.py +0 -0
  450. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_zip_in.py +0 -0
  451. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_zip_out.py +0 -0
  452. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_staging/test_zip_to_zip.py +0 -0
  453. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_summary.py +0 -0
  454. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_thread_parallelism.py +0 -0
  455. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_threads/__init__.py +0 -0
  456. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_threads/test_configs.py +0 -0
  457. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_threads/test_lazy_errors.py +0 -0
  458. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_utils/__init__.py +0 -0
  459. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_utils/test_execute_wait.py +0 -0
  460. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_utils/test_representation_mixin.py +0 -0
  461. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/test_utils/test_sanitize_dns.py +0 -0
  462. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/unit/__init__.py +0 -0
  463. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/unit/test_file.py +0 -0
  464. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/unit/test_globus_compute_executor.py +0 -0
  465. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/unit/test_usage_tracking.py +0 -0
  466. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/tests/utils.py +0 -0
  467. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/usage_tracking/__init__.py +0 -0
  468. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/usage_tracking/api.py +0 -0
  469. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/usage_tracking/levels.py +0 -0
  470. {parsl-2025.5.19 → parsl-2025.6.2}/parsl/utils.py +0 -0
  471. {parsl-2025.5.19 → parsl-2025.6.2}/parsl.egg-info/dependency_links.txt +0 -0
  472. {parsl-2025.5.19 → parsl-2025.6.2}/parsl.egg-info/entry_points.txt +0 -0
  473. {parsl-2025.5.19 → parsl-2025.6.2}/parsl.egg-info/top_level.txt +0 -0
  474. {parsl-2025.5.19 → parsl-2025.6.2}/setup.cfg +0 -0
  475. {parsl-2025.5.19 → parsl-2025.6.2}/setup.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: parsl
3
- Version: 2025.5.19
3
+ Version: 2025.6.2
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/2025.05.19.tar.gz
6
+ Download-URL: https://github.com/Parsl/parsl/archive/2025.06.02.tar.gz
7
7
  Author: The Parsl Team
8
8
  Author-email: parsl@googlegroups.com
9
9
  License: Apache 2.0
@@ -161,13 +161,12 @@ def get_any_address() -> str:
161
161
 
162
162
  def tcp_url(address: str, port: Union[str, int, None] = None) -> str:
163
163
  """Construct a tcp url safe for IPv4 and IPv6"""
164
+ port_suffix = f":{port}" if port else ""
164
165
  if address == "*":
165
- return "tcp://*"
166
+ return "tcp://*" + port_suffix
166
167
 
167
168
  ip_addr = ipaddress.ip_address(address)
168
169
 
169
- port_suffix = f":{port}" if port else ""
170
-
171
170
  if ip_addr.version == 6 and port_suffix:
172
171
  url = f"tcp://[{address}]{port_suffix}"
173
172
  else:
@@ -8,7 +8,7 @@ import warnings
8
8
  from collections import defaultdict
9
9
  from concurrent.futures import Future
10
10
  from dataclasses import dataclass
11
- from typing import Callable, Dict, List, Optional, Sequence, Set, Tuple, Union
11
+ from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union
12
12
 
13
13
  import typeguard
14
14
 
@@ -363,7 +363,9 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin, UsageIn
363
363
 
364
364
  def validate_resource_spec(self, resource_specification: dict):
365
365
  if resource_specification:
366
- acceptable_fields: Set[str] = set() # add new resource spec field names here to make htex accept them
366
+ """HTEX supports the following *Optional* resource specifications:
367
+ priority: lower value is higher priority"""
368
+ acceptable_fields = {'priority'} # add new resource spec field names here to make htex accept them
367
369
  keys = set(resource_specification.keys())
368
370
  invalid_keys = keys - acceptable_fields
369
371
  if invalid_keys:
@@ -599,20 +601,20 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin, UsageIn
599
601
  self._result_queue_thread.start()
600
602
  logger.debug("Started result queue thread: %r", self._result_queue_thread)
601
603
 
602
- def hold_worker(self, worker_id: str) -> None:
603
- """Puts a worker on hold, preventing scheduling of additional tasks to it.
604
+ def _hold_manager(self, manager_id: str) -> None:
605
+ """Puts a manager on hold, preventing scheduling of additional tasks to it.
604
606
 
605
607
  This is called "hold" mostly because this only stops scheduling of tasks,
606
- and does not actually kill the worker.
608
+ and does not actually kill the manager or workers.
607
609
 
608
610
  Parameters
609
611
  ----------
610
612
 
611
- worker_id : str
612
- Worker id to be put on hold
613
+ manager_id : str
614
+ Manager id to be put on hold
613
615
  """
614
- self.command_client.run("HOLD_WORKER;{}".format(worker_id))
615
- logger.debug("Sent hold request to manager: {}".format(worker_id))
616
+ self.command_client.run("HOLD_WORKER;{}".format(manager_id))
617
+ logger.debug("Sent hold request to manager: {}".format(manager_id))
616
618
 
617
619
  @property
618
620
  def outstanding(self) -> int:
@@ -656,7 +658,7 @@ class HighThroughputExecutor(BlockProviderExecutor, RepresentationMixin, UsageIn
656
658
  for manager in managers:
657
659
  if manager['block_id'] == block_id:
658
660
  logger.debug("Sending hold to manager: {}".format(manager['manager']))
659
- self.hold_worker(manager['manager'])
661
+ self._hold_manager(manager['manager'])
660
662
 
661
663
  def submit(self, func, resource_specification, *args, **kwargs):
662
664
  """Submits work to the outgoing_q.
@@ -5,13 +5,13 @@ import logging
5
5
  import os
6
6
  import pickle
7
7
  import platform
8
- import queue
9
8
  import sys
10
9
  import threading
11
10
  import time
12
11
  from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, cast
13
12
 
14
13
  import zmq
14
+ from sortedcontainers import SortedList
15
15
 
16
16
  from parsl import curvezmq
17
17
  from parsl.addresses import tcp_url
@@ -131,7 +131,7 @@ class Interchange:
131
131
  self.hub_address = hub_address
132
132
  self.hub_zmq_port = hub_zmq_port
133
133
 
134
- self.pending_task_queue: queue.Queue[Any] = queue.Queue(maxsize=10 ** 6)
134
+ self.pending_task_queue: SortedList[Any] = SortedList(key=lambda tup: (tup[0], tup[1]))
135
135
 
136
136
  # count of tasks that have been received from the submit side
137
137
  self.task_counter = 0
@@ -196,13 +196,12 @@ class Interchange:
196
196
  eg. [{'task_id':<x>, 'buffer':<buf>} ... ]
197
197
  """
198
198
  tasks = []
199
- for _ in range(0, count):
200
- try:
201
- x = self.pending_task_queue.get(block=False)
202
- except queue.Empty:
203
- break
204
- else:
205
- tasks.append(x)
199
+ try:
200
+ for _ in range(count):
201
+ *_, task = self.pending_task_queue.pop()
202
+ tasks.append(task)
203
+ except IndexError:
204
+ pass
206
205
 
207
206
  return tasks
208
207
 
@@ -220,11 +219,11 @@ class Interchange:
220
219
  def process_command(self, monitoring_radio: Optional[MonitoringRadioSender]) -> None:
221
220
  """ Command server to run async command to the interchange
222
221
  """
223
- logger.debug("entering command_server section")
224
222
 
225
223
  reply: Any # the type of reply depends on the command_req received (aka this needs dependent types...)
226
224
 
227
225
  if self.command_channel in self.socks and self.socks[self.command_channel] == zmq.POLLIN:
226
+ logger.debug("entering command_server section")
228
227
 
229
228
  command_req = self.command_channel.recv_pyobj()
230
229
  logger.debug("Received command request: {}".format(command_req))
@@ -342,8 +341,15 @@ class Interchange:
342
341
  if self.task_incoming in self.socks and self.socks[self.task_incoming] == zmq.POLLIN:
343
342
  logger.debug("start task_incoming section")
344
343
  msg = self.task_incoming.recv_pyobj()
344
+
345
+ # Process priority, higher number = lower priority
346
+ resource_spec = msg.get('resource_spec', {})
347
+ priority = resource_spec.get('priority', float('inf'))
348
+ queue_entry = (-priority, -self.task_counter, msg)
349
+
345
350
  logger.debug("putting message onto pending_task_queue")
346
- self.pending_task_queue.put(msg)
351
+
352
+ self.pending_task_queue.add(queue_entry)
347
353
  self.task_counter += 1
348
354
  logger.debug(f"Fetched {self.task_counter} tasks so far")
349
355
 
@@ -378,23 +384,24 @@ class Interchange:
378
384
  return
379
385
 
380
386
  if msg['type'] == 'registration':
381
- # We set up an entry only if registration works correctly
382
- self._ready_managers[manager_id] = {'last_heartbeat': time.time(),
383
- 'idle_since': time.time(),
384
- 'block_id': None,
385
- 'start_time': msg['start_time'],
386
- 'max_capacity': 0,
387
- 'worker_count': 0,
388
- 'active': True,
389
- 'draining': False,
390
- 'parsl_version': msg['parsl_v'],
391
- 'python_version': msg['python_v'],
392
- 'tasks': []}
393
- self.connected_block_history.append(msg['block_id'])
394
-
395
- interesting_managers.add(manager_id)
396
- logger.info(f"Adding manager: {manager_id!r} to ready queue")
397
- m = self._ready_managers[manager_id]
387
+ ix_minor_py = self.current_platform['python_v'].rsplit(".", 1)[0]
388
+ ix_parsl_v = self.current_platform['parsl_v']
389
+ mgr_minor_py = msg['python_v'].rsplit(".", 1)[0]
390
+ mgr_parsl_v = msg['parsl_v']
391
+
392
+ m = ManagerRecord(
393
+ block_id=None,
394
+ start_time=msg['start_time'],
395
+ tasks=[],
396
+ worker_count=0,
397
+ max_capacity=0,
398
+ active=True,
399
+ draining=False,
400
+ last_heartbeat=time.time(),
401
+ idle_since=time.time(),
402
+ parsl_version=mgr_parsl_v,
403
+ python_version=msg['python_v'],
404
+ )
398
405
 
399
406
  # m is a ManagerRecord, but msg is a dict[Any,Any] and so can
400
407
  # contain arbitrary fields beyond those in ManagerRecord (and
@@ -405,23 +412,43 @@ class Interchange:
405
412
  logger.info(f"Registration info for manager {manager_id!r}: {msg}")
406
413
  self._send_monitoring_info(monitoring_radio, m)
407
414
 
408
- if (msg['python_v'].rsplit(".", 1)[0] != self.current_platform['python_v'].rsplit(".", 1)[0] or
409
- msg['parsl_v'] != self.current_platform['parsl_v']):
410
- logger.error(f"Manager {manager_id!r} has incompatible version info with the interchange")
411
- logger.debug("Setting kill event")
415
+ if (mgr_minor_py, mgr_parsl_v) != (ix_minor_py, ix_parsl_v):
412
416
  kill_event.set()
413
- e = VersionMismatch("py.v={} parsl.v={}".format(self.current_platform['python_v'].rsplit(".", 1)[0],
414
- self.current_platform['parsl_v']),
415
- "py.v={} parsl.v={}".format(msg['python_v'].rsplit(".", 1)[0],
416
- msg['parsl_v'])
417
- )
418
- result_package = {'type': 'result', 'task_id': -1, 'exception': serialize_object(e)}
417
+ e = VersionMismatch(
418
+ f"py.v={ix_minor_py} parsl.v={ix_parsl_v}",
419
+ f"py.v={mgr_minor_py} parsl.v={mgr_parsl_v}",
420
+ )
421
+ result_package = {
422
+ 'type': 'result',
423
+ 'task_id': -1,
424
+ 'exception': serialize_object(e),
425
+ }
419
426
  pkl_package = pickle.dumps(result_package)
420
427
  self.results_outgoing.send(pkl_package)
421
- logger.error("Sent failure reports, shutting down interchange")
428
+ logger.error(
429
+ "Manager has incompatible version info with the interchange;"
430
+ " sending failure reports and shutting down:"
431
+ f"\n Interchange: {e.interchange_version}"
432
+ f"\n Manager: {e.manager_version}"
433
+ )
434
+
422
435
  else:
423
- logger.info(f"Manager {manager_id!r} has compatible Parsl version {msg['parsl_v']}")
424
- logger.info(f"Manager {manager_id!r} has compatible Python version {msg['python_v'].rsplit('.', 1)[0]}")
436
+ # We really should update the associated data structure; but not
437
+ # at this time. *kicks can down the road*
438
+ assert m['block_id'] is not None, "Verified externally currently"
439
+
440
+ # set up entry only if we accept the registration
441
+ self._ready_managers[manager_id] = m
442
+ self.connected_block_history.append(m['block_id'])
443
+
444
+ interesting_managers.add(manager_id)
445
+
446
+ logger.info(
447
+ f"Registered manager {manager_id!r} (py{mgr_minor_py},"
448
+ f" {mgr_parsl_v}) and added to ready queue"
449
+ )
450
+ logger.debug("Manager %r -> %s", manager_id, m)
451
+
425
452
  elif msg['type'] == 'heartbeat':
426
453
  manager = self._ready_managers.get(manager_id)
427
454
  if manager:
@@ -461,10 +488,10 @@ class Interchange:
461
488
  len(self._ready_managers)
462
489
  )
463
490
 
464
- if interesting_managers and not self.pending_task_queue.empty():
491
+ if interesting_managers and self.pending_task_queue:
465
492
  shuffled_managers = self.manager_selector.sort_managers(self._ready_managers, interesting_managers)
466
493
 
467
- while shuffled_managers and not self.pending_task_queue.empty(): # cf. the if statement above...
494
+ while shuffled_managers and self.pending_task_queue: # cf. the if statement above...
468
495
  manager_id = shuffled_managers.pop()
469
496
  m = self._ready_managers[manager_id]
470
497
  tasks_inflight = len(m['tasks'])
@@ -491,10 +518,7 @@ class Interchange:
491
518
  self._send_monitoring_info(monitoring_radio, m)
492
519
  else:
493
520
  interesting_managers.remove(manager_id)
494
- # logger.debug("Nothing to send to manager {}".format(manager_id))
495
521
  logger.debug("leaving _ready_managers section, with %s managers still interesting", len(interesting_managers))
496
- else:
497
- logger.debug("either no interesting managers or no tasks, so skipping manager pass")
498
522
 
499
523
  def process_results_incoming(self, interesting_managers: Set[bytes], monitoring_radio: Optional[MonitoringRadioSender]) -> None:
500
524
  # Receive any results and forward to client
@@ -605,8 +629,6 @@ def start_file_logger(filename: str, level: int = logging.DEBUG, format_string:
605
629
 
606
630
  )
607
631
 
608
- global logger
609
- logger = logging.getLogger(LOGGER_NAME)
610
632
  logger.setLevel(level)
611
633
  handler = logging.FileHandler(filename)
612
634
  handler.setLevel(level)
@@ -40,16 +40,18 @@ from parsl.utils import setproctitle
40
40
 
41
41
  from .errors import WorkQueueFailure, WorkQueueTaskFailure
42
42
 
43
+ IMPORT_EXCEPTION = None
43
44
  try:
44
- import work_queue as wq
45
- from work_queue import (
45
+ from ndcctools import work_queue as wq
46
+ from ndcctools.work_queue import (
46
47
  WORK_QUEUE_ALLOCATION_MODE_MAX_THROUGHPUT,
47
48
  WORK_QUEUE_DEFAULT_PORT,
48
49
  WorkQueue,
49
50
  )
50
- except ImportError:
51
+ except ImportError as e:
51
52
  _work_queue_enabled = False
52
53
  WORK_QUEUE_DEFAULT_PORT = 0
54
+ IMPORT_EXCEPTION = e
53
55
  else:
54
56
  _work_queue_enabled = True
55
57
 
@@ -257,7 +259,7 @@ class WorkQueueExecutor(BlockProviderExecutor, putils.RepresentationMixin):
257
259
  BlockProviderExecutor.__init__(self, provider=provider,
258
260
  block_error_handler=True)
259
261
  if not _work_queue_enabled:
260
- raise OptionalModuleMissing(['work_queue'], "WorkQueueExecutor requires the work_queue module.")
262
+ raise OptionalModuleMissing(['work_queue'], f"WorkQueueExecutor requires the work_queue module. More info: {IMPORT_EXCEPTION}")
261
263
 
262
264
  self.scaling_cores_per_worker = scaling_cores_per_worker
263
265
  self.label = label
@@ -1,8 +1,5 @@
1
1
  import logging
2
2
  from abc import ABCMeta, abstractmethod
3
- from typing import Optional
4
-
5
- _db_manager_excepts: Optional[Exception]
6
3
 
7
4
  logger = logging.getLogger(__name__)
8
5
 
@@ -5,6 +5,7 @@ import time
5
5
 
6
6
  from parsl.jobs.states import JobState, JobStatus
7
7
  from parsl.launchers import SingleNodeLauncher
8
+ from parsl.providers.errors import SubmitException
8
9
  from parsl.providers.pbspro.template import template_string
9
10
  from parsl.providers.torque.torque import TorqueProvider, translate_table
10
11
 
@@ -97,6 +98,14 @@ class PBSProProvider(TorqueProvider):
97
98
 
98
99
  retcode, stdout, stderr = self.execute_wait("qstat -f -F json {0}".format(job_id_list))
99
100
 
101
+ # If qstat failed do not update job state
102
+ if retcode != 0:
103
+ logger.warning("qstat failed with retcode:%s STDOUT:%s STDERR:%s",
104
+ retcode,
105
+ stdout.strip(),
106
+ stderr.strip())
107
+ return
108
+
100
109
  job_statuses = json.loads(stdout)
101
110
 
102
111
  if 'Jobs' in job_statuses:
@@ -198,10 +207,19 @@ class PBSProProvider(TorqueProvider):
198
207
  'job_stderr_path': job_stderr_path,
199
208
  }
200
209
  else:
201
- message = "Command '{}' failed with return code {}".format(launch_cmd, retcode)
202
- if (stdout is not None) and (stderr is not None):
203
- message += "\nstderr:{}\nstdout{}".format(stderr.strip(), stdout.strip())
204
- logger.error(message)
210
+ message = f"Submit command '{launch_cmd}' failed"
211
+ logger.error(
212
+ f"{message}\n"
213
+ f" Return code: {retcode}\n"
214
+ f" STDOUT: {stdout.strip()}\n"
215
+ f" STDERR: {stderr.strip()}"
216
+ )
217
+ raise SubmitException(
218
+ job_name=job_name,
219
+ message=message,
220
+ stdout=stdout,
221
+ stderr=stderr,
222
+ )
205
223
 
206
224
  return job_id
207
225
 
@@ -2,6 +2,7 @@ import logging
2
2
  import math
3
3
  import os
4
4
  import re
5
+ import sys
5
6
  import time
6
7
  from typing import Any, Dict, Optional
7
8
 
@@ -50,6 +51,28 @@ squeue_translate_table = {
50
51
  }
51
52
 
52
53
 
54
+ if sys.version_info < (3, 12):
55
+ from itertools import islice
56
+ from typing import Iterable
57
+
58
+ def batched(
59
+ iterable: Iterable[tuple[object, Any]], n: int, *, strict: bool = False
60
+ ):
61
+ """Batched
62
+ Turns a list into a batch of size n. This code is from
63
+ https://docs.python.org/3.12/library/itertools.html#itertools.batched
64
+ and in versions 3.12+ this can be replaced with
65
+ itertools.batched
66
+ """
67
+ if n < 1:
68
+ raise ValueError("n must be at least one")
69
+ iterator = iter(iterable)
70
+ while batch := tuple(islice(iterator, n)):
71
+ yield batch
72
+ else:
73
+ from itertools import batched
74
+
75
+
53
76
  class SlurmProvider(ClusterProvider, RepresentationMixin):
54
77
  """Slurm Execution Provider
55
78
 
@@ -99,6 +122,12 @@ class SlurmProvider(ClusterProvider, RepresentationMixin):
99
122
  symbolic group for the job ID.
100
123
  worker_init : str
101
124
  Command to be run before starting a worker, such as 'module load Anaconda; source activate env'.
125
+ cmd_timeout : int (Default = 10)
126
+ Number of seconds to wait for slurm commands to finish. For schedulers with many this
127
+ may need to be increased to wait longer for scheduler information.
128
+ status_batch_size: int (Default = 50)
129
+ Number of jobs to batch together in calls to the scheduler status. For schedulers
130
+ with many jobs this may need to be decreased to get jobs in smaller batches.
102
131
  exclusive : bool (Default = True)
103
132
  Requests nodes which are not shared with other running jobs.
104
133
  launcher : Launcher
@@ -127,6 +156,7 @@ class SlurmProvider(ClusterProvider, RepresentationMixin):
127
156
  regex_job_id: str = r"Submitted batch job (?P<id>\S*)",
128
157
  worker_init: str = '',
129
158
  cmd_timeout: int = 10,
159
+ status_batch_size: int = 50,
130
160
  exclusive: bool = True,
131
161
  launcher: Launcher = SingleNodeLauncher()):
132
162
  label = 'slurm'
@@ -148,6 +178,8 @@ class SlurmProvider(ClusterProvider, RepresentationMixin):
148
178
  self.qos = qos
149
179
  self.constraint = constraint
150
180
  self.clusters = clusters
181
+ # Used to batch requests to sacct/squeue for long jobs lists
182
+ self.status_batch_size = status_batch_size
151
183
  self.scheduler_options = scheduler_options + '\n'
152
184
  if exclusive:
153
185
  self.scheduler_options += "#SBATCH --exclusive\n"
@@ -199,22 +231,23 @@ class SlurmProvider(ClusterProvider, RepresentationMixin):
199
231
  Returns:
200
232
  [status...] : Status list of all jobs
201
233
  '''
202
- job_id_list = ','.join(
203
- [jid for jid, job in self.resources.items() if not job['status'].terminal]
204
- )
205
- if not job_id_list:
206
- logger.debug('No active jobs, skipping status update')
234
+ active_jobs = {jid: job for jid, job in self.resources.items() if not job["status"].terminal}
235
+ if len(active_jobs) == 0:
236
+ logger.debug("No active jobs, skipping status update")
207
237
  return
208
238
 
209
- cmd = self._cmd.format(job_id_list)
210
- logger.debug("Executing %s", cmd)
211
- retcode, stdout, stderr = self.execute_wait(cmd)
212
- logger.debug("sacct/squeue returned %s %s", stdout, stderr)
213
-
214
- # Execute_wait failed. Do no update
215
- if retcode != 0:
216
- logger.warning("sacct/squeue failed with non-zero exit code {}".format(retcode))
217
- return
239
+ stdout = ""
240
+ for job_batch in batched(active_jobs.items(), self.status_batch_size):
241
+ job_id_list = ",".join(jid for jid, job in job_batch if not job["status"].terminal)
242
+ cmd = self._cmd.format(job_id_list)
243
+ logger.debug("Executing %s", cmd)
244
+ retcode, batch_stdout, batch_stderr = self.execute_wait(cmd)
245
+ logger.debug(f"sacct/squeue returned {retcode} {batch_stdout} {batch_stderr}")
246
+ stdout += batch_stdout
247
+ # Execute_wait failed. Do no update
248
+ if retcode != 0:
249
+ logger.warning("sacct/squeue failed with non-zero exit code {}".format(retcode))
250
+ return
218
251
 
219
252
  jobs_missing = set(self.resources.keys())
220
253
  for line in stdout.split('\n'):
@@ -167,6 +167,14 @@ def pytest_configure(config):
167
167
  'markers',
168
168
  'issue_3620: Marks tests that do not work correctly on GlobusComputeExecutor (ref: issue 3620)'
169
169
  )
170
+ config.addinivalue_line(
171
+ 'markers',
172
+ 'workqueue: Marks local tests that require a working Work Queue installation'
173
+ )
174
+ config.addinivalue_line(
175
+ 'markers',
176
+ 'taskvine: Marks local tests that require a working Task Vine installation'
177
+ )
170
178
 
171
179
 
172
180
  @pytest.fixture(autouse=True, scope='session')
@@ -400,13 +408,13 @@ def try_assert():
400
408
  check_period_ms: int = 20,
401
409
  ):
402
410
  tb = create_traceback(start=1)
403
- timeout_s = abs(timeout_ms) / 1000.0
404
411
  check_period_s = abs(check_period_ms) / 1000.0
405
412
  if attempts > 0:
406
413
  for _attempt_no in range(attempts):
414
+ time.sleep(random.random() * check_period_s) # jitter
415
+ check_period_s *= 2
407
416
  if test_func():
408
417
  return
409
- time.sleep(check_period_s)
410
418
  else:
411
419
  att_fail = (
412
420
  f"\n (Still failing after attempt limit [{attempts}], testing"
@@ -415,12 +423,15 @@ def try_assert():
415
423
  exc = AssertionError(f"{str(fail_msg)}{att_fail}".strip())
416
424
  raise exc.with_traceback(tb)
417
425
 
418
- elif timeout_s > 0:
426
+ elif timeout_ms > 0:
427
+ timeout_s = abs(timeout_ms) / 1000.0
419
428
  end = time.monotonic() + timeout_s
420
429
  while time.monotonic() < end:
430
+ wait_for = random.random() * check_period_s # jitter
431
+ time.sleep(min(wait_for, end - time.monotonic()))
432
+ check_period_s *= 2
421
433
  if test_func():
422
434
  return
423
- time.sleep(check_period_s)
424
435
  att_fail = (
425
436
  f"\n (Still failing after timeout [{timeout_ms}ms], with attempts "
426
437
  f"every {check_period_ms}ms)"
@@ -23,7 +23,7 @@ def test_resource(n=2):
23
23
  break
24
24
 
25
25
  # Specify incorrect number of resources
26
- spec = {'cores': 2, 'memory': 1000}
26
+ spec = {'cores': 1, 'memory': 1}
27
27
  fut = double(n, parsl_resource_specification=spec)
28
28
  try:
29
29
  fut.result()
@@ -35,7 +35,7 @@ def test_resource(n=2):
35
35
 
36
36
  # Specify resources with wrong types
37
37
  # 'cpus' is incorrect, should be 'cores'
38
- spec = {'cpus': 2, 'memory': 1000, 'disk': 1000}
38
+ spec = {'cpus': 1, 'memory': 1, 'disk': 1}
39
39
  fut = double(n, parsl_resource_specification=spec)
40
40
  try:
41
41
  fut.result()
@@ -0,0 +1,70 @@
1
+ import pytest
2
+
3
+ import parsl
4
+ from parsl.app.app import python_app
5
+ from parsl.config import Config
6
+ from parsl.executors import HighThroughputExecutor
7
+ from parsl.executors.high_throughput.manager_selector import RandomManagerSelector
8
+ from parsl.providers import LocalProvider
9
+ from parsl.usage_tracking.levels import LEVEL_1
10
+
11
+
12
+ @python_app
13
+ def fake_task(parsl_resource_specification=None):
14
+ import time
15
+ return time.time()
16
+
17
+
18
+ @pytest.mark.local
19
+ def test_priority_queue():
20
+ provider = LocalProvider(
21
+ init_blocks=0,
22
+ max_blocks=0,
23
+ min_blocks=0,
24
+ )
25
+
26
+ htex = HighThroughputExecutor(
27
+ label="htex_local",
28
+ max_workers_per_node=1,
29
+ manager_selector=RandomManagerSelector(),
30
+ provider=provider,
31
+ )
32
+
33
+ config = Config(
34
+ executors=[htex],
35
+ strategy="htex_auto_scale",
36
+ usage_tracking=LEVEL_1,
37
+ )
38
+
39
+ with parsl.load(config):
40
+ futures = {}
41
+
42
+ # Submit tasks with mixed priorities
43
+ # Priorities: [10, 10, 5, 5, 1, 1] to test fallback behavior
44
+ for i, priority in enumerate([10, 10, 5, 5, 1, 1]):
45
+ spec = {'priority': priority}
46
+ futures[(priority, i)] = fake_task(parsl_resource_specification=spec)
47
+
48
+ provider.max_blocks = 1
49
+
50
+ # Wait for completion
51
+ results = {
52
+ key: future.result() for key, future in futures.items()
53
+ }
54
+
55
+ # Sort by finish time
56
+ sorted_by_completion = sorted(results.items(), key=lambda item: item[1])
57
+ execution_order = [key for key, _ in sorted_by_completion]
58
+
59
+ # check priority queue functionality
60
+ priorities_only = [p for (p, i) in execution_order]
61
+ assert priorities_only == sorted(priorities_only), "Priority execution order failed"
62
+
63
+ # check FIFO fallback
64
+ from collections import defaultdict
65
+ seen = defaultdict(list)
66
+ for (priority, idx) in execution_order:
67
+ seen[priority].append(idx)
68
+
69
+ for priority, indices in seen.items():
70
+ assert indices == sorted(indices), f"FIFO fallback violated for priority {priority}"
@@ -36,3 +36,10 @@ def test_resource_spec_validation_bad_keys():
36
36
 
37
37
  with pytest.raises(InvalidResourceSpecification):
38
38
  htex.validate_resource_spec({"num_nodes": 2})
39
+
40
+
41
+ @pytest.mark.local
42
+ def test_resource_spec_validation_one_key():
43
+ htex = HighThroughputExecutor()
44
+ ret_val = htex.validate_resource_spec({"priority": 2})
45
+ assert ret_val is None
@@ -12,12 +12,15 @@ from parsl.executors.high_throughput.interchange import Interchange
12
12
  from parsl.executors.high_throughput.manager_selector import RandomManagerSelector
13
13
 
14
14
 
15
- def make_interchange(*, interchange_address: Optional[str], cert_dir: Optional[str]) -> Interchange:
15
+ def make_interchange(*,
16
+ interchange_address: Optional[str],
17
+ cert_dir: Optional[str],
18
+ worker_ports: Optional[tuple[int, int]] = None) -> Interchange:
16
19
  return Interchange(interchange_address=interchange_address,
17
20
  cert_dir=cert_dir,
18
21
  client_address="127.0.0.1",
19
22
  client_ports=(50055, 50056, 50057),
20
- worker_ports=None,
23
+ worker_ports=worker_ports,
21
24
  worker_port_range=(54000, 55000),
22
25
  hub_address=None,
23
26
  hub_zmq_port=None,
@@ -105,3 +108,10 @@ def test_limited_interface_binding(cert_dir: Optional[str]):
105
108
  assert len(matched_conns) == 1
106
109
  # laddr.ip can return ::ffff:127.0.0.1 when using IPv6
107
110
  assert address in matched_conns[0].laddr.ip
111
+
112
+
113
+ @pytest.mark.local
114
+ @pytest.mark.parametrize("encrypted", (True, False), indirect=True)
115
+ def test_fixed_ports(cert_dir: Optional[str]):
116
+ ix = make_interchange(interchange_address=None, cert_dir=cert_dir, worker_ports=(51117, 51118))
117
+ assert ix.interchange_address == "*"