diff --git a/.gitignore b/.gitignore
index b464566b..0d27eb1c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -83,6 +83,7 @@ target/
# Jupyter Notebook
.ipynb_checkpoints
PPO_UC2/
+docs/_static/notebooks/html/*.html
# IPython
profile_default/
@@ -152,6 +153,7 @@ docs/source/primaite-dependencies.rst
src/primaite/outputs/
simulation_output/
sessions/
+PrimAITE-PPO-example-agent.zip
# benchmark session outputs
benchmark/output
diff --git a/docs/conf.py b/docs/conf.py
index a666e460..33e192aa 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -66,6 +66,33 @@ html_theme_options = {"globaltoc_collapse": True, "globaltoc_maxdepth": 2}
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("
")
+ for notebook in notebooks:
+ if notebook == "notebook_links.html":
+ continue
+ notebook_link = (
+ f'- '
+ f"{notebook.replace('.html', '')}"
+ f"
\n"
+ )
+ links.append(notebook_link)
+ links.append("")
+
+ 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):
"""Replaces a token from the list of tokens."""
result = source[0]
@@ -74,7 +101,10 @@ def replace_token(app: Any, docname: Any, source: Any):
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."""
diff --git a/docs/index.rst b/docs/index.rst
index 52bc8b57..a03c857f 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -104,14 +104,19 @@ Head over to the :ref:`getting-started` page to install and setup PrimAITE!
:hidden:
source/getting_started
- source/primaite_session
- source/example_notebooks
source/simulation
source/game_layer
source/config
source/environment
source/customising_scenarios
+.. toctree::
+ :caption: Notebooks:
+ :hidden:
+
+ source/example_notebooks
+ source/executed_notebooks
+
.. toctree::
:caption: Developer information:
:hidden:
diff --git a/docs/make.bat b/docs/make.bat
index 399e9150..a0e2a485 100644
--- a/docs/make.bat
+++ b/docs/make.bat
@@ -9,10 +9,14 @@ REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
+if "%JUPYTER%" == "" (
+ set JUPYTER=jupyter
+)
set SOURCEDIR=.
set BUILDDIR=_build
set AUTOSUMMARYDIR="%cd%\source\_autosummary\"
+set JUPYTEROUTPUTPATH="%cd%\_static\notebooks\html"
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
@@ -27,6 +31,15 @@ if errorlevel 9009 (
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
REM delete autosummary if it exists
@@ -36,6 +49,15 @@ IF EXIST %AUTOSUMMARYDIR% (
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
set LICENSEBUILD=pip-licenses --format=rst --with-urls
set DEPS="%cd%\source\primaite-dependencies.rst"
@@ -54,5 +76,10 @@ IF EXIST %AUTOSUMMARYDIR% (
RMDIR %AUTOSUMMARYDIR% /s /q
)
+IF EXIST %JUPYTEROUTPUTPATH% (
+ echo deleting %JUPYTEROUTPUTPATH%
+ RMDIR %JUPYTEROUTPUTPATH% /s /q
+)
+
:end
popd
diff --git a/docs/source/configuration/simulation.rst b/docs/source/configuration/simulation.rst
index 9da2b6a3..ab51d7fd 100644
--- a/docs/source/configuration/simulation.rst
+++ b/docs/source/configuration/simulation.rst
@@ -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.
``endpoint_a_hostname``
-^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^
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``
``endpoint_b_hostname``
-^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^
The ``hostname`` of the node which must be connected.
diff --git a/docs/source/example_notebooks.rst b/docs/source/example_notebooks.rst
index 99d47822..4499a00c 100644
--- a/docs/source/example_notebooks.rst
+++ b/docs/source/example_notebooks.rst
@@ -5,9 +5,14 @@
Example Jupyter Notebooks
=========================
+Executed Notebooks
+------------------
+
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 ` 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 ` page is completed as a prerequisite.
Running Jupyter Notebooks
-------------------------
diff --git a/docs/source/executed_notebooks.rst b/docs/source/executed_notebooks.rst
new file mode 100644
index 00000000..849529f2
--- /dev/null
+++ b/docs/source/executed_notebooks.rst
@@ -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}
diff --git a/src/primaite/notebooks/Data-Manipulation-Customising-Red-Agent.ipynb b/src/primaite/notebooks/Data-Manipulation-Customising-Red-Agent.ipynb
index 74a1e0ef..de473a7b 100644
--- a/src/primaite/notebooks/Data-Manipulation-Customising-Red-Agent.ipynb
+++ b/src/primaite/notebooks/Data-Manipulation-Customising-Red-Agent.ipynb
@@ -50,7 +50,7 @@
" cfg = yaml.safe_load(f)\n",
" make_cfg_have_flat_obs(cfg)\n",
"\n",
- "env = PrimaiteGymEnv(game_config = cfg)\n",
+ "env = PrimaiteGymEnv(env_config = cfg)\n",
"obs, info = env.reset()\n",
"print('env created successfully')"
]
@@ -232,7 +232,7 @@
" if agent['ref'] == \"data_manipulation_attacker\":\n",
" agent['agent_settings'] = change\n",
"\n",
- "env = PrimaiteGymEnv(game_config = cfg)\n",
+ "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n",
"for step in range(100):\n",
" step_num = env.game.step_counter\n",
@@ -261,7 +261,7 @@
"with open(data_manipulation_config_path(), 'r') as f:\n",
" cfg = yaml.safe_load(f)\n",
"\n",
- "env = PrimaiteGymEnv(game_config = cfg)\n",
+ "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n",
"for ep in range(12):\n",
" env.reset()\n",
@@ -307,7 +307,7 @@
" if agent['ref'] == \"data_manipulation_attacker\":\n",
" agent.update(change)\n",
"\n",
- "env = PrimaiteGymEnv(game_config = cfg)\n",
+ "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n",
"for ep in range(12):\n",
" env.reset()\n",
@@ -365,7 +365,7 @@
" if node['hostname'] in ['client_1', 'client_2']:\n",
" node['applications'] = change['applications']\n",
"\n",
- "env = PrimaiteGymEnv(game_config = cfg)\n",
+ "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n",
"for ep in range(5):\n",
" env.reset()\n",
@@ -410,7 +410,7 @@
" if node['hostname'] in ['client_1', 'client_2']:\n",
" node['applications'] = change['applications']\n",
"\n",
- "env = PrimaiteGymEnv(game_config = cfg)\n",
+ "env = PrimaiteGymEnv(env_config = cfg)\n",
"env.reset()\n",
"for ep in range(5):\n",
" env.reset()\n",