parsl 2024.3.11__py3-none-any.whl → 2025.1.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. parsl/__init__.py +9 -10
  2. parsl/addresses.py +29 -7
  3. parsl/app/app.py +7 -8
  4. parsl/app/bash.py +15 -8
  5. parsl/app/errors.py +10 -13
  6. parsl/app/futures.py +8 -10
  7. parsl/app/python.py +2 -1
  8. parsl/benchmark/perf.py +2 -1
  9. parsl/concurrent/__init__.py +2 -2
  10. parsl/config.py +57 -10
  11. parsl/configs/ASPIRE1.py +6 -5
  12. parsl/configs/Azure.py +9 -8
  13. parsl/configs/bridges.py +6 -4
  14. parsl/configs/cc_in2p3.py +3 -3
  15. parsl/configs/ec2.py +3 -1
  16. parsl/configs/expanse.py +4 -3
  17. parsl/configs/frontera.py +3 -4
  18. parsl/configs/htex_local.py +3 -4
  19. parsl/configs/illinoiscluster.py +3 -1
  20. parsl/configs/improv.py +34 -0
  21. parsl/configs/kubernetes.py +4 -3
  22. parsl/configs/local_threads.py +5 -1
  23. parsl/configs/midway.py +5 -3
  24. parsl/configs/osg.py +4 -2
  25. parsl/configs/polaris.py +4 -2
  26. parsl/configs/stampede2.py +6 -5
  27. parsl/configs/summit.py +3 -3
  28. parsl/configs/toss3_llnl.py +4 -3
  29. parsl/configs/vineex_local.py +6 -4
  30. parsl/configs/wqex_local.py +5 -3
  31. parsl/curvezmq.py +4 -0
  32. parsl/data_provider/data_manager.py +4 -3
  33. parsl/data_provider/file_noop.py +1 -2
  34. parsl/data_provider/files.py +3 -3
  35. parsl/data_provider/ftp.py +1 -3
  36. parsl/data_provider/globus.py +7 -6
  37. parsl/data_provider/http.py +2 -2
  38. parsl/data_provider/rsync.py +1 -1
  39. parsl/data_provider/staging.py +2 -2
  40. parsl/data_provider/zip.py +135 -0
  41. parsl/dataflow/dependency_resolvers.py +115 -0
  42. parsl/dataflow/dflow.py +262 -224
  43. parsl/dataflow/errors.py +3 -5
  44. parsl/dataflow/futures.py +27 -14
  45. parsl/dataflow/memoization.py +5 -5
  46. parsl/dataflow/rundirs.py +5 -6
  47. parsl/dataflow/taskrecord.py +4 -5
  48. parsl/executors/__init__.py +4 -2
  49. parsl/executors/base.py +45 -15
  50. parsl/executors/errors.py +13 -0
  51. parsl/executors/execute_task.py +37 -0
  52. parsl/executors/flux/execute_parsl_task.py +3 -3
  53. parsl/executors/flux/executor.py +18 -19
  54. parsl/executors/flux/flux_instance_manager.py +26 -27
  55. parsl/executors/high_throughput/errors.py +43 -3
  56. parsl/executors/high_throughput/executor.py +316 -282
  57. parsl/executors/high_throughput/interchange.py +158 -167
  58. parsl/executors/high_throughput/manager_record.py +5 -0
  59. parsl/executors/high_throughput/manager_selector.py +55 -0
  60. parsl/executors/high_throughput/monitoring_info.py +2 -1
  61. parsl/executors/high_throughput/mpi_executor.py +113 -0
  62. parsl/executors/high_throughput/mpi_prefix_composer.py +10 -11
  63. parsl/executors/high_throughput/mpi_resource_management.py +6 -17
  64. parsl/executors/high_throughput/probe.py +9 -7
  65. parsl/executors/high_throughput/process_worker_pool.py +115 -77
  66. parsl/executors/high_throughput/zmq_pipes.py +81 -23
  67. parsl/executors/radical/executor.py +130 -79
  68. parsl/executors/radical/rpex_resources.py +17 -15
  69. parsl/executors/radical/rpex_worker.py +4 -3
  70. parsl/executors/status_handling.py +157 -51
  71. parsl/executors/taskvine/__init__.py +1 -1
  72. parsl/executors/taskvine/errors.py +1 -1
  73. parsl/executors/taskvine/exec_parsl_function.py +2 -2
  74. parsl/executors/taskvine/executor.py +41 -57
  75. parsl/executors/taskvine/factory.py +1 -1
  76. parsl/executors/taskvine/factory_config.py +1 -1
  77. parsl/executors/taskvine/manager.py +18 -13
  78. parsl/executors/taskvine/manager_config.py +9 -5
  79. parsl/executors/threads.py +6 -6
  80. parsl/executors/workqueue/errors.py +1 -1
  81. parsl/executors/workqueue/exec_parsl_function.py +6 -5
  82. parsl/executors/workqueue/executor.py +64 -63
  83. parsl/executors/workqueue/parsl_coprocess.py +1 -1
  84. parsl/jobs/error_handlers.py +2 -2
  85. parsl/jobs/job_status_poller.py +30 -113
  86. parsl/jobs/states.py +7 -2
  87. parsl/jobs/strategy.py +43 -31
  88. parsl/launchers/__init__.py +12 -3
  89. parsl/launchers/errors.py +1 -1
  90. parsl/launchers/launchers.py +6 -12
  91. parsl/log_utils.py +9 -6
  92. parsl/monitoring/db_manager.py +59 -95
  93. parsl/monitoring/errors.py +6 -0
  94. parsl/monitoring/monitoring.py +87 -356
  95. parsl/monitoring/queries/pandas.py +1 -2
  96. parsl/monitoring/radios/base.py +13 -0
  97. parsl/monitoring/radios/filesystem.py +52 -0
  98. parsl/monitoring/radios/htex.py +57 -0
  99. parsl/monitoring/radios/multiprocessing.py +17 -0
  100. parsl/monitoring/radios/udp.py +56 -0
  101. parsl/monitoring/radios/zmq.py +17 -0
  102. parsl/monitoring/remote.py +33 -37
  103. parsl/monitoring/router.py +212 -0
  104. parsl/monitoring/types.py +5 -6
  105. parsl/monitoring/visualization/app.py +4 -2
  106. parsl/monitoring/visualization/models.py +0 -1
  107. parsl/monitoring/visualization/plots/default/workflow_plots.py +11 -4
  108. parsl/monitoring/visualization/plots/default/workflow_resource_plots.py +1 -0
  109. parsl/monitoring/visualization/utils.py +0 -1
  110. parsl/monitoring/visualization/views.py +16 -8
  111. parsl/multiprocessing.py +0 -1
  112. parsl/process_loggers.py +1 -2
  113. parsl/providers/__init__.py +8 -17
  114. parsl/providers/aws/aws.py +2 -3
  115. parsl/providers/azure/azure.py +4 -5
  116. parsl/providers/base.py +2 -18
  117. parsl/providers/cluster_provider.py +4 -12
  118. parsl/providers/condor/condor.py +7 -17
  119. parsl/providers/errors.py +2 -2
  120. parsl/providers/googlecloud/googlecloud.py +2 -1
  121. parsl/providers/grid_engine/grid_engine.py +5 -14
  122. parsl/providers/kubernetes/kube.py +80 -40
  123. parsl/providers/local/local.py +13 -26
  124. parsl/providers/lsf/lsf.py +5 -23
  125. parsl/providers/pbspro/pbspro.py +5 -17
  126. parsl/providers/slurm/slurm.py +81 -39
  127. parsl/providers/torque/torque.py +3 -14
  128. parsl/serialize/__init__.py +8 -3
  129. parsl/serialize/base.py +1 -2
  130. parsl/serialize/concretes.py +5 -4
  131. parsl/serialize/facade.py +3 -3
  132. parsl/serialize/proxystore.py +3 -2
  133. parsl/tests/__init__.py +1 -1
  134. parsl/tests/configs/azure_single_node.py +4 -5
  135. parsl/tests/configs/bridges.py +3 -2
  136. parsl/tests/configs/cc_in2p3.py +1 -3
  137. parsl/tests/configs/comet.py +2 -1
  138. parsl/tests/configs/ec2_single_node.py +1 -2
  139. parsl/tests/configs/ec2_spot.py +1 -2
  140. parsl/tests/configs/flux_local.py +11 -0
  141. parsl/tests/configs/frontera.py +2 -3
  142. parsl/tests/configs/htex_local.py +3 -5
  143. parsl/tests/configs/htex_local_alternate.py +11 -15
  144. parsl/tests/configs/htex_local_intask_staging.py +5 -9
  145. parsl/tests/configs/htex_local_rsync_staging.py +4 -8
  146. parsl/tests/configs/local_radical.py +1 -3
  147. parsl/tests/configs/local_radical_mpi.py +2 -2
  148. parsl/tests/configs/local_threads_checkpoint_periodic.py +8 -10
  149. parsl/tests/configs/local_threads_monitoring.py +0 -1
  150. parsl/tests/configs/midway.py +2 -2
  151. parsl/tests/configs/nscc_singapore.py +3 -3
  152. parsl/tests/configs/osg_htex.py +1 -1
  153. parsl/tests/configs/petrelkube.py +3 -2
  154. parsl/tests/configs/slurm_local.py +24 -0
  155. parsl/tests/configs/summit.py +1 -0
  156. parsl/tests/configs/taskvine_ex.py +4 -7
  157. parsl/tests/configs/user_opts.py +2 -8
  158. parsl/tests/configs/workqueue_ex.py +4 -6
  159. parsl/tests/conftest.py +27 -13
  160. parsl/tests/integration/test_stress/test_python_simple.py +3 -4
  161. parsl/tests/integration/test_stress/test_python_threads.py +3 -5
  162. parsl/tests/manual_tests/htex_local.py +4 -6
  163. parsl/tests/manual_tests/test_basic.py +1 -0
  164. parsl/tests/manual_tests/test_log_filter.py +3 -1
  165. parsl/tests/manual_tests/test_memory_limits.py +6 -8
  166. parsl/tests/manual_tests/test_regression_220.py +2 -1
  167. parsl/tests/manual_tests/test_udp_simple.py +4 -4
  168. parsl/tests/manual_tests/test_worker_count.py +3 -2
  169. parsl/tests/scaling_tests/htex_local.py +2 -4
  170. parsl/tests/scaling_tests/test_scale.py +0 -9
  171. parsl/tests/scaling_tests/vineex_condor.py +1 -2
  172. parsl/tests/scaling_tests/vineex_local.py +1 -2
  173. parsl/tests/site_tests/site_config_selector.py +1 -6
  174. parsl/tests/site_tests/test_provider.py +4 -2
  175. parsl/tests/site_tests/test_site.py +2 -0
  176. parsl/tests/sites/test_affinity.py +7 -7
  177. parsl/tests/sites/test_dynamic_executor.py +3 -4
  178. parsl/tests/sites/test_ec2.py +3 -2
  179. parsl/tests/sites/test_worker_info.py +4 -5
  180. parsl/tests/test_aalst_patterns.py +0 -1
  181. parsl/tests/test_bash_apps/test_apptimeout.py +2 -2
  182. parsl/tests/test_bash_apps/test_basic.py +10 -4
  183. parsl/tests/test_bash_apps/test_error_codes.py +5 -7
  184. parsl/tests/test_bash_apps/test_inputs_default.py +25 -0
  185. parsl/tests/test_bash_apps/test_kwarg_storage.py +1 -1
  186. parsl/tests/test_bash_apps/test_memoize.py +2 -8
  187. parsl/tests/test_bash_apps/test_memoize_ignore_args.py +9 -14
  188. parsl/tests/test_bash_apps/test_memoize_ignore_args_regr.py +9 -14
  189. parsl/tests/test_bash_apps/test_multiline.py +1 -1
  190. parsl/tests/test_bash_apps/test_pipeline.py +1 -1
  191. parsl/tests/test_bash_apps/test_std_uri.py +123 -0
  192. parsl/tests/test_bash_apps/test_stdout.py +33 -8
  193. parsl/tests/test_callables.py +2 -2
  194. parsl/tests/test_checkpointing/test_periodic.py +21 -39
  195. parsl/tests/test_checkpointing/test_python_checkpoint_1.py +1 -0
  196. parsl/tests/test_checkpointing/test_python_checkpoint_2.py +2 -2
  197. parsl/tests/test_checkpointing/test_python_checkpoint_3.py +0 -1
  198. parsl/tests/test_checkpointing/test_regression_239.py +1 -1
  199. parsl/tests/test_checkpointing/test_task_exit.py +2 -3
  200. parsl/tests/test_docs/test_from_slides.py +5 -2
  201. parsl/tests/test_docs/test_kwargs.py +4 -1
  202. parsl/tests/test_docs/test_tutorial_1.py +1 -2
  203. parsl/tests/test_docs/test_workflow1.py +2 -2
  204. parsl/tests/test_docs/test_workflow2.py +0 -1
  205. parsl/tests/test_error_handling/test_rand_fail.py +2 -2
  206. parsl/tests/test_error_handling/test_resource_spec.py +10 -12
  207. parsl/tests/test_error_handling/test_retries.py +6 -16
  208. parsl/tests/test_error_handling/test_retry_handler.py +1 -0
  209. parsl/tests/test_error_handling/test_retry_handler_failure.py +2 -1
  210. parsl/tests/test_error_handling/test_serialization_fail.py +1 -1
  211. parsl/tests/test_error_handling/test_wrap_with_logs.py +1 -0
  212. parsl/tests/test_execute_task.py +29 -0
  213. parsl/tests/test_flux.py +1 -1
  214. parsl/tests/test_htex/test_basic.py +2 -3
  215. parsl/tests/test_htex/test_block_manager_selector_unit.py +20 -0
  216. parsl/tests/test_htex/test_command_client_timeout.py +66 -0
  217. parsl/tests/test_htex/test_connected_blocks.py +3 -2
  218. parsl/tests/test_htex/test_cpu_affinity_explicit.py +6 -10
  219. parsl/tests/test_htex/test_disconnected_blocks.py +6 -5
  220. parsl/tests/test_htex/test_disconnected_blocks_failing_provider.py +71 -0
  221. parsl/tests/test_htex/test_drain.py +79 -0
  222. parsl/tests/test_htex/test_htex.py +51 -25
  223. parsl/tests/test_htex/test_manager_failure.py +0 -1
  224. parsl/tests/test_htex/test_manager_selector_by_block.py +51 -0
  225. parsl/tests/test_htex/test_managers_command.py +36 -0
  226. parsl/tests/test_htex/test_missing_worker.py +2 -12
  227. parsl/tests/test_htex/test_multiple_disconnected_blocks.py +9 -9
  228. parsl/tests/test_htex/test_resource_spec_validation.py +45 -0
  229. parsl/tests/test_htex/test_zmq_binding.py +29 -8
  230. parsl/tests/test_monitoring/test_app_names.py +86 -0
  231. parsl/tests/test_monitoring/test_basic.py +73 -25
  232. parsl/tests/test_monitoring/test_db_locks.py +6 -4
  233. parsl/tests/test_monitoring/test_fuzz_zmq.py +19 -8
  234. parsl/tests/test_monitoring/test_htex_init_blocks_vs_monitoring.py +80 -0
  235. parsl/tests/test_monitoring/test_incomplete_futures.py +5 -4
  236. parsl/tests/test_monitoring/test_memoization_representation.py +4 -2
  237. parsl/tests/test_monitoring/test_stdouterr.py +134 -0
  238. parsl/tests/test_monitoring/test_viz_colouring.py +1 -0
  239. parsl/tests/test_mpi_apps/test_bad_mpi_config.py +33 -26
  240. parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py +28 -11
  241. parsl/tests/test_mpi_apps/test_mpi_prefix.py +4 -4
  242. parsl/tests/test_mpi_apps/test_mpi_scheduler.py +7 -2
  243. parsl/tests/test_mpi_apps/test_mpiex.py +64 -0
  244. parsl/tests/test_mpi_apps/test_resource_spec.py +42 -49
  245. parsl/tests/test_providers/test_kubernetes_provider.py +102 -0
  246. parsl/tests/test_providers/test_local_provider.py +3 -132
  247. parsl/tests/test_providers/test_pbspro_template.py +2 -3
  248. parsl/tests/test_providers/test_slurm_template.py +2 -3
  249. parsl/tests/test_providers/test_submiterror_deprecation.py +2 -1
  250. parsl/tests/test_python_apps/test_context_manager.py +128 -0
  251. parsl/tests/test_python_apps/test_dep_standard_futures.py +2 -1
  252. parsl/tests/test_python_apps/test_dependencies_deep.py +59 -0
  253. parsl/tests/test_python_apps/test_fail.py +0 -25
  254. parsl/tests/test_python_apps/test_futures.py +2 -1
  255. parsl/tests/test_python_apps/test_inputs_default.py +22 -0
  256. parsl/tests/test_python_apps/test_join.py +0 -1
  257. parsl/tests/test_python_apps/test_lifted.py +11 -7
  258. parsl/tests/test_python_apps/test_memoize_bad_id_for_memo.py +1 -0
  259. parsl/tests/test_python_apps/test_outputs.py +1 -1
  260. parsl/tests/test_python_apps/test_pluggable_future_resolution.py +161 -0
  261. parsl/tests/test_radical/test_mpi_funcs.py +1 -2
  262. parsl/tests/test_regression/test_1480.py +2 -1
  263. parsl/tests/test_regression/test_1653.py +2 -1
  264. parsl/tests/test_regression/test_226.py +1 -0
  265. parsl/tests/test_regression/test_2652.py +1 -0
  266. parsl/tests/test_regression/test_69a.py +0 -1
  267. parsl/tests/test_regression/test_854.py +4 -2
  268. parsl/tests/test_regression/test_97_parallelism_0.py +1 -2
  269. parsl/tests/test_regression/test_98.py +0 -1
  270. parsl/tests/test_scaling/test_block_error_handler.py +9 -4
  271. parsl/tests/test_scaling/test_regression_1621.py +11 -15
  272. parsl/tests/test_scaling/test_regression_3568_scaledown_vs_MISSING.py +84 -0
  273. parsl/tests/test_scaling/test_regression_3696_oscillation.py +103 -0
  274. parsl/tests/test_scaling/test_scale_down.py +2 -5
  275. parsl/tests/test_scaling/test_scale_down_htex_auto_scale.py +6 -18
  276. parsl/tests/test_scaling/test_scale_down_htex_unregistered.py +71 -0
  277. parsl/tests/test_scaling/test_shutdown_scalein.py +73 -0
  278. parsl/tests/test_scaling/test_worker_interchange_bad_messages_3262.py +90 -0
  279. parsl/tests/test_serialization/test_2555_caching_deserializer.py +1 -1
  280. parsl/tests/test_serialization/test_3495_deserialize_managerlost.py +47 -0
  281. parsl/tests/test_serialization/test_basic.py +2 -1
  282. parsl/tests/test_serialization/test_htex_code_cache.py +3 -4
  283. parsl/tests/test_serialization/test_pack_resource_spec.py +2 -1
  284. parsl/tests/test_serialization/test_proxystore_configured.py +10 -6
  285. parsl/tests/test_serialization/test_proxystore_impl.py +5 -3
  286. parsl/tests/test_shutdown/test_kill_monitoring.py +64 -0
  287. parsl/tests/test_staging/staging_provider.py +2 -2
  288. parsl/tests/test_staging/test_1316.py +3 -4
  289. parsl/tests/test_staging/test_docs_1.py +2 -1
  290. parsl/tests/test_staging/test_docs_2.py +2 -1
  291. parsl/tests/test_staging/test_elaborate_noop_file.py +2 -3
  292. parsl/tests/{test_data → test_staging}/test_file.py +6 -6
  293. parsl/tests/{test_data → test_staging}/test_output_chain_filenames.py +3 -0
  294. parsl/tests/test_staging/test_staging_ftp.py +1 -0
  295. parsl/tests/test_staging/test_staging_https.py +5 -2
  296. parsl/tests/test_staging/test_staging_stdout.py +64 -0
  297. parsl/tests/test_staging/test_zip_in.py +39 -0
  298. parsl/tests/test_staging/test_zip_out.py +110 -0
  299. parsl/tests/test_staging/test_zip_to_zip.py +41 -0
  300. parsl/tests/test_summary.py +2 -2
  301. parsl/tests/test_thread_parallelism.py +0 -1
  302. parsl/tests/test_threads/test_configs.py +1 -2
  303. parsl/tests/test_threads/test_lazy_errors.py +2 -2
  304. parsl/tests/test_utils/test_execute_wait.py +35 -0
  305. parsl/tests/test_utils/test_sanitize_dns.py +76 -0
  306. parsl/tests/unit/test_address.py +20 -0
  307. parsl/tests/unit/test_file.py +99 -0
  308. parsl/tests/unit/test_usage_tracking.py +66 -0
  309. parsl/usage_tracking/api.py +65 -0
  310. parsl/usage_tracking/levels.py +6 -0
  311. parsl/usage_tracking/usage.py +104 -62
  312. parsl/utils.py +139 -6
  313. parsl/version.py +1 -1
  314. {parsl-2024.3.11.data → parsl-2025.1.13.data}/scripts/exec_parsl_function.py +6 -5
  315. parsl-2025.1.13.data/scripts/interchange.py +649 -0
  316. {parsl-2024.3.11.data → parsl-2025.1.13.data}/scripts/process_worker_pool.py +115 -77
  317. parsl-2025.1.13.dist-info/METADATA +96 -0
  318. parsl-2025.1.13.dist-info/RECORD +462 -0
  319. {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/WHEEL +1 -1
  320. parsl/channels/__init__.py +0 -7
  321. parsl/channels/base.py +0 -141
  322. parsl/channels/errors.py +0 -113
  323. parsl/channels/local/local.py +0 -164
  324. parsl/channels/oauth_ssh/oauth_ssh.py +0 -110
  325. parsl/channels/ssh/ssh.py +0 -276
  326. parsl/channels/ssh_il/__init__.py +0 -0
  327. parsl/channels/ssh_il/ssh_il.py +0 -74
  328. parsl/configs/ad_hoc.py +0 -35
  329. parsl/executors/radical/rpex_master.py +0 -42
  330. parsl/monitoring/radios.py +0 -175
  331. parsl/providers/ad_hoc/__init__.py +0 -0
  332. parsl/providers/ad_hoc/ad_hoc.py +0 -248
  333. parsl/providers/cobalt/__init__.py +0 -0
  334. parsl/providers/cobalt/cobalt.py +0 -236
  335. parsl/providers/cobalt/template.py +0 -17
  336. parsl/tests/configs/ad_hoc_cluster_htex.py +0 -35
  337. parsl/tests/configs/cooley_htex.py +0 -37
  338. parsl/tests/configs/htex_ad_hoc_cluster.py +0 -28
  339. parsl/tests/configs/local_adhoc.py +0 -18
  340. parsl/tests/configs/swan_htex.py +0 -43
  341. parsl/tests/configs/theta.py +0 -37
  342. parsl/tests/integration/test_channels/__init__.py +0 -0
  343. parsl/tests/integration/test_channels/test_channels.py +0 -17
  344. parsl/tests/integration/test_channels/test_local_channel.py +0 -42
  345. parsl/tests/integration/test_channels/test_scp_1.py +0 -45
  346. parsl/tests/integration/test_channels/test_ssh_1.py +0 -40
  347. parsl/tests/integration/test_channels/test_ssh_errors.py +0 -46
  348. parsl/tests/integration/test_channels/test_ssh_file_transport.py +0 -41
  349. parsl/tests/integration/test_channels/test_ssh_interactive.py +0 -24
  350. parsl/tests/manual_tests/test_ad_hoc_htex.py +0 -48
  351. parsl/tests/manual_tests/test_fan_in_out_htex_remote.py +0 -88
  352. parsl/tests/manual_tests/test_oauth_ssh.py +0 -13
  353. parsl/tests/sites/test_local_adhoc.py +0 -61
  354. parsl/tests/test_channels/__init__.py +0 -0
  355. parsl/tests/test_channels/test_large_output.py +0 -22
  356. parsl/tests/test_data/__init__.py +0 -0
  357. parsl/tests/test_mpi_apps/test_mpi_mode_disabled.py +0 -51
  358. parsl/tests/test_providers/test_cobalt_deprecation_warning.py +0 -16
  359. parsl-2024.3.11.dist-info/METADATA +0 -98
  360. parsl-2024.3.11.dist-info/RECORD +0 -447
  361. parsl/{channels/local → monitoring/radios}/__init__.py +0 -0
  362. parsl/{channels/oauth_ssh → tests/test_shutdown}/__init__.py +0 -0
  363. parsl/tests/{test_data → test_staging}/test_file_apps.py +0 -0
  364. parsl/tests/{test_data → test_staging}/test_file_staging.py +0 -0
  365. parsl/{channels/ssh → tests/unit}/__init__.py +0 -0
  366. {parsl-2024.3.11.data → parsl-2025.1.13.data}/scripts/parsl_coprocess.py +1 -1
  367. {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/LICENSE +0 -0
  368. {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/entry_points.txt +0 -0
  369. {parsl-2024.3.11.dist-info → parsl-2025.1.13.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,7 @@
1
- from parsl.providers import LocalProvider
2
- from parsl.channels import LocalChannel
3
-
4
1
  from parsl.config import Config
5
2
  from parsl.executors import HighThroughputExecutor
3
+ from parsl.providers import LocalProvider
4
+ from parsl.usage_tracking.levels import LEVEL_1
6
5
 
7
6
  config = Config(
8
7
  executors=[
@@ -10,10 +9,10 @@ config = Config(
10
9
  label="htex_local",
11
10
  cores_per_worker=1,
12
11
  provider=LocalProvider(
13
- channel=LocalChannel(),
14
12
  init_blocks=1,
15
13
  max_blocks=1,
16
14
  ),
17
15
  )
18
16
  ],
17
+ usage_tracking=LEVEL_1,
19
18
  )
@@ -1,7 +1,8 @@
1
1
  from parsl.config import Config
2
- from parsl.providers import SlurmProvider
3
2
  from parsl.executors import HighThroughputExecutor
4
3
  from parsl.launchers import SrunLauncher
4
+ from parsl.providers import SlurmProvider
5
+ from parsl.usage_tracking.levels import LEVEL_1
5
6
 
6
7
  """ This config assumes that it is used to launch parsl tasks from the login nodes
7
8
  of the Campus Cluster at UIUC. Each job submitted to the scheduler will request 2 nodes for 10 minutes.
@@ -25,4 +26,5 @@ config = Config(
25
26
  ),
26
27
  )
27
28
  ],
29
+ usage_tracking=LEVEL_1,
28
30
  )
@@ -0,0 +1,34 @@
1
+ from parsl.config import Config
2
+ from parsl.executors import HighThroughputExecutor
3
+ from parsl.launchers import MpiRunLauncher
4
+ from parsl.providers import PBSProProvider
5
+
6
+ config = Config(
7
+ executors=[
8
+ HighThroughputExecutor(
9
+ label="Improv_multinode",
10
+ max_workers_per_node=32,
11
+ provider=PBSProProvider(
12
+ account="YOUR_ALLOCATION_ON_IMPROV",
13
+ # PBS directives (header lines), for example:
14
+ # scheduler_options='#PBS -l mem=4gb',
15
+ scheduler_options='',
16
+
17
+ queue="compute",
18
+
19
+ # Command to be run before starting a worker:
20
+ # **WARNING** Improv requires an openmpi module to be
21
+ # loaded for the MpiRunLauncher. Add additional env
22
+ # load commands to this multiline string.
23
+ worker_init='''
24
+ module load gcc/13.2.0;
25
+ module load openmpi/5.0.3-gcc-13.2.0; ''',
26
+ launcher=MpiRunLauncher(),
27
+
28
+ # number of compute nodes allocated for each block
29
+ nodes_per_block=2,
30
+ walltime='00:10:00'
31
+ ),
32
+ ),
33
+ ],
34
+ )
@@ -1,8 +1,8 @@
1
+ from parsl.addresses import address_by_route
1
2
  from parsl.config import Config
2
3
  from parsl.executors import HighThroughputExecutor
3
4
  from parsl.providers import KubernetesProvider
4
- from parsl.addresses import address_by_route
5
-
5
+ from parsl.usage_tracking.levels import LEVEL_1
6
6
 
7
7
  config = Config(
8
8
  executors=[
@@ -37,5 +37,6 @@ config = Config(
37
37
  max_blocks=10,
38
38
  ),
39
39
  ),
40
- ]
40
+ ],
41
+ usage_tracking=LEVEL_1,
41
42
  )
@@ -1,4 +1,8 @@
1
1
  from parsl.config import Config
2
2
  from parsl.executors.threads import ThreadPoolExecutor
3
+ from parsl.usage_tracking.levels import LEVEL_1
3
4
 
4
- config = Config(executors=[ThreadPoolExecutor()])
5
+ config = Config(
6
+ executors=[ThreadPoolExecutor()],
7
+ usage_tracking=LEVEL_1,
8
+ )
parsl/configs/midway.py CHANGED
@@ -1,8 +1,9 @@
1
+ from parsl.addresses import address_by_interface
1
2
  from parsl.config import Config
2
- from parsl.providers import SlurmProvider
3
- from parsl.launchers import SrunLauncher
4
3
  from parsl.executors import HighThroughputExecutor
5
- from parsl.addresses import address_by_interface
4
+ from parsl.launchers import SrunLauncher
5
+ from parsl.providers import SlurmProvider
6
+ from parsl.usage_tracking.levels import LEVEL_1
6
7
 
7
8
  config = Config(
8
9
  executors=[
@@ -28,4 +29,5 @@ config = Config(
28
29
  ),
29
30
  )
30
31
  ],
32
+ usage_tracking=LEVEL_1,
31
33
  )
parsl/configs/osg.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from parsl.config import Config
2
- from parsl.providers import CondorProvider
3
2
  from parsl.executors import HighThroughputExecutor
3
+ from parsl.providers import CondorProvider
4
+ from parsl.usage_tracking.levels import LEVEL_1
4
5
 
5
6
  config = Config(
6
7
  executors=[
@@ -26,5 +27,6 @@ python3 -m venv parsl_env; source parsl_env/bin/activate; python3 -m pip install
26
27
  worker_logdir_root='$OSG_WN_TMP',
27
28
  worker_ports=(31000, 31001)
28
29
  )
29
- ]
30
+ ],
31
+ usage_tracking=LEVEL_1,
30
32
  )
parsl/configs/polaris.py CHANGED
@@ -1,8 +1,9 @@
1
1
  from parsl.addresses import address_by_interface
2
+ from parsl.config import Config
2
3
  from parsl.executors import HighThroughputExecutor
3
4
  from parsl.launchers import MpiExecLauncher
4
5
  from parsl.providers import PBSProProvider
5
- from parsl.config import Config
6
+ from parsl.usage_tracking.levels import LEVEL_1
6
7
 
7
8
  # There are three user parameters to change for the PBSProProvider:
8
9
  # YOUR_ACCOUNT: Account to charge usage
@@ -34,5 +35,6 @@ config = Config(
34
35
  cpus_per_node=64,
35
36
  ),
36
37
  ),
37
- ]
38
+ ],
39
+ usage_tracking=LEVEL_1,
38
40
  )
@@ -1,10 +1,10 @@
1
+ from parsl.addresses import address_by_interface
1
2
  from parsl.config import Config
2
- from parsl.providers import SlurmProvider
3
- from parsl.launchers import SrunLauncher
4
- from parsl.executors import HighThroughputExecutor
5
3
  from parsl.data_provider.globus import GlobusStaging
6
- from parsl.addresses import address_by_interface
7
-
4
+ from parsl.executors import HighThroughputExecutor
5
+ from parsl.launchers import SrunLauncher
6
+ from parsl.providers import SlurmProvider
7
+ from parsl.usage_tracking.levels import LEVEL_1
8
8
 
9
9
  config = Config(
10
10
  executors=[
@@ -35,4 +35,5 @@ config = Config(
35
35
  )
36
36
 
37
37
  ],
38
+ usage_tracking=LEVEL_1,
38
39
  )
parsl/configs/summit.py CHANGED
@@ -1,10 +1,9 @@
1
+ from parsl.addresses import address_by_interface
1
2
  from parsl.config import Config
2
3
  from parsl.executors import HighThroughputExecutor
3
-
4
4
  from parsl.launchers import JsrunLauncher
5
5
  from parsl.providers import LSFProvider
6
-
7
- from parsl.addresses import address_by_interface
6
+ from parsl.usage_tracking.levels import LEVEL_1
8
7
 
9
8
  config = Config(
10
9
  executors=[
@@ -28,4 +27,5 @@ config = Config(
28
27
  )
29
28
 
30
29
  ],
30
+ usage_tracking=LEVEL_1,
31
31
  )
@@ -1,8 +1,8 @@
1
1
  from parsl.config import Config
2
2
  from parsl.executors import FluxExecutor
3
- from parsl.providers import SlurmProvider
4
3
  from parsl.launchers import SrunLauncher
5
-
4
+ from parsl.providers import SlurmProvider
5
+ from parsl.usage_tracking.levels import LEVEL_1
6
6
 
7
7
  config = Config(
8
8
  executors=[
@@ -25,5 +25,6 @@ config = Config(
25
25
  cmd_timeout=120,
26
26
  ),
27
27
  )
28
- ]
28
+ ],
29
+ usage_tracking=LEVEL_1,
29
30
  )
@@ -1,8 +1,9 @@
1
- from parsl.config import Config
2
- from parsl.executors.taskvine import TaskVineExecutor
3
- from parsl.executors.taskvine import TaskVineManagerConfig
4
1
  import uuid
5
2
 
3
+ from parsl.config import Config
4
+ from parsl.executors.taskvine import TaskVineExecutor, TaskVineManagerConfig
5
+ from parsl.usage_tracking.levels import LEVEL_1
6
+
6
7
  config = Config(
7
8
  executors=[
8
9
  TaskVineExecutor(
@@ -15,5 +16,6 @@ config = Config(
15
16
  # To disable status reporting, comment out the project_name.
16
17
  manager_config=TaskVineManagerConfig(project_name="parsl-vine-" + str(uuid.uuid4())),
17
18
  )
18
- ]
19
+ ],
20
+ usage_tracking=LEVEL_1,
19
21
  )
@@ -1,7 +1,8 @@
1
+ import uuid
2
+
1
3
  from parsl.config import Config
2
4
  from parsl.executors import WorkQueueExecutor
3
-
4
- import uuid
5
+ from parsl.usage_tracking.levels import LEVEL_1
5
6
 
6
7
  config = Config(
7
8
  executors=[
@@ -21,5 +22,6 @@ config = Config(
21
22
  # A shared filesystem is not needed when using Work Queue.
22
23
  shared_fs=False
23
24
  )
24
- ]
25
+ ],
26
+ usage_tracking=LEVEL_1,
25
27
  )
parsl/curvezmq.py CHANGED
@@ -160,6 +160,9 @@ class ServerContext(BaseContext):
160
160
  except zmq.ZMQError as e:
161
161
  raise ValueError("Invalid CurveZMQ key format") from e
162
162
  sock.setsockopt(zmq.CURVE_SERVER, True) # Must come before bind
163
+
164
+ # This flag enables IPV6 in addition to IPV4
165
+ sock.setsockopt(zmq.IPV6, True)
163
166
  return sock
164
167
 
165
168
  def term(self):
@@ -202,4 +205,5 @@ class ClientContext(BaseContext):
202
205
  sock.setsockopt(zmq.CURVE_SERVERKEY, server_public_key)
203
206
  except zmq.ZMQError as e:
204
207
  raise ValueError("Invalid CurveZMQ key format") from e
208
+ sock.setsockopt(zmq.IPV6, True)
205
209
  return sock
@@ -1,13 +1,14 @@
1
1
  import logging
2
2
  from concurrent.futures import Future
3
- from typing import Any, Callable, List, Optional, TYPE_CHECKING
3
+ from typing import TYPE_CHECKING, Any, Callable, List, Optional
4
4
 
5
5
  from parsl.app.futures import DataFuture
6
- from parsl.data_provider.files import File
7
6
  from parsl.data_provider.file_noop import NoOpFileStaging
7
+ from parsl.data_provider.files import File
8
8
  from parsl.data_provider.ftp import FTPSeparateTaskStaging
9
9
  from parsl.data_provider.http import HTTPSeparateTaskStaging
10
10
  from parsl.data_provider.staging import Staging
11
+ from parsl.data_provider.zip import ZipFileStaging
11
12
 
12
13
  if TYPE_CHECKING:
13
14
  from parsl.dataflow.dflow import DataFlowKernel
@@ -17,7 +18,7 @@ logger = logging.getLogger(__name__)
17
18
  # these will be shared between all executors that do not explicitly
18
19
  # override, so should not contain executor-specific state
19
20
  default_staging: List[Staging]
20
- default_staging = [NoOpFileStaging(), FTPSeparateTaskStaging(), HTTPSeparateTaskStaging()]
21
+ default_staging = [NoOpFileStaging(), FTPSeparateTaskStaging(), HTTPSeparateTaskStaging(), ZipFileStaging()]
21
22
 
22
23
 
23
24
  class DataManager:
@@ -1,8 +1,7 @@
1
1
  import logging
2
2
 
3
- from parsl.utils import RepresentationMixin
4
3
  from parsl.data_provider.staging import Staging
5
-
4
+ from parsl.utils import RepresentationMixin
6
5
 
7
6
  logger = logging.getLogger(__name__)
8
7
 
@@ -5,13 +5,13 @@ to transfer the file as well as to give the appropriate filepath depending
5
5
  on where (client-side, remote-side, intermediary-side) the File.filepath is
6
6
  being called from.
7
7
  """
8
- import os
9
-
10
- import typeguard
11
8
  import logging
9
+ import os
12
10
  from typing import Optional, Union
13
11
  from urllib.parse import urlparse
14
12
 
13
+ import typeguard
14
+
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
17
 
@@ -3,10 +3,8 @@ import logging
3
3
  import os
4
4
 
5
5
  import parsl
6
-
7
- from parsl.utils import RepresentationMixin
8
6
  from parsl.data_provider.staging import Staging
9
-
7
+ from parsl.utils import RepresentationMixin
10
8
 
11
9
  logger = logging.getLogger(__name__)
12
10
 
@@ -1,15 +1,16 @@
1
- import logging
2
1
  import json
3
- import globus_sdk
2
+ import logging
4
3
  import os
5
- import parsl
6
- import typeguard
7
-
8
4
  from functools import partial
9
5
  from typing import Optional
6
+
7
+ import globus_sdk
8
+ import typeguard
9
+
10
+ import parsl
10
11
  from parsl.app.app import python_app
11
- from parsl.utils import RepresentationMixin
12
12
  from parsl.data_provider.staging import Staging
13
+ from parsl.utils import RepresentationMixin
13
14
 
14
15
  logger = logging.getLogger(__name__)
15
16
 
@@ -1,11 +1,11 @@
1
1
  import logging
2
2
  import os
3
+
3
4
  import requests
4
5
 
5
6
  import parsl
6
-
7
- from parsl.utils import RepresentationMixin
8
7
  from parsl.data_provider.staging import Staging
8
+ from parsl.utils import RepresentationMixin
9
9
 
10
10
  logger = logging.getLogger(__name__)
11
11
 
@@ -1,8 +1,8 @@
1
1
  import logging
2
2
  import os
3
3
 
4
- from parsl.utils import RepresentationMixin
5
4
  from parsl.data_provider.staging import Staging
5
+ from parsl.utils import RepresentationMixin
6
6
 
7
7
  logger = logging.getLogger(__name__)
8
8
 
@@ -1,9 +1,9 @@
1
1
  from concurrent.futures import Future
2
- from typing import Optional, Callable
2
+ from typing import TYPE_CHECKING, Callable, Optional
3
+
3
4
  from parsl.app.futures import DataFuture
4
5
  from parsl.data_provider.files import File
5
6
 
6
- from typing import TYPE_CHECKING
7
7
  if TYPE_CHECKING:
8
8
  from parsl.data_provider.data_manager import DataManager
9
9
 
@@ -0,0 +1,135 @@
1
+ import logging
2
+ import os
3
+ import zipfile
4
+ from typing import Tuple
5
+
6
+ import filelock
7
+
8
+ import parsl
9
+ from parsl.data_provider.files import File
10
+ from parsl.data_provider.staging import Staging
11
+ from parsl.errors import ParslError
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class ZipAuthorityError(ParslError):
17
+ def __init__(self, file):
18
+ self.file = file
19
+
20
+ def __str__(self):
21
+ return f"ZipFileStaging cannot stage Files with an authority (netloc) section ({self.file.netloc}), for {self.file.url}"
22
+
23
+
24
+ class ZipFileStaging(Staging):
25
+ """A stage-out provider for zip files.
26
+
27
+ This provider will stage out files by writing them into the specified zip
28
+ file.
29
+
30
+ The filename of both the zip file and the file contained in that zip are
31
+ specified using a zip: URL, like this:
32
+
33
+ zip:/tmp/foo/this.zip/inside/here.txt
34
+
35
+ This URL names a zip file ``/tmp/foo/this.zip`` containing a file
36
+ ``inside/here.txt``.
37
+
38
+ The provider will use the Python filelock package to lock the zip file so
39
+ that it does not conflict with other instances of itself. This lock will
40
+ not protect against other modifications to the zip file.
41
+ """
42
+
43
+ def can_stage_out(self, file: File) -> bool:
44
+ return self.is_zip_url(file)
45
+
46
+ def can_stage_in(self, file: File) -> bool:
47
+ return self.is_zip_url(file)
48
+
49
+ def is_zip_url(self, file: File) -> bool:
50
+ logger.debug("archive provider checking File {}".format(repr(file)))
51
+
52
+ # First check if this is the scheme we care about
53
+ if file.scheme != "zip":
54
+ return False
55
+
56
+ # This is some basic validation to check that the user isn't specifying
57
+ # an authority section and expecting it to mean something.
58
+ if file.netloc != "":
59
+ raise ZipAuthorityError(file)
60
+
61
+ # If we got this far, we can stage this file
62
+ return True
63
+
64
+ def stage_out(self, dm, executor, file, parent_fut):
65
+ assert file.scheme == 'zip'
66
+
67
+ zip_path, inside_path = zip_path_split(file.path)
68
+
69
+ working_dir = dm.dfk.executors[executor].working_dir
70
+
71
+ if working_dir:
72
+ file.local_path = os.path.join(working_dir, inside_path)
73
+
74
+ # TODO: I think its the right behaviour that a staging out provider should create the directory structure
75
+ # for the file to be placed in?
76
+ os.makedirs(os.path.dirname(file.local_path), exist_ok=True)
77
+ else:
78
+ raise RuntimeError("zip file staging requires a working_dir to be specified")
79
+
80
+ stage_out_app = _zip_stage_out_app(dm)
81
+ app_fut = stage_out_app(zip_path, inside_path, working_dir, inputs=[file], _parsl_staging_inhibit=True, parent_fut=parent_fut)
82
+ return app_fut
83
+
84
+ def stage_in(self, dm, executor, file, parent_fut):
85
+ assert file.scheme == 'zip'
86
+
87
+ zip_path, inside_path = zip_path_split(file.path)
88
+
89
+ working_dir = dm.dfk.executors[executor].working_dir
90
+
91
+ if working_dir:
92
+ file.local_path = os.path.join(working_dir, inside_path)
93
+
94
+ stage_in_app = _zip_stage_in_app(dm)
95
+ app_fut = stage_in_app(zip_path, inside_path, working_dir, outputs=[file], _parsl_staging_inhibit=True, parent_fut=parent_fut)
96
+ return app_fut._outputs[0]
97
+
98
+
99
+ def _zip_stage_out(zip_file, inside_path, working_dir, parent_fut=None, inputs=[], _parsl_staging_inhibit=True):
100
+ file = inputs[0]
101
+
102
+ os.makedirs(os.path.dirname(zip_file), exist_ok=True)
103
+
104
+ with filelock.FileLock(zip_file + ".lock"):
105
+ with zipfile.ZipFile(zip_file, mode='a', compression=zipfile.ZIP_DEFLATED) as z:
106
+ z.write(file, arcname=inside_path)
107
+
108
+ os.remove(file)
109
+
110
+
111
+ def _zip_stage_out_app(dm):
112
+ return parsl.python_app(executors=['_parsl_internal'], data_flow_kernel=dm.dfk)(_zip_stage_out)
113
+
114
+
115
+ def _zip_stage_in(zip_file, inside_path, working_dir, *, parent_fut, outputs, _parsl_staging_inhibit=True):
116
+ with filelock.FileLock(zip_file + ".lock"):
117
+ with zipfile.ZipFile(zip_file, mode='r') as z:
118
+ content = z.read(inside_path)
119
+ with open(outputs[0], "wb") as of:
120
+ of.write(content)
121
+
122
+
123
+ def _zip_stage_in_app(dm):
124
+ return parsl.python_app(executors=['_parsl_internal'], data_flow_kernel=dm.dfk)(_zip_stage_in)
125
+
126
+
127
+ def zip_path_split(path: str) -> Tuple[str, str]:
128
+ """Split zip: path into a zipfile name and a contained-file name.
129
+ """
130
+ index = path.find(".zip/")
131
+
132
+ zip_path = path[:index + 4]
133
+ inside_path = path[index + 5:]
134
+
135
+ return (zip_path, inside_path)
@@ -0,0 +1,115 @@
1
+ from concurrent.futures import Future
2
+ from dataclasses import dataclass
3
+ from functools import singledispatch
4
+ from typing import Callable, Sequence
5
+
6
+
7
+ @dataclass
8
+ class DependencyResolver:
9
+ """A DependencyResolver describes how app dependencies can be resolved.
10
+ It is specified as two functions: `traverse_to_gather` which turns an
11
+ app parameter into a sequence of futures which must be waited for before
12
+ the task can be executed (for example, in the case of
13
+ `DEEP_DEPENDENCY_RESOLVER` this traverses structures such as lists to
14
+ find every contained ``Future``), and `traverse_to_unwrap` which turns an
15
+ app parameter into its value to be passed to the app on execution
16
+ (for example in the case of `DEEP_DEPENDENCY_RESOLVER` this replaces a
17
+ list containing futures with a new list containing the values of those
18
+ resolved futures).
19
+
20
+ By default, Parsl will use `SHALLOW_DEPENDENCY_RESOLVER` which only
21
+ resolves Futures passed directly as arguments.
22
+ """
23
+ traverse_to_gather: Callable[[object], Sequence[Future]]
24
+ traverse_to_unwrap: Callable[[object], object]
25
+
26
+
27
+ @singledispatch
28
+ def shallow_traverse_to_gather(o):
29
+ # objects in general do not expose futures that we can see
30
+ return []
31
+
32
+
33
+ @singledispatch
34
+ def shallow_traverse_to_unwrap(o):
35
+ # objects in general unwrap to themselves
36
+ return o
37
+
38
+
39
+ @shallow_traverse_to_gather.register
40
+ def _(fut: Future):
41
+ return [fut]
42
+
43
+
44
+ @shallow_traverse_to_unwrap.register
45
+ @singledispatch
46
+ def _(fut: Future):
47
+ assert fut.done()
48
+ return fut.result()
49
+
50
+
51
+ @singledispatch
52
+ def deep_traverse_to_gather(o):
53
+ # objects in general do not expose futures that we can see
54
+ return []
55
+
56
+
57
+ @singledispatch
58
+ def deep_traverse_to_unwrap(o):
59
+ # objects in general unwrap to themselves
60
+ return o
61
+
62
+
63
+ @deep_traverse_to_gather.register
64
+ def _(fut: Future):
65
+ return [fut]
66
+
67
+
68
+ @deep_traverse_to_unwrap.register
69
+ @singledispatch
70
+ def _(fut: Future):
71
+ assert fut.done()
72
+ return fut.result()
73
+
74
+
75
+ @deep_traverse_to_gather.register(tuple)
76
+ @deep_traverse_to_gather.register(list)
77
+ @deep_traverse_to_gather.register(set)
78
+ def _(iterable):
79
+ return [e for v in iterable for e in deep_traverse_to_gather(v)]
80
+
81
+
82
+ @deep_traverse_to_unwrap.register(tuple)
83
+ @deep_traverse_to_unwrap.register(list)
84
+ @deep_traverse_to_unwrap.register(set)
85
+ @singledispatch
86
+ def _(iterable):
87
+
88
+ type_ = type(iterable)
89
+ return type_(map(deep_traverse_to_unwrap, iterable))
90
+
91
+
92
+ @deep_traverse_to_gather.register(dict)
93
+ def _(dictionary):
94
+ futures = []
95
+ for key, value in dictionary.items():
96
+ futures.extend(deep_traverse_to_gather(key))
97
+ futures.extend(deep_traverse_to_gather(value))
98
+ return futures
99
+
100
+
101
+ @deep_traverse_to_unwrap.register(dict)
102
+ def _(dictionary):
103
+ unwrapped_dict = {}
104
+ for key, value in dictionary.items():
105
+ key = deep_traverse_to_unwrap(key)
106
+ value = deep_traverse_to_unwrap(value)
107
+ unwrapped_dict[key] = value
108
+ return unwrapped_dict
109
+
110
+
111
+ DEEP_DEPENDENCY_RESOLVER = DependencyResolver(traverse_to_gather=deep_traverse_to_gather,
112
+ traverse_to_unwrap=deep_traverse_to_unwrap)
113
+
114
+ SHALLOW_DEPENDENCY_RESOLVER = DependencyResolver(traverse_to_gather=shallow_traverse_to_gather,
115
+ traverse_to_unwrap=shallow_traverse_to_unwrap)