parsl 2024.5.27__py3-none-any.whl → 2024.6.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. parsl/__init__.py +9 -10
  2. parsl/addresses.py +6 -4
  3. parsl/app/app.py +3 -6
  4. parsl/app/bash.py +4 -4
  5. parsl/app/errors.py +5 -3
  6. parsl/app/futures.py +3 -3
  7. parsl/app/python.py +2 -1
  8. parsl/benchmark/perf.py +2 -1
  9. parsl/channels/__init__.py +2 -2
  10. parsl/channels/base.py +0 -1
  11. parsl/channels/errors.py +2 -1
  12. parsl/channels/oauth_ssh/oauth_ssh.py +4 -3
  13. parsl/channels/ssh/ssh.py +9 -1
  14. parsl/channels/ssh_il/ssh_il.py +1 -0
  15. parsl/concurrent/__init__.py +2 -2
  16. parsl/config.py +32 -9
  17. parsl/configs/ASPIRE1.py +3 -3
  18. parsl/configs/Azure.py +6 -7
  19. parsl/configs/ad_hoc.py +4 -3
  20. parsl/configs/bridges.py +3 -3
  21. parsl/configs/cc_in2p3.py +2 -2
  22. parsl/configs/ec2.py +1 -1
  23. parsl/configs/expanse.py +1 -2
  24. parsl/configs/frontera.py +2 -3
  25. parsl/configs/htex_local.py +1 -2
  26. parsl/configs/illinoiscluster.py +1 -1
  27. parsl/configs/kubernetes.py +1 -2
  28. parsl/configs/midway.py +3 -3
  29. parsl/configs/osg.py +1 -1
  30. parsl/configs/polaris.py +1 -1
  31. parsl/configs/stampede2.py +4 -5
  32. parsl/configs/summit.py +1 -3
  33. parsl/configs/toss3_llnl.py +1 -2
  34. parsl/configs/vineex_local.py +3 -3
  35. parsl/configs/wqex_local.py +2 -2
  36. parsl/data_provider/data_manager.py +3 -3
  37. parsl/data_provider/file_noop.py +1 -2
  38. parsl/data_provider/files.py +3 -3
  39. parsl/data_provider/ftp.py +1 -3
  40. parsl/data_provider/globus.py +7 -6
  41. parsl/data_provider/http.py +2 -2
  42. parsl/data_provider/rsync.py +1 -1
  43. parsl/data_provider/staging.py +2 -2
  44. parsl/data_provider/zip.py +4 -5
  45. parsl/dataflow/dflow.py +57 -26
  46. parsl/dataflow/errors.py +2 -1
  47. parsl/dataflow/futures.py +1 -2
  48. parsl/dataflow/memoization.py +5 -5
  49. parsl/dataflow/rundirs.py +1 -1
  50. parsl/dataflow/taskrecord.py +4 -5
  51. parsl/executors/__init__.py +3 -3
  52. parsl/executors/base.py +1 -0
  53. parsl/executors/flux/execute_parsl_task.py +2 -2
  54. parsl/executors/flux/executor.py +11 -12
  55. parsl/executors/flux/flux_instance_manager.py +3 -3
  56. parsl/executors/high_throughput/executor.py +31 -36
  57. parsl/executors/high_throughput/interchange.py +37 -38
  58. parsl/executors/high_throughput/manager_record.py +1 -0
  59. parsl/executors/high_throughput/monitoring_info.py +2 -1
  60. parsl/executors/high_throughput/mpi_executor.py +5 -2
  61. parsl/executors/high_throughput/mpi_prefix_composer.py +1 -1
  62. parsl/executors/high_throughput/mpi_resource_management.py +1 -2
  63. parsl/executors/high_throughput/probe.py +6 -4
  64. parsl/executors/high_throughput/process_worker_pool.py +31 -20
  65. parsl/executors/high_throughput/zmq_pipes.py +28 -14
  66. parsl/executors/radical/executor.py +15 -15
  67. parsl/executors/radical/rpex_master.py +1 -2
  68. parsl/executors/radical/rpex_resources.py +1 -2
  69. parsl/executors/radical/rpex_worker.py +2 -1
  70. parsl/executors/status_handling.py +5 -4
  71. parsl/executors/taskvine/__init__.py +1 -1
  72. parsl/executors/taskvine/errors.py +1 -1
  73. parsl/executors/taskvine/exec_parsl_function.py +2 -2
  74. parsl/executors/taskvine/executor.py +23 -24
  75. parsl/executors/taskvine/factory.py +1 -1
  76. parsl/executors/taskvine/manager.py +11 -13
  77. parsl/executors/threads.py +4 -5
  78. parsl/executors/workqueue/errors.py +1 -1
  79. parsl/executors/workqueue/exec_parsl_function.py +5 -4
  80. parsl/executors/workqueue/executor.py +26 -27
  81. parsl/executors/workqueue/parsl_coprocess.py +1 -1
  82. parsl/jobs/error_handlers.py +1 -1
  83. parsl/jobs/job_status_poller.py +2 -5
  84. parsl/jobs/states.py +1 -1
  85. parsl/jobs/strategy.py +2 -2
  86. parsl/launchers/__init__.py +12 -3
  87. parsl/launchers/errors.py +1 -1
  88. parsl/log_utils.py +1 -2
  89. parsl/monitoring/db_manager.py +16 -10
  90. parsl/monitoring/monitoring.py +11 -15
  91. parsl/monitoring/queries/pandas.py +1 -2
  92. parsl/monitoring/radios.py +2 -4
  93. parsl/monitoring/remote.py +13 -8
  94. parsl/monitoring/router.py +8 -11
  95. parsl/monitoring/types.py +2 -0
  96. parsl/monitoring/visualization/app.py +4 -2
  97. parsl/monitoring/visualization/models.py +0 -1
  98. parsl/monitoring/visualization/plots/default/workflow_plots.py +8 -4
  99. parsl/monitoring/visualization/plots/default/workflow_resource_plots.py +1 -0
  100. parsl/monitoring/visualization/utils.py +0 -1
  101. parsl/monitoring/visualization/views.py +16 -9
  102. parsl/multiprocessing.py +0 -1
  103. parsl/process_loggers.py +1 -2
  104. parsl/providers/__init__.py +9 -12
  105. parsl/providers/ad_hoc/ad_hoc.py +1 -1
  106. parsl/providers/aws/aws.py +2 -3
  107. parsl/providers/azure/azure.py +4 -5
  108. parsl/providers/base.py +1 -1
  109. parsl/providers/cluster_provider.py +1 -1
  110. parsl/providers/cobalt/cobalt.py +3 -3
  111. parsl/providers/condor/condor.py +4 -2
  112. parsl/providers/errors.py +2 -2
  113. parsl/providers/googlecloud/googlecloud.py +2 -1
  114. parsl/providers/grid_engine/grid_engine.py +2 -2
  115. parsl/providers/kubernetes/kube.py +24 -9
  116. parsl/providers/local/local.py +5 -1
  117. parsl/providers/lsf/lsf.py +2 -2
  118. parsl/providers/pbspro/pbspro.py +1 -1
  119. parsl/providers/slurm/slurm.py +36 -27
  120. parsl/providers/torque/torque.py +1 -1
  121. parsl/serialize/__init__.py +8 -3
  122. parsl/serialize/base.py +1 -2
  123. parsl/serialize/concretes.py +5 -4
  124. parsl/serialize/proxystore.py +3 -2
  125. parsl/tests/__init__.py +1 -1
  126. parsl/tests/configs/ad_hoc_cluster_htex.py +4 -4
  127. parsl/tests/configs/azure_single_node.py +4 -5
  128. parsl/tests/configs/bridges.py +3 -2
  129. parsl/tests/configs/cc_in2p3.py +2 -2
  130. parsl/tests/configs/comet.py +2 -1
  131. parsl/tests/configs/ec2_single_node.py +1 -2
  132. parsl/tests/configs/ec2_spot.py +1 -2
  133. parsl/tests/configs/flux_local.py +11 -0
  134. parsl/tests/configs/frontera.py +3 -2
  135. parsl/tests/configs/htex_ad_hoc_cluster.py +2 -4
  136. parsl/tests/configs/htex_local.py +2 -3
  137. parsl/tests/configs/htex_local_alternate.py +8 -11
  138. parsl/tests/configs/htex_local_intask_staging.py +5 -7
  139. parsl/tests/configs/htex_local_rsync_staging.py +4 -6
  140. parsl/tests/configs/local_adhoc.py +1 -1
  141. parsl/tests/configs/local_radical.py +1 -3
  142. parsl/tests/configs/local_radical_mpi.py +2 -2
  143. parsl/tests/configs/midway.py +2 -2
  144. parsl/tests/configs/nscc_singapore.py +3 -3
  145. parsl/tests/configs/osg_htex.py +1 -1
  146. parsl/tests/configs/petrelkube.py +3 -2
  147. parsl/tests/configs/summit.py +1 -0
  148. parsl/tests/configs/swan_htex.py +2 -2
  149. parsl/tests/configs/taskvine_ex.py +3 -5
  150. parsl/tests/configs/theta.py +2 -2
  151. parsl/tests/configs/workqueue_ex.py +3 -4
  152. parsl/tests/conftest.py +8 -4
  153. parsl/tests/integration/test_channels/test_ssh_errors.py +1 -1
  154. parsl/tests/integration/test_stress/test_python_simple.py +3 -4
  155. parsl/tests/integration/test_stress/test_python_threads.py +3 -5
  156. parsl/tests/manual_tests/htex_local.py +4 -4
  157. parsl/tests/manual_tests/test_ad_hoc_htex.py +2 -1
  158. parsl/tests/manual_tests/test_basic.py +1 -0
  159. parsl/tests/manual_tests/test_fan_in_out_htex_remote.py +4 -4
  160. parsl/tests/manual_tests/test_log_filter.py +3 -1
  161. parsl/tests/manual_tests/test_memory_limits.py +6 -6
  162. parsl/tests/manual_tests/test_regression_220.py +2 -1
  163. parsl/tests/manual_tests/test_udp_simple.py +4 -3
  164. parsl/tests/manual_tests/test_worker_count.py +3 -2
  165. parsl/tests/scaling_tests/htex_local.py +2 -2
  166. parsl/tests/scaling_tests/test_scale.py +0 -9
  167. parsl/tests/scaling_tests/vineex_condor.py +1 -2
  168. parsl/tests/scaling_tests/vineex_local.py +1 -2
  169. parsl/tests/site_tests/test_provider.py +3 -1
  170. parsl/tests/site_tests/test_site.py +2 -0
  171. parsl/tests/sites/test_affinity.py +7 -5
  172. parsl/tests/sites/test_dynamic_executor.py +3 -3
  173. parsl/tests/sites/test_ec2.py +3 -2
  174. parsl/tests/sites/test_local_adhoc.py +2 -1
  175. parsl/tests/sites/test_worker_info.py +4 -3
  176. parsl/tests/test_aalst_patterns.py +0 -1
  177. parsl/tests/test_bash_apps/test_apptimeout.py +2 -2
  178. parsl/tests/test_bash_apps/test_error_codes.py +1 -4
  179. parsl/tests/test_bash_apps/test_memoize_ignore_args.py +1 -0
  180. parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +2 -2
  181. parsl/tests/test_bash_apps/test_pipeline.py +1 -1
  182. parsl/tests/test_bash_apps/test_std_uri.py +4 -3
  183. parsl/tests/test_bash_apps/test_stdout.py +20 -2
  184. parsl/tests/test_callables.py +2 -2
  185. parsl/tests/test_checkpointing/test_python_checkpoint_1.py +1 -0
  186. parsl/tests/test_checkpointing/test_python_checkpoint_2.py +2 -1
  187. parsl/tests/test_checkpointing/test_regression_239.py +1 -1
  188. parsl/tests/test_checkpointing/test_task_exit.py +1 -1
  189. parsl/tests/test_docs/test_from_slides.py +2 -2
  190. parsl/tests/test_docs/test_kwargs.py +1 -1
  191. parsl/tests/test_docs/test_tutorial_1.py +1 -2
  192. parsl/tests/test_docs/test_workflow1.py +2 -2
  193. parsl/tests/test_docs/test_workflow2.py +0 -1
  194. parsl/tests/test_error_handling/test_rand_fail.py +2 -2
  195. parsl/tests/test_error_handling/test_resource_spec.py +4 -2
  196. parsl/tests/test_error_handling/test_retries.py +2 -1
  197. parsl/tests/test_error_handling/test_retry_handler.py +1 -0
  198. parsl/tests/test_error_handling/test_retry_handler_failure.py +2 -1
  199. parsl/tests/test_error_handling/test_serialization_fail.py +1 -1
  200. parsl/tests/test_error_handling/test_wrap_with_logs.py +1 -0
  201. parsl/tests/test_flux.py +1 -1
  202. parsl/tests/test_htex/test_command_client_timeout.py +9 -12
  203. parsl/tests/test_htex/test_connected_blocks.py +3 -2
  204. parsl/tests/test_htex/test_cpu_affinity_explicit.py +5 -2
  205. parsl/tests/test_htex/test_disconnected_blocks.py +6 -4
  206. parsl/tests/test_htex/test_drain.py +5 -5
  207. parsl/tests/test_htex/test_htex.py +1 -2
  208. parsl/tests/test_htex/test_managers_command.py +3 -2
  209. parsl/tests/test_htex/test_multiple_disconnected_blocks.py +6 -4
  210. parsl/tests/test_htex/test_zmq_binding.py +22 -6
  211. parsl/tests/test_monitoring/test_app_names.py +3 -2
  212. parsl/tests/test_monitoring/test_basic.py +4 -4
  213. parsl/tests/test_monitoring/test_db_locks.py +6 -3
  214. parsl/tests/test_monitoring/test_fuzz_zmq.py +6 -3
  215. parsl/tests/test_monitoring/test_htex_init_blocks_vs_monitoring.py +5 -5
  216. parsl/tests/test_monitoring/test_incomplete_futures.py +5 -3
  217. parsl/tests/test_monitoring/test_memoization_representation.py +4 -1
  218. parsl/tests/test_monitoring/test_stdouterr.py +4 -4
  219. parsl/tests/test_monitoring/test_viz_colouring.py +1 -0
  220. parsl/tests/test_mpi_apps/test_bad_mpi_config.py +1 -1
  221. parsl/tests/test_mpi_apps/test_mpi_mode_disabled.py +2 -0
  222. parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py +7 -5
  223. parsl/tests/test_mpi_apps/test_mpi_prefix.py +4 -4
  224. parsl/tests/test_mpi_apps/test_mpi_scheduler.py +7 -2
  225. parsl/tests/test_mpi_apps/test_mpiex.py +4 -3
  226. parsl/tests/test_mpi_apps/test_resource_spec.py +9 -10
  227. parsl/tests/test_providers/test_cobalt_deprecation_warning.py +2 -0
  228. parsl/tests/test_providers/test_local_provider.py +2 -1
  229. parsl/tests/test_providers/test_pbspro_template.py +1 -1
  230. parsl/tests/test_providers/test_slurm_template.py +1 -1
  231. parsl/tests/test_providers/test_submiterror_deprecation.py +2 -1
  232. parsl/tests/test_python_apps/test_context_manager.py +99 -3
  233. parsl/tests/test_python_apps/test_dep_standard_futures.py +2 -1
  234. parsl/tests/test_python_apps/test_dependencies_deep.py +59 -0
  235. parsl/tests/test_python_apps/test_futures.py +2 -1
  236. parsl/tests/test_python_apps/test_join.py +0 -1
  237. parsl/tests/test_python_apps/test_lifted.py +3 -3
  238. parsl/tests/test_python_apps/test_memoize_bad_id_for_memo.py +1 -0
  239. parsl/tests/test_python_apps/test_pluggable_future_resolution.py +1 -1
  240. parsl/tests/test_radical/test_mpi_funcs.py +1 -2
  241. parsl/tests/test_regression/test_1480.py +2 -1
  242. parsl/tests/test_regression/test_1653.py +2 -1
  243. parsl/tests/test_regression/test_2652.py +1 -0
  244. parsl/tests/test_regression/test_69a.py +0 -1
  245. parsl/tests/test_regression/test_854.py +4 -2
  246. parsl/tests/test_regression/test_97_parallelism_0.py +1 -2
  247. parsl/tests/test_regression/test_98.py +0 -1
  248. parsl/tests/test_scaling/test_block_error_handler.py +9 -4
  249. parsl/tests/test_scaling/test_scale_down.py +2 -3
  250. parsl/tests/test_scaling/test_scale_down_htex_auto_scale.py +4 -5
  251. parsl/tests/test_scaling/test_scale_down_htex_unregistered.py +3 -4
  252. parsl/tests/test_scaling/test_shutdown_scalein.py +1 -2
  253. parsl/tests/test_serialization/test_2555_caching_deserializer.py +1 -1
  254. parsl/tests/test_serialization/test_basic.py +2 -1
  255. parsl/tests/test_serialization/test_htex_code_cache.py +3 -4
  256. parsl/tests/test_serialization/test_pack_resource_spec.py +2 -1
  257. parsl/tests/test_serialization/test_proxystore_configured.py +10 -5
  258. parsl/tests/test_serialization/test_proxystore_impl.py +5 -3
  259. parsl/tests/test_shutdown/test_kill_monitoring.py +3 -2
  260. parsl/tests/test_staging/staging_provider.py +2 -2
  261. parsl/tests/test_staging/test_1316.py +3 -2
  262. parsl/tests/test_staging/test_docs_1.py +1 -1
  263. parsl/tests/test_staging/test_docs_2.py +2 -1
  264. parsl/tests/test_staging/test_elaborate_noop_file.py +2 -2
  265. parsl/tests/test_staging/test_staging_https.py +2 -2
  266. parsl/tests/test_staging/test_staging_stdout.py +4 -3
  267. parsl/tests/test_staging/test_zip_in.py +6 -8
  268. parsl/tests/test_staging/test_zip_out.py +7 -9
  269. parsl/tests/test_staging/test_zip_to_zip.py +6 -8
  270. parsl/tests/test_summary.py +2 -1
  271. parsl/tests/test_thread_parallelism.py +0 -1
  272. parsl/tests/test_threads/test_configs.py +1 -1
  273. parsl/tests/test_threads/test_lazy_errors.py +2 -1
  274. parsl/tests/unit/test_usage_tracking.py +45 -0
  275. parsl/usage_tracking/api.py +2 -3
  276. parsl/usage_tracking/levels.py +6 -0
  277. parsl/usage_tracking/usage.py +60 -39
  278. parsl/utils.py +13 -2
  279. parsl/version.py +1 -1
  280. {parsl-2024.5.27.data → parsl-2024.6.10.data}/scripts/exec_parsl_function.py +5 -4
  281. {parsl-2024.5.27.data → parsl-2024.6.10.data}/scripts/process_worker_pool.py +31 -20
  282. {parsl-2024.5.27.dist-info → parsl-2024.6.10.dist-info}/METADATA +2 -2
  283. parsl-2024.6.10.dist-info/RECORD +475 -0
  284. parsl-2024.5.27.dist-info/RECORD +0 -471
  285. {parsl-2024.5.27.data → parsl-2024.6.10.data}/scripts/parsl_coprocess.py +1 -1
  286. {parsl-2024.5.27.dist-info → parsl-2024.6.10.dist-info}/LICENSE +0 -0
  287. {parsl-2024.5.27.dist-info → parsl-2024.6.10.dist-info}/WHEEL +0 -0
  288. {parsl-2024.5.27.dist-info → parsl-2024.6.10.dist-info}/entry_points.txt +0 -0
  289. {parsl-2024.5.27.dist-info → parsl-2024.6.10.dist-info}/top_level.txt +0 -0
@@ -6,15 +6,15 @@
6
6
  # of the globus staging provider
7
7
 
8
8
  import logging
9
+
9
10
  import pytest
10
11
 
11
12
  import parsl
12
-
13
13
  from parsl import bash_app, python_app
14
14
  from parsl.config import Config
15
15
  from parsl.data_provider.files import File
16
16
  from parsl.executors.threads import ThreadPoolExecutor
17
- from parsl.tests.test_staging.staging_provider import NoOpTestingFileStaging, NoOpError
17
+ from parsl.tests.test_staging.staging_provider import NoOpError, NoOpTestingFileStaging
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
 
@@ -1,9 +1,9 @@
1
+ import pytest
2
+
1
3
  import parsl
2
4
  from parsl.app.app import python_app
3
5
  from parsl.data_provider.files import File
4
6
 
5
- import pytest
6
-
7
7
  # This config is for the local test which will adding an executor.
8
8
  # Most tests in this file should be non-local and use the configuration
9
9
  # specificed with --config, not this one.
@@ -1,12 +1,13 @@
1
1
  import logging
2
2
  import os
3
- import parsl
4
- import pytest
5
3
  import zipfile
6
4
 
5
+ import pytest
6
+
7
+ import parsl
7
8
  from parsl.app.futures import DataFuture
8
- from parsl.tests.configs.htex_local import fresh_config as local_config
9
9
  from parsl.data_provider.files import File
10
+ from parsl.tests.configs.htex_local import fresh_config as local_config
10
11
 
11
12
 
12
13
  @parsl.bash_app
@@ -1,18 +1,16 @@
1
- import parsl
2
- import pytest
3
1
  import random
4
2
  import zipfile
5
3
 
6
- from parsl.data_provider.files import File
7
- from parsl.data_provider.zip import ZipAuthorityError, ZipFileStaging
4
+ import pytest
8
5
 
9
- from parsl.providers import LocalProvider
6
+ import parsl
10
7
  from parsl.channels import LocalChannel
11
- from parsl.launchers import SimpleLauncher
12
-
13
8
  from parsl.config import Config
9
+ from parsl.data_provider.files import File
10
+ from parsl.data_provider.zip import ZipAuthorityError, ZipFileStaging
14
11
  from parsl.executors import HighThroughputExecutor
15
-
12
+ from parsl.launchers import SimpleLauncher
13
+ from parsl.providers import LocalProvider
16
14
  from parsl.tests.configs.htex_local import fresh_config as local_config
17
15
 
18
16
 
@@ -1,18 +1,16 @@
1
- import parsl
2
- import pytest
3
1
  import zipfile
4
2
 
5
- from parsl.data_provider.files import File
6
- from parsl.data_provider.data_manager import default_staging
7
- from parsl.data_provider.zip import ZipAuthorityError, ZipFileStaging
3
+ import pytest
8
4
 
9
- from parsl.providers import LocalProvider
5
+ import parsl
10
6
  from parsl.channels import LocalChannel
11
- from parsl.launchers import SimpleLauncher
12
-
13
7
  from parsl.config import Config
8
+ from parsl.data_provider.data_manager import default_staging
9
+ from parsl.data_provider.files import File
10
+ from parsl.data_provider.zip import ZipAuthorityError, ZipFileStaging
14
11
  from parsl.executors import HighThroughputExecutor
15
-
12
+ from parsl.launchers import SimpleLauncher
13
+ from parsl.providers import LocalProvider
16
14
  from parsl.tests.configs.htex_local import fresh_config as local_config
17
15
 
18
16
 
@@ -1,18 +1,16 @@
1
- import parsl
2
- import pytest
3
1
  import random
4
2
  import zipfile
5
3
 
6
- from parsl.data_provider.files import File
7
- from parsl.data_provider.zip import ZipAuthorityError, ZipFileStaging
4
+ import pytest
8
5
 
9
- from parsl.providers import LocalProvider
6
+ import parsl
10
7
  from parsl.channels import LocalChannel
11
- from parsl.launchers import SimpleLauncher
12
-
13
8
  from parsl.config import Config
9
+ from parsl.data_provider.files import File
10
+ from parsl.data_provider.zip import ZipAuthorityError, ZipFileStaging
14
11
  from parsl.executors import HighThroughputExecutor
15
-
12
+ from parsl.launchers import SimpleLauncher
13
+ from parsl.providers import LocalProvider
16
14
  from parsl.tests.configs.htex_local import fresh_config as local_config
17
15
 
18
16
 
@@ -1,5 +1,6 @@
1
- import parsl
2
1
  import pytest
2
+
3
+ import parsl
3
4
  from parsl.tests.configs.local_threads import fresh_config
4
5
 
5
6
 
@@ -5,7 +5,6 @@ import pytest
5
5
  from parsl.app.app import bash_app, python_app
6
6
  from parsl.tests.configs.local_threads import config
7
7
 
8
-
9
8
  local_config = config
10
9
 
11
10
 
@@ -7,9 +7,9 @@ from parsl.tests.configs.local_threads import fresh_config
7
7
 
8
8
  @python_app
9
9
  def worker_identify(x, sleep_dur=0.2):
10
- import time
11
10
  import os
12
11
  import threading
12
+ import time
13
13
  time.sleep(sleep_dur)
14
14
  return {"pid": os.getpid(),
15
15
  "tid": threading.current_thread()}
@@ -1,5 +1,6 @@
1
- import parsl
2
1
  import pytest
2
+
3
+ import parsl
3
4
  from parsl import python_app
4
5
  from parsl.tests.configs.local_threads import fresh_config
5
6
 
@@ -0,0 +1,45 @@
1
+ """Test usage_tracking values."""
2
+
3
+ import pytest
4
+
5
+ import parsl
6
+ from parsl.config import Config
7
+ from parsl.errors import ConfigurationError
8
+
9
+
10
+ @pytest.mark.local
11
+ def test_config_load():
12
+ """Test loading a config with usage tracking."""
13
+ with parsl.load(Config(usage_tracking=3)):
14
+ pass
15
+ parsl.clear()
16
+
17
+
18
+ @pytest.mark.local
19
+ @pytest.mark.parametrize("level", (0, 1, 2, 3, False, True))
20
+ def test_valid(level):
21
+ """Test valid usage_tracking values."""
22
+ Config(usage_tracking=level)
23
+ assert Config(usage_tracking=level).usage_tracking == level
24
+
25
+
26
+ @pytest.mark.local
27
+ @pytest.mark.parametrize("level", (12, 1000, -1))
28
+ def test_invalid_values(level):
29
+ """Test invalid usage_tracking values."""
30
+ with pytest.raises(ConfigurationError):
31
+ Config(usage_tracking=level)
32
+
33
+
34
+ @pytest.mark.local
35
+ @pytest.mark.parametrize("level", ("abcd", None, bytes(1), 1.0, 1j, object()))
36
+ def test_invalid_types(level):
37
+ """Test invalid usage_tracking types."""
38
+ with pytest.raises(Exception) as ex:
39
+ Config(usage_tracking=level)
40
+
41
+ # with typeguard 4.x this is TypeCheckError,
42
+ # with typeguard 2.x this is TypeError
43
+ # we can't instantiate TypeCheckError if we're in typeguard 2.x environment
44
+ # because it does not exist... so check name using strings.
45
+ assert ex.type.__name__ in ["TypeCheckError", "TypeError"]
@@ -1,11 +1,9 @@
1
1
  import inspect
2
-
3
- from parsl.utils import RepresentationMixin
4
-
5
2
  from abc import abstractmethod
6
3
  from functools import singledispatch
7
4
  from typing import Any, List, Sequence
8
5
 
6
+ from parsl.utils import RepresentationMixin
9
7
 
10
8
  # Traverse the configuration hierarchy, returning a JSON component
11
9
  # for each one. Configuration components which implement
@@ -14,6 +12,7 @@ from typing import Any, List, Sequence
14
12
  # are traversed in sequence. Other types default to reporting no
15
13
  # usage information.
16
14
 
15
+
17
16
  @singledispatch
18
17
  def get_parsl_usage(obj) -> List[Any]:
19
18
  return []
@@ -0,0 +1,6 @@
1
+ """Module for defining the usage tracking levels."""
2
+
3
+ DISABLED = 0 # Tracking is disabled
4
+ LEVEL_1 = 1 # Share info about Parsl version, Python version, platform
5
+ LEVEL_2 = 2 # Share info about config + level 1
6
+ LEVEL_3 = 3 # Share info about app count, app fails, execution time + level 2
@@ -1,21 +1,24 @@
1
- import uuid
2
- import time
3
- import os
4
1
  import json
5
2
  import logging
3
+ import platform
6
4
  import socket
7
5
  import sys
8
- import platform
6
+ import time
7
+ import uuid
9
8
 
9
+ from parsl.dataflow.states import States
10
+ from parsl.errors import ConfigurationError
11
+ from parsl.multiprocessing import ForkProcess
10
12
  from parsl.usage_tracking.api import get_parsl_usage
13
+ from parsl.usage_tracking.levels import DISABLED as USAGE_TRACKING_DISABLED
14
+ from parsl.usage_tracking.levels import LEVEL_3 as USAGE_TRACKING_LEVEL_3
11
15
  from parsl.utils import setproctitle
12
- from parsl.multiprocessing import ForkProcess
13
- from parsl.dataflow.states import States
14
16
  from parsl.version import VERSION as PARSL_VERSION
15
17
 
16
18
  logger = logging.getLogger(__name__)
17
19
 
18
20
  from typing import Callable
21
+
19
22
  from typing_extensions import ParamSpec
20
23
 
21
24
  # protocol version byte: when (for example) compression parameters are changed
@@ -110,28 +113,33 @@ class UsageTracker:
110
113
  self.python_version = "{}.{}.{}".format(sys.version_info.major,
111
114
  sys.version_info.minor,
112
115
  sys.version_info.micro)
113
- self.tracking_enabled = self.check_tracking_enabled()
114
- logger.debug("Tracking status: {}".format(self.tracking_enabled))
115
-
116
- def check_tracking_enabled(self):
117
- """Check if tracking is enabled.
118
-
119
- Tracking will be enabled unless either of these is true:
120
-
121
- 1. dfk.config.usage_tracking is set to False
122
- 2. Environment variable PARSL_TRACKING is set to false (case insensitive)
123
-
116
+ self.tracking_level = self.check_tracking_level()
117
+ self.start_time = None
118
+ logger.debug("Tracking level: {}".format(self.tracking_level))
119
+
120
+ def check_tracking_level(self) -> int:
121
+ """Check if tracking is enabled and return level.
122
+
123
+ Checks usage_tracking in Config
124
+ - Possible values: [True, False, 0, 1, 2, 3]
125
+
126
+ True/False values are treated as Level 1/Level 0 respectively.
127
+
128
+ Returns: int
129
+ - 0 : Tracking is disabled
130
+ - 1 : Tracking is enabled with level 1
131
+ Share info about Parsl version, Python version, platform
132
+ - 2 : Tracking is enabled with level 2
133
+ Share info about config + level 1
134
+ - 3 : Tracking is enabled with level 3
135
+ Share info about app count, app fails, execution time + level 2
124
136
  """
125
- track = True
126
-
127
- if not self.config.usage_tracking:
128
- track = False
137
+ if not USAGE_TRACKING_DISABLED <= self.config.usage_tracking <= USAGE_TRACKING_LEVEL_3:
138
+ raise ConfigurationError(
139
+ f"Usage Tracking values must be 0, 1, 2, or 3 and not {self.config.usage_tracking}"
140
+ )
129
141
 
130
- envvar = str(os.environ.get("PARSL_TRACKING", True)).lower()
131
- if envvar == "false":
132
- track = False
133
-
134
- return track
142
+ return self.config.usage_tracking
135
143
 
136
144
  def construct_start_message(self) -> bytes:
137
145
  """Collect preliminary run info at the start of the DFK.
@@ -143,18 +151,28 @@ class UsageTracker:
143
151
  'parsl_v': self.parsl_version,
144
152
  'python_v': self.python_version,
145
153
  'platform.system': platform.system(),
146
- 'start': int(time.time()),
147
- 'components': get_parsl_usage(self.dfk._config)}
154
+ 'tracking_level': int(self.tracking_level)}
155
+
156
+ if self.tracking_level >= 2:
157
+ message['components'] = get_parsl_usage(self.dfk._config)
158
+
159
+ if self.tracking_level == 3:
160
+ self.start_time = int(time.time())
161
+ message['start'] = self.start_time
162
+
148
163
  logger.debug(f"Usage tracking start message: {message}")
149
164
 
150
165
  return self.encode_message(message)
151
166
 
152
167
  def construct_end_message(self) -> bytes:
153
168
  """Collect the final run information at the time of DFK cleanup.
169
+ This is only called if tracking level is 3.
154
170
 
155
171
  Returns:
156
172
  - Message dict dumped as json string, ready for UDP
157
173
  """
174
+ end_time = int(time.time())
175
+
158
176
  app_count = self.dfk.task_count
159
177
 
160
178
  app_fails = self.dfk.task_state_counts[States.failed] + self.dfk.task_state_counts[States.dep_fail]
@@ -167,7 +185,8 @@ class UsageTracker:
167
185
  'app_fails': app_fails}
168
186
 
169
187
  message = {'correlator': self.correlator_uuid,
170
- 'end': int(time.time()),
188
+ 'end': end_time,
189
+ 'execution_time': end_time - self.start_time,
171
190
  'components': [dfk_component] + get_parsl_usage(self.dfk._config)}
172
191
  logger.debug(f"Usage tracking end message (unencoded): {message}")
173
192
 
@@ -178,20 +197,22 @@ class UsageTracker:
178
197
 
179
198
  def send_UDP_message(self, message: bytes) -> None:
180
199
  """Send UDP message."""
181
- if self.tracking_enabled:
182
- try:
183
- proc = udp_messenger(self.domain_name, self.UDP_PORT, self.sock_timeout, message)
184
- self.procs.append(proc)
185
- except Exception as e:
186
- logger.debug("Usage tracking failed: {}".format(e))
200
+ try:
201
+ proc = udp_messenger(self.domain_name, self.UDP_PORT, self.sock_timeout, message)
202
+ self.procs.append(proc)
203
+ except Exception as e:
204
+ logger.debug("Usage tracking failed: {}".format(e))
187
205
 
188
206
  def send_start_message(self) -> None:
189
- message = self.construct_start_message()
190
- self.send_UDP_message(message)
207
+ if self.tracking_level:
208
+ self.start_time = time.time()
209
+ message = self.construct_start_message()
210
+ self.send_UDP_message(message)
191
211
 
192
212
  def send_end_message(self) -> None:
193
- message = self.construct_end_message()
194
- self.send_UDP_message(message)
213
+ if self.tracking_level == 3:
214
+ message = self.construct_end_message()
215
+ self.send_UDP_message(message)
195
216
 
196
217
  def close(self, timeout: float = 10.0) -> None:
197
218
  """First give each process one timeout period to finish what it is
parsl/utils.py CHANGED
@@ -7,7 +7,19 @@ import threading
7
7
  import time
8
8
  from contextlib import contextmanager
9
9
  from types import TracebackType
10
- from typing import Any, Callable, List, Sequence, Tuple, Union, Generator, IO, AnyStr, Dict, Optional
10
+ from typing import (
11
+ IO,
12
+ Any,
13
+ AnyStr,
14
+ Callable,
15
+ Dict,
16
+ Generator,
17
+ List,
18
+ Optional,
19
+ Sequence,
20
+ Tuple,
21
+ Union,
22
+ )
11
23
 
12
24
  import typeguard
13
25
  from typing_extensions import Type
@@ -16,7 +28,6 @@ import parsl
16
28
  from parsl.app.errors import BadStdStreamFile
17
29
  from parsl.version import VERSION
18
30
 
19
-
20
31
  try:
21
32
  import setproctitle as setproctitle_module
22
33
  except ImportError:
parsl/version.py CHANGED
@@ -3,4 +3,4 @@
3
3
  Year.Month.Day[alpha/beta/..]
4
4
  Alphas will be numbered like this -> 2024.12.10a0
5
5
  """
6
- VERSION = '2024.05.27'
6
+ VERSION = '2024.06.10'
@@ -1,10 +1,11 @@
1
+ import pickle
2
+ import sys
3
+ import traceback
4
+
1
5
  from parsl.app.errors import RemoteExceptionWrapper
2
6
  from parsl.data_provider.files import File
3
- from parsl.utils import get_std_fname_mode
4
- import traceback
5
- import sys
6
- import pickle
7
7
  from parsl.serialize import serialize
8
+ from parsl.utils import get_std_fname_mode
8
9
 
9
10
  # This scripts executes a parsl function which is pickled in a file:
10
11
  #
@@ -1,39 +1,41 @@
1
1
  #!python
2
2
 
3
3
  import argparse
4
+ import json
4
5
  import logging
6
+ import math
7
+ import multiprocessing
5
8
  import os
6
- import sys
9
+ import pickle
7
10
  import platform
11
+ import queue
12
+ import sys
8
13
  import threading
9
- import pickle
10
14
  import time
11
- import queue
12
15
  import uuid
13
- from typing import Sequence, Optional, Dict, List
14
-
15
- import zmq
16
- import math
17
- import json
18
- import psutil
19
- import multiprocessing
20
16
  from multiprocessing.managers import DictProxy
21
17
  from multiprocessing.sharedctypes import Synchronized
18
+ from typing import Dict, List, Optional, Sequence
19
+
20
+ import psutil
21
+ import zmq
22
22
 
23
23
  from parsl import curvezmq
24
- from parsl.process_loggers import wrap_with_logs
25
- from parsl.version import VERSION as PARSL_VERSION
26
24
  from parsl.app.errors import RemoteExceptionWrapper
27
25
  from parsl.executors.high_throughput.errors import WorkerLost
28
- from parsl.executors.high_throughput.probe import probe_addresses
29
- from parsl.multiprocessing import SpawnContext
30
- from parsl.serialize import unpack_res_spec_apply_message, serialize
26
+ from parsl.executors.high_throughput.mpi_prefix_composer import (
27
+ VALID_LAUNCHERS,
28
+ compose_all,
29
+ )
31
30
  from parsl.executors.high_throughput.mpi_resource_management import (
31
+ MPITaskScheduler,
32
32
  TaskScheduler,
33
- MPITaskScheduler
34
33
  )
35
-
36
- from parsl.executors.high_throughput.mpi_prefix_composer import compose_all, VALID_LAUNCHERS
34
+ from parsl.executors.high_throughput.probe import probe_addresses
35
+ from parsl.multiprocessing import SpawnContext
36
+ from parsl.process_loggers import wrap_with_logs
37
+ from parsl.serialize import serialize, unpack_res_spec_apply_message
38
+ from parsl.version import VERSION as PARSL_VERSION
37
39
 
38
40
  HEARTBEAT_CODE = (2 ** 32) - 1
39
41
  DRAINED_CODE = (2 ** 32) - 2
@@ -677,7 +679,8 @@ def worker(
677
679
  # If desired, set process affinity
678
680
  if cpu_affinity != "none":
679
681
  # Count the number of cores per worker
680
- avail_cores = sorted(os.sched_getaffinity(0)) # Get the available threads
682
+ # OSX does not implement os.sched_getaffinity
683
+ avail_cores = sorted(os.sched_getaffinity(0)) # type: ignore[attr-defined, unused-ignore]
681
684
  cores_per_worker = len(avail_cores) // pool_size
682
685
  assert cores_per_worker > 0, "Affinity does not work if there are more workers than cores"
683
686
 
@@ -717,7 +720,15 @@ def worker(
717
720
  os.environ["KMP_AFFINITY"] = f"explicit,proclist=[{proc_list}]" # For Intel OpenMP
718
721
 
719
722
  # Set the affinity for this worker
720
- os.sched_setaffinity(0, my_cores)
723
+ # OSX does not implement os.sched_setaffinity so type checking
724
+ # is ignored here in two ways:
725
+ # On a platform without sched_setaffinity, that attribute will not
726
+ # be defined, so ignore[attr-defined] will tell mypy to ignore this
727
+ # incorrect-for-OS X attribute access.
728
+ # On a platform with sched_setaffinity, that type: ignore message
729
+ # will be redundant, and ignore[unused-ignore] tells mypy to ignore
730
+ # that this ignore is unneeded.
731
+ os.sched_setaffinity(0, my_cores) # type: ignore[attr-defined, unused-ignore]
721
732
  logger.info("Set worker CPU affinity to {}".format(my_cores))
722
733
 
723
734
  # If desired, pin to accelerator
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: parsl
3
- Version: 2024.5.27
3
+ Version: 2024.6.10
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.05.27.tar.gz
6
+ Download-URL: https://github.com/Parsl/parsl/archive/2024.06.10.tar.gz
7
7
  Author: The Parsl Team
8
8
  Author-email: parsl@googlegroups.com
9
9
  License: Apache 2.0