From e312d97e5c6b5c26d24237727e2ec899008cb220 Mon Sep 17 00:00:00 2001 From: mjwen Date: Tue, 7 Nov 2023 11:36:24 -0600 Subject: [PATCH 01/23] Allow SSHTunnel in Settings --- src/jobflow/core/store.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jobflow/core/store.py b/src/jobflow/core/store.py index 923cbb46..fbccf077 100644 --- a/src/jobflow/core/store.py +++ b/src/jobflow/core/store.py @@ -661,6 +661,10 @@ def all_subclasses(cl): all_stores = {s.__name__: s for s in all_subclasses(maggma.stores.Store)} + # add ssh tunnel support + tunnel = maggma.stores.ssh_tunnel.SSHTunnel + all_stores[tunnel.__name__] = tunnel + docs_store_info = spec["docs_store"] docs_store = _construct_store(docs_store_info, all_stores) From c87139f5221ab277a8e3661fa429f47fffcf093b Mon Sep 17 00:00:00 2001 From: JaGeo Date: Thu, 23 Nov 2023 23:48:49 +0100 Subject: [PATCH 02/23] Add fibonacci example to tutorial --- docs/tutorials/5-dynamic-flows.ipynb | 295 ++++++++++++++++++++------- 1 file changed, 221 insertions(+), 74 deletions(-) diff --git a/docs/tutorials/5-dynamic-flows.ipynb b/docs/tutorials/5-dynamic-flows.ipynb index b99861ed..9673cd21 100644 --- a/docs/tutorials/5-dynamic-flows.ipynb +++ b/docs/tutorials/5-dynamic-flows.ipynb @@ -39,11 +39,15 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "78348798", "metadata": { "nbsphinx": "hidden", - "tags": [] + "tags": [], + "ExecuteTime": { + "end_time": "2023-11-23T22:46:57.984085360Z", + "start_time": "2023-11-23T22:46:57.166923399Z" + } }, "outputs": [], "source": [ @@ -54,35 +58,40 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "964a8c44", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.036098609Z", + "start_time": "2023-11-23T22:46:57.208641695Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "2023-06-08 09:55:05,762 INFO Started executing jobs locally\n", - "2023-06-08 09:55:05,873 INFO Starting job - make_list (68b72ca9-00ae-430f-a61c-fbea22bbf0aa)\n", - "2023-06-08 09:55:05,874 INFO Finished job - make_list (68b72ca9-00ae-430f-a61c-fbea22bbf0aa)\n", - "2023-06-08 09:55:05,874 INFO Starting job - add_distributed (01821a62-3ee2-47f0-a6ca-fd373ea0ea09)\n", - "2023-06-08 09:55:05,875 INFO Finished job - add_distributed (01821a62-3ee2-47f0-a6ca-fd373ea0ea09)\n", - "2023-06-08 09:55:05,876 INFO Starting job - add (fbc49130-2bbe-49b0-a190-48815c03a0b0)\n", - "2023-06-08 09:55:05,876 INFO Finished job - add (fbc49130-2bbe-49b0-a190-48815c03a0b0)\n", - "2023-06-08 09:55:05,877 INFO Starting job - add (ca3636e3-50f7-4ec8-a5e7-66bc4e14b901)\n", - "2023-06-08 09:55:05,877 INFO Finished job - add (ca3636e3-50f7-4ec8-a5e7-66bc4e14b901)\n", - "2023-06-08 09:55:05,877 INFO Starting job - add (28dbe7c4-b29b-46c4-9d0c-2aee7334b999)\n", - "2023-06-08 09:55:05,878 INFO Finished job - add (28dbe7c4-b29b-46c4-9d0c-2aee7334b999)\n", - "2023-06-08 09:55:05,878 INFO Starting job - add (1bffefd1-4edc-43d5-b99f-b0833fca2b8d)\n", - "2023-06-08 09:55:05,879 INFO Finished job - add (1bffefd1-4edc-43d5-b99f-b0833fca2b8d)\n", - "2023-06-08 09:55:05,879 INFO Finished executing jobs locally\n" + "2023-11-23 23:46:57,177 INFO Started executing jobs locally\n", + "2023-11-23 23:46:57,179 INFO Starting job - make_list (16fc2fd0-c9c7-420d-b0e1-3e6b5802c744)\n", + "2023-11-23 23:46:57,182 INFO Finished job - make_list (16fc2fd0-c9c7-420d-b0e1-3e6b5802c744)\n", + "2023-11-23 23:46:57,183 INFO Starting job - add_distributed (536e3c78-7d59-43ed-9f4f-72ce9b3793ef)\n", + "2023-11-23 23:46:57,191 INFO Finished job - add_distributed (536e3c78-7d59-43ed-9f4f-72ce9b3793ef)\n", + "2023-11-23 23:46:57,193 INFO Starting job - add (44007968-8394-442f-ba96-d52dc30a80ce)\n", + "2023-11-23 23:46:57,195 INFO Finished job - add (44007968-8394-442f-ba96-d52dc30a80ce)\n", + "2023-11-23 23:46:57,196 INFO Starting job - add (1af57ed7-3594-4180-b550-787c5f029d9f)\n", + "2023-11-23 23:46:57,198 INFO Finished job - add (1af57ed7-3594-4180-b550-787c5f029d9f)\n", + "2023-11-23 23:46:57,199 INFO Starting job - add (f7ea9158-40f8-4439-9d18-b6b6fb3e9289)\n", + "2023-11-23 23:46:57,201 INFO Finished job - add (f7ea9158-40f8-4439-9d18-b6b6fb3e9289)\n", + "2023-11-23 23:46:57,202 INFO Starting job - add (72c752d3-208a-45ce-bbb6-625e4debed73)\n", + "2023-11-23 23:46:57,204 INFO Finished job - add (72c752d3-208a-45ce-bbb6-625e4debed73)\n", + "2023-11-23 23:46:57,205 INFO Finished executing jobs locally\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "/Users/alexmganose/dev/src/jobflow/src/jobflow/utils/graph.py:53: UserWarning: Some jobs are not connected, their ordering may be random\n", + "/home/jgeorge/miniconda3/envs/AddJobflowTutorial/lib/python3.10/site-packages/jobflow/utils/graph.py:49: UserWarning: Some jobs are not connected, their ordering may be random\n", " warnings.warn(\"Some jobs are not connected, their ordering may be random\")\n" ] } @@ -118,20 +127,29 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "82e368e6", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.037599975Z", + "start_time": "2023-11-23T22:46:57.233955503Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "68b72ca9-00ae-430f-a61c-fbea22bbf0aa -> {1: Response(output=[2, 2, 2, 2], detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "01821a62-3ee2-47f0-a6ca-fd373ea0ea09 -> {1: Response(output=None, detour=None, addition=None, replace=, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "fbc49130-2bbe-49b0-a190-48815c03a0b0 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "ca3636e3-50f7-4ec8-a5e7-66bc4e14b901 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "28dbe7c4-b29b-46c4-9d0c-2aee7334b999 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "1bffefd1-4edc-43d5-b99f-b0833fca2b8d -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" + "16fc2fd0-c9c7-420d-b0e1-3e6b5802c744 -> {1: Response(output=[2, 2, 2, 2], detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "536e3c78-7d59-43ed-9f4f-72ce9b3793ef -> {1: Response(output=None, detour=None, addition=None, replace=Flow(name='Flow', uuid='1d51c5df-174a-41c8-b017-98494c8411f1')\n", + "1. Job(name='add', uuid='44007968-8394-442f-ba96-d52dc30a80ce')\n", + "2. Job(name='add', uuid='1af57ed7-3594-4180-b550-787c5f029d9f')\n", + "3. Job(name='add', uuid='f7ea9158-40f8-4439-9d18-b6b6fb3e9289')\n", + "4. Job(name='add', uuid='72c752d3-208a-45ce-bbb6-625e4debed73'), stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "44007968-8394-442f-ba96-d52dc30a80ce -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "1af57ed7-3594-4180-b550-787c5f029d9f -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "f7ea9158-40f8-4439-9d18-b6b6fb3e9289 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "72c752d3-208a-45ce-bbb6-625e4debed73 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" ] } ], @@ -171,22 +189,27 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "81870e55", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.041273240Z", + "start_time": "2023-11-23T22:46:57.406089273Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "2023-06-08 09:55:07,374 INFO Started executing jobs locally\n", - "2023-06-08 09:55:07,377 INFO Starting job - add (8270f7cc-e12a-457b-adca-a196ee62ae85)\n", - "2023-06-08 09:55:07,379 INFO Finished job - add (8270f7cc-e12a-457b-adca-a196ee62ae85)\n", - "2023-06-08 09:55:07,380 INFO Starting job - add_with_logic (fd549146-aabb-4e4b-b79a-ca6b6fd2c172)\n", - "2023-06-08 09:55:07,382 INFO Finished job - add_with_logic (fd549146-aabb-4e4b-b79a-ca6b6fd2c172)\n", - "2023-06-08 09:55:07,384 INFO Starting job - add (9db2454f-4f1d-4d08-8497-1239cad74d0c)\n", - "2023-06-08 09:55:07,384 INFO Finished job - add (9db2454f-4f1d-4d08-8497-1239cad74d0c)\n", - "2023-06-08 09:55:07,385 INFO Finished executing jobs locally\n" + "2023-11-23 23:46:57,406 INFO Started executing jobs locally\n", + "2023-11-23 23:46:57,408 INFO Starting job - add (34ba86a3-99cd-461e-bc17-511fdf6e08ec)\n", + "2023-11-23 23:46:57,411 INFO Finished job - add (34ba86a3-99cd-461e-bc17-511fdf6e08ec)\n", + "2023-11-23 23:46:57,412 INFO Starting job - add_with_logic (349afb69-d732-44b8-b770-2500f44511f9)\n", + "2023-11-23 23:46:57,421 INFO Finished job - add_with_logic (349afb69-d732-44b8-b770-2500f44511f9)\n", + "2023-11-23 23:46:57,422 INFO Starting job - add (64e623da-cf31-485e-9ed1-1f996a955868)\n", + "2023-11-23 23:46:57,424 INFO Finished job - add (64e623da-cf31-485e-9ed1-1f996a955868)\n", + "2023-11-23 23:46:57,425 INFO Finished executing jobs locally\n" ] } ], @@ -209,17 +232,23 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "fdc68eb5", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.046206634Z", + "start_time": "2023-11-23T22:46:57.448864584Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "8270f7cc-e12a-457b-adca-a196ee62ae85 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "fd549146-aabb-4e4b-b79a-ca6b6fd2c172 -> {1: Response(output=None, detour=None, addition=, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "9db2454f-4f1d-4d08-8497-1239cad74d0c -> {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" + "34ba86a3-99cd-461e-bc17-511fdf6e08ec -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "349afb69-d732-44b8-b770-2500f44511f9 -> {1: Response(output=None, detour=None, addition=Flow(name='Flow', uuid='20581dd8-b00e-424b-94ad-7f2b2f4a240b')\n", + "1. Job(name='add', uuid='64e623da-cf31-485e-9ed1-1f996a955868'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "64e623da-cf31-485e-9ed1-1f996a955868 -> {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" ] } ], @@ -238,20 +267,25 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "27569bd7", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.090608163Z", + "start_time": "2023-11-23T22:46:57.481314817Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "2023-06-08 09:55:08,838 INFO Started executing jobs locally\n", - "2023-06-08 09:55:08,841 INFO Starting job - add (ec551667-1500-45cc-b61a-2361a18b99fd)\n", - "2023-06-08 09:55:08,843 INFO Finished job - add (ec551667-1500-45cc-b61a-2361a18b99fd)\n", - "2023-06-08 09:55:08,843 INFO Starting job - add_with_logic (e7d3fb53-fa56-45bd-9951-45b70028ada7)\n", - "2023-06-08 09:55:08,846 INFO Finished job - add_with_logic (e7d3fb53-fa56-45bd-9951-45b70028ada7)\n", - "2023-06-08 09:55:08,847 INFO Finished executing jobs locally\n" + "2023-11-23 23:46:57,479 INFO Started executing jobs locally\n", + "2023-11-23 23:46:57,481 INFO Starting job - add (0ae20220-b69c-4e6b-827a-2f046b00d504)\n", + "2023-11-23 23:46:57,484 INFO Finished job - add (0ae20220-b69c-4e6b-827a-2f046b00d504)\n", + "2023-11-23 23:46:57,485 INFO Starting job - add_with_logic (145dea09-be6c-47fc-ac46-c9a6908323e7)\n", + "2023-11-23 23:46:57,490 INFO Finished job - add_with_logic (145dea09-be6c-47fc-ac46-c9a6908323e7)\n", + "2023-11-23 23:46:57,491 INFO Finished executing jobs locally\n" ] } ], @@ -274,16 +308,21 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "b8d0c011", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.092445839Z", + "start_time": "2023-11-23T22:46:57.524568954Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "ec551667-1500-45cc-b61a-2361a18b99fd -> {1: Response(output=21, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "e7d3fb53-fa56-45bd-9951-45b70028ada7 -> {1: Response(output=None, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" + "0ae20220-b69c-4e6b-827a-2f046b00d504 -> {1: Response(output=21, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "145dea09-be6c-47fc-ac46-c9a6908323e7 -> {1: Response(output=None, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" ] } ], @@ -300,6 +339,108 @@ "Now, we see that the `Response(addition)` does not launch a new job.\n" ] }, + { + "cell_type": "markdown", + "source": [ + "In this way, one can also compute the Fibonacci numbers:" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 9, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2023-11-23 23:46:57,625 INFO Started executing jobs locally\n", + "2023-11-23 23:46:57,626 INFO Starting job - fibonacci (81d7944a-bd5a-4edd-a67f-36d2312e506b)\n", + "2023-11-23 23:46:57,630 INFO Finished job - fibonacci (81d7944a-bd5a-4edd-a67f-36d2312e506b)\n", + "2023-11-23 23:46:57,631 INFO Starting job - fibonacci (3219e168-b719-409a-8dbd-94370c03e162)\n", + "2023-11-23 23:46:57,634 INFO Finished job - fibonacci (3219e168-b719-409a-8dbd-94370c03e162)\n", + "2023-11-23 23:46:57,636 INFO Starting job - fibonacci (98308b42-817b-4ee5-bf68-fefcf1bd0de3)\n", + "2023-11-23 23:46:57,639 INFO Finished job - fibonacci (98308b42-817b-4ee5-bf68-fefcf1bd0de3)\n", + "2023-11-23 23:46:57,640 INFO Starting job - fibonacci (57c73c23-9fbf-4f08-8e0f-7698027b632b)\n", + "2023-11-23 23:46:57,643 INFO Finished job - fibonacci (57c73c23-9fbf-4f08-8e0f-7698027b632b)\n", + "2023-11-23 23:46:57,644 INFO Starting job - fibonacci (33c81f02-e87b-4848-8780-a09de20041b1)\n", + "2023-11-23 23:46:57,647 INFO Finished job - fibonacci (33c81f02-e87b-4848-8780-a09de20041b1)\n", + "2023-11-23 23:46:57,648 INFO Starting job - fibonacci (690e4d45-9e9b-43d8-8865-2085cc0feee2)\n", + "2023-11-23 23:46:57,650 INFO Finished job - fibonacci (690e4d45-9e9b-43d8-8865-2085cc0feee2)\n", + "2023-11-23 23:46:57,651 INFO Starting job - fibonacci (8142cc72-a4e3-4884-a446-98f0bea98569)\n", + "2023-11-23 23:46:57,655 INFO Finished job - fibonacci (8142cc72-a4e3-4884-a446-98f0bea98569)\n", + "2023-11-23 23:46:57,656 INFO Starting job - fibonacci (c2b4ec59-5088-4daf-9dba-34a2a3fbe56e)\n", + "2023-11-23 23:46:57,659 INFO Finished job - fibonacci (c2b4ec59-5088-4daf-9dba-34a2a3fbe56e)\n", + "2023-11-23 23:46:57,660 INFO Starting job - fibonacci (2db909a8-14df-4bd1-89a8-d188948382f1)\n", + "2023-11-23 23:46:57,663 INFO Finished job - fibonacci (2db909a8-14df-4bd1-89a8-d188948382f1)\n", + "2023-11-23 23:46:57,664 INFO Starting job - fibonacci (273a46cc-4762-495e-a1d7-e4e26203f122)\n", + "2023-11-23 23:46:57,666 INFO Finished job - fibonacci (273a46cc-4762-495e-a1d7-e4e26203f122)\n", + "2023-11-23 23:46:57,667 INFO Starting job - fibonacci (3fe6a08d-74f9-406f-a219-fdd68f1f6ec9)\n", + "2023-11-23 23:46:57,670 INFO Finished job - fibonacci (3fe6a08d-74f9-406f-a219-fdd68f1f6ec9)\n", + "2023-11-23 23:46:57,671 INFO Starting job - fibonacci (5c44497a-4497-4bf2-a0ee-172abf1251eb)\n", + "2023-11-23 23:46:57,674 INFO Finished job - fibonacci (5c44497a-4497-4bf2-a0ee-172abf1251eb)\n", + "2023-11-23 23:46:57,675 INFO Starting job - fibonacci (1b21a0be-8b79-42ad-a13b-c43c7077d637)\n", + "2023-11-23 23:46:57,678 INFO Finished job - fibonacci (1b21a0be-8b79-42ad-a13b-c43c7077d637)\n", + "2023-11-23 23:46:57,679 INFO Starting job - fibonacci (a6af5fcc-2a3b-4a40-8620-28edadb64b9f)\n", + "2023-11-23 23:46:57,682 INFO Finished job - fibonacci (a6af5fcc-2a3b-4a40-8620-28edadb64b9f)\n", + "2023-11-23 23:46:57,683 INFO Starting job - fibonacci (552ad89c-3e1f-4385-8eb5-01a761a6f9f1)\n", + "2023-11-23 23:46:57,686 INFO Finished job - fibonacci (552ad89c-3e1f-4385-8eb5-01a761a6f9f1)\n", + "2023-11-23 23:46:57,687 INFO Finished executing jobs locally\n", + "{'81d7944a-bd5a-4edd-a67f-36d2312e506b': {1: Response(output=2, detour=None, addition=Flow(name='Flow', uuid='b497505f-e73a-4324-99b4-2923d76bed6e')\n", + "1. Job(name='fibonacci', uuid='3219e168-b719-409a-8dbd-94370c03e162'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '3219e168-b719-409a-8dbd-94370c03e162': {1: Response(output=3, detour=None, addition=Flow(name='Flow', uuid='985aad5f-060f-4841-a2d0-edcdb4a4526d')\n", + "1. Job(name='fibonacci', uuid='98308b42-817b-4ee5-bf68-fefcf1bd0de3'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '98308b42-817b-4ee5-bf68-fefcf1bd0de3': {1: Response(output=5, detour=None, addition=Flow(name='Flow', uuid='076cc046-7ffe-40fe-a14d-5c97d9e92b40')\n", + "1. Job(name='fibonacci', uuid='57c73c23-9fbf-4f08-8e0f-7698027b632b'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '57c73c23-9fbf-4f08-8e0f-7698027b632b': {1: Response(output=8, detour=None, addition=Flow(name='Flow', uuid='38b57dd4-ddb1-425c-8153-5e2c195942da')\n", + "1. Job(name='fibonacci', uuid='33c81f02-e87b-4848-8780-a09de20041b1'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '33c81f02-e87b-4848-8780-a09de20041b1': {1: Response(output=13, detour=None, addition=Flow(name='Flow', uuid='057e0e16-62d3-461e-a13b-9d86c5f72780')\n", + "1. Job(name='fibonacci', uuid='690e4d45-9e9b-43d8-8865-2085cc0feee2'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '690e4d45-9e9b-43d8-8865-2085cc0feee2': {1: Response(output=21, detour=None, addition=Flow(name='Flow', uuid='a2f5bb27-5539-48be-a706-04af3756eedf')\n", + "1. Job(name='fibonacci', uuid='8142cc72-a4e3-4884-a446-98f0bea98569'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '8142cc72-a4e3-4884-a446-98f0bea98569': {1: Response(output=34, detour=None, addition=Flow(name='Flow', uuid='c0b854aa-aae5-4277-b7e1-45416e65384e')\n", + "1. Job(name='fibonacci', uuid='c2b4ec59-5088-4daf-9dba-34a2a3fbe56e'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, 'c2b4ec59-5088-4daf-9dba-34a2a3fbe56e': {1: Response(output=55, detour=None, addition=Flow(name='Flow', uuid='f31f638f-4147-4677-b8f5-72e44d9b12f9')\n", + "1. Job(name='fibonacci', uuid='2db909a8-14df-4bd1-89a8-d188948382f1'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '2db909a8-14df-4bd1-89a8-d188948382f1': {1: Response(output=89, detour=None, addition=Flow(name='Flow', uuid='5f5383a3-7b2d-4e86-98ca-66636006e6a3')\n", + "1. Job(name='fibonacci', uuid='273a46cc-4762-495e-a1d7-e4e26203f122'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '273a46cc-4762-495e-a1d7-e4e26203f122': {1: Response(output=144, detour=None, addition=Flow(name='Flow', uuid='4711a431-8976-4e7c-be1c-cb4962aab4a7')\n", + "1. Job(name='fibonacci', uuid='3fe6a08d-74f9-406f-a219-fdd68f1f6ec9'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '3fe6a08d-74f9-406f-a219-fdd68f1f6ec9': {1: Response(output=233, detour=None, addition=Flow(name='Flow', uuid='0dc7cb69-5797-4880-a8b7-c54f99490322')\n", + "1. Job(name='fibonacci', uuid='5c44497a-4497-4bf2-a0ee-172abf1251eb'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '5c44497a-4497-4bf2-a0ee-172abf1251eb': {1: Response(output=377, detour=None, addition=Flow(name='Flow', uuid='2469da06-bb02-4597-925c-df154d34115d')\n", + "1. Job(name='fibonacci', uuid='1b21a0be-8b79-42ad-a13b-c43c7077d637'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '1b21a0be-8b79-42ad-a13b-c43c7077d637': {1: Response(output=610, detour=None, addition=Flow(name='Flow', uuid='c92c422d-372c-45bd-9159-1ef9243c8f7f')\n", + "1. Job(name='fibonacci', uuid='a6af5fcc-2a3b-4a40-8620-28edadb64b9f'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, 'a6af5fcc-2a3b-4a40-8620-28edadb64b9f': {1: Response(output=987, detour=None, addition=Flow(name='Flow', uuid='4e7d136c-a125-4c08-b660-247bea293d64')\n", + "1. Job(name='fibonacci', uuid='552ad89c-3e1f-4385-8eb5-01a761a6f9f1'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '552ad89c-3e1f-4385-8eb5-01a761a6f9f1': {1: Response(output=1597, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}\n" + ] + } + ], + "source": [ + "\"\"\"A dynamic workflow that calculates the Fibonacci sequence.\"\"\"\n", + "from jobflow import Response, job, run_locally\n", + "\n", + "\n", + "@job\n", + "def fibonacci(smaller, larger, stop_point=1000):\n", + " \"\"\"Calculate the next number in the Fibonacci sequence.\n", + "\n", + " If the number is larger than stop_point, the job will stop the workflow\n", + " execution, otherwise, a new job will be submitted to calculate the next number.\n", + " \"\"\"\n", + " total = smaller + larger\n", + "\n", + " if total > stop_point:\n", + " return total\n", + "\n", + " new_job = fibonacci(larger, total, stop_point=stop_point)\n", + " return Response(output=total, addition=new_job)\n", + "\n", + "\n", + "fibonacci_job = fibonacci(1, 1)\n", + "\n", + "# run the job; responses will contain the output from all jobs\n", + "responses = run_locally(fibonacci_job)\n", + "print(responses)\n" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.136876182Z", + "start_time": "2023-11-23T22:46:57.625858812Z" + } + } + }, { "cell_type": "markdown", "id": "5c0122e3", @@ -318,22 +459,27 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "id": "fee35a97", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.142624609Z", + "start_time": "2023-11-23T22:46:57.774129081Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "2023-06-08 09:55:10,850 INFO Started executing jobs locally\n", - "2023-06-08 09:55:10,853 INFO Starting job - add (d5020d71-4bbc-4307-8fa5-c65d0d9b9b9a)\n", - "2023-06-08 09:55:10,855 INFO Finished job - add (d5020d71-4bbc-4307-8fa5-c65d0d9b9b9a)\n", - "2023-06-08 09:55:10,856 INFO Starting job - add_with_logic (8786b3c4-5697-4ed8-9f46-fd0c89e4c374)\n", - "2023-06-08 09:55:10,858 INFO Finished job - add_with_logic (8786b3c4-5697-4ed8-9f46-fd0c89e4c374)\n", - "2023-06-08 09:55:10,859 INFO Starting job - add (c33d72c2-f396-4f2c-898e-c667c0913dcb)\n", - "2023-06-08 09:55:10,859 INFO Finished job - add (c33d72c2-f396-4f2c-898e-c667c0913dcb)\n", - "2023-06-08 09:55:10,860 INFO Finished executing jobs locally\n" + "2023-11-23 23:46:57,774 INFO Started executing jobs locally\n", + "2023-11-23 23:46:57,775 INFO Starting job - add (55465994-efcd-4835-b92e-f7ea36765268)\n", + "2023-11-23 23:46:57,778 INFO Finished job - add (55465994-efcd-4835-b92e-f7ea36765268)\n", + "2023-11-23 23:46:57,779 INFO Starting job - add_with_logic (d6cf8229-dbcc-422c-8504-177c433f48ac)\n", + "2023-11-23 23:46:57,786 INFO Finished job - add_with_logic (d6cf8229-dbcc-422c-8504-177c433f48ac)\n", + "2023-11-23 23:46:57,788 INFO Starting job - add (996e6af8-c56f-4779-8135-00493dbf9298)\n", + "2023-11-23 23:46:57,790 INFO Finished job - add (996e6af8-c56f-4779-8135-00493dbf9298)\n", + "2023-11-23 23:46:57,791 INFO Finished executing jobs locally\n" ] } ], @@ -356,19 +502,20 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "id": "b3b7e8ba", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-23T22:46:58.143531724Z", + "start_time": "2023-11-23T22:46:57.816557390Z" + } + }, "outputs": [ { "data": { - "text/plain": [ - "{'d5020d71-4bbc-4307-8fa5-c65d0d9b9b9a': {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", - " '8786b3c4-5697-4ed8-9f46-fd0c89e4c374': {1: Response(output=None, detour=, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", - " 'c33d72c2-f396-4f2c-898e-c667c0913dcb': {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}" - ] + "text/plain": "{'55465994-efcd-4835-b92e-f7ea36765268': {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n 'd6cf8229-dbcc-422c-8504-177c433f48ac': {1: Response(output=None, detour=Flow(name='Flow', uuid='98311314-8087-4787-b2ea-c89478ff2999')\n 1. Job(name='add', uuid='996e6af8-c56f-4779-8135-00493dbf9298'), addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n '996e6af8-c56f-4779-8135-00493dbf9298': {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}" }, - "execution_count": 9, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -388,9 +535,9 @@ ], "metadata": { "kernelspec": { - "display_name": "atomate2", + "name": "python3", "language": "python", - "name": "atomate2" + "display_name": "Python 3 (ipykernel)" }, "language_info": { "codemirror_mode": { From 03e7e2ee88990d8b18c97c541fd769018eef41b0 Mon Sep 17 00:00:00 2001 From: JaGeo Date: Thu, 23 Nov 2023 23:55:35 +0100 Subject: [PATCH 03/23] cleanup --- docs/tutorials/5-dynamic-flows.ipynb | 250 +++++++++++++-------------- 1 file changed, 117 insertions(+), 133 deletions(-) diff --git a/docs/tutorials/5-dynamic-flows.ipynb b/docs/tutorials/5-dynamic-flows.ipynb index 9673cd21..43844076 100644 --- a/docs/tutorials/5-dynamic-flows.ipynb +++ b/docs/tutorials/5-dynamic-flows.ipynb @@ -39,14 +39,14 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "78348798", "metadata": { "nbsphinx": "hidden", "tags": [], "ExecuteTime": { - "end_time": "2023-11-23T22:46:57.984085360Z", - "start_time": "2023-11-23T22:46:57.166923399Z" + "end_time": "2023-11-23T22:55:01.113171569Z", + "start_time": "2023-11-23T22:55:01.112486877Z" } }, "outputs": [], @@ -58,12 +58,12 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "964a8c44", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.036098609Z", - "start_time": "2023-11-23T22:46:57.208641695Z" + "end_time": "2023-11-23T22:55:03.025973341Z", + "start_time": "2023-11-23T22:55:01.974313960Z" } }, "outputs": [ @@ -71,20 +71,20 @@ "name": "stdout", "output_type": "stream", "text": [ - "2023-11-23 23:46:57,177 INFO Started executing jobs locally\n", - "2023-11-23 23:46:57,179 INFO Starting job - make_list (16fc2fd0-c9c7-420d-b0e1-3e6b5802c744)\n", - "2023-11-23 23:46:57,182 INFO Finished job - make_list (16fc2fd0-c9c7-420d-b0e1-3e6b5802c744)\n", - "2023-11-23 23:46:57,183 INFO Starting job - add_distributed (536e3c78-7d59-43ed-9f4f-72ce9b3793ef)\n", - "2023-11-23 23:46:57,191 INFO Finished job - add_distributed (536e3c78-7d59-43ed-9f4f-72ce9b3793ef)\n", - "2023-11-23 23:46:57,193 INFO Starting job - add (44007968-8394-442f-ba96-d52dc30a80ce)\n", - "2023-11-23 23:46:57,195 INFO Finished job - add (44007968-8394-442f-ba96-d52dc30a80ce)\n", - "2023-11-23 23:46:57,196 INFO Starting job - add (1af57ed7-3594-4180-b550-787c5f029d9f)\n", - "2023-11-23 23:46:57,198 INFO Finished job - add (1af57ed7-3594-4180-b550-787c5f029d9f)\n", - "2023-11-23 23:46:57,199 INFO Starting job - add (f7ea9158-40f8-4439-9d18-b6b6fb3e9289)\n", - "2023-11-23 23:46:57,201 INFO Finished job - add (f7ea9158-40f8-4439-9d18-b6b6fb3e9289)\n", - "2023-11-23 23:46:57,202 INFO Starting job - add (72c752d3-208a-45ce-bbb6-625e4debed73)\n", - "2023-11-23 23:46:57,204 INFO Finished job - add (72c752d3-208a-45ce-bbb6-625e4debed73)\n", - "2023-11-23 23:46:57,205 INFO Finished executing jobs locally\n" + "2023-11-23 23:55:02,807 INFO Started executing jobs locally\n", + "2023-11-23 23:55:02,937 INFO Starting job - make_list (d509897c-c318-4b2e-889e-a77331480a58)\n", + "2023-11-23 23:55:02,955 INFO Finished job - make_list (d509897c-c318-4b2e-889e-a77331480a58)\n", + "2023-11-23 23:55:02,956 INFO Starting job - add_distributed (7e07bfa4-a0cc-4535-b6c8-e3ec78fe96fb)\n", + "2023-11-23 23:55:02,963 INFO Finished job - add_distributed (7e07bfa4-a0cc-4535-b6c8-e3ec78fe96fb)\n", + "2023-11-23 23:55:03,005 INFO Starting job - add (62d7192e-d2af-4f28-a790-ac4987bd9f41)\n", + "2023-11-23 23:55:03,008 INFO Finished job - add (62d7192e-d2af-4f28-a790-ac4987bd9f41)\n", + "2023-11-23 23:55:03,009 INFO Starting job - add (d8a7d4aa-8255-417f-9cc8-bc9e16896d33)\n", + "2023-11-23 23:55:03,012 INFO Finished job - add (d8a7d4aa-8255-417f-9cc8-bc9e16896d33)\n", + "2023-11-23 23:55:03,012 INFO Starting job - add (15ce2067-8138-4692-baf8-8ceada256139)\n", + "2023-11-23 23:55:03,014 INFO Finished job - add (15ce2067-8138-4692-baf8-8ceada256139)\n", + "2023-11-23 23:55:03,015 INFO Starting job - add (43477f07-28fd-4944-9ae7-02f41282c8d3)\n", + "2023-11-23 23:55:03,017 INFO Finished job - add (43477f07-28fd-4944-9ae7-02f41282c8d3)\n", + "2023-11-23 23:55:03,018 INFO Finished executing jobs locally\n" ] }, { @@ -127,12 +127,12 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "82e368e6", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.037599975Z", - "start_time": "2023-11-23T22:46:57.233955503Z" + "end_time": "2023-11-23T22:55:03.075177954Z", + "start_time": "2023-11-23T22:55:03.026408190Z" } }, "outputs": [ @@ -140,16 +140,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "16fc2fd0-c9c7-420d-b0e1-3e6b5802c744 -> {1: Response(output=[2, 2, 2, 2], detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "536e3c78-7d59-43ed-9f4f-72ce9b3793ef -> {1: Response(output=None, detour=None, addition=None, replace=Flow(name='Flow', uuid='1d51c5df-174a-41c8-b017-98494c8411f1')\n", - "1. Job(name='add', uuid='44007968-8394-442f-ba96-d52dc30a80ce')\n", - "2. Job(name='add', uuid='1af57ed7-3594-4180-b550-787c5f029d9f')\n", - "3. Job(name='add', uuid='f7ea9158-40f8-4439-9d18-b6b6fb3e9289')\n", - "4. Job(name='add', uuid='72c752d3-208a-45ce-bbb6-625e4debed73'), stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "44007968-8394-442f-ba96-d52dc30a80ce -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "1af57ed7-3594-4180-b550-787c5f029d9f -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "f7ea9158-40f8-4439-9d18-b6b6fb3e9289 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "72c752d3-208a-45ce-bbb6-625e4debed73 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" + "d509897c-c318-4b2e-889e-a77331480a58 -> {1: Response(output=[2, 2, 2, 2], detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "7e07bfa4-a0cc-4535-b6c8-e3ec78fe96fb -> {1: Response(output=None, detour=None, addition=None, replace=Flow(name='Flow', uuid='ab9475e6-781b-4560-a0cc-4c260f80762a')\n", + "1. Job(name='add', uuid='62d7192e-d2af-4f28-a790-ac4987bd9f41')\n", + "2. Job(name='add', uuid='d8a7d4aa-8255-417f-9cc8-bc9e16896d33')\n", + "3. Job(name='add', uuid='15ce2067-8138-4692-baf8-8ceada256139')\n", + "4. Job(name='add', uuid='43477f07-28fd-4944-9ae7-02f41282c8d3'), stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "62d7192e-d2af-4f28-a790-ac4987bd9f41 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "d8a7d4aa-8255-417f-9cc8-bc9e16896d33 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "15ce2067-8138-4692-baf8-8ceada256139 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "43477f07-28fd-4944-9ae7-02f41282c8d3 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" ] } ], @@ -189,12 +189,12 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "id": "81870e55", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.041273240Z", - "start_time": "2023-11-23T22:46:57.406089273Z" + "end_time": "2023-11-23T22:55:06.857848628Z", + "start_time": "2023-11-23T22:55:06.789602522Z" } }, "outputs": [ @@ -202,14 +202,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "2023-11-23 23:46:57,406 INFO Started executing jobs locally\n", - "2023-11-23 23:46:57,408 INFO Starting job - add (34ba86a3-99cd-461e-bc17-511fdf6e08ec)\n", - "2023-11-23 23:46:57,411 INFO Finished job - add (34ba86a3-99cd-461e-bc17-511fdf6e08ec)\n", - "2023-11-23 23:46:57,412 INFO Starting job - add_with_logic (349afb69-d732-44b8-b770-2500f44511f9)\n", - "2023-11-23 23:46:57,421 INFO Finished job - add_with_logic (349afb69-d732-44b8-b770-2500f44511f9)\n", - "2023-11-23 23:46:57,422 INFO Starting job - add (64e623da-cf31-485e-9ed1-1f996a955868)\n", - "2023-11-23 23:46:57,424 INFO Finished job - add (64e623da-cf31-485e-9ed1-1f996a955868)\n", - "2023-11-23 23:46:57,425 INFO Finished executing jobs locally\n" + "2023-11-23 23:55:06,796 INFO Started executing jobs locally\n", + "2023-11-23 23:55:06,797 INFO Starting job - add (5630b6ba-1e9a-42ff-be51-ece43fe76643)\n", + "2023-11-23 23:55:06,800 INFO Finished job - add (5630b6ba-1e9a-42ff-be51-ece43fe76643)\n", + "2023-11-23 23:55:06,801 INFO Starting job - add_with_logic (008b1973-6421-418f-b47d-8f32054fedc8)\n", + "2023-11-23 23:55:06,807 INFO Finished job - add_with_logic (008b1973-6421-418f-b47d-8f32054fedc8)\n", + "2023-11-23 23:55:06,808 INFO Starting job - add (4e43d6b6-523a-4760-b1cf-3f68916e80fd)\n", + "2023-11-23 23:55:06,812 INFO Finished job - add (4e43d6b6-523a-4760-b1cf-3f68916e80fd)\n", + "2023-11-23 23:55:06,813 INFO Finished executing jobs locally\n" ] } ], @@ -232,12 +232,12 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "id": "fdc68eb5", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.046206634Z", - "start_time": "2023-11-23T22:46:57.448864584Z" + "end_time": "2023-11-23T22:55:07.823489602Z", + "start_time": "2023-11-23T22:55:07.816907763Z" } }, "outputs": [ @@ -245,10 +245,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "34ba86a3-99cd-461e-bc17-511fdf6e08ec -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "349afb69-d732-44b8-b770-2500f44511f9 -> {1: Response(output=None, detour=None, addition=Flow(name='Flow', uuid='20581dd8-b00e-424b-94ad-7f2b2f4a240b')\n", - "1. Job(name='add', uuid='64e623da-cf31-485e-9ed1-1f996a955868'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "64e623da-cf31-485e-9ed1-1f996a955868 -> {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" + "5630b6ba-1e9a-42ff-be51-ece43fe76643 -> {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "008b1973-6421-418f-b47d-8f32054fedc8 -> {1: Response(output=None, detour=None, addition=Flow(name='Flow', uuid='1994a56f-6dd8-4e35-a187-76d27d808d09')\n", + "1. Job(name='add', uuid='4e43d6b6-523a-4760-b1cf-3f68916e80fd'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "4e43d6b6-523a-4760-b1cf-3f68916e80fd -> {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" ] } ], @@ -267,12 +267,12 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "27569bd7", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.090608163Z", - "start_time": "2023-11-23T22:46:57.481314817Z" + "end_time": "2023-11-23T22:55:09.827238198Z", + "start_time": "2023-11-23T22:55:09.755367636Z" } }, "outputs": [ @@ -280,12 +280,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "2023-11-23 23:46:57,479 INFO Started executing jobs locally\n", - "2023-11-23 23:46:57,481 INFO Starting job - add (0ae20220-b69c-4e6b-827a-2f046b00d504)\n", - "2023-11-23 23:46:57,484 INFO Finished job - add (0ae20220-b69c-4e6b-827a-2f046b00d504)\n", - "2023-11-23 23:46:57,485 INFO Starting job - add_with_logic (145dea09-be6c-47fc-ac46-c9a6908323e7)\n", - "2023-11-23 23:46:57,490 INFO Finished job - add_with_logic (145dea09-be6c-47fc-ac46-c9a6908323e7)\n", - "2023-11-23 23:46:57,491 INFO Finished executing jobs locally\n" + "2023-11-23 23:55:09,755 INFO Started executing jobs locally\n", + "2023-11-23 23:55:09,756 INFO Starting job - add (92e3f817-1350-4492-aeee-ec3501bce66f)\n", + "2023-11-23 23:55:09,759 INFO Finished job - add (92e3f817-1350-4492-aeee-ec3501bce66f)\n", + "2023-11-23 23:55:09,759 INFO Starting job - add_with_logic (e20fe185-4e34-4422-914f-e0acb4cbd529)\n", + "2023-11-23 23:55:09,764 INFO Finished job - add_with_logic (e20fe185-4e34-4422-914f-e0acb4cbd529)\n", + "2023-11-23 23:55:09,765 INFO Finished executing jobs locally\n" ] } ], @@ -308,12 +308,12 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "id": "b8d0c011", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.092445839Z", - "start_time": "2023-11-23T22:46:57.524568954Z" + "end_time": "2023-11-23T22:55:10.647133331Z", + "start_time": "2023-11-23T22:55:10.639661076Z" } }, "outputs": [ @@ -321,8 +321,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "0ae20220-b69c-4e6b-827a-2f046b00d504 -> {1: Response(output=21, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", - "145dea09-be6c-47fc-ac46-c9a6908323e7 -> {1: Response(output=None, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" + "92e3f817-1350-4492-aeee-ec3501bce66f -> {1: Response(output=21, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n", + "e20fe185-4e34-4422-914f-e0acb4cbd529 -> {1: Response(output=None, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}\n" ] } ], @@ -350,59 +350,44 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "2023-11-23 23:46:57,625 INFO Started executing jobs locally\n", - "2023-11-23 23:46:57,626 INFO Starting job - fibonacci (81d7944a-bd5a-4edd-a67f-36d2312e506b)\n", - "2023-11-23 23:46:57,630 INFO Finished job - fibonacci (81d7944a-bd5a-4edd-a67f-36d2312e506b)\n", - "2023-11-23 23:46:57,631 INFO Starting job - fibonacci (3219e168-b719-409a-8dbd-94370c03e162)\n", - "2023-11-23 23:46:57,634 INFO Finished job - fibonacci (3219e168-b719-409a-8dbd-94370c03e162)\n", - "2023-11-23 23:46:57,636 INFO Starting job - fibonacci (98308b42-817b-4ee5-bf68-fefcf1bd0de3)\n", - "2023-11-23 23:46:57,639 INFO Finished job - fibonacci (98308b42-817b-4ee5-bf68-fefcf1bd0de3)\n", - "2023-11-23 23:46:57,640 INFO Starting job - fibonacci (57c73c23-9fbf-4f08-8e0f-7698027b632b)\n", - "2023-11-23 23:46:57,643 INFO Finished job - fibonacci (57c73c23-9fbf-4f08-8e0f-7698027b632b)\n", - "2023-11-23 23:46:57,644 INFO Starting job - fibonacci (33c81f02-e87b-4848-8780-a09de20041b1)\n", - "2023-11-23 23:46:57,647 INFO Finished job - fibonacci (33c81f02-e87b-4848-8780-a09de20041b1)\n", - "2023-11-23 23:46:57,648 INFO Starting job - fibonacci (690e4d45-9e9b-43d8-8865-2085cc0feee2)\n", - "2023-11-23 23:46:57,650 INFO Finished job - fibonacci (690e4d45-9e9b-43d8-8865-2085cc0feee2)\n", - "2023-11-23 23:46:57,651 INFO Starting job - fibonacci (8142cc72-a4e3-4884-a446-98f0bea98569)\n", - "2023-11-23 23:46:57,655 INFO Finished job - fibonacci (8142cc72-a4e3-4884-a446-98f0bea98569)\n", - "2023-11-23 23:46:57,656 INFO Starting job - fibonacci (c2b4ec59-5088-4daf-9dba-34a2a3fbe56e)\n", - "2023-11-23 23:46:57,659 INFO Finished job - fibonacci (c2b4ec59-5088-4daf-9dba-34a2a3fbe56e)\n", - "2023-11-23 23:46:57,660 INFO Starting job - fibonacci (2db909a8-14df-4bd1-89a8-d188948382f1)\n", - "2023-11-23 23:46:57,663 INFO Finished job - fibonacci (2db909a8-14df-4bd1-89a8-d188948382f1)\n", - "2023-11-23 23:46:57,664 INFO Starting job - fibonacci (273a46cc-4762-495e-a1d7-e4e26203f122)\n", - "2023-11-23 23:46:57,666 INFO Finished job - fibonacci (273a46cc-4762-495e-a1d7-e4e26203f122)\n", - "2023-11-23 23:46:57,667 INFO Starting job - fibonacci (3fe6a08d-74f9-406f-a219-fdd68f1f6ec9)\n", - "2023-11-23 23:46:57,670 INFO Finished job - fibonacci (3fe6a08d-74f9-406f-a219-fdd68f1f6ec9)\n", - "2023-11-23 23:46:57,671 INFO Starting job - fibonacci (5c44497a-4497-4bf2-a0ee-172abf1251eb)\n", - "2023-11-23 23:46:57,674 INFO Finished job - fibonacci (5c44497a-4497-4bf2-a0ee-172abf1251eb)\n", - "2023-11-23 23:46:57,675 INFO Starting job - fibonacci (1b21a0be-8b79-42ad-a13b-c43c7077d637)\n", - "2023-11-23 23:46:57,678 INFO Finished job - fibonacci (1b21a0be-8b79-42ad-a13b-c43c7077d637)\n", - "2023-11-23 23:46:57,679 INFO Starting job - fibonacci (a6af5fcc-2a3b-4a40-8620-28edadb64b9f)\n", - "2023-11-23 23:46:57,682 INFO Finished job - fibonacci (a6af5fcc-2a3b-4a40-8620-28edadb64b9f)\n", - "2023-11-23 23:46:57,683 INFO Starting job - fibonacci (552ad89c-3e1f-4385-8eb5-01a761a6f9f1)\n", - "2023-11-23 23:46:57,686 INFO Finished job - fibonacci (552ad89c-3e1f-4385-8eb5-01a761a6f9f1)\n", - "2023-11-23 23:46:57,687 INFO Finished executing jobs locally\n", - "{'81d7944a-bd5a-4edd-a67f-36d2312e506b': {1: Response(output=2, detour=None, addition=Flow(name='Flow', uuid='b497505f-e73a-4324-99b4-2923d76bed6e')\n", - "1. Job(name='fibonacci', uuid='3219e168-b719-409a-8dbd-94370c03e162'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '3219e168-b719-409a-8dbd-94370c03e162': {1: Response(output=3, detour=None, addition=Flow(name='Flow', uuid='985aad5f-060f-4841-a2d0-edcdb4a4526d')\n", - "1. Job(name='fibonacci', uuid='98308b42-817b-4ee5-bf68-fefcf1bd0de3'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '98308b42-817b-4ee5-bf68-fefcf1bd0de3': {1: Response(output=5, detour=None, addition=Flow(name='Flow', uuid='076cc046-7ffe-40fe-a14d-5c97d9e92b40')\n", - "1. Job(name='fibonacci', uuid='57c73c23-9fbf-4f08-8e0f-7698027b632b'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '57c73c23-9fbf-4f08-8e0f-7698027b632b': {1: Response(output=8, detour=None, addition=Flow(name='Flow', uuid='38b57dd4-ddb1-425c-8153-5e2c195942da')\n", - "1. Job(name='fibonacci', uuid='33c81f02-e87b-4848-8780-a09de20041b1'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '33c81f02-e87b-4848-8780-a09de20041b1': {1: Response(output=13, detour=None, addition=Flow(name='Flow', uuid='057e0e16-62d3-461e-a13b-9d86c5f72780')\n", - "1. Job(name='fibonacci', uuid='690e4d45-9e9b-43d8-8865-2085cc0feee2'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '690e4d45-9e9b-43d8-8865-2085cc0feee2': {1: Response(output=21, detour=None, addition=Flow(name='Flow', uuid='a2f5bb27-5539-48be-a706-04af3756eedf')\n", - "1. Job(name='fibonacci', uuid='8142cc72-a4e3-4884-a446-98f0bea98569'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '8142cc72-a4e3-4884-a446-98f0bea98569': {1: Response(output=34, detour=None, addition=Flow(name='Flow', uuid='c0b854aa-aae5-4277-b7e1-45416e65384e')\n", - "1. Job(name='fibonacci', uuid='c2b4ec59-5088-4daf-9dba-34a2a3fbe56e'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, 'c2b4ec59-5088-4daf-9dba-34a2a3fbe56e': {1: Response(output=55, detour=None, addition=Flow(name='Flow', uuid='f31f638f-4147-4677-b8f5-72e44d9b12f9')\n", - "1. Job(name='fibonacci', uuid='2db909a8-14df-4bd1-89a8-d188948382f1'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '2db909a8-14df-4bd1-89a8-d188948382f1': {1: Response(output=89, detour=None, addition=Flow(name='Flow', uuid='5f5383a3-7b2d-4e86-98ca-66636006e6a3')\n", - "1. Job(name='fibonacci', uuid='273a46cc-4762-495e-a1d7-e4e26203f122'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '273a46cc-4762-495e-a1d7-e4e26203f122': {1: Response(output=144, detour=None, addition=Flow(name='Flow', uuid='4711a431-8976-4e7c-be1c-cb4962aab4a7')\n", - "1. Job(name='fibonacci', uuid='3fe6a08d-74f9-406f-a219-fdd68f1f6ec9'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '3fe6a08d-74f9-406f-a219-fdd68f1f6ec9': {1: Response(output=233, detour=None, addition=Flow(name='Flow', uuid='0dc7cb69-5797-4880-a8b7-c54f99490322')\n", - "1. Job(name='fibonacci', uuid='5c44497a-4497-4bf2-a0ee-172abf1251eb'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '5c44497a-4497-4bf2-a0ee-172abf1251eb': {1: Response(output=377, detour=None, addition=Flow(name='Flow', uuid='2469da06-bb02-4597-925c-df154d34115d')\n", - "1. Job(name='fibonacci', uuid='1b21a0be-8b79-42ad-a13b-c43c7077d637'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '1b21a0be-8b79-42ad-a13b-c43c7077d637': {1: Response(output=610, detour=None, addition=Flow(name='Flow', uuid='c92c422d-372c-45bd-9159-1ef9243c8f7f')\n", - "1. Job(name='fibonacci', uuid='a6af5fcc-2a3b-4a40-8620-28edadb64b9f'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, 'a6af5fcc-2a3b-4a40-8620-28edadb64b9f': {1: Response(output=987, detour=None, addition=Flow(name='Flow', uuid='4e7d136c-a125-4c08-b660-247bea293d64')\n", - "1. Job(name='fibonacci', uuid='552ad89c-3e1f-4385-8eb5-01a761a6f9f1'), replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}, '552ad89c-3e1f-4385-8eb5-01a761a6f9f1': {1: Response(output=1597, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}\n" + "2023-11-23 23:55:13,324 INFO Started executing jobs locally\n", + "2023-11-23 23:55:13,325 INFO Starting job - fibonacci (6f7a1e92-577f-4289-85e5-e07a82e542db)\n", + "2023-11-23 23:55:13,329 INFO Finished job - fibonacci (6f7a1e92-577f-4289-85e5-e07a82e542db)\n", + "2023-11-23 23:55:13,329 INFO Starting job - fibonacci (862ce31a-a963-419a-9862-f419c47c3c9e)\n", + "2023-11-23 23:55:13,332 INFO Finished job - fibonacci (862ce31a-a963-419a-9862-f419c47c3c9e)\n", + "2023-11-23 23:55:13,333 INFO Starting job - fibonacci (81c28a0a-f1ad-487c-b484-46729f6ca9a6)\n", + "2023-11-23 23:55:13,335 INFO Finished job - fibonacci (81c28a0a-f1ad-487c-b484-46729f6ca9a6)\n", + "2023-11-23 23:55:13,336 INFO Starting job - fibonacci (084e2022-5a00-4ca8-9edf-46977ca08388)\n", + "2023-11-23 23:55:13,338 INFO Finished job - fibonacci (084e2022-5a00-4ca8-9edf-46977ca08388)\n", + "2023-11-23 23:55:13,339 INFO Starting job - fibonacci (382f371c-9e92-4185-8dbb-829801ec1afd)\n", + "2023-11-23 23:55:13,342 INFO Finished job - fibonacci (382f371c-9e92-4185-8dbb-829801ec1afd)\n", + "2023-11-23 23:55:13,342 INFO Starting job - fibonacci (f4521225-993a-4b42-9818-8aaff0da9181)\n", + "2023-11-23 23:55:13,345 INFO Finished job - fibonacci (f4521225-993a-4b42-9818-8aaff0da9181)\n", + "2023-11-23 23:55:13,346 INFO Starting job - fibonacci (3d475e3e-3774-4015-b056-a23f5cf1da6a)\n", + "2023-11-23 23:55:13,349 INFO Finished job - fibonacci (3d475e3e-3774-4015-b056-a23f5cf1da6a)\n", + "2023-11-23 23:55:13,351 INFO Starting job - fibonacci (ddc61891-1ce1-4d96-b66e-cb60d52e642a)\n", + "2023-11-23 23:55:13,353 INFO Finished job - fibonacci (ddc61891-1ce1-4d96-b66e-cb60d52e642a)\n", + "2023-11-23 23:55:13,354 INFO Starting job - fibonacci (499ab638-d8cc-4272-b2b4-f64d246f3676)\n", + "2023-11-23 23:55:13,357 INFO Finished job - fibonacci (499ab638-d8cc-4272-b2b4-f64d246f3676)\n", + "2023-11-23 23:55:13,357 INFO Starting job - fibonacci (71b7d00f-0109-4a23-8a54-fb29ef143cd2)\n", + "2023-11-23 23:55:13,360 INFO Finished job - fibonacci (71b7d00f-0109-4a23-8a54-fb29ef143cd2)\n", + "2023-11-23 23:55:13,361 INFO Starting job - fibonacci (d60f3f5d-821a-434a-a8c1-50468b381d5f)\n", + "2023-11-23 23:55:13,363 INFO Finished job - fibonacci (d60f3f5d-821a-434a-a8c1-50468b381d5f)\n", + "2023-11-23 23:55:13,364 INFO Starting job - fibonacci (7828008e-2f89-4226-aaac-66f25d4ccf0a)\n", + "2023-11-23 23:55:13,367 INFO Finished job - fibonacci (7828008e-2f89-4226-aaac-66f25d4ccf0a)\n", + "2023-11-23 23:55:13,367 INFO Starting job - fibonacci (062b0cad-2b62-4f42-bd39-ac1b3c90d141)\n", + "2023-11-23 23:55:13,370 INFO Finished job - fibonacci (062b0cad-2b62-4f42-bd39-ac1b3c90d141)\n", + "2023-11-23 23:55:13,371 INFO Starting job - fibonacci (6c1bf8e4-1808-42b4-a99e-49dd031894bd)\n", + "2023-11-23 23:55:13,373 INFO Finished job - fibonacci (6c1bf8e4-1808-42b4-a99e-49dd031894bd)\n", + "2023-11-23 23:55:13,374 INFO Starting job - fibonacci (d82e352d-1ca3-40d2-85d1-3f08989d3551)\n", + "2023-11-23 23:55:13,376 INFO Finished job - fibonacci (d82e352d-1ca3-40d2-85d1-3f08989d3551)\n", + "2023-11-23 23:55:13,377 INFO Finished executing jobs locally\n" ] } ], @@ -430,14 +415,13 @@ "fibonacci_job = fibonacci(1, 1)\n", "\n", "# run the job; responses will contain the output from all jobs\n", - "responses = run_locally(fibonacci_job)\n", - "print(responses)\n" + "responses = run_locally(fibonacci_job)\n" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.136876182Z", - "start_time": "2023-11-23T22:46:57.625858812Z" + "end_time": "2023-11-23T22:55:13.426518952Z", + "start_time": "2023-11-23T22:55:13.322421257Z" } } }, @@ -459,12 +443,12 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "id": "fee35a97", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.142624609Z", - "start_time": "2023-11-23T22:46:57.774129081Z" + "end_time": "2023-11-23T22:55:16.347154656Z", + "start_time": "2023-11-23T22:55:16.266053982Z" } }, "outputs": [ @@ -472,14 +456,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "2023-11-23 23:46:57,774 INFO Started executing jobs locally\n", - "2023-11-23 23:46:57,775 INFO Starting job - add (55465994-efcd-4835-b92e-f7ea36765268)\n", - "2023-11-23 23:46:57,778 INFO Finished job - add (55465994-efcd-4835-b92e-f7ea36765268)\n", - "2023-11-23 23:46:57,779 INFO Starting job - add_with_logic (d6cf8229-dbcc-422c-8504-177c433f48ac)\n", - "2023-11-23 23:46:57,786 INFO Finished job - add_with_logic (d6cf8229-dbcc-422c-8504-177c433f48ac)\n", - "2023-11-23 23:46:57,788 INFO Starting job - add (996e6af8-c56f-4779-8135-00493dbf9298)\n", - "2023-11-23 23:46:57,790 INFO Finished job - add (996e6af8-c56f-4779-8135-00493dbf9298)\n", - "2023-11-23 23:46:57,791 INFO Finished executing jobs locally\n" + "2023-11-23 23:55:16,275 INFO Started executing jobs locally\n", + "2023-11-23 23:55:16,278 INFO Starting job - add (301d75f0-7042-494a-9f24-cab0428c2fd1)\n", + "2023-11-23 23:55:16,281 INFO Finished job - add (301d75f0-7042-494a-9f24-cab0428c2fd1)\n", + "2023-11-23 23:55:16,282 INFO Starting job - add_with_logic (97be61a8-eec4-4e64-bf53-ba37621575e7)\n", + "2023-11-23 23:55:16,292 INFO Finished job - add_with_logic (97be61a8-eec4-4e64-bf53-ba37621575e7)\n", + "2023-11-23 23:55:16,293 INFO Starting job - add (d4c31f68-09ad-418a-ac52-89b303fc2a00)\n", + "2023-11-23 23:55:16,296 INFO Finished job - add (d4c31f68-09ad-418a-ac52-89b303fc2a00)\n", + "2023-11-23 23:55:16,296 INFO Finished executing jobs locally\n" ] } ], @@ -502,20 +486,20 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "id": "b3b7e8ba", "metadata": { "ExecuteTime": { - "end_time": "2023-11-23T22:46:58.143531724Z", - "start_time": "2023-11-23T22:46:57.816557390Z" + "end_time": "2023-11-23T22:55:17.024836601Z", + "start_time": "2023-11-23T22:55:17.019427206Z" } }, "outputs": [ { "data": { - "text/plain": "{'55465994-efcd-4835-b92e-f7ea36765268': {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n 'd6cf8229-dbcc-422c-8504-177c433f48ac': {1: Response(output=None, detour=Flow(name='Flow', uuid='98311314-8087-4787-b2ea-c89478ff2999')\n 1. Job(name='add', uuid='996e6af8-c56f-4779-8135-00493dbf9298'), addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n '996e6af8-c56f-4779-8135-00493dbf9298': {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}" + "text/plain": "{'301d75f0-7042-494a-9f24-cab0428c2fd1': {1: Response(output=3, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n '97be61a8-eec4-4e64-bf53-ba37621575e7': {1: Response(output=None, detour=Flow(name='Flow', uuid='0de995a5-1110-4200-b010-276cb2017474')\n 1. Job(name='add', uuid='d4c31f68-09ad-418a-ac52-89b303fc2a00'), addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n 'd4c31f68-09ad-418a-ac52-89b303fc2a00': {1: Response(output=5, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}" }, - "execution_count": 11, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } From 003ec3a0b2c0550c63f8fd5bc91a4e5c6ae191ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 23:47:29 +0000 Subject: [PATCH 04/23] Bump moto from 4.2.10 to 4.2.11 (#500) Bumps [moto](https://github.com/getmoto/moto) from 4.2.10 to 4.2.11. - [Release notes](https://github.com/getmoto/moto/releases) - [Changelog](https://github.com/getmoto/moto/blob/master/CHANGELOG.md) - [Commits](https://github.com/getmoto/moto/compare/4.2.10...4.2.11) --- updated-dependencies: - dependency-name: moto dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7ca63aaa..3ac99790 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ docs = [ "sphinx==7.2.6", ] dev = ["pre-commit>=2.12.1"] -tests = ["moto==4.2.10", "pytest-cov==4.1.0", "pytest==7.4.3"] +tests = ["moto==4.2.11", "pytest-cov==4.1.0", "pytest==7.4.3"] vis = ["matplotlib", "pydot"] fireworks = ["FireWorks"] strict = [ @@ -55,7 +55,7 @@ strict = [ "maggma==0.58.0", "matplotlib==3.8.2", "monty==2023.11.3", - "moto==4.2.10", + "moto==4.2.11", "networkx==3.2.1", "pydantic-settings==2.1.0", "pydantic==2.5.2", From e1f4aab6390ab30c7f1ebc34ee051e457854ff87 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Tue, 5 Dec 2023 09:49:01 +0000 Subject: [PATCH 05/23] Update release.yml --- .github/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/release.yml b/.github/release.yml index 4d38a629..b56e0d10 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -14,6 +14,9 @@ changelog: - title: Documentation 📖 labels: - documentation + - title: House-Keeping 🧹 + labels: + - house-keeping - title: Other Changes labels: - "*" From 8ffcf525688f261bd12bd4ffff129bf0fc0a9101 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Tue, 5 Dec 2023 09:56:40 +0000 Subject: [PATCH 06/23] Update changelog --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad97b09..171488b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # Change log +## v0.1.15 + +### Bug Fixes 🐛 +* Fix JobStoreDocument validator by @utf in https://github.com/materialsproject/jobflow/pull/478 +* fix Flow deserialization for hosts by @gpetretto in https://github.com/materialsproject/jobflow/pull/499 +### Enhancements 🛠 +* Formalizing the JobStore document format as a pydantic model by @hrushikesh-s in https://github.com/materialsproject/jobflow/pull/424 +* Simplify code by using `Flow` methods `__len__` and `__getitem__` by @janosh in https://github.com/materialsproject/jobflow/pull/467 +* `run_locally()` add `root_dir: str | Path | None` keyword by @janosh in https://github.com/materialsproject/jobflow/pull/486 +* Allow SSHTunnel in job stores by @mjwen in https://github.com/materialsproject/jobflow/pull/477 +### Documentation 📖 +* JOSS paper by @utf in https://github.com/materialsproject/jobflow/pull/446 +* JOSS Paper: Add missing DOIs by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/452 +* JOSS Paper: Reduce line-spacing in code blocks by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/454 +* JOSS Paper update: Add missing year to `refs.bib` by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/458 +* JOSS Paper: Remove stray tick mark in "[@montydb]`" by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/459 +* JOSS Paper: Add another missing year to `refs.bib` by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/461 +* Update refs.bib by @xuanxu in https://github.com/materialsproject/jobflow/pull/462 +* JOSS: Add missing `,` to paper by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/479 +* JOSS: Add more complete Zenodo reference info by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/481 +* JOSS: Fix references to include all coauthors and remove "others" by @Andrew-S-Rosen in https://github.com/materialsproject/jobflow/pull/480 +* Add fibonacci example to tutorial by @JaGeo in https://github.com/materialsproject/jobflow/pull/494 +### House-Keeping 🧹 +* Remove `__all__` from all modules by @janosh in https://github.com/materialsproject/jobflow/pull/442 +* Bump minimum Python version to 3.9 by @janosh in https://github.com/materialsproject/jobflow/pull/455 +* Replace deprecated `pkg_resources` with `importlib.metadata.version` by @janosh in https://github.com/materialsproject/jobflow/pull/460 +* Match `atomate2` `ruff` config by @janosh in https://github.com/materialsproject/jobflow/pull/464 +* Test error messages by @janosh in https://github.com/materialsproject/jobflow/pull/465 + +## New Contributors +* @hrushikesh-s made their first contribution in https://github.com/materialsproject/jobflow/pull/424 +* @xuanxu made their first contribution in https://github.com/materialsproject/jobflow/pull/462 + +**Full Changelog**: https://github.com/materialsproject/jobflow/compare/v0.1.14...v0.1.15 + ## v0.1.14 ### Bug Fixes 🐛 From d80f17d96f2302609913f55763052efa55e0fb59 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Fri, 8 Dec 2023 09:41:20 -0800 Subject: [PATCH 07/23] unpin and update pre-commit hooks --- .pre-commit-config.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 00ba6cdf..6f141f9d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ default_language_version: exclude: "^src/atomate2/vasp/schemas/calc_types/" repos: - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.1.3 + rev: v0.1.7 hooks: - id: ruff args: [--fix] @@ -23,18 +23,18 @@ repos: additional_dependencies: [black] exclude: ^(README.md|paper/paper.md)$ - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 entry: pflake8 files: ^src/ additional_dependencies: - - pyproject-flake8==6.0.0 - - flake8-bugbear==22.12.6 - - flake8-typing-imports==1.14.0 - - flake8-docstrings==1.6.0 - - flake8-rst-docstrings==0.3.0 - - flake8-rst==0.8.0 + - pyproject-flake8 + - flake8-bugbear + - flake8-typing-imports + - flake8-docstrings + - flake8-rst-docstrings + - flake8-rst - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.10.0 hooks: @@ -43,7 +43,7 @@ repos: - id: rst-directive-colons - id: rst-inline-touching-normal - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.1 + rev: v1.7.1 hooks: - id: mypy files: ^src/ From 3f607e199e03349c2ea51a5cbb48a32e6a5eadf6 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Fri, 8 Dec 2023 09:41:30 -0800 Subject: [PATCH 08/23] add explicit stacklevel to warnings (fixes flake8 B028) --- src/jobflow/core/flow.py | 3 ++- src/jobflow/core/job.py | 3 ++- src/jobflow/core/store.py | 4 ++-- src/jobflow/managers/local.py | 2 +- src/jobflow/settings.py | 3 ++- src/jobflow/utils/enum.py | 2 +- src/jobflow/utils/graph.py | 4 +++- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/jobflow/core/flow.py b/src/jobflow/core/flow.py index 7f9e911a..9ac5ba8a 100644 --- a/src/jobflow/core/flow.py +++ b/src/jobflow/core/flow.py @@ -274,7 +274,8 @@ def output(self, output: Any): f"Flow '{self.name}' contains a Flow or Job as an output. " f"Usually the Flow output should be the output of a Job or " f"another Flow (e.g. job.output). If this message is " - f"unexpected then double check the outputs of your Flow." + f"unexpected then double check the outputs of your Flow.", + stacklevel=2, ) # check if the jobs array contains all jobs needed for the references diff --git a/src/jobflow/core/job.py b/src/jobflow/core/job.py index f11e1917..3f2f64e6 100644 --- a/src/jobflow/core/job.py +++ b/src/jobflow/core/job.py @@ -359,7 +359,8 @@ def __init__( f"Job '{self.name}' contains an Flow or Job as an input. " f"Usually inputs should be the output of a Job or an Flow (e.g. " f"job.output). If this message is unexpected then double check the " - f"inputs to your Job." + f"inputs to your Job.", + stacklevel=2, ) def __repr__(self): diff --git a/src/jobflow/core/store.py b/src/jobflow/core/store.py index ebbc3de0..e5707169 100644 --- a/src/jobflow/core/store.py +++ b/src/jobflow/core/store.py @@ -282,7 +282,7 @@ def update( from jobflow.utils.find import find_key, update_in_dictionary - if save is None or save is True: + if save in (None, True): save = self.save save_keys = _prepare_save(save) @@ -766,7 +766,7 @@ def _group_blobs(infos, locs): new_locations = [] for store_load in load.values(): for blob, location in zip(blob_infos, locations): - if store_load is True: + if store_load: new_blobs.append(blob) new_locations.append(location) elif isinstance(store_load, bool): diff --git a/src/jobflow/managers/local.py b/src/jobflow/managers/local.py index 5c1fb9fb..1b09b186 100644 --- a/src/jobflow/managers/local.py +++ b/src/jobflow/managers/local.py @@ -156,7 +156,7 @@ def _run(root_flow): response, jobflow_stopped = _run_job(job, parents) encountered_bad_response = encountered_bad_response or response is None - if jobflow_stopped is True: + if jobflow_stopped: return False return not encountered_bad_response diff --git a/src/jobflow/settings.py b/src/jobflow/settings.py index d2a7e890..8cb09153 100644 --- a/src/jobflow/settings.py +++ b/src/jobflow/settings.py @@ -137,7 +137,8 @@ def load_default_settings(cls, values): if Path(config_file_path).exists(): if Path(config_file_path).stat().st_size == 0: warnings.warn( - f"An empty JobFlow config file was located at {config_file_path}" + f"An empty JobFlow config file was located at {config_file_path}", + stacklevel=2, ) else: try: diff --git a/src/jobflow/utils/enum.py b/src/jobflow/utils/enum.py index 8e7e6c21..efdd7639 100644 --- a/src/jobflow/utils/enum.py +++ b/src/jobflow/utils/enum.py @@ -12,7 +12,7 @@ def __str__(self): def __eq__(self, other): """Compare to another enum for equality.""" - if type(self) == type(other) and self.value == other.value: + if type(self) is type(other) and self.value == other.value: return True return str(self.value) == str(other) diff --git a/src/jobflow/utils/graph.py b/src/jobflow/utils/graph.py index b253c950..b289e625 100644 --- a/src/jobflow/utils/graph.py +++ b/src/jobflow/utils/graph.py @@ -46,7 +46,9 @@ def itergraph(graph: nx.DiGraph): subgraphs = [graph.subgraph(c) for c in nx.weakly_connected_components(graph)] if len(subgraphs) > 1: - warnings.warn("Some jobs are not connected, their ordering may be random") + warnings.warn( + "Some jobs are not connected, their ordering may be random", stacklevel=2 + ) for subgraph in subgraphs: yield from nx.topological_sort(subgraph) From d3c690da0d711cc213f943994faee18a4e93227c Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Fri, 8 Dec 2023 09:43:57 -0800 Subject: [PATCH 09/23] fix dead dynamic wf doc link reported in https://github.com/openjournals/joss-reviews/issues/5995#issuecomment-1847542926 --- docs/tutorials/3-defining-jobs.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/3-defining-jobs.ipynb b/docs/tutorials/3-defining-jobs.ipynb index d36731cb..1e4ddef5 100644 --- a/docs/tutorials/3-defining-jobs.ipynb +++ b/docs/tutorials/3-defining-jobs.ipynb @@ -103,7 +103,7 @@ "id": "fatal-bible", "metadata": {}, "source": [ - "Jobs also have an index. This tracks the number of times the job has been \"replaced\" (replacing is covered in detail in the [Dynamic and nested Flows tutorial](dynamic-flows)).\n" + "Jobs also have an index. This tracks the number of times the job has been \"replaced\" (replacing is covered in detail in the [Dynamic and nested Flows tutorial](5-dynamic-flows.html)).\n" ] }, { @@ -233,7 +233,7 @@ "source": [ "from jobflow.managers.local import run_locally\n", "\n", - "response = run_locally(add(1,2))" + "response = run_locally(add(1, 2))" ] }, { From f00a5cceed44c254b78bd1891a18397fb864d47a Mon Sep 17 00:00:00 2001 From: Matthew Evans <7916000+ml-evs@users.noreply.github.com> Date: Fri, 8 Dec 2023 18:30:24 +0000 Subject: [PATCH 10/23] Fix tutorial links --- docs/tutorials.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 0ba33463..ef546080 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -14,4 +14,4 @@ Tutorials tutorials/8-fireworks .. Note:: - [@jageo](https://github.com/JaGeo) also has a set of [Jobflow tutorials](https://jageo.github.io/Advanced_Jobflow_Tutorial/intro.html) written within the context of computational materials science applications, which you may wish to check out after exploring the basics here. + `@jageo `_ also has a set of `Jobflow tutorials `_ written within the context of computational materials science applications, which you may wish to check out after exploring the basics here. From 0e820fd122b97523674bb2d92f5a5ba9ec06d4d5 Mon Sep 17 00:00:00 2001 From: Max Gallant Date: Fri, 8 Dec 2023 11:10:46 -0800 Subject: [PATCH 11/23] Fix tutorial bug --- docs/tutorials/2-introduction.ipynb | 54 ++++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/docs/tutorials/2-introduction.ipynb b/docs/tutorials/2-introduction.ipynb index d2a95426..01d9af8e 100644 --- a/docs/tutorials/2-introduction.ipynb +++ b/docs/tutorials/2-introduction.ipynb @@ -103,7 +103,7 @@ { "data": { "text/plain": [ - "OutputReference(76f9fef1-e2c7-4ad7-b090-b9153866c582)" + "OutputReference(aa2a6b1a-4846-4154-94b9-4296b2a64e5d)" ] }, "execution_count": 4, @@ -153,18 +153,24 @@ "source": [ "## Creating Flows\n", "\n", - "A `Flow` is a collection of `Job`s or other `Flow` objects. Flows are the primary tool for defining workflows in jobflow. Let's create a Flow from the jobs we just made:\n" + "A `Flow` is a collection of `Job`s or other `Flow` objects. Flows are the primary tool for defining workflows in jobflow. Let's create a Flow from the jobs we just made. We will repeat the lines we used to create them here for clarity.\n" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 15, "id": "danish-indonesia", "metadata": {}, "outputs": [], "source": [ "from jobflow import Flow\n", "\n", + "time_github = time_website(\"https://www.github.com\")\n", + "time_google = time_website(\"https://www.google.com\")\n", + "time_nyt = time_website(\"https://www.nytimes.com\")\n", + "\n", + "sum_times = sum_numbers([time_github.output, time_google.output, time_nyt.output])\n", + "\n", "flow = Flow([time_github, time_google, time_nyt, sum_times])" ] }, @@ -186,9 +192,9 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAqsAAAHBCAYAAABOnPJQAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAA9IklEQVR4nO3deZydZX3+8c81mYQkhEUFVHCJG1VEa2VzxVK1ra3VnwVEpAgqKK7Voihq3VfqVhVF2VH2RFFc6lJRkT0RxAJqVdAiLoBECFkn8/39cQ4YWSfJzNxn+bxfL14nmTnznGsmz9zPxX3u53lSVUiSJEm9aKR1AEmSJOnOWFYlSZLUsyyrkiRJ6lmWVUmSJPUsy6okSZJ6lmVVkiRJPcuyKkmSpJ5lWZUkSVLPsqxKkiSpZ1lWJUmS1LMsq5IkSepZllVJkiT1LMuqJEmSepZlVZIkST3LsipJkqSeZVmVJElSz7KsSpIkqWdZViVJktSzLKuSJEnqWZZVSZIk9SzLqiRJknqWZVWSJEk9y7IqSZKknmVZlSRJUs+yrEqSJKlnWVYlSZLUsyyrkiRJ6lmWVUmSJPUsy6okSZJ6lmVVkiRJPcuyKkmSpJ5lWZUkSVLPsqxKkiSpZ1lWJUmS1LMsq5IkSepZo60DtJJkq5Fkv9kzZjx6xsjI5mvGx5esWLPm0vGq46rq2tb5JPUXxxRJk8kx5U9SVa0zTKskO82dOfPQsfHxZzxpm23qEVtsMWfu6CjLxsa4/Lrrlp9z9dUZHRn52rKxsfdV1UWt80rqbY4pkiaTY8rtDVVZnTkyctCs0dEP7bPddrOfNn/+yCazZt3uOTetWsU3r7pq/KTLL1+xamzs4NXj40c0iCqpDzimSJpMjil3rFlZTfIA4HJgs6paM9WvN3Nk5KBNN9roQ4ftttvcrefNu9vnX7N0KYecddayG1eu/LMdIcn+wAFV9aR1ef0k+wD7VdXfrmt2SXdtuscTmJwxxfFE6k2OKb1lWk+wSnJVkqcBVNWvqmredOwESXaaNTo64R0AYOt58zhst93mzhod/VCSHTc0Q1WduPZOkKSSPHRDtysNq1bjSfe1m44pjifS5HNM6d0xZSiuBjB35sxD99luu9kT3QFusfW8eTx/u+1mzx0dPXSKoknqQ44pkiaTY8pdm7aymuSzwAOAM5MsTXJIt7mPdj//nSTvTnJu9/NnJrlXkhOT3JjkoiTz19rew5N8M8kfkvwkyXPv5HW3Ghsff8ajt9xyZM8zzmC8u+zho4sWsfeXvnTr8/7jggs446c/BeDm1av56EUXsc+ZZ7LwJz8ZWTE29qwk9/7zzebjSf6Y5MdJnrrWJ/ZP8oskNyW5sju1fsvHv9/98/e6T/9h93vdq/vxZya5JMmS7s/h0Rv2U5cGU6vxpPvcrVavWfMPJ1522ci6jif7nnkm1y9fPrJ6zZp/SLLlnzbpeCK15JjS22PKtJXVqtoX+BXwT1U1DzjtDp72PGBfYBvgIcB5wLHAPYErgLcBJNkY+CZwErAVsDfwySSPvO0GR5L9nrjNNvWQe9yDuaOj/HzJEgAuu/Za5oyO8qsbbwTgf669lkdt2fl3/tCFFzJjZISjn/EMDn/609l41qwR4PC1NrsL8Atgi26mzye5ZzfXx4BnVNUmwBOAS+7gZ7Fr949/2X2b4dQkjwWOAV4K3Av4NPClJBvd1c9VGkatxhPojClPut/9xjeeOXOdx5OPP/3pXHbttTxo881njCT7dTfpeCI15pjyZz+LnhtTem0ZwLFV9fOq+iPwNeDnVfWtqhoDTgf+qvu8ZwJXVdWxVTVWVT8AFgJ73HaDs2fMePR2W2wxB2D7LbfkR9deyx9WrADgife7Hz+69lp+e/PNLBsb40Gbb84NK1aw6Le/5SWPeQyzR0fZfPZsHrf11iOBtRcr/x74aFWtrqpTgZ8A/9j93DiwfZI5VfWbqrpsgt/7gcCnq+qCqlpTVccDK4HHTfinJ2ltkz6ewJ/GlPUdT/7fttty8+rVM2fPmHHLrITjidQfHFMajSm9dlOA36315+V38PdbFnM8ENglyZK1Pj8KfPa2G5wxMrL53NHOt/moLbfkgmuuYYs5c9h+yy159JZb8u1f/pJZM2bwyC22YCTh98uWsWZ8nH8588xbt7F6zRqAuWtt9tf155dR+CWwdVXd3J0ufx1wdJJzgIOr6scT+N4fCOyX5FVrfWwWsPUEvlbS7U36eAJ/GlPWdzwZr2LuzJmMjIxs3v2Q44nUHxxTGo0p011WJ+s6Wf8HfLeqnn53T1wzPr5k2dgY0Cmrx1x6KVvMncujttySR26xBZ9YvJiZM2bcOr2+5Zw5zBwZ4ZRnPYsZI52J56/8/Occe+mlZ6y12W2SZK2d4QHAlwCq6uvA15PMAd4NHAk8eYLf03uq6j0TeK6kBuMJ/GlMecxWW63XeAK3jilLun91PJF6g2PKXX9PzcaU6V4G8DvgwZOwnS8D2ybZN8nM7n87JXnEbZ+4Ys2aSy+/7rrlANtssgmzZszg27/8JdtvuSVzZ85k89mzOefqq2/dEe45Zw6Pvc99OPKHP2TZ6tWMV7HoN79ZsXxsbOlam90KeHX3dfcEHgF8Ncm9kzyruy5kJbAUuLPLXtz2Z3EkcFCSXdKxcZJ/TLLJBv6spEE17eMJ/GlMWd/x5DdLl3LO1VevXLFmzaXdTTqeSL3BMeXOfxZNx5TpLqvvA97SnRq/w7UbE1FVNwF/S2ex8zXAb4EPALdb6Dtedfw5v/51blq1CujMrm46axZbzZ17698BHrL55rd+zcE778zY+Dgv/frX2fOMM7jwN7/ZqODitTZ7AfAw4DrgPcAeVXU9nZ/nwd1MfwCeArz8Tr6NtwPHd8+qe25VLaKzJuQTwA3Az4D91+kHIw2XaR9P4M/HlHUdT557xhm869xz+dG1146Md9Z8geOJ1CscU/7k7fTQmDIUt1vdeNasz++z3XbPfs62265zOf/8T386ftJll51x8+rVu09FNkn9xzFF0mRyTLlrvXY1gCmxbPXq9514+eUrrlm69O6fvJZrli7lpMsvX7FsbOx9UxRNUh9yTJE0mRxT7trAldUkl3UvYnvrf8BZy1evPvWQs85aNtEd4ZqlS3n9WWetWDU2dnB3+lvSkLmj8aQ7pmy7amzs4HUdUw4566xljinS8LqrMWXF2Njhrz/rrDWOKbc3FMsAbjFzZOSgWaOjH3r+dtvNfvr8+SObzJp1u+fctGoV37zyyvGTLr989fKxsWUFD6+q3zeIK6nHrdOYcsUVK1aNjR28enz8iAZRJfWwJFsBi0eSL84eHX2hY8qfG6qyCpBkx7mjo4eOjY//wxPvd7/abost5swZHWX52BiXX3fd8nOuvjqjIyNf7U6p/zOwM/B3VXVnZ8xJGmLrMqYM+uyHpHWXZAbwdeD8qnqLY8rtDV1ZvUWSLUeS/WbPmPHokZGRzcfHx5esWLPm0vGq46vq2u5zRoFvAOdU1b+3TSypl90ypswcGdl3RucWhBfedkyRpNtK8m46d4L6s4mxifSUYTG0ZXWiktwbWAy8tKq+0jqPpN6W5B3AeFW9o3UWSb0tyTOBTwE7uOTwzg3cCVaTrap+B+wFHJNkfuM4kiRpACR5EHA0sJdF9a5ZViegqs4B3g8sSDK7dR5JktS/ul1iAfDeqjq3dZ5eZ1mduI8CV3YfJUmS1td/0rkL1MdaB+kHltUJqs7i3hcDuyXZt3UeSZLUf5K8gM6tTg8oTxyakNHWAfpJVd2YZA/g20kuqaoftc4kSZL6Q5JHAR8C/rqqbmqdp184s7qOugX13+isX920dR5JktT7kmwGLAReU1WXtc7TTyyr66GqPgucRecKAWmdR5Ik9a5uVzgG+FZVndg6T7+xrK6/1wDzu4+SJEl35rXA/buPWkeuWV1PVbWiu371giQXdi9vJUmSdKskTwIOAXapqpWt8/QjZ1Y3QFVdBbwIOCXJVo3jSJKkHtK9C+YpwAur6pet8/Qry+oG6t6C9Xjg5CQzWueRJEntJRmlU1SPqaqvtc7Tzyyrk+NtQAHvbB1EkiT1hHcBq4F3tA7S71yzOgmqak2SvYHFSc6vqjNbZ5IkSW0keRbwfGCHqlrTOk+/c2Z1klTVtcBewFFJHtw6jyRJmn7dDnAksFdVXdc6zyCwrE6iqjoPeC9wepLZrfNIkqTp0z32LwDeXVXnt84zKCyrk+9jwM+6j5IkaXh8HPgJ8InWQQaJZXWSVVUBBwC7JtmvdR5JkjT1kuwPPAk4sNsFNEk8wWoKVNVNSXYHvpPk4qq6tHUmSZI0NZL8JfAfwFOqamnrPIPGmdUpUlWX0bkV68IkmzWOI0mSpkD3GL8AeHVVXd46zyCyrE6hqjoR+CZwTJK0ziNJkiZP99h+HPD1qjq5cZyBZVmdeq8F7g/8W+sgkiRpUh0MbN191BRxzeoUq6qVSfYELkxyYVWd3TqTJEnaMEl2BV4H7FxVK1vnGWTOrE6DqvolsD9wcpL7NI4jSZI2QJL7AicD+1XVr1rnGXSW1WlSVV8DjqZTWJ3RliSpD3WP4acAn6mqr7fOMwwsq9PrncAq4F2tg0iSpPXyHmA5HsunjTN806iq1iTZB/hBkvOq6kutM0mSpIlJ8mzgecAOVTXeOs+wcGZ1mlXVdcBzgaOSPKR1HkmSdPe6x+wjgT27x3JNE8tqA1V1Pp23DxYkmdM6jyRJunPdY/VC4B1VdWHrPMPGstrOJ4AfAx9vHUSSJN2lTwCXA59sHWQYWVYbqaoCDgSemOSFrfNIkqTbS/Ii4PHAS7rHbk0zT7BqqKqWJtkd+G6Si6vqktaZJElSR5LHAB8Adq2qpY3jDC1nVhurqsuBV9NZv7p54ziSJAnoHpMXAq+sqisaxxlqltUeUFUnA/8FHJskrfNIkjTMkowAxwNfqapTW+cZdpbV3nEwsDWd+wxLkqR2Xg9shcfknuCa1R5RVSuT7AlcmOSCqvpe60ySJA2bJH8NvBbYqapWtU0jcGa1p1TVr4D9gJOT3Ld1HkmShkn32HsisG9V/V/rPOqwrPaYqvo68BnglCTOfEuSNA2SzAROBY6oqm+2zqM/saz2pncBy4H3tA4iSdKQeC+wFI+9PceZux5UVeNJ/gVYnOS8qjqjdSZJkgZVkucAewI7VNV46zz6c86s9qiquo7OL85nkjy0dR5JkgZRkocBnwb2rKrrW+fR7VlWe1hVXQi8g84NA+a0ziNJ0iBJMhdYALytqi5qnUd3zLLa+z4JXA4c3jqIJEmDonsTnsOBHwFHNI6ju2BZ7XFVVcBLgMcleXHrPJIkDYgXAzsBL+0ea9WjPMGqD1TV0iS7A99L8oOqurh1JkmS+lWSxwLvA55UVTe3zqO75sxqn6iqK4BX0lm/unnjOJIk9aUk96CzTvXlVfWT1nl09yyrfaSqTgW+AhyfxH87SZLWQffYeQLwpao6vXUeTYyFp/+8DtgKeH3rIJIk9Zk3APcCDmkdRBPnmtU+U1WrkjwXuDDJBVX1ndaZJEnqdUl2A14N7FRVq1rn0cQ5s9qHqur/gBcAJya5b+s8kiT1siTbACcC/1JVV7fOo3VjWe1TVfVNOteFOy3JzNZ5JEnqRd1j5KnA4VX1363zaN1ZVvvbe4Cb6Fx+Q5Ik3d77gSV4rOxbrlntY1U1nmRfYHGSc6vq860zSZLUK7rXKP9nYIeqGm+dR+vHmdU+V1XXA3sCRyR5WOs8kiT1giTbAp8C9qyqP7TOo/VnWR0AVXUR8DZgYZK5rfNIktRSko2BhcC/V9Wi1nm0YSyrg+MI4FLgk0nSOowkSS10j4GfAi4GPtM4jiaBZXVAVFUBLwV2BA5oHEeSpFZeAvwVcFD32Kg+5wlWA6Sqbu4uJv9+ksVV9YPWmSRJmi5JdgTeDTyxqpa1zqPJ4czqgKmqnwAvBxYkuUfrPJIkTYck9wROB15WVT9tnUeTx7I6gKrqdOBLwAlJ/DeWJA207rHus8AXqmpB6zyaXBaZwXUIcE/gDa2DSJI0xQ4FNsNj3kByzeqAqqpVSZ4LXJTk/Ko6q3UmSZImW5KnAq8Adqyq1a3zaPI5szrAqurXwL7AiUm2aZ1HkqTJ1D22fQ7Yp6quaZ1HU8OyOuCq6r+Bw4FTk8xsnUeSpMnQPaadBnzMdw8Hm2V1OLwPWAJ8oHEOSZImy2HAH/DYNvBcszoEqmo8yQuAxUnO9UxJSVI/S7In8Gxgh6oab51HU8uZ1SFRVX8A9gQ+lWTb1nkkSVofSR4OfBLYo6puaJ1HU8+yOkSqahHwFmBhko1b55EkaV10j10LgDd5l8bhYVkdPp8BLqYzw5rWYSRJmojuMevTwCLgqMZxNI0sq0Omqgo4CPgr4CWN40iSNFEHAY8CXt49lmlIeILVEKqqZUl2B85Jsri7PECSpJ6UZCfgHcATq2pZ6zyaXs6sDqmq+imd/0s9Pck9W+eRJOmOJLkXcDrw0qr639Z5NP0sq0OsqhYCnwc+m8R9QZLUU7rHps8Cp1fVF1rnURsWFL0R2BQ4tHUQSZJu483APDxGDTXXrA65qlqdZC9gUZLzu7dnlSSpqSRPp7NcbceqGmudR+04syqq6hpgH+BzSbZpnUeSNNyS3B84Adinqn7TOo/asqwKgKo6C/gYnROuZrXOI0kaTt1j0GnAR6vqO43jqAdYVrW2DwDXA4e1DiJJGlr/Afwej0Xqcs2qblVV40leACxOcm5VndY6kyRpeCR5HvBMYAcv/K9bOLOqP1NVNwB7AIcneXjrPJKk4ZDkEcDHgT2qaknjOOohllXdTlX9AHgTsCDJxq3zSJIGW5J5wELgjVV1ces86i2WVd2Zo4BFwKeTpHUYSdJg6h5jPgOcX1VHt86j3mNZ1R3qrhV6OfAoOte5kyRpKrwc2A54Resg6k2eYKU7VVXLkuwBnJNkUVVd1DqTJGlwJNkFeBvwhKpa3jqPepMzq7pLVfW/wEvpXH/1Xq3zSJIGQ5It6FxP9cCq+lnrPOpdllXdrar6AnA68Nkk7jOSpA2SZAbwOeCUqvpi6zzqbRYPTdShwDzgza2DSJL63luA2XhM0QS4ZlUTUlVjSfYCFiU5v6q+2TqTJKn/JPk74CV0Lvw/1jqPep8zq5qwqvoNsA9wQpL7t84jSeovSR4AHA/sXVW/bZ1H/cGyqnVSVd8BPkrnhKtZbdNIkvpFko3onP/woar6Xus86h+WVa2Pw4DfAR9sHUSS1Dc+BFyDxw6tI9esap1VVSXZD1ic5NyqOqV1JklS70ryfODvgR27N52RJsyyqvVSVUu6Nwz4RpIfVtUVrTNJknpPku2A/wSeVlVLGsdRH3IZgNZbVV0MvBFYmGRe6zySpN6SZBNgIXBIVf2wdR71J8uqNkhVHQ2cD3wmSVrnkST1hu4x4UjgnKo6tnUe9S/LqibDK4DtgJe3DiJJ6hmvBLYFXtU6iPqba1a1wapqeZLdgfOSLKqqC1pnkiS1k+RxdO5S9fiqWt46j/qbM6uaFFX1c+BA4LQkW7TOI0lqI8mWwGnAAVX1i9Z51P8sq5o0VfVF4BTgc0lmtM4jSZpe3bH/RODEqjqzdR4NBsuqJtubgdl03v6RJA2Xt9JZYvjvrYNocLhmVZOqqsaSPI/ODQPOr6qvt84kSZp6SZ4BvBjYoarGWufR4HBmVZOuqn4L7A0cn+QBrfNIkqZWkgcCxwF7V9XvGsfRgLGsakpU1ffo3Af69CQbtc4jSZoa3TF+AXBYVZ3dOo8Gj2VVU+mDwDV0SqskaTB9BPgV8OHWQTSYLKuaMlVVwAuBv0/y/NZ5JEmTK8k+wNOAF3XHfGnSeYKVplRVLeneMOBbSS6pqstbZ5IkbbgkjwQ+Cjy1qv7YOI4GmDOrmnJV9UPgEGBhkk1a55EkbZjuWL4QeF1VXdo6jwabZVXToqqOBb4PHJkkrfNIktZPdww/GvhuVR3fOo8Gn2VV0+lVwLbAK1sHkSStt1cDDwH+tXUQDQfXrGraVNWKJHsA5yW5qKrOb51JkjRxSZ4AvAl4XFWtaJ1Hw8GZVU2rqvoFcABwWpItW+eRJE1Mkq2AU+mc+X9l6zwaHpZVTbuqOhM4ETgxyYzWeSRJd607Vp8EnFBVX2mdR8PFsqpW/p3OMpS3tg4iSbpb7wCCY7YacM2qmqiqsSR7A4uTnFdV/9U6kyTp9pL8I7AfsENVrWmdR8PHmVU1U1W/A/YGjkvywNZ5JEl/Lsl84BjgeVX1+8ZxNKQsq2qqqs4G/gNYkGSj1nkkSR1JZgMLgPdX1Tmt82h4WVbVCz4M/Ar4SOsgkqRbfRS4svsoNWNZVXNVVcCLgKcl2ad1Hkkadkn2BXYDXtwdo6VmPMFKPaGq/ti9YcB/J7mkqi5rnUmShlGSR9F5x+tvqurG1nkkZ1bVM6rqUuBgYGGSTVrnkaRhk2RTOutUX1tVP2qdRwLLqnpMVZ0AfBc4Okla55GkYdEdc48Bvl1Vn2udR7qFZVW96F+BhwCvbh1EkobIa4AHdh+lnuGaVfWcqlrRXb96fpKLqurc1pkkaZAleRLwRmCXqlrZOo+0NmdW1ZOq6ko6Vwg4NclWrfNI0qBKcm/gFOCFVXVV4zjS7VhW1bOq6ivACcBJSWa0ziNJgybJKHAycGxVfbV1HumOWFbV694KBHh74xySNIjeCazBMVY9zDWr6mlVtSbJ3sDiJOd3Z1slSRsoyT8B/wLsUFVrWueR7owzq+p5VfV74HnAMUnmN44jSX0vyYOBo4C9qura1nmku2JZVV+oqnOA9wMLksxunUeS+lV3DD0deG9Vndc6j3R3LKvqJx8Fruw+SpLWz8eAn3UfpZ5nWVXfqKoCXgzslmTf1nkkqd8k2Q/YFTigO6ZKPc8TrNRXqurGJLsDZyW5xHtXS9LEJHk08EHgr6vqptZ5pIlyZlV9p6r+B3gtnfWrm7bOI0m9LslmwELgX6vqstZ5pHVhWVVfqqrPAd+mc4WAtM4jSb2qO0YeB3yjqk5qHEdaZ5ZV9bPXAA/sPkqS7tjBwNbAv7UOIq0P16yqb1XVyiR7AhckubB7eStJUleSXYHXAbtU1crWeaT14cyq+lpVXQW8EDglyVaN40hSz0hyH+BkYP+q+mXrPNL6sqyq71XVV+msxzo5yYzGcSSpuSSjwCnAUVX1X63zSBvCsqpB8XZgHHhn4xyS1AveDazEMVEDwDWrGghVtSbJ84HFSc6rqi+3ziRJLSR5FvB84LFVtaZ1HmlDObOqgVFV1wJ7AUcneXDrPJI03ZI8BDgKeG5VXdc6jzQZLKsaKFV1HvBe4PQks1vnkaTpkmQOsAB4V1Wd3zqPNFksqxpEHwN+1n2UpGHxceDHwCdaB5Emk2VVA6eqCjgAeHKS/VrnkaSpluRFwBOAA7tjoDQwPMFKA6mqbkqyB/CdJBdX1aWtM0nSVEjyGOADwK5VtbRxHGnSObOqgVVVlwH/CixMslnrPJI02ZJsTmed6quq6orGcaQpYVnVQKuqk4BvAMckSes8kjRZumPaccDXquqUxnGkKWNZ1TD4N+B+3UdJGhSvB+4DHNw6iDSVXLOqgVdVK5M8F7ggyYVVdXbrTJK0IZI8hc7/gO9cVata55GmkjOrGgpV9Utgf+DkJPdpHEeS1luS+wInAS+oql+1ziNNNcuqhkZV/RdwNJ3C6rsKkvpOd+w6BfhMVX2jdR5pOlhWNWzeCawC3tU6iCSth/cCy3EM0xBxdklDparWJNkHWJzkvKr6UutMkjQRSf4fsBewQ1WNN44jTRtnVjV0quo6OgP+UUke0jqPJN2dJA8FPgPs2R3DpKFhWdVQqqrz6SwJWJBkTus8knRnkswFFgJvr6oLW+eRpptlVcPscODHwMdbB5GkO9K98P/hwP8An2ocR2rCsqqhVVUFHAg8IckLW+eRpDvwYmBn4CXdMUsaOp5gpaFWVUuT7A58L8nFVXVJ60ySBJDkscD7gCdX1c2t80itOLOqoVdVVwCvorN+dfPGcSSJJPcATgdeUVU/bp1HasmyKgFVdQrwNeDY7hoxSWoiyQhwPPDlqjqtdR6pNZcBaFhsDNz3rp5w5ZVXfvKf/umfTrr3ve/9PuCoKcrxR+A6wLVnvWkU2BqYtb4b2HXXXe+RpICHbkCOVcCvgTUbsA1NnQBbAJtNxcZ32223l1577bX3O/PMM9/A3e9HvwFcIqCBFtdra8DNpHPJl2cAK+7uyePj41m2bNnc2bNnrxgdHZ2KojATuBZ4MnDVFGxf6+8FdP4nZTWw3hdcX7ly5SyAjTbaaNUGZBmhU5xfDHxuA7ajyTcf+D6dsrp6sjc+NjY2Y8WKFbPnzp27bGRkZCIH6NnAV4E9piKP1AssqxpkAb4CPAWY2zjL2tYA1wN/BVzTOIs6ngccA/TaNXeXA/sDvhXcG7YBfgDcC5jROMvalgFnAf+E79poALlmVYNsG2A3equoQucgtwnwrNZBdKs303tFFTqZDm0dQrf6f8Cm9FZRhc4Y91TuZqmT1K8sqxpk9wNWtg5xJ+YAD2gdQre6T+sAd2Hr1gF0qwfQedu9F60E7t86hDQVLKsaZBu8fx933HFcc836v1N/1VVXcdJJJ93Zp/396x0bdAUI95OhsUH/FlO8n8AG7sdSr3IQlO7CNBxcNADcTzQR7ifS+rGsauh8+MMfZvvtt2f77bfnox/9KFdddRXbb7/9rZ//4Ac/yNvf/nYWLFjAokWL2GeffXjMYx7D8uXLmT9/Pm94wxvYeeed2XnnnfnZz34GwP7778+CBQtu3ca8efMAeOMb38jZZ5/NYx7zGD7ykY9M7zeqDeJ+oolwP5GmnmVVQ2Xx4sUce+yxXHDBBZx//vkceeSR3HDDDXf43D322IMdd9yRE088kUsuuYQ5czrn32y66aZceOGFvPKVr+Q1r3nNXb7e+9//fp785CdzySWX8NrXvnayvx1NEfcTTYT7iTQ9LKsaKt///vd5znOew8Ybb8y8efP453/+Z84+++x12sbee+996+N55503FTHVmPuJJsL9RJoellUNlTu6rvCSJUsYH//TNeBXrLjrewesfTfWW/48Ojp66zaqilWrNuR68GrN/UQT4X4iTQ/LqobKrrvuyhlnnMGyZcu4+eab+cIXvsAznvEMfv/733P99dezcuVKvvzlL9/6/E022YSbbrrpz7Zx6qmn3vr4+Mc/HoD58+ezePFiAL74xS+yevXqO/169T73E02E+4k0PUZbB5Cm02Mf+1j2339/dt55ZwAOOOAAdtppJ9761reyyy678KAHPYiHP/zhtz5///3356CDDmLOnDm3vkW3cuVKdtllF8bHxzn55JMBOPDAA3n2s5/NzjvvzFOf+lQ23nhjAB796EczOjrKX/7lX7L//vu7zqxPuJ9oItxPpOnh7VY1yJ5A557Zm03WBufPn8+iRYvYYostJmNzHwDeOBkb0ga7js4tNCfFJO8n1wFbTsaGtMH+A3jdZG1skveTPwJ/D5w/GRuTeonLADTIVtG7F8kep3fvrjWMVrcOcBdcsNg7VgC9OsMT3Fc0oFwGoEH2cyb51ohXXXXVZG1qOfDTydqYNtjPgXszSf9zM4n7SeF+0kv+F1gGbDwZG5vE/QQ6Y90vJnODUq9wZlWD7Abg9XQOLr1kOZ236hbc3RM1bV5K523UXpo1K2AJ8PLGOfQnpwIX0Pkd7iXL6CxPWNI4hzQlXLOqYXAg8ArgPpO94arKkiVLNp8xY8bYpptuOpHTdG8CzgJehcsAes0jgY8DDwNmru9GbrrppnlJmDdv3tINyLKazizeK4ArNmA7mnwbAZ8A/hrY5O6efOONN26yZs2a0c0333xJkqk44P62m+eoKdi21BMsq9IGSnIvYBFwcFV9vnUetZXkHcB4Vb2jdRa1lWRPOidS7lBVd3xrK0l3y2UA0gaqquuBPYEjkjysdR5J7SX5C+CTwJ4WVWnDWFalSVBVi4C3AguTzG2dR1I7STYGFgJvrqrFrfNI/c6yKk2eTwM/BD6Zte+hKGlodH/3jwAWA0c2jiMNBMuqNEmqswD8IGBH4IDGcSS18VLgL4GXlSeFSJPC66xKk6iqbk6yO3B2ksVV9YPWmSRNjyQ7Au8EnlRVvXbJPKlvObMqTbKq+gmda2MuSHKP1nkkTb3uVUEWAAdVlTdykCaRZVWaAlW1APgicEISf8+kAdb9Hf8ssNDL10mTz4OoNHUOAe4JvKF1EElT6k10bhDwxtZBpEHkmlVpilTV6iTPBS5Kcn5VndU6k6TJleTpdJb97FhVq1vnkQaRM6vSFKqqXwP7Aicm2aZ1HkmTJ8n9gROAfarqmtZ5pEFlWZWmWFX9N3A4cGqS9b7nvKTekWQWcBrwn75rIk0ty6o0Pd4HLKFzn3BJ/e8/gGuBw1oHkQada1alaVBV40leACxKcm73agGS+lCSvYBn0lmnOt46jzTonFmVpklV/QHYk87tWLdtnUfSukvycOATwB5VdUPrPNIwsKxK06iqFgNvARYm2bh1HkkTl2QesBA4tKoubp1HGhaWVWn6HQn8APhUkrQOI+nudX9XPw1cCBzdOI40VCyr0jSrqgJeBjwGeEnbNJIm6GXA9sArur/DkqaJJ1hJDVTVsiR7AN9PsriqFrXOJOmOJdkZeDvwhKpa1jiONHScWZUaqaqfAgcBpye5Z+s8km4vyb3oXE/1pVX1s9Z5pGFkWZUaqqrPA58HPpvE30ephySZAZwInF5VX2idRxpWHhyl9t4IbAoc2jqIpD/zFmAO/m5KTblmVWqsqlZ3LzK+KMkFVfWt1pmkYZfk7+icALljVY21ziMNM2dWpR5QVdcA+9BZDnC/1nmkYZbkAcDxwPOr6jet80jDzrIq9YiqOgv4GHBaklmt80jDqPu7dxrw4ar6bus8kiyrUq/5AHA9cFjrINKQ+hDwW+A/WgeR1OGaVamHVNV4khfQWb96blWd1jqTNCySPA94Bp11ql74X+oRzqxKPaaqbgD2AD6R5OGt80jDIMl2wMeBPapqSeM4ktZiWZV6UFVdDLwJWJBk49Z5pEGWZB6wAHhDVV3SOI6k27CsSr3raOAi4NNJ0jqMNIi6v1tHAudV1TGt80i6Pcuq1KO6a+ZeATyKzm1ZJU2+VwAPB17ZOoikO+YJVlIPq6plSXYHzk2yqKouap1JGhRJHge8FXh8VS1vnUfSHXNmVepxVfUz4KXA6Unu1TqPNAiSbEnneqoHVtXPW+eRdOcsq1IfqKovAKfTucOVv7fSBkgyAzgROKmqvtg6j6S75kFP6h+HAvOAN7cOIvW5twIzgbe0DiLp7rlmVeoTVTWWZC86Nwy4oKq+0TqT1G+S/D3wYjoX/h9rnUfS3XNmVeojVfUbYB/ghCT3b51H6idJHggcB+xdVb9tHEfSBFlWpT5TVd8BPkLnhKtZjeNIfSHJRnTWfX+wqs5unUfSxFlWpf50GPA74IOtg0h94sPA1cCHWgeRtG5csyr1oaqqJPvRWb96blWd0jqT1KuSPB/4WzrrVKt1HknrxrIq9amqWpJkD+CbSX5YVVe0ziT1miSPBP4TeFpV/bF1HknrzmUAUh+rqkuANwALk8xrHEfqKUk2ARYCr6+qH7bOI2n9WFalPldVxwDnAZ9JktZ5pF7Q/V04Cji7qo5rHEfSBrCsSoPhlcAjgJe3DiL1iFcBD+s+SupjrlmVBkBVLe+uXz0vyaKquqB1JqmVJE+gc6e3x1fVitZ5JG0YZ1alAVFVPwcOBE5LskXrPFILSbYCTgVeXFW/aJ1H0oazrEoDpKq+CJwCnJhkRus80nTq7vMnAZ+tqi+3ziNpclhWpcHzZmAj4N9bB5Gm2dvpHNfe2jiHpEnkmlVpwFTVWJLnAYuTnF9V/9U6kzTVkvwD8EJgh6oaa51H0uRxZlUaQFX1W2Bv4LgkD2idR5pKSeYDxwLPq6rfNY4jaZJZVqUBVVXfo3Mf9NOTbNQ6jzQVuvv26cAHqur7rfNImnyWVWmwfRC4hk5plQbRR4FfAh9pnEPSFLGsSgOsqgrYH/i7JM9vHEeaVEn+BXgq8KLuvi5pAHmClTTgquqP3RsGfCvJJVV1eetM0oZKsj2d2dS/qaobW+eRNHWcWZWGQFX9EHg9sDDJJq3zSBsiyabAQuDgqvpR6zySppZlVRoSVXUc8H3gyCRpHEdaL9199xjgrKo6oXUeSVPPsioNl1cB2wKvbB1EWk+vAeZ3HyUNAdesSkOkqlZ016+el+Siqjq/dSZpopI8EXgjsEtVrWidR9L0cGZVGjJV9QvgAOC0JFu2ziNNRJKtgFPonPl/VeM4kqaRZVUaQlV1JnAicFKSGa3zSHelu4+eDBxfVV9pnUfS9LKsSsPr34EZwNtaB5HuxjuBwn1VGkquWZWGVFWNJdkbWJzkvKr6WutM0m0leSbwAmCHqlrTOo+k6efMqjTEqup3wN7AcUke2DqPtLYkDwKOBvaqqt+3ziOpDcuqNOSq6mzgMGBBko1a55EAkswGFgDvq6pzW+eR1I5lVRLAh4Ff0bl9pdQL/hP4efdR0hCzrEqiqgp4EfC0JPu0zqPhlmQ/4K+BA7r7pqQh5glWkgCoqj8m2R34dpJLquqy1pk0fJI8GvggsFtV3dg6j6T2nFmVdKuq+hFwMLAwySat82i4JNkMWAi8pqr+p3UeSb3Bsirpz1TVCcB3gaOTpHUeDYfuvnYM8M2qOrF1Hkm9w7Iq6Y78K/AQ4NWtg2ho/Btwf+C1rYNI6i2uWZV0O1W1IskewPlJLvLSQZpKSZ4MHALsXFUrW+eR1FucWZV0h6rqSjpXCDg1yVat82gwJbkPcDKwf1X9snUeSb3HsirpTlXVV4ATgJOSzGidR4MlySidonqMt/uVdGcsq5LuzluBAO9oHUQD513Aaty3JN0F16xKuktVtSbJ3sDiJOd1Z1ulDZLkWcA+wA5VtaZ1Hkm9y5lVSXerqn4PPA84Jsn8xnHU55I8GDgK2Kuqrm2dR1Jvs6xKmpCqOgd4P7AgyezWedSfkswBFgDvrqrzWueR1Pssq5LWxUeBK7uP0vr4OPDT7qMk3S3LqqQJq6oCXgzslmTf1nnUX5K8EHgicEB3X5Kku+UJVpLWSVXdmGR34Kwkl1TVj1pnUu9L8hjgMOApVbW0cRxJfcSZVUnrrKr+h85tMRck2bR1HvW2JJvTWaf66qq6vHEcSX3GsippvVTV54Bv07lCQFrnUW/q7hvHAv9VVSe3ziOp/1hWJW2I1wAP7D5Kd+R1wNbAwa2DSOpPrlmVtN6qamWSPYELklxUVd9vnUm9I8mudErqzlW1snUeSf3JmVVJG6SqrgJeCJyS5N6N46hHJLkvcDKwX1X9qnUeSf3Lsippg1XVV+msSzw5ie/YDLnuPnAKcGRVfb11Hkn9zbIqabK8HVgDvLNxDrX3HmAF8K7WQST1P2dAJE2KqlqT5PnA4iTnVdWZrTNp+iV5NvA8YIeqWtM6j6T+58yqpElTVdcCewFHJXlw6zyaXkkeChwJPLeqrmudR9JgsKxKmlRVdR7wXuD0JLNb59H0SDKHzoX/31FVF7TOI2lwWFYlTYWPAT/rPmo4HA5cDnyydRBJg8WyKmnSVVUBBwBPTrJf6zyaWkleDDwOeEn3316SJo0nWEmaElV1U5I9gO8kubiqLm2dSZMvyV8B7wd2raqlrfNIGjzOrEqaMlV1GfCvwMIkm7XOo8mVZHM661RfWVVXNI4jaUBZViVNqao6CfgGcGyStM6jyZFkBDge+EpVndo6j6TBZVmVNB3+DdiGzn3iNRheD2wFvK51EEmDzTWrkqZcVa1M8lzggiQXVtX3WmfS+kvy18BrgZ2qalXbNJIGnTOrkqZFVf0S2B84Ocl9GsfRekpyX+AkYN+q+r/WeSQNPsuqpGlTVf8FHAWcksR3dvpMkpnAqcARVfXN1nkkDQfLqqTp9k5gJfDu1kG0zt4L3Iz/dpKmkTMbkqZVVa1Jsg/wgyTnVtWXWmfS3Uvyz8CewA5VNd46j6Th4cyqpGlXVdcBzwWOSvKQ1nl015I8DDgC2LOqrm+dR9JwsaxKaqKqzgfeBSxIMqd1Ht2xJHOBhcDbquqi1nkkDR/LqqSWPgH8GPh46yC6ve5NHD4JXEpnZlWSpp1lVVIzVVXAgcATkrywdR7dzgHAjsBLu/9WkjTtPMFKUlNVtTTJ7sD3klxcVZe0ziRI8lg6Z/8/qapubp1H0vByZlVSc1V1BfAqOutXN28cZ+gluQewAHh5Vf2kdR5Jw82yKqknVNUpwNeA47prJdVAkhHgBOBLVXV66zySZFmV1EsOBu4DvL51kCH2BuBewCGtg0gSuGZVUg+pqlVJngtcmOSCqvpu60zDJMluwKuBnapqVes8kgTOrErqMVX1K+AFwElJ7ts6z7BIsg1wIrBvVV3dOo8k3cKyKqnnVNU3gM8ApyTxHaAplmQmcCpweFV9q3UeSVqbZVVSr3oXsJzO5ZM0tT4ALAHe1ziHJN2OMxaSelJVjSf5F2BxknOr6ozWmQZRkj2A5wA7VNV46zySdFvOrErqWVV1HbAn8JkkD22dZ9Ak2Rb4FLBnVf2hdR5JuiOWVUk9raouBN5B54YBc1rnGRRJNgYWAm+pqkWt80jSnbGsSuoHnwQuAw5vHWQQdG+68CngYjonsklSz7KsSup5VVXAS4Bdkry4dZ4B8BLgr4CDuj9bSepZnmAlqS9U1c1JdgfOTvKDqrq4daZ+lGRH4N3AE6tqWes8knR3nFmV1Deq6sfAK+isX71H6zz9Jsk9gdOBl1XVT1vnkaSJsKxK6itVdRrwZeD4JI5hE9T9WX0W+EJVLWidR5ImyoFeUj96PbAFcEjrIH3kUGAz4A2tg0jSunDNqqS+U1WrkjwXuCjJBVV1VutMvSzJ0+gsn9ipqla3ziNJ68KZVUl9qaquBl4AnJhk69Z5elWS+9F5+3+fqvp16zyStK4sq5L6VlV9k871Qk9NMrN1nl6TZBZwGvAxZ58l9SvLqqR+9x7gJuB9rYP0oMOA64EPtA4iSevLNauS+lpVjSfZF1ic5Nyq+nzrTL2gu6b3WcAOVTXeOo8krS9nViX1vaq6HtgTOCLJw1rnaS3Jw+ncmnaPqrqhdR5J2hCWVUkDoaouAt4GLEwyt3WeVpJsDCwA3lRVP2idR5I2lGVV0iA5Avgh8MkkaR1munW/508Di4CjGseRpElhWZU0MKqqgIOAHYEDGsdp4SDgUcDLuz8LSep7nmAlaaBU1c1Jdge+n+QHVbW4dabpkGQn4B3AE6tqWes8kjRZnFmVNHCq6ifAy4DTk9yzdZ6pluRewOnAQVX1v63zSNJksqxKGkhVtQD4InBCkoEd67rf2+eA071sl6RBNLADuCQBhwD3AN7YOsgUeguwMXBo6yCSNBVcsyppYFXV6u7F8RcluaCq/rt1psmU5G+BlwI7VtVY6zySNBWcWZU00Krq18C/AJ9Lsk3rPJMlyf2BE4B9quo3rfNI0lSxrEoaeN0Z1U8ApyaZ2TrPhkoyi84JVR+pqu80jiNJU8qyKmlYvA9YAnygcY7J8EHgd8BhrYNI0lRzzaqkoVBV40leACxOcm73agF9J8nzgH8EdvDC/5KGgTOrkoZGVf0B2BP4VJJtW+dZV0keAXwc2KOqljSOI0nTwrIqaahU1SI6l3tamGTj1nkmKsk8YCHwxqq6uHUeSZoullVJw+gzwA+AI5KkdZi70834GeD8qjq6dR5Jmk6WVUlDp7vW82XAX9K5TmmvezmwHfCK1kEkabp5gpWkoVRVy5LsAXw/yaLu8oCek2QX4G3AE6pqees8kjTdnFmVNLSq6qfAQcCCJPdqnee2kmwBnAYcWFU/a51HklqwrEoaalX1eTonLn02Sc+MiUlmACcCp1TVF1vnkaRWemZglqSG3ghsArypdZC1/DuwEfDm1kEkqSXXrEoaelW1OslewKIk51fVt1rmSfL3wIF0Lvw/1jKLJLXmzKokAVV1DbAPneUA92uVI8kDgOOAvavqt61ySFKvsKxKUldVnQV8DDgtyazpfv0kGwGnAx+qqu9N9+tLUi+yrErSn/sAcD1wWIPX/hBwDfDBBq8tST3JNauStJaqGk/yAmBxknOr6rTpeN0kzwf+Htixe9MCSRLOrErS7VTVDcAewOFJHj7Vr5dkO+A/gd2raslUv54k9RPLqiTdgar6AZ1LWS1MMm+qXifJJnSu83pIVf1wql5HkvqVZVWS7txRwIXAp5Nksjfe3eaRwDlVdexkb1+SBoFlVZLuRHft6CuA7YGX3dVzk8xL8jhgG+B+SR6XZOO7eYlXAdt2HyVJdyCu45eku5bkocC5wDOr6sI7ec6Lgc8Aq4ECZgEH3NmMaZLHA18EHldVv5iS4JI0ACyrkjQBSZ4DfATYAXgwcN+q+tJan98Y+A2d27YC/BHYuqqWrfWcZwO/Bn4JLAZeUVVnTs93IEn9yWUAkjQBVfUFOhfsPxs4h9tcC7WqbgbeS2dmdTXw7rWLateH6czQfg840aIqSXfPsipJE9C9IsC2wF8AM4H5SWbe5mkfp7MEYBz45G2+fiPg/t2v3Rb4iwmsaZWkoWdZlaSJ+VvgWWv9fTWw3dpP6M6uHgEcfgezqtt3v+YWzwGePgU5JWmgWFYlaQKq6vN0CueXgFXAXOBpt3w+yVYzRkZeP3d09J6bzJq17cYzZ352xsjI65Ns2X3K07pfswo4A3hkVZ0xnd+DJPUjT7CSpHWU5GHA5+isPT1t7syZh46Njz/jSdtsU4/YYos5c0dHWTY2xuXXXbf8nKuvzujIyNeWjY0tp3Ni1r5V9bOm34Ak9RHLqiStp5kjIwfNGh390D7bbTf7afPnj2wya9btnnPTqlV886qrxk+6/PIVq8bGDl49Pn5Eg6iS1Lcsq5K0HmaOjBy06UYbfeiw3Xabu/W8u78b6zVLl3LIWWctu3HlSgurJK0Dy6okraMkO82dOfM7H3va0yZUVG9xzdKlvPpb31q2bPXqp1TVorvY/nzgSmBmVY1teGJJ6l+eYCVJ62juzJmH7rPddrPXpagCbD1vHs/fbrvZc0dHD52iaJI0cCyrkrQOkmw1Nj7+jKfNn79e4+fT588fGRsf/4e1rhIwpZKMTsfrSNJUsaxK6itJ3pDk10luSvKTJE9NclySd6/1nL9OcvVaf78qyeuTXJrk5iRHJ7l3kq91t/OtJPe4m9edn6SAjwU2OvBrX+OUK6649fMfvvBCjv+f/7n175f+/vfs++Uv3/r3/b/yFRb85Ce84TvfYaxqNvDlCWR4UZJrkvwmycFrZRlJ8sYkP09yfZLTktxz7ZxJXpzkV8C3k8xO8rnuc5ckuSjJvdfxRy9JTVhWJfWNJH8BvBLYqao2Af4OuGqCX747nYvwbwv8E/A14E3AFnTGwldPZCMjyQ77P+pRee9TnsJJl1/Or268ccL5z7n6at6z667s+8hHAjx6Ahl2Ax5G54YEb0xyy3VdXw38P+ApwNbADcDht/napwCPoPMz2g/YjM4dtO4FHAQsn3BwSWrIsiqpn6wBNgK2SzKzqq6qqp9P8Gs/XlW/q6pfA2cDF1TVxVW1EvgC8FcT2cic0dGrNp01iwdvvjkP3mwzrlyyZMLhn/XQh3KP2bPZcu5cZiQ3TCDDO6rq5qr6EXAssHf34y8F3lxVV3e/9u3AHrd5y//t3a9dTufOWfcCHlpVa6pqcVVNvGVLUkOWVUl9o3sx/dfQKWe/T3JKkq0n+OW/W+vPy+/g7xM6W2p8fPx3y8Y6J+hvNDrK8rGJn6y/+ezZnRcbG6NgxQQy/N9af/4lnVlUgAcCX+i+pb8EuIJOkb/3nXztZ4GvA6d0lxUclmTmhINLUkOWVUl9papOqqon0SlsBXwAuJnOrUxvcZ+pev0Va9b86PLrrrvdW+gbjY6ycq3iesOKFXe6jcuvu275eNUNE3i5+6/15wcA13T//H/AM6pq87X+m92dNb7FrdclrKrVVfWOqtoOeALwTOAFE3h9SWrOsiqpbyT5iyR/k2QjOjOTy+nMKF4C/EOSeya5D53Z1ylRcMI5v/51blq16s8+/pDNN2fRb3/LTatW8YcVKzjjf//3Dr/+plWrOOfqqwP8YgIv9+9J5iZ5JPBC4NTux48A3pPkgQBJtkzy7DvbSJLdkjwqyQzgRjrLAtZM4PUlqTnLqqR+shHwfuA64LfAVnROUPos8EM6J1t9gz+Vuqlw7ejIyNe+ddVV42t/8G8e+EAetNlm7P+Vr/CW732PXe9//zv84m9eddX46MjIV4GVE3it7wI/A/4b+GBVfaP78f8EvgR8I8lNwPnALnexnfsAC+gU1Su62/3cBF5fkprzDlaStI6m+g5WkqQ/cWZVktZRVV20amzs4EPOOmvZNUuXTuhrrlm6lEPOOmvZqrGxgy2qkjRxzqxKUleSfYBP38GnfllVj7ztB2eOjBw0a3T0Q8/fbrvZT58/f2STWbNu94U3rVrFN6+8cvykK65YsWps7ODV4+NHTEF0SRpYllVJ2gBJdpw7Onro2Pj4Pzzxfver7bbYYs6c7iWtLr/uuuXnXH11RkdGvrpsbOx9zqhK0rqzrErSJEiy5Uiy3+wZMx49MjKy+fj4+JIVa9ZcOl51fFVd2zqfJPUry6okSZJ6lidYSZIkqWdZViVJktSzLKuSJEnqWZZVSZIk9SzLqiRJknqWZVWSJEk9y7IqSZKknmVZlSRJUs+yrEqSJKlnWVYlSZLUsyyrkiRJ6lmWVUmSJPUsy6okSZJ6lmVVkiRJPcuyKkmSpJ5lWZUkSVLPsqxKkiSpZ1lWJUmS1LMsq5IkSepZllVJkiT1LMuqJEmSepZlVZIkST3LsipJkqSeZVmVJElSz7KsSpIkqWdZViVJktSzLKuSJEnqWZZVSZIk9SzLqiRJknqWZVWSJEk9y7IqSZKknmVZlSRJUs+yrEqSJKlnWVYlSZLUs/4/uG55ibqeppUAAAAASUVORK5CYII=\n", + "image/png": "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", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -327,16 +333,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "2023-06-08 10:05:39,732 INFO Started executing jobs locally\n", - "2023-06-08 10:05:39,737 INFO Starting job - time_website (76f9fef1-e2c7-4ad7-b090-b9153866c582)\n", - "2023-06-08 10:05:40,126 INFO Finished job - time_website (76f9fef1-e2c7-4ad7-b090-b9153866c582)\n", - "2023-06-08 10:05:40,128 INFO Starting job - time_website (f658ee45-b6e8-4078-98fd-9ab33a0c5747)\n", - "2023-06-08 10:05:40,306 INFO Finished job - time_website (f658ee45-b6e8-4078-98fd-9ab33a0c5747)\n", - "2023-06-08 10:05:40,307 INFO Starting job - time_website (3cd950be-b7f6-4991-84a2-420593dbe75c)\n", - "2023-06-08 10:05:40,792 INFO Finished job - time_website (3cd950be-b7f6-4991-84a2-420593dbe75c)\n", - "2023-06-08 10:05:40,793 INFO Starting job - sum_numbers (11b7679d-9d07-45b0-8c7b-f0bf42527ef0)\n", - "2023-06-08 10:05:40,798 INFO Finished job - sum_numbers (11b7679d-9d07-45b0-8c7b-f0bf42527ef0)\n", - "2023-06-08 10:05:40,799 INFO Finished executing jobs locally\n" + "2023-12-08 11:15:18,266 INFO Started executing jobs locally\n", + "2023-12-08 11:15:18,270 INFO Starting job - time_website (f7831f60-617e-490d-8854-ef3e25a78504)\n", + "2023-12-08 11:15:18,873 INFO Finished job - time_website (f7831f60-617e-490d-8854-ef3e25a78504)\n", + "2023-12-08 11:15:18,875 INFO Starting job - time_website (993990cd-872e-4c8f-823b-ac4eea8756c6)\n", + "2023-12-08 11:15:19,300 INFO Finished job - time_website (993990cd-872e-4c8f-823b-ac4eea8756c6)\n", + "2023-12-08 11:15:19,304 INFO Starting job - time_website (3c2d3abd-be33-4857-9943-6526bfb05804)\n", + "2023-12-08 11:15:19,774 INFO Finished job - time_website (3c2d3abd-be33-4857-9943-6526bfb05804)\n", + "2023-12-08 11:15:19,777 INFO Starting job - sum_numbers (2be44e87-0918-481f-ae77-7a5931074e1e)\n", + "2023-12-08 11:15:19,783 INFO Finished job - sum_numbers (2be44e87-0918-481f-ae77-7a5931074e1e)\n", + "2023-12-08 11:15:19,785 INFO Finished executing jobs locally\n" ] } ], @@ -404,10 +410,10 @@ { "data": { "text/plain": [ - "{'76f9fef1-e2c7-4ad7-b090-b9153866c582': {1: Response(output=0.07634975000000033, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", - " 'f658ee45-b6e8-4078-98fd-9ab33a0c5747': {1: Response(output=0.0056510840000001394, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", - " '3cd950be-b7f6-4991-84a2-420593dbe75c': {1: Response(output=0.15688537499999988, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", - " '11b7679d-9d07-45b0-8c7b-f0bf42527ef0': {1: Response(output=0.23888620900000035, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}" + "{'f7831f60-617e-490d-8854-ef3e25a78504': {1: Response(output=0.20485366717912257, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", + " '993990cd-872e-4c8f-823b-ac4eea8756c6': {1: Response(output=0.06472958298400044, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", + " '3c2d3abd-be33-4857-9943-6526bfb05804': {1: Response(output=0.18873387505300343, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)},\n", + " '2be44e87-0918-481f-ae77-7a5931074e1e': {1: Response(output=0.45831712521612644, detour=None, addition=None, replace=None, stored_data=None, stop_children=False, stop_jobflow=False)}}" ] }, "execution_count": 11, @@ -441,7 +447,7 @@ { "data": { "text/plain": [ - "0.07634975000000033" + "0.20485366717912257" ] }, "execution_count": 12, @@ -477,7 +483,7 @@ { "data": { "text/plain": [ - "0.07634975000000033" + "0.20485366717912257" ] }, "execution_count": 13, @@ -502,9 +508,9 @@ ], "metadata": { "kernelspec": { - "display_name": "atomate2", + "display_name": "jobflow-dev", "language": "python", - "name": "atomate2" + "name": "jobflow-dev" }, "language_info": { "codemirror_mode": { @@ -516,7 +522,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.10.12" } }, "nbformat": 4, From 090678827651ad5690abb5869b5ebd8235dc0764 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Fri, 8 Dec 2023 09:47:13 -0800 Subject: [PATCH 12/23] ruff auto-remove needless lambdas --- src/jobflow/core/store.py | 4 ++-- src/jobflow/settings.py | 2 +- src/jobflow/utils/find.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jobflow/core/store.py b/src/jobflow/core/store.py index e5707169..8899b78b 100644 --- a/src/jobflow/core/store.py +++ b/src/jobflow/core/store.py @@ -282,7 +282,7 @@ def update( from jobflow.utils.find import find_key, update_in_dictionary - if save in (None, True): + if save in {None, True}: save = self.save save_keys = _prepare_save(save) @@ -766,7 +766,7 @@ def _group_blobs(infos, locs): new_locations = [] for store_load in load.values(): for blob, location in zip(blob_infos, locations): - if store_load: + if store_load is True: new_blobs.append(blob) new_locations.append(location) elif isinstance(store_load, bool): diff --git a/src/jobflow/settings.py b/src/jobflow/settings.py index 8cb09153..620914e1 100644 --- a/src/jobflow/settings.py +++ b/src/jobflow/settings.py @@ -107,7 +107,7 @@ class JobflowSettings(BaseSettings): JOB_STORE: JobStore = Field( default_factory=lambda: JobStore( MemoryStore(), - additional_stores=defaultdict(lambda: _default_additional_store()), + additional_stores=defaultdict(_default_additional_store), ), description="Default JobStore to use when running locally or using FireWorks. " "See the :obj:`JobflowSettings` docstring for more details on the " diff --git a/src/jobflow/utils/find.py b/src/jobflow/utils/find.py index 43e6903d..5dfc98e9 100644 --- a/src/jobflow/utils/find.py +++ b/src/jobflow/utils/find.py @@ -233,7 +233,7 @@ def get_root_locations(locations): >>> _get_root_locations([["a", "b"], ["a"], ["c", "d"]]) [["a"], ["c", "d"]] """ - sorted_locs = sorted(locations, key=lambda x: len(x)) + sorted_locs = sorted(locations, key=len) root_locations = [] for loc in sorted_locs: if any(loc[: len(rloc)] == rloc for rloc in root_locations): From 7666ca6dea6bd7c732e08c10293b8fa08cc9ea90 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Fri, 8 Dec 2023 09:53:19 -0800 Subject: [PATCH 13/23] CI check for dead links in jupyter notebooks and markdown docs --- .github/workflows/link-check.yml | 29 +++++++++++++++++++++++++++++ paper/paper.md | 2 +- src/jobflow/core/store.py | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/link-check.yml diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml new file mode 100644 index 00000000..dd12e443 --- /dev/null +++ b/.github/workflows/link-check.yml @@ -0,0 +1,29 @@ +name: Check Links + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + check_links: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + pip install pytest-check-links nbconvert + + - name: Run link check + run: | + pytest --check-links **/**/*.md **/**/*.ipynb --check-links-ignore "https://www.gauss-centre.eu" diff --git a/paper/paper.md b/paper/paper.md index fb46383c..844062d9 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -206,6 +206,6 @@ Naturally, the summary presented in this article constitutes only a small subset # Acknowledgements -This work was primarily funded and intellectually led by the Materials Project, which is funded by the U.S. Department of Energy, Office of Science, Office of Basic Energy Sciences, Materials Sciences and Engineering Division, under Contract no. DE-AC02-05-CH11231: Materials Project program KC23MP. A.S.R. acknowledges support via a Miller Research Fellowship from the Miller Institute for Basic Research in Science, University of California, Berkeley. J.G would like to acknowledge the Gauss Centre for Supercomputing e.V. ([www.gauss-centre.eu](http://www.gauss-centre.eu/)) for funding workflow-related developments by providing generous computing time on the GCS Supercomputer SuperMUC-NG at Leibniz Supercomputing Centre ([www.lrz.de](http://www.lrz.de/)) (Project pn73da). J.R. acknowledges support from the German Academic Scholarship Foundation (Studienstiftung). M.L.E. thanks the BEWARE scheme of the Wallonia-Brussels Federation for funding under the European Commission's Marie Curie-Skłodowska Action (COFUND 847587). G.P. and D.W. acknowledge Umicore for the financial support in developing the remote execution mode of jobflow. D.W. and G.M.R. acknowledge funding from the European Union’s Horizon 2020 research and innovation program under the grant agreement No 951786 (NOMAD CoE). A.M.G. is supported by EPSRC Fellowship EP/T033231/1. +This work was primarily funded and intellectually led by the Materials Project, which is funded by the U.S. Department of Energy, Office of Science, Office of Basic Energy Sciences, Materials Sciences and Engineering Division, under Contract no. DE-AC02-05-CH11231: Materials Project program KC23MP. A.S.R. acknowledges support via a Miller Research Fellowship from the Miller Institute for Basic Research in Science, University of California, Berkeley. J.G would like to acknowledge the Gauss Centre for Supercomputing e.V. () for funding workflow-related developments by providing generous computing time on the GCS Supercomputer SuperMUC-NG at Leibniz Supercomputing Centre ([www.lrz.de](http://www.lrz.de/)) (Project pn73da). J.R. acknowledges support from the German Academic Scholarship Foundation (Studienstiftung). M.L.E. thanks the BEWARE scheme of the Wallonia-Brussels Federation for funding under the European Commission's Marie Curie-Skłodowska Action (COFUND 847587). G.P. and D.W. acknowledge Umicore for the financial support in developing the remote execution mode of jobflow. D.W. and G.M.R. acknowledge funding from the European Union’s Horizon 2020 research and innovation program under the grant agreement No 951786 (NOMAD CoE). A.M.G. is supported by EPSRC Fellowship EP/T033231/1. # References diff --git a/src/jobflow/core/store.py b/src/jobflow/core/store.py index 8899b78b..62143d4a 100644 --- a/src/jobflow/core/store.py +++ b/src/jobflow/core/store.py @@ -282,7 +282,7 @@ def update( from jobflow.utils.find import find_key, update_in_dictionary - if save in {None, True}: + if save in (None, True): save = self.save save_keys = _prepare_save(save) From 8384d30e6d56630ef1c4aa89e9d1cccf31c9389d Mon Sep 17 00:00:00 2001 From: Andrew-S-Rosen Date: Fri, 8 Dec 2023 12:22:15 -0800 Subject: [PATCH 14/23] Add store documentation --- docs/index.rst | 1 + docs/stores.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 docs/stores.md diff --git a/docs/index.rst b/docs/index.rst index 77edb054..2e5d92a0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,6 +6,7 @@ Install jobflow Install FireWorks (Optional) Tutorials + Configuring Data Stores .. toctree:: :caption: Information diff --git a/docs/stores.md b/docs/stores.md new file mode 100644 index 00000000..ceba9978 --- /dev/null +++ b/docs/stores.md @@ -0,0 +1,53 @@ +# Stores + +## Overview + +Jobflow relies on the [maggma package](https://github.com/materialsproject/maggma) to provide a unified interface to a variety of data stores. By default, all calculations are run using a `MemoryStore`, which persists solely in the current process' memory. In production calculations, one will generally want to use a persistent data store, such as a MongoDB database. This also allows one to run calculations in a distributed manner with a common data store. + +For a list of all available data stores, refer to the [maggma documentation](https://materialsproject.github.io/maggma/getting_started/stores/#list-of-stores). Here, we will go over how to use Jobflow with MongoDB via a [`MongoStore`](https://materialsproject.github.io/maggma/reference/stores/#maggma.stores.mongolike.MemoryStore). + +## Configuring a `MongoStore` + +### Creating a `jobflow.yaml` File + +To modify basic Jobflow settings, you will first need to make a `jobflow.yaml` file if you haven't done so already. You will then need to define a `JOBFLOW_CONFIG_FILE` environment variable pointing to the file you made. For instance, in your `~/.bashrc` file, add the following line: + +```bash +export JOBFLOW_CONFIG_FILE="/path/to/my/jobflow.yaml" +``` + +If this environment variable is not specified, Jobflow will look for the file in `~/.jobflow.yaml`. + +### Basic Configuration + +In your `jobflow.yaml` copy the example below and fill in the fields with the appropriate values for a MongoDB store. + +```yaml title="jobflow.yaml" +JOB_STORE: + docs_store: + type: MongoStore + host: + port: 27017 + username: + password: + database: + collection_name: +``` + +### MongoDB Atlas + +If you are using a URI (as is common with MongoDB Atlas), then you will instead have a `jobflow.yaml` file that looks like the example below. Here, you will put the full URI in the `host` field. The `username` and `password` are part of the URI and so should not be included elsewhere in the YAML file. + +```yaml title="jobflow.yaml" +JOB_STORE: + docs_store: + type: MongoStore + host: + port: 27017 + database: + collection_name: +``` + +## Additional Details + +For additional details on how to specify a data store as well as the various settings available to modify in Jobflow, refer to the [API documentation](https://materialsproject.github.io/jobflow/jobflow.settings.html) for `jobflow.settings`. From 1badc258ad5f8df78cf5b29c5c5e9682e973ecb3 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Sun, 10 Dec 2023 16:09:42 +0000 Subject: [PATCH 15/23] Create docs.yml --- .github/workflows/docs.yml | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..d66dfb87 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,55 @@ +name: build-docs + +on: + workflow_dispatch: + push: + branches: [main] + +# set GITHUB_TOKEN permissions to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +jobs: + build-docs: + if: github.repository_owner == 'materialsproject' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.workflow_run.head_branch }} + + - name: Install pandoc + run: sudo apt-get install pandoc + + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + cache: pip + cache-dependency-path: pyproject.toml + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install .[strict,docs] + + - name: Build + run: sphinx-build docs docs_build + + - name: Upload build artifact + uses: actions/upload-pages-artifact@v2 + with: + path: ./docs_build + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build-docs + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 From 7524ccab9c2f1cd39d345dd05952d34a1f525a16 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Sun, 10 Dec 2023 16:10:32 +0000 Subject: [PATCH 16/23] Delete .github/workflows/docs_manual.yml --- .github/workflows/docs_manual.yml | 38 ------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 .github/workflows/docs_manual.yml diff --git a/.github/workflows/docs_manual.yml b/.github/workflows/docs_manual.yml deleted file mode 100644 index fcaaf36d..00000000 --- a/.github/workflows/docs_manual.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: build-docs - -on: - workflow_dispatch: - -jobs: - - build-docs: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.workflow_run.head_branch }} - - - name: Install pandoc - run: sudo apt-get install pandoc - - - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: pip - cache-dependency-path: pyproject.toml - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install .[strict,docs] - - - name: Build - run: sphinx-build docs docs_build - - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - with: - deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} - publish_dir: ./docs_build From 729b4070fe7a1cc8fd782f089776cacec6586b58 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Sun, 10 Dec 2023 16:12:15 +0000 Subject: [PATCH 17/23] Update deploy.yml --- .github/workflows/deploy.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7aa30979..656524a2 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -81,7 +81,9 @@ jobs: ref: ${{ github.event.workflow_run.head_branch }} - name: Write release info - run: awk 'BEGIN {p = 0} {a = 0 }; /^v\d*.\d*.\d*./ { p += 1; a = 1}; p + a == 1 { print } ' CHANGELOG.md | sed -e '1,1d' | sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba' -e '}' > release_info.txt + awk 'BEGIN {p = 0} {a = 0 }; /^\#\#\ v\d*.\d*.\d*./ { p += 1; a = 1}; p + a == 1 { print } ' CHANGELOG.md | sed -e '1,1d' | sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba' -e '}' > release_info.txt + echo "" >> release_info.txt + awk '/CONTRIBUTOR SECTION/{f=1; c=0} f' CHANGELOG.md >> release_info.txt - name: Release uses: actions/create-release@v1 From ebe0130845fb12a2e33272351570c3a3c11ed747 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Sun, 10 Dec 2023 16:20:09 +0000 Subject: [PATCH 18/23] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3ac99790..ae0d6d64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ description = "jobflow is a library for writing computational workflows" readme = "README.md" keywords = ["high-throughput", "workflow"] license = { text = "modified BSD" } -authors = [{ name = "Alex Ganose", email = "alexganose@gmail.com" }] +authors = [{ name = "Alex Ganose", email = "a.ganose@imperial.ac.uk" }] dynamic = ["version"] classifiers = [ "Development Status :: 5 - Production/Stable", From ae609e0afa5aea9c28086fd60c267482ab6ddbf0 Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Sun, 10 Dec 2023 16:23:34 +0000 Subject: [PATCH 19/23] Update deploy.yml --- .github/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 656524a2..4f28238a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,7 +10,7 @@ jobs: deploy-docs: # only run if commit is a push to master and the testing finished - if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && startsWith(github.event.workflow_run.head_branch, 'v0.') }} + if: ${{ github.repository_owner == 'materialsproject' && github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && startsWith(github.event.workflow_run.head_branch, 'v0.') }} runs-on: ubuntu-latest steps: @@ -44,7 +44,7 @@ jobs: deploy-pypi: # only run if commit is tagged as a version and the docs finished - if: ${{ startsWith(github.event.workflow_run.head_branch, 'v') }} + if: github.repository_owner == 'materialsproject' && github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && startsWith(github.event.workflow_run.head_branch, 'v0.') runs-on: ubuntu-latest needs: - deploy-docs From 6f4d5121d05d2ff92da088900fc1c04859c0d97e Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Sun, 10 Dec 2023 16:27:59 +0000 Subject: [PATCH 20/23] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e893a016..9d2a61ee 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -46,4 +46,5 @@ Before a pull request can be merged, the following items must be checked: Note that the CI system will run all the above checks. But it will be much more efficient if you already fix most errors prior to submitting the PR. It is highly recommended that you use the pre-commit hook provided in the repository. Simply -`cp pre-commit .git/hooks` and a check will be run prior to allowing commits. +`pip install pre-commit` and then `pre-commit install` and a check will be run +prior to allowing commits. From ad2dbb8fe0c13870417a3a4c0823fb6245fda11e Mon Sep 17 00:00:00 2001 From: Alex Ganose Date: Sun, 10 Dec 2023 16:30:52 +0000 Subject: [PATCH 21/23] Fix linting --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9d2a61ee..100d80a3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -46,5 +46,5 @@ Before a pull request can be merged, the following items must be checked: Note that the CI system will run all the above checks. But it will be much more efficient if you already fix most errors prior to submitting the PR. It is highly recommended that you use the pre-commit hook provided in the repository. Simply -`pip install pre-commit` and then `pre-commit install` and a check will be run +`pip install pre-commit` and then `pre-commit install` and a check will be run prior to allowing commits. From bdf3d3b40968fe3e1a83f894427be630fb012c0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 23:15:49 +0000 Subject: [PATCH 22/23] Bump maggma from 0.58.0 to 0.59.0 Bumps [maggma](https://github.com/materialsproject/maggma) from 0.58.0 to 0.59.0. - [Release notes](https://github.com/materialsproject/maggma/releases) - [Changelog](https://github.com/materialsproject/maggma/blob/main/docs/CHANGELOG.md) - [Commits](https://github.com/materialsproject/maggma/compare/v0.58.0...v0.59.0) --- updated-dependencies: - dependency-name: maggma dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ae0d6d64..87863617 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ fireworks = ["FireWorks"] strict = [ "FireWorks==2.0.3", "PyYAML==6.0.1", - "maggma==0.58.0", + "maggma==0.59.0", "matplotlib==3.8.2", "monty==2023.11.3", "moto==4.2.11", From 758a0c865bda2ed42bff7db61c161c2b78bde2f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 23:15:54 +0000 Subject: [PATCH 23/23] Bump typing-extensions from 4.8.0 to 4.9.0 Bumps [typing-extensions](https://github.com/python/typing_extensions) from 4.8.0 to 4.9.0. - [Release notes](https://github.com/python/typing_extensions/releases) - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - [Commits](https://github.com/python/typing_extensions/compare/4.8.0...4.9.0) --- updated-dependencies: - dependency-name: typing-extensions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ae0d6d64..e294e844 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ strict = [ "pydantic==2.5.2", "pydash==7.0.6", "pydot==1.4.2", - "typing-extensions==4.8.0", + "typing-extensions==4.9.0", ] [project.urls]