From fa3392fb7d257a587fbe50438a11088b29626e60 Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Thu, 16 May 2024 15:45:49 +0200 Subject: [PATCH 01/10] Use generate_docstring_hpp.py of opm-common and delete the one here --- python/generate_docstring_hpp.py | 41 -------------------------------- python/simulators/CMakeLists.txt | 9 +++++-- 2 files changed, 7 insertions(+), 43 deletions(-) delete mode 100755 python/generate_docstring_hpp.py diff --git a/python/generate_docstring_hpp.py b/python/generate_docstring_hpp.py deleted file mode 100755 index 9c1d7f632c4..00000000000 --- a/python/generate_docstring_hpp.py +++ /dev/null @@ -1,41 +0,0 @@ -import json -import sys - -def generate_hpp_from_json(json_path: str, output_hpp_path: str): - with open(json_path, 'r', encoding='utf-8') as file: - docstrings = json.load(file) - - hpp_content = """\ -#ifndef PYBLACKOILSIMULATORDOC_HPP -#define PYBLACKOILSIMULATORDOC_HPP - -// Generated docstrings for PyBlackOilSimulator -namespace Opm::Pybind::DocStrings { -""" - - for func_name, info in docstrings.items(): - signature = info['signature'] - doc = info['doc'].replace('\n', '\n ') - hpp_content += f""" -static constexpr char {func_name}_docstring[] = R\"doc( -{doc} -)doc\";\n""" - - hpp_content += """\ -} // namespace Opm::Pybind::DocStrings - -#endif // PYBLACKOILSIMULATORDOC_HPP -""" - - with open(output_hpp_path, 'w', encoding='utf-8') as file: - file.write(hpp_content) - -if __name__ == "__main__": - # Check that exactly two command line arguments are provided - if len(sys.argv) != 3: - print("Usage: python generate_docstring_hpp.py ") - sys.exit(1) - # Extract json_path and output_hpp_path from command line arguments - json_path = sys.argv[1] - output_hpp_path = sys.argv[2] - generate_hpp_from_json(json_path, output_hpp_path) diff --git a/python/simulators/CMakeLists.txt b/python/simulators/CMakeLists.txt index 672bbc0ad47..3538649d181 100644 --- a/python/simulators/CMakeLists.txt +++ b/python/simulators/CMakeLists.txt @@ -7,11 +7,16 @@ set(PYTHON_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyBlackOilSimu # ${PYTHON_EXECUTABLE} is set there to ${Python3_EXECUTABLE} # # Command to run the Python script + +find_file(PYTHON_GENERATE_DOCSTRINGS_PY generate_docstring_hpp.py + PATHS ${opm-common_DIR} ${opm-common_PYTHON_COMMON_DIR} + PATH_SUFFIXES python NO_DEFAULT_PATH REQUIRED) + add_custom_command( OUTPUT ${PYTHON_DOCSTRINGS_GENERATED_HPP} COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_SOURCE_DIR} - ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/python/generate_docstring_hpp.py - ${PYTHON_DOCSTRINGS_FILE} ${PYTHON_DOCSTRINGS_GENERATED_HPP} + ${PYTHON_EXECUTABLE} ${PYTHON_GENERATE_DOCSTRINGS_PY} + ${PYTHON_DOCSTRINGS_FILE} ${PYTHON_DOCSTRINGS_GENERATED_HPP} PYBLACKOILSIMULATORDOC_HPP "Opm::Pybind::DocStrings" DEPENDS ${PYTHON_DOCSTRINGS_FILE} COMMENT "Generating PyBlackOilSimulatorDoc.hpp from JSON file" ) From 22c44a71938da14cf7b507eae38a3a09fe6b46e0 Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Thu, 16 May 2024 06:18:52 +0200 Subject: [PATCH 02/10] Update python version --- .github/workflows/python_sphinx_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index 06caf423fe2..514f4bece84 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -22,7 +22,7 @@ jobs: with: fetch-depth: 0 # Fetch all history for all tags and branches - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install poetry From e6dffd8a92f5cfcfb9f62520d1ec8e1a29dbe904 Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Thu, 16 May 2024 06:24:54 +0200 Subject: [PATCH 03/10] Move html files to python/gh-pages --- .github/workflows/python_sphinx_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index 514f4bece84..4fc89546392 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -44,7 +44,7 @@ jobs: poetry run sphinx-versioned -m master -b master --git-root ../../ - name: Copy documentation to gh-pages run: | - cp -r python/sphinx_docs/docs/_build/* gh-pages/ + cp -r python/sphinx_docs/docs/_build/* python/gh-pages/ - name: Deploy documentation if: ${{ github.event_name == 'push' }} uses: JamesIves/github-pages-deploy-action@v4 From 7e1c72759d241cdf56f78ce47e573d3900f64dc1 Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Thu, 16 May 2024 15:46:33 +0200 Subject: [PATCH 04/10] Build documentation at push and pull_request to master --- .github/workflows/python_sphinx_docs.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index 4fc89546392..e9bd6813c6d 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -2,12 +2,12 @@ name: Build Python Sphinx Docs and push to gh-pages on: push: - branches: main + branches: master paths: - 'python/**' - '.github/workflows/python_sphinx_docs.yml' pull_request: - branches: main + branches: master paths: - 'python/**' - '.github/workflows/python_sphinx_docs.yml' @@ -17,7 +17,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: checkout source code + - name: Checkout source code uses: actions/checkout@v4 with: fetch-depth: 0 # Fetch all history for all tags and branches @@ -39,8 +39,8 @@ jobs: cd sphinx_docs # Currently we build only docs for the HEAD of the master branch # Later we can add release tags to the list to get the docs for the releases - # For example: -b "main, release/2024.04/final" will build the docs for - # the main branch and the release/2024.04/final tag + # For example: -b "master, release/2024.04/final" will build the docs for + # the master branch and the release/2024.04/final tag poetry run sphinx-versioned -m master -b master --git-root ../../ - name: Copy documentation to gh-pages run: | From 64a8f1e457ae73fdda78d287397f5ceecd816810 Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Wed, 26 Jun 2024 07:18:16 +0200 Subject: [PATCH 05/10] Add Directive for OPM Common and OPM Embedded A rebuild of the documentation is also triggered when the file docstrings_common.json is updated in opm-common --- .github/workflows/python_sphinx_docs.yml | 6 +- .gitignore | 3 + ...trings.json => docstrings_simulators.json} | 45 ++++++----- python/simulators/CMakeLists.txt | 13 +++- python/sphinx_docs/docs/common.rst | 4 + python/sphinx_docs/docs/conf.py | 5 +- python/sphinx_docs/docs/embedded.rst | 54 +++++++++++++ python/sphinx_docs/docs/index.rst | 14 +++- python/sphinx_docs/docs/introduction.rst | 5 +- python/sphinx_docs/docs/python.rst | 4 - python/sphinx_docs/docs/simulators.rst | 4 + .../sphinx_ext_docstrings.py | 76 +++++++++++-------- 12 files changed, 169 insertions(+), 64 deletions(-) rename python/{docstrings.json => docstrings_simulators.json} (70%) create mode 100644 python/sphinx_docs/docs/common.rst create mode 100644 python/sphinx_docs/docs/embedded.rst delete mode 100644 python/sphinx_docs/docs/python.rst create mode 100644 python/sphinx_docs/docs/simulators.rst diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index e9bd6813c6d..3a7ca28a59f 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -11,6 +11,8 @@ on: paths: - 'python/**' - '.github/workflows/python_sphinx_docs.yml' + repository_dispatch: + types: [docstrings_common_updated] permissions: contents: write jobs: @@ -21,6 +23,9 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 # Fetch all history for all tags and branches + - name: Get docstrings_common.json from opm-common + run: | + curl -L -o python/docstrings_common.json https://raw.githubusercontent.com/${{ github.repository_owner }}/opm-common/master/python/docstrings_common.json - name: Set up Python uses: actions/setup-python@v5 with: @@ -46,7 +51,6 @@ jobs: run: | cp -r python/sphinx_docs/docs/_build/* python/gh-pages/ - name: Deploy documentation - if: ${{ github.event_name == 'push' }} uses: JamesIves/github-pages-deploy-action@v4 with: branch: gh-pages diff --git a/.gitignore b/.gitignore index beab3e67455..7e00280e927 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,9 @@ build/ # Python sphinx build python/sphinx_docs/docs/_build/ +# docstrings_common.json - this is copied over from opm-common and not tracked here +python/docstrings_common.json + # Python cache directories **/__pycache__/ diff --git a/python/docstrings.json b/python/docstrings_simulators.json similarity index 70% rename from python/docstrings.json rename to python/docstrings_simulators.json index c3717f927e8..1f0edf226ca 100644 --- a/python/docstrings.json +++ b/python/docstrings_simulators.json @@ -1,78 +1,83 @@ { + "PyBlackOilSimulator":{ + "type": "class", + "signature": "opm.simulators.BlackOilSimulator", + "doc": "The SummaryState class - this is where the current summary results of the simulator are stored.\nThe SummaryState class has methods to get hold of well, group and general variables." + }, "PyBlackOilSimulator_filename_constructor": { - "signature": "__init__(deck_filename: str) -> None", + "signature": "opm.simulators.BlackOilSimulator.__init__(deck_filename: str) -> None", "doc": "Constructor using a deck file name.\n\n:param deck_filename: The file name of the deck to be used for the simulation.\n:type deck_filename: str" }, "PyBlackOilSimulator_objects_constructor": { - "signature": "__init__(deck: Deck, state: EclipseState, schedule: Schedule, summary_config: SummaryConfig) -> None", + "signature": "opm.simulators.BlackOilSimulator.__init__(deck: Deck, state: EclipseState, schedule: Schedule, summary_config: SummaryConfig) -> None", "doc": "Constructor using Deck, EclipseState, Schedule, and SummaryConfig objects.\n\n:param deck: Deck object.\n:type deck: Deck\n:param state: EclipseState object.\n:type state: EclipseState\n:param schedule: Schedule object.\n:type schedule: Schedule\n:param summary_config: SummaryConfig object.\n:type summary_config: SummaryConfig" }, "advance": { - "signature": "advance(report_step: int) -> None", + "signature": "opm.simulators.BlackOilSimulator.advance(report_step: int) -> None", "doc": "Advance the simulation to a specific report step.\n\n:param report_step: Target report step to advance to.\n:type report_step: int" }, "checkSimulationFinished": { - "signature": "check_simulation_finished() -> bool", + "signature": "opm.simulators.BlackOilSimulator.check_simulation_finished() -> bool", "doc": "Check if the simulation has finished.\n\n:return: True if the simulation is finished, False otherwise." }, "currentStep": { - "signature": "current_step() -> int", + "signature": "opm.simulators.BlackOilSimulator.current_step() -> int", "doc": "Get the current simulation step.\n\n:return: The current step number." }, "getCellVolumes": { - "signature": "get_cell_volumes() -> NDArray[float]", + "signature": "opm.simulators.BlackOilSimulator.get_cell_volumes() -> NDArray[float]", "doc": "Retrieve the cell volumes of the simulation grid.\n\n:return: An array of cell volumes.\n:type return: NDArray[float]" }, "getDT": { - "signature": "get_dt() -> float", + "signature": "opm.simulators.BlackOilSimulator.get_dt() -> float", "doc": "Get the timestep size of the last completed step.\n\n:return: Timestep size in days.\n:type return: float" }, "getFluidStateVariable": { - "signature": "get_fluid_state_variable(name: str) -> NDArray[float]", + "signature": "opm.simulators.BlackOilSimulator.get_fluid_state_variable(name: str) -> NDArray[float]", "doc": "Retrieve a fluid state variable for the simulation grid.\n\n:param name: The name of the variable. Valid names are 'pw' (pressure water), 'pg' (pressure gas), 'po' (pressure oil), 'rho_w' (density water), 'rho_g' (density gas), 'rho_o' (density oil)'Rs' (soultion gas-oil ratio), 'Rv' (volatile gas-oil ratio), 'Sw' (water saturation), 'Sg' (gas saturation), 'So' (oil saturation), and 'T' (temperature).\n:type name: str\n\n:return: An array of fluid state variables.\n:type return: NDArray[float]" }, "getPorosity": { - "signature": "get_porosity() -> numpy.ndarray", + "signature": "opm.simulators.BlackOilSimulator.get_porosity() -> NDArray[float]", "doc": "Retrieve the porosity values of the simulation grid.\n\n:return: An array of porosity values.\n:type return: numpy.ndarray" }, "getPrimaryVarMeaning": { - "signature": "get_primary_var_meaning(variable: str) -> NDArray[int]", + "signature": "opm.simulators.BlackOilSimulator.get_primary_var_meaning(variable: str) -> NDArray[int]", "doc": "Retrieve the primary variable meaning of the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: An array of primary variable meanings. See ``get_primary_variable_meaning_map()`` for more information.\n:type return: NDArray[int]" }, "getPrimaryVarMeaningMap": { - "signature": "get_primary_var_meaning_map(variable: str) -> dict[str, int]", + "signature": "opm.simulators.BlackOilSimulator.get_primary_var_meaning_map(variable: str) -> dict[str, int]", "doc": "Retrieve the primary variable meaning map for each primary variable.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: A dictionary of primary variable meanings. The keys are the primary variable meanings and the values are the corresponding integer codes. The integer codes are used to represent the primary variable meanings in the simulation grid. For variable name 'pressure', the valid keys are: 'Po', 'Pg', and 'Pw', for variable name 'water', the valid keys are: 'Sw', 'Rvw', 'Rsw', and 'Disabled', for variable name 'gas', the valid keys are: 'Sg', 'Rs', 'Rv', and 'Disabled', for variable name 'brine', the valid keys are: 'Cs', 'Sp', and 'Disabled'.\n:type return: dict[str, int]" }, "getPrimaryVariable": { - "signature": "get_primary_variable(variable: str) -> NDArray[float]", + "signature": "opm.simulators.BlackOilSimulator.get_primary_variable(variable: str) -> NDArray[float]", "doc": "Retrieve the primary variable's values for the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: An array of primary variable values. See ``get_primary_variable_meaning()`` for more information.\n:type return: NDArray[float]" }, "run": { - "signature": "run() -> int", + "signature": "opm.simulators.BlackOilSimulator.run() -> int", "doc": "Runs the simulation to completion with the provided deck file or previously set deck.\n\n:return: EXIT_SUCCESS if the simulation completes successfully." }, "setPorosity": { - "signature": "set_porosity(array: NDArray[float]) -> None", + "signature": "opm.simulators.BlackOilSimulator.set_porosity(array: NDArray[float]) -> None", "doc": "Set the porosity values for the simulation grid.\n\n:param array: An array of porosity values to be set.\n:type array: NDArray[float]" }, "setPrimaryVariable": { - "signature": "set_primary_variable(variable: str, value: NDArray[float]) -> None", + "signature": "opm.simulators.BlackOilSimulator.set_primary_variable(variable: str, value: NDArray[float]) -> None", "doc": "Set the primary variable's values for the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n:param value: An array of primary variable values to be set. See ``get_primary_variable()`` for more information.\n:type value: NDArray[float]" }, "setupMpi": { - "signature": "mpi_init(init: bool, finalize: bool) -> None", + "signature": "opm.simulators.BlackOilSimulator.mpi_init(init: bool, finalize: bool) -> None", "doc": "Setup MPI for parallel simulation. This method should be called before any other method.\n:param init: Whether to call ``MPI_Init()`` or not.\n:param finalize:Whether to call ``MPI_Finalize()```when the simulator object goes out of scope.\n\n:return: None" }, "step": { - "signature": "step() -> int", + "signature": "opm.simulators.BlackOilSimulator.step() -> int", "doc": "Execute the next simulation report step.\n\n:return: Result of the simulation step." }, "stepCleanup": { - "signature": "step_cleanup() -> int", + "signature": "opm.simulators.BlackOilSimulator.step_cleanup() -> int", "doc": "Perform cleanup after the last simulation step.\n\n:return: EXIT_SUCCESS if cleanup is successful." }, "stepInit": { - "signature": "step_init() -> int", + "signature": "opm.simulators.BlackOilSimulator.step_init() -> int", "doc": "Initialize the simulation before taking the first report step. This method should be called before the first call to ``step()``\n\n:return: EXIT_SUCCESS if the initialization is successful." } -} \ No newline at end of file +} diff --git a/python/simulators/CMakeLists.txt b/python/simulators/CMakeLists.txt index 3538649d181..fb678c2be1c 100644 --- a/python/simulators/CMakeLists.txt +++ b/python/simulators/CMakeLists.txt @@ -1,7 +1,7 @@ set(PYTHON_OPM_SIMULATORS_PACKAGE_PATH ${PROJECT_BINARY_DIR}/python/opm/simulators) # Set the path to the input docstrings.json file and the output .hpp file -set(PYTHON_DOCSTRINGS_FILE "${PROJECT_SOURCE_DIR}/python/docstrings.json") +set(PYTHON_DOCSTRINGS_FILE "${PROJECT_SOURCE_DIR}/python/docstrings_simulators.json") set(PYTHON_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyBlackOilSimulatorDoc.hpp") # Note: If the new find_package(Python3) is used in the top level CMakeLists.txt, the variable # ${PYTHON_EXECUTABLE} is set there to ${Python3_EXECUTABLE} @@ -20,6 +20,17 @@ add_custom_command( DEPENDS ${PYTHON_DOCSTRINGS_FILE} COMMENT "Generating PyBlackOilSimulatorDoc.hpp from JSON file" ) + +# This file from opm-common is needed to build the documentation using Sphinx +# For local builds of the documentation, it is copied to opm-simulators from opm-common +# For the online documentation, this file is copied using a github Action +# This file is not tracked by git here, it is in the .gitignore +find_file(DOCSTRINGS_JSON docstrings_common.json + PATHS ${opm-common_DIR} ${opm-common_PYTHON_COMMON_DIR} + PATH_SUFFIXES python NO_DEFAULT_PATH REQUIRED) + +configure_file(${DOCSTRINGS_JSON} ${PROJECT_SOURCE_DIR}/python/docstrings_common.json COPYONLY) + # NOTE: The variable ${PYBIND11_SYSTEM} is set in python/CMakeLists.txt # to the value "SYSTEM" or unset, depending on the current version of Pybind11. # The value is then forwarded to target_include_directories(), see diff --git a/python/sphinx_docs/docs/common.rst b/python/sphinx_docs/docs/common.rst new file mode 100644 index 00000000000..c28c406d0b9 --- /dev/null +++ b/python/sphinx_docs/docs/common.rst @@ -0,0 +1,4 @@ +OPM Common Python Documentation +=============================== + +.. opm_common_docstrings:: diff --git a/python/sphinx_docs/docs/conf.py b/python/sphinx_docs/docs/conf.py index ae6feab46d9..110fb800a61 100644 --- a/python/sphinx_docs/docs/conf.py +++ b/python/sphinx_docs/docs/conf.py @@ -1,6 +1,6 @@ # Configuration file for the Sphinx documentation builder. -project = "opm.simulators" +project = "OPM Python Documentation" copyright = "2024 Equinor ASA" author = "Håkon Hægland" @@ -36,7 +36,8 @@ def extract_opm_simulators_release(): # Our sphinx extension that will use the docstrings.json file to generate documentation extensions = ["opm_simulators_docs.sphinx_ext_docstrings"] # Path to docstrings.json -opm_simulators_docstrings_path = os.path.abspath('../../docstrings.json') +opm_simulators_docstrings_path = os.path.abspath('../../docstrings_simulators.json') +opm_common_docstrings_path = os.path.abspath('../../docstrings_common.json') templates_path = ["_templates"] exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] diff --git a/python/sphinx_docs/docs/embedded.rst b/python/sphinx_docs/docs/embedded.rst new file mode 100644 index 00000000000..011c99ba218 --- /dev/null +++ b/python/sphinx_docs/docs/embedded.rst @@ -0,0 +1,54 @@ +OPM Embedded Python Documentation +================================= + +The PYACTION keyword is a flow specific keyword which allows for executing embedded Python +code in the SCHEDULE section. The embedded Python code will then be executed at the end of each successful timestep. + +The PYACTION keyword is inspired +by the ACTIONX keyword, but instead of a .DATA formatted condition you +are allowed to implement the condition with a general Python script. The +ACTIONX keywords are very clearly separated in a condition part and an +action part in the form of a list of keywords which are effectively injected in +the SCHEDULE section when the condition evaluates to true. +This is not so for PYACTION where there is one Python script in which both +conditions can be evaluated and changes applied. + +In order to enable the PYACTION keyword: + +1. OPM flow must be compiled with the cmake switches -DOPM ENABLE EMBEDDED PYTHON=ON and -DOPM ENABLE PYTHON=ON, the default is to build with these switches set to OFF. + +2. The keyword PYACTION must be added to the SCHEDULE section: + +.. code-block:: python + + / + / -- path to the python script, relative to the location of the DATA-file + +3. You need to provide the Python script. + + +To interact with the simulator in the embedded Python code, you can access four variables from the simulator: + +.. code-block:: python + + # Python module opm_embedded + import opm_embedded + # The current EclipseState + ecl_state = opm_embedded.current_ecl_state + # The current Schedule + schedule = opm_embedded.current_schedule + # The current SummaryState + summary_state = opm_embedded.current_summary_state + # The current report step + report_step = opm_embedded.current_report_step + + +- current_ecl_state: An instance of the `EclipseState `_ class - this is a representation of all static properties in the model, ranging from porosity to relperm tables. The content of the ecl state is immutable - you are not allowed to change the static properties at runtime. + +- current_schedule: An instance of the `Schedule `_ class - this is a representation of all the content from the SCHEDULE section, notably all well and group information and the timestepping. + +- current_report_step: This is an integer for the report step we are currently working on. Observe that the PYACTION is called for every simulator timestep, i.e. it will typically be called multiple times with the same value for the report step argument. + +- current_summary_state: An instance of the `SummaryState `_ class, this is where the current summary results of the simulator are stored. The SummaryState class has methods to get hold of well, group and general variables. + +See also: PYACTION in the `reference manual `_ for more information. diff --git a/python/sphinx_docs/docs/index.rst b/python/sphinx_docs/docs/index.rst index e97b5938104..b3a1ec4cea0 100644 --- a/python/sphinx_docs/docs/index.rst +++ b/python/sphinx_docs/docs/index.rst @@ -1,13 +1,19 @@ -Welcome to the Python documentation for opm-simulators! -======================================================= +Welcome to the Python documentation for OPM Flow! +================================================= + +There are two Python APIs within OPM Flow: +- running flow from Python code using the Python bindings +- running a Python script embedded in a simulation .. toctree:: :maxdepth: 1 :caption: Contents: introduction - python - + common + simulators + embedded + Indices and tables ================== diff --git a/python/sphinx_docs/docs/introduction.rst b/python/sphinx_docs/docs/introduction.rst index a9237774096..5b8bb5c258a 100644 --- a/python/sphinx_docs/docs/introduction.rst +++ b/python/sphinx_docs/docs/introduction.rst @@ -1,4 +1,7 @@ Introduction ============ -Documentation for the ``opm.simulators`` Python module. \ No newline at end of file +Documentation for the OPM Python interfaces. + +#TODO: expand on the introduction, add information about installation and requirements for example. Some example code would also be nice. + diff --git a/python/sphinx_docs/docs/python.rst b/python/sphinx_docs/docs/python.rst deleted file mode 100644 index df0f99cf40a..00000000000 --- a/python/sphinx_docs/docs/python.rst +++ /dev/null @@ -1,4 +0,0 @@ -Python Module Documentation -=========================== - -.. opm_simulators_docstrings:: diff --git a/python/sphinx_docs/docs/simulators.rst b/python/sphinx_docs/docs/simulators.rst new file mode 100644 index 00000000000..61b64fee0ed --- /dev/null +++ b/python/sphinx_docs/docs/simulators.rst @@ -0,0 +1,4 @@ +OPM Simulators Python Documentation +=================================== + +.. opm_simulators_docstrings:: diff --git a/python/sphinx_docs/src/opm_simulators_docs/sphinx_ext_docstrings.py b/python/sphinx_docs/src/opm_simulators_docs/sphinx_ext_docstrings.py index a8c0734db83..32418f13d5a 100644 --- a/python/sphinx_docs/src/opm_simulators_docs/sphinx_ext_docstrings.py +++ b/python/sphinx_docs/src/opm_simulators_docs/sphinx_ext_docstrings.py @@ -4,43 +4,57 @@ from sphinx.util.docutils import SphinxDirective from docutils import nodes -class PybindDocstringsDirective(SphinxDirective): +def read_doc_strings(directive, docstrings_path): + print(docstrings_path) + with open(docstrings_path, 'r') as file: + docstrings = json.load(file) + result = [] + for name, item in docstrings.items(): + # Create a ViewList instance for the function signature and docstring + rst = ViewList() + + # Check if signature exists and prepend it to the docstring + signature = item.get('signature', '') + item_type = item.get('type', 'method') + signature_line = f".. py:{item_type}:: {signature}" if signature else f".. py:{item_type}:: {name}()" + rst.append(signature_line, source="") + rst.append("", source="") + + # Add the docstring text if it exists + docstring = item.get('doc', '') + if docstring: + for line in docstring.split('\n'): + rst.append(f" {line}", source="") + + # Create a node that will be populated by nested_parse_with_titles + node = nodes.section() + node.document = directive.state.document + # Parse the rst content + nested_parse_with_titles(directive.state, rst, node) + + result.extend(node.children) + return result + +class SimulatorsDirective(SphinxDirective): + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def run(self): + return read_doc_strings(self, self.state.document.settings.env.app.config.opm_simulators_docstrings_path) + +class CommonDirective(SphinxDirective): required_arguments = 0 optional_arguments = 0 final_argument_whitespace = False option_spec = {} def run(self): - env = self.state.document.settings.env - docstrings_path = env.app.config.opm_simulators_docstrings_path - with open(docstrings_path, 'r') as file: - docstrings = json.load(file) - result = [] - for func_name, doc_info in docstrings.items(): - signature = doc_info.get('signature', '') - docstring = doc_info.get('doc', '') - - # Create a ViewList instance for the function signature and docstring - rst = ViewList() - - # Check if signature exists and prepend it to the docstring - signature_line = f".. py:function:: {signature}" if signature else f".. py:function:: {func_name}()" - rst.append(signature_line, source="") - rst.append("", source="") - # Add the docstring text if it exists - if docstring: - for line in docstring.split('\n'): - rst.append(f" {line}", source="") - - # Create a node that will be populated by nested_parse_with_titles - node = nodes.section() - node.document = self.state.document - # Parse the rst content - nested_parse_with_titles(self.state, rst, node) - - result.extend(node.children) - return result + return read_doc_strings(self, self.state.document.settings.env.app.config.opm_common_docstrings_path) def setup(app): app.add_config_value('opm_simulators_docstrings_path', None, 'env') - app.add_directive("opm_simulators_docstrings", PybindDocstringsDirective) + app.add_config_value('opm_common_docstrings_path', None, 'env') + app.add_directive("opm_simulators_docstrings", SimulatorsDirective) + app.add_directive("opm_common_docstrings", CommonDirective) From 1f41bd6ebd55cc082b588e1f236eb2608f183bbc Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Fri, 5 Jul 2024 11:48:08 +0200 Subject: [PATCH 06/10] Force build documentation for master --- .github/workflows/python_sphinx_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index 3a7ca28a59f..ea4fdf45d5e 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -46,7 +46,7 @@ jobs: # Later we can add release tags to the list to get the docs for the releases # For example: -b "master, release/2024.04/final" will build the docs for # the master branch and the release/2024.04/final tag - poetry run sphinx-versioned -m master -b master --git-root ../../ + poetry run sphinx-versioned -m master -b master --force --git-root ../../ - name: Copy documentation to gh-pages run: | cp -r python/sphinx_docs/docs/_build/* python/gh-pages/ From cbff81428c201ecfbed1d666ce68e1f17843849b Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Fri, 5 Jul 2024 15:14:47 +0200 Subject: [PATCH 07/10] Only trigger the rebuild of the documentation when a PR gets merged, not for any open PR --- .github/workflows/python_sphinx_docs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index ea4fdf45d5e..fefe3afa196 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -6,7 +6,8 @@ on: paths: - 'python/**' - '.github/workflows/python_sphinx_docs.yml' - pull_request: + pull_request_target: + types: closed branches: master paths: - 'python/**' From 1ff7b79b1d9619a54d965691fd5dbb3433231014 Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Tue, 9 Jul 2024 13:51:38 +0200 Subject: [PATCH 08/10] Add continue-on-error: true to every step of the documentation pipeline, such that all steps can run through and this is not diagnosed as a failure --- .github/workflows/python_sphinx_docs.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index fefe3afa196..df4a9ee09b7 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -22,22 +22,28 @@ jobs: steps: - name: Checkout source code uses: actions/checkout@v4 + continue-on-error: true with: fetch-depth: 0 # Fetch all history for all tags and branches - name: Get docstrings_common.json from opm-common + continue-on-error: true run: | curl -L -o python/docstrings_common.json https://raw.githubusercontent.com/${{ github.repository_owner }}/opm-common/master/python/docstrings_common.json - name: Set up Python + continue-on-error: true uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install poetry + continue-on-error: true uses: abatilo/actions-poetry@v2 - name: Install python dependencies + continue-on-error: true run: | cd python/sphinx_docs poetry install - name: Build documentation + continue-on-error: true run: | cd python mkdir gh-pages @@ -49,9 +55,11 @@ jobs: # the master branch and the release/2024.04/final tag poetry run sphinx-versioned -m master -b master --force --git-root ../../ - name: Copy documentation to gh-pages + continue-on-error: true run: | cp -r python/sphinx_docs/docs/_build/* python/gh-pages/ - name: Deploy documentation + continue-on-error: true uses: JamesIves/github-pages-deploy-action@v4 with: branch: gh-pages From 8f38801db0c7835ca2f37e23c37089836604f99e Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Tue, 9 Jul 2024 14:05:19 +0200 Subject: [PATCH 09/10] Use our own forks of the github action workflows for the actions that do not directly come from github --- .github/workflows/python_sphinx_docs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index df4a9ee09b7..2d7072e6852 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -36,7 +36,7 @@ jobs: python-version: "3.11" - name: Install poetry continue-on-error: true - uses: abatilo/actions-poetry@v2 + uses: OPM/actions-poetry@master - name: Install python dependencies continue-on-error: true run: | @@ -60,7 +60,7 @@ jobs: cp -r python/sphinx_docs/docs/_build/* python/gh-pages/ - name: Deploy documentation continue-on-error: true - uses: JamesIves/github-pages-deploy-action@v4 + uses: OPM/github-pages-deploy-action@dev with: branch: gh-pages folder: python/gh-pages From e20a589c214efd829a5260f1ff286e34834f8736 Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel Date: Tue, 9 Jul 2024 14:37:54 +0200 Subject: [PATCH 10/10] Deploy documentation on own fork on separate branch --- .github/workflows/python_sphinx_docs.yml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python_sphinx_docs.yml b/.github/workflows/python_sphinx_docs.yml index 2d7072e6852..f08dd6d5692 100644 --- a/.github/workflows/python_sphinx_docs.yml +++ b/.github/workflows/python_sphinx_docs.yml @@ -2,7 +2,8 @@ name: Build Python Sphinx Docs and push to gh-pages on: push: - branches: master + branches: + - '**' paths: - 'python/**' - '.github/workflows/python_sphinx_docs.yml' @@ -53,14 +54,28 @@ jobs: # Later we can add release tags to the list to get the docs for the releases # For example: -b "master, release/2024.04/final" will build the docs for # the master branch and the release/2024.04/final tag - poetry run sphinx-versioned -m master -b master --force --git-root ../../ + # If this is a build for master, then the build the documentation for the master branch + if [ "${{ github.ref }}" == "refs/heads/master" ]; then + branch=master + else + branch=${{ github.ref }} + fi + poetry run sphinx-versioned -m master -b "${branch}" --force --git-root ../../ - name: Copy documentation to gh-pages continue-on-error: true run: | cp -r python/sphinx_docs/docs/_build/* python/gh-pages/ - - name: Deploy documentation + - name: Deploy documentation for PR merge to master or push to master + if: github.ref == 'refs/heads/master' continue-on-error: true uses: OPM/github-pages-deploy-action@dev with: branch: gh-pages folder: python/gh-pages + - name: Deploy documentation for PRs and other branches + if: github.event_name == 'push' && github.ref != 'refs/heads/master' + continue-on-error: true + uses: OPM/github-pages-deploy-action@dev + with: + branch: gh-pages + folder: python/gh-pages-${{ github.ref }}