diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f516e56 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + # Python + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a7eb393..b5895eb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,20 +1,23 @@ name: tests -on: [push, pull_request] +on: + push: + branches: ["main"] + pull_request: + schedule: + - cron: "0 8 * * *" jobs: - pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v3 - with: - python-version: 3.8 - - uses: pre-commit/action@v2.0.0 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v3 + with: + python-version: "3.10" + - uses: pre-commit/action@v2.0.0 tests: - strategy: matrix: python-version: ["3.8", "3.9", "3.10", "3.11", " 3.12"] @@ -28,21 +31,18 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - python -m bash_kernel.install # For testing a non-standard kernel - pip install . + - name: Install dependencies + run: | + python -m pip install --upgrade pip hatch - - name: Run tests - run: pytest + - name: Run tests + run: hatch run test:test -x docs: runs-on: ubuntu-latest @@ -51,16 +51,13 @@ jobs: - uses: actions/setup-python@v3 - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install . + python -m pip install --upgrade pip hatch + - name: Build docs run: | - cd doc - make html-strict + hatch run doc:build publish: - name: Publish to PyPi needs: [tests] if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') diff --git a/.gitignore b/.gitignore index f4c55ce..6372f76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.tox/ +.venv *.py[cod] # Packages diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 69709cf..70cee8f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,24 +1,76 @@ +ci: + autoupdate_schedule: monthly + autoupdate_commit_msg: "chore: update pre-commit hooks" + repos: - - repo: "https://github.com/pre-commit/pre-commit-hooks" - rev: v4.3.0 + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 hooks: - - id: trailing-whitespace + - id: check-case-conflict + - id: check-ast + - id: check-docstring-first + - id: check-executables-have-shebangs + - id: check-added-large-files + - id: check-case-conflict + - id: check-merge-conflict + - id: check-json + - id: check-toml + - id: check-yaml + - id: debug-statements - id: end-of-file-fixer - - repo: "https://github.com/pycqa/flake8/" - rev: 3.9.2 + - id: trailing-whitespace + + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.27.1 + hooks: + - id: check-github-workflows + + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.17 + hooks: + - id: mdformat + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v3.0.3" + hooks: + - id: prettier + types_or: [yaml, html, json] + + - repo: https://github.com/adamchainz/blacken-docs + rev: "1.16.0" + hooks: + - id: blacken-docs + additional_dependencies: [black==23.7.0] + exclude: | + (?x)^( + doc/source/index.rst| + tests/test_execute.py + )$(|) + + - repo: https://github.com/codespell-project/codespell + rev: "v2.2.6" hooks: - - id: flake8 - - repo: "https://github.com/ambv/black" - rev: 22.3.0 + - id: codespell + args: ["-L", "sur,nd"] + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: "v1.10.0" hooks: - - id: black - language_version: python3 - - repo: "https://github.com/PyCQA/isort" - rev: 5.12.0 + - id: rst-backticks + - id: rst-directive-colons + - id: rst-inline-touching-normal + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.5 hooks: - - id: isort - - repo: https://github.com/asottile/pyupgrade - rev: v2.34.0 + - id: ruff + types_or: [python, jupyter] + args: ["--fix", "--show-fixes"] + - id: ruff-format + types_or: [python, jupyter] + + - repo: https://github.com/scientific-python/cookie + rev: "2023.10.27" hooks: - - id: pyupgrade - args: ["--py36-plus"] + - id: sp-repo-review + additional_dependencies: ["repo-review[cli]"] diff --git a/.readthedocs.yml b/.readthedocs.yml index 188c1aa..6c8b931 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -7,4 +7,8 @@ sphinx: configuration: doc/source/conf.py python: install: - - requirements: requirements.txt + # install itself with pip install . + - method: pip + path: . + extra_requirements: + - doc diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..05ada48 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,138 @@ +# General Jupyter contributor guidelines + +If you're reading this section, you're probably interested in +contributing to Jupyter. Welcome and thanks for your interest in +contributing! + +Please take a look at the Contributor documentation, familiarize +yourself with using the Jupyter Server, and introduce yourself on the +mailing list and share what area of the project you are interested in +working on. + +For general documentation about contributing to Jupyter projects, see +the [Project Jupyter Contributor +Documentation](https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html). + +# Setting Up a Development Environment + +## Installing the Jupyter Server + +The development version of the server requires +[node](https://nodejs.org/en/download/) and +[pip](https://pip.pypa.io/en/stable/installing/). + +Once you have installed the dependencies mentioned above, use the +following steps: + +``` +pip install --upgrade pip +git clone https://github.com/jupyter/jupyter-sphinx +cd jupyter-server +pip install -e ".[test]" +``` + +## Code Styling and Quality Checks + +`jupyter-sphinx` has adopted automatic code formatting so you shouldn't +need to worry too much about your code style. As long as your code is +valid, the pre-commit hook should take care of how it should look. +`pre-commit` and its associated hooks will automatically be installed +when you run `pip install -e ".[test]"` + +To install `pre-commit` hook manually, run the following: + +``` +pre-commit install +``` + +You can invoke the pre-commit hook by hand at any time with: + +``` +pre-commit run +``` + +which should run any autoformatting on your code and tell you about any +errors it couldn't fix automatically. You may also install [black +integration](https://github.com/psf/black#editor-integration) into your +text editor to format code automatically. + +If you have already committed files before setting up the pre-commit +hook with `pre-commit install`, you can fix everything up using +`pre-commit run --all-files`. You need to make the fixing commit +yourself after that. + +Some of the hooks only run on CI by default, but you can invoke them by +running with the `--hook-stage manual` argument. + +There are three hatch scripts that can be run locally as well: +`hatch run lint:build` will enforce styling. + +# Running Tests + +Install dependencies: + +``` +pip install -e .[test] +``` + +To run the Python tests, use: + +``` +pytest +``` + +You can also run the tests using `hatch` without installing test +dependencies in your local environment: + +``` +pip install hatch +hatch run test:test +``` + +The command takes any argument that you can give to `pytest`, e.g.: + +``` +hatch run test:test -k name_of_method_to_test +``` + +You can also drop into a shell in the test environment by running: + +``` +hatch -e test shell +``` + +# Building the Docs + +Install the docs requirements using `pip`: + +``` +pip install .[doc] +``` + +Once you have installed the required packages, you can build the docs +with: + +``` +cd docs +make html +``` + +You can also run the tests using `hatch` without installing test +dependencies in your local environment. + +```bash +pip install hatch +hatch run docs:build +``` + +You can also drop into a shell in the docs environment by running: + +``` +hatch -e docs shell +``` + +After that, the generated HTML files will be available at +`build/html/index.html`. You may view the docs in your browser. + +You should also have a look at the [Project Jupyter Documentation +Guide](https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html). diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 6dae480..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include LICENSE -recursive-include jupyter_sphinx/thebelab/* diff --git a/README.md b/README.md index 40efc51..e7f1cd2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Jupyter Sphinx Extensions -``jupyter-sphinx`` enables running code embedded in Sphinx documentation and +`jupyter-sphinx` enables running code embedded in Sphinx documentation and embedding output of that code into the resulting document. It has support for rich output such as images and even Jupyter interactive widgets. @@ -23,7 +23,6 @@ conda install jupyter_sphinx -c conda-forge You can check out the documentation on https://jupyter-sphinx.readthedocs.io for up to date usage information and examples. - ## License We use a shared copyright model that enables all contributors to maintain the diff --git a/RELEASE.md b/RELEASE.md index a05b9f4..bf847a8 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -5,32 +5,38 @@ PyPI when a GitHub release is added. To cut a new Jupyter Sphinx release, follow these steps: -* Ensure that all tests are passing on master. -* In [`_version.py`](https://github.com/jupyter/jupyter-sphinx/blob/master/jupyter_sphinx/_version.py), +- Ensure that all tests are passing on master. + +- In [`_version.py`](https://github.com/jupyter/jupyter-sphinx/blob/master/jupyter_sphinx/_version.py), change the "release type" section to "final" e.g.: ```python version_info = (0, 2, 3, "final") ``` -* Make a release commit and push to master + +- Make a release commit and push to master ``` git add jupyter_sphinx/_version.py git commit -m "RLS: 0.2.3" git push upstream master ``` -* [Create a new github release](https://github.com/jupyter/jupyter-sphinx/releases/new). + +- [Create a new github release](https://github.com/jupyter/jupyter-sphinx/releases/new). The target should be **master**, the tag and the title should be the version number, e.g. `0.2.3`. -* Creating the release in GitHub will push a tag commit to the repository, which will + +- Creating the release in GitHub will push a tag commit to the repository, which will trigger [a GitHub action](https://github.com/jupyter/jupyter-sphinx/blob/master/.github/workflows/artifacts.yml) to build `jupyter-sphinx` and push the new version to PyPI. [Confirm that the version has been bumped](https://pypi.org/project/jupyter-sphinx/). -* In [`_version.py`](https://github.com/jupyter/jupyter-sphinx/blob/master/jupyter_sphinx/_version.py), + +- In [`_version.py`](https://github.com/jupyter/jupyter-sphinx/blob/master/jupyter_sphinx/_version.py), bump the minor version and change the "release type" section to "alpha". **make sure to include a number after the release type**, e.g.: ```python version_info = (0, 2, 4, "alpha", 1) ``` -* That's it! + +- That's it! diff --git a/jupyter_sphinx/_version.py b/jupyter_sphinx/_version.py index 6d28903..0519dca 100644 --- a/jupyter_sphinx/_version.py +++ b/jupyter_sphinx/_version.py @@ -1,12 +1,18 @@ -version_info = (0, 4, 0, "final") +""" +store the current version info of the project. -_specifier_ = {"alpha": "a", "beta": "b", "candidate": "rc", "final": ""} +""" +import re +from typing import List -__version__ = "{}.{}.{}{}".format( - version_info[0], - version_info[1], - version_info[2], - "" - if version_info[3] == "final" - else _specifier_[version_info[3]] + str(version_info[4]), -) +# Version string must appear intact for automatic versioning +__version__ = "0.4.0" + +# Build up version_info tuple for backwards compatibility +pattern = r"(?P\d+).(?P\d+).(?P\d+)(?P.*)" +match = re.match(pattern, __version__) +assert match is not None +parts: List[object] = [int(match[part]) for part in ["major", "minor", "patch"]] +if match["rest"]: + parts.append(match["rest"]) +version_info = tuple(parts) diff --git a/jupyter_sphinx/ast.py b/jupyter_sphinx/ast.py index 35402f3..568aed7 100644 --- a/jupyter_sphinx/ast.py +++ b/jupyter_sphinx/ast.py @@ -295,7 +295,7 @@ def run(self): class JupyterCellNode(docutils.nodes.container): - """Inserted into doctree whever a JupyterCell directive is encountered. + """Inserted into doctree wherever a JupyterCell directive is encountered. Contains code that will be executed in a Jupyter kernel at a later doctree-transformation step. @@ -387,7 +387,6 @@ def __init__(self, rawsource="", *children, **attributes): super().__init__("", state=attributes["state"]) def html(self): - # escape to avoid early closing of the tag in the html page json_data = json.dumps(self["state"]).replace("", r"<\/script>") @@ -625,7 +624,7 @@ class CombineCellInputOutput(SphinxTransform): def apply(self): moved_outputs = set() - for cell_node in self.document.traverse(JupyterCellNode): + for cell_node in self.document.findall(JupyterCellNode): if not cell_node.attributes["execute"]: if not cell_node.attributes["hide_code"]: # Cell came from jupyter-input diff --git a/jupyter_sphinx/execute.py b/jupyter_sphinx/execute.py index 558a26b..cb473cf 100644 --- a/jupyter_sphinx/execute.py +++ b/jupyter_sphinx/execute.py @@ -123,12 +123,12 @@ def apply(self): linenos_config = self.config.jupyter_sphinx_linenos continue_linenos = self.config.jupyter_sphinx_continue_linenos # Check if we have anything to execute. - if not doctree.traverse(JupyterCellNode): + if not next(doctree.findall(JupyterCellNode), False): return if thebe_config: # Add the button at the bottom if it is not present - if not doctree.traverse(ThebeButtonNode): + if not next(doctree.findall(ThebeButtonNode), False): doctree.append(ThebeButtonNode()) add_thebelab_library(doctree, self.env) @@ -140,7 +140,7 @@ def apply(self): jupyter_nodes = (JupyterCellNode, JupyterKernelNode) nodes_by_notebook = split_on( lambda n: isinstance(n, JupyterKernelNode), - doctree.traverse(lambda n: isinstance(n, jupyter_nodes)), + list(doctree.findall(lambda n: isinstance(n, jupyter_nodes))), ) for first, *nodes in nodes_by_notebook: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..66f0cab --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,84 @@ +[build-system] +requires = ["hatchling>=1.5"] +build-backend = "hatchling.build" + +[project] +name = "jupyter-sphinx" +dynamic = ["version"] +description = "Jupyter Sphinx Extensions" +readme = "README.md" +license = {file="LICENSE"} +requires-python = ">=3.8" +authors = [ + { name = "Jupyter Development Team", email = "jupyter@googlegroups.com" }, +] +dependencies = [ + "ipykernel>=4.5.1", + "IPython", + "ipywidgets>=7.0.0", + "nbconvert>=5.5", + "nbformat", + "Sphinx>=7", +] + +[project.urls] +"Bug Tracker" = "https://github.com/jupyter/jupyter-sphinx/issues/" +Documentation = "https://jupyter-sphinx.readthedocs.io" +Homepage = "https://jupyter.org" +"Source Code" = "https://github.com/jupyter/jupyter-sphinx/" + +[project.optional-dependencies] +test = [ + "pytest", + "bash_kernel" +] +doc = [ + "matplotlib" +] + +[tool.hatch.version] +path = "jupyter_sphinx/_version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/jupyter_sphinx", +] + +[tool.hatch.envs.lint] +detached = true +dependencies = ["pre-commit"] +[tool.hatch.envs.lint.scripts] +build = [ + "pre-commit run --all-files ruff", + "pre-commit run --all-files ruff-format", +] + +[tool.hatch.envs.doc] +features = ["doc"] +[tool.hatch.envs.doc.scripts] +build = "cd doc; make html-strict" + +[tool.hatch.envs.test] +features = ["test"] +[tool.hatch.envs.test.env-vars] +JUPYTER_PLATFORM_DIRS = "1" +[tool.hatch.envs.test.scripts] +test = ["python -m bash_kernel.install", "python -m pytest -vv {args}"] +nowarn = "test -W default {args}" + +[tool.pytest.ini_options] +minversion = "7.0" +xfail_strict = true +log_cli_level = "info" +addopts = [ + "-ra", "--durations=10", "--color=yes", "--strict-config", "--strict-markers" +] +testpaths = ["tests/"] +filterwarnings = [ + "error", + # https://github.com/dateutil/dateutil/issues/1314 + "module:datetime.datetime.utc:DeprecationWarning" +] + +[tool.repo-review] +ignore = ["GH102", "MY100", "RF001", "PY007", "GH103", "PC140"] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 8d4344f..0000000 --- a/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -sphinx>=7.0 -ipykernel>=4.5.1 -ipywidgets>=7.0.0 -IPython -nbconvert>=5.4 -nbformat - -# For documentation building and testing -matplotlib -pytest - -# A non-standard kernel -bash_kernel diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 86e7f09..0000000 --- a/setup.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[metadata] -license_file = LICENSE - -[flake8] -max-line-length = 120 -extend-ignore = E203 - -[isort] -profile = black diff --git a/setup.py b/setup.py deleted file mode 100644 index dfb7eff..0000000 --- a/setup.py +++ /dev/null @@ -1,41 +0,0 @@ -import os - -from setuptools import setup - -here = os.path.abspath(os.path.dirname(__file__)) -name = "jupyter_sphinx" - -version_ns = {} -with open(os.path.join(here, name, "_version.py")) as f: - exec(f.read(), {}, version_ns) - -with open(os.path.join(here, "README.md")) as f: - description = f.read() - -setup( - name=name, - version=version_ns["__version__"], - author="Jupyter Development Team", - author_email="jupyter@googlegroups.com", - description="Jupyter Sphinx Extensions", - long_description=description, - long_description_content_type="text/markdown", - url="https://github.com/jupyter/jupyter-sphinx/", - project_urls={ - "Bug Tracker": "https://github.com/jupyter/jupyter-sphinx/issues/", - "Documentation": "https://jupyter-sphinx.readthedocs.io", - "Source Code": "https://github.com/jupyter/jupyter-sphinx/", - }, - license="BSD", - packages=["jupyter_sphinx"], - install_requires=[ - "Sphinx>=7", - "ipykernel>=4.5.1", - "ipywidgets>=7.0.0", - "IPython", - "nbconvert>=5.5", - "nbformat", - ], - python_requires=">= 3.8", - package_data={"jupyter_sphinx": ["thebelab/*", "css/*"]}, -) diff --git a/tests/test_execute.py b/tests/test_execute.py index dd7fc90..53f554b 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -1,3 +1,4 @@ +import asyncio import os import shutil import sys @@ -30,6 +31,10 @@ from jupyter_sphinx.thebelab import ThebeButtonNode, ThebeOutputNode, ThebeSourceNode +if os.name == "nt": + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + + @pytest.fixture() def doctree(): source_trees = [] @@ -87,7 +92,7 @@ def test_basic(doctree, buildername): 2 + 2 """ tree = doctree(source, buildername=buildername) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert not cell.attributes["code_below"] assert not cell.attributes["hide_code"] @@ -105,7 +110,7 @@ def test_hide_output(doctree): 2 + 2 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert cell.attributes["hide_output"] assert len(celloutput.children) == 0 @@ -120,7 +125,7 @@ def test_hide_code(doctree): 2 + 2 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (celloutput,) = cell.children assert cell.attributes["hide_code"] assert len(cell.children) == 1 @@ -135,7 +140,7 @@ def test_code_below(doctree): 2 + 2 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (celloutput, cellinput) = cell.children assert cell.attributes["code_below"] assert cellinput.children[0].astext().strip() == "2 + 2" @@ -150,7 +155,7 @@ def test_linenos(doctree): 2 + 2 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert cellinput.children[0]["linenos"] assert len(cell.children) == 2 @@ -164,7 +169,7 @@ def test_linenos(doctree): 2 + 2 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (celloutput, cellinput) = cell.children assert cellinput.children[0]["linenos"] @@ -176,7 +181,7 @@ def test_linenos_conf_option(doctree): 2 + 2 """ tree = doctree(source, config="jupyter_sphinx_linenos = True") - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert cellinput.children[0].attributes["linenos"] assert "highlight_args" not in cellinput.children[0].attributes @@ -194,7 +199,7 @@ def test_continue_linenos_conf_option(doctree): """ tree = doctree(source, config="jupyter_sphinx_continue_linenos = True") - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert not cellinput.children[0].attributes["linenos"] assert cellinput.children[0].astext().strip() == "2 + 2" @@ -218,7 +223,7 @@ def test_continue_linenos_conf_option(doctree): "jupyter_sphinx_continue_linenos = True", ) - cell0, cell1 = tree.traverse(JupyterCellNode) + cell0, cell1 = tree.findall(JupyterCellNode) (cellinput0, celloutput0) = cell0.children (cellinput1, celloutput1) = cell1.children assert cellinput0.children[0].attributes["linenos"] @@ -248,7 +253,7 @@ def test_continue_linenos_conf_option(doctree): config="jupyter_sphinx_linenos = True\n" "jupyter_sphinx_continue_linenos = True", ) - cell0, cell1 = tree.traverse(JupyterCellNode) + cell0, cell1 = tree.findall(JupyterCellNode) (cellinput0, celloutput0) = cell0.children (cellinput1, celloutput1) = cell1.children assert cellinput0.children[0].attributes["highlight_args"]["linenostart"] == 7 @@ -282,7 +287,7 @@ def test_emphasize_lines(doctree): 5 + 5 """ tree = doctree(source) - cell0, cell1 = tree.traverse(JupyterCellNode) + cell0, cell1 = tree.findall(JupyterCellNode) assert cell0.attributes["emphasize_lines"] == [1, 3, 4, 5] assert cell1.attributes["emphasize_lines"] == [2, 4] @@ -300,7 +305,7 @@ def test_execution_environment_carries_over(doctree): a """ tree = doctree(source) - _, cell1 = tree.traverse(JupyterCellNode) + _, cell1 = tree.findall(JupyterCellNode) (_, celloutput1) = cell1.children assert celloutput1.children[0].astext().strip() == "2" @@ -321,7 +326,7 @@ def test_kernel_restart(doctree): a """ tree = doctree(source) - _, cell1 = tree.traverse(JupyterCellNode) + _, cell1 = tree.findall(JupyterCellNode) (_, celloutput1) = cell1.children assert "NameError" in celloutput1.children[0].astext() @@ -342,7 +347,7 @@ def test_raises(doctree): raise ValueError() """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (_, celloutput) = cell.children assert "ValueError" in celloutput.children[0].astext() @@ -353,7 +358,7 @@ def test_raises(doctree): raise ValueError() """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (_, celloutput) = cell.children assert "ValueError" in celloutput.children[0].astext() @@ -366,8 +371,8 @@ def test_widgets(doctree): ipywidgets.Button() """ tree = doctree(source) - assert len(list(tree.traverse(JupyterWidgetViewNode))) == 1 - assert len(list(tree.traverse(JupyterWidgetStateNode))) == 1 + assert len(list(tree.findall(JupyterWidgetViewNode))) == 1 + assert len(list(tree.findall(JupyterWidgetStateNode))) == 1 def test_javascript(doctree): @@ -378,7 +383,7 @@ def test_javascript(doctree): Javascript('window.alert("Hello world!")') """ tree = doctree(source) - (node,) = list(tree.traverse(raw)) + (node,) = list(tree.findall(raw)) (text,) = node.children assert "world" in text @@ -390,7 +395,7 @@ def test_stdout(doctree): print('hello world') """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (_, celloutput) = cell.children assert len(cell.children) == 2 assert celloutput.children[0].astext().strip() == "hello world" @@ -406,7 +411,7 @@ def test_stderr(doctree): tree, _, warnings = doctree(source, return_all=True) assert "hello world" in warnings - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (_, celloutput) = cell.children assert len(celloutput) == 0 # no output @@ -418,7 +423,7 @@ def test_stderr(doctree): print('hello world', file=sys.stderr) """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (_, celloutput) = cell.children assert len(cell.children) == 2 assert "stderr" in celloutput.children[0].attributes["classes"] @@ -436,7 +441,7 @@ def test_thebe_hide_output(doctree): 2 + 2 """ tree = doctree(source, thebe_config) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert cell.attributes["hide_output"] assert len(celloutput.children) == 0 @@ -455,7 +460,7 @@ def test_thebe_hide_code(doctree): 2 + 2 """ tree = doctree(source, thebe_config) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert cell.attributes["hide_code"] assert len(cell.children) == 2 @@ -480,7 +485,7 @@ def test_thebe_code_below(doctree): 2 + 2 """ tree = doctree(source, thebe_config) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, celloutput) = cell.children assert cell.attributes["code_below"] @@ -504,7 +509,7 @@ def test_thebe_button_auto(doctree): 1 + 1 """ tree = doctree(source, config=config) - assert len(tree.traverse(ThebeButtonNode)) == 1 + assert len(list(tree.findall(ThebeButtonNode))) == 1 def test_thebe_button_manual(doctree): @@ -517,14 +522,14 @@ def test_thebe_button_manual(doctree): .. thebe-button:: """ tree = doctree(source, config) - assert len(tree.traverse(ThebeButtonNode)) == 1 + assert len(list(tree.findall(ThebeButtonNode))) == 1 def test_thebe_button_none(doctree): config = 'jupyter_sphinx_thebelab_config = {"dummy": True}' source = "No Jupyter cells" tree = doctree(source, config) - assert len(tree.traverse(ThebeButtonNode)) == 0 + assert len(list(tree.findall(ThebeButtonNode))) == 0 def test_latex(doctree): @@ -539,9 +544,9 @@ def test_latex(doctree): for start, end in delimiter_pairs: tree = doctree(source.format(start, end)) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (_, celloutput) = cell.children - assert next(iter(celloutput.traverse(math_block))).astext() == r"\int" + assert next(celloutput.findall(math_block)).astext() == r"\int" def test_cell_output_to_nodes(doctree): @@ -582,7 +587,7 @@ def test_cell_output_to_nodes(doctree): for index, cell in enumerate(cells): cell = from_dict(cell) (output_node,) = cell_output_to_nodes(cell["outputs"], True, output_dir, None) - (image_node,) = output_node.traverse(image) + (image_node,) = output_node.findall(image) assert image_node.attributes["uri"] == img_locs[index] # Testing inline functionality @@ -615,7 +620,7 @@ def test_download_role(text, reftarget, caption, tmp_path): "document.settings.env.docname": "path/to/docname", "document.settings.env.srcdir": str(tmp_path), "document.settings.env.app.srcdir": str(tmp_path), - "reporter.get_source_and_line": lambda l: ("source", l), + "reporter.get_source_and_line": lambda line: ("source", line), } mock_inliner.configure_mock(**config) ret, msg = role("jupyter-download-notebook", text, text, 0, mock_inliner) @@ -680,7 +685,7 @@ def test_input_cell(doctree): 2 + 2 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, empty) = cell.children assert cell.attributes["hide_output"] is True assert cellinput.children[0].attributes["linenos"] is False @@ -696,7 +701,7 @@ def test_input_cell_linenos(doctree): 2 + 2 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) (cellinput, empty) = cell.children assert cell.attributes["hide_output"] is True assert cellinput.children[0].attributes["linenos"] is True @@ -715,7 +720,7 @@ def test_output_cell(doctree): 4 """ tree = doctree(source) - (cell,) = tree.traverse(JupyterCellNode) + (cell,) = tree.findall(JupyterCellNode) ( cellinput, celloutput, @@ -749,7 +754,7 @@ def test_multiple_directives(doctree): 5 """ tree = doctree(source) - (ex, jin) = tree.traverse(JupyterCellNode) + (ex, jin) = tree.findall(JupyterCellNode) (ex_in, ex_out) = ex.children (jin_in, jin_out) = jin.children assert ex_in.children[0].astext().strip() == "2 + 2" diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 3b045ff..0000000 --- a/tox.ini +++ /dev/null @@ -1,9 +0,0 @@ -[tox] -envlist = py38,py39,py310,py311,py312 - -[testenv] -deps = - sphinx - pytest -commands = - pytest