#2472: integrating jupyter notebooks into documentation

This commit is contained in:
Czar Echavez
2024-05-09 13:43:55 +01:00
parent d02b7744ae
commit 81c523dc67
8 changed files with 94 additions and 12 deletions

2
.gitignore vendored
View File

@@ -83,6 +83,7 @@ target/
# Jupyter Notebook # Jupyter Notebook
.ipynb_checkpoints .ipynb_checkpoints
PPO_UC2/ PPO_UC2/
docs/_static/notebooks/html/*.html
# IPython # IPython
profile_default/ profile_default/
@@ -152,6 +153,7 @@ docs/source/primaite-dependencies.rst
src/primaite/outputs/ src/primaite/outputs/
simulation_output/ simulation_output/
sessions/ sessions/
PrimAITE-PPO-example-agent.zip
# benchmark session outputs # benchmark session outputs
benchmark/output benchmark/output

View File

@@ -66,6 +66,33 @@ html_theme_options = {"globaltoc_collapse": True, "globaltoc_maxdepth": 2}
html_copy_source = False html_copy_source = False
def get_notebook_links() -> str:
"""
Returns a string which will be added to the RST.
Allows for dynamic addition of notebooks to the documentation.
"""
notebooks = os.listdir("_static/notebooks/html")
links = []
links.append("<ul>")
for notebook in notebooks:
if notebook == "notebook_links.html":
continue
notebook_link = (
f'<li><a href="../_static/notebooks/html/{notebook}" target="blank">'
f"{notebook.replace('.html', '')}"
f"</a></li>\n"
)
links.append(notebook_link)
links.append("<ul>")
with open("_static/notebooks/html/notebook_links.html", "w") as html_file:
html_file.write("".join(links))
return ":file: ../_static/notebooks/html/notebook_links.html"
def replace_token(app: Any, docname: Any, source: Any): def replace_token(app: Any, docname: Any, source: Any):
"""Replaces a token from the list of tokens.""" """Replaces a token from the list of tokens."""
result = source[0] result = source[0]
@@ -74,7 +101,10 @@ def replace_token(app: Any, docname: Any, source: Any):
source[0] = result source[0] = result
tokens = {"{VERSION}": release} # Token VERSION is replaced by the value of the PrimAITE version in the version file tokens = {
"{VERSION}": release,
"{NOTEBOOK_LINKS}": get_notebook_links(),
} # Token VERSION is replaced by the value of the PrimAITE version in the version file
"""Dict containing the tokens that need to be replaced in documentation.""" """Dict containing the tokens that need to be replaced in documentation."""

View File

@@ -104,14 +104,19 @@ Head over to the :ref:`getting-started` page to install and setup PrimAITE!
:hidden: :hidden:
source/getting_started source/getting_started
source/primaite_session
source/example_notebooks
source/simulation source/simulation
source/game_layer source/game_layer
source/config source/config
source/environment source/environment
source/customising_scenarios source/customising_scenarios
.. toctree::
:caption: Notebooks:
:hidden:
source/example_notebooks
source/executed_notebooks
.. toctree:: .. toctree::
:caption: Developer information: :caption: Developer information:
:hidden: :hidden:

View File

@@ -9,10 +9,14 @@ REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" ( if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build set SPHINXBUILD=sphinx-build
) )
if "%JUPYTER%" == "" (
set JUPYTER=jupyter
)
set SOURCEDIR=. set SOURCEDIR=.
set BUILDDIR=_build set BUILDDIR=_build
set AUTOSUMMARYDIR="%cd%\source\_autosummary\" set AUTOSUMMARYDIR="%cd%\source\_autosummary\"
set JUPYTEROUTPUTPATH="%cd%\_static\notebooks\html"
%SPHINXBUILD% >NUL 2>NUL %SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 ( if errorlevel 9009 (
@@ -27,6 +31,15 @@ if errorlevel 9009 (
exit /b 1 exit /b 1
) )
%JUPYTER% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.'jupyter' command was not found. Make sure you have Jupyter
echo.installed, then set the JUPYTER environment variable to point
echo.to the full path of the 'jupyter' executable.
exit /b 1
)
if "%1" == "" goto help if "%1" == "" goto help
REM delete autosummary if it exists REM delete autosummary if it exists
@@ -36,6 +49,15 @@ IF EXIST %AUTOSUMMARYDIR% (
RMDIR %AUTOSUMMARYDIR% /s /q RMDIR %AUTOSUMMARYDIR% /s /q
) )
REM delete notebook if it exists
IF EXIST %JUPYTEROUTPUTPATH% (
echo deleting %JUPYTEROUTPUTPATH%
RMDIR %JUPYTEROUTPUTPATH% /s /q
)
REM run and print html of notebooks
JUPYTER nbconvert --execute --to html --output-dir %JUPYTEROUTPUTPATH% "%cd%\..\src\primaite\**\*.ipynb"
REM print the YT licenses REM print the YT licenses
set LICENSEBUILD=pip-licenses --format=rst --with-urls set LICENSEBUILD=pip-licenses --format=rst --with-urls
set DEPS="%cd%\source\primaite-dependencies.rst" set DEPS="%cd%\source\primaite-dependencies.rst"
@@ -54,5 +76,10 @@ IF EXIST %AUTOSUMMARYDIR% (
RMDIR %AUTOSUMMARYDIR% /s /q RMDIR %AUTOSUMMARYDIR% /s /q
) )
IF EXIST %JUPYTEROUTPUTPATH% (
echo deleting %JUPYTEROUTPUTPATH%
RMDIR %JUPYTEROUTPUTPATH% /s /q
)
:end :end
popd popd

View File

@@ -75,7 +75,7 @@ this results in:
The human readable name for the link. Not used in code, however is useful for a human to understand what the link is for. The human readable name for the link. Not used in code, however is useful for a human to understand what the link is for.
``endpoint_a_hostname`` ``endpoint_a_hostname``
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
The ``hostname`` of the node which must be connected. The ``hostname`` of the node which must be connected.
@@ -86,7 +86,7 @@ The port on ``endpoint_a_hostname`` which is to be connected to ``endpoint_b_por
This accepts an integer value e.g. if port 1 is to be connected, the configuration should be ``endpoint_a_port: 1`` This accepts an integer value e.g. if port 1 is to be connected, the configuration should be ``endpoint_a_port: 1``
``endpoint_b_hostname`` ``endpoint_b_hostname``
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
The ``hostname`` of the node which must be connected. The ``hostname`` of the node which must be connected.

View File

@@ -5,9 +5,14 @@
Example Jupyter Notebooks Example Jupyter Notebooks
========================= =========================
Executed Notebooks
------------------
There are a few example notebooks included which help with the understanding of PrimAITE's capabilities. There are a few example notebooks included which help with the understanding of PrimAITE's capabilities.
The Jupyter Notebooks can be run via the 2 examples below. These assume that the instructions to install PrimAITE from the :ref:`Getting Started <getting-started>` page is completed as a prerequisite. The PrimAITE documentation includes a pre executed example of notebooks. See :ref:`Executed Notebooks`.
The Jupyter notebooks can also be run interactively via the 2 examples below. These assume that the instructions to install PrimAITE from the :ref:`Getting Started <getting-started>` page is completed as a prerequisite.
Running Jupyter Notebooks Running Jupyter Notebooks
------------------------- -------------------------

View File

@@ -0,0 +1,13 @@
.. only:: comment
© Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
.. _Executed Notebooks:
Executed Jupyter Notebooks
==========================
Below is a list of available pre-executed notebooks.
.. raw:: html
{NOTEBOOK_LINKS}

View File

@@ -50,7 +50,7 @@
" cfg = yaml.safe_load(f)\n", " cfg = yaml.safe_load(f)\n",
" make_cfg_have_flat_obs(cfg)\n", " make_cfg_have_flat_obs(cfg)\n",
"\n", "\n",
"env = PrimaiteGymEnv(game_config = cfg)\n", "env = PrimaiteGymEnv(env_config = cfg)\n",
"obs, info = env.reset()\n", "obs, info = env.reset()\n",
"print('env created successfully')" "print('env created successfully')"
] ]
@@ -232,7 +232,7 @@
" if agent['ref'] == \"data_manipulation_attacker\":\n", " if agent['ref'] == \"data_manipulation_attacker\":\n",
" agent['agent_settings'] = change\n", " agent['agent_settings'] = change\n",
"\n", "\n",
"env = PrimaiteGymEnv(game_config = cfg)\n", "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n", "env.reset()\n",
"for step in range(100):\n", "for step in range(100):\n",
" step_num = env.game.step_counter\n", " step_num = env.game.step_counter\n",
@@ -261,7 +261,7 @@
"with open(data_manipulation_config_path(), 'r') as f:\n", "with open(data_manipulation_config_path(), 'r') as f:\n",
" cfg = yaml.safe_load(f)\n", " cfg = yaml.safe_load(f)\n",
"\n", "\n",
"env = PrimaiteGymEnv(game_config = cfg)\n", "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n", "env.reset()\n",
"for ep in range(12):\n", "for ep in range(12):\n",
" env.reset()\n", " env.reset()\n",
@@ -307,7 +307,7 @@
" if agent['ref'] == \"data_manipulation_attacker\":\n", " if agent['ref'] == \"data_manipulation_attacker\":\n",
" agent.update(change)\n", " agent.update(change)\n",
"\n", "\n",
"env = PrimaiteGymEnv(game_config = cfg)\n", "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n", "env.reset()\n",
"for ep in range(12):\n", "for ep in range(12):\n",
" env.reset()\n", " env.reset()\n",
@@ -365,7 +365,7 @@
" if node['hostname'] in ['client_1', 'client_2']:\n", " if node['hostname'] in ['client_1', 'client_2']:\n",
" node['applications'] = change['applications']\n", " node['applications'] = change['applications']\n",
"\n", "\n",
"env = PrimaiteGymEnv(game_config = cfg)\n", "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n", "env.reset()\n",
"for ep in range(5):\n", "for ep in range(5):\n",
" env.reset()\n", " env.reset()\n",
@@ -410,7 +410,7 @@
" if node['hostname'] in ['client_1', 'client_2']:\n", " if node['hostname'] in ['client_1', 'client_2']:\n",
" node['applications'] = change['applications']\n", " node['applications'] = change['applications']\n",
"\n", "\n",
"env = PrimaiteGymEnv(game_config = cfg)\n", "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n", "env.reset()\n",
"for ep in range(5):\n", "for ep in range(5):\n",
" env.reset()\n", " env.reset()\n",