├── .github
├── dependabot.yml
├── release.yml
└── workflows
│ ├── tests.yml
│ └── tests_devdeps.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── codecov.yml
├── docs
├── _static
│ ├── custom.css
│ ├── logo-square.svg
│ └── logo-wide.svg
├── authoring
│ ├── basics.md
│ ├── custom-formats.Rmd
│ ├── index.md
│ ├── jupyter-notebooks.md
│ └── text-notebooks.md
├── computation
│ ├── coconut-lang.md
│ ├── execute.md
│ └── index.md
├── conf.py
├── configuration.md
├── docutils.md
├── index.md
├── quickstart.md
├── reference
│ ├── api.rst
│ ├── changelog.md
│ └── contributing.md
├── render
│ ├── format_code_cells.md
│ ├── glue.md
│ ├── hiding.md
│ ├── images
│ │ └── fun-fish.png
│ ├── index.md
│ ├── inline.md
│ ├── interactive.md
│ └── orphaned_nb.ipynb
└── requirements.txt
├── myst_nb
├── __init__.py
├── _compat.py
├── cli.py
├── core
│ ├── __init__.py
│ ├── config.py
│ ├── execute
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── cache.py
│ │ ├── direct.py
│ │ └── inline.py
│ ├── lexers.py
│ ├── loggers.py
│ ├── nb_to_tokens.py
│ ├── read.py
│ ├── render.py
│ ├── utils.py
│ └── variables.py
├── docutils_.py
├── ext
│ ├── __init__.py
│ ├── download.py
│ ├── eval
│ │ └── __init__.py
│ ├── execution_tables.py
│ ├── glue
│ │ ├── __init__.py
│ │ ├── crossref.py
│ │ ├── directives.py
│ │ ├── domain.py
│ │ ├── roles.py
│ │ └── utils.py
│ └── utils.py
├── sphinx_.py
├── sphinx_ext.py
├── static
│ ├── __init__.py
│ └── mystnb.css
└── warnings_.py
├── pyproject.toml
├── tests
├── conftest.py
├── nb_fixtures
│ ├── basic.txt
│ └── reporter_warnings.txt
├── notebooks
│ ├── basic_failing.ipynb
│ ├── basic_nometadata.md
│ ├── basic_relative.ipynb
│ ├── basic_run.ipynb
│ ├── basic_run_intl.ipynb
│ ├── basic_stderr.ipynb
│ ├── basic_unrun.ipynb
│ ├── basic_unrun.md
│ ├── complex_outputs.ipynb
│ ├── complex_outputs_unrun.ipynb
│ ├── custom-formats.Rmd
│ ├── custom-formats2.extra.exnt
│ ├── example.jpg
│ ├── file_level_config.ipynb
│ ├── file_level_config.md
│ ├── fun-fish.png
│ ├── hide_cell_content.ipynb
│ ├── ipywidgets.ipynb
│ ├── kernel_alias.md
│ ├── latex_build
│ │ ├── index.ipynb
│ │ └── other.ipynb
│ ├── locale
│ │ └── es
│ │ │ └── LC_MESSAGES
│ │ │ └── basic_run_intl.po
│ ├── merge_streams.ipynb
│ ├── merge_streams_parallel.ipynb
│ ├── metadata_figure.ipynb
│ ├── metadata_image.ipynb
│ ├── metadata_image_output.ipynb
│ ├── metadata_multiple_image.ipynb
│ ├── mystnb_codecell_file.md
│ ├── mystnb_codecell_file.py
│ ├── mystnb_codecell_file_warnings.md
│ ├── nb_exec_table.md
│ ├── sleep_10.ipynb
│ ├── sleep_10_metadata_timeout.ipynb
│ ├── unknown_mimetype.ipynb
│ ├── with_eval.md
│ └── with_glue.ipynb
├── test_ansi_lexer.py
├── test_cli.py
├── test_codecell_file.py
├── test_codecell_file
│ ├── test_codecell_file.ipynb
│ ├── test_codecell_file.xml
│ ├── test_codecell_file_warnings.ipynb
│ └── test_codecell_file_warnings.xml
├── test_docutils.py
├── test_eval.py
├── test_eval
│ └── test_sphinx.txt
├── test_execute.py
├── test_execute
│ ├── test_allow_errors_auto.ipynb
│ ├── test_allow_errors_auto.xml
│ ├── test_allow_errors_cache.ipynb
│ ├── test_allow_errors_cache.xml
│ ├── test_basic_failing_auto.ipynb
│ ├── test_basic_failing_auto.xml
│ ├── test_basic_failing_cache.ipynb
│ ├── test_basic_failing_cache.xml
│ ├── test_basic_failing_inline.ipynb
│ ├── test_basic_failing_inline.xml
│ ├── test_basic_unrun_auto.ipynb
│ ├── test_basic_unrun_auto.xml
│ ├── test_basic_unrun_cache.ipynb
│ ├── test_basic_unrun_cache.xml
│ ├── test_basic_unrun_inline.ipynb
│ ├── test_basic_unrun_inline.xml
│ ├── test_complex_outputs_unrun_auto.ipynb
│ ├── test_complex_outputs_unrun_auto.xml
│ ├── test_complex_outputs_unrun_cache.ipynb
│ ├── test_complex_outputs_unrun_cache.xml
│ ├── test_custom_convert_auto.ipynb
│ ├── test_custom_convert_auto.xml
│ ├── test_custom_convert_cache.ipynb
│ ├── test_custom_convert_cache.xml
│ ├── test_custom_convert_multiple_extensions_auto.ipynb
│ ├── test_custom_convert_multiple_extensions_auto.xml
│ ├── test_custom_convert_multiple_extensions_cache.ipynb
│ ├── test_custom_convert_multiple_extensions_cache.xml
│ ├── test_exclude_path.xml
│ ├── test_jupyter_cache_path.ipynb
│ ├── test_jupyter_cache_path.xml
│ ├── test_nb_exec_table.xml
│ ├── test_no_execute.ipynb
│ └── test_no_execute.xml
├── test_glue.py
├── test_glue
│ └── test_parser.txt
├── test_parser.py
├── test_parser
│ ├── test_basic_run.xml
│ ├── test_basic_run_intl.xml
│ ├── test_complex_outputs.xml
│ └── test_toctree_in_ipynb.xml
├── test_render_outputs.py
├── test_render_outputs
│ ├── test_basic_run.xml
│ ├── test_complex_outputs.xml
│ ├── test_complex_outputs_latex.xml
│ ├── test_file_level_config_ipynb.xml
│ ├── test_file_level_config_md.xml
│ ├── test_hide_cell_content.xml
│ ├── test_merge_streams.xml
│ ├── test_merge_streams_parallel.xml
│ ├── test_metadata_figure.xml
│ ├── test_metadata_image.xml
│ ├── test_metadata_image_output.xml
│ ├── test_metadata_multiple_image.xml
│ ├── test_stderr_remove.xml
│ ├── test_stderr_tag.xml
│ └── test_unknown_mimetype.xml
├── test_text_based.py
└── test_text_based
│ ├── test_basic_run.ipynb
│ ├── test_basic_run.xml
│ ├── test_basic_run_exec_off.ipynb
│ └── test_basic_run_exec_off.xml
└── tox.ini
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "pip"
9 | directory: "/"
10 | schedule:
11 | interval: "monthly"
12 |
13 | - package-ecosystem: "github-actions"
14 | directory: "/"
15 | schedule:
16 | interval: "monthly"
17 | groups:
18 | actions:
19 | patterns:
20 | - "*"
21 | labels:
22 | - "github_actions"
23 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | authors:
4 | - dependabot
5 | - pre-commit-ci
6 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: continuous-integration
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | tags:
7 | - 'v*'
8 | pull_request:
9 | schedule:
10 | # run every Monday at 5am UTC
11 | - cron: '0 5 * * 1'
12 | workflow_dispatch:
13 |
14 | jobs:
15 |
16 | tests:
17 |
18 | strategy:
19 | fail-fast: false
20 | matrix:
21 | os: [ubuntu-latest]
22 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
23 | sphinx: [""] # Newest Sphinx (any)
24 | myst-parser: [""] # Newest MyST Parser (any)
25 | include:
26 | # Just check the other platforms once
27 | - os: windows-latest
28 | python-version: "3.12"
29 | sphinx: "~=8.0"
30 | myst-parser: "~=4.0"
31 | pillow: "==11.0.0"
32 | - os: macos-latest
33 | python-version: "3.12"
34 | sphinx: "~=8.0"
35 | myst-parser: "~=4.0"
36 | pillow: "==11.0.0"
37 | - os: ubuntu-latest
38 | python-version: "3.12"
39 | sphinx: "~=8.0"
40 | myst-parser: "~=4.0"
41 | pillow: "==11.0.0"
42 | # Oldest known-compatible dependencies
43 | - os: ubuntu-latest
44 | python-version: "3.9"
45 | sphinx: "==5.0.0"
46 | myst-parser: "==1.0.0"
47 | pillow: "==11.0.0"
48 | # Mid-range dependencies
49 | - os: ubuntu-latest
50 | python-version: "3.11"
51 | sphinx: "==7.0.0"
52 | myst-parser: "==3.0.0"
53 | pillow: "==11.0.0"
54 | # Newest known-compatible dependencies
55 | - os: ubuntu-latest
56 | python-version: "3.12"
57 | sphinx: "==8.0.2"
58 | myst-parser: "==4.0.0"
59 | pillow: "==11.0.0"
60 |
61 | runs-on: ${{ matrix.os }}
62 |
63 | steps:
64 | - uses: actions/checkout@v4
65 | - name: Set up Python ${{ matrix.python-version }}
66 | uses: actions/setup-python@v5
67 | with:
68 | python-version: ${{ matrix.python-version }}
69 | allow-prereleases: true
70 | cache: pip
71 | - name: Install myst-nb with Sphinx ${{ matrix.sphinx }}
72 | shell: bash
73 | run: |
74 | pip install --upgrade "Sphinx${{ matrix.sphinx }}" "myst-parser${{ matrix.myst-parser }}" "pillow${{ matrix.pillow }}" -e .[testing]
75 | pip freeze
76 |
77 | - name: Run pytest
78 | run: pytest --durations=10
79 |
80 | coverage:
81 | needs: [tests]
82 | runs-on: ubuntu-latest
83 |
84 | steps:
85 | - uses: actions/checkout@v4
86 | - name: Set up Python ${{ matrix.python-version }}
87 | uses: actions/setup-python@v5
88 | with:
89 | python-version: "3.11"
90 | cache: pip
91 | - name: Install dependencies
92 | run: |
93 | pip install -e .[testing]
94 | pip freeze
95 |
96 | - name: Run pytest
97 | run: pytest --durations=10 --cov=myst_nb --cov-report=xml --cov-report=term-missing
98 |
99 | - name: Create cov
100 | run: coverage xml
101 | # for some reason the tests/conftest.py::check_nbs fixture breaks pytest-cov's cov-report outputting
102 | # this is why we run `coverage xml` afterwards (required by codecov)
103 |
104 | # TEMPORARY FIX: Disable codecov until we can get it working again
105 | - name: Upload to Codecov
106 | uses: codecov/codecov-action@v4
107 | if: false
108 | with:
109 | name: myst-nb-pytests
110 | flags: pytests
111 | files: ./coverage.xml
112 |
113 | publish:
114 |
115 | name: Publish to PyPi
116 | needs: [tests]
117 | if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
118 | runs-on: ubuntu-latest
119 | steps:
120 | - name: Checkout source
121 | uses: actions/checkout@v4
122 | - name: Set up Python
123 | uses: actions/setup-python@v5
124 | with:
125 | python-version: "3.10"
126 | - name: install flit
127 | run: |
128 | pip install flit~=3.4
129 | - name: Build and publish
130 | run: |
131 | flit publish
132 | env:
133 | FLIT_USERNAME: __token__
134 | FLIT_PASSWORD: ${{ secrets.PYPI_KEY }}
135 |
--------------------------------------------------------------------------------
/.github/workflows/tests_devdeps.yml:
--------------------------------------------------------------------------------
1 | name: continuous-integration-devdeps
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | schedule:
7 | # run every Monday at 5am UTC
8 | - cron: '0 5 * * 1'
9 | workflow_dispatch:
10 |
11 | jobs:
12 |
13 | tests:
14 |
15 | strategy:
16 | fail-fast: false
17 | matrix:
18 | sphinx: [""] # Newest Sphinx (any)
19 | myst-parser: [""] # Newest MyST Parser (any)
20 |
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - uses: actions/checkout@v4
25 | - name: Set up Python 3.12
26 | uses: actions/setup-python@v5
27 | with:
28 | python-version: "3.12"
29 | cache: pip
30 | - name: Install myst-nb with development Sphinx and myst-parser versions
31 | run: |
32 | pip install --upgrade pip
33 | pip install --upgrade git+https://github.com/executablebooks/MyST-Parser.git#egg=myst-parser git+https://github.com/sphinx-doc/sphinx.git#egg=sphinx -e .[testing]
34 |
35 | - name: Run pytest
36 | run: pytest --durations=10
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | wheels/
22 | pip-wheel-metadata/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | (PosixPath('/*
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
131 | # Jupyter Cache
132 | .jupyter_cache
133 |
134 | # OSX
135 | .DS_Store
136 |
137 | .vscode/
138 |
139 | todos.md
140 | _archive/
141 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # Install pre-commit hooks via
2 | # pre-commit install
3 |
4 | exclude: >
5 | (?x)^(
6 | \.vscode/settings\.json|
7 | tests/commonmark/commonmark\.json|
8 | .*\.xml|
9 | tests/.*\.txt
10 | )$
11 |
12 | ci:
13 | autoupdate_schedule: 'monthly'
14 |
15 | repos:
16 |
17 | - repo: https://github.com/pre-commit/pre-commit-hooks
18 | rev: v5.0.0
19 | hooks:
20 | - id: check-json
21 | - id: check-yaml
22 | - id: end-of-file-fixer
23 | - id: trailing-whitespace
24 | - id: check-added-large-files
25 | - id: check-case-conflict
26 | - id: check-merge-conflict
27 | - id: mixed-line-ending
28 | - id: trailing-whitespace
29 |
30 | - repo: https://github.com/astral-sh/ruff-pre-commit
31 | rev: v0.11.12
32 | hooks:
33 | - id: ruff
34 | args: ["--fix", "--show-fixes"]
35 | - id: ruff-format
36 |
37 | - repo: https://github.com/pre-commit/mirrors-mypy
38 | rev: v1.16.0
39 | hooks:
40 | - id: mypy
41 | args: [--config-file=pyproject.toml]
42 | additional_dependencies:
43 | - importlib_metadata
44 | - myst-parser~=2.0.0
45 | - "sphinx~=7.3.7"
46 | - nbclient
47 | - types-PyYAML
48 | files: >
49 | (?x)^(
50 | myst_nb/.+\.py|
51 | )$
52 |
53 | - repo: https://github.com/codespell-project/codespell
54 | rev: v2.4.1
55 | hooks:
56 | - id: codespell
57 | args: ["-S", "*.ipynb"]
58 |
--------------------------------------------------------------------------------
/.readthedocs.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | build:
4 | os: ubuntu-22.04
5 | tools:
6 | python: "3.11"
7 |
8 | python:
9 | install:
10 | - method: pip
11 | path: .
12 | extra_requirements:
13 | - rtd
14 | - requirements: docs/requirements.txt
15 |
16 | sphinx:
17 | configuration: docs/conf.py
18 | builder: html
19 | fail_on_warning: true
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2020, ExecutableBookProject
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MyST-NB
2 |
3 | [![Github-CI][github-ci]][github-link]
4 | [![Coverage Status][codecov-badge]][codecov-link]
5 | [![Documentation Status][rtd-badge]][rtd-link]
6 | [![PyPI][pypi-badge]][pypi-link]
7 | [![Conda Version][conda-badge]][conda-link]
8 |
9 | A collection of tools for working with Jupyter Notebooks in Sphinx.
10 |
11 | The primary tool this package provides is a Sphinx parser for `ipynb` files.
12 | This allows you to directly convert Jupyter Notebooks into Sphinx documents.
13 | It relies heavily on the [`MyST` parser](https://github.com/executablebooks/myst-parser).
14 |
15 | For more information, [see the MyST-NB documentation](https://myst-nb.readthedocs.io/en/latest/)
16 |
17 | ## Contributing
18 |
19 | We welcome all contributions!
20 | See the [Contributing Guide](https://myst-nb.readthedocs.io/en/latest/reference/contributing.html) for more details.
21 |
22 | [github-ci]: https://github.com/executablebooks/MyST-NB/workflows/continuous-integration/badge.svg?branch=master
23 | [github-link]: https://github.com/executablebooks/MyST-NB
24 | [rtd-badge]: https://readthedocs.org/projects/myst-nb/badge/?version=latest
25 | [rtd-link]: https://myst-nb.readthedocs.io/en/latest/?badge=latest
26 | [codecov-badge]: https://codecov.io/gh/executablebooks/MyST-NB/branch/master/graph/badge.svg
27 | [codecov-link]: https://codecov.io/gh/executablebooks/MyST-NB
28 | [pypi-badge]: https://img.shields.io/pypi/v/myst-nb.svg
29 | [pypi-link]: https://pypi.org/project/myst-nb
30 | [conda-badge]: https://img.shields.io/conda/vn/conda-forge/myst-nb.svg
31 | [conda-link]: https://anaconda.org/conda-forge/myst-nb
32 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | target: 80%
6 | threshold: 0.5%
7 | patch:
8 | default:
9 | target: 80%
10 | threshold: 0.5%
11 |
--------------------------------------------------------------------------------
/docs/_static/custom.css:
--------------------------------------------------------------------------------
1 | /** Add a counter before subsections **/
2 | h1 {
3 | counter-reset: subsection;
4 | }
5 | h2 {
6 | counter-reset: subsubsection;
7 | }
8 | h2::before {
9 | counter-increment: subsection;
10 | content: counter(subsection) ". ";
11 | }
12 | h3::before {
13 | counter-increment: subsubsection;
14 | content: counter(subsection) "." counter(subsubsection) ". ";
15 | }
16 |
--------------------------------------------------------------------------------
/docs/_static/logo-square.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/_static/logo-wide.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/authoring/basics.md:
--------------------------------------------------------------------------------
1 |
2 | (authoring/intro)=
3 | # The basics
4 |
5 | ## Default file formats
6 |
7 | As well as writing in the Sphinx default format, [RestructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) (`.rst`), loading `myst_nb` will also parse:
8 |
9 | - Markdown files (`.md`)
10 | - Jupyter notebooks (`.ipynb`)
11 | - MyST-NB text-based notebooks (`.md` + top-matter)
12 |
13 | ## Custom file extensions
14 |
15 | You can change which file extensions are parsed by MyST-NB using
16 | the [source_suffix](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-source_suffix) option in your `conf.py`, e.g.:
17 |
18 | ```python
19 | extensions = ["myst_nb"]
20 | source_suffix = {
21 | '.rst': 'restructuredtext',
22 | '.ipynb': 'myst-nb',
23 | '.myst': 'myst-nb',
24 | }
25 | ```
26 |
27 | ## Other notebook formats
28 |
29 | See the [](write/custom_formats) section, for how to integrate other Notebook formats into your build, and integration with [jupytext](https://github.com/mwouts/jupytext).
30 |
31 | ## MyST Markdown
32 |
33 | For all file formats, Markdown authoring is the backbone of MyST-NB.
34 | By default, the MyST flavour of Markdown is enabled,
35 | which extends [CommonMark](https://commonmark.org/) with RST inspired syntaxes to provide the additional functionality required for technical writing.
36 |
37 | In particular MyST adds targets, roles and directives syntax, allowing you to utilise all available Docutils/Sphinx features:
38 |
39 | ::::{grid} 2
40 | :gutter: 1
41 |
42 | :::{grid-item-card} RestructuredText
43 |
44 | ```
45 | .. _target:
46 | Header
47 | ------
48 |
49 | :role-name:`content`
50 |
51 | .. directive-name:: argument
52 | :parameter: value
53 |
54 | content
55 | ```
56 | :::
57 |
58 | :::{grid-item-card} MyST Markdown
59 |
60 | ````
61 | (target)=
62 | # Header
63 |
64 | {role-name}`content`
65 |
66 | ```{directive-name} argument
67 | :parameter: value
68 |
69 | content
70 | ```
71 | ````
72 | :::
73 | ::::
74 |
75 | :::{seealso}
76 | See the [](authoring/jupyter-notebooks) section, for more details on how to author Jupyter notebooks.
77 | :::
78 |
79 | ## Text-based notebooks
80 |
81 | MyST-NB text-based notebooks are a special format for storing Jupyter notebooks in a text file.
82 | They map directly to a Notebook file, without directly storing the code execution outputs.
83 |
84 | To designate a Markdown file as a text-based notebook, add the following top-matter to the start of the file:
85 |
86 | ```yaml
87 | ---
88 | file_format: mystnb
89 | kernelspec:
90 | name: python3
91 | ---
92 | ```
93 |
94 | The `kernelspec.name` should relate to a [Jupyter kernel](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels) installed in your environment.
95 |
96 | MyST-NB will also recognise [jupytext](https://jupytext.readthedocs.io) top-matter, such as:
97 |
98 | ```yaml
99 | ---
100 | kernelspec:
101 | name: python3
102 | display_name: python3
103 | jupytext:
104 | text_representation:
105 | extension: .md
106 | format_name: myst
107 | format_version: '0.13'
108 | jupytext_version: 1.13.8
109 | ---
110 | ```
111 |
112 | Code cells are then designated by the `code-cell` directive:
113 |
114 | ````markdown
115 | ```{code-cell}
116 | :tags: [my-tag]
117 |
118 | print("Hello world!")
119 | ```
120 | ````
121 |
122 | and Markdown can be split into cells by the `+++` break syntax:
123 |
124 | ```markdown
125 | Markdown cell 1
126 |
127 | +++ {"tags": ["my-tag"]}
128 |
129 | Markdown cell 2, with metadata tags
130 | ```
131 |
132 | :::{seealso}
133 | See the [](authoring/text-notebooks) section, for more details on text-based notebooks, and integration with [jupytext](https://jupytext.readthedocs.io).
134 | :::
135 |
136 | ## Configuration
137 |
138 | MyST-NB parsing, execution and rendering can be configured at three levels of specificity; globally, per file, and per notebook cell, with the most specific configuration taking precedence.
139 |
140 | See the [](config/intro) section, for more details on how to configure MyST-NB.
141 |
--------------------------------------------------------------------------------
/docs/authoring/custom-formats.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | author: "Marc Wouts"
3 | date: "June 16, 2018"
4 | jupyter:
5 | kernelspec:
6 | display_name: Python
7 | language: python
8 | name: python3
9 | ---
10 |
11 | (write/custom_formats)=
12 |
13 | # Custom Formats
14 |
15 | You can designate additional file types to be converted to Notebooks, and then executed / parsed in the same manner as regular Notebooks, by adding the following configuration to your `conf.py`:
16 |
17 | ```python
18 | nb_custom_formats = {
19 | ".mysuffix": "mylibrary.converter_function"
20 | }
21 | ```
22 |
23 | - The string should be a Python function that will be loaded by `import mylibrary.converter_function`
24 | - The function should take a file's contents (as a `str`) and return an [nbformat.NotebookNode](inv:nbformat#api)
25 |
26 | If the function takes additional keyword arguments, then you can specify these as dictionary in a second argument.
27 | For example this is what the default conversion would look like:
28 |
29 | ```python
30 | nb_custom_formats = {
31 | '.ipynb': ['nbformat.reads', {'as_version': 4}],
32 | }
33 | ```
34 |
35 | :::{important}
36 |
37 | By default, Markdown cells in the Notebook will be parsed using the same MyST parser configuration as for other Markdown files ([see available configuration options](config/intro)).
38 |
39 | But, if this is incompatible with your file format, then you can specify for the Markdown to be parsed as **strictly CommonMark**, using a third argument:
40 |
41 | ```python
42 | nb_custom_formats = {
43 | '.ipynb': ['nbformat.reads', {'as_version': 4}, True],
44 | }
45 | ```
46 |
47 | :::
48 |
49 | Finally, for text-based formats, MyST-NB also searches for an optional `source_map` key in the output Notebook's metadata.
50 | This key should be a list mapping each cell to the starting line number in the original source file, for example for a notebook with three cells:
51 |
52 | ```json
53 | {
54 | "metadata": {
55 | "source_map": [10, 21, 53]
56 | }
57 | }
58 | ```
59 |
60 | This mapping allows for "true" error reporting, as described in [](myst/error-reporting).
61 |
62 | ## Using Jupytext
63 |
64 | A common conversion tool is [jupytext](https://github.com/mwouts/jupytext), which has been used to convert this very `.Rmd` file to a notebook!
65 |
66 | The configuration looks like:
67 |
68 | ```python
69 | nb_custom_formats = {
70 | ".Rmd": ["jupytext.reads", {"fmt": "Rmd"}]
71 | }
72 | ```
73 |
74 | :::{important}
75 | For full compatibility with `myst-nb`, `jupytext>=1.11.2` should be used.
76 | :::
77 |
78 | For example:
79 |
80 | ```
81 | \```{python echo=TRUE}
82 | import pandas as pd
83 | series = pd.Series({'A':1, 'B':3, 'C':2})
84 | pd.DataFrame({"Columne A": series})
85 | \```
86 | ```
87 |
88 | ```{python echo=TRUE}
89 | import pandas as pd
90 | series = pd.Series({'A':1, 'B':3, 'C':2})
91 | pd.DataFrame({"Columne A": series})
92 | ```
93 |
94 | ```
95 | \```{python bar_plot, echo=FALSE, fig.height=5, fig.width=8}
96 | series.plot(kind='bar', title='Sample plot')
97 | \```
98 | ```
99 |
100 | ```{python bar_plot, echo=FALSE, fig.height=5, fig.width=8}
101 | series.plot(kind='bar', title='Sample plot')
102 | ```
103 |
104 | ## Acknowledgements
105 |
106 | Thanks to [nbsphinx](https://nbsphinx.readthedocs.io), for providing the initial implementation which this was built on.
107 |
--------------------------------------------------------------------------------
/docs/authoring/index.md:
--------------------------------------------------------------------------------
1 | # Authoring
2 |
3 | Create content in one or more formats.
4 |
5 | ```{toctree}
6 | :maxdepth: 1
7 |
8 | basics
9 | jupyter-notebooks
10 | text-notebooks
11 | custom-formats
12 | ```
13 |
--------------------------------------------------------------------------------
/docs/authoring/jupyter-notebooks.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: python3
5 | ---
6 |
7 | (authoring/jupyter-notebooks)=
8 | # Jupyter Notebooks
9 |
10 | This notebook is a demonstration of directly-parsing Jupyter Notebooks into
11 | Sphinx using the MyST parser.[^download]
12 |
13 | [^download]: This notebook can be downloaded as **{nb-download}`jupyter-notebooks.ipynb`** and {download}`jupyter-notebooks.md`
14 |
15 | ## Markdown
16 |
17 | :::{seealso}
18 | For more information about what you can write with MyST Markdown, see the
19 | [MyST Parser documentation](inv:myst#intro/get-started).
20 | :::
21 |
22 | ### Configuration
23 |
24 | The MyST-NB parser derives from [the base MyST-Parser](inv:myst#intro/get-started), and so all the same configuration options are available.
25 | See the [MyST configuration options](inv:myst#sphinx/config-options) for the full set of options, and [MyST syntax guide](inv:myst#syntax/core) for all the syntax options.
26 |
27 | To build documentation from this notebook, the following options are set:
28 |
29 | ```python
30 | myst_enable_extensions = [
31 | "amsmath",
32 | "colon_fence",
33 | "deflist",
34 | "dollarmath",
35 | "html_image",
36 | ]
37 | myst_url_schemes = ("http", "https", "mailto")
38 | ```
39 |
40 | :::{note}
41 | Loading the `myst_nb` extension also activates the [`myst_parser`](inv:myst#index) extension, for enabling the MyST flavour of Markdown.
42 | It is not required to add this explicitly in the list of `extensions`.
43 | :::
44 |
45 | ### Syntax
46 |
47 | As you can see, markdown is parsed as expected. Embedding images should work as expected.
48 | For example, here's the MyST-NB logo:
49 |
50 | ```md
51 | 
52 | ```
53 |
54 | 
55 |
56 | By adding `"html_image"` to the `myst_enable_extensions` list in the sphinx configuration ([see here](inv:myst#syntax/images)), you can even add HTML `img` tags with attributes:
57 |
58 | ```html
59 |
60 | ```
61 |
62 |
63 |
64 | Because MyST-NB is using the MyST-markdown parser, you can include rich markdown with Sphinx in your notebook.
65 | For example, here's a note admonition block:
66 |
67 | :::::{note}
68 | **Wow**, a note!
69 | It was generated with this code ([as explained here](inv:myst:std:label#syntax/admonitions)):
70 |
71 | ````md
72 | :::{note}
73 | **Wow**, a note!
74 | :::
75 | ````
76 |
77 | :::::
78 |
79 | If you wish to use "bare" LaTeX equations, then you should add `"amsmath"` to the `myst_enable_extensions` list in the sphinx configuration.
80 | This is [explained here](inv:myst:std:label#syntax/amsmath), and works as such:
81 |
82 | ```latex
83 | \begin{equation}
84 | \frac {\partial u}{\partial x} + \frac{\partial v}{\partial y} = - \, \frac{\partial w}{\partial z}
85 | \end{equation}
86 |
87 | \begin{align*}
88 | 2x - 5y &= 8 \\
89 | 3x + 9y &= -12
90 | \end{align*}
91 | ```
92 |
93 | \begin{equation}
94 | \frac {\partial u}{\partial x} + \frac{\partial v}{\partial y} = - \, \frac{\partial w}{\partial z}
95 | \end{equation}
96 |
97 | \begin{align*}
98 | 2x - 5y &= 8 \\
99 | 3x + 9y &= -12
100 | \end{align*}
101 |
102 | Also you can use features like **equation numbering** and referencing in the notebooks:
103 |
104 | ```md
105 | $$e^{i\pi} + 1 = 0$$ (euler)
106 | ```
107 |
108 | $$e^{i\pi} + 1 = 0$$ (euler)
109 |
110 | Euler's identity, equation {math:numref}`euler`, was elected one of the
111 | most beautiful mathematical formulas.
112 |
113 | You can see the syntax used for this example [here in the MyST documentation](inv:myst:std:label#syntax/math).
114 |
115 | ## Code cells and outputs
116 |
117 | You can run cells, and the cell outputs will be captured and inserted into
118 | the resulting Sphinx site.
119 |
120 | ### `__repr__` and HTML outputs
121 |
122 | For example, here's some simple Python:
123 |
124 | ```{code-cell} ipython3
125 | import matplotlib.pyplot as plt
126 | import numpy as np
127 | data = np.random.rand(3, 100) * 100
128 | data[:, :10]
129 | ```
130 |
131 | This will also work with HTML outputs
132 |
133 | ```{code-cell} ipython3
134 | import pandas as pd
135 | df = pd.DataFrame(data.T, columns=['a', 'b', 'c'])
136 | df.head()
137 | ```
138 |
139 | as well as math outputs
140 |
141 | ```{code-cell} ipython3
142 | from IPython.display import Math
143 | Math(r"\sum_{i=0}^n i^2 = \frac{(n^2+n)(2n+1)}{6}")
144 | ```
145 |
146 | This works for error messages as well:
147 |
148 | ```{code-cell} ipython3
149 | :tags: [raises-exception]
150 |
151 | print("This will be properly printed...")
152 | print(thiswont)
153 | ```
154 |
155 | ### Images
156 |
157 | Images that are generated from your code (e.g., with Matplotlib) will also
158 | be embedded.
159 |
160 | ```{code-cell} ipython3
161 | fig, ax = plt.subplots()
162 | ax.scatter(*data, c=data[2])
163 | ```
164 |
165 | ## Raw cells
166 |
167 | The [raw cell type](https://nbformat.readthedocs.io/en/latest/format_description.html#raw-nbconvert-cells) can be used to specifically render the content as a specific [MIME media type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types).
168 |
169 | ````markdown
170 | ```{raw-cell}
171 | :format: text/html
172 |
173 |
My cat is very grumpy.
174 | ```
175 | ````
176 |
177 | ```{raw-cell}
178 | :format: text/html
179 |
180 | My cat is very grumpy.
181 | ```
182 |
--------------------------------------------------------------------------------
/docs/computation/coconut-lang.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: coconut
5 | ---
6 |
7 | # Jupyter kernels
8 |
9 | A Jupyter Notebook can utilise any program kernel that implements the [Jupyter messaging protocol](http://jupyter-client.readthedocs.io/en/latest/messaging.html) for executing code.
10 | There are kernels available for [Python](http://ipython.org/notebook.html), [Julia](https://github.com/JuliaLang/IJulia.jl), [Ruby](https://github.com/minad/iruby), [Haskell](https://github.com/gibiansky/IHaskell) and [many other languages](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels).
11 |
12 | In this notebook we demonstrate executing code with the [Coconut Programming Language](http://coconut-lang.org), a variant of Python built for *simple, elegant, Pythonic functional programming*.
13 |
14 | In the first example we will define a recursive `factorial` function, a fundamentally functional approach that doesn’t involve any state changes or loops:
15 |
16 | ```{code-cell} coconut
17 | def factorial(n):
18 | """Compute n! where n is an integer >= 0."""
19 | case n:
20 | match 0:
21 | return 1
22 | match x is int if x > 0:
23 | return x * factorial(x-1)
24 | else:
25 | raise TypeError("the argument to factorial must be an integer >= 0")
26 |
27 | 3 |> factorial |> print
28 | ```
29 |
30 | Although this example is very basic, pattern-matching is both one of Coconut’s most powerful and most complicated features.
31 |
32 | In the second example, we implement the quick sort algorithm.
33 | This quick_sort algorithm works using a bunch of new constructs:
34 |
35 | ```{code-cell} coconut
36 | def quick_sort(l):
37 | """Sort the input iterator using the quick sort algorithm."""
38 | match [head] :: tail in l:
39 | tail = reiterable(tail)
40 | yield from quick_sort(left) :: [head] :: quick_sort(right) where:
41 | left = (x for x in tail if x < head)
42 | right = (x for x in tail if x >= head)
43 | # By yielding nothing if the match falls through, we implicitly return an empty iterator.
44 |
45 | [3,0,4,2,1] |> quick_sort |> list |> print
46 | ```
47 |
48 | Finally, we see that exceptions are raised as one would expect:
49 |
50 | ```{code-cell} coconut
51 | :tags: [raises-exception]
52 | x
53 | ```
54 |
--------------------------------------------------------------------------------
/docs/computation/index.md:
--------------------------------------------------------------------------------
1 | # Computations
2 |
3 | Execute code and cache its output.
4 |
5 | ```{toctree}
6 | execute
7 | coconut-lang
8 | ```
9 |
--------------------------------------------------------------------------------
/docs/docutils.md:
--------------------------------------------------------------------------------
1 | (render/single-page)=
2 | # Single page builds
3 |
4 | ```{versionadded} 0.14.0
5 | ```
6 |
7 | Sphinx, and thus MyST-NB, is built on top of the [Docutils](https://docutils.sourceforge.io/docs/) package.
8 | MyST-NB offers a renderer, parser and CLI-interface for working directly with Docutils, independent of Sphinx, as described below.
9 |
10 | :::{note}
11 | Since these tools are independent of Sphinx, this means they cannot parse any Sphinx or Sphinx extensions specific roles or directives.
12 | :::
13 |
14 | On installing MyST-NB, the following CLI-commands are made available:
15 |
16 | - `mystnb-docutils-html`: converts notebooks to HTML
17 | - `mystnb-docutils-html5`: converts notebooks to HTML5
18 | - `mystnb-docutils-latex`: converts notebooks to LaTeX
19 | - `mystnb-docutils-xml`: converts notebooks to docutils-native XML
20 | - `mystnb-docutils-pseudoxml`: converts notebooks to pseudo-XML (to visualise the AST structure)
21 |
22 | Each command can be piped stdin or take a file path as an argument:
23 |
24 | ```console
25 | $ mystnb-docutils-html --help
26 | $ mystnb-docutils-html --nb-execution-mode="off" hello-world.ipynb
27 | $ mystnb-docutils-html --nb-read-as-md="yes" hello-world.md
28 | ```
29 |
30 | The commands are based on the [Docutils Front-End Tools](https://docutils.sourceforge.io/docs/user/tools.html), and so follow the same argument and options structure, included many of the MyST NB specific options detailed in the [](config/intro) section.
31 |
32 | :::{dropdown} Shared Docutils CLI Options
33 | ```{docutils-cli-help}
34 | ```
35 | :::
36 |
37 | The CLI commands can also utilise the [`docutils.conf` configuration file](https://docutils.sourceforge.io/docs/user/config.html) to configure the behaviour of the CLI commands. For example:
38 |
39 | ```ini
40 | # These entries affect all processing:
41 | [general]
42 | nb_execution_mode: off
43 |
44 | # These entries affect specific HTML output:
45 | [html writers]
46 | embed-stylesheet: no
47 |
48 | [html5 writer]
49 | stylesheet-dirs: path/to/html5_polyglot/
50 | stylesheet-path: minimal.css, responsive.css
51 | ```
52 |
53 | You can also use the {py:class}`myst_nb.docutils_.Parser` class programmatically with the [Docutils publisher API](https://docutils.sourceforge.io/docs/api/publisher.html):
54 |
55 | ```python
56 | from docutils.core import publish_string
57 | from nbformat import writes
58 | from nbformat.v4 import new_notebook
59 | from myst_nb.docutils_ import Parser
60 |
61 | source = writes(new_notebook())
62 | output = publish_string(
63 | source=source,
64 | writer_name="html5",
65 | settings_overrides={
66 | "nb_execution_mode": "off",
67 | "embed_stylesheet": False,
68 | },
69 | parser=Parser(),
70 | )
71 | ```
72 |
73 | Finally, you can include MyST Markdown files within a RestructuredText file, using the [`include` directive](https://docutils.sourceforge.io/docs/ref/rst/directives.html#include):
74 |
75 | ```rst
76 | .. include:: include.ipynb
77 | :parser: myst_nb.docutils_
78 | ```
79 |
80 | ```{important}
81 | The `parser` option requires `docutils>=0.17`
82 | ```
83 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | sd_hide_title: true
3 | ---
4 |
5 | # Overview
6 |
7 | ::::{grid}
8 | :reverse:
9 | :gutter: 3 4 4 4
10 | :margin: 1 2 1 2
11 |
12 | :::{grid-item}
13 | :columns: 12 4 4 4
14 |
15 | ```{image} _static/logo-square.svg
16 | :width: 200px
17 | :class: sd-m-auto
18 | ```
19 |
20 | :::
21 |
22 | :::{grid-item}
23 | :columns: 12 8 8 8
24 | :child-align: justify
25 | :class: sd-fs-5
26 |
27 | ```{rubric} Jupyter Notebook Publishing
28 | ```
29 |
30 | A Sphinx and Docutils extension for compiling Jupyter Notebooks into high quality documentation formats.
31 |
32 | ```{button-ref} quickstart
33 | :ref-type: doc
34 | :color: primary
35 | :class: sd-rounded-pill
36 |
37 | Get Started
38 | ```
39 |
40 | :::
41 |
42 | ::::
43 |
44 | ----------------
45 |
46 | ::::{grid} 1 2 2 3
47 | :gutter: 1 1 1 2
48 |
49 | :::{grid-item-card} {material-regular}`edit_note;2em` Write
50 | :link: authoring/intro
51 | :link-type: ref
52 |
53 | Mix Jupyter notebooks with text-based notebooks, Markdown and RST documents.\
54 | Use MyST Markdown syntax to support technical authoring features such as cross-referencing, figures, and admonitions.
55 |
56 | +++
57 | [Learn more »](authoring/intro)
58 | :::
59 |
60 | :::{grid-item-card} {material-regular}`published_with_changes;2em` Compute
61 | :link: execute/intro
62 | :link-type: ref
63 |
64 | Generate dynamic outputs using Jupyter kernels, with configurable execution handling.\
65 | Cache execution outputs, for fast re-builds.
66 |
67 | +++
68 | [Learn more »](execute/intro)
69 | :::
70 |
71 | :::{grid-item-card} {material-regular}`preview;2em` Render
72 | :link: render/code-cells
73 | :link-type: ref
74 |
75 | Convert Jupyter execution outputs to rich embedded content.\
76 | Insert computed variables within the document flow.\
77 | Build single or collections of documents into multiple formats (HTML, PDF, ...).
78 |
79 | +++
80 | [Learn more »](render/code-cells)
81 | :::
82 |
83 | ::::
84 |
85 | ----------------
86 |
87 | MyST-NB is a module within the [Executable Books Project](https://executablebooks.org),
88 | an international collaboration to build open source tools that facilitate publishing computational narratives using the Jupyter ecosystem.
89 | It is also a core component of [Jupyter Book](inv:jb#intro).
90 |
91 | Check out the [Gallery of Jupyter Books](https://executablebooks.org/en/latest/gallery),
92 | for inspiration from across the community.
93 |
94 | See also, the [MyST-Markdown VS Code extension](https://marketplace.visualstudio.com/items?itemName=ExecutableBookProject.myst-highlight)
95 | and [jupyterlab-myst](https://github.com/executablebooks/jupyterlab-myst), for editor tools to author your notebooks.
96 |
97 | ```{toctree}
98 | :hidden:
99 | :maxdepth: 2
100 |
101 | quickstart
102 | ```
103 |
104 | ```{toctree}
105 | :caption: Guides
106 | :hidden:
107 | :maxdepth: 2
108 |
109 | authoring/index
110 | computation/index
111 | render/index
112 | configuration
113 | docutils
114 | ```
115 |
116 | ```{toctree}
117 | :caption: Reference
118 | :hidden:
119 | :titlesonly:
120 | :maxdepth: 1
121 |
122 | reference/api
123 | reference/changelog
124 | reference/contributing
125 | ```
126 |
--------------------------------------------------------------------------------
/docs/quickstart.md:
--------------------------------------------------------------------------------
1 | # Get Started
2 |
3 | `myst-nb` is distributed as a Python package and requires no non-Python dependencies.
4 |
5 | Use pip to install `myst-nb`:
6 |
7 | ```bash
8 | pip install myst-nb
9 | ```
10 |
11 | You can use the `mystnb-quickstart` CLI to quickly create an example Sphinx + MyST-NB project:
12 |
13 | ```bash
14 | mystnb-quickstart my_project/docs/
15 | ```
16 |
17 | or simply add `myst_nb` to your existing Sphinx configuration:
18 |
19 | ```python
20 | extensions = [
21 | ...,
22 | "myst_nb"
23 | ]
24 | ```
25 |
26 | By default, MyST-NB will now parse both markdown (`.md`) and notebooks (`.ipynb`).
27 |
28 | If you used the `myst_parser` extension already, remove it from the extension list to avoid conflict — it is imported by `myst_nb` automatically; all its options, such as `myst_enable_extension`, will be processed.
29 |
30 |
31 | ```{button-ref} authoring/intro
32 | :ref-type: myst
33 | :color: primary
34 |
35 | Begin authoring your content {material-regular}`navigate_next;2em`
36 | ```
37 |
38 | Once you have finished authoring your content, you can now use the [sphinx-build CLI](https://www.sphinx-doc.org/en/master/man/sphinx-build.html) to build your documentation, e.g.
39 |
40 | ```bash
41 | sphinx-build -nW --keep-going -b html docs/ docs/_build/html
42 | ```
43 |
44 |
45 | :::{tip}
46 | MyST-NB is parallel-friendly, so you can also distribute the build (and execution of notebooks) over *N* processes with: `sphinx-build -j 4`
47 | :::
48 |
49 | ```{admonition} The execution environment is the same as your Sphinx environment
50 | Your Sphinx build shares the same environment with the notebooks you execute during a build.
51 | Ensure that you call the correct `sphinx-build` command when building your documentation, or the environment needed to run the notebooks may not be correct.
52 | This often happens if you see an `Extension error` in the build log, or an error from `jupyter-cache`.
53 | ```
54 |
55 |
56 | :::{seealso}
57 | Check out [Read the Docs](https://docs.readthedocs.io) for hosting and *continuous deployment* of documentation
58 | :::
59 |
--------------------------------------------------------------------------------
/docs/reference/api.rst:
--------------------------------------------------------------------------------
1 | .. _api/main:
2 |
3 | Python API
4 | ==========
5 |
6 | The parsing of a notebook consists of a number of stages, with each stage separated into a separate module:
7 |
8 | 1. The configuration is set (from a file or CLI)
9 | 2. The parser is called with an input string and source
10 | 3. The parser reads the input string to a notebook node
11 | 4. The notebook is converted to a Markdown-It tokens syntax tree
12 | 5. The notebook code outputs are potentially updated, via execution or from a cache
13 | 6. The syntax tree is transformed to a docutils document AST (calling the renderer plugin)
14 | 7. The docutils document is processed by docutils/sphinx, to create the desired output format(s)
15 |
16 | Configuration
17 | -------------
18 |
19 | .. autoclass:: myst_nb.core.config.NbParserConfig
20 | :members:
21 |
22 | Parsers
23 | -------
24 |
25 | .. autoclass:: myst_nb.docutils_.Parser
26 | :members:
27 |
28 | .. autoclass:: myst_nb.sphinx_.Parser
29 | :members:
30 |
31 | Read
32 | ----
33 |
34 | .. autoclass:: myst_nb.core.read.NbReader
35 | :members:
36 |
37 | .. autofunction:: myst_nb.core.read.create_nb_reader
38 |
39 | .. autofunction:: myst_nb.core.read.is_myst_markdown_notebook
40 |
41 | .. autofunction:: myst_nb.core.read.read_myst_markdown_notebook
42 |
43 | Execute
44 | -------
45 |
46 | .. autofunction:: myst_nb.core.execute.create_client
47 |
48 | .. autoclass:: myst_nb.core.execute.base.NotebookClientBase
49 | :members:
50 |
51 | .. autoclass:: myst_nb.core.execute.direct.NotebookClientDirect
52 |
53 | .. autoclass:: myst_nb.core.execute.cache.NotebookClientCache
54 |
55 | .. autoclass:: myst_nb.core.execute.inline.NotebookClientInline
56 |
57 | .. autoexception:: myst_nb.core.execute.base.ExecutionError
58 |
59 | .. autoexception:: myst_nb.core.execute.base.EvalNameError
60 |
61 | .. autoclass:: myst_nb.core.execute.base.ExecutionResult
62 | :members:
63 |
64 | Render plugin
65 | -------------
66 |
67 | .. autoclass:: myst_nb.core.render.MimeData
68 | :members:
69 |
70 | .. autoclass:: myst_nb.core.render.NbElementRenderer
71 | :members:
72 |
73 | .. autoclass:: myst_nb.core.render.MimeRenderPlugin
74 | :members:
75 | :undoc-members:
76 |
77 | .. autoclass:: myst_nb.core.render.ExampleMimeRenderPlugin
78 | :members:
79 | :undoc-members:
80 |
81 | Lexers
82 | ------
83 |
84 | .. autoclass:: myst_nb.core.lexers.AnsiColorLexer
85 | :members:
86 | :undoc-members:
87 | :show-inheritance:
88 |
89 | Loggers
90 | -------
91 |
92 | .. autoclass:: myst_nb.core.loggers.DocutilsDocLogger
93 | :members:
94 | :undoc-members:
95 | :show-inheritance:
96 |
97 |
98 | .. autoclass:: myst_nb.core.loggers.SphinxDocLogger
99 | :members:
100 | :undoc-members:
101 | :show-inheritance:
102 |
--------------------------------------------------------------------------------
/docs/reference/changelog.md:
--------------------------------------------------------------------------------
1 | ```{include} ../../CHANGELOG.md
2 | :relative-docs: docs/
3 | ```
4 |
--------------------------------------------------------------------------------
/docs/render/hiding.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: python3
5 | ---
6 |
7 | # Hide cell contents
8 |
9 | You can use Jupyter Notebook **cell tags** to control some of the behavior of
10 | the rendered notebook.[^download]
11 | If you are using cell tags for the first time, you can read more about them in this tutorial
12 |
13 | [^download]: This notebook can be downloaded as
14 | **{nb-download}`hiding.ipynb`** and {download}`hiding.md`
15 |
16 | (use/hiding/code)=
17 |
18 | ## Hide code cells
19 |
20 | You can use **cell tags** to control the content hidden with code cells at the cell level.
21 | Add the following tags to a cell's metadata to control
22 | what to hide in code cells:
23 |
24 | * **`hide-input`** tag to hide the cell inputs
25 | * **`hide-output`** to hide the cell outputs
26 | * **`hide-cell`** to hide the entire cell
27 |
28 | For example, we'll show cells with each below.
29 |
30 | ```{code-cell} ipython3
31 | :tags: [remove-cell]
32 |
33 | import matplotlib.pyplot as plt
34 | import numpy as np
35 | data = np.random.rand(2, 100) * 100
36 | ```
37 |
38 | Here is a cell with a `hide-input` tag.
39 |
40 | ```{code-cell} ipython3
41 | :tags: [hide-input]
42 |
43 | # This cell has a hide-input tag
44 | fig, ax = plt.subplots()
45 | points =ax.scatter(*data, c=data[0], s=data[0])
46 | ```
47 |
48 | Here's a cell with a `hide-output` tag:
49 |
50 | ```{code-cell} ipython3
51 | :tags: [hide-output]
52 |
53 | # This cell has a hide-output tag
54 | fig, ax = plt.subplots()
55 | points =ax.scatter(*data, c=data[0], s=data[0])
56 | ```
57 |
58 | Here's a cell with both `hide-input` and `hide-output` tags:
59 |
60 | ```{code-cell} ipython3
61 | :tags: [hide-input, hide-output]
62 |
63 | # This cell has a hide-output tag
64 | fig, ax = plt.subplots()
65 | points =ax.scatter(*data, c=data[0], s=data[0])
66 | ```
67 |
68 | Here's a cell with a `hide-cell` tag:
69 |
70 | ```{code-cell} ipython3
71 | :tags: [hide-cell]
72 |
73 | # This cell has a hide-cell tag
74 | fig, ax = plt.subplots()
75 | points =ax.scatter(*data, c=data[0], s=data[0])
76 | ```
77 |
78 | Finally, a cell with both `remove-input` (see below) and `hide-output` tags:
79 |
80 | ```{code-cell} ipython3
81 | :tags: [remove-input, hide-output]
82 |
83 | fig, ax = plt.subplots()
84 | points = ax.scatter(*data, c=data[0], s=data[0])
85 | ```
86 |
87 | You can control the hide/show prompts by using the `code_prompt_show` and `code_prompt_hide` configuration options.
88 | The optional `{type}` placeholder will be replaced with `content`, `source`, or `outputs`, depending on the hide tag.
89 | See the {ref}`config/intro` section for more details.
90 |
91 | ````markdown
92 |
93 | ```{code-cell} ipython3
94 | :tags: [hide-cell]
95 | :mystnb:
96 | : code_prompt_show: "My show prompt for {type}"
97 | : code_prompt_hide: "My hide prompt for {type}"
98 |
99 | print("hallo world")
100 | ```
101 | ````
102 |
103 | ```{code-cell} ipython3
104 | :tags: [hide-cell]
105 | :mystnb:
106 | : code_prompt_show: "My show prompt for {type}"
107 | : code_prompt_hide: "My hide prompt for {type}"
108 |
109 | print("hallo world")
110 | ```
111 |
112 | (use/hiding/markdown)=
113 |
114 | ## Hide markdown cells
115 |
116 | You cannot hide an entire markdown cell, but you can hide sections of markdown **content** by using roles and directives.
117 |
118 | For information on how to hide / toggle markdown content in Sphinx, see either [the `sphinx-togglebutton` documentation](https://sphinx-togglebutton.readthedocs.io/en/latest/) or the [`sphinx-design` dropdowns documentation](https://sphinx-design.readthedocs.io/en/latest/dropdowns.html).
119 |
120 | (use/removing)=
121 |
122 | ## Remove parts of cells
123 |
124 | Sometimes, you want to entirely remove parts of a cell so that it doesn't make it into the output at all.
125 |
126 | To do this at the global level, use the `nb_remove_code_source` or `nb_remove_code_outputs` configuration options, or at a per-file level, e.g.
127 |
128 | ```yaml
129 | ---
130 | mystnb:
131 | remove_code_source: true
132 | remove_code_outputs: true
133 | ---
134 | ```
135 |
136 | See the [configuration section](config/intro) for more details.
137 |
138 | At a per-cell level you can use the same tag pattern described above,
139 | but with the word `remove_` instead of `hide_`. Use the following tags:
140 |
141 | * **`remove-input`** tag to remove the cell inputs
142 | * **`remove-output`** to remove the cell outputs
143 | * **`remove-cell`** to remove the entire cell
144 |
145 | +++
146 |
147 | Here is a cell with a `remove-input` tag. The inputs will not make it into
148 | the page at all.
149 |
150 | ```{code-cell} ipython3
151 | :tags: [remove-input]
152 |
153 | fig, ax = plt.subplots()
154 | points =ax.scatter(*data, c=data[0], s=data[0])
155 | ```
156 |
157 | Here's a cell with a `remove-output` tag:
158 |
159 | ```{code-cell} ipython3
160 | :tags: [remove-output]
161 |
162 | fig, ax = plt.subplots()
163 | points = ax.scatter(*data, c=data[0], s=data[0])
164 | ```
165 |
166 | And the following cell has a `remove-cell` tag (there should be nothing
167 | below, since the cell will be gone).
168 |
169 | ```{code-cell} ipython3
170 | :tags: [remove-cell]
171 |
172 | fig, ax = plt.subplots()
173 | points = ax.scatter(*data, c=data[0], s=data[0])
174 | ```
175 |
--------------------------------------------------------------------------------
/docs/render/images/fun-fish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/executablebooks/MyST-NB/201a48c2fff428ba15eaed096dec2f43b040ddc1/docs/render/images/fun-fish.png
--------------------------------------------------------------------------------
/docs/render/index.md:
--------------------------------------------------------------------------------
1 | # Rendering
2 |
3 | Convert Jupyter execution outputs to embedded content,
4 | and build output formats.
5 |
6 | ```{toctree}
7 | :maxdepth: 1
8 | format_code_cells
9 | hiding
10 | interactive
11 | inline
12 | glue
13 | ```
14 |
--------------------------------------------------------------------------------
/docs/render/inline.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: python3
5 | mystnb:
6 | execution_mode: 'inline'
7 | ---
8 |
9 | (render/eval)=
10 |
11 | # Inline variable evaluation (eval)
12 |
13 | ```{versionadded} 0.15.0
14 | ```
15 |
16 | The `eval` submodule allows you to insert code variables directly into the text flow of your documentation.
17 |
18 | Use of `eval` requires that the [notebook execution mode](execute/modes) is set to `inline`, since the variables are evaluated by the notebook kernel.
19 | For example, using the [top-matter](authoring/text-notebooks):
20 |
21 | ```yaml
22 | ---
23 | file_format: mystnb
24 | kernelspec:
25 | name: python3
26 | mystnb:
27 | execution_mode: 'inline'
28 | ---
29 | ```
30 |
31 | ## Basic example
32 |
33 | Below we set a variable `v1` within a code cell.
34 |
35 | ```{code-cell} ipython3
36 | v1 = "My variable"
37 | ```
38 |
39 | Using the `eval` role, we can insert the variable `v1` into the text of a paragraph:
40 |
41 | `` {eval}`v1` `` -> {eval}`v1`
42 |
43 | If we update the variable, we can see the change reflected in subsequent evaluation:
44 |
45 | ```{code-cell} ipython3
46 | v1 = "My new variable"
47 | ```
48 |
49 | `` {eval}`v1` `` -> {eval}`v1`
50 |
51 | :::{important}
52 | Variable names must match the regex `[a-zA-Z][a-zA-Z0-9_]*`
53 | :::
54 |
55 | ## Inserting different output types
56 |
57 | Any variable type can be inserted into the text flow using the `eval` role,
58 | and the most suitable output type will be used, based on the output format (see {ref}`render/output/priority` for more information).
59 | For example:
60 |
61 | ```{code-cell} ipython3
62 | import ipywidgets as widgets
63 | slider = widgets.IntSlider(value=5, min=0, max=10)
64 | ```
65 |
66 | An inline slider (`` {eval}`slider` ``): {eval}`slider`
67 |
68 | You can also use the `eval` directive to insert variables as blocks:
69 |
70 | ```{code-cell} ipython3
71 | import matplotlib.pyplot as plt
72 | myplot, ax = plt.subplots(figsize=(6, 2))
73 | mean = 2.0
74 | ax.plot([1,2,3])
75 | ax.grid()
76 | plt.close()
77 | ```
78 |
79 | using:
80 |
81 | ````markdown
82 | ```{eval} myplot
83 | ```
84 | ````
85 |
86 | gives:
87 |
88 | ```{eval} myplot
89 | ```
90 |
91 | ## Embedding outputs in figures
92 |
93 | The `eval:figure` directive allows you to embed outputs in a figure,
94 | with an optional caption and other formatting options.
95 |
96 | For example, we can embed the output of the above plot in a figure:
97 |
98 | `````markdown
99 | ```{eval:figure} myplot
100 | :name: myplot
101 | My plot with a mean value of {eval}`mean`.
102 | ```
103 | `````
104 |
105 | which gives:
106 |
107 | ```{eval:figure} myplot
108 | :name: myplot
109 | My plot with a mean value of {eval}`mean`.
110 | ```
111 |
112 | That can be referenced with `` {ref}`myplot` ``: {ref}`myplot`
113 |
114 | The following directive options are available:
115 |
116 | :::{table} `eval:figure` directive options
117 | | Option | Type | Description |
118 | | ------ | ---- | ----------- |
119 | | figwidth | length or percentage | The width of the figure |
120 | | figclass | text | A space-separated list of class names for the figure |
121 | | name | text | referenceable label for the figure |
122 | | alt | text | Alternate text of an image |
123 | | height | length | The desired height of an image |
124 | | width | length or percentage | The width of an image |
125 | | scale | percentage | The uniform scaling factor of an image |
126 | | class | text | A space-separated list of class names for the image |
127 | | align | text | left, center, or right |
128 | :::
129 |
--------------------------------------------------------------------------------
/docs/render/interactive.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: python3
5 | ---
6 |
7 | # Widgets and interactive outputs
8 |
9 | Jupyter Notebooks have support for many kinds of interactive outputs.
10 | These should all be supported in MyST-NB by passing the output HTML through automatically.
11 | This page has a few common examples.[^download]
12 |
13 | [^download]: This notebook can be downloaded as **{nb-download}`interactive.ipynb`** and {download}`interactive.md`
14 |
15 | First off, we'll download a little bit of data and show its structure:
16 |
17 | ```{code-cell} ipython3
18 | import plotly.express as px
19 | data = px.data.iris()
20 | data.head()
21 | ```
22 |
23 | ## Plotting libraries
24 |
25 | ### Altair
26 |
27 | Interactive outputs will work under the assumption that the outputs they produce have
28 | self-contained HTML that works without requiring any external dependencies to load.
29 | See the [`Altair` installation instructions](https://altair-viz.github.io/getting_started/installation.html#installation) to get set up with Altair.
30 | Below is some example output.
31 |
32 | ```{code-cell} ipython3
33 | import altair as alt
34 | alt.Chart(data=data).mark_point().encode(
35 | x="sepal_width",
36 | y="sepal_length",
37 | color="species",
38 | size='sepal_length'
39 | )
40 | ```
41 |
42 | ### Plotly
43 |
44 | Plotly is another interactive plotting library that provides a high-level API for visualization.
45 | See the [Plotly JupyterLab documentation](https://plotly.com/python/getting-started/#jupyterlab-support-python-35) to get started with Plotly in the notebook.
46 |
47 | Below is some example output.
48 |
49 | ```{code-cell} ipython3
50 | import plotly.io as pio
51 | import plotly.express as px
52 | import plotly.offline as py
53 |
54 | df = px.data.iris()
55 | fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species", size="sepal_length")
56 | fig
57 | ```
58 |
59 | :::{important}
60 |
61 | You may need to supply the `require.js` for plotly to display; in your `conf.py`:
62 |
63 | ```python
64 | html_js_files = ["https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"]
65 | ```
66 |
67 | :::
68 |
69 | ### Bokeh
70 |
71 | Bokeh provides several options for interactive visualizations, and is part of the PyViz ecosystem. See
72 | [the Bokeh with Jupyter documentation](https://docs.bokeh.org/en/latest/docs/user_guide/jupyter.html#userguide-jupyter) to
73 | get started.
74 |
75 | Below is some example output.
76 |
77 | ```{code-cell} ipython3
78 | from bokeh.plotting import figure, show, output_notebook
79 | output_notebook()
80 | ```
81 |
82 | ```{code-cell} ipython3
83 | from bokeh.plotting import figure, show, output_notebook
84 | output_notebook()
85 |
86 | p = figure()
87 | p.circle(data["sepal_width"], data["sepal_length"], fill_color=data["species"], size=data["sepal_length"])
88 | show(p)
89 | ```
90 |
91 | ## ipywidgets
92 |
93 | :::{note}
94 | IPyWidgets uses a special JS package `@jupyter-widgets/html-manager` for rendering Jupyter widgets outside notebooks. `myst-nb` loads a specific version of this package, which may be incompatible with your installation of IPyWidgets. If this is the case, you might need to specify the appropriate `nb_ipywidgets_js` config value, e.g. for `0.20.0`
95 | ```yaml
96 |
97 | sphinx:
98 | recursive_update: true
99 | config:
100 | nb_ipywidgets_js:
101 | # Load IPywidgets bundle for embedding.
102 | "https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager@0.20.0/dist/embed-amd.js":
103 | "data-jupyter-widgets-cdn": "https://cdn.jsdelivr.net/npm/"
104 | "crossorigin": "anonymous"
105 | ```
106 | To determine which version of `@jupyter-widgets/html-manager` is required, find the `html-manager` JS package in the [`ipywidgets` repo](https://github.com/jupyter-widgets/ipywidgets), and identify its version.
107 | :::
108 |
109 | You may also run code for Jupyter Widgets in your document, and the interactive HTML
110 | outputs will embed themselves in your side. See [the ipywidgets documentation](https://ipywidgets.readthedocs.io/en/latest/user_install.html)
111 | for how to get set up in your own environment.
112 |
113 | ```{admonition} Widgets often need a kernel
114 | Note that `ipywidgets` tend to behave differently from other interactive viz libraries.
115 | They interact both with Javascript, and with Python.
116 | Some functionality in `ipywidgets` may not work in rendered pages (because no Python kernel is running).
117 | You may be able to get around this with tools for remote kernels, like [thebelab](https://thebelab.readthedocs.org).
118 | ```
119 |
120 | Here are some simple widget elements rendered below.
121 |
122 | ```{code-cell} ipython3
123 | import ipywidgets as widgets
124 | widgets.IntSlider(
125 | value=7,
126 | min=0,
127 | max=10,
128 | step=1,
129 | description='Test:',
130 | disabled=False,
131 | continuous_update=False,
132 | orientation='horizontal',
133 | readout=True,
134 | readout_format='d'
135 | )
136 | ```
137 |
138 | ```{code-cell} ipython3
139 | tab_contents = ['P0', 'P1', 'P2', 'P3', 'P4']
140 | children = [widgets.Text(description=name) for name in tab_contents]
141 | tab = widgets.Tab()
142 | tab.children = children
143 | for ii in range(len(children)):
144 | tab.set_title(ii, f"tab_{ii}")
145 | tab
146 | ```
147 |
148 | You can find [a list of possible Jupyter Widgets](https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html) in the jupyter-widgets documentation.
149 |
--------------------------------------------------------------------------------
/docs/render/orphaned_nb.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "(orphaned-nb)=\n",
8 | "\n",
9 | "# An orphaned notebook\n",
10 | "\n",
11 | "This defines a variable that we'll re-use in another notebook."
12 | ]
13 | },
14 | {
15 | "cell_type": "code",
16 | "execution_count": 1,
17 | "metadata": {},
18 | "outputs": [
19 | {
20 | "data": {
21 | "text/plain": [
22 | "'My orphaned variable!'"
23 | ]
24 | },
25 | "metadata": {
26 | "scrapbook": {
27 | "mime_prefix": "",
28 | "name": "orphaned_var"
29 | }
30 | },
31 | "output_type": "display_data"
32 | }
33 | ],
34 | "source": [
35 | "from myst_nb import glue\n",
36 | "\n",
37 | "glue(\"var_text\", \"My orphaned variable!\")\n",
38 | "glue(\"var_float\", 1.0 / 3.0)"
39 | ]
40 | }
41 | ],
42 | "metadata": {
43 | "kernelspec": {
44 | "display_name": "Python 3",
45 | "language": "python",
46 | "name": "python3"
47 | },
48 | "language_info": {
49 | "codemirror_mode": {
50 | "name": "ipython",
51 | "version": 3
52 | },
53 | "file_extension": ".py",
54 | "mimetype": "text/x-python",
55 | "name": "python",
56 | "nbconvert_exporter": "python",
57 | "pygments_lexer": "ipython3",
58 | "version": "3.7.6"
59 | },
60 | "orphan": true
61 | },
62 | "nbformat": 4,
63 | "nbformat_minor": 4
64 | }
65 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | # this is only required by coconut kernel
2 | # Version limit is due to coconut and ipython inncompatibility as of 24/4/2025
3 | ipython<9
4 |
--------------------------------------------------------------------------------
/myst_nb/__init__.py:
--------------------------------------------------------------------------------
1 | """A docutils/sphinx parser for Jupyter Notebooks."""
2 |
3 | __version__ = "1.2.0"
4 |
5 |
6 | def setup(app):
7 | """Sphinx extension setup."""
8 | # we import this locally, so sphinx is not automatically imported
9 | from .sphinx_ext import sphinx_setup
10 |
11 | return sphinx_setup(app)
12 |
13 |
14 | def glue(name: str, variable, display: bool = True) -> None:
15 | """Glue a variable into the notebook's cell metadata.
16 |
17 | Parameters
18 | ----------
19 | name: string
20 | A unique name for the variable. You can use this name to refer to the variable
21 | later on.
22 | variable: Python object
23 | A variable in Python for which you'd like to store its display value. This is
24 | not quite the same as storing the object itself - the stored information is
25 | what is *displayed* when you print or show the object in a Jupyter Notebook.
26 | display: bool
27 | Display the object you are gluing. This is helpful in sanity-checking the
28 | state of the object at glue-time.
29 | """
30 | # we import this locally, so IPython is not automatically imported
31 | from myst_nb.ext.glue import glue
32 |
33 | return glue(name, variable, display)
34 |
--------------------------------------------------------------------------------
/myst_nb/_compat.py:
--------------------------------------------------------------------------------
1 | from docutils.nodes import Element
2 |
3 |
4 | def findall(node: Element):
5 | # findall replaces traverse in docutils v0.18
6 | # note a difference is that findall is an iterator
7 | return getattr(node, "findall", node.traverse)
8 |
--------------------------------------------------------------------------------
/myst_nb/core/__init__.py:
--------------------------------------------------------------------------------
1 | """Modules for core functionality.
2 |
3 | The parsing of a notebook consists of a number of stages,
4 | with each stage separated into a separate module:
5 |
6 | 1. The configuration is set (from a file or CLI)
7 | 2. The parser is called with an input string and source
8 | 3. The parser reads the input string to a notebook node
9 | 4. The notebook is converted to a Markdown-It tokens syntax tree
10 | 5. The notebook code outputs are potentially updated, via execution or from a cache
11 | 6. The syntax tree is transformed to a docutils document AST (calling the renderer plugin)
12 | 7. The docutils document is processed by docutils/sphinx, to create the desired output format(s)
13 | """
14 |
--------------------------------------------------------------------------------
/myst_nb/core/execute/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from pathlib import Path, PurePosixPath
4 | from typing import TYPE_CHECKING
5 |
6 | from .base import ExecutionError, ExecutionResult, NotebookClientBase # noqa: F401
7 | from .cache import NotebookClientCache
8 | from .direct import NotebookClientDirect
9 | from .inline import NotebookClientInline
10 |
11 | if TYPE_CHECKING:
12 | from nbformat import NotebookNode
13 |
14 | from myst_nb.core.config import NbParserConfig
15 | from myst_nb.core.loggers import LoggerType
16 |
17 |
18 | def create_client(
19 | notebook: NotebookNode,
20 | source: str,
21 | nb_config: NbParserConfig,
22 | logger: LoggerType,
23 | read_fmt: None | dict = None,
24 | ) -> NotebookClientBase:
25 | """Create a notebook execution client, to update its outputs.
26 |
27 | This function may execute the notebook if necessary, to update its outputs,
28 | or populate from a cache.
29 |
30 | :param notebook: The notebook to update.
31 | :param source: Path to or description of the input source being processed.
32 | :param nb_config: The configuration for the notebook parser.
33 | :param logger: The logger to use.
34 | :param read_fmt: The format of the input source (to parse to jupyter cache)
35 |
36 | :returns: The updated notebook, and the (optional) execution metadata.
37 | """
38 | # path should only be None when using docutils programmatically,
39 | # e.g. source=""
40 | try:
41 | path = Path(source) if Path(source).is_file() else None
42 | except OSError:
43 | path = None # occurs on Windows for `source=""`
44 |
45 | # check if the notebook is excluded from execution by pattern
46 | if path is not None and nb_config.execution_excludepatterns:
47 | posix_path = PurePosixPath(path.as_posix())
48 | for pattern in nb_config.execution_excludepatterns:
49 | if posix_path.match(pattern):
50 | logger.info(f"Excluded from execution by pattern: {pattern!r}")
51 | return NotebookClientBase(notebook, path, nb_config, logger)
52 |
53 | # 'auto' mode only executes the notebook if it is missing at least one output
54 | missing_outputs = (
55 | len(cell.outputs) == 0 for cell in notebook.cells if cell["cell_type"] == "code"
56 | )
57 | if nb_config.execution_mode == "auto" and not any(missing_outputs):
58 | logger.info("Skipped execution in 'auto' mode (all outputs present)")
59 | return NotebookClientBase(notebook, path, nb_config, logger)
60 |
61 | if nb_config.execution_mode in ("auto", "force"):
62 | return NotebookClientDirect(notebook, path, nb_config, logger)
63 |
64 | if nb_config.execution_mode == "cache":
65 | return NotebookClientCache(notebook, path, nb_config, logger, read_fmt=read_fmt)
66 |
67 | if nb_config.execution_mode == "inline":
68 | return NotebookClientInline(notebook, path, nb_config, logger)
69 |
70 | return NotebookClientBase(notebook, path, nb_config, logger)
71 |
--------------------------------------------------------------------------------
/myst_nb/core/execute/cache.py:
--------------------------------------------------------------------------------
1 | """Execute a notebook from the cache."""
2 |
3 | from __future__ import annotations
4 |
5 | from contextlib import nullcontext, suppress
6 | from datetime import datetime
7 | import os
8 | from tempfile import TemporaryDirectory
9 | from typing import ContextManager
10 |
11 | from jupyter_cache import get_cache
12 | from jupyter_cache.base import CacheBundleIn
13 | from jupyter_cache.cache.db import NbProjectRecord
14 | from jupyter_cache.executors.utils import single_nb_execution
15 |
16 | from .base import ExecutionError, NotebookClientBase
17 |
18 |
19 | class NotebookClientCache(NotebookClientBase):
20 | """A notebook client that retrieves notebook outputs from the cache,
21 | or executes the notebook and adds them to the cache, on entrance of the context.
22 | """
23 |
24 | def start_client(self):
25 | # setup the cache
26 | cache = get_cache(self.nb_config.execution_cache_path or ".jupyter_cache")
27 | # TODO config on what notebook/cell metadata to hash/merge
28 |
29 | # attempt to match the notebook to one in the cache
30 | cache_record = None
31 | with suppress(KeyError):
32 | cache_record = cache.match_cache_notebook(self.notebook)
33 |
34 | # use the cached notebook if it exists
35 | if cache_record is not None:
36 | self.logger.info(f"Using cached notebook: ID={cache_record.pk}")
37 | _, self._notebook = cache.merge_match_into_notebook(self.notebook)
38 | self.exec_metadata = {
39 | "mtime": cache_record.created.timestamp(),
40 | "runtime": cache_record.data.get("execution_seconds", None),
41 | "method": self.nb_config.execution_mode,
42 | "succeeded": True,
43 | "error": None,
44 | "traceback": None,
45 | }
46 | return
47 |
48 | if self.path is None:
49 | raise ValueError(
50 | "Input source must exist as file, if execution_mode is 'cache'"
51 | )
52 |
53 | # attempt to execute the notebook
54 | read_fmt = self._kwargs.get("read_fmt", None)
55 | if read_fmt is not None:
56 | stage_record = cache.add_nb_to_project(str(self.path), read_data=read_fmt)
57 | else:
58 | stage_record = cache.add_nb_to_project(str(self.path))
59 | # TODO do in try/except, in case of db write errors
60 | NbProjectRecord.remove_tracebacks([stage_record.pk], cache.db)
61 | cwd_context: ContextManager[str] = (
62 | TemporaryDirectory()
63 | if self.nb_config.execution_in_temp
64 | else nullcontext(str(self.path.parent))
65 | )
66 | with cwd_context as cwd:
67 | cwd = os.path.abspath(cwd)
68 | self.logger.info(
69 | "Executing notebook using "
70 | + ("temporary" if self.nb_config.execution_in_temp else "local")
71 | + " CWD"
72 | )
73 | result = single_nb_execution(
74 | self.notebook,
75 | cwd=cwd,
76 | allow_errors=self.nb_config.execution_allow_errors,
77 | timeout=self.nb_config.execution_timeout,
78 | meta_override=True, # TODO still support this?
79 | )
80 |
81 | # handle success / failure cases
82 | # TODO do in try/except to be careful (in case of database write errors?
83 | if result.err is not None:
84 | msg = f"Executing notebook failed: {result.err.__class__.__name__}"
85 | if self.nb_config.execution_show_tb:
86 | msg += f"\n{result.exc_string}"
87 | self.logger.warning(msg, subtype="exec")
88 | if self.nb_config.execution_raise_on_error:
89 | raise ExecutionError(str(self.path)) from result.err
90 | NbProjectRecord.set_traceback(stage_record.uri, result.exc_string, cache.db)
91 | else:
92 | self.logger.info(f"Executed notebook in {result.time:.2f} seconds")
93 | cache_record = cache.cache_notebook_bundle(
94 | CacheBundleIn(
95 | self.notebook,
96 | stage_record.uri,
97 | data={"execution_seconds": result.time},
98 | ),
99 | check_validity=False,
100 | overwrite=True,
101 | )
102 | self.logger.info(f"Cached executed notebook: ID={cache_record.pk}")
103 |
104 | self.exec_metadata = {
105 | "mtime": datetime.now().timestamp(),
106 | "runtime": result.time,
107 | "method": self.nb_config.execution_mode,
108 | "succeeded": False if result.err else True,
109 | "error": f"{result.err.__class__.__name__}" if result.err else None,
110 | "traceback": result.exc_string if result.err else None,
111 | }
112 |
--------------------------------------------------------------------------------
/myst_nb/core/execute/direct.py:
--------------------------------------------------------------------------------
1 | """Execute a notebook directly."""
2 |
3 | from __future__ import annotations
4 |
5 | from contextlib import nullcontext
6 | from datetime import datetime
7 | import os
8 | from tempfile import TemporaryDirectory
9 | from typing import ContextManager
10 |
11 | from jupyter_cache.executors.utils import single_nb_execution
12 |
13 | from .base import ExecutionError, NotebookClientBase
14 |
15 |
16 | class NotebookClientDirect(NotebookClientBase):
17 | """A notebook client that executes the notebook directly,
18 | on entrance of the context.
19 | """
20 |
21 | def start_client(self):
22 | # setup the execution current working directory
23 | cwd_context: ContextManager[str]
24 | if self.nb_config.execution_in_temp:
25 | cwd_context = TemporaryDirectory()
26 | else:
27 | if self.path is None:
28 | raise ValueError(
29 | "Input source must exist as file, if execution_in_temp=False"
30 | )
31 | cwd_context = nullcontext(str(self.path.parent))
32 |
33 | # execute in the context of the current working directory
34 | with cwd_context as cwd:
35 | cwd = os.path.abspath(cwd)
36 | self.logger.info(
37 | "Executing notebook using "
38 | + ("temporary" if self.nb_config.execution_in_temp else "local")
39 | + " CWD"
40 | )
41 | result = single_nb_execution(
42 | self.notebook,
43 | cwd=cwd,
44 | allow_errors=self.nb_config.execution_allow_errors,
45 | timeout=self.nb_config.execution_timeout,
46 | meta_override=True, # TODO still support this?
47 | )
48 |
49 | if result.err is not None:
50 | if self.nb_config.execution_raise_on_error:
51 | raise ExecutionError(str(self.path)) from result.err
52 | msg = f"Executing notebook failed: {result.err.__class__.__name__}"
53 | if self.nb_config.execution_show_tb:
54 | msg += f"\n{result.exc_string}"
55 | self.logger.warning(msg, subtype="exec")
56 | else:
57 | self.logger.info(f"Executed notebook in {result.time:.2f} seconds")
58 |
59 | self.exec_metadata = {
60 | "mtime": datetime.now().timestamp(),
61 | "runtime": result.time,
62 | "method": self.nb_config.execution_mode,
63 | "succeeded": False if result.err else True,
64 | "error": f"{result.err.__class__.__name__}" if result.err else None,
65 | "traceback": result.exc_string if result.err else None,
66 | }
67 |
--------------------------------------------------------------------------------
/myst_nb/core/utils.py:
--------------------------------------------------------------------------------
1 | """Shared utilities."""
2 |
3 | from __future__ import annotations
4 |
5 | import re
6 |
7 | from nbformat import NotebookNode
8 |
9 | _RGX_CARRIAGERETURN = re.compile(r".*\r(?=[^\n])")
10 | _RGX_BACKSPACE = re.compile(r"[^\n]\b")
11 |
12 |
13 | def coalesce_streams(outputs: list[NotebookNode]) -> list[NotebookNode]:
14 | """Merge all stream outputs with shared names into single streams.
15 |
16 | This ensure deterministic outputs.
17 |
18 | Adapted from:
19 | https://github.com/computationalmodelling/nbval/blob/master/nbval/plugin.py.
20 | """
21 | if not outputs:
22 | return []
23 |
24 | new_outputs = []
25 | streams: dict[str, NotebookNode] = {}
26 | for output in outputs:
27 | if output["output_type"] == "stream":
28 | if output["name"] in streams:
29 | out = output["text"].rstrip()
30 | if out:
31 | streams[output["name"]]["text"] += f"{out}\n"
32 | else:
33 | output["text"] = output["text"].rstrip() + "\n"
34 | new_outputs.append(output)
35 | streams[output["name"]] = output
36 | else:
37 | new_outputs.append(output)
38 |
39 | # process \r and \b characters
40 | for output in streams.values():
41 | old = output["text"]
42 | while len(output["text"]) < len(old):
43 | old = output["text"]
44 | # Cancel out anything-but-newline followed by backspace
45 | output["text"] = _RGX_BACKSPACE.sub("", output["text"])
46 | # Replace all carriage returns not followed by newline
47 | output["text"] = _RGX_CARRIAGERETURN.sub("", output["text"])
48 |
49 | # We also want to ensure stdout and stderr are always in the same consecutive order,
50 | # because they are asynchronous, so order isn't guaranteed.
51 | for i, output in enumerate(new_outputs):
52 | if output["output_type"] == "stream" and output["name"] == "stderr":
53 | if (
54 | len(new_outputs) >= i + 2
55 | and new_outputs[i + 1]["output_type"] == "stream"
56 | and new_outputs[i + 1]["name"] == "stdout"
57 | ):
58 | stdout = new_outputs.pop(i + 1)
59 | new_outputs.insert(i, stdout)
60 |
61 | return new_outputs
62 |
--------------------------------------------------------------------------------
/myst_nb/ext/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/executablebooks/MyST-NB/201a48c2fff428ba15eaed096dec2f43b040ddc1/myst_nb/ext/__init__.py
--------------------------------------------------------------------------------
/myst_nb/ext/download.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pathlib import Path
3 |
4 | from docutils import nodes
5 | from sphinx.addnodes import download_reference
6 | from sphinx.util.docutils import ReferenceRole
7 |
8 | from myst_nb.sphinx_ import SphinxEnvType
9 |
10 |
11 | class NbDownloadRole(ReferenceRole):
12 | """Role to download an executed notebook."""
13 |
14 | def run(self):
15 | """Run the role."""
16 | # get a path relative to the current document
17 | self.env: SphinxEnvType
18 | path = Path(self.env.mystnb_config.output_folder).joinpath(
19 | *(self.env.docname.split("/")[:-1] + self.target.split("/"))
20 | )
21 | reftarget = (
22 | path.as_posix()
23 | if os.name == "nt"
24 | else ("/" + os.path.relpath(path, self.env.app.srcdir))
25 | )
26 | node = download_reference(self.rawtext, reftarget=reftarget)
27 | self.set_source_info(node)
28 | title = self.title if self.has_explicit_title else self.target
29 | node += nodes.literal(
30 | self.rawtext, title, classes=["xref", "download", "myst-nb"]
31 | )
32 | return [node], []
33 |
--------------------------------------------------------------------------------
/myst_nb/ext/glue/__init__.py:
--------------------------------------------------------------------------------
1 | """Functionality for storing special data in notebook code cells,
2 | which can then be inserted into the document body.
3 | """
4 |
5 | from __future__ import annotations
6 |
7 | from typing import TYPE_CHECKING, Any
8 |
9 | import IPython
10 | from IPython.display import display as ipy_display
11 | from nbformat import NotebookNode
12 |
13 | from myst_nb.core.loggers import LoggerType
14 |
15 | if TYPE_CHECKING:
16 | from sphinx.application import Sphinx
17 |
18 | from myst_nb.docutils_ import DocutilsApp
19 |
20 | GLUE_PREFIX = "application/papermill.record/"
21 |
22 |
23 | def load_glue_sphinx(app: Sphinx) -> None:
24 | """Load the eval domain."""
25 | from .directives import PasteAnyDirective
26 | from .domain import NbGlueDomain
27 | from .roles import PasteRoleAny
28 |
29 | app.add_directive("glue", PasteAnyDirective, override=True)
30 | app.add_role("glue", PasteRoleAny(), override=True)
31 | app.add_domain(NbGlueDomain)
32 |
33 |
34 | def load_glue_docutils(app: DocutilsApp) -> None:
35 | from .directives import (
36 | PasteAnyDirective,
37 | PasteFigureDirective,
38 | PasteMarkdownDirective,
39 | PasteMathDirective,
40 | )
41 | from .roles import PasteMarkdownRole, PasteRoleAny, PasteTextRole
42 |
43 | for name, role in [
44 | ("glue", PasteRoleAny()),
45 | ("glue:", PasteRoleAny()),
46 | ("glue:any", PasteRoleAny()),
47 | ("glue:text", PasteTextRole()),
48 | ("glue:md", PasteMarkdownRole()),
49 | ]:
50 | app.roles[name] = role
51 |
52 | for name, directive in [
53 | ("glue", PasteAnyDirective),
54 | ("glue:", PasteAnyDirective),
55 | ("glue:any", PasteAnyDirective),
56 | ("glue:figure", PasteFigureDirective),
57 | ("glue:math", PasteMathDirective),
58 | ("glue:md", PasteMarkdownDirective),
59 | ]:
60 | app.directives[name] = directive
61 |
62 |
63 | def glue(name: str, variable: Any, display: bool = True) -> None:
64 | """Glue a variable into the notebook's cell metadata.
65 |
66 | Parameters
67 | ----------
68 | name: string
69 | A unique name for the variable. You can use this name to refer to the variable
70 | later on.
71 | variable: Python object
72 | A variable in Python for which you'd like to store its display value. This is
73 | not quite the same as storing the object itself - the stored information is
74 | what is *displayed* when you print or show the object in a Jupyter Notebook.
75 | display: bool
76 | Display the object you are gluing. This is helpful in sanity-checking the
77 | state of the object at glue-time.
78 | """
79 | mimebundle, metadata = IPython.core.formatters.format_display_data(variable)
80 | mime_prefix = "" if display else GLUE_PREFIX
81 | metadata["scrapbook"] = dict(name=name, mime_prefix=mime_prefix)
82 | ipy_display(
83 | {mime_prefix + k: v for k, v in mimebundle.items()}, raw=True, metadata=metadata
84 | )
85 |
86 |
87 | def extract_glue_data(
88 | notebook: NotebookNode,
89 | source_map: list[int],
90 | logger: LoggerType,
91 | ) -> dict[str, NotebookNode]:
92 | """Extract all the glue data from the notebook."""
93 | # note this assumes v4 notebook format
94 | data: dict[str, NotebookNode] = {}
95 | for index, cell in enumerate(notebook.cells):
96 | if cell.cell_type != "code":
97 | continue
98 | for key, cell_data in extract_glue_data_cell(cell):
99 | if key in data:
100 | logger.warning(
101 | f"glue key {key!r} duplicate",
102 | subtype="glue",
103 | line=source_map[index],
104 | )
105 | data[key] = cell_data
106 |
107 | return data
108 |
109 |
110 | def extract_glue_data_cell(cell: NotebookNode) -> list[tuple[str, NotebookNode]]:
111 | """Extract glue data from a single cell."""
112 | outputs = []
113 | data = []
114 | for output in cell.get("outputs", []):
115 | meta = output.get("metadata", {})
116 | if "scrapbook" not in meta:
117 | outputs.append(output)
118 | continue
119 | key = meta["scrapbook"]["name"]
120 | mime_prefix = len(meta["scrapbook"].get("mime_prefix", ""))
121 | output["data"] = {k[mime_prefix:]: v for k, v in output["data"].items()}
122 | data.append((key, output))
123 | if not mime_prefix:
124 | # assume that the output is a displayable object
125 | outputs.append(output)
126 | cell.outputs = outputs
127 | return data
128 |
--------------------------------------------------------------------------------
/myst_nb/ext/glue/crossref.py:
--------------------------------------------------------------------------------
1 | """Sphinx only cross-document gluing.
2 |
3 | Note, we restrict this to a only a subset of mime-types and data -> nodes transforms,
4 | since adding these nodes in a post-transform will not apply any transforms to them.
5 | """
6 |
7 | from __future__ import annotations
8 |
9 | from functools import lru_cache
10 | import json
11 | from pathlib import Path
12 | from typing import Any, Sequence
13 |
14 | from docutils import nodes
15 | from sphinx.transforms.post_transforms import SphinxPostTransform
16 | from sphinx.util import logging as sphinx_logging
17 |
18 | from myst_nb._compat import findall
19 | from myst_nb.core.loggers import DEFAULT_LOG_TYPE
20 | from myst_nb.core.render import get_mime_priority
21 | from myst_nb.core.variables import format_plain_text
22 |
23 | from .utils import PendingGlueReference
24 |
25 | SPHINX_LOGGER = sphinx_logging.getLogger(__name__)
26 |
27 |
28 | @lru_cache(maxsize=3)
29 | def read_glue_cache(folder: str, docname: str) -> dict[str, Any]:
30 | """Read a glue cache from the build folder, for a particular document."""
31 | docpath = docname.split("/")
32 | path = Path(folder).joinpath(*docpath[:-1]).joinpath(f"{docpath[-1]}.glue.json")
33 | if not path.exists():
34 | return {}
35 | with path.open("r") as f:
36 | return json.load(f)
37 |
38 |
39 | class ReplacePendingGlueReferences(SphinxPostTransform):
40 | """Sphinx only cross-document gluing.
41 |
42 | Note, we restrict this to a only a subset of mime-types and data -> nodes transforms,
43 | since adding these nodes in a post-transform will not apply any transforms to them.
44 | """
45 |
46 | default_priority = 5
47 |
48 | def apply(self, **kwargs):
49 | """Apply the transform."""
50 | cache_folder = self.env.mystnb_config.output_folder # type: ignore
51 | bname = self.app.builder.name
52 | priority_list = get_mime_priority(
53 | bname, self.config["nb_mime_priority_overrides"]
54 | )
55 | node: PendingGlueReference
56 | for node in list(findall(self.document)(PendingGlueReference)):
57 | data = read_glue_cache(cache_folder, node.refdoc)
58 | if node.key not in data:
59 | SPHINX_LOGGER.warning(
60 | f"Glue reference {node.key!r} not found in doc {node.refdoc!r} "
61 | f"[{DEFAULT_LOG_TYPE}.glue_ref]",
62 | type=DEFAULT_LOG_TYPE,
63 | subtype="glue_ref",
64 | location=node,
65 | )
66 | node.parent.remove(node)
67 | continue
68 | output = data[node.key]
69 | if node.gtype == "text":
70 | _nodes = generate_text_nodes(node, output)
71 | else:
72 | _nodes = generate_any_nodes(node, output, priority_list)
73 |
74 | if _nodes:
75 | node.replace_self(_nodes)
76 | else:
77 | node.parent.remove(node)
78 |
79 |
80 | def ref_warning(msg: str, node) -> None:
81 | """Log a warning for a reference."""
82 | SPHINX_LOGGER.warning(
83 | f"{msg} [{DEFAULT_LOG_TYPE}.glue_ref]",
84 | type=DEFAULT_LOG_TYPE,
85 | subtype="glue_ref",
86 | location=node,
87 | )
88 |
89 |
90 | def generate_any_nodes(
91 | node: PendingGlueReference, output: dict[str, Any], priority_list: Sequence[str]
92 | ) -> list[nodes.Element]:
93 | """Generate nodes for a cell, according to the highest priority mime type."""
94 | data = output["data"]
95 | for mime_type in priority_list:
96 | if mime_type not in data:
97 | continue
98 | if mime_type == "text/plain":
99 | if node.inline:
100 | return [nodes.literal(data[mime_type], data[mime_type])]
101 | else:
102 | return [nodes.literal_block(data[mime_type], data[mime_type])]
103 | if mime_type == "text/html":
104 | return [
105 | nodes.raw(
106 | text=data[mime_type], format="html", classes=["output", "text_html"]
107 | )
108 | ]
109 | ref_warning(
110 | f"No allowed mime type found in {node.key!r}: {list(output['data'])}", node
111 | )
112 | return []
113 |
114 |
115 | def generate_text_nodes(node: PendingGlueReference, output: dict[str, Any]):
116 | """Generate nodes for a cell, for formatted text/plain."""
117 | data = output["data"]
118 | if "text/plain" not in data:
119 | ref_warning(f"No text/plain found in {node.key!r}", node)
120 | return []
121 | try:
122 | text = format_plain_text(data["text/plain"], node["fmt_spec"])
123 | except Exception as exc:
124 | ref_warning(f"Failed to format text/plain: {exc}", node)
125 | return []
126 | return [nodes.inline(text, text, classes=["pasted-text"])]
127 |
--------------------------------------------------------------------------------
/myst_nb/ext/glue/domain.py:
--------------------------------------------------------------------------------
1 | """A domain to register in sphinx.
2 |
3 | This is required for any directive/role names using `:`.
4 | """
5 |
6 | from sphinx.domains import Domain
7 |
8 | from .directives import (
9 | PasteAnyDirective,
10 | PasteFigureDirective,
11 | PasteMarkdownDirective,
12 | PasteMathDirective,
13 | )
14 | from .roles import PasteMarkdownRole, PasteRoleAny, PasteTextRole
15 |
16 |
17 | class NbGlueDomain(Domain):
18 | """A sphinx domain for defining glue roles and directives.
19 |
20 | Note, the only reason we use this,
21 | is that sphinx will not allow for `:` in a directive/role name,
22 | if it is part of a domain.
23 | """
24 |
25 | name = "glue"
26 | label = "NotebookGlue"
27 |
28 | # data version, bump this when the format of self.data changes
29 | data_version = 1
30 |
31 | roles = {
32 | "": PasteRoleAny(),
33 | "any": PasteRoleAny(),
34 | "text": PasteTextRole(),
35 | "md": PasteMarkdownRole(),
36 | }
37 | directives = {
38 | "": PasteAnyDirective,
39 | "any": PasteAnyDirective,
40 | "figure": PasteFigureDirective,
41 | "math": PasteMathDirective,
42 | "md": PasteMarkdownDirective,
43 | }
44 |
45 | def merge_domaindata(self, *args, **kwargs):
46 | pass
47 |
48 | def resolve_any_xref(self, *args, **kwargs):
49 | return []
50 |
--------------------------------------------------------------------------------
/myst_nb/ext/glue/utils.py:
--------------------------------------------------------------------------------
1 | """Utilities for working with docutils and sphinx.
2 |
3 | We intentionally do no import sphinx in this module,
4 | in order to allow docutils-only use without sphinx installed.
5 | """
6 |
7 | from __future__ import annotations
8 |
9 | from functools import partial
10 | from typing import TYPE_CHECKING, Any
11 |
12 | from docutils import nodes
13 |
14 | from myst_nb.core.render import NbElementRenderer
15 | from myst_nb.core.variables import (
16 | RetrievalError,
17 | VariableOutput,
18 | create_warning,
19 | is_sphinx,
20 | )
21 |
22 | if TYPE_CHECKING:
23 | from sphinx.environment import BuildEnvironment
24 |
25 | glue_warning = partial(create_warning, subtype="glue")
26 |
27 |
28 | class PendingGlueReference(nodes.Element):
29 | """A glue reference to another document."""
30 |
31 | @property
32 | def refdoc(self) -> str:
33 | return self.attributes["refdoc"]
34 |
35 | @property
36 | def key(self) -> str:
37 | return self.attributes["key"]
38 |
39 | @property
40 | def inline(self) -> bool:
41 | return self.attributes.get("inline", False)
42 |
43 | @property
44 | def gtype(self) -> str | None:
45 | return self.attributes.get("gtype", None)
46 |
47 |
48 | class PendingGlueReferenceError(Exception):
49 | """An error occurred while resolving a pending glue reference."""
50 |
51 |
52 | def create_pending_glue_ref(
53 | document: nodes.document,
54 | source: str,
55 | line: int,
56 | rel_doc: str,
57 | key: str,
58 | inline: bool = False,
59 | gtype: str | None = None,
60 | **kwargs: Any,
61 | ) -> PendingGlueReference:
62 | """Create a pending glue reference."""
63 | if not is_sphinx(document):
64 | raise PendingGlueReferenceError(
65 | "Pending glue references are only supported in sphinx."
66 | )
67 | env: BuildEnvironment = document.settings.env
68 | _, filepath = env.relfn2path(rel_doc, env.docname)
69 | refdoc = env.path2doc(filepath)
70 | if refdoc is None:
71 | raise PendingGlueReferenceError(
72 | f"Pending glue reference document not found: {filepath!r}."
73 | )
74 | ref = PendingGlueReference(
75 | refdoc=refdoc, key=key, inline=inline, gtype=gtype, **kwargs
76 | )
77 | ref.source = source
78 | ref.line = line
79 | return ref
80 |
81 |
82 | def retrieve_glue_data(document: nodes.document, key: str) -> VariableOutput:
83 | """Retrieve the glue data from a specific document."""
84 | msg = f"No key {key!r} found in glue data for this document."
85 | if "nb_renderer" not in document:
86 | raise RetrievalError(msg)
87 | element: NbElementRenderer = document["nb_renderer"]
88 | glue_data = element.renderer.nb_client.glue_data
89 |
90 | if key not in glue_data:
91 | raise RetrievalError(msg)
92 |
93 | return VariableOutput(
94 | data=glue_data[key]["data"],
95 | metadata=glue_data[key].get("metadata", {}),
96 | nb_renderer=element,
97 | vtype="glue",
98 | )
99 |
--------------------------------------------------------------------------------
/myst_nb/ext/utils.py:
--------------------------------------------------------------------------------
1 | """Extension utilities for extensions.
2 |
3 | We intentionally do no import sphinx in this module,
4 | in order to allow docutils-only use without sphinx installed.
5 | """
6 |
7 | from __future__ import annotations
8 |
9 | from typing import Any
10 |
11 | from docutils import nodes
12 | from docutils.parsers.rst import Directive
13 | from docutils.parsers.rst.states import Inliner
14 | from docutils.utils import unescape
15 |
16 | from myst_nb._compat import findall
17 |
18 |
19 | def set_source_info(node: nodes.Node, source: str, line: int) -> None:
20 | """Set the source info for a node and its descendants."""
21 | for _node in findall(node)(include_self=True):
22 | _node.source = source
23 | _node.line = line
24 |
25 |
26 | class RoleBase:
27 | """A base class for creating a role."""
28 |
29 | @property
30 | def document(self) -> nodes.document:
31 | """Get the document."""
32 | return self.inliner.document
33 |
34 | def set_source_info(self, node: nodes.Node) -> None:
35 | """Set the source info for a node and its descendants."""
36 | set_source_info(node, self.source, self.line)
37 |
38 | def __call__(
39 | self,
40 | name: str,
41 | rawtext: str,
42 | text: str,
43 | lineno: int,
44 | inliner: Inliner,
45 | options=None,
46 | content=(),
47 | ) -> tuple[list[nodes.Node], list[nodes.system_message]]:
48 | self.text: str = unescape(text)
49 | self.inliner = inliner
50 | self.rawtext = rawtext
51 | source, line = inliner.reporter.get_source_and_line(lineno)
52 | self.source: str = source
53 | self.line: int = line
54 | return self.run()
55 |
56 | def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
57 | """Run the role."""
58 | raise NotImplementedError
59 |
60 |
61 | class DirectiveBase(Directive):
62 | """A base class for creating a directive."""
63 |
64 | @property
65 | def document(self) -> nodes.document:
66 | return self.state.document
67 |
68 | def __init__(self, *args, **kwargs) -> None:
69 | self.arguments: list[str]
70 | self.options: dict[str, Any]
71 | self.content: str
72 | super().__init__(*args, **kwargs)
73 | source, line = self.state_machine.get_source_and_line(self.lineno)
74 | self.source: str = source
75 | self.line: int = line
76 |
77 | def set_source_info(self, node: nodes.Node) -> None:
78 | """Set source and line number to the node and its descendants."""
79 | nodes = node if isinstance(node, (list, tuple)) else [node]
80 | for _node in nodes:
81 | set_source_info(_node, self.source, self.line)
82 |
--------------------------------------------------------------------------------
/myst_nb/static/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/executablebooks/MyST-NB/201a48c2fff428ba15eaed096dec2f43b040ddc1/myst_nb/static/__init__.py
--------------------------------------------------------------------------------
/myst_nb/warnings_.py:
--------------------------------------------------------------------------------
1 | """Central handling of warnings for the myst-nb extension."""
2 |
3 | from __future__ import annotations
4 |
5 | from enum import Enum
6 | from typing import Sequence
7 |
8 | from docutils import nodes
9 | from myst_parser.warnings_ import MystWarnings
10 | from myst_parser.warnings_ import create_warning as myst_parser_create_warnings
11 |
12 | __all__ = [
13 | "MystWarnings",
14 | "MystNBWarnings",
15 | "create_warning",
16 | ]
17 |
18 |
19 | class MystNBWarnings(Enum):
20 | """MySTNB warning types."""
21 |
22 | LEXER = "lexer"
23 | """Issue resolving lexer"""
24 |
25 | FIG_CAPTION = "fig_caption"
26 | """Issue resoliving figure caption"""
27 |
28 | MIME_TYPE = "mime_type"
29 | """Issue resolving MIME type"""
30 | OUTPUT_TYPE = "output_type"
31 | """Issue resolving Output type"""
32 |
33 | CELL_METADATA_KEY = "cell_metadata_key"
34 | """Issue with a key in a cell's `metadata` dictionary."""
35 | CELL_CONFIG = "cell_config"
36 | """Issue with a cell's configuration or metadata."""
37 |
38 |
39 | def _is_suppressed_warning(
40 | type: str, subtype: str, suppress_warnings: Sequence[str]
41 | ) -> bool:
42 | """Check whether the warning is suppressed or not.
43 |
44 | Mirrors:
45 | https://github.com/sphinx-doc/sphinx/blob/47d9035bca9e83d6db30a0726a02dc9265bd66b1/sphinx/util/logging.py
46 | """
47 | if type is None:
48 | return False
49 |
50 | subtarget: str | None
51 |
52 | for warning_type in suppress_warnings:
53 | if "." in warning_type:
54 | target, subtarget = warning_type.split(".", 1)
55 | else:
56 | target, subtarget = warning_type, None
57 |
58 | if target == type and subtarget in (None, subtype, "*"):
59 | return True
60 |
61 | return False
62 |
63 |
64 | def create_warning(
65 | document: nodes.document,
66 | message: str,
67 | subtype: MystNBWarnings | MystWarnings,
68 | *,
69 | line: int | None = None,
70 | append_to: nodes.Element | None = None,
71 | ) -> nodes.system_message | None:
72 | """Generate a warning, logging if it is necessary.
73 |
74 | If the warning type is listed in the ``suppress_warnings`` configuration,
75 | then ``None`` will be returned and no warning logged.
76 | """
77 | # Pass off Myst Parser warnings to that package
78 | if isinstance(subtype, MystWarnings):
79 | myst_parser_create_warnings(
80 | document=document,
81 | message=message,
82 | subtype=subtype,
83 | line=line,
84 | append_to=append_to,
85 | )
86 |
87 | wtype = "myst-nb"
88 | # figure out whether to suppress the warning, if sphinx is available,
89 | # it will have been set up by the Sphinx environment,
90 | # otherwise we will use the configuration set by docutils
91 | suppress_warnings: Sequence[str] = []
92 | try:
93 | suppress_warnings = document.settings.env.app.config.suppress_warnings
94 | except AttributeError:
95 | suppress_warnings = document.settings.myst_suppress_warnings or []
96 | if _is_suppressed_warning(wtype, subtype.value, suppress_warnings):
97 | return None
98 |
99 | kwargs = {"line": line} if line is not None else {}
100 | message = f"{message} [{wtype}.{subtype.value}]"
101 | msg_node = document.reporter.warning(message, **kwargs)
102 | if append_to is not None:
103 | append_to.append(msg_node)
104 | return msg_node
105 |
--------------------------------------------------------------------------------
/tests/nb_fixtures/reporter_warnings.txt:
--------------------------------------------------------------------------------
1 | Unknown Role:
2 | .
3 | cells:
4 | - cell_type: markdown
5 | metadata: {}
6 | source: |
7 | a
8 | - cell_type: markdown
9 | metadata: {}
10 | source: |
11 | {unknown}`a`
12 | .
13 | :20002: (WARNING/2) Unknown interpreted text role "unknown". [myst.role_unknown]
14 | .
15 |
16 | Unknown directive:
17 | .
18 | cells:
19 | - cell_type: markdown
20 | metadata: {}
21 | source: |
22 | a
23 | ```{xyz}
24 | ```
25 | .
26 | :10003: (WARNING/2) Unknown directive type: 'xyz' [myst.directive_unknown]
27 | .
28 |
29 | Directive parsing error:
30 | .
31 | cells:
32 | - cell_type: markdown
33 | metadata: {}
34 | source: |
35 | ```{class}
36 | ```
37 | .
38 | :10002: (ERROR/3) Directive 'class': 1 argument(s) required, 0 supplied
39 | .
40 |
41 | Directive run error:
42 | .
43 | cells:
44 | - cell_type: markdown
45 | metadata: {}
46 | source: |
47 | ```{date}
48 | x
49 | ```
50 | .
51 | :10002: (ERROR/3) Invalid context: the "date" directive can only be used within a substitution definition.
52 | .
53 |
54 | Duplicate reference definition:
55 | .
56 | cells:
57 | - cell_type: markdown
58 | metadata: {}
59 | source: |
60 | [a]: b
61 | - cell_type: markdown
62 | metadata: {}
63 | source: |
64 | d
65 |
66 | [a]: c
67 | .
68 | :20004: (WARNING/2) Duplicate reference definition: A [myst.duplicate_def]
69 | .
70 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_failing.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": null,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "raise Exception(\"oopsie!\")"
19 | ]
20 | }
21 | ],
22 | "metadata": {
23 | "kernelspec": {
24 | "display_name": "Python 3",
25 | "language": "python",
26 | "name": "python3"
27 | },
28 | "language_info": {
29 | "codemirror_mode": {
30 | "name": "ipython",
31 | "version": 3
32 | },
33 | "file_extension": ".py",
34 | "mimetype": "text/x-python",
35 | "name": "python",
36 | "nbconvert_exporter": "python",
37 | "pygments_lexer": "ipython3",
38 | "version": "3.6.1"
39 | },
40 | "test_name": "notebook1"
41 | },
42 | "nbformat": 4,
43 | "nbformat_minor": 2
44 | }
45 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_nometadata.md:
--------------------------------------------------------------------------------
1 | # a title
2 |
3 | this was created using `jupytext --to myst tests/notebooks/basic_unrun.ipynb` but
4 | with the jupytext metadata removed.
5 |
6 | ```{code-cell} ipython3
7 | a=1
8 | print(a)
9 | ```
10 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_relative.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": null,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "# Test reading a relative file to make sure relative paths work\n",
19 | "from PIL import Image\n",
20 | "\n",
21 | "image = Image.open(\"./example.jpg\")"
22 | ]
23 | }
24 | ],
25 | "metadata": {
26 | "kernelspec": {
27 | "display_name": "Python 3",
28 | "language": "python",
29 | "name": "python3"
30 | },
31 | "language_info": {
32 | "codemirror_mode": {
33 | "name": "ipython",
34 | "version": 3
35 | },
36 | "file_extension": ".py",
37 | "mimetype": "text/x-python",
38 | "name": "python",
39 | "nbconvert_exporter": "python",
40 | "pygments_lexer": "ipython3",
41 | "version": "3.8.5"
42 | },
43 | "test_name": "notebook1",
44 | "widgets": {
45 | "application/vnd.jupyter.widget-state+json": {
46 | "state": {},
47 | "version_major": 2,
48 | "version_minor": 0
49 | }
50 | }
51 | },
52 | "nbformat": 4,
53 | "nbformat_minor": 4
54 | }
55 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_run.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "1\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "a = 1\n",
27 | "print(a)"
28 | ]
29 | }
30 | ],
31 | "metadata": {
32 | "kernelspec": {
33 | "display_name": "Python 3",
34 | "language": "python",
35 | "name": "python3"
36 | },
37 | "language_info": {
38 | "codemirror_mode": {
39 | "name": "ipython",
40 | "version": 3
41 | },
42 | "file_extension": ".py",
43 | "mimetype": "text/x-python",
44 | "name": "python",
45 | "nbconvert_exporter": "python",
46 | "pygments_lexer": "ipython3",
47 | "version": "3.6.1"
48 | },
49 | "test_name": "notebook1"
50 | },
51 | "nbformat": 4,
52 | "nbformat_minor": 2
53 | }
54 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_run_intl.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "1\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "a = 1\n",
27 | "print(a)"
28 | ]
29 | }
30 | ],
31 | "metadata": {
32 | "kernelspec": {
33 | "display_name": "Python 3",
34 | "language": "python",
35 | "name": "python3"
36 | },
37 | "language_info": {
38 | "codemirror_mode": {
39 | "name": "ipython",
40 | "version": 3
41 | },
42 | "file_extension": ".py",
43 | "mimetype": "text/x-python",
44 | "name": "python",
45 | "nbconvert_exporter": "python",
46 | "pygments_lexer": "ipython3",
47 | "version": "3.6.1"
48 | },
49 | "test_name": "notebook1"
50 | },
51 | "nbformat": 4,
52 | "nbformat_minor": 2
53 | }
54 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_stderr.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stderr",
10 | "output_type": "stream",
11 | "text": [
12 | "hallo\n"
13 | ]
14 | }
15 | ],
16 | "source": [
17 | "import sys\n",
18 | "\n",
19 | "print(\"hallo\", file=sys.stderr)"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": 1,
25 | "metadata": {
26 | "tags": [
27 | "remove-stderr"
28 | ]
29 | },
30 | "outputs": [
31 | {
32 | "name": "stderr",
33 | "output_type": "stream",
34 | "text": [
35 | "hallo\n"
36 | ]
37 | }
38 | ],
39 | "source": [
40 | "import sys\n",
41 | "\n",
42 | "print(\"hallo\", file=sys.stderr)"
43 | ]
44 | }
45 | ],
46 | "metadata": {
47 | "kernelspec": {
48 | "display_name": "Python 3",
49 | "language": "python",
50 | "name": "python3"
51 | },
52 | "language_info": {
53 | "codemirror_mode": {
54 | "name": "ipython",
55 | "version": 3
56 | },
57 | "file_extension": ".py",
58 | "mimetype": "text/x-python",
59 | "name": "python",
60 | "nbconvert_exporter": "python",
61 | "pygments_lexer": "ipython3",
62 | "version": "3.6.1"
63 | }
64 | },
65 | "nbformat": 4,
66 | "nbformat_minor": 2
67 | }
68 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_unrun.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": null,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "a = 1\n",
19 | "print(a)"
20 | ]
21 | }
22 | ],
23 | "metadata": {
24 | "kernelspec": {
25 | "display_name": "Python 3",
26 | "language": "python",
27 | "name": "python3"
28 | },
29 | "language_info": {
30 | "codemirror_mode": {
31 | "name": "ipython",
32 | "version": 3
33 | },
34 | "file_extension": ".py",
35 | "mimetype": "text/x-python",
36 | "name": "python",
37 | "nbconvert_exporter": "python",
38 | "pygments_lexer": "ipython3",
39 | "version": "3.6.1"
40 | },
41 | "test_name": "notebook1"
42 | },
43 | "nbformat": 4,
44 | "nbformat_minor": 2
45 | }
46 |
--------------------------------------------------------------------------------
/tests/notebooks/basic_unrun.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | display_name: Python 3
5 | language: python
6 | name: python3
7 | author: Chris
8 | ---
9 |
10 | # a title
11 |
12 | this was created using `jupytext --to myst tests/notebooks/basic_unrun.ipynb`
13 |
14 | ```{code-cell} ipython3
15 | a = 1
16 | print(a)
17 | ```
18 |
--------------------------------------------------------------------------------
/tests/notebooks/custom-formats.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Test chunk options in Rmd/Jupyter conversion"
3 | author: "Marc Wouts"
4 | date: "June 16, 2018"
5 | jupyter:
6 | kernelspec:
7 | display_name: Python
8 | language: python
9 | name: python3
10 | ---
11 |
12 | # Custom Formats
13 |
14 | ```{python echo=TRUE}
15 | import pandas as pd
16 |
17 | x = pd.Series({"A": 1, "B": 3, "C": 2})
18 | ```
19 |
20 | ```{python bar_plot, echo=FALSE, fig.height=5, fig.width=8}
21 | x.plot(kind="bar", title="Sample plot")
22 | ```
23 |
--------------------------------------------------------------------------------
/tests/notebooks/custom-formats2.extra.exnt:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Test chunk options in Rmd/Jupyter conversion"
3 | author: "Marc Wouts"
4 | date: "June 16, 2018"
5 | jupyter:
6 | kernelspec:
7 | display_name: Python
8 | language: python
9 | name: python3
10 | ---
11 |
12 | # Custom Formats
13 |
14 | ```{python echo=TRUE}
15 | import pandas as pd
16 |
17 | x = pd.Series({"A": 1, "B": 3, "C": 2})
18 | ```
19 |
20 | ```{python bar_plot, echo=FALSE, fig.height=5, fig.width=8}
21 | x.plot(kind="bar", title="Sample plot")
22 | ```
23 |
--------------------------------------------------------------------------------
/tests/notebooks/example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/executablebooks/MyST-NB/201a48c2fff428ba15eaed096dec2f43b040ddc1/tests/notebooks/example.jpg
--------------------------------------------------------------------------------
/tests/notebooks/file_level_config.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "be9f2c4c",
6 | "metadata": {},
7 | "source": [
8 | "# Title\n",
9 | "\n",
10 | "name\n",
11 | ": definition"
12 | ]
13 | }
14 | ],
15 | "metadata": {
16 | "file_format": "mystnb",
17 | "kernelspec": {
18 | "display_name": "python3",
19 | "name": "python3"
20 | },
21 | "myst": {
22 | "enable_extensions": [
23 | "deflist"
24 | ]
25 | },
26 | "mystnb": {
27 | "execution_mode": "off"
28 | }
29 | },
30 | "nbformat": 4,
31 | "nbformat_minor": 5
32 | }
33 |
--------------------------------------------------------------------------------
/tests/notebooks/file_level_config.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: python3
5 | myst:
6 | enable_extensions:
7 | - "deflist"
8 | mystnb:
9 | execution_mode: "off"
10 | ---
11 |
12 | # Title
13 |
14 | name
15 | : definition
16 |
--------------------------------------------------------------------------------
/tests/notebooks/fun-fish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/executablebooks/MyST-NB/201a48c2fff428ba15eaed096dec2f43b040ddc1/tests/notebooks/fun-fish.png
--------------------------------------------------------------------------------
/tests/notebooks/hide_cell_content.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Hide Code Cell Content"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 1,
13 | "metadata": {
14 | "tags": [
15 | "hide-input"
16 | ]
17 | },
18 | "outputs": [
19 | {
20 | "name": "stdout",
21 | "output_type": "stream",
22 | "text": [
23 | "hide-input\n"
24 | ]
25 | }
26 | ],
27 | "source": [
28 | "print(\"hide-input\")"
29 | ]
30 | },
31 | {
32 | "cell_type": "code",
33 | "execution_count": 2,
34 | "metadata": {
35 | "tags": [
36 | "hide-output"
37 | ]
38 | },
39 | "outputs": [
40 | {
41 | "name": "stdout",
42 | "output_type": "stream",
43 | "text": [
44 | "hide-output\n"
45 | ]
46 | }
47 | ],
48 | "source": [
49 | "print(\"hide-output\")"
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": 4,
55 | "metadata": {
56 | "tags": [
57 | "hide-cell"
58 | ]
59 | },
60 | "outputs": [
61 | {
62 | "name": "stdout",
63 | "output_type": "stream",
64 | "text": [
65 | "hide-cell\n"
66 | ]
67 | }
68 | ],
69 | "source": [
70 | "print(\"hide-cell\")"
71 | ]
72 | },
73 | {
74 | "cell_type": "code",
75 | "execution_count": 5,
76 | "metadata": {
77 | "tags": [
78 | "hide-cell"
79 | ],
80 | "mystnb": {
81 | "code_prompt_show": "My show message",
82 | "code_prompt_hide": "My hide message"
83 | }
84 | },
85 | "outputs": [
86 | {
87 | "name": "stdout",
88 | "output_type": "stream",
89 | "text": [
90 | "hide-cell custom message\n"
91 | ]
92 | }
93 | ],
94 | "source": [
95 | "print(\"hide-cell custom message\")"
96 | ]
97 | }
98 | ],
99 | "metadata": {
100 | "kernelspec": {
101 | "display_name": "Python 3.8.13",
102 | "language": "python",
103 | "name": "python3"
104 | },
105 | "language_info": {
106 | "codemirror_mode": {
107 | "name": "ipython",
108 | "version": 3
109 | },
110 | "file_extension": ".py",
111 | "mimetype": "text/x-python",
112 | "name": "python",
113 | "nbconvert_exporter": "python",
114 | "pygments_lexer": "ipython3",
115 | "version": "3.8.13"
116 | },
117 | "orig_nbformat": 4,
118 | "vscode": {
119 | "interpreter": {
120 | "hash": "321f99720af1749431335326d75386e6232ab33d0a78426e9f427a66c2c329a4"
121 | }
122 | }
123 | },
124 | "nbformat": 4,
125 | "nbformat_minor": 2
126 | }
127 |
--------------------------------------------------------------------------------
/tests/notebooks/kernel_alias.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: other
5 | ---
6 |
7 | # a title
8 |
9 | ```{code-cell} ipython3
10 | print("hi")
11 | ```
12 |
--------------------------------------------------------------------------------
/tests/notebooks/latex_build/index.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# MyST: An example project\n",
8 | "\n",
9 | "```{toctree}\n",
10 | "other\n",
11 | "```"
12 | ]
13 | }
14 | ],
15 | "metadata": {
16 | "kernelspec": {
17 | "display_name": "Python 3",
18 | "language": "python",
19 | "name": "python3"
20 | },
21 | "language_info": {
22 | "codemirror_mode": {
23 | "name": "ipython",
24 | "version": 3
25 | },
26 | "file_extension": ".py",
27 | "mimetype": "text/x-python",
28 | "name": "python",
29 | "nbconvert_exporter": "python",
30 | "pygments_lexer": "ipython3",
31 | "version": "3.7.6"
32 | }
33 | },
34 | "nbformat": 4,
35 | "nbformat_minor": 4
36 | }
37 |
--------------------------------------------------------------------------------
/tests/notebooks/latex_build/other.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "(title_ref)=\n",
8 | "# Title\n",
9 | "\n",
10 | "```{contents}\n",
11 | "---\n",
12 | "depth: 2\n",
13 | "---\n",
14 | "```\n",
15 | "\n",
16 | "Content\n"
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "execution_count": 3,
22 | "metadata": {},
23 | "outputs": [
24 | {
25 | "name": "stdout",
26 | "output_type": "stream",
27 | "text": [
28 | "1\n"
29 | ]
30 | }
31 | ],
32 | "source": [
33 | "print(1)"
34 | ]
35 | }
36 | ],
37 | "metadata": {
38 | "kernelspec": {
39 | "display_name": "Python 3",
40 | "language": "python",
41 | "name": "python3"
42 | },
43 | "language_info": {
44 | "codemirror_mode": {
45 | "name": "ipython",
46 | "version": 3
47 | },
48 | "file_extension": ".py",
49 | "mimetype": "text/x-python",
50 | "name": "python",
51 | "nbconvert_exporter": "python",
52 | "pygments_lexer": "ipython3",
53 | "version": "3.8.1"
54 | }
55 | },
56 | "nbformat": 4,
57 | "nbformat_minor": 4
58 | }
59 |
--------------------------------------------------------------------------------
/tests/notebooks/locale/es/LC_MESSAGES/basic_run_intl.po:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C)
3 | # This file is distributed under the same license as the Project name not set package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: Project name not set \n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2024-09-21 23:48+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 |
19 | #: ../tests/notebooks/basic_run_intl.ipynb:10002
20 | msgid "a title"
21 | msgstr "un título"
22 |
23 | #: ../tests/notebooks/basic_run_intl.ipynb:10004
24 | msgid "some text"
25 | msgstr "algo de texto"
26 |
--------------------------------------------------------------------------------
/tests/notebooks/merge_streams.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stdout",
10 | "output_type": "stream",
11 | "text": [
12 | "stdout1\n",
13 | "stdout2\n"
14 | ]
15 | },
16 | {
17 | "name": "stderr",
18 | "output_type": "stream",
19 | "text": [
20 | "stderr1\n",
21 | "stderr2\n"
22 | ]
23 | },
24 | {
25 | "name": "stdout",
26 | "output_type": "stream",
27 | "text": [
28 | "stdout3\n"
29 | ]
30 | },
31 | {
32 | "name": "stderr",
33 | "output_type": "stream",
34 | "text": [
35 | "stderr3\n"
36 | ]
37 | },
38 | {
39 | "data": {
40 | "text/plain": [
41 | "1"
42 | ]
43 | },
44 | "execution_count": 1,
45 | "metadata": {},
46 | "output_type": "execute_result"
47 | }
48 | ],
49 | "source": [
50 | "import sys\n",
51 | "\n",
52 | "print(\"stdout1\", file=sys.stdout)\n",
53 | "print(\"stdout2\", file=sys.stdout)\n",
54 | "print(\"stderr1\", file=sys.stderr)\n",
55 | "print(\"stderr2\", file=sys.stderr)\n",
56 | "print(\"stdout3\", file=sys.stdout)\n",
57 | "print(\"stderr3\", file=sys.stderr)\n",
58 | "1"
59 | ]
60 | }
61 | ],
62 | "metadata": {
63 | "kernelspec": {
64 | "display_name": "Python 3",
65 | "language": "python",
66 | "name": "python3"
67 | },
68 | "language_info": {
69 | "codemirror_mode": {
70 | "name": "ipython",
71 | "version": 3
72 | },
73 | "file_extension": ".py",
74 | "mimetype": "text/x-python",
75 | "name": "python",
76 | "nbconvert_exporter": "python",
77 | "pygments_lexer": "ipython3",
78 | "version": "3.6.1"
79 | }
80 | },
81 | "nbformat": 4,
82 | "nbformat_minor": 2
83 | }
84 |
--------------------------------------------------------------------------------
/tests/notebooks/merge_streams_parallel.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {
7 | "execution": {
8 | "iopub.execute_input": "2024-09-19T21:44:29.809012Z",
9 | "iopub.status.busy": "2024-09-19T21:44:29.808809Z",
10 | "iopub.status.idle": "2024-09-19T21:44:29.978481Z",
11 | "shell.execute_reply": "2024-09-19T21:44:29.977891Z"
12 | }
13 | },
14 | "outputs": [
15 | {
16 | "name": "stdout",
17 | "output_type": "stream",
18 | "text": [
19 | "0"
20 | ]
21 | },
22 | {
23 | "name": "stdout",
24 | "output_type": "stream",
25 | "text": [
26 | "0"
27 | ]
28 | },
29 | {
30 | "name": "stdout",
31 | "output_type": "stream",
32 | "text": [
33 | "0"
34 | ]
35 | },
36 | {
37 | "name": "stdout",
38 | "output_type": "stream",
39 | "text": [
40 | "0"
41 | ]
42 | },
43 | {
44 | "name": "stdout",
45 | "output_type": "stream",
46 | "text": [
47 | "0"
48 | ]
49 | },
50 | {
51 | "name": "stdout",
52 | "output_type": "stream",
53 | "text": [
54 | "0"
55 | ]
56 | },
57 | {
58 | "name": "stdout",
59 | "output_type": "stream",
60 | "text": [
61 | "0"
62 | ]
63 | },
64 | {
65 | "name": "stdout",
66 | "output_type": "stream",
67 | "text": [
68 | "0"
69 | ]
70 | },
71 | {
72 | "name": "stdout",
73 | "output_type": "stream",
74 | "text": [
75 | "0"
76 | ]
77 | },
78 | {
79 | "name": "stdout",
80 | "output_type": "stream",
81 | "text": [
82 | "\n"
83 | ]
84 | },
85 | {
86 | "name": "stdout",
87 | "output_type": "stream",
88 | "text": [
89 | "0"
90 | ]
91 | },
92 | {
93 | "name": "stdout",
94 | "output_type": "stream",
95 | "text": [
96 | "\n"
97 | ]
98 | },
99 | {
100 | "name": "stdout",
101 | "output_type": "stream",
102 | "text": [
103 | "\n"
104 | ]
105 | },
106 | {
107 | "name": "stdout",
108 | "output_type": "stream",
109 | "text": [
110 | "\n"
111 | ]
112 | },
113 | {
114 | "name": "stdout",
115 | "output_type": "stream",
116 | "text": [
117 | "\n"
118 | ]
119 | },
120 | {
121 | "name": "stdout",
122 | "output_type": "stream",
123 | "text": [
124 | "\n"
125 | ]
126 | },
127 | {
128 | "name": "stdout",
129 | "output_type": "stream",
130 | "text": [
131 | "\n"
132 | ]
133 | },
134 | {
135 | "name": "stdout",
136 | "output_type": "stream",
137 | "text": [
138 | "\n"
139 | ]
140 | },
141 | {
142 | "name": "stdout",
143 | "output_type": "stream",
144 | "text": [
145 | "\n"
146 | ]
147 | },
148 | {
149 | "name": "stdout",
150 | "output_type": "stream",
151 | "text": [
152 | "\n"
153 | ]
154 | }
155 | ],
156 | "source": [
157 | "from concurrent.futures import ProcessPoolExecutor\n",
158 | "\n",
159 | "with ProcessPoolExecutor() as executor:\n",
160 | " for i in executor.map(print, [0] * 10):\n",
161 | " pass"
162 | ]
163 | }
164 | ],
165 | "metadata": {
166 | "kernelspec": {
167 | "display_name": "Python 3",
168 | "language": "python",
169 | "name": "python3"
170 | },
171 | "language_info": {
172 | "codemirror_mode": {
173 | "name": "ipython",
174 | "version": 3
175 | },
176 | "file_extension": ".py",
177 | "mimetype": "text/x-python",
178 | "name": "python",
179 | "nbconvert_exporter": "python",
180 | "pygments_lexer": "ipython3",
181 | "version": "3.12.3"
182 | }
183 | },
184 | "nbformat": 4,
185 | "nbformat_minor": 4
186 | }
187 |
--------------------------------------------------------------------------------
/tests/notebooks/mystnb_codecell_file.md:
--------------------------------------------------------------------------------
1 | ---
2 | jupytext:
3 | text_representation:
4 | extension: .md
5 | format_name: myst
6 | kernelspec:
7 | display_name: Python 3
8 | language: python
9 | name: python3
10 | author: Matt
11 | ---
12 |
13 | # a title
14 |
15 | ```{code-cell} ipython3
16 | :load: mystnb_codecell_file.py
17 | ```
18 |
--------------------------------------------------------------------------------
/tests/notebooks/mystnb_codecell_file.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa
2 |
3 | import numpy as np
4 |
--------------------------------------------------------------------------------
/tests/notebooks/mystnb_codecell_file_warnings.md:
--------------------------------------------------------------------------------
1 | ---
2 | jupytext:
3 | text_representation:
4 | extension: .md
5 | format_name: myst
6 | kernelspec:
7 | display_name: Python 3
8 | language: python
9 | name: python3
10 | author: Aakash
11 | ---
12 |
13 | # a title
14 |
15 | ```{code-cell} ipython3
16 | :load: mystnb_codecell_file.py
17 | i = 10
18 | print(i)
19 | ```
20 |
--------------------------------------------------------------------------------
/tests/notebooks/nb_exec_table.md:
--------------------------------------------------------------------------------
1 | ---
2 | jupytext:
3 | text_representation:
4 | extension: .md
5 | format_name: myst
6 | format_version: '0.8'
7 | jupytext_version: 1.4.1+dev
8 | kernelspec:
9 | display_name: Python 3
10 | language: python
11 | name: python3
12 | author: Chris
13 | ---
14 |
15 | # Test the `nb-exec-table` directive
16 |
17 | ```{code-cell} ipython3
18 | print("hi")
19 | ```
20 |
21 | This directive should generate a table of executed notebook statistics.
22 |
23 | ```{nb-exec-table}
24 | ```
25 |
--------------------------------------------------------------------------------
/tests/notebooks/sleep_10.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {
7 | "init_cell": true
8 | },
9 | "outputs": [],
10 | "source": [
11 | "import time\n",
12 | "\n",
13 | "time.sleep(10)"
14 | ]
15 | }
16 | ],
17 | "metadata": {
18 | "celltoolbar": "Edit Metadata",
19 | "execution": {},
20 | "hide_input": false,
21 | "jupytext": {},
22 | "kernelspec": {
23 | "display_name": "Python 3",
24 | "language": "python",
25 | "name": "python3"
26 | },
27 | "language_info": {
28 | "codemirror_mode": {
29 | "name": "ipython",
30 | "version": 3
31 | },
32 | "file_extension": ".py",
33 | "mimetype": "text/x-python",
34 | "name": "python",
35 | "nbconvert_exporter": "python",
36 | "pygments_lexer": "ipython3",
37 | "version": "3.6.10"
38 | }
39 | },
40 | "nbformat": 4,
41 | "nbformat_minor": 2
42 | }
43 |
--------------------------------------------------------------------------------
/tests/notebooks/sleep_10_metadata_timeout.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {
7 | "init_cell": true
8 | },
9 | "outputs": [],
10 | "source": [
11 | "import time\n",
12 | "\n",
13 | "time.sleep(10)"
14 | ]
15 | }
16 | ],
17 | "metadata": {
18 | "celltoolbar": "Edit Metadata",
19 | "execution": {
20 | "timeout": 1
21 | },
22 | "hide_input": false,
23 | "jupytext": {},
24 | "kernelspec": {
25 | "display_name": "Python 3",
26 | "language": "python",
27 | "name": "python3"
28 | },
29 | "language_info": {
30 | "codemirror_mode": {
31 | "name": "ipython",
32 | "version": 3
33 | },
34 | "file_extension": ".py",
35 | "mimetype": "text/x-python",
36 | "name": "python",
37 | "nbconvert_exporter": "python",
38 | "pygments_lexer": "ipython3",
39 | "version": "3.6.10"
40 | }
41 | },
42 | "nbformat": 4,
43 | "nbformat_minor": 2
44 | }
45 |
--------------------------------------------------------------------------------
/tests/notebooks/unknown_mimetype.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "data": {
10 | "unknown": ""
11 | },
12 | "metadata": {},
13 | "output_type": "display_data"
14 | }
15 | ],
16 | "source": [
17 | "a = 1\n",
18 | "print(a)"
19 | ]
20 | }
21 | ],
22 | "metadata": {
23 | "kernelspec": {
24 | "display_name": "Python 3",
25 | "language": "python",
26 | "name": "python3"
27 | },
28 | "language_info": {
29 | "codemirror_mode": {
30 | "name": "ipython",
31 | "version": 3
32 | },
33 | "file_extension": ".py",
34 | "mimetype": "text/x-python",
35 | "name": "python",
36 | "nbconvert_exporter": "python",
37 | "pygments_lexer": "ipython3",
38 | "version": "3.6.1"
39 | },
40 | "test_name": "notebook1"
41 | },
42 | "nbformat": 4,
43 | "nbformat_minor": 2
44 | }
45 |
--------------------------------------------------------------------------------
/tests/notebooks/with_eval.md:
--------------------------------------------------------------------------------
1 | ---
2 | file_format: mystnb
3 | kernelspec:
4 | name: python3
5 | mystnb:
6 | execution_mode: 'inline'
7 | ---
8 |
9 | # Inline evaluation
10 |
11 | ```{code-cell} ipython3
12 | a = 1
13 | ```
14 |
15 | Evaluated inline variable: {eval}`a`
16 |
17 | ```{eval} a
18 | ```
19 |
20 | ```{code-cell} ipython3
21 | import base64
22 | from IPython.display import Image
23 | string = "iVBORw0KGgoAAAANSUhEUgAAAHQAAAB0CAYAAABUmhYnAAAEd0lEQVR4Xu2c0ZLjIAwEk///6GzVvZlspWtWksNRnVcwiGmNwHaS5+v1ej38HKPAU6DHsPy3EIGexVOgh/EUqEBPU+Cw9biHCvQwBQ5bjg4V6GEKHLYcHSrQwxQ4bDk6VKCHKXDYcnSoQA9T4LDllB36fD5vlWR9fUvz0+ve9fp0/O7FU7w0n0CXhBSoDiXTRO06FBKKBLLkLvlGgkTp+UvndPzu/ul46Xq7x2/fQ8kR0wtOBaL+1J6uZ+3fPb5Aw0PRtxOWEkigAr3mCJUMuk9cM45uG3ZvJwel8dN4byW8+r1cgWYPVgRaLIlpwqWCT1cgHbr8skOgYUqkgtHwVYfQKZTiTW8rdCgQFWjtt2Pjty3TGdztOB0aHlosuVcHpglJ+h3nUFow7bE6dDOHCjRN2fBty917qEAF+jEHaI+bTlhK0Nsf/aUBpXtYdXy6noDS9dTePf74oYgWRO3dC6b57k6o7vUJFAh3Cz6dMAIV6FWB9FCQlry1f/ejQXLgt9eX6tXu0DSAtL9APysm0OYHI2mCUgVKxxOoQNOcubc/7XnF5yj3LuYPs5Ud+oc5Ry8R6GEpK1CBjlaMuwcvl1xyBC2I8im9T0xva6pPbtL1V+MjPQW6KEQJRAlAggs0vK2oCibQ4g9+LbnXb96THlQBvl5y0yclqYNQAKgAVGIJQHWPpfjf4uv+bUsagECvClCCkL46VIdecyQtKZRhlKGW3OG3LekeQ0DSBOk+1VLCdbdTAqfzlUuuQFPJe/fM9kORQAV6UYBKJslF11NJS0s8xZO2U3zpeO0lNw2g2+HV8dLbKJov1aMKWKDFfyITKKRsegqmjE7H06FpTRHoRwUoQUnu9pJLh4z0EFMdjwRI46ESWwVC8VK7QMN/TRHookDqCB1Knry261AdmmXMdG86xabzd49H83fP1+5QWkB3e7sg4eu06nra46++4K4uqHp9uyACrSKpXS/Q5kMRnUJruN6vnr7Po/VMn9KrepX3UBKgGmD1UVw6P61HoKmi0F+HfhZIhy766NDhU2F66CEgzQXjQRUjjb8aX7tDaYFpwKkgAi0SSAUXaO0Pjkk/HUoKFQ9p0wm/hjcONC2B6W3B24KKv1ZLx0vzgfQoFsyHQJe3LQINHUEZrUNre6wO1aHLw+AvO5QOHdReLbE0/vSeedyhKBWUDh00XpoAAg2/EkIAqD0FlPYXqEDp3Pix/b8/FKUOIMem7fR6j8Yr0fvlYoEWK4JAw0dplOE6dLnrqH5JrCp4NcMFejPQ6h7RnTAUT/eTKkpYiidtH99D04C6bwvS+QX65W8sUMkVaKgAlcRwuLfuNL5Ah/fQKkC6Pi2JKXB6NEjxUTslKF1P7e17KE1YbRfoZwUFuuijQ4v/l5s6VocOOzQFYv9ZBcoldzY8R08VEGiq2Ob9Bbo5oDQ8gaaKbd5foJsDSsMTaKrY5v0FujmgNDyBpopt3l+gmwNKwxNoqtjm/QW6OaA0PIGmim3eX6CbA0rDE2iq2Ob9Bbo5oDS8H8eCMw7yCzx+AAAAAElFTkSuQmCC"
24 | img = Image(base64.b64decode(string))
25 | ```
26 |
27 | ```{eval:figure} img
28 | A caption
29 | ```
30 |
--------------------------------------------------------------------------------
/tests/test_ansi_lexer.py:
--------------------------------------------------------------------------------
1 | from pygments.token import Text, Token
2 | import pytest
3 |
4 | from myst_nb.core import lexers
5 |
6 |
7 | @pytest.mark.parametrize(
8 | ("bold", "faint", "fg_color", "bg_color", "expected"),
9 | (
10 | (False, False, False, False, Text),
11 | (True, False, False, False, Token.Color.Bold),
12 | (True, False, "Red", False, Token.Color.Bold.Red),
13 | (True, False, "Red", "Blue", Token.Color.Bold.Red.BGBlue),
14 | (True, True, "Red", "Blue", Token.Color.Bold.Faint.Red.BGBlue),
15 | ),
16 | )
17 | def test_token_from_lexer_state(bold, faint, fg_color, bg_color, expected):
18 | ret = lexers._token_from_lexer_state(bold, faint, fg_color, bg_color)
19 | assert ret == expected
20 |
21 |
22 | def _highlight(text):
23 | return tuple(lexers.AnsiColorLexer().get_tokens(text))
24 |
25 |
26 | def test_plain_text():
27 | assert _highlight("hello world\n") == ((Text, "hello world\n"),)
28 |
29 |
30 | def test_simple_colors():
31 | assert _highlight(
32 | "plain text\n"
33 | "\x1b[31mred text\n"
34 | "\x1b[1;32mbold green text\n"
35 | "\x1b[39mfg color turned off\n"
36 | "\x1b[0mplain text after reset\n"
37 | "\x1b[1mbold text\n"
38 | "\x1b[43mbold from previous line with yellow bg\n"
39 | "\x1b[49mbg color turned off\n"
40 | "\x1b[2mfaint turned on\n"
41 | "\x1b[22mbold turned off\n"
42 | ) == (
43 | (Text, "plain text\n"),
44 | (Token.Color.Red, "red text\n"),
45 | (Token.Color.Bold.Green, "bold green text\n"),
46 | (Token.Color.Bold, "fg color turned off\n"),
47 | (Text, "plain text after reset\n"),
48 | (Token.Color.Bold, "bold text\n"),
49 | (Token.Color.Bold.BGYellow, "bold from previous line with yellow bg\n"),
50 | (Token.Color.Bold, "bg color turned off\n"),
51 | (Token.Color.Bold.Faint, "faint turned on\n"),
52 | (Text, "bold turned off\n"),
53 | )
54 |
55 |
56 | def test_highlight_empty_end_specifier():
57 | ret = _highlight("plain\x1b[31mred\x1b[mplain\n")
58 | assert ret == ((Text, "plain"), (Token.Color.Red, "red"), (Text, "plain\n"))
59 |
60 |
61 | def test_ignores_unrecognized_ansi_color_codes():
62 | """It should just strip and ignore any unrecognized color ANSI codes."""
63 | assert _highlight(
64 | # unknown int code
65 | "\x1b[99m"
66 | "plain text\n"
67 | # invalid non-int code
68 | "\x1b[=m"
69 | "plain text\n"
70 | ) == (
71 | (Text, "plain text\n"),
72 | (Text, "plain text\n"),
73 | )
74 |
75 |
76 | def test_ignores_valid_ansi_non_color_codes():
77 | """It should just strip and ignore any non-color ANSI codes.
78 |
79 | These include things like moving the cursor position, erasing lines, etc.
80 | """
81 | assert _highlight(
82 | # restore cursor position
83 | "\x1b[u"
84 | "plain "
85 | # move cursor backwards 55 steps
86 | "\x1b[55C"
87 | "text\n"
88 | ) == (
89 | # Ideally these would be just one token, but our regex isn't smart
90 | # enough yet.
91 | (Text, "plain "),
92 | (Text, "text\n"),
93 | )
94 |
95 |
96 | def test_ignores_completely_invalid_escapes():
97 | """It should strip and ignore invalid escapes.
98 |
99 | This shouldn't happen in valid ANSI text, but we could have an escape
100 | followed by garbage.
101 | """
102 | assert _highlight("plain \x1b[%text\n") == (
103 | (Text, "plain "),
104 | (Text, "%text\n"),
105 | )
106 |
--------------------------------------------------------------------------------
/tests/test_cli.py:
--------------------------------------------------------------------------------
1 | """Test the quickstart CLI"""
2 |
3 | import os
4 | from pathlib import Path
5 |
6 | import nbformat
7 | from sphinx import version_info as sphinx_version_info
8 |
9 | from myst_nb.cli import md_to_nb, quickstart
10 |
11 |
12 | def test_quickstart(tmp_path: Path, make_app):
13 | """Test the quickstart CLI builds a valid sphinx project."""
14 | project_path = tmp_path / "project"
15 | quickstart([str(project_path)])
16 | assert {p.name for p in project_path.iterdir()} == {
17 | ".gitignore",
18 | "conf.py",
19 | "index.md",
20 | "notebook1.ipynb",
21 | "notebook2.md",
22 | }
23 |
24 | # For compatibility with multiple versions of sphinx, convert pathlib.Path to
25 | # sphinx.testing.path.path here.
26 | if sphinx_version_info >= (7, 2):
27 | app_srcdir = project_path
28 | else:
29 | from sphinx.testing.path import path
30 |
31 | app_srcdir = path(os.fspath(project_path))
32 |
33 | app = make_app(srcdir=app_srcdir, buildername="html")
34 | app.build()
35 | assert app._warning.getvalue().strip() == ""
36 | assert (project_path / "_build/html/index.html").exists()
37 |
38 |
39 | def test_md_to_nb(tmp_path: Path):
40 | """Test the md_to_nb CLI."""
41 | path = tmp_path / "notebook.md"
42 | outpath = path.with_suffix(".ipynb")
43 | path.write_text(
44 | """\
45 | ---
46 | kernelspec:
47 | name: python3
48 | ---
49 | # Title
50 | +++
51 | next cell
52 | """,
53 | "utf-8",
54 | )
55 | md_to_nb([str(path)])
56 | assert path.exists()
57 | with outpath.open("r") as handle:
58 | nb = nbformat.read(handle, as_version=4)
59 | assert nb.metadata == {"kernelspec": {"display_name": "python3", "name": "python3"}}
60 | assert len(nb.cells) == 2
61 |
--------------------------------------------------------------------------------
/tests/test_codecell_file.py:
--------------------------------------------------------------------------------
1 | """Test notebooks containing code cells with the `load` option."""
2 |
3 | import pytest
4 | from sphinx.util.fileutil import copy_asset_file
5 |
6 |
7 | @pytest.mark.sphinx_params(
8 | "mystnb_codecell_file.md",
9 | conf={"nb_execution_mode": "cache", "source_suffix": {".md": "myst-nb"}},
10 | )
11 | def test_codecell_file(sphinx_run, file_regression, check_nbs, get_test_path):
12 | asset_path = get_test_path("mystnb_codecell_file.py")
13 | copy_asset_file(str(asset_path), str(sphinx_run.app.srcdir))
14 | sphinx_run.build()
15 | assert sphinx_run.warnings() == ""
16 | assert set(sphinx_run.env.metadata["mystnb_codecell_file"].keys()) == {
17 | "jupytext",
18 | "author",
19 | "source_map",
20 | "wordcount",
21 | "kernelspec",
22 | "language_info",
23 | }
24 | assert set(sphinx_run.env.nb_metadata["mystnb_codecell_file"].keys()) == {
25 | "exec_data",
26 | }
27 | assert sphinx_run.env.metadata["mystnb_codecell_file"]["author"] == "Matt"
28 | assert sphinx_run.env.metadata["mystnb_codecell_file"]["kernelspec"] == {
29 | "display_name": "Python 3",
30 | "language": "python",
31 | "name": "python3",
32 | }
33 | try:
34 | file_regression.check(
35 | sphinx_run.get_nb(),
36 | check_fn=check_nbs,
37 | extension=".ipynb",
38 | encoding="utf-8",
39 | )
40 | finally:
41 | file_regression.check(
42 | sphinx_run.get_doctree().pformat(), extension=".xml", encoding="utf-8"
43 | )
44 |
45 |
46 | @pytest.mark.sphinx_params(
47 | "mystnb_codecell_file_warnings.md",
48 | conf={"nb_execution_mode": "force", "source_suffix": {".md": "myst-nb"}},
49 | )
50 | def test_codecell_file_warnings(sphinx_run, file_regression, check_nbs, get_test_path):
51 | asset_path = get_test_path("mystnb_codecell_file.py")
52 | copy_asset_file(str(asset_path), str(sphinx_run.app.srcdir))
53 | sphinx_run.build()
54 | # assert (
55 | # "mystnb_codecell_file_warnings.md:14 content of code-cell "
56 | # "is being overwritten by :load: mystnb_codecell_file.py"
57 | # in sphinx_run.warnings()
58 | # )
59 | assert set(sphinx_run.env.metadata["mystnb_codecell_file_warnings"].keys()) == {
60 | "jupytext",
61 | "author",
62 | "source_map",
63 | "wordcount",
64 | "kernelspec",
65 | "language_info",
66 | }
67 | assert set(sphinx_run.env.nb_metadata["mystnb_codecell_file_warnings"].keys()) == {
68 | "exec_data",
69 | }
70 | assert (
71 | sphinx_run.env.metadata["mystnb_codecell_file_warnings"]["author"] == "Aakash"
72 | )
73 | assert sphinx_run.env.metadata["mystnb_codecell_file_warnings"]["kernelspec"] == {
74 | "display_name": "Python 3",
75 | "language": "python",
76 | "name": "python3",
77 | }
78 | try:
79 | file_regression.check(
80 | sphinx_run.get_nb(),
81 | check_fn=check_nbs,
82 | extension=".ipynb",
83 | encoding="utf-8",
84 | )
85 | finally:
86 | file_regression.check(
87 | sphinx_run.get_doctree().pformat(), extension=".xml", encoding="utf-8"
88 | )
89 |
--------------------------------------------------------------------------------
/tests/test_codecell_file/test_codecell_file.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "77fd61dd",
6 | "metadata": {},
7 | "source": [
8 | "# a title"
9 | ]
10 | },
11 | {
12 | "cell_type": "code",
13 | "execution_count": 1,
14 | "id": "2e32aa7d",
15 | "metadata": {
16 | "load": "mystnb_codecell_file.py"
17 | },
18 | "outputs": [],
19 | "source": [
20 | "# flake8: noqa\n",
21 | "\n",
22 | "import numpy as np\n"
23 | ]
24 | }
25 | ],
26 | "metadata": {
27 | "author": "Matt",
28 | "jupytext": {
29 | "text_representation": {
30 | "extension": ".md",
31 | "format_name": "myst"
32 | }
33 | },
34 | "kernelspec": {
35 | "display_name": "Python 3",
36 | "language": "python",
37 | "name": "python3"
38 | },
39 | "language_info": {
40 | "codemirror_mode": {
41 | "name": "ipython",
42 | "version": 3
43 | },
44 | "file_extension": ".py",
45 | "mimetype": "text/x-python",
46 | "name": "python",
47 | "nbconvert_exporter": "python",
48 | "pygments_lexer": "ipython3",
49 | "version": "3.8.10"
50 | },
51 | "source_map": [
52 | 11,
53 | 15
54 | ]
55 | },
56 | "nbformat": 4,
57 | "nbformat_minor": 5
58 | }
59 |
--------------------------------------------------------------------------------
/tests/test_codecell_file/test_codecell_file.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 |
7 |
8 | # flake8: noqa
9 |
10 | import numpy as np
--------------------------------------------------------------------------------
/tests/test_codecell_file/test_codecell_file_warnings.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "daa53dc3",
6 | "metadata": {},
7 | "source": [
8 | "# a title"
9 | ]
10 | },
11 | {
12 | "cell_type": "code",
13 | "execution_count": 1,
14 | "id": "d218bd29",
15 | "metadata": {
16 | "load": "mystnb_codecell_file.py"
17 | },
18 | "outputs": [],
19 | "source": [
20 | "# flake8: noqa\n",
21 | "\n",
22 | "import numpy as np\n"
23 | ]
24 | }
25 | ],
26 | "metadata": {
27 | "author": "Aakash",
28 | "jupytext": {
29 | "text_representation": {
30 | "extension": ".md",
31 | "format_name": "myst"
32 | }
33 | },
34 | "kernelspec": {
35 | "display_name": "Python 3",
36 | "language": "python",
37 | "name": "python3"
38 | },
39 | "language_info": {
40 | "codemirror_mode": {
41 | "name": "ipython",
42 | "version": 3
43 | },
44 | "file_extension": ".py",
45 | "mimetype": "text/x-python",
46 | "name": "python",
47 | "nbconvert_exporter": "python",
48 | "pygments_lexer": "ipython3",
49 | "version": "3.8.10"
50 | },
51 | "source_map": [
52 | 11,
53 | 15
54 | ]
55 | },
56 | "nbformat": 4,
57 | "nbformat_minor": 5
58 | }
59 |
--------------------------------------------------------------------------------
/tests/test_codecell_file/test_codecell_file_warnings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 |
7 |
8 | # flake8: noqa
9 |
10 | import numpy as np
--------------------------------------------------------------------------------
/tests/test_docutils.py:
--------------------------------------------------------------------------------
1 | """Run parsing tests against the docutils parser."""
2 |
3 | from io import StringIO
4 | import json
5 | from pathlib import Path
6 |
7 | from docutils.core import publish_doctree, publish_string
8 | import pytest
9 | import sphinx
10 | import yaml
11 |
12 | from myst_nb.docutils_ import Parser
13 |
14 | FIXTURE_PATH = Path(__file__).parent.joinpath("nb_fixtures")
15 |
16 |
17 | @pytest.mark.param_file(FIXTURE_PATH / "basic.txt")
18 | def test_basic(file_params):
19 | """Test basic parsing."""
20 | if (
21 | "Footnote definitions defined in different cells" in file_params.title
22 | and sphinx.version_info[0] < 5
23 | ):
24 | pytest.skip("footnote definition ids changes")
25 | dct = yaml.safe_load(file_params.content)
26 | dct.update({"nbformat": 4, "nbformat_minor": 4})
27 | dct.setdefault("metadata", {})
28 | dct["metadata"].setdefault(
29 | "kernelspec", {"name": "python3", "display_name": "Python 3", "language": ""}
30 | )
31 | report_stream = StringIO()
32 | doctree = publish_doctree(
33 | json.dumps(dct),
34 | parser=Parser(),
35 | settings_overrides={
36 | "nb_execution_mode": "off",
37 | "nb_output_folder": "",
38 | "myst_all_links_external": True,
39 | "warning_stream": report_stream,
40 | },
41 | )
42 | assert report_stream.getvalue().rstrip() == ""
43 |
44 | file_params.assert_expected(doctree.pformat(), rstrip=True)
45 |
46 |
47 | @pytest.mark.param_file(FIXTURE_PATH / "reporter_warnings.txt")
48 | def test_reporting(file_params):
49 | """Test that warnings and errors are reported as expected."""
50 | dct = yaml.safe_load(file_params.content)
51 | dct.update({"metadata": {}, "nbformat": 4, "nbformat_minor": 4})
52 | report_stream = StringIO()
53 | publish_doctree(
54 | json.dumps(dct),
55 | parser=Parser(),
56 | settings_overrides={
57 | "nb_execution_mode": "off",
58 | "nb_output_folder": "",
59 | "warning_stream": report_stream,
60 | },
61 | )
62 | file_params.assert_expected(report_stream.getvalue(), rstrip=True)
63 |
64 |
65 | def test_html_resources(tmp_path):
66 | """Test HTML resources are correctly output."""
67 | report_stream = StringIO()
68 | result = publish_string(
69 | json.dumps({"cells": [], "metadata": {}, "nbformat": 4, "nbformat_minor": 4}),
70 | parser=Parser(),
71 | writer_name="html",
72 | settings_overrides={
73 | "nb_execution_mode": "off",
74 | "nb_output_folder": str(tmp_path),
75 | "warning_stream": report_stream,
76 | "output_encoding": "unicode",
77 | "embed_stylesheet": False,
78 | },
79 | )
80 | assert report_stream.getvalue().rstrip() == ""
81 | assert "mystnb.css" in result
82 | assert "pygments.css" in result
83 | assert tmp_path.joinpath("mystnb.css").is_file()
84 | assert tmp_path.joinpath("pygments.css").is_file()
85 |
--------------------------------------------------------------------------------
/tests/test_eval.py:
--------------------------------------------------------------------------------
1 | """Test the `eval` directives and roles."""
2 |
3 | import pytest
4 |
5 |
6 | @pytest.mark.sphinx_params("with_eval.md", conf={"nb_execution_mode": "inline"})
7 | def test_sphinx(sphinx_run, clean_doctree, file_regression):
8 | """Test a sphinx build."""
9 | sphinx_run.build()
10 | # print(sphinx_run.status())
11 | # print(sphinx_run.warnings())
12 | assert sphinx_run.warnings() == ""
13 | doctree = clean_doctree(sphinx_run.get_resolved_doctree("with_eval"))
14 | file_regression.check(
15 | doctree.pformat(),
16 | encoding="utf-8",
17 | )
18 |
--------------------------------------------------------------------------------
/tests/test_eval/test_sphinx.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Inline evaluation
5 |
6 |
7 |
8 | a = 1
9 |
10 | Evaluated inline variable:
11 |
12 | 1
13 |
14 | 1
15 |
16 |
17 |
18 | import base64
19 | from IPython.display import Image
20 | string = "iVBORw0KGgoAAAANSUhEUgAAAHQAAAB0CAYAAABUmhYnAAAEd0lEQVR4Xu2c0ZLjIAwEk///6GzVvZlspWtWksNRnVcwiGmNwHaS5+v1ej38HKPAU6DHsPy3EIGexVOgh/EUqEBPU+Cw9biHCvQwBQ5bjg4V6GEKHLYcHSrQwxQ4bDk6VKCHKXDYcnSoQA9T4LDllB36fD5vlWR9fUvz0+ve9fp0/O7FU7w0n0CXhBSoDiXTRO06FBKKBLLkLvlGgkTp+UvndPzu/ul46Xq7x2/fQ8kR0wtOBaL+1J6uZ+3fPb5Aw0PRtxOWEkigAr3mCJUMuk9cM45uG3ZvJwel8dN4byW8+r1cgWYPVgRaLIlpwqWCT1cgHbr8skOgYUqkgtHwVYfQKZTiTW8rdCgQFWjtt2Pjty3TGdztOB0aHlosuVcHpglJ+h3nUFow7bE6dDOHCjRN2fBty917qEAF+jEHaI+bTlhK0Nsf/aUBpXtYdXy6noDS9dTePf74oYgWRO3dC6b57k6o7vUJFAh3Cz6dMAIV6FWB9FCQlry1f/ejQXLgt9eX6tXu0DSAtL9APysm0OYHI2mCUgVKxxOoQNOcubc/7XnF5yj3LuYPs5Ud+oc5Ry8R6GEpK1CBjlaMuwcvl1xyBC2I8im9T0xva6pPbtL1V+MjPQW6KEQJRAlAggs0vK2oCibQ4g9+LbnXb96THlQBvl5y0yclqYNQAKgAVGIJQHWPpfjf4uv+bUsagECvClCCkL46VIdecyQtKZRhlKGW3OG3LekeQ0DSBOk+1VLCdbdTAqfzlUuuQFPJe/fM9kORQAV6UYBKJslF11NJS0s8xZO2U3zpeO0lNw2g2+HV8dLbKJov1aMKWKDFfyITKKRsegqmjE7H06FpTRHoRwUoQUnu9pJLh4z0EFMdjwRI46ESWwVC8VK7QMN/TRHookDqCB1Knry261AdmmXMdG86xabzd49H83fP1+5QWkB3e7sg4eu06nra46++4K4uqHp9uyACrSKpXS/Q5kMRnUJruN6vnr7Po/VMn9KrepX3UBKgGmD1UVw6P61HoKmi0F+HfhZIhy766NDhU2F66CEgzQXjQRUjjb8aX7tDaYFpwKkgAi0SSAUXaO0Pjkk/HUoKFQ9p0wm/hjcONC2B6W3B24KKv1ZLx0vzgfQoFsyHQJe3LQINHUEZrUNre6wO1aHLw+AvO5QOHdReLbE0/vSeedyhKBWUDh00XpoAAg2/EkIAqD0FlPYXqEDp3Pix/b8/FKUOIMem7fR6j8Yr0fvlYoEWK4JAw0dplOE6dLnrqH5JrCp4NcMFejPQ6h7RnTAUT/eTKkpYiidtH99D04C6bwvS+QX65W8sUMkVaKgAlcRwuLfuNL5Ah/fQKkC6Pi2JKXB6NEjxUTslKF1P7e17KE1YbRfoZwUFuuijQ4v/l5s6VocOOzQFYv9ZBcoldzY8R08VEGiq2Ob9Bbo5oDQ8gaaKbd5foJsDSsMTaKrY5v0FujmgNDyBpopt3l+gmwNKwxNoqtjm/QW6OaA0PIGmim3eX6CbA0rDE2iq2Ob9Bbo5oDS8H8eCMw7yCzx+AAAAAElFTkSuQmCC"
21 | img = Image(base64.b64decode(string))
22 |
23 |
24 |
25 | A caption
26 |
--------------------------------------------------------------------------------
/tests/test_execute/test_allow_errors_auto.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "ename": "Exception",
19 | "evalue": "oopsie!",
20 | "output_type": "error",
21 | "traceback": [
22 | "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
23 | "\u001B[0;31mException\u001B[0m Traceback (most recent call last)",
24 | "Cell \u001B[0;32mIn[1], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124moopsie!\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
25 | "\u001B[0;31mException\u001B[0m: oopsie!"
26 | ]
27 | }
28 | ],
29 | "source": [
30 | "raise Exception(\"oopsie!\")"
31 | ]
32 | }
33 | ],
34 | "metadata": {
35 | "kernelspec": {
36 | "display_name": "Python 3",
37 | "language": "python",
38 | "name": "python3"
39 | },
40 | "language_info": {
41 | "codemirror_mode": {
42 | "name": "ipython",
43 | "version": 3
44 | },
45 | "file_extension": ".py",
46 | "mimetype": "text/x-python",
47 | "name": "python",
48 | "nbconvert_exporter": "python",
49 | "pygments_lexer": "ipython3",
50 | "version": "3.10.12"
51 | },
52 | "test_name": "notebook1"
53 | },
54 | "nbformat": 4,
55 | "nbformat_minor": 2
56 | }
57 |
--------------------------------------------------------------------------------
/tests/test_execute/test_allow_errors_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | raise Exception("oopsie!")
11 |
12 |
13 | ---------------------------------------------------------------------------
14 | Exception Traceback (most recent call last)
15 | Cell In[1], line 1
16 | ----> 1 raise Exception("oopsie!")
17 |
18 | Exception: oopsie!
19 |
--------------------------------------------------------------------------------
/tests/test_execute/test_allow_errors_cache.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "ename": "Exception",
19 | "evalue": "oopsie!",
20 | "output_type": "error",
21 | "traceback": [
22 | "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
23 | "\u001B[0;31mException\u001B[0m Traceback (most recent call last)",
24 | "Cell \u001B[0;32mIn[1], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124moopsie!\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
25 | "\u001B[0;31mException\u001B[0m: oopsie!"
26 | ]
27 | }
28 | ],
29 | "source": [
30 | "raise Exception(\"oopsie!\")"
31 | ]
32 | }
33 | ],
34 | "metadata": {
35 | "kernelspec": {
36 | "display_name": "Python 3",
37 | "language": "python",
38 | "name": "python3"
39 | },
40 | "language_info": {
41 | "codemirror_mode": {
42 | "name": "ipython",
43 | "version": 3
44 | },
45 | "file_extension": ".py",
46 | "mimetype": "text/x-python",
47 | "name": "python",
48 | "nbconvert_exporter": "python",
49 | "pygments_lexer": "ipython3",
50 | "version": "3.10.12"
51 | },
52 | "test_name": "notebook1"
53 | },
54 | "nbformat": 4,
55 | "nbformat_minor": 2
56 | }
57 |
--------------------------------------------------------------------------------
/tests/test_execute/test_allow_errors_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | raise Exception("oopsie!")
11 |
12 |
13 | ---------------------------------------------------------------------------
14 | Exception Traceback (most recent call last)
15 | Cell In[1], line 1
16 | ----> 1 raise Exception("oopsie!")
17 |
18 | Exception: oopsie!
19 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_failing_auto.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "ename": "Exception",
19 | "evalue": "oopsie!",
20 | "output_type": "error",
21 | "traceback": [
22 | "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
23 | "\u001B[0;31mException\u001B[0m Traceback (most recent call last)",
24 | "Cell \u001B[0;32mIn[1], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124moopsie!\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
25 | "\u001B[0;31mException\u001B[0m: oopsie!"
26 | ]
27 | }
28 | ],
29 | "source": [
30 | "raise Exception(\"oopsie!\")"
31 | ]
32 | }
33 | ],
34 | "metadata": {
35 | "kernelspec": {
36 | "display_name": "Python 3",
37 | "language": "python",
38 | "name": "python3"
39 | },
40 | "language_info": {
41 | "codemirror_mode": {
42 | "name": "ipython",
43 | "version": 3
44 | },
45 | "file_extension": ".py",
46 | "mimetype": "text/x-python",
47 | "name": "python",
48 | "nbconvert_exporter": "python",
49 | "pygments_lexer": "ipython3",
50 | "version": "3.10.12"
51 | },
52 | "test_name": "notebook1"
53 | },
54 | "nbformat": 4,
55 | "nbformat_minor": 2
56 | }
57 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_failing_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | raise Exception("oopsie!")
11 |
12 |
13 | ---------------------------------------------------------------------------
14 | Exception Traceback (most recent call last)
15 | Cell In[1], line 1
16 | ----> 1 raise Exception("oopsie!")
17 |
18 | Exception: oopsie!
19 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_failing_cache.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "ename": "Exception",
19 | "evalue": "oopsie!",
20 | "output_type": "error",
21 | "traceback": [
22 | "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
23 | "\u001B[0;31mException\u001B[0m Traceback (most recent call last)",
24 | "Cell \u001B[0;32mIn[1], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124moopsie!\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
25 | "\u001B[0;31mException\u001B[0m: oopsie!"
26 | ]
27 | }
28 | ],
29 | "source": [
30 | "raise Exception(\"oopsie!\")"
31 | ]
32 | }
33 | ],
34 | "metadata": {
35 | "kernelspec": {
36 | "display_name": "Python 3",
37 | "language": "python",
38 | "name": "python3"
39 | },
40 | "language_info": {
41 | "codemirror_mode": {
42 | "name": "ipython",
43 | "version": 3
44 | },
45 | "file_extension": ".py",
46 | "mimetype": "text/x-python",
47 | "name": "python",
48 | "nbconvert_exporter": "python",
49 | "pygments_lexer": "ipython3",
50 | "version": "3.10.12"
51 | },
52 | "test_name": "notebook1"
53 | },
54 | "nbformat": 4,
55 | "nbformat_minor": 2
56 | }
57 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_failing_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | raise Exception("oopsie!")
11 |
12 |
13 | ---------------------------------------------------------------------------
14 | Exception Traceback (most recent call last)
15 | Cell In[1], line 1
16 | ----> 1 raise Exception("oopsie!")
17 |
18 | Exception: oopsie!
19 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_failing_inline.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "ename": "Exception",
19 | "evalue": "oopsie!",
20 | "output_type": "error",
21 | "traceback": [
22 | "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
23 | "\u001B[0;31mException\u001B[0m Traceback (most recent call last)",
24 | "Cell \u001B[0;32mIn[1], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124moopsie!\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n",
25 | "\u001B[0;31mException\u001B[0m: oopsie!"
26 | ]
27 | }
28 | ],
29 | "source": [
30 | "raise Exception(\"oopsie!\")"
31 | ]
32 | }
33 | ],
34 | "metadata": {
35 | "kernelspec": {
36 | "display_name": "Python 3",
37 | "language": "python",
38 | "name": "python3"
39 | },
40 | "language_info": {
41 | "codemirror_mode": {
42 | "name": "ipython",
43 | "version": 3
44 | },
45 | "file_extension": ".py",
46 | "mimetype": "text/x-python",
47 | "name": "python",
48 | "nbconvert_exporter": "python",
49 | "pygments_lexer": "ipython3",
50 | "version": "3.10.12"
51 | },
52 | "test_name": "notebook1"
53 | },
54 | "nbformat": 4,
55 | "nbformat_minor": 2
56 | }
57 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_failing_inline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | raise Exception("oopsie!")
11 |
12 |
13 | ---------------------------------------------------------------------------
14 | Exception Traceback (most recent call last)
15 | Cell In[1], line 1
16 | ----> 1 raise Exception("oopsie!")
17 |
18 | Exception: oopsie!
19 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_unrun_auto.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "1\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "a = 1\n",
27 | "print(a)"
28 | ]
29 | }
30 | ],
31 | "metadata": {
32 | "kernelspec": {
33 | "display_name": "Python 3",
34 | "language": "python",
35 | "name": "python3"
36 | },
37 | "language_info": {
38 | "codemirror_mode": {
39 | "name": "ipython",
40 | "version": 3
41 | },
42 | "file_extension": ".py",
43 | "mimetype": "text/x-python",
44 | "name": "python",
45 | "nbconvert_exporter": "python",
46 | "pygments_lexer": "ipython3",
47 | "version": "3.10.12"
48 | },
49 | "test_name": "notebook1"
50 | },
51 | "nbformat": 4,
52 | "nbformat_minor": 2
53 | }
54 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_unrun_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
13 |
14 | 1
15 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_unrun_cache.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "1\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "a = 1\n",
27 | "print(a)"
28 | ]
29 | }
30 | ],
31 | "metadata": {
32 | "kernelspec": {
33 | "display_name": "Python 3",
34 | "language": "python",
35 | "name": "python3"
36 | },
37 | "language_info": {
38 | "codemirror_mode": {
39 | "name": "ipython",
40 | "version": 3
41 | },
42 | "file_extension": ".py",
43 | "mimetype": "text/x-python",
44 | "name": "python",
45 | "nbconvert_exporter": "python",
46 | "pygments_lexer": "ipython3",
47 | "version": "3.10.12"
48 | },
49 | "test_name": "notebook1"
50 | },
51 | "nbformat": 4,
52 | "nbformat_minor": 2
53 | }
54 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_unrun_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
13 |
14 | 1
15 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_unrun_inline.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "1\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "a = 1\n",
27 | "print(a)"
28 | ]
29 | }
30 | ],
31 | "metadata": {
32 | "kernelspec": {
33 | "display_name": "Python 3",
34 | "language": "python",
35 | "name": "python3"
36 | },
37 | "language_info": {
38 | "codemirror_mode": {
39 | "name": "ipython",
40 | "version": 3
41 | },
42 | "file_extension": ".py",
43 | "mimetype": "text/x-python",
44 | "name": "python",
45 | "nbconvert_exporter": "python",
46 | "pygments_lexer": "ipython3",
47 | "version": "3.10.12"
48 | },
49 | "test_name": "notebook1"
50 | },
51 | "nbformat": 4,
52 | "nbformat_minor": 2
53 | }
54 |
--------------------------------------------------------------------------------
/tests/test_execute/test_basic_unrun_inline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
13 |
14 | 1
15 |
--------------------------------------------------------------------------------
/tests/test_execute/test_custom_convert_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Custom Formats
5 |
6 |
7 |
8 | import pandas as pd
9 |
10 | x = pd.Series({"A": 1, "B": 3, "C": 2})
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/test_execute/test_custom_convert_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Custom Formats
5 |
6 |
7 |
8 | import pandas as pd
9 |
10 | x = pd.Series({"A": 1, "B": 3, "C": 2})
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/test_execute/test_custom_convert_multiple_extensions_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Custom Formats
5 |
6 |
7 |
8 | import pandas as pd
9 |
10 | x = pd.Series({"A": 1, "B": 3, "C": 2})
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/test_execute/test_custom_convert_multiple_extensions_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Custom Formats
5 |
6 |
7 |
8 | import pandas as pd
9 |
10 | x = pd.Series({"A": 1, "B": 3, "C": 2})
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/test_execute/test_exclude_path.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
--------------------------------------------------------------------------------
/tests/test_execute/test_jupyter_cache_path.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "1\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "a = 1\n",
27 | "print(a)"
28 | ]
29 | }
30 | ],
31 | "metadata": {
32 | "kernelspec": {
33 | "display_name": "Python 3",
34 | "language": "python",
35 | "name": "python3"
36 | },
37 | "language_info": {
38 | "codemirror_mode": {
39 | "name": "ipython",
40 | "version": 3
41 | },
42 | "file_extension": ".py",
43 | "mimetype": "text/x-python",
44 | "name": "python",
45 | "nbconvert_exporter": "python",
46 | "pygments_lexer": "ipython3",
47 | "version": "3.10.12"
48 | },
49 | "test_name": "notebook1"
50 | },
51 | "nbformat": 4,
52 | "nbformat_minor": 2
53 | }
54 |
--------------------------------------------------------------------------------
/tests/test_execute/test_jupyter_cache_path.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
13 |
14 | 1
15 |
--------------------------------------------------------------------------------
/tests/test_execute/test_nb_exec_table.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Test the
5 |
6 | nb-exec-table
7 | directive
8 |
9 |
10 |
11 | print("hi")
12 |
13 |
14 | hi
15 |
16 | This directive should generate a table of executed notebook statistics.
17 |
18 |
--------------------------------------------------------------------------------
/tests/test_execute/test_no_execute.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# a title\n",
8 | "\n",
9 | "some text\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": null,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "a = 1\n",
19 | "print(a)"
20 | ]
21 | }
22 | ],
23 | "metadata": {
24 | "kernelspec": {
25 | "display_name": "Python 3",
26 | "language": "python",
27 | "name": "python3"
28 | },
29 | "language_info": {
30 | "codemirror_mode": {
31 | "name": "ipython",
32 | "version": 3
33 | },
34 | "file_extension": ".py",
35 | "mimetype": "text/x-python",
36 | "name": "python",
37 | "nbconvert_exporter": "python",
38 | "pygments_lexer": "ipython3",
39 | "version": "3.6.1"
40 | },
41 | "test_name": "notebook1"
42 | },
43 | "nbformat": 4,
44 | "nbformat_minor": 2
45 | }
46 |
--------------------------------------------------------------------------------
/tests/test_execute/test_no_execute.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
--------------------------------------------------------------------------------
/tests/test_glue.py:
--------------------------------------------------------------------------------
1 | """Test the `glue` directives and roles."""
2 |
3 | from IPython.core.displaypub import DisplayPublisher
4 | from IPython.core.interactiveshell import InteractiveShell
5 | import nbformat
6 | import pytest
7 |
8 | from myst_nb.ext.glue import extract_glue_data, glue
9 |
10 |
11 | class MockDisplayPublisher(DisplayPublisher):
12 | def __init__(self, *args, **kwargs):
13 | super().__init__(*args, **kwargs)
14 | self.publish_calls = []
15 |
16 | def publish(self, data, **kwargs):
17 | kwargs["data"] = data
18 | self.publish_calls.append(kwargs)
19 |
20 |
21 | @pytest.fixture()
22 | def mock_ipython():
23 | """A mock IPython shell for testing notebook cell executions."""
24 | shell = InteractiveShell.instance() # type: InteractiveShell
25 | shell.display_pub = MockDisplayPublisher()
26 | yield shell.display_pub
27 | InteractiveShell.clear_instance()
28 |
29 |
30 | def test_glue_func_text(mock_ipython):
31 | glue("a", "b")
32 | assert mock_ipython.publish_calls == [
33 | {
34 | "metadata": {"scrapbook": {"name": "a", "mime_prefix": ""}},
35 | "data": {"text/plain": "'b'"},
36 | }
37 | ]
38 |
39 |
40 | def test_glue_func_obj(mock_ipython):
41 | class Obj:
42 | def __repr__(self):
43 | return "repr"
44 |
45 | def _repr_html_(self):
46 | return "repr
"
47 |
48 | glue("a", Obj())
49 | assert mock_ipython.publish_calls == [
50 | {
51 | "metadata": {"scrapbook": {"name": "a", "mime_prefix": ""}},
52 | "data": {"text/html": "repr
", "text/plain": "repr"},
53 | }
54 | ]
55 |
56 |
57 | def test_glue_func_obj_no_display(mock_ipython):
58 | class Obj:
59 | def __repr__(self):
60 | return "repr"
61 |
62 | def _repr_html_(self):
63 | return "repr
"
64 |
65 | glue("a", Obj(), display=False)
66 | assert mock_ipython.publish_calls == [
67 | {
68 | "metadata": {
69 | "scrapbook": {
70 | "name": "a",
71 | "mime_prefix": "application/papermill.record/",
72 | }
73 | },
74 | "data": {
75 | "application/papermill.record/text/html": "repr
",
76 | "application/papermill.record/text/plain": "repr",
77 | },
78 | }
79 | ]
80 |
81 |
82 | def test_extract_glue_data(get_test_path):
83 | path = get_test_path("with_glue.ipynb")
84 | with open(path) as handle:
85 | notebook = nbformat.read(handle, as_version=4)
86 | data = extract_glue_data(notebook, [], None)
87 | assert set(data) == {
88 | "key_text1",
89 | "key_float",
90 | "key_undisplayed",
91 | "key_df",
92 | "key_plt",
93 | "sym_eq",
94 | }
95 |
96 |
97 | @pytest.mark.sphinx_params("with_glue.ipynb", conf={"nb_execution_mode": "off"})
98 | def test_parser(sphinx_run, clean_doctree, file_regression):
99 | """Test a sphinx build."""
100 | # TODO test duplicate warning in docutils
101 | sphinx_run.build()
102 | # print(sphinx_run.status())
103 | # print(sphinx_run.warnings())
104 | assert sphinx_run.warnings() == ""
105 | assert sphinx_run.env.nb_metadata["with_glue"]["glue"] == [
106 | "key_text1",
107 | "key_float",
108 | "key_undisplayed",
109 | "key_df",
110 | "key_plt",
111 | "sym_eq",
112 | ]
113 | doctree = clean_doctree(sphinx_run.get_resolved_doctree("with_glue"))
114 | file_regression.check(
115 | doctree.pformat(),
116 | encoding="utf-8",
117 | )
118 |
--------------------------------------------------------------------------------
/tests/test_parser/test_basic_run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |
6 | some text
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
13 |
14 | 1
15 |
--------------------------------------------------------------------------------
/tests/test_parser/test_basic_run_intl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | un título
5 |
6 | algo de texto
7 |
8 |
9 |
10 | a = 1
11 | print(a)
12 |
13 |
14 | 1
15 |
--------------------------------------------------------------------------------
/tests/test_parser/test_toctree_in_ipynb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 | Contents
9 |
10 |
11 |
12 |
13 | Title
14 |
15 | Content
16 |
17 |
18 |
19 | print(1)
20 |
21 |
22 | 1
23 |
--------------------------------------------------------------------------------
/tests/test_render_outputs/test_basic_run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a title
5 |