From d80f17d96f2302609913f55763052efa55e0fb59 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Fri, 8 Dec 2023 09:41:20 -0800 Subject: [PATCH 01/15] 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 02/15] 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 03/15] 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 04/15] 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 05/15] 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": "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\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 06/15] 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 07/15] 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 08/15] 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 09/15] 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 10/15] 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 11/15] 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 12/15] 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 13/15] 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 14/15] 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 15/15] 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.