Showing preview only (321K chars total). Download the full file or copy to clipboard to get everything.
Repository: jupyter/nbclient
Branch: main
Commit: e500e95e01a0
Files: 69
Total size: 302.2 KB
Directory structure:
gitextract_xrhwfx_4/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── check-release.yml
│ ├── main.yml
│ ├── prep-release.yml
│ ├── publish-changelog.yml
│ └── publish-release.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── RELEASING.md
├── binder/
│ ├── empty_notebook.ipynb
│ ├── environment.yml
│ └── run_nbclient.ipynb
├── docs/
│ ├── Makefile
│ ├── UPDATE.md
│ ├── _static/
│ │ └── custom.css
│ ├── autogen_config.py
│ ├── client.rst
│ ├── conf.py
│ ├── index.rst
│ ├── installation.rst
│ ├── make.bat
│ └── reference/
│ ├── index.rst
│ ├── modules.rst
│ └── nbclient.rst
├── nbclient/
│ ├── __init__.py
│ ├── _version.py
│ ├── cli.py
│ ├── client.py
│ ├── exceptions.py
│ ├── jsonutil.py
│ ├── output_widget.py
│ ├── py.typed
│ └── util.py
├── pyproject.toml
└── tests/
├── __init__.py
├── base.py
├── conftest.py
├── fake_kernelmanager.py
├── files/
│ ├── Autokill.ipynb
│ ├── Check History in Memory.ipynb
│ ├── Clear Output.ipynb
│ ├── Disable Stdin.ipynb
│ ├── Empty Cell.ipynb
│ ├── Error.ipynb
│ ├── Factorials.ipynb
│ ├── HelloWorld.ipynb
│ ├── Inline Image.ipynb
│ ├── Interrupt.ipynb
│ ├── JupyterWidgets.ipynb
│ ├── Other Comms.ipynb
│ ├── Output.ipynb
│ ├── Parallel Execute A.ipynb
│ ├── Parallel Execute B.ipynb
│ ├── SVG.ipynb
│ ├── Skip Exceptions with Cell Tags.ipynb
│ ├── Skip Exceptions.ipynb
│ ├── Skip Execution with Cell Tag.ipynb
│ ├── Sleep1s.ipynb
│ ├── Unicode.ipynb
│ ├── UnicodePy3.ipynb
│ └── update-display-id.ipynb
├── test_cli.py
├── test_client.py
└── test_util.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions:
patterns:
- "*"
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
time: "04:00"
groups:
actions:
patterns:
- "*"
================================================
FILE: .github/workflows/check-release.yml
================================================
name: Check Release
on:
push:
branches: ["*"]
pull_request:
branches: ["*"]
release:
types: [published]
schedule:
- cron: "0 0 * * *"
jobs:
check_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install Dependencies
shell: bash
run: |
pip install -e .
- name: Check Release
uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
push:
branches: ["main"]
pull_request:
workflow_dispatch:
schedule:
- cron: "0 8 * * *"
defaults:
run:
shell: bash -eux {0}
jobs:
test_lint:
name: Test Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Run Linters
run: |
hatch run typing:test
hatch run lint:build
pipx run interrogate -v .
pipx run doc8 --max-line-length=200
test_docs:
name: Test Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- run: hatch run docs:build
build:
name: Build, test and code coverage
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
include:
- os: ubuntu-latest
python-version: "pypy-3.11"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Run the tests
run: hatch run cov:test || hatch run test:test --lf
- uses: jupyterlab/maintainer-tools/.github/actions/upload-coverage@v1
coverage:
runs-on: ubuntu-latest
needs:
- build
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/report-coverage@v1
test_minimum_versions:
name: Test Minimum Versions
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
dependency_type: minimum
- name: Run the unit tests
run: |
hatch run test:nowarn || hatch -v run test:nowarn --lf
test_prereleases:
name: Test Prereleases
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
dependency_type: pre
- name: Run the tests
run: |
hatch run test:nowarn || hatch run test:nowarn --lf
make_sdist:
name: Make SDist
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: jupyterlab/maintainer-tools/.github/actions/make-sdist@v1
test_sdist:
runs-on: ubuntu-latest
needs: [make_sdist]
name: Install from SDist and Test
timeout-minutes: 20
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: jupyterlab/maintainer-tools/.github/actions/test-sdist@v1
with:
package_spec: .
test_command: hatch run test:test || hatch run test:test --lf
check_links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1
check_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Check Release
uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
tests_check: # This job does nothing and is only used for the branch protection
if: always()
needs:
- coverage
- test_lint
- test_docs
- test_minimum_versions
- test_prereleases
- check_links
- check_release
- test_sdist
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}
================================================
FILE: .github/workflows/prep-release.yml
================================================
name: "Step 1: Prep Release"
on:
workflow_dispatch:
inputs:
version_spec:
description: "New Version Specifier"
default: "next"
required: false
branch:
description: "The branch to target"
required: false
post_version_spec:
description: "Post Version Specifier"
required: false
silent:
description: "Set a placeholder in the changelog and don't publish the release."
required: false
type: boolean
since:
description: "Use PRs with activity since this date or git reference"
required: false
since_last_stable:
description: "Use PRs with activity since the last stable git tag"
required: false
type: boolean
jobs:
prep_release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Prep Release
id: prep-release
uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
version_spec: ${{ github.event.inputs.version_spec }}
silent: ${{ github.event.inputs.silent }}
post_version_spec: ${{ github.event.inputs.post_version_spec }}
target: ${{ github.event.inputs.target }}
branch: ${{ github.event.inputs.branch }}
since: ${{ github.event.inputs.since }}
since_last_stable: ${{ github.event.inputs.since_last_stable }}
- name: "** Next Step **"
run: |
echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}"
================================================
FILE: .github/workflows/publish-changelog.yml
================================================
name: "Publish Changelog"
on:
release:
types: [published]
workflow_dispatch:
inputs:
branch:
description: "The branch to target"
required: false
jobs:
publish_changelog:
runs-on: ubuntu-latest
environment: release
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Publish changelog
id: publish-changelog
uses: jupyter-server/jupyter_releaser/.github/actions/publish-changelog@v2
with:
token: ${{ steps.app-token.outputs.token }}
branch: ${{ github.event.inputs.branch }}
- name: "** Next Step **"
run: |
echo "Merge the changelog update PR: ${{ steps.publish-changelog.outputs.pr_url }}"
================================================
FILE: .github/workflows/publish-release.yml
================================================
name: "Step 2: Publish Release"
on:
workflow_dispatch:
inputs:
branch:
description: "The target branch"
required: false
release_url:
description: "The URL of the draft GitHub release"
required: false
steps_to_skip:
description: "Comma separated list of steps to skip"
required: false
jobs:
publish_release:
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Populate Release
id: populate-release
uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2
with:
token: ${{ steps.app-token.outputs.token }}
branch: ${{ github.event.inputs.branch }}
release_url: ${{ github.event.inputs.release_url }}
steps_to_skip: ${{ github.event.inputs.steps_to_skip }}
- name: Finalize Release
id: finalize-release
uses: jupyter-server/jupyter_releaser/.github/actions/finalize-release@v2
with:
token: ${{ steps.app-token.outputs.token }}
release_url: ${{ steps.populate-release.outputs.release_url }}
- name: "** Next Step **"
if: ${{ success() }}
run: |
echo "Verify the final release"
echo ${{ steps.finalize-release.outputs.release_url }}
- name: "** Failure Message **"
if: ${{ failure() }}
run: |
echo "Failed to Publish the Draft Release Url:"
echo ${{ steps.populate-release.outputs.release_url }}
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Autogenerated docs
docs/reference/config_options.rst
docs/changelog.md
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
docs/changelog.md
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
Pipfile
Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# Pycharm stuff
.idea/
# VSCode
.vscode
================================================
FILE: .pre-commit-config.yaml
================================================
ci:
autoupdate_schedule: monthly
autoupdate_commit_msg: "chore: update pre-commit hooks"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-case-conflict
- id: check-ast
- id: check-docstring-first
- id: check-executables-have-shebangs
- id: check-added-large-files
- id: check-case-conflict
- id: check-merge-conflict
- id: check-json
- id: check-toml
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.27.4
hooks:
- id: check-github-workflows
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.17
hooks:
- id: mdformat
additional_dependencies:
[mdformat-gfm, mdformat-frontmatter, mdformat-footnote]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v4.0.0-alpha.8"
hooks:
- id: prettier
types_or: [yaml, html, json]
- repo: https://github.com/adamchainz/blacken-docs
rev: "1.16.0"
hooks:
- id: blacken-docs
additional_dependencies: [black==23.7.0]
- repo: https://github.com/codespell-project/codespell
rev: "v2.2.6"
hooks:
- id: codespell
args: ["-L", "sur,nd"]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: "v1.10.0"
hooks:
- id: rst-backticks
- id: rst-directive-colons
- id: rst-inline-touching-normal
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.19.0"
hooks:
- id: mypy
files: "^nbclient"
stages: [manual]
args: ["--install-types", "--non-interactive"]
additional_dependencies:
[
"traitlets>=5.13",
"jupyter_core>=5.3.2",
"jupyter_client",
"nbformat",
]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.0
hooks:
- id: ruff
types_or: [python, jupyter]
args: ["--fix", "--show-fixes"]
exclude: "^tests/files/.*.ipynb"
- id: ruff-format
types_or: [python, jupyter]
exclude: "^tests/files/.*.ipynb"
- repo: https://github.com/scientific-python/cookie
rev: "2024.01.24"
hooks:
- id: sp-repo-review
additional_dependencies: ["repo-review[cli]"]
================================================
FILE: .readthedocs.yml
================================================
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
sphinx:
configuration: docs/conf.py
formats: all
python:
install:
- method: pip
path: .
extra_requirements:
- docs
build:
os: ubuntu-22.04
tools:
python: "3.11"
================================================
FILE: CHANGELOG.md
================================================
# Changes in NBClient {#changelog}
<!-- <START NEW CHANGELOG ENTRY> -->
## 0.10.4
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.10.3...af9b77a952b78b2bd548945471114315d202afbf))
### Merged PRs
- Allow `display_id` to be `None` [#338](https://github.com/jupyter/nbclient/pull/338) ([@davidbrochart](https://github.com/davidbrochart), [@YannickJadoul](https://github.com/YannickJadoul), [@slayoo](https://github.com/slayoo))
### Contributors to this release
The following people contributed discussions, new ideas, code and documentation contributions, and review.
See [our definition of contributors](https://github-activity.readthedocs.io/en/latest/#how-does-this-tool-define-contributions-in-the-reports).
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2025-12-19&to=2025-12-23&type=c))
@davidbrochart ([activity](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2025-12-19..2025-12-23&type=Issues)) | @slayoo ([activity](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Aslayoo+updated%3A2025-12-19..2025-12-23&type=Issues)) | @YannickJadoul ([activity](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3AYannickJadoul+updated%3A2025-12-19..2025-12-23&type=Issues))
<!-- <END NEW CHANGELOG ENTRY> -->
## 0.10.3
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.10.2...b42ad03acc0bb1ed26db65ab72ac617679cbbb62))
### Merged PRs
- Drop Python 3.9, test 3.14 and pypy-3.11 [#337](https://github.com/jupyter/nbclient/pull/337) ([@davidbrochart](https://github.com/davidbrochart))
- correct execution count in test for ipython 9.8 and above [#335](https://github.com/jupyter/nbclient/pull/335) ([@drorspei](https://github.com/drorspei), [@davidbrochart](https://github.com/davidbrochart))
- Update contribution with pytest instructions, remove tox. [#331](https://github.com/jupyter/nbclient/pull/331) ([@dgrahn](https://github.com/dgrahn), [@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
The following people contributed discussions, new ideas, code and documentation contributions, and review.
See [our definition of contributors](https://github-activity.readthedocs.io/en/latest/#how-does-this-tool-define-contributions-in-the-reports).
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2024-12-19&to=2025-12-19&type=c))
@davidbrochart ([activity](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2024-12-19..2025-12-19&type=Issues)) | @dgrahn ([activity](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adgrahn+updated%3A2024-12-19..2025-12-19&type=Issues)) | @drorspei ([activity](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adrorspei+updated%3A2024-12-19..2025-12-19&type=Issues))
## 0.10.2
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.10.1...5a68cb361412d540e23fbc444cda75ede73c16d1))
### Merged PRs
- Drop Python 3.8, test PyPy 3.10 [#323](https://github.com/jupyter/nbclient/pull/323) ([@davidbrochart](https://github.com/davidbrochart))
- Gracefully handle explicit transient=None [#322](https://github.com/jupyter/nbclient/pull/322) ([@callmephilip](https://github.com/callmephilip))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2024-11-29&to=2024-12-19&type=c))
[@callmephilip](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Acallmephilip+updated%3A2024-11-29..2024-12-19&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2024-11-29..2024-12-19&type=Issues)
## 0.10.1
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.10.0...e6df5842d471047afcb45595d95a39be549896e4))
### Maintenance and upkeep improvements
- Run docs on ubuntu [#314](https://github.com/jupyter/nbclient/pull/314) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
- avoid deprecation warning for py313 [#320](https://github.com/jupyter/nbclient/pull/320) ([@lucascolley](https://github.com/lucascolley))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2024-03-13&to=2024-11-29&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2024-03-13..2024-11-29&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2024-03-13..2024-11-29&type=Issues) | [@lucascolley](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Alucascolley+updated%3A2024-03-13..2024-11-29&type=Issues)
## 0.10.0
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.9.1...3286ae09f41d04fd3354519582750775abc034e5))
### Enhancements made
- Optionally write out executed notebook in jupyter-execute [#307](https://github.com/jupyter/nbclient/pull/307) ([@wpk-nist-gov](https://github.com/wpk-nist-gov))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2024-03-12&to=2024-03-12&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2024-03-12..2024-03-12&type=Issues) | [@wpk-nist-gov](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Awpk-nist-gov+updated%3A2024-03-12..2024-03-12&type=Issues)
## 0.9.1
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.9.0...6f6aa8cb1a853c81975fcc48fa5cfcc3d37bcddd))
### Maintenance and upkeep improvements
- Update Release Scripts [#309](https://github.com/jupyter/nbclient/pull/309) ([@blink1073](https://github.com/blink1073))
- Pin to Pytest 7 [#308](https://github.com/jupyter/nbclient/pull/308) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
- chore: update pre-commit hooks [#305](https://github.com/jupyter/nbclient/pull/305) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- chore: update pre-commit hooks [#304](https://github.com/jupyter/nbclient/pull/304) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- chore: update pre-commit hooks [#303](https://github.com/jupyter/nbclient/pull/303) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Bump actions/checkout from 3 to 4 [#302](https://github.com/jupyter/nbclient/pull/302) ([@dependabot](https://github.com/dependabot))
- chore: update pre-commit hooks [#300](https://github.com/jupyter/nbclient/pull/300) ([@pre-commit-ci](https://github.com/pre-commit-ci))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2023-11-07&to=2024-03-12&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2023-11-07..2024-03-12&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adependabot+updated%3A2023-11-07..2024-03-12&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2023-11-07..2024-03-12&type=Issues)
## 0.9.0
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.8.0...31cf1e751935628b2ce8b88b7c00e5b53e9dcfd6))
### Maintenance and upkeep improvements
- Use jupyter releaser [#301](https://github.com/jupyter/nbclient/pull/301) ([@blink1073](https://github.com/blink1073))
- Clean up lint and move tests out of source [#299](https://github.com/jupyter/nbclient/pull/299) ([@blink1073](https://github.com/blink1073))
- Adopt ruff format [#298](https://github.com/jupyter/nbclient/pull/298) ([@blink1073](https://github.com/blink1073))
- Update typings for mypy 1.6 [#297](https://github.com/jupyter/nbclient/pull/297) ([@blink1073](https://github.com/blink1073))
- Adopt sp-repo-review [#295](https://github.com/jupyter/nbclient/pull/295) ([@blink1073](https://github.com/blink1073))
- Fix lint error [#289](https://github.com/jupyter/nbclient/pull/289) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
- Bump actions/checkout from 3 to 4 [#293](https://github.com/jupyter/nbclient/pull/293) ([@dependabot](https://github.com/dependabot))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2023-05-22&to=2023-11-07&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2023-05-22..2023-11-07&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adependabot+updated%3A2023-05-22..2023-11-07&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2023-05-22..2023-11-07&type=Issues)
## 0.8.0
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.7.4...cb7b4f7f409bbd06d55cc339afdcdea79da0e199))
### Maintenance and upkeep improvements
- Bump min version support [#287](https://github.com/jupyter/nbclient/pull/287) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
- Bump actions/checkout from 2 to 3 [#275](https://github.com/jupyter/nbclient/pull/275) ([@dependabot](https://github.com/dependabot))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2023-04-25&to=2023-05-22&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2023-04-25..2023-05-22&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adependabot+updated%3A2023-04-25..2023-05-22&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2023-04-25..2023-05-22&type=Issues)
## 0.7.4
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.7.3...20b7d4b6eef33ccd1bbd8d346a7a75522ac67d75))
### Enhancements made
- include stream output in CellExecutionError [#282](https://github.com/jupyter/nbclient/pull/282) ([@minrk](https://github.com/minrk))
### Bugs fixed
- avoid duplicate 'Exception: message' in CellExecutionError [#283](https://github.com/jupyter/nbclient/pull/283) ([@minrk](https://github.com/minrk))
### Maintenance and upkeep improvements
- Use local coverage [#281](https://github.com/jupyter/nbclient/pull/281) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
- Send KeyboardInterrupt a little later in test_run_all_notebooks\[Interrupt.ipynb-opts6\] [#285](https://github.com/jupyter/nbclient/pull/285) ([@kxxt](https://github.com/kxxt))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2023-04-03&to=2023-04-25&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2023-04-03..2023-04-25&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2023-04-03..2023-04-25&type=Issues) | [@kxxt](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Akxxt+updated%3A2023-04-03..2023-04-25&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Aminrk+updated%3A2023-04-03..2023-04-25&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2023-04-03..2023-04-25&type=Issues)
## 0.7.3
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.7.2...aa62bc79274d264e9b9d70a139c9506a740b5d77))
### Maintenance and upkeep improvements
- Fix test stability [#276](https://github.com/jupyter/nbclient/pull/276) ([@blink1073](https://github.com/blink1073))
- Clean up license [#274](https://github.com/jupyter/nbclient/pull/274) ([@dcsaba89](https://github.com/dcsaba89))
- Update codecov link [#271](https://github.com/jupyter/nbclient/pull/271) ([@blink1073](https://github.com/blink1073))
- Add spelling and docstring enforcement [#269](https://github.com/jupyter/nbclient/pull/269) ([@blink1073](https://github.com/blink1073))
- Adopt ruff and address lint [#267](https://github.com/jupyter/nbclient/pull/267) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
- Add coalesce_streams [#279](https://github.com/jupyter/nbclient/pull/279) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-11-29&to=2023-04-03&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2022-11-29..2023-04-03&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-11-29..2023-04-03&type=Issues) | [@dcsaba89](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adcsaba89+updated%3A2022-11-29..2023-04-03&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2022-11-29..2023-04-03&type=Issues)
## 0.7.2
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.7.1...e6f8b9f7001f9988a29bb011a0f6052987e6507a))
### Merged PRs
- Allow space after In [#264](https://github.com/jupyter/nbclient/pull/264) ([@davidbrochart](https://github.com/davidbrochart))
- Fix jupyter_core pinning [#263](https://github.com/jupyter/nbclient/pull/263) ([@davidbrochart](https://github.com/davidbrochart))
- Update README, add Python 3.11 [#260](https://github.com/jupyter/nbclient/pull/260) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-11-29&to=2022-11-29&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-11-29..2022-11-29&type=Issues)
## 0.7.1
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.7.0...168340e8313e63fd9e037280f98ed22d47e2231b))
### Maintenance and upkeep improvements
- CI Refactor [#257](https://github.com/jupyter/nbclient/pull/257) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
- Remove nest-asyncio [#259](https://github.com/jupyter/nbclient/pull/259) ([@davidbrochart](https://github.com/davidbrochart))
- Add upper bound to dependencies [#258](https://github.com/jupyter/nbclient/pull/258) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-10-06&to=2022-11-29&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2022-10-06..2022-11-29&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-10-06..2022-11-29&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2022-10-06..2022-11-29&type=Issues)
## 0.7.0
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.8...449f17d0374f43694d2203d216c97dd4ac7f2c0e))
### Maintenance and upkeep improvements
- Cleanup CI [#254](https://github.com/jupyter/nbclient/pull/254) ([@blink1073](https://github.com/blink1073))
- Handle client 8 support [#253](https://github.com/jupyter/nbclient/pull/253) ([@blink1073](https://github.com/blink1073))
### Other merged PRs
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-09-09&to=2022-10-06&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2022-09-09..2022-10-06&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2022-09-09..2022-10-06&type=Issues)
## 0.6.8
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.7...f7d72b2c6937fc30add18b7413f89b691d1710be))
### Merged PRs
- Fix tests compatibility with IPython 8.5.0 [#251](https://github.com/jupyter/nbclient/pull/251) ([@frenzymadness](https://github.com/frenzymadness))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-08-23&to=2022-09-09&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-08-23..2022-09-09&type=Issues) | [@frenzymadness](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Afrenzymadness+updated%3A2022-08-23..2022-09-09&type=Issues)
## 0.6.7
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.6...979fb908dc133cc80a698c74d9b3d9d8af6c7bde))
### Merged PRs
- Fix tests for ipywidgets 8 [#246](https://github.com/jupyter/nbclient/pull/246) ([@frenzymadness](https://github.com/frenzymadness))
- \[pre-commit.ci\] pre-commit autoupdate [#236](https://github.com/jupyter/nbclient/pull/236) ([@pre-commit-ci](https://github.com/pre-commit-ci))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-07-01&to=2022-08-23&type=c))
[@frenzymadness](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Afrenzymadness+updated%3A2022-07-01..2022-08-23&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2022-07-01..2022-08-23&type=Issues)
## 0.6.6
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.5...b4a7cebf0238d4fbe814e19afbee8df3f610e80d))
### Merged PRs
- Start new client if needed in blocking setup_kernel [#241](https://github.com/jupyter/nbclient/pull/241) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-06-30&to=2022-07-01&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-06-30..2022-07-01&type=Issues)
## 0.6.5
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.4...6aed8bec58d69004d3b6687c8bf589f175630f8d))
### Merged PRs
- Start new client if needed [#239](https://github.com/jupyter/nbclient/pull/239) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-05-31&to=2022-06-30&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-05-31..2022-06-30&type=Issues)
## 0.6.4
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.3...01465b8d8597efa81f54f713ad3944fe963ab453))
### Merged PRs
- Make sure kernel is cleaned up in case an error occurred while starting kernel client [#234](https://github.com/jupyter/nbclient/pull/234) ([@CiprianAnton](https://github.com/CiprianAnton))
- Suppress most warnings in tests [#232](https://github.com/jupyter/nbclient/pull/232) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-05-09&to=2022-05-31&type=c))
[@CiprianAnton](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3ACiprianAnton+updated%3A2022-05-09..2022-05-31&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-05-09..2022-05-31&type=Issues)
## 0.6.3
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.2...61d36ce423b00231833c737f59041f33d72a7bb3))
### Bugs fixed
- Clean up docs and typings [#230](https://github.com/jupyter/nbclient/pull/230) ([@blink1073](https://github.com/blink1073))
### Documentation improvements
- Clean up docs and typings [#230](https://github.com/jupyter/nbclient/pull/230) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-05-03&to=2022-05-09&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2022-05-03..2022-05-09&type=Issues) | [@chrisjsewell](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Achrisjsewell+updated%3A2022-05-03..2022-05-09&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-05-03..2022-05-09&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ameeseeksmachine+updated%3A2022-05-03..2022-05-09&type=Issues)
## 0.6.2
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.1...bd36f50a299fb2e0656386ec487c2bbc67a9a1c4))
### Merged PRs
- Fix documentation generation [#228](https://github.com/jupyter/nbclient/pull/228) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-05-03&to=2022-05-03&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-05-03..2022-05-03&type=Issues)
## 0.6.1
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.6.0...571a65faa7b86bb647567373a529d9d8df38dd2f))
### Merged PRs
- \[pre-commit.ci\] pre-commit autoupdate [#225](https://github.com/jupyter/nbclient/pull/225) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Add error_on_interrupt trait [#224](https://github.com/jupyter/nbclient/pull/224) ([@davidbrochart](https://github.com/davidbrochart))
- Fix typo [#223](https://github.com/jupyter/nbclient/pull/223) ([@davidbrochart](https://github.com/davidbrochart))
- Add on_cell_executed hook [#222](https://github.com/jupyter/nbclient/pull/222) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-04-12&to=2022-05-03&type=c))
[@brichet](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Abrichet+updated%3A2022-04-12..2022-05-03&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-04-12..2022-05-03&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Apre-commit-ci+updated%3A2022-04-12..2022-05-03&type=Issues)
## 0.6.0
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.5.13...295e0eee4a6b9c5c0ee0d490b4c4058a95c6cb79))
### Maintenance and upkeep improvements
- Fix typings and update mypy settings [#220](https://github.com/jupyter/nbclient/pull/220) ([@blink1073](https://github.com/blink1073))
- Add missing dep on testpath [#219](https://github.com/jupyter/nbclient/pull/219) ([@blink1073](https://github.com/blink1073))
- Add more pre-commit hooks and update flake8 [#218](https://github.com/jupyter/nbclient/pull/218) ([@blink1073](https://github.com/blink1073))
### Documentation improvements
- Clean up docs handling [#216](https://github.com/jupyter/nbclient/pull/216) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-03-11&to=2022-04-12&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Ablink1073+updated%3A2022-03-11..2022-04-12&type=Issues)
## 0.5.13
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.5.12...af2315aefbd8d08c1d6a473c289beef1e8ebbecb))
### Merged PRs
- Drop ipython_genutils [#209](https://github.com/jupyter/nbclient/pull/209) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-03-06&to=2022-03-11&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-03-06..2022-03-11&type=Issues)
## 0.5.12
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.5.11...d20e29e803e5a22379f7a1356e7cf55d4649e9cb))
### Merged PRs
- Require traitlets>=5.0.0 [#204](https://github.com/jupyter/nbclient/pull/204) ([@davidbrochart](https://github.com/davidbrochart))
- Extend the ignored part of IPython outputs [#202](https://github.com/jupyter/nbclient/pull/202) ([@frenzymadness](https://github.com/frenzymadness))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-02-14&to=2022-03-06&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-02-14..2022-03-06&type=Issues) | [@frenzymadness](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Afrenzymadness+updated%3A2022-02-14..2022-03-06&type=Issues)
## 0.5.11
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.5.10...050c7da89a98159e6361b1ad0dbefd215db5f816))
### Merged PRs
- Pin ipython\<8 in tests [#198](https://github.com/jupyter/nbclient/pull/198) ([@davidbrochart](https://github.com/davidbrochart))
- Clear execution metadata, prefer msg header date when recording times [#195](https://github.com/jupyter/nbclient/pull/195) ([@kevin-bates](https://github.com/kevin-bates))
- Client hooks [#188](https://github.com/jupyter/nbclient/pull/188) ([@devintang3](https://github.com/devintang3))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2022-01-13&to=2022-02-14&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2022-01-13..2022-02-14&type=Issues) | [@devintang3](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adevintang3+updated%3A2022-01-13..2022-02-14&type=Issues) | [@kevin-bates](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Akevin-bates+updated%3A2022-01-13..2022-02-14&type=Issues)
## 0.5.10
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.5.9...e82c5d8d064ac1097f4e12f387b4c47ea5c576ff))
### Merged PRs
- Fix ipywidgets version in tests [#192](https://github.com/jupyter/nbclient/pull/192) ([@martinRenou](https://github.com/martinRenou))
- Compatibility with IPython 8 where tracebacks are different [#190](https://github.com/jupyter/nbclient/pull/190) ([@frenzymadness](https://github.com/frenzymadness))
- Drop tox [#187](https://github.com/jupyter/nbclient/pull/187) ([@davidbrochart](https://github.com/davidbrochart))
- Update README [#185](https://github.com/jupyter/nbclient/pull/185) ([@davidbrochart](https://github.com/davidbrochart))
- Drop python3.6, test python3.10 [#184](https://github.com/jupyter/nbclient/pull/184) ([@davidbrochart](https://github.com/davidbrochart))
- Fix typos [#182](https://github.com/jupyter/nbclient/pull/182) ([@kianmeng](https://github.com/kianmeng))
- Use codecov Github action v2 [#168](https://github.com/jupyter/nbclient/pull/168) ([@takluyver](https://github.com/takluyver))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2021-11-19&to=2022-01-13&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2021-11-19..2022-01-13&type=Issues) | [@frenzymadness](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Afrenzymadness+updated%3A2021-11-19..2022-01-13&type=Issues) | [@kianmeng](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Akianmeng+updated%3A2021-11-19..2022-01-13&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3AmartinRenou+updated%3A2021-11-19..2022-01-13&type=Issues) | [@takluyver](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Atakluyver+updated%3A2021-11-19..2022-01-13&type=Issues)
## 0.5.9
([Full Changelog](https://github.com/jupyter/nbclient/compare/v0.5.8...0146681d7ffd62cbc675c8d1463a2b016a3d3008))
### Merged PRs
- Remove jupyter-run, keep jupyter-execute [#180](https://github.com/jupyter/nbclient/pull/180) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2021-11-12&to=2021-11-19&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2021-11-12..2021-11-19&type=Issues)
## 0.5.8
No merged PRs
## 0.5.7
([Full Changelog](https://github.com/jupyter/nbclient/compare/0.5.6...d86c404536fb443898b631acaf29ce7ad88b06d9))
### Merged PRs
- Prepare for use with Jupyter Releaser [#175](https://github.com/jupyter/nbclient/pull/175) ([@davidbrochart](https://github.com/davidbrochart))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter/nbclient/graphs/contributors?from=2021-11-12&to=2021-11-12&type=c))
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fnbclient+involves%3Adavidbrochart+updated%3A2021-11-12..2021-11-12&type=Issues)
## 0.5.6
- Changed `jupyter execute` to `jupyter run` [#173](https://github.com/jupyter/nbclient/pull/173) ([@palewire](https://github.com/palewire))
- Move IPYKERNEL_CELL_NAME from tox to pytest [#172](https://github.com/jupyter/nbclient/pull/172) ([@frenzymadness](https://github.com/frenzymadness))
## 0.5.5
- Added CLI to README [#170](https://github.com/jupyter/nbclient/pull/170) ([@palewire](https://github.com/palewire))
- Add "jupyter execute" command-line interface [#165](https://github.com/jupyter/nbclient/pull/165) ([@palewire](https://github.com/palewire))
- Fix: updating buffers overwrote previous buffers [#169](https://github.com/jupyter/nbclient/pull/169) ([@maartenbreddels](https://github.com/maartenbreddels))
- Fix tests for ipykernel without debugpy [#166](https://github.com/jupyter/nbclient/pull/166) ([@frenzymadness](https://github.com/frenzymadness))
- gitignore Pipfile [#164](https://github.com/jupyter/nbclient/pull/164) ([@palewire](https://github.com/palewire))
- Fixed CONTRIBUTING.md link [#163](https://github.com/jupyter/nbclient/pull/163) ([@palewire](https://github.com/palewire))
- Fix typo [#162](https://github.com/jupyter/nbclient/pull/162) ([@The-Compiler](https://github.com/The-Compiler))
- Move format & lint to pre-commit [#161](https://github.com/jupyter/nbclient/pull/161) ([@chrisjsewell](https://github.com/chrisjsewell))
- Add `skip-execution` cell tag functionality [#151](https://github.com/jupyter/nbclient/pull/151) ([@chrisjsewell](https://github.com/chrisjsewell))
## 0.5.4
- Replace `km.cleanup` with `km.cleanup_resources` [#152](https://github.com/jupyter/nbclient/pull/152) ([@davidbrochart](https://github.com/davidbrochart))
- Use async generator backport only on old python [#154](https://github.com/jupyter/nbclient/pull/154) ([@mkoeppe](https://github.com/mkoeppe))
- Support parsing of IPython dev version [#150](https://github.com/jupyter/nbclient/pull/150) ([@cphyc](https://github.com/cphyc))
- Set `IPYKERNEL_CELL_NAME = <IPY-INPUT>` [#147](https://github.com/jupyter/nbclient/pull/147) ([@davidbrochart](https://github.com/davidbrochart))
- Print useful error message on exception [#142](https://github.com/jupyter/nbclient/pull/142) ([@certik](https://github.com/certik))
## 0.5.3
- Fix ipykernel's `stop_on_error` value to take into account `raises-exception` tag and `force_raise_errors` [#137](https://github.com/jupyter/nbclient/pull/137)
## 0.5.2
- Set minimum python version supported to 3.6.1 to avoid 3.6.0 issues
- CellExecutionError is now unpickleable
- Added testing for python 3.9
- Changed travis tests to github actions
- Documentation referencing an old model instead of NotebookClient was fixed
- `allow_error_names` option was added for a more specific scope of `allow_errors` to be applied
## 0.5.1
- Update kernel client class JIT if it's the synchronous version
- Several documentation fixes / improvements
## 0.5.0
- Move `language_info` retrieval before cell execution [#102](https://github.com/jupyter/nbclient/pull/102)
- HistoryManager setting for ipython kernels no longer applies twice (fix for 5.0 trailets release)
- Improved error handling around language_info missing
- `(async_)start_new_kernel_client` is now split into `(async_)start_new_kernel` and `(async_)start_new_kernel_client`
## 0.4.2 - 0.4.3
These patch releases were removed due to backwards incompatible changes that should have been a minor release.
If you were using these versions for the couple days they were up, move to 0.5.0 and you shouldn't have any issues.
## 0.4.1
- Python type hinting added to most interfaces! [#83](https://github.com/jupyter/nbclient/pull/83)
- Several documentation fixes and improvements were made [#86](https://github.com/jupyter/nbclient/pull/86)
- An asynchronous heart beat check was added to correctly raise a DeadKernelError when kernels die unexpectantly [#90](https://github.com/jupyter/nbclient/pull/90)
## 0.4.0
### Major Changes
- Use KernelManager's graceful shutdown rather than KILLing kernels [#64](https://github.com/jupyter/nbclient/pull/64)
- Mimic an Output widget at the frontend so that the Output widget behaves correctly [#68](https://github.com/jupyter/nbclient/pull/68)
- Nested asyncio is automatic, and works with Tornado [#71](https://github.com/jupyter/nbclient/pull/71)
- `async_execute` now has a `reset_kc` argument to control if the client is reset upon execution request [#53](https://github.com/jupyter/nbclient/pull/53)
### Fixes
- Fix `OSError: [WinError 6] The handle is invalid` for windows/python\<3.7 [#77](https://github.com/jupyter/nbclient/pull/77)
- Async wrapper Exceptions no longer loose their caused exception information [#65](https://github.com/jupyter/nbclient/pull/65)
- `extra_arguments` are now configurable by config settings [#66](https://github.com/jupyter/nbclient/pull/66)
### Operational
- Cross-OS testing now run on PRs via Github Actions [#63](https://github.com/jupyter/nbclient/pull/63)
## 0.3.1
### Fixes
- Check that a kernel manager exists before cleaning up the kernel [#61](https://github.com/jupyter/nbclient/pull/61)
- Force client class to be async when kernel manager is MultiKernelManager [#55](https://github.com/jupyter/nbclient/pull/55)
- Replace pip install with conda install in Binder [#54](https://github.com/jupyter/nbclient/pull/54)
## 0.3.0
### Major Changes
- The `(async_)start_new_kernel_client` method now supports starting a new client when its kernel manager (`self.km`) is a `MultiKernelManager`. The method now returns the kernel id in addition to the kernel client. If the kernel manager was a `KernelManager`, the returned kernel id is `None`. [#51](https://github.com/jupyter/nbclient/pull/51)
- Added sphinx-book-theme for documentation. Added a CircleCI job to let us preview the built documentation in a PR. [#50](https://github.com/jupyter/nbclient/pull/50)
- Added `reset_kc` option to `reset_execution_trackers`, so that the kernel client can be reset and a new one created in calls to `(async_)execute` [#44](https://github.com/jupyter/nbclient/pull/44)
### Docs
- Fixed documentation [#46](https://github.com/jupyter/nbclient/pull/46) [#47](https://github.com/jupyter/nbclient/pull/47)
- Added documentation status badge to the README
- Removed conda from documentation build
## 0.2.0
### Major Changes
- Async support is now available on the client. Methods that support async have an `async_` prefix and can be awaited [#10](https://github.com/jupyter/nbclient/pull/10) [#35](https://github.com/jupyter/nbclient/pull/35) [#37](https://github.com/jupyter/nbclient/pull/37) [#38](https://github.com/jupyter/nbclient/pull/38)
- Dropped support for Python 3.5 due to async compatibility issues [#34](https://github.com/jupyter/nbclient/pull/34)
- Notebook documents now include the [new kernel timing fields](https://github.com/jupyter/nbformat/pull/144) [#32](https://github.com/jupyter/nbclient/pull/32)
### Fixes
- Memory and process leaks from nbclient should now be fixed [#34](https://github.com/jupyter/nbclient/pull/34)
- Notebook execution exceptions now include error information in addition to the message [#41](https://github.com/jupyter/nbclient/pull/41)
### Docs
- Added [binder examples](https://mybinder.org/v2/gh/jupyter/nbclient/master?filepath=binder%2Frun_nbclient.ipynb) / tests [#7](https://github.com/jupyter/nbclient/pull/7)
- Added changelog to docs [#22](https://github.com/jupyter/nbclient/pull/22)
- Doc typo fixes [#27](https://github.com/jupyter/nbclient/pull/27) [#30](https://github.com/jupyter/nbclient/pull/30)
## 0.1.0
- Initial release -- moved out of nbconvert 6.0.0-a0
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
We follow the [Jupyter Contribution Workflow](https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html) and the [IPython Contributing Guide](https://github.com/ipython/ipython/blob/master/CONTRIBUTING.md).
## Code formatting
Use the [pre-commit](https://pre-commit.com/) tool to format and lint the codebase:
```console
# to apply to only staged files
$ pre-commit run
# to run against all files
$ pre-commit run --all-files
# to install so that it is run before commits
$ pre-commit install
```
## Testing
Tests can be run through [`hatch`](https://hatch.pypa.io/) which will automatically manage test environments and dependencies.
```console
# to run all tests
$ hatch run test:test
# to run with coverage (used by CI)
$ hatch run cov:test
```
## Documentation
NbClient needs some PRs to copy over documentation!
## Releasing
If you are going to release a version of `nbclient` you should also be capable
of testing it and building the docs.
Please follow the instructions in [Testing](#testing) and [Documentation](#documentation) if
you are unfamiliar with how to do so.
The rest of the release process can be found in [these release instructions](./RELEASING.md).
================================================
FILE: LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2020-, Jupyter Development Team
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
[](https://mybinder.org/v2/gh/jupyter/nbclient/main?filepath=binder%2Frun_nbclient.ipynb)
[](https://github.com/jupyter/nbclient/actions)
[](https://nbclient.readthedocs.io/en/latest/?badge=latest)
[](https://www.python.org/downloads/release/python-370/)
[](https://www.python.org/downloads/release/python-380/)
[](https://www.python.org/downloads/release/python-390/)
[](https://www.python.org/downloads/release/python-3100/)
[](https://www.python.org/downloads/release/python-3110/)
[](https://github.com/ambv/black)
# nbclient
**NBClient** lets you **execute** notebooks.
A client library for programmatic notebook execution, **NBClient** is a tool for running Jupyter Notebooks in
different execution contexts, including the command line.
## Interactive Demo
To demo **NBClient** interactively, click this Binder badge to start the demo:
[](https://mybinder.org/v2/gh/jupyter/nbclient/main?filepath=binder%2Frun_nbclient.ipynb)
## Installation
In a terminal, run:
```
python3 -m pip install nbclient
```
## Documentation
See [ReadTheDocs](https://nbclient.readthedocs.io/en/latest/) for more in-depth details about the project and the
[API Reference](https://nbclient.readthedocs.io/en/latest/reference/index.html).
## Python Version Support
This library currently supports Python 3.6+ versions. As minor Python
versions are officially sunset by the Python org, nbclient will similarly
drop support in the future.
## Origins
This library used to be part of the [nbconvert](https://nbconvert.readthedocs.io/en/latest/) project. NBClient extracted nbconvert's `ExecutePreprocessor`into its own library for easier updating and importing by downstream libraries and applications.
## Relationship to JupyterClient
NBClient and JupyterClient are distinct projects.
`jupyter_client` is a client library for the jupyter protocol. Specifically, `jupyter_client` provides the Python API
for starting, managing and communicating with Jupyter kernels.
While, nbclient allows notebooks to be run in different execution contexts.
## About the Jupyter Development Team
The Jupyter Development Team is the set of all contributors to the Jupyter project.
This includes all of the Jupyter subprojects.
The core team that coordinates development on GitHub can be found here:
https://github.com/jupyter/.
## Our Copyright Policy
Jupyter uses a shared copyright model. Each contributor maintains copyright
over their contributions to Jupyter. But, it is important to note that these
contributions are typically only changes to the repositories. Thus, the Jupyter
source code, in its entirety is not the copyright of any single person or
institution. Instead, it is the collective copyright of the entire Jupyter
Development Team. If individual contributors want to maintain a record of what
changes/contributions they have specific copyright on, they should indicate
their copyright in the commit message of the change, when they commit the
change to one of the Jupyter repositories.
With this in mind, the following banner should be used in any source code file
to indicate the copyright and license terms:
```
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
```
================================================
FILE: RELEASING.md
================================================
# Releasing
## Using `jupyter_releaser`
The recommended way to make a release is to use [`jupyter_releaser`](https://github.com/jupyter-server/jupyter_releaser#checklist-for-adoption).
## Manual Release
### Prerequisites
- First check that the CHANGELOG.md is up to date for the next release version
- Install packaging requirements: `pip install tbump build tomlkit==0.7.0`
### Bump version
- `export version=<NEW_VERSION>`
- `tbump ${version} --no-push`
### Push to GitHub
```bash
git push upstream && git push upstream --tags
```
### Push to PyPI
```bash
rm -rf dist/*
rm -rf build/*
python -m build .
twine upload dist/*
```
================================================
FILE: binder/empty_notebook.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Show a pandas dataframe"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import scrapbook as sb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"data = pd.DataFrame(np.random.randn(20, 2), columns=[\"a\", \"b\"])\n",
"data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Use scrapbook to store this data in the notebook\n",
"sb.glue(\"dataframe\", data.to_dict())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Make a matplotlib plot"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Make and display a plot\n",
"fig, ax = plt.subplots()\n",
"ax.scatter(data[\"a\"], data[\"b\"])\n",
"sb.glue(\"plot\", fig, \"display\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: binder/environment.yml
================================================
name: nbclient
channels:
- conda-forge
dependencies:
- numpy
- pandas
- matplotlib
- scrapbook
- nbformat
- nbclient
================================================
FILE: binder/run_nbclient.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import nbformat as nbf\n",
"import pandas as pd\n",
"import scrapbook as sb\n",
"\n",
"import nbclient"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Background\n",
"\n",
"This notebook uses `nbclient` to read and execute an *empty* notebook.\n",
"The empty notebook generates some fake data, makes a plot, and stores\n",
"both the data and the plot inside the notebook using the\n",
"[scrapbook package](https://github.com/nteract/scrapbook). We will\n",
"then be able to access the generated contents of the notebook here.\n",
"\n",
"You can see the empty notebook by clicking this button:\n",
"\n",
"<a href=\"empty_notebook.ipynb\"><button>Empty notebook</button></a>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Read and execute the empty notebook"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# We use nbformat to represent our empty notebook in-memory\n",
"nb = nbf.read(\"./empty_notebook.ipynb\", nbf.NO_CONVERT)\n",
"\n",
"# Execute our in-memory notebook, which will now have outputs\n",
"nb = nbclient.execute(nb)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Inspect the new notebook for its contents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# First we'll convert our nbformat NotebokNote into a *scrapbook* NotebookNode\n",
"nb = sb.read_notebook(nb)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# We can access the dataframe that was created and glued into the empty notebook\n",
"pd.DataFrame.from_dict(nb.scraps.get(\"dataframe\").data).head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# We can also access the generated plot by \"re-gluing\" the notebook here\n",
"nb.reglue(\"plot\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: docs/Makefile
================================================
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = nbclient
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
================================================
FILE: docs/UPDATE.md
================================================
TODO: Figure out make options needed for non-api changes
```
sphinx-apidoc -f -o reference ../nbclient
```
================================================
FILE: docs/_static/custom.css
================================================
img.logo {
width:100%
}
.right-next {
float: right;
max-width: 45%;
overflow: auto;
text-overflow: ellipsis;
white-space: nowrap;
}
.right-next::after{
content: ' »';
}
.left-prev {
float: left;
max-width: 45%;
overflow: auto;
text-overflow: ellipsis;
white-space: nowrap;
}
.left-prev::before{
content: '« ';
}
.prev-next-bottom {
margin-top: 3em;
}
.prev-next-top {
margin-bottom: 1em;
}
================================================
FILE: docs/autogen_config.py
================================================
#!/usr/bin/env python
"""
autogen_config.py
Create config_options.rst, a Sphinx documentation source file.
Documents the options that may be set in nbconvert's configuration file,
jupyter_nbconvert_config.py.
"""
import os
import os.path
from nbclient.cli import NbClientApp
header = """\
.. This is an automatically generated file.
.. do not modify by hand.
.. _other-full-config:
Config file and command line options
====================================
Jupyter ``nbclient`` can be run with a variety of command line arguments.
A list of available options can be found below in the :ref:`options section
<options>`.
.. _options:
Options
-------
This list of options can be generated by running the following and hitting
enter::
$ jupyter execute --help-all
"""
try:
indir = os.path.dirname(__file__)
except NameError:
indir = os.getcwd()
destination = os.path.join(indir, "reference/config_options.rst")
with open(destination, "w") as f:
app = NbClientApp()
f.write(header)
f.write(app.document_config_options())
================================================
FILE: docs/client.rst
================================================
Executing notebooks
===================
.. module:: nbclient.client.guide
Jupyter notebooks are often saved with output cells that have been cleared.
NBClient provides a convenient way to execute the input cells of an
.ipynb notebook file and save the results, both input and output cells,
as a .ipynb file.
In this section we show how to execute a ``.ipynb`` notebook
document saving the result in notebook format. If you need to export
notebooks to other formats, such as reStructured Text or Markdown (optionally
executing them) see `nbconvert <https://nbconvert.readthedocs.io/en/latest/>`_.
Executing notebooks can be very helpful, for example, to run all notebooks
in Python library in one step, or as a way to automate the data analysis in
projects involving more than one notebook.
Using the Python API interface
------------------------------
This section will illustrate the Python API interface.
Example
~~~~~~~
Let's start with a complete quick example, leaving detailed explanations
to the following sections.
**Import**: First we import nbformat and the :class:`NotebookClient`
class::
import nbformat
from nbclient import NotebookClient
**Load**: Assuming that ``notebook_filename`` contains the path to a notebook,
we can load it with::
nb = nbformat.read(notebook_filename, as_version=4)
**Configure**: Next, we configure the notebook execution mode::
client = NotebookClient(nb, timeout=600, kernel_name='python3', resources={'metadata': {'path': 'notebooks/'}})
We specified two (optional) arguments ``timeout`` and ``kernel_name``, which
define respectively the cell execution timeout and the execution kernel.
Usually you don't need to set these options, but these and other options are
available to control execution context. Note that ``path`` specifies
in which folder to execute the notebook.
**Execute/Run**: To actually run the notebook we call the method
``execute``::
client.execute()
Hopefully, we will not get any errors during the notebook execution
(see the last section for error handling). This notebook will
now have its cell outputs populated with the result of running
each cell.
**Save**: Finally, save the resulting notebook with::
nbformat.write(nb, 'executed_notebook.ipynb')
That's all. Your executed notebook will be saved in the current folder
in the file ``executed_notebook.ipynb``.
Execution arguments (traitlets)
-------------------------------
The arguments passed to :class:`NotebookClient` are configuration options
called `traitlets <https://traitlets.readthedocs.io/en/stable>`_.
There are many cool things about traitlets. For example,
they enforce the input type, and they can be accessed/modified as
class attributes.
Let's now discuss in more detail the two traitlets we used.
The ``timeout`` traitlet defines the maximum time (in seconds) each notebook
cell is allowed to run, if the execution takes longer an exception will be
raised. The default is 30 s, so in cases of long-running cells you may want to
specify an higher value. The ``timeout`` option can also be set to ``None``
or ``-1`` to remove any restriction on execution time.
The second traitlet, ``kernel_name``, allows specifying the name of the kernel
to be used for the execution. By default, the kernel name is obtained from the
notebook metadata. The traitlet ``kernel_name`` allows specifying a
user-defined kernel, overriding the value in the notebook metadata. A common
use case is that of a Python 2/3 library which includes documentation/testing
notebooks. These notebooks will specify either a python2 or python3 kernel in
their metadata (depending on the kernel used the last time the notebook was
saved). In reality, these notebooks will work on both Python 2 and Python 3,
and, for testing, it is important to be able to execute them programmatically
on both versions. Here the traitlet ``kernel_name`` helps simplify and
maintain consistency: we can just run a notebook twice, specifying first
"python2" and then "python3" as the kernel name.
Hooks before and after notebook or cell execution
-------------------------------------------------
There are several configurable hooks that allow the user to execute code before and
after a notebook or a cell is executed. Each one is configured with a function that will be called in its
respective place in the execution pipeline.
Each is described below:
**Notebook-level hooks**: These hooks are called with a single extra parameter:
- ``notebook=NotebookNode``: the current notebook being executed.
Here is the available hooks:
- ``on_notebook_start`` will run when the notebook client is initialized, before any execution has happened.
- ``on_notebook_complete`` will run when the notebook client has finished executing, after kernel cleanup.
- ``on_notebook_error`` will run when the notebook client has encountered an exception before kernel cleanup.
**Cell-level hooks**: These hooks are called with at least two parameters:
- ``cell=NotebookNode``: a reference to the current cell.
- ``cell_index=int``: the index of the cell in the current notebook's list of cells.
Here are the available hooks:
- ``on_cell_start`` will run for all cell types before the cell is executed.
- ``on_cell_execute`` will run right before the code cell is executed.
- ``on_cell_complete`` will run after execution, if the cell is executed with no errors.
- ``on_cell_executed`` will run right after the code cell is executed.
- ``on_cell_error`` will run if there is an error during cell execution.
``on_cell_executed`` and ``on_cell_error`` are called with an extra parameter ``execute_reply=dict``.
Handling errors and exceptions
------------------------------
In the previous sections we saw how to save an executed notebook, assuming
there are no execution errors. But, what if there are errors?
Execution until first error
~~~~~~~~~~~~~~~~~~~~~~~~~~~
An error during the notebook execution, by default, will stop the execution
and raise a ``CellExecutionError``. Conveniently, the source cell causing
the error and the original error name and message are also printed.
After an error, we can still save the notebook as before::
nbformat.write(nb, 'executed_notebook.ipynb')
The saved notebook contains the output up until the failing cell,
and includes a full stack-trace and error (which can help debugging).
Handling errors
~~~~~~~~~~~~~~~
A useful pattern to execute notebooks while handling errors is the following::
from nbclient.exceptions import CellExecutionError
try:
client.execute()
except CellExecutionError:
msg = 'Error executing the notebook "%s".\n\n' % notebook_filename
msg += 'See notebook "%s" for the traceback.' % notebook_filename_out
print(msg)
raise
finally:
nbformat.write(nb, notebook_filename_out)
This will save the executed notebook regardless of execution errors.
In case of errors, however, an additional message is printed and the
``CellExecutionError`` is raised. The message directs the user to
the saved notebook for further inspection.
Execute and save all errors
~~~~~~~~~~~~~~~~~~~~~~~~~~~
As a last scenario, it is sometimes useful to execute notebooks which raise
exceptions, for example to show an error condition. In this case, instead of
stopping the execution on the first error, we can keep executing the notebook
using the traitlet ``allow_errors`` (default is False). With
``allow_errors=True``, the notebook is executed until the end, regardless of
any error encountered during the execution. The output notebook, will contain
the stack-traces and error messages for **all** the cells raising exceptions.
Widget state
------------
If your notebook contains any
`Jupyter Widgets <https://github.com/jupyter-widgets/ipywidgets/>`_,
the state of all the widgets can be stored in the notebook's metadata.
This allows rendering of the live widgets on for instance nbviewer, or when
converting to html.
We can tell nbclient to not store the state using the ``store_widget_state``
argument::
client = NotebookClient(nb, store_widget_state=False)
This widget rendering is not performed against a browser during execution, so
only widget default states or states manipulated via user code will be
calculated during execution. ``%%javascript`` cells will execute upon notebook
rendering, enabling complex interactions to function as expected when viewed by
a UI.
If you can't view widget results after execution, you may need to select
:menuselection:`Trust Notebook` under the :menuselection:`File` menu.
Using a command-line interface
------------------------------
This section will illustrate how to run notebooks from your terminal. It supports the most basic use case. For more sophisticated execution options, consider the `papermill <https://pypi.org/project/papermill/>`_ library.
This library's command line tool is available by running ``jupyter execute``. It expects notebooks as input arguments and accepts optional flags to modify the default behavior.
Running a notebook is this easy.::
jupyter execute notebook.ipynb
You can pass more than one notebook as well.::
jupyter execute notebook.ipynb notebook2.ipynb
By default, notebook errors will be raised and printed into the terminal. You can suppress them by passing the ``--allow-errors`` flag.::
jupyter execute notebook.ipynb --allow-errors
Other options allow you to modify the timeout length and dictate the kernel in use. A full set of options is available via the help command.::
jupyter execute --help
An application used to execute notebook files (*.ipynb)
Options
=======
The options below are convenience aliases to configurable class-options,
as listed in the "Equivalent to" description-line of the aliases.
To see all configurable class-options for some <cmd>, use:
<cmd> --help-all
--allow-errors
Errors are ignored and execution is continued until the end of the notebook.
Equivalent to: [--NbClientApp.allow_errors=True]
--timeout=<Int>
The time to wait (in seconds) for output from executions. If a cell
execution takes longer, a TimeoutError is raised. ``-1`` will disable the
timeout.
Default: None
Equivalent to: [--NbClientApp.timeout]
--startup_timeout=<Int>
The time to wait (in seconds) for the kernel to start. If kernel startup
takes longer, a RuntimeError is raised.
Default: 60
Equivalent to: [--NbClientApp.startup_timeout]
--kernel_name=<Unicode>
Name of kernel to use to execute the cells. If not set, use the kernel_spec
embedded in the notebook.
Default: ''
Equivalent to: [--NbClientApp.kernel_name]
To see all available configurables, use `--help-all`.
================================================
FILE: docs/conf.py
================================================
#!/usr/bin/env python3
#
# nbclient documentation build configuration file, created by
# sphinx-quickstart on Mon Jan 26 16:00:00 2020.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import shutil
import sys
import nbclient
sys.path.insert(0, os.path.abspath(".."))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.mathjax",
"sphinx.ext.napoleon",
# 'autodoc_traits', # TODO
"myst_parser",
]
try:
import enchant # type:ignore # noqa
extensions += ["sphinxcontrib.spelling"]
except ImportError:
pass
autodoc_mock_imports = ["pytest", "nbconvert", "testpath"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_suffix = [".rst", ".md"]
# The master toctree document.
master_doc = "index"
# General information about the project.
project = "nbclient"
copyright = "2020, Project Jupyter" # noqa
author = "Project Jupyter"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = ".".join(nbclient.__version__.split(".")[0:2])
# The full version, including alpha/beta/rc tags.
release = nbclient.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line foexitr these cases.
language = "en"
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "UPDATE.md"]
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
default_role = "any"
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "sphinx_book_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
"path_to_docs": "docs",
"repository_url": "https://github.com/jupyter/nbclient",
"repository_branch": "master",
"use_edit_page_button": True,
"navigation_with_keys": False,
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
# html_sidebars = {}
html_title = "nbclient"
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = "nclientdoc"
# -- Options for LaTeX output ---------------------------------------------
# latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
# }
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [(master_doc, "nbclient.tex", "nbclient Documentation", "jupyter team", "manual")]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "nbclient", "nbclient Documentation", [author], 1)]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
"nbclient",
"nbclient Documentation",
author,
"nbclient",
"One line description of project.",
"Miscellaneous",
)
]
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {"python": ("https://docs.python.org/", None)}
def setup(app):
here = os.path.abspath(os.path.dirname(__file__))
dest = os.path.join(here, "changelog.md")
shutil.copy(os.path.join(here, "..", "CHANGELOG.md"), dest)
autogen_config = os.path.join(here, "autogen_config.py")
prev_dir = os.getcwd()
os.chdir(here)
with open(autogen_config) as f:
exec(compile(f.read(), autogen_config, "exec"), {}) # noqa
os.chdir(prev_dir)
================================================
FILE: docs/index.rst
================================================
Welcome to nbclient
===================
.. image:: https://img.shields.io/github/stars/jupyter/nbclient?label=stars&style=social
:alt: GitHub stars
:target: https://github.com/jupyter/nbclient
.. image:: https://github.com/jupyter/nbclient/workflows/CI/badge.svg
:alt: GitHub Actions
:target: https://github.com/jupyter/nbclient/actions
.. image:: https://codecov.io/github/jupyter/nbclient/coverage.svg?branch=master
:alt: CodeCov
:target: https://codecov.io/gh/jupyter/nbclient
---
**NBClient** lets you **execute** notebooks.
A client library for programmatic notebook execution, **NBClient** is a tool for running Jupyter Notebooks in
different execution contexts, including the command line. NBClient was spun out of `nbconvert <https://nbconvert.readthedocs.io/en/latest/>`_'s
former ``ExecutePreprocessor``.
Demo
----
To demo **NBClient** interactively, click the Binder link below:
.. image:: https://mybinder.org/badge_logo.svg
:target: https://mybinder.org/v2/gh/jupyter/nbclient/master?filepath=binder%2Frun_nbclient.ipynb
Origins
-------
This library used to be part of `nbconvert <https://nbconvert.readthedocs.io/en/latest/>`_ and was extracted into its ownlibrary for easier updating and importing by downstream libraries and applications.
Python Version Support
----------------------
This library currently supports python 3.6+ versions. As minor python
versions are officially sunset by the python org, nbclient will similarly
drop support in the future.
Documentation
-------------
These pages guide you through the installation and usage of nbclient.
.. toctree::
:maxdepth: 1
:caption: Documentation
installation
client
changelog
API Reference
-------------
If you are looking for information about a specific function, class, or method,
this documentation section will help you.
.. toctree::
:maxdepth: 3
:caption: Table of Contents
reference/index.rst
Indices and tables
------------------
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
================================================
FILE: docs/installation.rst
================================================
Installation
============
Installing nbclient
-------------------
From the command line:
.. code-block:: bash
python3 -m pip install nbclient
.. seealso::
`Installing Jupyter <https://jupyter.readthedocs.io/en/latest/install.html>`__
NBClient is part of the Jupyter ecosystem.
================================================
FILE: docs/make.bat
================================================
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=nbclient
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
================================================
FILE: docs/reference/index.rst
================================================
Reference
=========
This part of the documentation lists the full API reference of all public classes and functions.
.. toctree::
:maxdepth: 2
nbclient
config_options
modules
================================================
FILE: docs/reference/modules.rst
================================================
nbclient
========
.. toctree::
:maxdepth: 4
nbclient
================================================
FILE: docs/reference/nbclient.rst
================================================
nbclient package
================
Subpackages
-----------
Submodules
----------
nbclient.client module
----------------------
.. automodule:: nbclient.client
:members:
:undoc-members:
:show-inheritance:
nbclient.exceptions module
--------------------------
.. automodule:: nbclient.exceptions
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: nbclient
:members:
:undoc-members:
:show-inheritance:
================================================
FILE: nbclient/__init__.py
================================================
from ._version import __version__, version_info
from .client import NotebookClient, execute
__all__ = ["__version__", "version_info", "NotebookClient", "execute"]
================================================
FILE: nbclient/_version.py
================================================
"""Version info."""
from __future__ import annotations
import re
__version__ = "0.10.4"
# Build up version_info tuple for backwards compatibility
pattern = r"(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)"
match = re.match(pattern, __version__)
if match:
parts: list[int | str] = [int(match[part]) for part in ["major", "minor", "patch"]]
if match["rest"]:
parts.append(match["rest"])
else:
parts = []
version_info = tuple(parts)
================================================
FILE: nbclient/cli.py
================================================
"""nbclient cli."""
from __future__ import annotations
import logging
import sys
import typing
from pathlib import Path
from textwrap import dedent
import nbformat
from jupyter_core.application import JupyterApp
from traitlets import Bool, Integer, List, Unicode, default
from traitlets.config import catch_config_error
from nbclient import __version__
from .client import NotebookClient
# mypy: disable-error-code="no-untyped-call"
nbclient_aliases: dict[str, str] = {
"timeout": "NbClientApp.timeout",
"startup_timeout": "NbClientApp.startup_timeout",
"kernel_name": "NbClientApp.kernel_name",
"output": "NbClientApp.output_base",
}
nbclient_flags: dict[str, typing.Any] = {
"allow-errors": (
{
"NbClientApp": {
"allow_errors": True,
},
},
"Errors are ignored and execution is continued until the end of the notebook.",
),
"inplace": (
{
"NbClientApp": {
"inplace": True,
},
},
"Overwrite input notebook with executed results.",
),
}
class NbClientApp(JupyterApp):
"""
An application used to execute notebook files (``*.ipynb``)
"""
version = Unicode(__version__)
name = "jupyter-execute"
aliases = nbclient_aliases
flags = nbclient_flags
description = "An application used to execute notebook files (*.ipynb)"
notebooks = List(Unicode(), help="Path of notebooks to convert").tag(config=True)
timeout = Integer(
None,
allow_none=True,
help=dedent(
"""
The time to wait (in seconds) for output from executions.
If a cell execution takes longer, a TimeoutError is raised.
``-1`` will disable the timeout.
"""
),
).tag(config=True)
startup_timeout = Integer(
60,
help=dedent(
"""
The time to wait (in seconds) for the kernel to start.
If kernel startup takes longer, a RuntimeError is
raised.
"""
),
).tag(config=True)
allow_errors = Bool(
False,
help=dedent(
"""
When a cell raises an error the default behavior is that
execution is stopped and a :py:class:`nbclient.exceptions.CellExecutionError`
is raised.
If this flag is provided, errors are ignored and execution
is continued until the end of the notebook.
"""
),
).tag(config=True)
skip_cells_with_tag = Unicode(
"skip-execution",
help=dedent(
"""
Name of the cell tag to use to denote a cell that should be skipped.
"""
),
).tag(config=True)
kernel_name = Unicode(
"",
help=dedent(
"""
Name of kernel to use to execute the cells.
If not set, use the kernel_spec embedded in the notebook.
"""
),
).tag(config=True)
inplace = Bool(
False,
help=dedent(
"""
Default is execute notebook without writing the newly executed notebook.
If this flag is provided, the newly generated notebook will
overwrite the input notebook.
"""
),
).tag(config=True)
output_base = Unicode(
None,
allow_none=True,
help=dedent(
"""
Write executed notebook to this file base name.
Supports pattern replacements ``'{notebook_name}'``,
the name of the input notebook file without extension.
Note that output is always relative to the parent directory of the
input notebook.
"""
),
).tag(config=True)
@default("log_level")
def _log_level_default(self) -> int:
return logging.INFO
@catch_config_error
def initialize(self, argv: list[str] | None = None) -> None:
"""Initialize the app."""
super().initialize(argv)
# Get notebooks to run
self.notebooks = self.get_notebooks()
# If there are none, throw an error
if not self.notebooks:
sys.exit(-1)
# If output, must have single notebook
if len(self.notebooks) > 1 and self.output_base is not None:
if "{notebook_name}" not in self.output_base:
msg = (
"If passing multiple notebooks with `--output=output` option, "
"output string must contain {notebook_name}"
)
raise ValueError(msg)
# Loop and run them one by one
for path in self.notebooks:
self.run_notebook(path)
def get_notebooks(self) -> list[str]:
"""Get the notebooks for the app."""
# If notebooks were provided from the command line, use those
if self.extra_args:
notebooks = self.extra_args
# If not, look to the class attribute
else:
notebooks = self.notebooks
# Return what we got.
return notebooks
def run_notebook(self, notebook_path: str) -> None:
"""Run a notebook by path."""
# Log it
self.log.info(f"Executing {notebook_path}")
input_path = Path(notebook_path).with_suffix(".ipynb")
# Get its parent directory so we can add it to the $PATH
path = input_path.parent.absolute()
# Optional output of executed notebook
if self.inplace:
output_path = input_path
elif self.output_base:
output_path = input_path.parent.joinpath(
self.output_base.format(notebook_name=input_path.with_suffix("").name)
).with_suffix(".ipynb")
else:
output_path = None
if output_path and not output_path.parent.is_dir():
msg = f"Cannot write to directory={output_path.parent} that does not exist"
raise ValueError(msg)
# Open up the notebook we're going to run
with input_path.open() as f:
nb = nbformat.read(f, as_version=4)
# Configure nbclient to run the notebook
client = NotebookClient(
nb,
timeout=self.timeout,
startup_timeout=self.startup_timeout,
skip_cells_with_tag=self.skip_cells_with_tag,
allow_errors=self.allow_errors,
kernel_name=self.kernel_name,
resources={"metadata": {"path": path}},
)
# Run it
client.execute()
# Save it
if output_path:
self.log.info(f"Save executed results to {output_path}")
nbformat.write(nb, output_path)
main = NbClientApp.launch_instance
================================================
FILE: nbclient/client.py
================================================
"""nbclient implementation."""
from __future__ import annotations
import asyncio
import atexit
import base64
import collections
import datetime
import re
import signal
import typing as t
from contextlib import asynccontextmanager, contextmanager
from queue import Empty
from textwrap import dedent
from time import monotonic
from jupyter_client.client import KernelClient
from jupyter_client.manager import KernelManager
from nbformat import NotebookNode
from nbformat.v4 import output_from_msg
from traitlets import Any, Bool, Callable, Dict, Enum, Integer, List, Type, Unicode, default
from traitlets.config.configurable import LoggingConfigurable
from .exceptions import (
CellControlSignal,
CellExecutionComplete,
CellExecutionError,
CellTimeoutError,
DeadKernelError,
)
from .output_widget import OutputWidget
from .util import ensure_async, run_hook, run_sync
_RGX_CARRIAGERETURN = re.compile(r".*\r(?=[^\n])")
_RGX_BACKSPACE = re.compile(r"[^\n]\b")
# mypy: disable-error-code="no-untyped-call"
def timestamp(msg: dict[str, t.Any] | None = None) -> str:
"""Get the timestamp for a message."""
if msg and "header" in msg: # The test mocks don't provide a header, so tolerate that
msg_header = msg["header"]
if "date" in msg_header and isinstance(msg_header["date"], datetime.datetime):
try:
# reformat datetime into expected format
formatted_time = datetime.datetime.strftime(
msg_header["date"], "%Y-%m-%dT%H:%M:%S.%fZ"
)
if (
formatted_time
): # docs indicate strftime may return empty string, so let's catch that too
return formatted_time
except Exception: # noqa
pass # fallback to a local time
return datetime.datetime.utcnow().isoformat() + "Z"
class NotebookClient(LoggingConfigurable):
"""
Encompasses a Client for executing cells in a notebook
"""
timeout = Integer(
None,
allow_none=True,
help=dedent(
"""
The time to wait (in seconds) for output from executions.
If a cell execution takes longer, a TimeoutError is raised.
``None`` or ``-1`` will disable the timeout. If ``timeout_func`` is set,
it overrides ``timeout``.
"""
),
).tag(config=True)
timeout_func: t.Callable[..., int | None] | None = Any( # type:ignore[assignment]
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which, when given the cell source as input,
returns the time to wait (in seconds) for output from cell
executions. If a cell execution takes longer, a TimeoutError
is raised.
Returning ``None`` or ``-1`` will disable the timeout for the cell.
Not setting ``timeout_func`` will cause the client to
default to using the ``timeout`` trait for all cells. The
``timeout_func`` trait overrides ``timeout`` if it is not ``None``.
"""
),
).tag(config=True)
interrupt_on_timeout = Bool(
False,
help=dedent(
"""
If execution of a cell times out, interrupt the kernel and
continue executing other cells rather than throwing an error and
stopping.
"""
),
).tag(config=True)
error_on_timeout = Dict(
default_value=None,
allow_none=True,
help=dedent(
"""
If a cell execution was interrupted after a timeout, don't wait for
the execute_reply from the kernel (e.g. KeyboardInterrupt error).
Instead, return an execute_reply with the given error, which should
be of the following form::
{
'ename': str, # Exception name, as a string
'evalue': str, # Exception value, as a string
'traceback': list(str), # traceback frames, as strings
}
"""
),
).tag(config=True)
startup_timeout = Integer(
60,
help=dedent(
"""
The time to wait (in seconds) for the kernel to start.
If kernel startup takes longer, a RuntimeError is
raised.
"""
),
).tag(config=True)
allow_errors = Bool(
False,
help=dedent(
"""
If ``False`` (default), when a cell raises an error the
execution is stopped and a ``CellExecutionError``
is raised, except if the error name is in
``allow_error_names``.
If ``True``, execution errors are ignored and the execution
is continued until the end of the notebook. Output from
exceptions is included in the cell output in both cases.
"""
),
).tag(config=True)
allow_error_names = List(
Unicode(),
help=dedent(
"""
List of error names which won't stop the execution. Use this if the
``allow_errors`` option it too general and you want to allow only
specific kinds of errors.
"""
),
).tag(config=True)
force_raise_errors = Bool(
False,
help=dedent(
"""
If False (default), errors from executing the notebook can be
allowed with a ``raises-exception`` tag on a single cell, or the
``allow_errors`` or ``allow_error_names`` configurable options for
all cells. An allowed error will be recorded in notebook output, and
execution will continue. If an error occurs when it is not
explicitly allowed, a ``CellExecutionError`` will be raised.
If True, ``CellExecutionError`` will be raised for any error that occurs
while executing the notebook. This overrides the ``allow_errors``
and ``allow_error_names`` options and the ``raises-exception`` cell
tag.
"""
),
).tag(config=True)
skip_cells_with_tag = Unicode(
"skip-execution",
help=dedent(
"""
Name of the cell tag to use to denote a cell that should be skipped.
"""
),
).tag(config=True)
extra_arguments = List(Unicode()).tag(config=True)
kernel_name = Unicode(
"",
help=dedent(
"""
Name of kernel to use to execute the cells.
If not set, use the kernel_spec embedded in the notebook.
"""
),
).tag(config=True)
raise_on_iopub_timeout = Bool(
False,
help=dedent(
"""
If ``False`` (default), then the kernel will continue waiting for
iopub messages until it receives a kernel idle message, or until a
timeout occurs, at which point the currently executing cell will be
skipped. If ``True``, then an error will be raised after the first
timeout. This option generally does not need to be used, but may be
useful in contexts where there is the possibility of executing
notebooks with memory-consuming infinite loops.
"""
),
).tag(config=True)
store_widget_state = Bool(
True,
help=dedent(
"""
If ``True`` (default), then the state of the Jupyter widgets created
at the kernel will be stored in the metadata of the notebook.
"""
),
).tag(config=True)
record_timing = Bool(
True,
help=dedent(
"""
If ``True`` (default), then the execution timings of each cell will
be stored in the metadata of the notebook.
"""
),
).tag(config=True)
iopub_timeout = Integer(
4,
allow_none=False,
help=dedent(
"""
The time to wait (in seconds) for IOPub output. This generally
doesn't need to be set, but on some slow networks (such as CI
systems) the default timeout might not be long enough to get all
messages.
"""
),
).tag(config=True)
shell_timeout_interval = Integer(
5,
allow_none=False,
help=dedent(
"""
The time to wait (in seconds) for Shell output before retrying.
This generally doesn't need to be set, but if one needs to check
for dead kernels at a faster rate this can help.
"""
),
).tag(config=True)
shutdown_kernel = Enum(
["graceful", "immediate"],
default_value="graceful",
help=dedent(
"""
If ``graceful`` (default), then the kernel is given time to clean
up after executing all cells, e.g., to execute its ``atexit`` hooks.
If ``immediate``, then the kernel is signaled to immediately
terminate.
"""
),
).tag(config=True)
ipython_hist_file = Unicode(
default_value=":memory:",
help="""Path to file to use for SQLite history database for an IPython kernel.
The specific value ``:memory:`` (including the colon
at both end but not the back ticks), avoids creating a history file. Otherwise, IPython
will create a history file for each kernel.
When running kernels simultaneously (e.g. via multiprocessing) saving history a single
SQLite file can result in database errors, so using ``:memory:`` is recommended in
non-interactive contexts.
""",
).tag(config=True)
kernel_manager_class = Type(
config=True, klass=KernelManager, help="The kernel manager class to use."
)
on_notebook_start = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes after the kernel manager and kernel client are setup, and
cells are about to execute.
Called with kwargs ``notebook``.
"""
),
).tag(config=True)
on_notebook_complete = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes after the kernel is cleaned up.
Called with kwargs ``notebook``.
"""
),
).tag(config=True)
on_notebook_error = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes when the notebook encounters an error.
Called with kwargs ``notebook``.
"""
),
).tag(config=True)
on_cell_start = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes before a cell is executed and before non-executing cells
are skipped.
Called with kwargs ``cell`` and ``cell_index``.
"""
),
).tag(config=True)
on_cell_execute = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes just before a code cell is executed.
Called with kwargs ``cell`` and ``cell_index``.
"""
),
).tag(config=True)
on_cell_complete = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes after a cell execution is complete. It is
called even when a cell results in a failure.
Called with kwargs ``cell`` and ``cell_index``.
"""
),
).tag(config=True)
on_cell_executed = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes just after a code cell is executed, whether
or not it results in an error.
Called with kwargs ``cell``, ``cell_index`` and ``execute_reply``.
"""
),
).tag(config=True)
on_cell_error = Callable(
default_value=None,
allow_none=True,
help=dedent(
"""
A callable which executes when a cell execution results in an error.
This is executed even if errors are suppressed with ``cell_allows_errors``.
Called with kwargs ``cell`, ``cell_index`` and ``execute_reply``.
"""
),
).tag(config=True)
@default("kernel_manager_class")
def _kernel_manager_class_default(self) -> type[KernelManager]:
"""Use a dynamic default to avoid importing jupyter_client at startup"""
from jupyter_client import AsyncKernelManager # type:ignore[attr-defined]
return AsyncKernelManager
_display_id_map: dict[str, t.Any] = Dict( # type:ignore[assignment]
help=dedent(
"""
mapping of locations of outputs with a given display_id
tracks cell index and output index within cell.outputs for
each appearance of the display_id
{
'display_id': {
cell_idx: [output_idx,]
}
}
"""
)
)
display_data_priority = List(
[
"text/html",
"application/pdf",
"text/latex",
"image/svg+xml",
"image/png",
"image/jpeg",
"text/markdown",
"text/plain",
],
help="""
An ordered list of preferred output type, the first
encountered will usually be used when converting discarding
the others.
""",
).tag(config=True)
resources: dict[str, t.Any] = Dict( # type:ignore[assignment]
help=dedent(
"""
Additional resources used in the conversion process. For example,
passing ``{'metadata': {'path': run_path}}`` sets the
execution path to ``run_path``.
"""
)
)
coalesce_streams = Bool(
help=dedent(
"""
Merge all stream outputs with shared names into single streams.
"""
)
)
def __init__(self, nb: NotebookNode, km: KernelManager | None = None, **kw: t.Any) -> None:
"""Initializes the execution manager.
Parameters
----------
nb : NotebookNode
Notebook being executed.
km : KernelManager (optional)
Optional kernel manager. If none is provided, a kernel manager will
be created.
"""
super().__init__(**kw)
self.nb: NotebookNode = nb
self.km: KernelManager | None = km
self.owns_km: bool = km is None # whether the NotebookClient owns the kernel manager
self.kc: KernelClient | None = None
self.reset_execution_trackers()
self.widget_registry: dict[str, dict[str, t.Any]] = {
"@jupyter-widgets/output": {"OutputModel": OutputWidget}
}
# comm_open_handlers should return an object with a .handle_msg(msg) method or None
self.comm_open_handlers: dict[str, t.Any] = {
"jupyter.widget": self.on_comm_open_jupyter_widget
}
def reset_execution_trackers(self) -> None:
"""Resets any per-execution trackers."""
self.task_poll_for_reply: asyncio.Future[t.Any] | None = None
self.code_cells_executed = 0
self._display_id_map = {}
self.widget_state: dict[str, dict[str, t.Any]] = {}
self.widget_buffers: dict[str, dict[tuple[str, ...], dict[str, str]]] = {}
# maps to list of hooks, where the last is used, this is used
# to support nested use of output widgets.
self.output_hook_stack: dict[str, list[OutputWidget]] = collections.defaultdict(list)
# our front-end mimicking Output widgets
self.comm_objects: dict[str, t.Any] = {}
def create_kernel_manager(self) -> KernelManager:
"""Creates a new kernel manager.
Returns
-------
km : KernelManager
Kernel manager whose client class is asynchronous.
"""
if not self.kernel_name:
kn = self.nb.metadata.get("kernelspec", {}).get("name")
if kn is not None:
self.kernel_name = kn
if not self.kernel_name:
self.km = self.kernel_manager_class(config=self.config)
else:
self.km = self.kernel_manager_class(kernel_name=self.kernel_name, config=self.config)
assert self.km is not None
return self.km
async def _async_cleanup_kernel(self) -> None:
assert self.km is not None
now = self.shutdown_kernel == "immediate"
try:
# Queue the manager to kill the process, and recover gracefully if it's already dead.
if await ensure_async(self.km.is_alive()):
await ensure_async(self.km.shutdown_kernel(now=now))
except RuntimeError as e:
# The error isn't specialized, so we have to check the message
if "No kernel is running!" not in str(e):
raise
finally:
# Remove any state left over even if we failed to stop the kernel
await ensure_async(self.km.cleanup_resources())
if getattr(self, "kc", None) and self.kc is not None:
await ensure_async(self.kc.stop_channels()) # type:ignore[func-returns-value]
self.kc = None
self.km = None
_cleanup_kernel = run_sync(_async_cleanup_kernel)
async def async_start_new_kernel(self, **kwargs: t.Any) -> None:
"""Creates a new kernel.
Parameters
----------
kwargs :
Any options for ``self.kernel_manager_class.start_kernel()``. Because
that defaults to AsyncKernelManager, this will likely include options
accepted by ``AsyncKernelManager.start_kernel()``, which includes ``cwd``.
"""
assert self.km is not None
resource_path = self.resources.get("metadata", {}).get("path") or None
if resource_path and "cwd" not in kwargs:
kwargs["cwd"] = resource_path
has_history_manager_arg = any(
arg.startswith("--HistoryManager.hist_file") for arg in self.extra_arguments
)
if (
hasattr(self.km, "ipykernel")
and self.km.ipykernel
and self.ipython_hist_file
and not has_history_manager_arg
):
self.extra_arguments += [f"--HistoryManager.hist_file={self.ipython_hist_file}"]
await ensure_async(self.km.start_kernel(extra_arguments=self.extra_arguments, **kwargs))
start_new_kernel = run_sync(async_start_new_kernel)
async def async_start_new_kernel_client(self) -> KernelClient:
"""Creates a new kernel client.
Returns
-------
kc : KernelClient
Kernel client as created by the kernel manager ``km``.
"""
assert self.km is not None
try:
self.kc = self.km.client()
await ensure_async(self.kc.start_channels()) # type:ignore[func-returns-value]
await ensure_async(self.kc.wait_for_ready(timeout=self.startup_timeout))
except Exception as e:
self.log.error(
"Error occurred while starting new kernel client for kernel {}: {}".format(
getattr(self.km, "kernel_id", None), str(e)
)
)
await self._async_cleanup_kernel()
raise
self.kc.allow_stdin = False
await run_hook(self.on_notebook_start, notebook=self.nb)
return self.kc
start_new_kernel_client = run_sync(async_start_new_kernel_client)
@contextmanager
def setup_kernel(self, **kwargs: t.Any) -> t.Generator[None, None, None]:
"""
Context manager for setting up the kernel to execute a notebook.
The assigns the Kernel Manager (``self.km``) if missing and Kernel Client(``self.kc``).
When control returns from the yield it stops the client's zmq channels, and shuts
down the kernel.
"""
# by default, cleanup the kernel client if we own the kernel manager
# and keep it alive if we don't
cleanup_kc = kwargs.pop("cleanup_kc", self.owns_km)
# Can't use run_until_complete on an asynccontextmanager function :(
if self.km is None:
self.km = self.create_kernel_manager()
if not self.km.has_kernel:
self.start_new_kernel(**kwargs)
if self.kc is None:
self.start_new_kernel_client()
try:
yield
finally:
if cleanup_kc:
self._cleanup_kernel()
@asynccontextmanager
async def async_setup_kernel(self, **kwargs: t.Any) -> t.AsyncGenerator[None, None]:
"""
Context manager for setting up the kernel to execute a notebook.
This assigns the Kernel Manager (``self.km``) if missing and Kernel Client(``self.kc``).
When control returns from the yield it stops the client's zmq channels, and shuts
down the kernel.
Handlers for SIGINT and SIGTERM are also added to cleanup in case of unexpected shutdown.
"""
# by default, cleanup the kernel client if we own the kernel manager
# and keep it alive if we don't
cleanup_kc = kwargs.pop("cleanup_kc", self.owns_km)
if self.km is None:
self.km = self.create_kernel_manager()
# self._cleanup_kernel uses run_async, which ensures the ioloop is running again.
# This is necessary as the ioloop has stopped once atexit fires.
atexit.register(self._cleanup_kernel)
def on_signal() -> None:
"""Handle signals."""
self._async_cleanup_kernel_future = asyncio.ensure_future(self._async_cleanup_kernel())
atexit.unregister(self._cleanup_kernel)
loop = asyncio.get_event_loop()
try:
loop.add_signal_handler(signal.SIGINT, on_signal)
loop.add_signal_handler(signal.SIGTERM, on_signal)
except RuntimeError:
# NotImplementedError: Windows does not support signals.
# RuntimeError: Raised when add_signal_handler is called outside the main thread
pass
if not self.km.has_kernel:
await self.async_start_new_kernel(**kwargs)
if self.kc is None:
await self.async_start_new_kernel_client()
try:
yield
except RuntimeError as e:
await run_hook(self.on_notebook_error, notebook=self.nb)
raise e
finally:
if cleanup_kc:
await self._async_cleanup_kernel()
await run_hook(self.on_notebook_complete, notebook=self.nb)
atexit.unregister(self._cleanup_kernel)
try:
loop.remove_signal_handler(signal.SIGINT)
loop.remove_signal_handler(signal.SIGTERM)
except RuntimeError:
pass
async def async_execute(self, reset_kc: bool = False, **kwargs: t.Any) -> NotebookNode:
"""
Executes each code cell.
Parameters
----------
kwargs :
Any option for ``self.kernel_manager_class.start_kernel()``. Because
that defaults to AsyncKernelManager, this will likely include options
accepted by ``jupyter_client.AsyncKernelManager.start_kernel()``,
which includes ``cwd``.
``reset_kc`` if True, the kernel client will be reset and a new one
will be created (default: False).
Returns
-------
nb : NotebookNode
The executed notebook.
"""
if reset_kc and self.owns_km:
await self._async_cleanup_kernel()
self.reset_execution_trackers()
async with self.async_setup_kernel(**kwargs):
assert self.kc is not None
self.log.info("Executing notebook with kernel: %s" % self.kernel_name)
msg_id = await ensure_async(self.kc.kernel_info())
info_msg = await self.async_wait_for_reply(msg_id)
if info_msg is not None:
if "language_info" in info_msg["content"]:
self.nb.metadata["language_info"] = info_msg["content"]["language_info"]
else:
raise RuntimeError(
'Kernel info received message content has no "language_info" key. '
"Content is:\n" + str(info_msg["content"])
)
for index, cell in enumerate(self.nb.cells):
# Ignore `'execution_count' in content` as it's always 1
# when store_history is False
await self.async_execute_cell(
cell, index, execution_count=self.code_cells_executed + 1
)
self.set_widgets_metadata()
return self.nb
execute = run_sync(async_execute)
def set_widgets_metadata(self) -> None:
"""Set with widget metadata."""
if self.widget_state:
self.nb.metadata.widgets = {
"application/vnd.jupyter.widget-state+json": {
"state": {
model_id: self._serialize_widget_state(state)
for model_id, state in self.widget_state.items()
if "_model_name" in state
},
"version_major": 2,
"version_minor": 0,
}
}
for key, widget in self.nb.metadata.widgets[
"application/vnd.jupyter.widget-state+json"
]["state"].items():
buffers = self.widget_buffers.get(key)
if buffers:
widget["buffers"] = list(buffers.values())
def _update_display_id(self, display_id: str, msg: dict[str, t.Any]) -> None:
"""Update outputs with a given display_id"""
if display_id not in self._display_id_map:
self.log.debug("display id %r not in %s", display_id, self._display_id_map)
return
if msg["header"]["msg_type"] == "update_display_data":
msg["header"]["msg_type"] = "display_data"
try:
out = output_from_msg(msg)
except ValueError:
self.log.error(f"unhandled iopub msg: {msg['msg_type']}")
return
for cell_idx, output_indices in self._display_id_map[display_id].items():
cell = self.nb["cells"][cell_idx]
outputs = cell["outputs"]
for output_idx in output_indices:
outputs[output_idx]["data"] = out["data"]
outputs[output_idx]["metadata"] = out["metadata"]
async def _async_poll_for_reply(
self,
msg_id: str,
cell: NotebookNode,
timeout: int | None,
task_poll_output_msg: asyncio.Future[t.Any],
task_poll_kernel_alive: asyncio.Future[t.Any],
) -> dict[str, t.Any]:
msg: dict[str, t.Any]
assert self.kc is not None
new_timeout: float | None = None
if timeout is not None:
deadline = monotonic() + timeout
new_timeout = float(timeout)
error_on_timeout_execute_reply = None
while True:
try:
if error_on_timeout_execute_reply:
msg = error_on_timeout_execute_reply
msg["parent_header"] = {"msg_id": msg_id}
else:
msg = await ensure_async(self.kc.shell_channel.get_msg(timeout=new_timeout))
if msg["parent_header"].get("msg_id") == msg_id:
if self.record_timing:
cell["metadata"]["execution"]["shell.execute_reply"] = timestamp(msg)
try:
await asyncio.wait_for(task_poll_output_msg, self.iopub_timeout)
except (asyncio.TimeoutError, Empty):
if self.raise_on_iopub_timeout:
task_poll_kernel_alive.cancel()
raise CellTimeoutError.error_from_timeout_and_cell(
"Timeout waiting for IOPub output", self.iopub_timeout, cell
) from None
else:
self.log.warning("Timeout waiting for IOPub output")
task_poll_kernel_alive.cancel()
return msg
else:
if new_timeout is not None:
new_timeout = max(0, deadline - monotonic())
except Empty:
# received no message, check if kernel is still alive
assert timeout is not None
task_poll_kernel_alive.cancel()
await self._async_check_alive()
error_on_timeout_execute_reply = await self._async_handle_timeout(timeout, cell)
async def _async_poll_output_msg(
self, parent_msg_id: str, cell: NotebookNode, cell_index: int
) -> None:
assert self.kc is not None
while True:
msg = await ensure_async(self.kc.iopub_channel.get_msg(timeout=None))
if msg["parent_header"].get("msg_id") == parent_msg_id:
try:
# Will raise CellExecutionComplete when completed
self.process_message(msg, cell, cell_index)
except CellExecutionComplete:
return
async def _async_poll_kernel_alive(self) -> None:
while True:
await asyncio.sleep(1)
try:
await self._async_check_alive()
except DeadKernelError:
assert self.task_poll_for_reply is not None
self.task_poll_for_reply.cancel()
return
def _get_timeout(self, cell: NotebookNode | None) -> int | None:
if self.timeout_func is not None and cell is not None:
timeout = self.timeout_func(cell)
else:
timeout = self.timeout
if not timeout or timeout < 0:
timeout = None
return timeout
async def _async_handle_timeout(
self, timeout: int, cell: NotebookNode | None = None
) -> None | dict[str, t.Any]:
self.log.error("Timeout waiting for execute reply (%is)." % timeout)
if self.interrupt_on_timeout:
self.log.error("Interrupting kernel")
assert self.km is not None
await ensure_async(self.km.interrupt_kernel())
if self.error_on_timeout:
execute_reply = {"content": {**self.error_on_timeout, "status": "error"}}
return execute_reply
return None
else:
assert cell is not None
raise CellTimeoutError.error_from_timeout_and_cell(
"Cell execution timed out", timeout, cell
)
async def _async_check_alive(self) -> None:
assert self.kc is not None
if not await ensure_async(self.kc.is_alive()): # type:ignore[attr-defined]
self.log.error("Kernel died while waiting for execute reply.")
raise DeadKernelError("Kernel died")
async def async_wait_for_reply(
self, msg_id: str, cell: NotebookNode | None = None
) -> dict[str, t.Any] | None:
"""Wait for a message reply."""
assert self.kc is not None
# wait for finish, with timeout
timeout = self._get_timeout(cell)
cummulative_time = 0
while True:
try:
msg: dict[str, t.Any] = await ensure_async(
self.kc.shell_channel.get_msg(timeout=self.shell_timeout_interval)
)
except Empty:
await self._async_check_alive()
cummulative_time += self.shell_timeout_interval
if timeout and cummulative_time > timeout:
await self._async_handle_timeout(timeout, cell)
break
else:
if msg["parent_header"].get("msg_id") == msg_id:
return msg
return None
wait_for_reply = run_sync(async_wait_for_reply)
# Backwards compatibility naming for papermill
_wait_for_reply = wait_for_reply
def _passed_deadline(self, deadline: int | None) -> bool:
if deadline is not None and deadline - monotonic() <= 0:
return True
return False
async def _check_raise_for_error(
self, cell: NotebookNode, cell_index: int, exec_reply: dict[str, t.Any] | None
) -> None:
if exec_reply is None:
return None
exec_reply_content = exec_reply["content"]
if exec_reply_content["status"] != "error":
return None
cell_allows_errors = (not self.force_raise_errors) and (
self.allow_errors
or exec_reply_content.get("ename") in self.allow_error_names
or "raises-exception" in cell.metadata.get("tags", [])
)
await run_hook(
self.on_cell_error, cell=cell, cell_index=cell_index, execute_reply=exec_reply
)
if not cell_allows_errors:
raise CellExecutionError.from_cell_and_msg(cell, exec_reply_content)
async def async_execute_cell(
self,
cell: NotebookNode,
cell_index: int,
execution_count: int | None = None,
store_history: bool = True,
) -> NotebookNode:
"""
Executes a single code cell.
To execute all cells see :meth:`execute`.
Parameters
----------
cell : nbformat.NotebookNode
The cell which is currently being processed.
cell_index : int
The position of the cell within the notebook object.
execution_count : int
The execution count to be assigned to the cell (default: Use kernel response)
store_history : bool
Determines if history should be stored in the kernel (default: False).
Specific to ipython kernels, which can store command histories.
Returns
-------
output : dict
The execution output payload (or None for no output).
Raises
------
CellExecutionError
If execution failed and should raise an exception, this will be raised
with defaults about the failure.
Returns
-------
cell : NotebookNode
The cell which was just processed.
"""
assert self.kc is not None
await run_hook(self.on_cell_start, cell=cell, cell_index=cell_index)
if cell.cell_type != "code" or not cell.source.strip():
self.log.debug("Skipping non-executing cell %s", cell_index)
return cell
if self.skip_cells_with_tag in cell.metadata.get("tags", []):
self.log.debug("Skipping tagged cell %s", cell_index)
return cell
if self.record_timing: # clear execution metadata prior to execution
cell["metadata"]["execution"] = {}
self.log.debug("Executing cell:\n%s", cell.source)
cell_allows_errors = (not self.force_raise_errors) and (
self.allow_errors or "raises-exception" in cell.metadata.get("tags", [])
)
await run_hook(self.on_cell_execute, cell=cell, cell_index=cell_index)
parent_msg_id = await ensure_async(
self.kc.execute(
cell.source, store_history=store_history, stop_on_error=not cell_allows_errors
)
)
await run_hook(self.on_cell_complete, cell=cell, cell_index=cell_index)
# We launched a code cell to execute
self.code_cells_executed += 1
exec_timeout = self._get_timeout(cell)
cell.outputs = []
self.clear_before_next_output = False
task_poll_kernel_alive = asyncio.ensure_future(self._async_poll_kernel_alive())
task_poll_output_msg = asyncio.ensure_future(
self._async_poll_output_msg(parent_msg_id, cell, cell_index)
)
self.task_poll_for_reply = asyncio.ensure_future(
self._async_poll_for_reply(
parent_msg_id, cell, exec_timeout, task_poll_output_msg, task_poll_kernel_alive
)
)
try:
exec_reply = await self.task_poll_for_reply
except asyncio.CancelledError:
# can only be cancelled by task_poll_kernel_alive when the kernel is dead
task_poll_output_msg.cancel()
raise DeadKernelError("Kernel died") from None
except Exception as e:
# Best effort to cancel request if it hasn't been resolved
try:
# Check if the task_poll_output is doing the raising for us
if not isinstance(e, CellControlSignal):
task_poll_output_msg.cancel()
finally:
raise
if execution_count:
cell["execution_count"] = execution_count
await run_hook(
self.on_cell_executed, cell=cell, cell_index=cell_index, execute_reply=exec_reply
)
if self.coalesce_streams and cell.outputs:
new_outputs = []
streams: dict[str, NotebookNode] = {}
for output in cell.outputs:
if output["output_type"] == "stream":
if output["name"] in streams:
streams[output["name"]]["text"] += output["text"]
else:
new_outputs.append(output)
streams[output["name"]] = output
else:
new_outputs.append(output)
# process \r and \b characters
for output in streams.values():
old = output["text"]
while len(output["text"]) < len(old):
old = output["text"]
# Cancel out anything-but-newline followed by backspace
output["text"] = _RGX_BACKSPACE.sub("", output["text"])
# Replace all carriage returns not followed by newline
output["text"] = _RGX_CARRIAGERETURN.sub("", output["text"])
# We also want to ensure stdout and stderr are always in the same consecutive order,
# because they are asynchronous, so order isn't guaranteed.
for i, output in enumerate(new_outputs):
if output["output_type"] == "stream" and output["name"] == "stderr":
if (
len(new_outputs) >= i + 2
and new_outputs[i + 1]["output_type"] == "stream"
and new_outputs[i + 1]["name"] == "stdout"
):
stdout = new_outputs.pop(i + 1)
new_outputs.insert(i, stdout)
cell.outputs = new_outputs
await self._check_raise_for_error(cell, cell_index, exec_reply)
self.nb["cells"][cell_index] = cell
return cell
execute_cell = run_sync(async_execute_cell)
def process_message(
self, msg: dict[str, t.Any], cell: NotebookNode, cell_index: int
) -> NotebookNode | None:
"""
Processes a kernel message, updates cell state, and returns the
resulting output object that was appended to cell.outputs.
The input argument *cell* is modified in-place.
Parameters
----------
msg : dict
The kernel message being processed.
cell : nbformat.NotebookNode
The cell which is currently being processed.
cell_index : int
The position of the cell within the notebook object.
Returns
-------
output : NotebookNode
The execution output payload (or None for no output).
Raises
------
CellExecutionComplete
Once a message arrives which indicates computation completeness.
"""
msg_type = msg["msg_type"]
self.log.debug("msg_type: %s", msg_type)
content = msg["content"]
self.log.debug("content: %s", content)
# while it's tempting to go for a more concise
# display_id = content.get("transient", {}).get("display_id", None)
# this breaks if transient is explicitly set to None
transient = content.get("transient")
display_id = transient.get("display_id") if transient else None
if display_id and msg_type in {"execute_result", "display_data", "update_display_data"}:
self._update_display_id(display_id, msg)
# set the prompt number for the input and the output
if "execution_count" in content:
cell["execution_count"] = content["execution_count"]
if self.record_timing:
if msg_type == "status":
if content["execution_state"] == "idle":
cell["metadata"]["execution"]["iopub.status.idle"] = timestamp(msg)
elif content["execution_state"] == "busy":
cell["metadata"]["execution"]["iopub.status.busy"] = timestamp(msg)
elif msg_type == "execute_input":
cell["metadata"]["execution"]["iopub.execute_input"] = timestamp(msg)
if msg_type == "status":
if content["execution_state"] == "idle":
raise CellExecutionComplete()
elif msg_type == "clear_output":
self.clear_output(cell.outputs, msg, cell_index)
elif msg_type.startswith("comm"):
self.handle_comm_msg(cell.outputs, msg, cell_index)
# Check for remaining messages we don't process
elif msg_type not in ["execute_input", "update_display_data"]:
# Assign output as our processed "result"
return self.output(cell.outputs, msg, display_id, cell_index)
return None
def output(
self,
outs: list[NotebookNode],
msg: dict[str, t.Any],
display_id: str | None,
cell_index: int,
) -> NotebookNode | None:
"""Handle output."""
msg_type = msg["msg_type"]
out: NotebookNode | None = None
parent_msg_id = msg["parent_header"].get("msg_id")
if self.output_hook_stack[parent_msg_id]:
# if we have a hook registered, it will override our
# default output behaviour (e.g. OutputWidget)
hook = self.output_hook_stack[parent_msg_id][-1]
hook.output(outs, msg, display_id, cell_index)
return None
try:
out = output_from_msg(msg)
except ValueError:
self.log.error(f"unhandled iopub msg: {msg_type}")
return None
if self.clear_before_next_output:
self.log.debug("Executing delayed clear_output")
outs[:] = []
self.clear_display_id_mapping(cell_index)
self.clear_before_next_output = False
if display_id:
# record output index in:
# _display_id_map[display_id][cell_idx]
cell_map = self._display_id_map.setdefault(display_id, {})
output_idx_list = cell_map.setdefault(cell_index, [])
output_idx_list.append(len(outs))
if out:
outs.append(out)
return out
def clear_output(
self, outs: list[NotebookNode], msg: dict[str, t.Any], cell_index: int
) -> None:
"""Clear output."""
content = msg["content"]
parent_msg_id = msg["parent_header"].get("msg_id")
if self.output_hook_stack[parent_msg_id]:
# if we have a hook registered, it will override our
# default clear_output behaviour (e.g. OutputWidget)
hook = self.output_hook_stack[parent_msg_id][-1]
hook.clear_output(outs, msg, cell_index)
return
if content.get("wait"):
self.log.debug("Wait to clear output")
self.clear_before_next_output = True
else:
self.log.debug("Immediate clear output")
outs[:] = []
self.clear_display_id_mapping(cell_index)
def clear_display_id_mapping(self, cell_index: int) -> None:
"""Clear a display id mapping for a cell."""
for _, cell_map in self._display_id_map.items():
if cell_index in cell_map:
cell_map[cell_index] = []
def handle_comm_msg(
self, outs: list[NotebookNode], msg: dict[str, t.Any], cell_index: int
) -> None:
"""Handle a comm message."""
content = msg["content"]
data = content["data"]
if self.store_widget_state and "state" in data: # ignore custom msg'es
self.widget_state.setdefault(content["comm_id"], {}).update(data["state"])
if data.get("buffer_paths"):
comm_id = content["comm_id"]
if comm_id not in self.widget_buffers:
self.widget_buffers[comm_id] = {}
# for each comm, the path uniquely identifies a buffer
new_buffers: dict[tuple[str, ...], dict[str, str]] = {
tuple(k["path"]): k for k in self._get_buffer_data(msg)
}
self.widget_buffers[comm_id].update(new_buffers)
# There are cases where we need to mimic a frontend, to get similar behaviour as
# when using the Output widget from Jupyter lab/notebook
if msg["msg_type"] == "comm_open":
target = msg["content"].get("target_name")
handler = self.comm_open_handlers.get(target)
if handler:
comm_id = msg["content"]["comm_id"]
comm_object = handler(msg)
if comm_object:
self.comm_objects[comm_id] = comm_object
else:
self.log.warning(f"No handler found for comm target {target!r}")
elif msg["msg_type"] == "comm_msg":
content = msg["content"]
comm_id = msg["content"]["comm_id"]
if comm_id in self.comm_objects:
self.comm_objects[comm_id].handle_msg(msg)
def _serialize_widget_state(self, state: dict[str, t.Any]) -> dict[str, t.Any]:
"""Serialize a widget state, following format in @jupyter-widgets/schema."""
return {
"model_name": state.get("_model_name"),
"model_module": state.get("_model_module"),
"model_module_version": state.get("_model_module_version"),
"state": state,
}
def _get_buffer_data(self, msg: dict[str, t.Any]) -> list[dict[str, str]]:
encoded_buffers = []
paths = msg["content"]["data"]["buffer_paths"]
buffers = msg["buffers"]
for path, buffer in zip(paths, buffers, strict=False):
encoded_buffers.append(
{
"data": base64.b64encode(buffer).decode("utf-8"),
"encoding": "base64",
"path": path,
}
)
return encoded_buffers
def register_output_hook(self, msg_id: str, hook: OutputWidget) -> None:
"""Registers an override object that handles output/clear_output instead.
Multiple hooks can be registered, where the last one will be used (stack based)
"""
# mimics
# https://jupyterlab.github.io/jupyterlab/services/interfaces/kernel.ikernelconnection.html#registermessagehook
self.output_hook_stack[msg_id].append(hook)
def remove_output_hook(self, msg_id: str, hook: OutputWidget) -> None:
"""Unregisters an override object that handles output/clear_output instead"""
# mimics
# https://jupyterlab.github.io/jupyterlab/services/interfaces/kernel.ikernelconnection.html#removemessagehook
removed_hook = self.output_hook_stack[msg_id].pop()
assert removed_hook == hook
def on_comm_open_jupyter_widget(self, msg: dict[str, t.Any]) -> t.Any | None:
"""Handle a jupyter widget comm open."""
content = msg["content"]
data = content["data"]
state = data["state"]
comm_id = msg["content"]["comm_id"]
module = self.widget_registry.get(state["_model_module"])
if module:
widget_class = module.get(state["_model_name"])
if widget_class:
return widget_class(comm_id, state, self.kc, self)
return None
def execute(
nb: NotebookNode,
cwd: str | None = None,
km: KernelManager | None = None,
**kwargs: t.Any,
) -> NotebookNode:
"""Execute a notebook's code, updating outputs within the notebook object.
This is a convenient wrapper around NotebookClient. It returns the
modified notebook object.
Parameters
----------
nb : NotebookNode
The notebook object to be executed
cwd : str, optional
If supplied, the kernel will run in this directory
km : AsyncKernelManager, optional
If supplied, the specified kernel manager will be used for code execution.
kwargs :
Any other options for NotebookClient, e.g. timeout, kernel_name
"""
resources = {}
if cwd is not None:
resources["metadata"] = {"path": cwd}
return NotebookClient(nb=nb, resources=resources, km=km, **kwargs).execute()
================================================
FILE: nbclient/exceptions.py
================================================
"""Exceptions for nbclient."""
from __future__ import annotations
from typing import Any
from nbformat import NotebookNode
class CellControlSignal(Exception): # noqa
"""
A custom exception used to indicate that the exception is used for cell
control actions (not the best model, but it's needed to cover existing
behavior without major refactors).
"""
pass
class CellTimeoutError(TimeoutError, CellControlSignal):
"""
A custom exception to capture when a cell has timed out during execution.
"""
@classmethod
def error_from_timeout_and_cell(
cls, msg: str, timeout: int, cell: NotebookNode
) -> CellTimeoutError:
"""Create an error from a timeout on a cell."""
if cell and cell.source:
src_by_lines = cell.source.strip().split("\n")
src = (
cell.source
if len(src_by_lines) < 11
else f"{src_by_lines[:5]}\n...\n{src_by_lines[-5:]}"
)
else:
src = "Cell contents not found."
return cls(timeout_err_msg.format(timeout=timeout, msg=msg, cell_contents=src))
class DeadKernelError(RuntimeError):
"""A dead kernel error."""
pass
class CellExecutionComplete(CellControlSignal):
"""
Used as a control signal for cell execution across execute_cell and
process_message function calls. Raised when all execution requests
are completed and no further messages are expected from the kernel
over zeromq channels.
"""
pass
class CellExecutionError(CellControlSignal):
"""
Custom exception to propagate exceptions that are raised during
notebook execution to the caller. This is mostly useful when
using nbconvert as a library, since it allows to deal with
failures gracefully.
"""
def __init__(self, traceback: str, ename: str, evalue: str) -> None:
"""Initialize the error."""
super().__init__(traceback)
self.traceback = traceback
self.ename = ename
self.evalue = evalue
def __reduce__(self) -> tuple[Any]:
"""Reduce implementation."""
return type(self), (self.traceback, self.ename, self.evalue) # type:ignore[return-value]
def __str__(self) -> str:
"""Str repr."""
if self.traceback:
return self.traceback
else:
return f"{self.ename}: {self.evalue}"
@classmethod
def from_cell_and_msg(cls, cell: NotebookNode, msg: dict[str, Any]) -> CellExecutionError:
"""Instantiate from a code cell object and a message contents
(message is either execute_reply or error)
"""
# collect stream outputs for our error message
stream_outputs: list[str] = []
for output in cell.outputs:
if output["output_type"] == "stream":
stream_outputs.append(
stream_output_msg.format(name=output["name"], text=output["text"].rstrip())
)
if stream_outputs:
# add blank line before, trailing separator
# if there is any stream output to display
stream_outputs.insert(0, "")
stream_outputs.append("------------------")
stream_output: str = "\n".join(stream_outputs)
tb = "\n".join(msg.get("traceback", []) or [])
return cls(
exec_err_msg.format(
cell=cell,
stream_output=stream_output,
traceback=tb,
),
ename=msg.get("ename", "<Error>"),
evalue=msg.get("evalue", ""),
)
stream_output_msg: str = """\
----- {name} -----
{text}"""
exec_err_msg: str = """\
An error occurred while executing the following cell:
------------------
{cell.source}
------------------
{stream_output}
{traceback}
"""
timeout_err_msg: str = """\
A cell timed out while it was being executed, after {timeout} seconds.
The message was: {msg}.
Here is a preview of the cell contents:
-------------------
{cell_contents}
-------------------
"""
================================================
FILE: nbclient/jsonutil.py
================================================
"""Utilities to manipulate JSON objects."""
# NOTE: this is a copy of ipykernel/jsonutils.py (+blackified)
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import annotations
import math
import numbers
import re
import types
from binascii import b2a_base64
from datetime import datetime
from typing import Any
# -----------------------------------------------------------------------------
# Globals and constants
# -----------------------------------------------------------------------------
# timestamp formats
ISO8601 = "%Y-%m-%dT%H:%M:%S.%f"
ISO8601_PAT = re.compile(
r"^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(\.\d{1,6})?Z?([\+\-]\d{2}:?\d{2})?$"
)
# holy crap, strptime is not threadsafe.
# Calling it once at import seems to help.
datetime.strptime("2000-01-01", "%Y-%m-%d")
# -----------------------------------------------------------------------------
# Classes and functions
# -----------------------------------------------------------------------------
# constants for identifying png/jpeg data
PNG = b"\x89PNG\r\n\x1a\n"
# front of PNG base64-encoded
PNG64 = b"iVBORw0KG"
JPEG = b"\xff\xd8"
# front of JPEG base64-encoded
JPEG64 = b"/9"
# constants for identifying gif data
GIF_64 = b"R0lGODdh"
GIF89_64 = b"R0lGODlh"
# front of PDF base64-encoded
PDF64 = b"JVBER"
def encode_images(format_dict: dict[str, str]) -> dict[str, str]:
"""b64-encodes images in a displaypub format dict
Perhaps this should be handled in json_clean itself?
Parameters
----------
format_dict : dict
A dictionary of display data keyed by mime-type
Returns
-------
format_dict : dict
A copy of the same dictionary,
but binary image data ('image/png', 'image/jpeg' or 'application/pdf')
is base64-encoded.
"""
return format_dict
def json_clean(obj: Any) -> Any:
"""Clean an object to ensure it's safe to encode in JSON.
Atomic, immutable objects are returned unmodified. Sets and tuples are
converted to lists, lists are copied and dicts are also copied.
Note: dicts whose keys could cause collisions upon encoding (such as a dict
with both the number 1 and the string '1' as keys) will cause a ValueError
to be raised.
Parameters
----------
obj : any python object
Returns
-------
out : object
A version of the input which will not cause an encoding error when
encoded as JSON. Note that this function does not *encode* its inputs,
it simply sanitizes it so that there will be no encoding errors later.
"""
# types that are 'atomic' and ok in json as-is.
atomic_ok = (str, type(None))
# containers that we need to convert into lists
container_to_list = (tuple, set, types.GeneratorType)
# Since bools are a subtype of Integrals, which are a subtype of Reals,
# we have to check them in that order.
if isinstance(obj, bool):
return obj
if isinstance(obj, numbers.Integral):
# cast int to int, in case subclasses override __str__ (e.g. boost enum, #4598)
return int(obj)
if isinstance(obj, numbers.Real):
# cast out-of-range floats to their reprs
if math.isnan(obj) or math.isinf(obj):
return repr(obj)
return float(obj)
if isinstance(obj, atomic_ok):
return obj
if isinstance(obj, bytes):
return b2a_base64(obj).decode("ascii")
if isinstance(obj, container_to_list) or (
hasattr(obj, "__iter__") and hasattr(obj, "__next__")
):
obj = list(obj)
if isinstance(obj, list):
return [json_clean(x) for x in obj]
if isinstance(obj, dict):
# First, validate that the dict won't lose data in conversion due to
# key collisions after stringification. This can happen with keys like
# True and 'true' or 1 and '1', which collide in JSON.
nkeys = len(obj)
nkeys_collapsed = len(set(map(str, obj)))
if nkeys != nkeys_collapsed:
raise ValueError(
"dict cannot be safely converted to JSON: "
"key collision would lead to dropped values"
)
# If all OK, proceed by making the new dict that will be json-safe
out = {}
for k, v in iter(obj.items()):
out[str(k)] = json_clean(v)
return out
if isinstance(obj, datetime):
return obj.strftime(ISO8601)
# we don't understand it, it's probably an unserializable object
raise ValueError("Can't clean for JSON: %r" % obj)
================================================
FILE: nbclient/output_widget.py
================================================
"""An output widget mimic."""
from __future__ import annotations
from typing import Any
from jupyter_client.client import KernelClient
from nbformat import NotebookNode
from nbformat.v4 import output_from_msg
from .jsonutil import json_clean
class OutputWidget:
"""This class mimics a front end output widget"""
def __init__(
self, comm_id: str, state: dict[str, Any], kernel_client: KernelClient, executor: Any
) -> None:
"""Initialize the widget."""
self.comm_id: str = comm_id
self.state: dict[str, Any] = state
self.kernel_client: KernelClient = kernel_client
self.executor = executor
self.topic: bytes = ("comm-%s" % self.comm_id).encode("ascii")
self.outputs: list[NotebookNode] = self.state["outputs"]
self.clear_before_next_output: bool = False
def clear_output(self, outs: list[NotebookNode], msg: dict[str, Any], cell_index: int) -> None:
"""Clear output."""
self.parent_header = msg["parent_header"]
content = msg["content"]
if content.get("wait"):
self.clear_before_next_output = True
else:
self.outputs = []
# sync back the state to the kernel
self.sync_state()
if hasattr(self.executor, "widget_state"):
# sync the state to the nbconvert state as well, since that is used for testing
self.executor.widget_state[self.comm_id]["outputs"] = self.outputs
def sync_state(self) -> None:
"""Sync state."""
state = {"outputs": self.outputs}
msg = {"method": "update", "state": state, "buffer_paths": []}
self.send(msg)
def _publish_msg(
self,
msg_type: str,
data: dict[str, Any] | None = None,
metadata: dict[str, Any] | None = None,
buffers: list[Any] | None = None,
**keys: Any,
) -> None:
"""Helper for sending a comm message on IOPub"""
data = {} if data is None else data
metadata = {} if metadata is None else metadata
content = json_clean(dict(data=data, comm_id=self.comm_id, **keys))
msg = self.kernel_client.session.msg(
msg_type, content=content, parent=self.parent_header, metadata=metadata
)
self.kernel_client.shell_channel.send(msg)
def send(
self,
data: dict[str, Any] | None = None,
metadata: dict[str, Any] | None = None,
buffers: list[Any] | None = None,
) -> None:
"""Send a comm message."""
self._publish_msg("comm_msg", data=data, metadata=metadata, buffers=buffers)
def output(
self, outs: list[NotebookNode], msg: dict[str, Any], display_id: str | None, cell_index: int
) -> None:
"""Handle output."""
if self.clear_before_next_output:
self.outputs = []
self.clear_before_next_output = False
self.parent_header = msg["parent_header"]
output = output_from_msg(msg) # type:ignore[no-untyped-call]
if self.outputs:
# try to coalesce/merge output text
last_output = self.outputs[-1]
if (
last_output["output_type"] == "stream"
and output["output_type"] == "stream"
and last_output["name"] == output["name"]
):
last_output["text"] += output["text"]
else:
self.outputs.append(output)
else:
self.outputs.append(output)
self.sync_state()
if hasattr(self.executor, "widget_state"):
# sync the state to the nbconvert state as well, since that is used for testing
self.executor.widget_state[self.comm_id]["outputs"] = self.outputs
def set_state(self, state: dict[str, Any]) -> None:
"""Set the state."""
if "msg_id" in state:
msg_id = state.get("msg_id")
if msg_id:
self.executor.register_output_hook(msg_id, self)
self.msg_id = msg_id
else:
self.executor.remove_output_hook(self.msg_id, self)
self.msg_id = msg_id
def handle_msg(self, msg: dict[str, Any]) -> None:
"""Handle a message."""
content = msg["content"]
comm_id = content["comm_id"]
if comm_id != self.comm_id:
raise AssertionError("Mismatched comm id")
data = content["data"]
if "state" in data:
self.set_state(data["state"])
================================================
FILE: nbclient/py.typed
================================================
================================================
FILE: nbclient/util.py
================================================
"""General utility methods"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import annotations
import inspect
from collections.abc import Callable
from typing import Any
from jupyter_core.utils import ensure_async, run_sync
__all__ = ["ensure_async", "run_sync", "run_hook"]
async def run_hook(hook: Callable[..., Any] | None, **kwargs: Any) -> None:
"""Run a hook callback."""
if hook is None:
return
res = hook(**kwargs)
if inspect.isawaitable(res):
await res
================================================
FILE: pyproject.toml
================================================
[build-system]
requires = [
"hatchling>=1.10.0",
]
build-backend = "hatchling.build"
[project]
name = "nbclient"
dynamic = [
"version",
]
description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor."
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.10.0"
authors = [
{ name = "Jupyter Development Team", email = "jupyter@googlegroups.com" },
]
keywords = [
"executor",
"jupyter",
"notebook",
"pipeline",
]
classifiers = [
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
dependencies = [
"jupyter_client>=6.1.12",
"jupyter_core>=4.12,!=5.0.*",
"nbformat>=5.1.3",
"traitlets>=5.4",
]
[project.optional-dependencies]
test = [
"flaky",
"ipykernel>=6.19.3",
"ipython",
"ipywidgets",
"nbconvert>=7.1.0",
"pytest-asyncio >=1.3.0",
"pytest-cov>=4.0",
"pytest>=9.0.1,<10",
"testpath",
"xmltodict",
]
docs = [
"autodoc-traits",
"mock",
"moto",
"myst-parser",
"sphinx-book-theme",
"sphinxcontrib_spelling",
"sphinx>=1.7",
"nbclient[test]",
]
dev = [
"pre-commit",
]
[project.scripts]
jupyter-execute = "nbclient.cli:main"
[project.urls]
Documentation = "https://nbclient.readthedocs.io"
Funding = "https://numfocus.org/"
Homepage = "https://jupyter.org"
Source = "https://github.com/jupyter/nbclient"
Tracker = "https://github.com/jupyter/nbclient/issues"
[tool.hatch.version]
path = "nbclient/_version.py"
[tool.hatch.build.targets.sdist]
include = [
"/nbclient",
"/tests"
]
[tool.hatch.envs.docs]
features = ["docs"]
[tool.hatch.envs.docs.scripts]
build = "make -C docs html SPHINXOPTS='-W'"
[tool.hatch.envs.test]
features = ["test"]
[tool.hatch.envs.test.scripts]
test = "python -m pytest -vv {args}"
nowarn = "test -W default {args}"
[tool.hatch.envs.cov]
features = ["test"]
dependencies = ["coverage[toml]", "pytest-cov"]
[tool.hatch.envs.cov.scripts]
test = "python -m pytest -vv --cov nbclient --cov-branch --cov-report term-missing:skip-covered {args}"
nowarn = "test -W default {args}"
[tool.hatch.envs.lint]
detached = true
dependencies = ["pre-commit"]
[tool.hatch.envs.lint.scripts]
build = [
"pre-commit run --all-files ruff",
"pre-commit run --all-files ruff-format"
]
[tool.hatch.envs.typing]
dependencies = [ "pre-commit"]
detached = true
[tool.hatch.envs.typing.scripts]
test = "pre-commit run --all-files --hook-stage manual mypy"
[tool.pytest.ini_options]
minversion = "6.0"
xfail_strict = true
log_cli_level = "info"
addopts = [
"-ra", "--durations=10", "--color=yes", "--doctest-modules",
"--showlocals", "--strict-markers", "--strict-config"
]
testpaths = ["tests"]
filterwarnings= [
# Fail on warnings
"error",
"module:Jupyter is migrating its paths:DeprecationWarning",
"module:unclosed <socket.socket:ResourceWarning",
"module:There is no current event loop:DeprecationWarning",
"module:unclosed event loop:ResourceWarning",
"module:Unclosed socket <zmq:ResourceWarning",
"module:zmq.eventloop.ioloop is deprecated:DeprecationWarning",
"module:subprocess .* is still running:ResourceWarning",
"module:Unclosed context <zmq:ResourceWarning",
"module:datetime.datetime.utc:DeprecationWarning",
"module:'asyncio.WindowsSelectorEventLoopPolicy' is deprecated and slated for removal in Python 3.16:DeprecationWarning",
"module:'asyncio.set_event_loop_policy' is deprecated and slated for removal in Python 3.16:DeprecationWarning",
]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
[tool.coverage.run]
relative_files = true
source = ["nbclient"]
[tool.mypy]
files = "nbclient"
python_version = "3.10"
strict = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = true
[[tool.mypy.overrides]]
module = [
"async_generator.*",
"testpath",
"xmltodict",
]
ignore_missing_imports = true
[tool.ruff]
line-length = 100
[tool.ruff.lint]
select = [
"A", "B", "C", "E", "F", "FBT", "I", "N", "Q", "RUF", "S", "T",
"UP", "W", "YTT",
]
ignore = [
# Q000 Single quotes found but double quotes preferred
"Q000",
# FBT001 Boolean positional arg in function definition
"FBT001", "FBT002", "FBT003",
# C901 `async_setup_kernel` is too complex (12)
"C901",
]
[tool.ruff.lint.per-file-ignores]
# S101 Use of `assert` detected
"tests/*" = ["S101"]
"nbclient/client.py" = ["S101"]
"*.ipynb" = ["B", "E402", "T201", "F821", "A001", "E722", "S110", "RUF001"]
[tool.interrogate]
ignore-init-module=true
ignore-private=true
ignore-semiprivate=true
ignore-property-decorators=true
ignore-nested-functions=true
ignore-nested-classes=true
fail-under=100
exclude = ["tests", "docs"]
[tool.repo-review]
ignore = ["PY005", "PY007", "GH102"]
================================================
FILE: tests/__init__.py
================================================
================================================
FILE: tests/base.py
================================================
import unittest
from nbformat import v4 as nbformat
# mypy: disable-error-code="no-untyped-call,no-untyped-def"
class NBClientTestsBase(unittest.TestCase):
def build_notebook(self, with_json_outputs=False):
"""Build a notebook in memory for use with NotebookClient tests"""
outputs = [
nbformat.new_output("stream", name="stdout", text="a"),
nbformat.new_output("display_data", data={"text/plain": "b"}),
nbformat.new_output("stream", name="stdout", text="c"),
nbformat.new_output("stream", name="stdout", text="d"),
nbformat.new_output("stream", name="stderr", text="e"),
nbformat.new_output("stream", name="stderr", text="f"),
nbformat.new_output("display_data", data={"image/png": "Zw=="}), # g
nbformat.new_output("display_data", data={"application/pdf": "aA=="}), # h
]
if with_json_outputs:
outputs.extend(
[
nbformat.new_output("display_data", data={"application/json": [1, 2, 3]}), # j
nbformat.new_output(
"display_data", data={"application/json": {"a": 1, "c": {"b": 2}}}
), # k
nbformat.new_output("display_data", data={"application/json": "abc"}), # l
nbformat.new_output("display_data", data={"application/json": 15.03}), # m
]
)
cells = [
nbformat.new_code_cell(source="$ e $", execution_count=1, outputs=outputs),
nbformat.new_markdown_cell(source="$ e $"),
]
return nbformat.new_notebook(cells=cells)
def build_resources(self):
"""Build an empty resources dictionary."""
return {"metadata": {}}
@classmethod
def merge_dicts(cls, *dict_args):
# Because this is annoying to do inline
outcome = {}
for d in dict_args:
outcome.update(d)
return outcome
================================================
FILE: tests/conftest.py
================================================
import asyncio
import os
# This is important for ipykernel to show the same string
# instead of randomly generated file names in outputs.
# See: https://github.com/ipython/ipykernel/blob/360685c6/ipykernel/compiler.py#L50-L55
os.environ["IPYKERNEL_CELL_NAME"] = "<IPY-INPUT>"
if os.name == "nt" and hasattr(asyncio, "WindowsSelectorEventLoopPolicy"):
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
================================================
FILE: tests/fake_kernelmanager.py
================================================
from jupyter_client.manager import AsyncKernelManager
# mypy: disable-error-code="no-untyped-call,no-untyped-def"
class FakeCustomKernelManager(AsyncKernelManager):
expected_methods = {"__init__": 0, "client": 0, "start_kernel": 0} # noqa
def __init__(self, *args, **kwargs):
self.log.info("FakeCustomKernelManager initialized")
self.expected_methods["__init__"] += 1
super().__init__(*args, **kwargs)
async def start_kernel(self, *args, **kwargs):
self.log.info("FakeCustomKernelManager started a kernel")
self.expected_methods["start_kernel"] += 1
return await super().start_kernel(*args, **kwargs)
def client(self, *args, **kwargs):
self.log.info("FakeCustomKernelManager created a client")
self.expected_methods["client"] += 1
return super().client(*args, **kwargs)
================================================
FILE: tests/files/Autokill.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import signal\n",
"\n",
"pid = os.getpid()\n",
"os.kill(pid, signal.SIGTERM)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: tests/files/Check History in Memory.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from IPython import get_ipython"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"ip = get_ipython()\n",
"assert ip.history_manager.hist_file == \":memory:\""
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}
================================================
FILE: tests/files/Clear Output.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import clear_output"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"9\n"
]
}
],
"source": [
"for i in range(10):\n",
" clear_output()\n",
" print(i)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"print(\"Hello world\")\n",
"clear_output()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello world"
]
}
],
"source": [
"print(\"Hello world\", end=\"\")\n",
"clear_output(wait=True) # no output after this"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"world"
]
}
],
"source": [
"print(\"Hello\", end=\"\")\n",
"clear_output(wait=True) # here we have new output after wait=True\n",
"print(\"world\", end=\"\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Hello world'"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"handle0 = display(\"Hello world\", display_id=\"id0\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'world'"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"handle1 = display(\"Hello\", display_id=\"id1\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"handle1.update(\"world\")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"handle2 = display(\"Hello world\", display_id=\"id2\")\n",
"clear_output() # clears all output, also with display_ids"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Hello world'"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"handle3 = display(\"Hello world\", display_id=\"id3\")\n",
"clear_output(wait=True)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"world"
]
}
],
"source": [
"handle4 = display(\"Hello\", display_id=\"id4\")\n",
"clear_output(wait=True)\n",
"print(\"world\", end=\"\")"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"handle4.update(\"Hello world\") # it is cleared, so it should not show up in the above cell"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
================================================
FILE: tests/files/Disable Stdin.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"try:\n",
" input = raw_input\n",
"except:\n",
" pass\n",
"\n",
"name = input(\"name: \")"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: tests/files/Empty Cell.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Test that executing skips over an empty cell."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Code 1'"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"Code 1\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Code 2'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"Code 2\""
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
================================================
FILE: tests/files/Error.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "d200673b",
"metadata": {},
"outputs": [
{
"ename": "ZeroDivisionError",
"evalue": "division by zero",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m/tmp/ipykernel_1277493/182040962.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m0\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mZeroDivisionError\u001b[0m: division by zero"
]
}
],
"source": [
"0 / 0"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
================================================
FILE: tests/files/Factorials.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"i, j = 1, 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2\n",
"3\n",
"5\n",
"8\n",
"13\n",
"21\n",
"34\n",
"55\n",
"89\n",
"144\n"
]
}
],
"source": [
"for m in range(10):\n",
" i, j = j, i + j\n",
" print(j)"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: tests/files/HelloWorld.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hello World\n"
]
}
],
"source": [
"print(\"Hello World\")"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: tests/files/Inline Image.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from IPython.display import Image"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": [
"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\n"
],
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Image(\"python.png\")"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: tests/files/Interrupt.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "KeyboardInterrupt",
"evalue": "",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-1-31d18a52bf41>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyboardInterrupt\u001b[0m: "
]
}
],
"source": [
"while True: continue"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"done\n"
]
}
],
"source": [
"print(\"done\")"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: tests/files/JupyterWidgets.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f46f26da84b54255bccc3a69d7eb08de",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Label(value='Hello World')"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import ipywidgets\n",
"\n",
"label = ipywidgets.Label(\"Hello World\")\n",
"display(label)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# it should also handle custom msg'es\n",
"label.send({\"msg\": \"Hello\"})"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {
"8273e8fe9d9941a4a63c062158e0a630": {
"model_module": "@jupyter-widgets/controls",
"model_module_version": "1.4.0",
"model_name": "DescriptionStyleModel",
"state": {
"description_width": ""
}
},
"a72770a4f541425f8fe85833a3dc2a8e": {
"model_module": "@jupyter-widgets/controls",
"model_module_version": "1.4.0",
"model_name": "LabelModel",
"state": {
"context_menu": null,
"layout": "IPY_MODEL_dec20f599109458ca607b1df5959469b",
"style": "IPY_MODEL_8273e8fe9d9941a4a63c062158e0a630",
"value": "Hello World"
}
},
"dec20f599109458ca607b1df5959469b": {
"model_module": "@jupyter-widgets/base",
"model_module_version": "1.1.0",
"mo
gitextract_xrhwfx_4/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── check-release.yml
│ ├── main.yml
│ ├── prep-release.yml
│ ├── publish-changelog.yml
│ └── publish-release.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── RELEASING.md
├── binder/
│ ├── empty_notebook.ipynb
│ ├── environment.yml
│ └── run_nbclient.ipynb
├── docs/
│ ├── Makefile
│ ├── UPDATE.md
│ ├── _static/
│ │ └── custom.css
│ ├── autogen_config.py
│ ├── client.rst
│ ├── conf.py
│ ├── index.rst
│ ├── installation.rst
│ ├── make.bat
│ └── reference/
│ ├── index.rst
│ ├── modules.rst
│ └── nbclient.rst
├── nbclient/
│ ├── __init__.py
│ ├── _version.py
│ ├── cli.py
│ ├── client.py
│ ├── exceptions.py
│ ├── jsonutil.py
│ ├── output_widget.py
│ ├── py.typed
│ └── util.py
├── pyproject.toml
└── tests/
├── __init__.py
├── base.py
├── conftest.py
├── fake_kernelmanager.py
├── files/
│ ├── Autokill.ipynb
│ ├── Check History in Memory.ipynb
│ ├── Clear Output.ipynb
│ ├── Disable Stdin.ipynb
│ ├── Empty Cell.ipynb
│ ├── Error.ipynb
│ ├── Factorials.ipynb
│ ├── HelloWorld.ipynb
│ ├── Inline Image.ipynb
│ ├── Interrupt.ipynb
│ ├── JupyterWidgets.ipynb
│ ├── Other Comms.ipynb
│ ├── Output.ipynb
│ ├── Parallel Execute A.ipynb
│ ├── Parallel Execute B.ipynb
│ ├── SVG.ipynb
│ ├── Skip Exceptions with Cell Tags.ipynb
│ ├── Skip Exceptions.ipynb
│ ├── Skip Execution with Cell Tag.ipynb
│ ├── Sleep1s.ipynb
│ ├── Unicode.ipynb
│ ├── UnicodePy3.ipynb
│ └── update-display-id.ipynb
├── test_cli.py
├── test_client.py
└── test_util.py
SYMBOL INDEX (175 symbols across 12 files)
FILE: docs/conf.py
function setup (line 189) | def setup(app):
FILE: nbclient/cli.py
class NbClientApp (line 48) | class NbClientApp(JupyterApp):
method _log_level_default (line 135) | def _log_level_default(self) -> int:
method initialize (line 139) | def initialize(self, argv: list[str] | None = None) -> None:
method get_notebooks (line 163) | def get_notebooks(self) -> list[str]:
method run_notebook (line 175) | def run_notebook(self, notebook_path: str) -> None:
FILE: nbclient/client.py
function timestamp (line 40) | def timestamp(msg: dict[str, t.Any] | None = None) -> str:
class NotebookClient (line 60) | class NotebookClient(LoggingConfigurable):
method _kernel_manager_class_default (line 388) | def _kernel_manager_class_default(self) -> type[KernelManager]:
method __init__ (line 445) | def __init__(self, nb: NotebookNode, km: KernelManager | None = None, ...
method reset_execution_trackers (line 470) | def reset_execution_trackers(self) -> None:
method create_kernel_manager (line 483) | def create_kernel_manager(self) -> KernelManager:
method _async_cleanup_kernel (line 503) | async def _async_cleanup_kernel(self) -> None:
method async_start_new_kernel (line 524) | async def async_start_new_kernel(self, **kwargs: t.Any) -> None:
method async_start_new_kernel_client (line 554) | async def async_start_new_kernel_client(self) -> KernelClient:
method setup_kernel (line 582) | def setup_kernel(self, **kwargs: t.Any) -> t.Generator[None, None, None]:
method async_setup_kernel (line 612) | async def async_setup_kernel(self, **kwargs: t.Any) -> t.AsyncGenerato...
method async_execute (line 669) | async def async_execute(self, reset_kc: bool = False, **kwargs: t.Any)...
method set_widgets_metadata (line 718) | def set_widgets_metadata(self) -> None:
method _update_display_id (line 739) | def _update_display_id(self, display_id: str, msg: dict[str, t.Any]) -...
method _async_poll_for_reply (line 761) | async def _async_poll_for_reply(
method _async_poll_output_msg (line 808) | async def _async_poll_output_msg(
method _async_poll_kernel_alive (line 821) | async def _async_poll_kernel_alive(self) -> None:
method _get_timeout (line 831) | def _get_timeout(self, cell: NotebookNode | None) -> int | None:
method _async_handle_timeout (line 842) | async def _async_handle_timeout(
method _async_check_alive (line 860) | async def _async_check_alive(self) -> None:
method async_wait_for_reply (line 866) | async def async_wait_for_reply(
method _passed_deadline (line 894) | def _passed_deadline(self, deadline: int | None) -> bool:
method _check_raise_for_error (line 899) | async def _check_raise_for_error(
method async_execute_cell (line 920) | async def async_execute_cell(
method process_message (line 1069) | def process_message(
method output (line 1138) | def output(
method clear_output (line 1182) | def clear_output(
method clear_display_id_mapping (line 1204) | def clear_display_id_mapping(self, cell_index: int) -> None:
method handle_comm_msg (line 1210) | def handle_comm_msg(
method _serialize_widget_state (line 1245) | def _serialize_widget_state(self, state: dict[str, t.Any]) -> dict[str...
method _get_buffer_data (line 1254) | def _get_buffer_data(self, msg: dict[str, t.Any]) -> list[dict[str, st...
method register_output_hook (line 1268) | def register_output_hook(self, msg_id: str, hook: OutputWidget) -> None:
method remove_output_hook (line 1277) | def remove_output_hook(self, msg_id: str, hook: OutputWidget) -> None:
method on_comm_open_jupyter_widget (line 1284) | def on_comm_open_jupyter_widget(self, msg: dict[str, t.Any]) -> t.Any ...
function execute (line 1298) | def execute(
FILE: nbclient/exceptions.py
class CellControlSignal (line 9) | class CellControlSignal(Exception): # noqa
class CellTimeoutError (line 19) | class CellTimeoutError(TimeoutError, CellControlSignal):
method error_from_timeout_and_cell (line 25) | def error_from_timeout_and_cell(
class DeadKernelError (line 41) | class DeadKernelError(RuntimeError):
class CellExecutionComplete (line 47) | class CellExecutionComplete(CellControlSignal):
class CellExecutionError (line 58) | class CellExecutionError(CellControlSignal):
method __init__ (line 66) | def __init__(self, traceback: str, ename: str, evalue: str) -> None:
method __reduce__ (line 73) | def __reduce__(self) -> tuple[Any]:
method __str__ (line 77) | def __str__(self) -> str:
method from_cell_and_msg (line 85) | def from_cell_and_msg(cls, cell: NotebookNode, msg: dict[str, Any]) ->...
FILE: nbclient/jsonutil.py
function encode_images (line 50) | def encode_images(format_dict: dict[str, str]) -> dict[str, str]:
function json_clean (line 73) | def json_clean(obj: Any) -> Any:
FILE: nbclient/output_widget.py
class OutputWidget (line 13) | class OutputWidget:
method __init__ (line 16) | def __init__(
method clear_output (line 28) | def clear_output(self, outs: list[NotebookNode], msg: dict[str, Any], ...
method sync_state (line 42) | def sync_state(self) -> None:
method _publish_msg (line 48) | def _publish_msg(
method send (line 65) | def send(
method output (line 74) | def output(
method set_state (line 102) | def set_state(self, state: dict[str, Any]) -> None:
method handle_msg (line 113) | def handle_msg(self, msg: dict[str, Any]) -> None:
FILE: nbclient/util.py
function run_hook (line 16) | async def run_hook(hook: Callable[..., Any] | None, **kwargs: Any) -> None:
FILE: tests/base.py
class NBClientTestsBase (line 8) | class NBClientTestsBase(unittest.TestCase):
method build_notebook (line 9) | def build_notebook(self, with_json_outputs=False):
method build_resources (line 41) | def build_resources(self):
method merge_dicts (line 46) | def merge_dicts(cls, *dict_args):
FILE: tests/fake_kernelmanager.py
class FakeCustomKernelManager (line 6) | class FakeCustomKernelManager(AsyncKernelManager):
method __init__ (line 9) | def __init__(self, *args, **kwargs):
method start_kernel (line 14) | async def start_kernel(self, *args, **kwargs):
method client (line 19) | def client(self, *args, **kwargs):
FILE: tests/test_cli.py
function jupyterapp (line 19) | def jupyterapp():
function client (line 25) | def client():
function writer (line 31) | def writer():
function reader (line 37) | def reader():
function path_open (line 43) | def path_open():
function test_mult (line 58) | def test_mult(input_names, relative, inplace, jupyterapp, client, reader...
function test_output (line 103) | def test_output(input_names, relative, output_base, jupyterapp, client, ...
function test_bad_output_dir (line 156) | def test_bad_output_dir(jupyterapp, client, reader, writer, path_open):
function test_cli_simple (line 173) | def test_cli_simple():
function test_no_notebooks (line 180) | def test_no_notebooks(jupyterapp):
FILE: tests/test_client.py
function get_executor_with_hooks (line 66) | def get_executor_with_hooks(nb=None, executor=None, async_hooks=False):
class AsyncMock (line 92) | class AsyncMock(Mock):
function make_future (line 96) | def make_future(obj: Any) -> asyncio.Future[Any]:
function normalize_base64 (line 107) | def normalize_base64(b64_text):
function run_notebook (line 116) | def run_notebook(filename, opts, resources=None):
function run_notebook_wrapper (line 144) | def run_notebook_wrapper(args):
function async_run_notebook (line 150) | async def async_run_notebook(filename, opts, resources=None):
function prepare_cell_mocks (line 175) | def prepare_cell_mocks(*messages_input, reply_msg=None):
function normalize_output (line 252) | def normalize_output(output):
function assert_notebooks_equal (line 281) | def assert_notebooks_equal(expected, actual):
function notebook_resources (line 302) | def notebook_resources():
function filter_messages_on_error_output (line 310) | def filter_messages_on_error_output(err_output):
function test_run_all_notebooks (line 350) | def test_run_all_notebooks(input_name, opts):
function test_parallel_notebooks (line 358) | def test_parallel_notebooks(capfd, tmpdir):
function test_many_parallel_notebooks (line 385) | def test_many_parallel_notebooks(capfd):
function test_async_parallel_notebooks (line 412) | def test_async_parallel_notebooks(capfd, tmpdir):
function test_many_async_parallel_notebooks (line 439) | def test_many_async_parallel_notebooks(capfd):
function test_execution_timing (line 464) | def test_execution_timing():
function test_synchronous_setup_kernel (line 494) | def test_synchronous_setup_kernel():
function test_startnewkernel_with_kernelmanager (line 504) | def test_startnewkernel_with_kernelmanager():
function test_start_new_kernel_history_file_setting (line 519) | def test_start_new_kernel_history_file_setting():
function test_start_new_kernel_client_cleans_up_kernel_on_failure (line 542) | def test_start_new_kernel_client_cleans_up_kernel_on_failure():
class TestExecute (line 574) | class TestExecute(NBClientTestsBase):
method test_constructor (line 579) | def test_constructor(self):
method test_populate_language_info (line 582) | def test_populate_language_info(self):
method test_empty_path (line 588) | def test_empty_path(self):
method test_empty_kernel_name (line 600) | def test_empty_kernel_name(self):
method test_disable_stdin (line 613) | def test_disable_stdin(self):
method test_timeout (line 634) | def test_timeout(self):
method test_timeout_func (line 653) | def test_timeout_func(self):
method test_sync_kernel_manager (line 665) | def test_sync_kernel_manager(self):
method test_kernel_death_after_timeout (line 677) | def test_kernel_death_after_timeout(self):
method test_kernel_death_during_execution (line 701) | def test_kernel_death_during_execution(self):
method test_allow_errors (line 714) | def test_allow_errors(self):
method test_force_raise_errors (line 731) | def test_force_raise_errors(self):
method test_reset_kernel_client (line 759) | def test_reset_kernel_client(self):
method test_cleanup_kernel_client (line 784) | def test_cleanup_kernel_client(self):
method test_custom_kernel_manager (line 804) | def test_custom_kernel_manager(self):
method test_process_message_wrapper (line 833) | def test_process_message_wrapper(self):
method test_execute_function (line 855) | def test_execute_function(self):
method test_widgets (line 866) | def test_widgets(self):
method test_execution_hook (line 893) | def test_execution_hook(self):
method test_error_execution_hook_error (line 908) | def test_error_execution_hook_error(self):
method test_error_notebook_hook (line 924) | def test_error_notebook_hook(self):
method test_async_execution_hook (line 940) | def test_async_execution_hook(self):
method test_error_async_execution_hook (line 955) | def test_error_async_execution_hook(self):
class TestRunCell (line 972) | class TestRunCell(NBClientTestsBase):
method test_idle_message (line 976) | def test_idle_message(self, executor, cell_mock, message_mock):
method test_message_for_wrong_parent (line 991) | def test_message_for_wrong_parent(self, executor, cell_mock, message_m...
method test_busy_message (line 1005) | def test_busy_message(self, executor, cell_mock, message_mock):
method test_deadline_exec_reply (line 1024) | def test_deadline_exec_reply(self, executor, cell_mock, message_mock):
method test_deadline_iopub (line 1047) | def test_deadline_iopub(self, executor, cell_mock, message_mock):
method test_eventual_deadline_iopub (line 1067) | def test_eventual_deadline_iopub(self, executor, cell_mock, message_mo...
method test_execute_input_message (line 1096) | def test_execute_input_message(self, executor, cell_mock, message_mock):
method test_stream_messages (line 1115) | def test_stream_messages(self, executor, cell_mock, message_mock):
method test_clear_output_message (line 1136) | def test_clear_output_message(self, executor, cell_mock, message_mock):
method test_clear_output_wait_message (line 1155) | def test_clear_output_wait_message(self, executor, cell_mock, message_...
method test_clear_output_wait_then_message_message (line 1181) | def test_clear_output_wait_then_message_message(self, executor, cell_m...
method test_clear_output_wait_then_update_display_message (line 1207) | def test_clear_output_wait_then_update_display_message(self, executor,...
method test_execution_count_message (line 1223) | def test_execution_count_message(self, executor, cell_mock, message_mo...
method test_execution_count_message_ignored_on_override (line 1238) | def test_execution_count_message_ignored_on_override(self, executor, c...
method test_execution_count_with_stream_message (line 1253) | def test_execution_count_with_stream_message(self, executor, cell_mock...
method test_widget_comm_message (line 1268) | def test_widget_comm_message(self, executor, cell_mock, message_mock):
method test_widget_comm_buffer_message_single (line 1289) | def test_widget_comm_buffer_message_single(self, executor, cell_mock, ...
method test_widget_comm_buffer_messages (line 1320) | def test_widget_comm_buffer_messages(self, executor, cell_mock, messag...
method test_unknown_comm_message (line 1345) | def test_unknown_comm_message(self, executor, cell_mock, message_mock):
method test_execute_result_message (line 1366) | def test_execute_result_message(self, executor, cell_mock, message_mock):
method test_execute_result_with_display_message (line 1395) | def test_execute_result_with_display_message(self, executor, cell_mock...
method test_display_data_without_id_message (line 1418) | def test_display_data_without_id_message(self, executor, cell_mock, me...
method test_display_data_message (line 1444) | def test_display_data_message(self, executor, cell_mock, message_mock):
method test_display_data_same_id_message (line 1487) | def test_display_data_same_id_message(self, executor, cell_mock, messa...
method test_update_display_data_without_id_message (line 1518) | def test_update_display_data_without_id_message(self, executor, cell_m...
method test_update_display_data_mismatch_id_message (line 1547) | def test_update_display_data_mismatch_id_message(self, executor, cell_...
method test_update_display_data_message (line 1581) | def test_update_display_data_message(self, executor, cell_mock, messag...
method test_error_message (line 1602) | def test_error_message(self, executor, cell_mock, message_mock):
method test_error_and_error_status_messages (line 1624) | def test_error_and_error_status_messages(self, executor, cell_mock, me...
method test_error_message_only (line 1648) | def test_error_message_only(self, executor, cell_mock, message_mock):
method test_allow_errors (line 1667) | def test_allow_errors(self, executor, cell_mock, message_mock):
method test_allow_error_names (line 1685) | def test_allow_error_names(self, executor, cell_mock, message_mock):
method test_raises_exception_tag (line 1703) | def test_raises_exception_tag(self, executor, cell_mock, message_mock):
method test_non_code_cell (line 1721) | def test_non_code_cell(self, executor, cell_mock, message_mock):
method test_no_source (line 1739) | def test_no_source(self, executor, cell_mock, message_mock):
method test_cell_hooks (line 1756) | def test_cell_hooks(self, executor, cell_mock, message_mock):
method test_error_cell_hooks (line 1783) | def test_error_cell_hooks(self, executor, cell_mock, message_mock):
method test_non_code_cell_hooks (line 1808) | def test_non_code_cell_hooks(self, executor, cell_mock, message_mock):
method test_async_cell_hooks (line 1822) | def test_async_cell_hooks(self, executor, cell_mock, message_mock):
method test_error_async_cell_hooks (line 1849) | def test_error_async_cell_hooks(self, executor, cell_mock, message_mock):
method test_coalesce_streams (line 1888) | def test_coalesce_streams(self, executor, cell_mock, message_mock):
FILE: tests/test_util.py
function some_async_function (line 13) | async def some_async_function():
function test_nested_asyncio_with_existing_ioloop (line 18) | def test_nested_asyncio_with_existing_ioloop():
function test_nested_asyncio_with_no_ioloop (line 29) | def test_nested_asyncio_with_no_ioloop():
function test_nested_asyncio_with_tornado (line 34) | def test_nested_asyncio_with_tornado():
function test_run_hook_sync (line 59) | async def test_run_hook_sync():
function test_run_hook_async (line 66) | async def test_run_hook_async():
Condensed preview — 69 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (333K chars).
[
{
"path": ".github/dependabot.yml",
"chars": 346,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directory: \"/\"\n schedule:\n interval: \"weekly\"\n "
},
{
"path": ".github/workflows/check-release.yml",
"chars": 589,
"preview": "name: Check Release\non:\n push:\n branches: [\"*\"]\n pull_request:\n branches: [\"*\"]\n release:\n types: [published"
},
{
"path": ".github/workflows/main.yml",
"chars": 4097,
"preview": "name: CI\n\non:\n push:\n branches: [\"main\"]\n pull_request:\n workflow_dispatch:\n schedule:\n - cron: \"0 8 * * *\"\n\nd"
},
{
"path": ".github/workflows/prep-release.yml",
"chars": 1689,
"preview": "name: \"Step 1: Prep Release\"\non:\n workflow_dispatch:\n inputs:\n version_spec:\n description: \"New Version "
},
{
"path": ".github/workflows/publish-changelog.yml",
"chars": 928,
"preview": "name: \"Publish Changelog\"\non:\n release:\n types: [published]\n\n workflow_dispatch:\n inputs:\n branch:\n "
},
{
"path": ".github/workflows/publish-release.yml",
"chars": 1798,
"preview": "name: \"Step 2: Publish Release\"\non:\n workflow_dispatch:\n inputs:\n branch:\n description: \"The target bran"
},
{
"path": ".gitignore",
"chars": 1940,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": ".pre-commit-config.yaml",
"chars": 2411,
"preview": "ci:\n autoupdate_schedule: monthly\n autoupdate_commit_msg: \"chore: update pre-commit hooks\"\n\nrepos:\n - repo: https://g"
},
{
"path": ".readthedocs.yml",
"chars": 354,
"preview": "# .readthedocs.yml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html fo"
},
{
"path": "CHANGELOG.md",
"chars": 37652,
"preview": "# Changes in NBClient {#changelog}\n\n<!-- <START NEW CHANGELOG ENTRY> -->\n\n## 0.10.4\n\n([Full Changelog](https://github.co"
},
{
"path": "CONTRIBUTING.md",
"chars": 1221,
"preview": "# Contributing\n\nWe follow the [Jupyter Contribution Workflow](https://jupyter.readthedocs.io/en/latest/contributing/cont"
},
{
"path": "LICENSE",
"chars": 1534,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2020-, Jupyter Development Team\n\nAll rights reserved.\n\nRedistribution and use in sou"
},
{
"path": "README.md",
"chars": 3882,
"preview": "[](https://mybinder.org/v2/gh/jupyter/nbclient/main?filepath=binder%2Frun_"
},
{
"path": "RELEASING.md",
"chars": 640,
"preview": "# Releasing\n\n## Using `jupyter_releaser`\n\nThe recommended way to make a release is to use [`jupyter_releaser`](https://g"
},
{
"path": "binder/empty_notebook.ipynb",
"chars": 1859,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Show a pandas dataframe\"\n ]\n }"
},
{
"path": "binder/environment.yml",
"chars": 131,
"preview": "name: nbclient\nchannels:\n - conda-forge\ndependencies:\n - numpy\n - pandas\n - matplotlib\n - scrapbook\n - nbformat\n "
},
{
"path": "binder/run_nbclient.ipynb",
"chars": 2827,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": "
},
{
"path": "docs/Makefile",
"chars": 606,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHI"
},
{
"path": "docs/UPDATE.md",
"chars": 108,
"preview": "TODO: Figure out make options needed for non-api changes\n\n```\nsphinx-apidoc -f -o reference ../nbclient\n```\n"
},
{
"path": "docs/_static/custom.css",
"chars": 450,
"preview": "img.logo {\n width:100%\n}\n\n.right-next {\n float: right;\n max-width: 45%;\n overflow: auto;\n text-overflow: el"
},
{
"path": "docs/autogen_config.py",
"chars": 1051,
"preview": "#!/usr/bin/env python\n\"\"\"\nautogen_config.py\n\nCreate config_options.rst, a Sphinx documentation source file.\nDocuments th"
},
{
"path": "docs/client.rst",
"chars": 10822,
"preview": "Executing notebooks\n===================\n\n.. module:: nbclient.client.guide\n\nJupyter notebooks are often saved with outpu"
},
{
"path": "docs/conf.py",
"chars": 6043,
"preview": "#!/usr/bin/env python3\n#\n# nbclient documentation build configuration file, created by\n# sphinx-quickstart on Mon Jan 26"
},
{
"path": "docs/index.rst",
"chars": 2033,
"preview": "Welcome to nbclient\n===================\n\n.. image:: https://img.shields.io/github/stars/jupyter/nbclient?label=stars&sty"
},
{
"path": "docs/installation.rst",
"chars": 295,
"preview": "Installation\n============\n\nInstalling nbclient\n-------------------\n\nFrom the command line:\n\n.. code-block:: bash\n\n pyt"
},
{
"path": "docs/make.bat",
"chars": 776,
"preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-bu"
},
{
"path": "docs/reference/index.rst",
"chars": 190,
"preview": "Reference\n=========\n\nThis part of the documentation lists the full API reference of all public classes and functions.\n\n."
},
{
"path": "docs/reference/modules.rst",
"chars": 61,
"preview": "nbclient\n========\n\n.. toctree::\n :maxdepth: 4\n\n nbclient\n"
},
{
"path": "docs/reference/nbclient.rst",
"chars": 476,
"preview": "nbclient package\n================\n\nSubpackages\n-----------\n\nSubmodules\n----------\n\nnbclient.client module\n--------------"
},
{
"path": "nbclient/__init__.py",
"chars": 164,
"preview": "from ._version import __version__, version_info\nfrom .client import NotebookClient, execute\n\n__all__ = [\"__version__\", \""
},
{
"path": "nbclient/_version.py",
"chars": 463,
"preview": "\"\"\"Version info.\"\"\"\nfrom __future__ import annotations\n\nimport re\n\n__version__ = \"0.10.4\"\n\n# Build up version_info tuple"
},
{
"path": "nbclient/cli.py",
"chars": 6781,
"preview": "\"\"\"nbclient cli.\"\"\"\nfrom __future__ import annotations\n\nimport logging\nimport sys\nimport typing\nfrom pathlib import Path"
},
{
"path": "nbclient/client.py",
"chars": 49883,
"preview": "\"\"\"nbclient implementation.\"\"\"\nfrom __future__ import annotations\n\nimport asyncio\nimport atexit\nimport base64\nimport col"
},
{
"path": "nbclient/exceptions.py",
"chars": 4065,
"preview": "\"\"\"Exceptions for nbclient.\"\"\"\nfrom __future__ import annotations\n\nfrom typing import Any\n\nfrom nbformat import Notebook"
},
{
"path": "nbclient/jsonutil.py",
"chars": 4612,
"preview": "\"\"\"Utilities to manipulate JSON objects.\"\"\"\n\n# NOTE: this is a copy of ipykernel/jsonutils.py (+blackified)\n\n# Copyright"
},
{
"path": "nbclient/output_widget.py",
"chars": 4534,
"preview": "\"\"\"An output widget mimic.\"\"\"\nfrom __future__ import annotations\n\nfrom typing import Any\n\nfrom jupyter_client.client imp"
},
{
"path": "nbclient/py.typed",
"chars": 0,
"preview": ""
},
{
"path": "nbclient/util.py",
"chars": 571,
"preview": "\"\"\"General utility methods\"\"\"\n\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified B"
},
{
"path": "pyproject.toml",
"chars": 5415,
"preview": "[build-system]\nrequires = [\n \"hatchling>=1.10.0\",\n]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"nbclient\"\ndy"
},
{
"path": "tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/base.py",
"chars": 2011,
"preview": "import unittest\n\nfrom nbformat import v4 as nbformat\n\n# mypy: disable-error-code=\"no-untyped-call,no-untyped-def\"\n\n\nclas"
},
{
"path": "tests/conftest.py",
"chars": 429,
"preview": "import asyncio\nimport os\n\n# This is important for ipykernel to show the same string\n# instead of randomly generated file"
},
{
"path": "tests/fake_kernelmanager.py",
"chars": 865,
"preview": "from jupyter_client.manager import AsyncKernelManager\n\n# mypy: disable-error-code=\"no-untyped-call,no-untyped-def\"\n\n\ncla"
},
{
"path": "tests/files/Autokill.ipynb",
"chars": 673,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": "
},
{
"path": "tests/files/Check History in Memory.ipynb",
"chars": 452,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n "
},
{
"path": "tests/files/Clear Output.ipynb",
"chars": 3697,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n "
},
{
"path": "tests/files/Disable Stdin.ipynb",
"chars": 339,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {\n \"collapsed\": false\n },\n \""
},
{
"path": "tests/files/Empty Cell.ipynb",
"chars": 1291,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"Test that executing skips over an e"
},
{
"path": "tests/files/Error.ipynb",
"chars": 1293,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"id\": \"d200673b\",\n \"metadata\": {},\n \"outputs\":"
},
{
"path": "tests/files/Factorials.ipynb",
"chars": 679,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": false\n },\n \"out"
},
{
"path": "tests/files/HelloWorld.ipynb",
"chars": 357,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": false\n },\n \"out"
},
{
"path": "tests/files/Inline Image.ipynb",
"chars": 14335,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": false\n },\n \"out"
},
{
"path": "tests/files/Interrupt.ipynb",
"chars": 1328,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": f"
},
{
"path": "tests/files/JupyterWidgets.ipynb",
"chars": 2155,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [\n {\n \"data\":"
},
{
"path": "tests/files/Other Comms.ipynb",
"chars": 1333,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"ExecuteTime\": {\n \"end_time\""
},
{
"path": "tests/files/Output.ipynb",
"chars": 20404,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {},\n \"outputs\": [\n {\n \"data\":"
},
{
"path": "tests/files/Parallel Execute A.ipynb",
"chars": 2429,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Ensure notebooks can execute in p"
},
{
"path": "tests/files/Parallel Execute B.ipynb",
"chars": 2429,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Ensure notebooks can execute in p"
},
{
"path": "tests/files/SVG.ipynb",
"chars": 1008,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": false\n },\n \"out"
},
{
"path": "tests/files/Skip Exceptions with Cell Tags.ipynb",
"chars": 2552,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"tags\": [\n "
},
{
"path": "tests/files/Skip Exceptions.ipynb",
"chars": 1343,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": false\n },\n \"out"
},
{
"path": "tests/files/Skip Execution with Cell Tag.ipynb",
"chars": 513,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {\n \"tags\": [\n \"skip-executio"
},
{
"path": "tests/files/Sleep1s.ipynb",
"chars": 1203,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"metadata\": {},\n \"outputs\": [],\n \"source\": "
},
{
"path": "tests/files/Unicode.ipynb",
"chars": 337,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": false\n },\n \"out"
},
{
"path": "tests/files/UnicodePy3.ipynb",
"chars": 438,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": false\n },\n \"out"
},
{
"path": "tests/files/update-display-id.ipynb",
"chars": 3468,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"metadata\": {\n \"collapsed\": true\n },\n \"outp"
},
{
"path": "tests/test_cli.py",
"chars": 5368,
"preview": "import sys\nfrom pathlib import Path\nfrom subprocess import CalledProcessError, check_output\nfrom unittest.mock import ca"
},
{
"path": "tests/test_client.py",
"chars": 71550,
"preview": "from __future__ import annotations\n\nimport asyncio\nimport concurrent.futures\nimport copy\nimport datetime\nimport functool"
},
{
"path": "tests/test_util.py",
"chars": 1856,
"preview": "import asyncio\nfrom unittest.mock import MagicMock\n\nimport pytest\nimport tornado\n\nfrom nbclient.util import run_hook, ru"
}
]
About this extraction
This page contains the full source code of the jupyter/nbclient GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 69 files (302.2 KB), approximately 86.6k tokens, and a symbol index with 175 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.