From 4f2c1d8b7e2b9d5e67209e6605a35ddd591ef1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agnieszka=20=C5=BBaba?= Date: Tue, 14 Jan 2025 19:15:50 +0100 Subject: [PATCH 01/10] add notebook_vars to jupyter-utils --- open_atmos_jupyter_utils/notebook_vars.py | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 open_atmos_jupyter_utils/notebook_vars.py diff --git a/open_atmos_jupyter_utils/notebook_vars.py b/open_atmos_jupyter_utils/notebook_vars.py new file mode 100644 index 0000000..a51caec --- /dev/null +++ b/open_atmos_jupyter_utils/notebook_vars.py @@ -0,0 +1,31 @@ +""" helper routines for use in smoke tests """ + +from pathlib import Path + +import nbformat + + +def notebook_vars(file: Path, plot: bool): + """Executes the code from all cells of the Jupyter notebook `file` and + returns a dictionary with the notebook variables. If the `plot` argument + is set to `True`, any code line within the notebook starting with `show_plot(` + (see [open_atmos_jupyter_utils docs](https://pypi.org/p/open_atmos_jupyter_utils)) + is replaced with `pyplot.show() #`, otherwise it is replaced with `pyplot.gca().clear() #` + to match the smoke-test conventions.""" + notebook = nbformat.read(file, nbformat.NO_CONVERT) + context = {} + for cell in notebook.cells: + if cell.cell_type != "markdown": + lines = cell.source.splitlines() + for i, line in enumerate(lines): + if line.strip().startswith("!"): + lines[i] = line.replace("!", "pass #") + if line.strip().startswith("show_plot("): + lines[i] = line.replace( + "show_plot(", + "from matplotlib import pyplot; " + + ("pyplot.show() #" if plot else "pyplot.gca().clear() #"), + ) + + exec("\n".join(lines), context) # pylint: disable=exec-used + return context From 11afb9c2ecf031b7e603376cbd295d77a11352a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agnieszka=20=C5=BBaba?= Date: Mon, 20 Jan 2025 17:37:35 +0100 Subject: [PATCH 02/10] add notebook_bars to init file --- open_atmos_jupyter_utils/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/open_atmos_jupyter_utils/__init__.py b/open_atmos_jupyter_utils/__init__.py index 6b308a8..df87288 100644 --- a/open_atmos_jupyter_utils/__init__.py +++ b/open_atmos_jupyter_utils/__init__.py @@ -4,3 +4,4 @@ from open_atmos_jupyter_utils.pip_install_on_colab import pip_install_on_colab from open_atmos_jupyter_utils.temporary_file import TemporaryFile from open_atmos_jupyter_utils.show_plot import show_plot, save_and_make_link +from open_atmos_jupyter_utils.notebook_vars import notebook_vars From d843970a3c30dcf8a18ea7e80eb9f2ffa42c5ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agnieszka=20=C5=BBaba?= Date: Mon, 20 Jan 2025 17:40:42 +0100 Subject: [PATCH 03/10] add nbfomat to pyproject.toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 96e71ad..aaebb20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ dependencies = [ "IPython", "matplotlib", "imageio", + "nbformat" ] [project.urls] "Homepage" = "https://github.com/open-atmos/jupyter-utils" From c5bdf1fff8c40389a1b8766604863f45c3002d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agnieszka=20=C5=BBaba?= Date: Mon, 20 Jan 2025 17:55:41 +0100 Subject: [PATCH 04/10] add notebook_vars description to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b9e1674..9191540 100644 --- a/README.md +++ b/README.md @@ -10,5 +10,6 @@ Utility routines used in Jupyter notebooks in [PySDM](https://github.com/open-at - [``show_anim()``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/show_anim.html) - a replacement for matplotlib's FuncAnimate() that inline-displays animations in gif format (thus github renderer compatible) and offers a way to download the .gif file (on Colab the widget triggers Google Drive download) - [``TemporaryFile``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/temporary_file.html) - a class equipped with ``make_link_widget()`` method returning a click-to-download Colab-compatible widget to be display()-ed in a Jupyter notebook - [``pip_install_on_colab('package_a', 'package_b', ...)``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/pip_install_on_colab.html) - a function handling execution of ``pip`` (and ``ldconfig``) on Colab +- [``notebook_vars``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/notebook_vars) - a function that executes Jupyter notebook and returns a dictionary with the variables public API docs are maintained at: https://open-atmos.github.io/jupyter-utils/ From f8d6bfa719a04b255e3800a2edfaef6dfa38ed26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agnieszka=20=C5=BBaba?= Date: Mon, 20 Jan 2025 18:59:44 +0100 Subject: [PATCH 05/10] create test for notebook vars --- examples/__init__.py | 0 tests/test_notebook_vars.py | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 examples/__init__.py create mode 100644 tests/test_notebook_vars.py diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_notebook_vars.py b/tests/test_notebook_vars.py new file mode 100644 index 0000000..f0a2f7e --- /dev/null +++ b/tests/test_notebook_vars.py @@ -0,0 +1,21 @@ +""" +test checking notebook_vars function +""" + +from pathlib import Path +import pytest + +from open_atmos_jupyter_utils import notebook_vars +import examples + +@pytest.fixture(scope="session", name="notebook_variables") +def notebook_variables_fixture(): + """returns variables from the notebook """ + print(examples.__file__) + return notebook_vars( + file=Path(examples.__file__).parent / "show_anim_example.ipynb", + plot=False, + ) + +def test_notebook_vars(notebook_variables): + assert notebook_variables["frame_range"][-1]==49 From eec70b52464eba5f3945677e94674651d3ff2084 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Mon, 20 Jan 2025 20:11:17 +0100 Subject: [PATCH 06/10] add new example notebook (to clarify and to speed up the notebook_vars tests); addressing pylint hints --- .github/workflows/pylint.yml | 2 +- examples/notebook_vars_example.ipynb | 18 ++++++++++++++++++ tests/test_notebook_vars.py | 5 +++-- 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 examples/notebook_vars_example.ipynb diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 2e531b7..bfb8332 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -20,7 +20,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip setuptools - pip install pylint + pip install pylint pytest python setup.py egg_info pip install -r *.egg-info/requires.txt - name: Analysing the code with pylint diff --git a/examples/notebook_vars_example.ipynb b/examples/notebook_vars_example.ipynb new file mode 100644 index 0000000..ab7340a --- /dev/null +++ b/examples/notebook_vars_example.ipynb @@ -0,0 +1,18 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "51913260-f89a-4237-bc7b-af5a0b1785f9", + "metadata": {}, + "outputs": [], + "source": [ + "a = 44\n", + "b = 666\n" + "c = a + b" + ] + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/test_notebook_vars.py b/tests/test_notebook_vars.py index f0a2f7e..4f9fa65 100644 --- a/tests/test_notebook_vars.py +++ b/tests/test_notebook_vars.py @@ -13,9 +13,10 @@ def notebook_variables_fixture(): """returns variables from the notebook """ print(examples.__file__) return notebook_vars( - file=Path(examples.__file__).parent / "show_anim_example.ipynb", + file=Path(examples.__file__).parent / "notebook_vars_example.ipynb", plot=False, ) def test_notebook_vars(notebook_variables): - assert notebook_variables["frame_range"][-1]==49 + """ checks for a value known only after notebook execution""" + assert notebook_variables["c"] == notebook_variables["a"] + notebook_variables["b"] From c9aadc2e762f98d96096c213779e1509596fc052 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Mon, 20 Jan 2025 20:13:06 +0100 Subject: [PATCH 07/10] fix json syntax --- examples/notebook_vars_example.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/notebook_vars_example.ipynb b/examples/notebook_vars_example.ipynb index ab7340a..9a1ea92 100644 --- a/examples/notebook_vars_example.ipynb +++ b/examples/notebook_vars_example.ipynb @@ -12,7 +12,7 @@ "c = a + b" ] } - }, + ], "nbformat": 4, "nbformat_minor": 5 } From 17e5282775b52d1cf3b8787193c4e7b1df0939f7 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Mon, 20 Jan 2025 20:15:58 +0100 Subject: [PATCH 08/10] add notebook metadata --- examples/notebook_vars_example.ipynb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/examples/notebook_vars_example.ipynb b/examples/notebook_vars_example.ipynb index 9a1ea92..4bf8975 100644 --- a/examples/notebook_vars_example.ipynb +++ b/examples/notebook_vars_example.ipynb @@ -13,6 +13,25 @@ ] } ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, "nbformat": 4, "nbformat_minor": 5 } From 39a8babc258634d9b02db32285a7bad042001424 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Mon, 20 Jan 2025 20:18:02 +0100 Subject: [PATCH 09/10] add missing comma --- examples/notebook_vars_example.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/notebook_vars_example.ipynb b/examples/notebook_vars_example.ipynb index 4bf8975..46907c3 100644 --- a/examples/notebook_vars_example.ipynb +++ b/examples/notebook_vars_example.ipynb @@ -8,7 +8,7 @@ "outputs": [], "source": [ "a = 44\n", - "b = 666\n" + "b = 666\n", "c = a + b" ] } From a19e29e179d78f1ea98212f00cb1feb5052f95a5 Mon Sep 17 00:00:00 2001 From: Sylwester Arabas Date: Mon, 20 Jan 2025 20:22:54 +0100 Subject: [PATCH 10/10] elaborate a bit more in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9191540..9980c82 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,6 @@ Utility routines used in Jupyter notebooks in [PySDM](https://github.com/open-at - [``show_anim()``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/show_anim.html) - a replacement for matplotlib's FuncAnimate() that inline-displays animations in gif format (thus github renderer compatible) and offers a way to download the .gif file (on Colab the widget triggers Google Drive download) - [``TemporaryFile``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/temporary_file.html) - a class equipped with ``make_link_widget()`` method returning a click-to-download Colab-compatible widget to be display()-ed in a Jupyter notebook - [``pip_install_on_colab('package_a', 'package_b', ...)``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/pip_install_on_colab.html) - a function handling execution of ``pip`` (and ``ldconfig``) on Colab -- [``notebook_vars``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/notebook_vars) - a function that executes Jupyter notebook and returns a dictionary with the variables +- [``notebook_vars``](https://open-atmos.github.io/jupyter-utils/open_atmos_jupyter_utils/notebook_vars) - a function that executes Jupyter notebook and returns a dictionary with all variables notebook variables (variable names as keys) - useful in setting up automated tests for notebooks without modifying the notebooks (e.g., using pytest fixtures) public API docs are maintained at: https://open-atmos.github.io/jupyter-utils/