pax_global_header 0000666 0000000 0000000 00000000064 14574064204 0014520 g ustar 00root root 0000000 0000000 52 comment=7423ddd21abb7f4e5b045275bf8145f1d895fa04
jupyter_server_terminals-0.5.3/ 0000775 0000000 0000000 00000000000 14574064204 0016673 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/.gitconfig 0000664 0000000 0000000 00000000064 14574064204 0020645 0 ustar 00root root 0000000 0000000 [blame]
ignoreRevsFile = .git-blame-ignore-revs
jupyter_server_terminals-0.5.3/.github/ 0000775 0000000 0000000 00000000000 14574064204 0020233 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/.github/dependabot.yml 0000664 0000000 0000000 00000000507 14574064204 0023065 0 ustar 00root root 0000000 0000000 version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions:
patterns:
- "*"
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
groups:
actions:
patterns:
- "*"
jupyter_server_terminals-0.5.3/.github/workflows/ 0000775 0000000 0000000 00000000000 14574064204 0022270 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/.github/workflows/enforce-label.yml 0000664 0000000 0000000 00000000500 14574064204 0025504 0 ustar 00root root 0000000 0000000 name: Enforce PR label
on:
pull_request:
types: [labeled, unlabeled, opened, edited, synchronize]
jobs:
enforce-label:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: enforce-triage-label
uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1
jupyter_server_terminals-0.5.3/.github/workflows/prep-release.yml 0000664 0000000 0000000 00000003231 14574064204 0025376 0 ustar 00root root 0000000 0000000 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 }}"
jupyter_server_terminals-0.5.3/.github/workflows/publish-changelog.yml 0000664 0000000 0000000 00000001640 14574064204 0026407 0 ustar 00root root 0000000 0000000 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 }}"
jupyter_server_terminals-0.5.3/.github/workflows/publish-release.yml 0000664 0000000 0000000 00000003406 14574064204 0026102 0 ustar 00root root 0000000 0000000 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 }}
jupyter_server_terminals-0.5.3/.github/workflows/test.yml 0000664 0000000 0000000 00000011012 14574064204 0023765 0 ustar 00root root 0000000 0000000 name: Tests
on:
push:
branches: ["main"]
pull_request:
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 .
pipx run doc8 --max-line-length=200
test:
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.8", "3.12"]
include:
- os: windows-latest
python-version: "3.9"
- os: ubuntu-latest
python-version: "pypy-3.9"
- os: macos-latest
python-version: "3.10"
- os: ubuntu-latest
python-version: "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 on pypy
if: ${{ startsWith(matrix.python-version, 'pypy') }}
run: |
hatch run test:nowarn || hatch run test:nowarn --lf
- name: Run the tests
if: ${{ !startsWith(matrix.python-version, 'pypy') }}
run: |
hatch run cov:test --cov-fail-under 75 || hatch run test:test --lf
- uses: jupyterlab/maintainer-tools/.github/actions/upload-coverage@v1
coverage:
runs-on: ubuntu-latest
needs:
- test
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/report-coverage@v1
test_docs:
name: Test Docs
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- run: hatch run docs:build
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 -vv run test:nowarn || hatch 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: 15
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: jupyterlab/maintainer-tools/.github/actions/test-sdist@v1
with:
extra_test: 'jupyter server extension list 2>&1 | grep -ie "jupyter_server_terminals.*OK"'
check_release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install Dependencies
run: |
pip install -e .
- name: Check Release
uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
check_links:
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/check-links@v1
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) }}
jupyter_server_terminals-0.5.3/.gitignore 0000664 0000000 0000000 00000000657 14574064204 0020673 0 ustar 00root root 0000000 0000000 MANIFEST
build
dist
_build
docs/man/*.gz
docs/source/api/generated
docs/source/config.rst
docs/gh-pages
node_modules
*.py[co]
__pycache__
*.egg-info
*~
*.bak
.ipynb_checkpoints
.tox
.DS_Store
\#*#
.#*
.coverage*
.pytest_cache
src
*.swp
*.map
Read the Docs
config.rst
docs/source/changelog.md
/.project
/.pydevproject
# jetbrains ide stuff
*.iml
.idea/
# vscode ide stuff
*.code-workspace
.history
.vscode/*
!.vscode/*.template
jupyter_server_terminals-0.5.3/.pre-commit-config.yaml 0000664 0000000 0000000 00000004200 14574064204 0023150 0 ustar 00root root 0000000 0000000 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
- 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.8.0"
hooks:
- id: mypy
files: "^jupyter_server_terminals"
stages: [manual]
args: ["--install-types", "--non-interactive"]
additional_dependencies:
["traitlets>=5.13", "jupyter_server>=2.10.1", "terminado>=0.18"]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.0
hooks:
- id: ruff
types_or: [python, jupyter]
args: ["--fix", "--show-fixes"]
- id: ruff-format
types_or: [python, jupyter]
- repo: https://github.com/scientific-python/cookie
rev: "2024.01.24"
hooks:
- id: sp-repo-review
additional_dependencies: ["repo-review[cli]"]
jupyter_server_terminals-0.5.3/.readthedocs.yaml 0000664 0000000 0000000 00000000362 14574064204 0022123 0 ustar 00root root 0000000 0000000 version: 2
sphinx:
configuration: docs/source/conf.py
python:
install:
# install itself with pip install .
- method: pip
path: .
extra_requirements:
- docs
build:
os: ubuntu-22.04
tools:
python: "3.11"
jupyter_server_terminals-0.5.3/CHANGELOG.md 0000664 0000000 0000000 00000062260 14574064204 0020512 0 ustar 00root root 0000000 0000000 # Changelog
All notable changes to this project will be documented in this file.
## 0.5.3
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.5.2...4d5e3041fe8b24511d0b78b99a7678e353b78612))
### Maintenance and upkeep improvements
- Update Release Scripts [#108](https://github.com/jupyter-server/jupyter_server_terminals/pull/108) ([@blink1073](https://github.com/blink1073))
- chore: update pre-commit hooks [#107](https://github.com/jupyter-server/jupyter_server_terminals/pull/107) ([@pre-commit-ci](https://github.com/pre-commit-ci))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2024-01-22&to=2024-03-12&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2024-01-22..2024-03-12&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2024-01-22..2024-03-12&type=Issues)
## 0.5.2
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.5.1...1d47163a9c02f75ff24943faa6a69bf8639b3517))
### Bugs fixed
- Fix usage of await [#106](https://github.com/jupyter-server/jupyter_server_terminals/pull/106) ([@blink1073](https://github.com/blink1073))
- Set terminals_available to False when not enabled [#105](https://github.com/jupyter-server/jupyter_server_terminals/pull/105) ([@Wh1isper](https://github.com/Wh1isper))
### Maintenance and upkeep improvements
- chore: update pre-commit hooks [#104](https://github.com/jupyter-server/jupyter_server_terminals/pull/104) ([@pre-commit-ci](https://github.com/pre-commit-ci))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2023-12-26&to=2024-01-22&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2023-12-26..2024-01-22&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2023-12-26..2024-01-22&type=Issues) | [@Wh1isper](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3AWh1isper+updated%3A2023-12-26..2024-01-22&type=Issues)
## 0.5.1
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.5.0...58ad66a5ce0bca03f6c569b32a8bef9c1bdccd2b))
### Bugs fixed
- fix: support OPTIONS method for CORS [#102](https://github.com/jupyter-server/jupyter_server_terminals/pull/102) ([@zhanba](https://github.com/zhanba))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2023-12-11&to=2023-12-26&type=c))
[@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Awelcome+updated%3A2023-12-11..2023-12-26&type=Issues) | [@zhanba](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Azhanba+updated%3A2023-12-11..2023-12-26&type=Issues)
## 0.5.0
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.4.4...00eb4ee20b8d5838e44de7a756823e4cf02949fa))
### Bugs fixed
- Fix respecting serverapp.terminals_enabled [#91](https://github.com/jupyter-server/jupyter_server_terminals/pull/91) ([@danielzgtg](https://github.com/danielzgtg))
### Maintenance and upkeep improvements
- Update ruff config [#101](https://github.com/jupyter-server/jupyter_server_terminals/pull/101) ([@blink1073](https://github.com/blink1073))
- Update typings for Server 2.10.1 and mypy 1.7 #425 [#99](https://github.com/jupyter-server/jupyter_server_terminals/pull/99) ([@blink1073](https://github.com/blink1073))
- Update types for terminado 0.18 [#98](https://github.com/jupyter-server/jupyter_server_terminals/pull/98) ([@blink1073](https://github.com/blink1073))
- Update ruff config [#97](https://github.com/jupyter-server/jupyter_server_terminals/pull/97) ([@blink1073](https://github.com/blink1073))
- Update typings for server 2.10 [#96](https://github.com/jupyter-server/jupyter_server_terminals/pull/96) ([@blink1073](https://github.com/blink1073))
- chore: update pre-commit hooks [#95](https://github.com/jupyter-server/jupyter_server_terminals/pull/95) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Clean up lint handling [#94](https://github.com/jupyter-server/jupyter_server_terminals/pull/94) ([@blink1073](https://github.com/blink1073))
- Adopt ruff format [#93](https://github.com/jupyter-server/jupyter_server_terminals/pull/93) ([@blink1073](https://github.com/blink1073))
- Update ruff and typing [#92](https://github.com/jupyter-server/jupyter_server_terminals/pull/92) ([@blink1073](https://github.com/blink1073))
- chore: update pre-commit hooks [#90](https://github.com/jupyter-server/jupyter_server_terminals/pull/90) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Fix typings for traitlets 5.10.1 [#89](https://github.com/jupyter-server/jupyter_server_terminals/pull/89) ([@blink1073](https://github.com/blink1073))
- Bump actions/checkout from 3 to 4 [#88](https://github.com/jupyter-server/jupyter_server_terminals/pull/88) ([@dependabot](https://github.com/dependabot))
- Adopt sp-repo-review [#87](https://github.com/jupyter-server/jupyter_server_terminals/pull/87) ([@blink1073](https://github.com/blink1073))
- Update mistune requirement from \<3.0 to \<4.0 [#83](https://github.com/jupyter-server/jupyter_server_terminals/pull/83) ([@dependabot](https://github.com/dependabot))
- Use local coverage [#80](https://github.com/jupyter-server/jupyter_server_terminals/pull/80) ([@blink1073](https://github.com/blink1073))
- Clean up license [#77](https://github.com/jupyter-server/jupyter_server_terminals/pull/77) ([@dcsaba89](https://github.com/dcsaba89))
- Add more linting [#75](https://github.com/jupyter-server/jupyter_server_terminals/pull/75) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2023-01-09&to=2023-12-11&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2023-01-09..2023-12-11&type=Issues) | [@codecov](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Acodecov+updated%3A2023-01-09..2023-12-11&type=Issues) | [@danielzgtg](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Adanielzgtg+updated%3A2023-01-09..2023-12-11&type=Issues) | [@dcsaba89](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Adcsaba89+updated%3A2023-01-09..2023-12-11&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Adependabot+updated%3A2023-01-09..2023-12-11&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2023-01-09..2023-12-11&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Awelcome+updated%3A2023-01-09..2023-12-11&type=Issues)
## 0.4.4
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.4.3...6791413888e45d2aeab5d9d154c98ca9dbd828d8))
### Maintenance and upkeep improvements
- Add typing file [#74](https://github.com/jupyter-server/jupyter_server_terminals/pull/74) ([@blink1073](https://github.com/blink1073))
- Add spelling and docstring enforcement [#72](https://github.com/jupyter-server/jupyter_server_terminals/pull/72) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-12-19&to=2023-01-09&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-12-19..2023-01-09&type=Issues) | [@codecov](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Acodecov+updated%3A2022-12-19..2023-01-09&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-12-19..2023-01-09&type=Issues)
## 0.4.3
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.4.2...b1f2a99b062192e809d770c517ce02988d32d121))
### Bugs fixed
- Fix Server Version Handling and Clean up CI [#71](https://github.com/jupyter-server/jupyter_server_terminals/pull/71) ([@blink1073](https://github.com/blink1073))
### Maintenance and upkeep improvements
- Update mistune requirement from \<2.0 to \<3.0 [#70](https://github.com/jupyter-server/jupyter_server_terminals/pull/70) ([@dependabot](https://github.com/dependabot))
- Adopt ruff and address lint [#69](https://github.com/jupyter-server/jupyter_server_terminals/pull/69) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-12-01&to=2022-12-19&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-12-01..2022-12-19&type=Issues) | [@codecov](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Acodecov+updated%3A2022-12-01..2022-12-19&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Adependabot+updated%3A2022-12-01..2022-12-19&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-12-01..2022-12-19&type=Issues)
## 0.4.2
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.4.1...744451298913d2c2d81698f94d16dfb595df897f))
### Maintenance and upkeep improvements
- Use pytest-jupyter [#67](https://github.com/jupyter-server/jupyter_server_terminals/pull/67) ([@blink1073](https://github.com/blink1073))
- Fixup workflows and add badges [#64](https://github.com/jupyter-server/jupyter_server_terminals/pull/64) ([@blink1073](https://github.com/blink1073))
### Documentation improvements
- Fixup workflows and add badges [#64](https://github.com/jupyter-server/jupyter_server_terminals/pull/64) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-11-21&to=2022-12-01&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-11-21..2022-12-01&type=Issues) | [@codecov](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Acodecov+updated%3A2022-11-21..2022-12-01&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-11-21..2022-12-01&type=Issues)
## 0.4.1
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.4.0...37da434a24475daf674e1711edc53af52dd6957d))
### Maintenance and upkeep improvements
- Switch away from deprecated zmqhandlers module in Jupyter Server 2.0 [#62](https://github.com/jupyter-server/jupyter_server_terminals/pull/62) ([@Zsailer](https://github.com/Zsailer))
- CI Cleanup [#61](https://github.com/jupyter-server/jupyter_server_terminals/pull/61) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-11-11&to=2022-11-21&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-11-11..2022-11-21&type=Issues) | [@codecov](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Acodecov+updated%3A2022-11-11..2022-11-21&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-11-11..2022-11-21&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3AZsailer+updated%3A2022-11-11..2022-11-21&type=Issues)
## 0.4.0
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.3.2...6aa63b9c7cfcbe44da7d65964f2b84e0a3a7c83c))
### Maintenance and upkeep improvements
- Add ability to release from repo [#59](https://github.com/jupyter-server/jupyter_server_terminals/pull/59) ([@blink1073](https://github.com/blink1073))
- Handle jupyter core warning [#58](https://github.com/jupyter-server/jupyter_server_terminals/pull/58) ([@blink1073](https://github.com/blink1073))
- Bump actions/checkout from 2 to 3 [#57](https://github.com/jupyter-server/jupyter_server_terminals/pull/57) ([@dependabot](https://github.com/dependabot))
- Add dependabot [#56](https://github.com/jupyter-server/jupyter_server_terminals/pull/56) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-10-31&to=2022-11-11&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-10-31..2022-11-11&type=Issues) | [@dependabot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Adependabot+updated%3A2022-10-31..2022-11-11&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-10-31..2022-11-11&type=Issues)
## 0.3.2
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.3.1...574e1018b7d924f09c1ca45389182f1fd314caee))
### Maintenance and upkeep improvements
- Use ensure_async function [#54](https://github.com/jupyter-server/jupyter_server_terminals/pull/54) ([@blink1073](https://github.com/blink1073))
- Maintenance cleanup [#51](https://github.com/jupyter-server/jupyter_server_terminals/pull/51) ([@blink1073](https://github.com/blink1073))
- Maintenance cleanup [#50](https://github.com/jupyter-server/jupyter_server_terminals/pull/50) ([@blink1073](https://github.com/blink1073))
- Ignore warnings in prerelease test [#47](https://github.com/jupyter-server/jupyter_server_terminals/pull/47) ([@blink1073](https://github.com/blink1073))
- Clean up pyproject and ci [#45](https://github.com/jupyter-server/jupyter_server_terminals/pull/45) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-09-08&to=2022-10-31&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-09-08..2022-10-31&type=Issues) | [@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Acodecov-commenter+updated%3A2022-09-08..2022-10-31&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-09-08..2022-10-31&type=Issues)
## 0.3.1
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.3.0...6d8b60bc758adc8656ff530a600fb7f57a34259e))
### Enhancements made
- Allow to pass string as a shell override [#42](https://github.com/jupyter-server/jupyter_server_terminals/pull/42) ([@krassowski](https://github.com/krassowski))
### Maintenance and upkeep improvements
- \[pre-commit.ci\] pre-commit autoupdate [#41](https://github.com/jupyter-server/jupyter_server_terminals/pull/41) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#40](https://github.com/jupyter-server/jupyter_server_terminals/pull/40) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#39](https://github.com/jupyter-server/jupyter_server_terminals/pull/39) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Fix flake8 v5 compat [#38](https://github.com/jupyter-server/jupyter_server_terminals/pull/38) ([@blink1073](https://github.com/blink1073))
- \[pre-commit.ci\] pre-commit autoupdate [#37](https://github.com/jupyter-server/jupyter_server_terminals/pull/37) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#36](https://github.com/jupyter-server/jupyter_server_terminals/pull/36) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#35](https://github.com/jupyter-server/jupyter_server_terminals/pull/35) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#34](https://github.com/jupyter-server/jupyter_server_terminals/pull/34) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Suppress tornado 6.2 beta warnings [#33](https://github.com/jupyter-server/jupyter_server_terminals/pull/33) ([@blink1073](https://github.com/blink1073))
- \[pre-commit.ci\] pre-commit autoupdate [#32](https://github.com/jupyter-server/jupyter_server_terminals/pull/32) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#31](https://github.com/jupyter-server/jupyter_server_terminals/pull/31) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#30](https://github.com/jupyter-server/jupyter_server_terminals/pull/30) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Use hatch backend [#29](https://github.com/jupyter-server/jupyter_server_terminals/pull/29) ([@blink1073](https://github.com/blink1073))
- \[pre-commit.ci\] pre-commit autoupdate [#28](https://github.com/jupyter-server/jupyter_server_terminals/pull/28) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#27](https://github.com/jupyter-server/jupyter_server_terminals/pull/27) ([@pre-commit-ci](https://github.com/pre-commit-ci))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-05-03&to=2022-09-08&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-05-03..2022-09-08&type=Issues) | [@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Acodecov-commenter+updated%3A2022-05-03..2022-09-08&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Akrassowski+updated%3A2022-05-03..2022-09-08&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-05-03..2022-09-08&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Awelcome+updated%3A2022-05-03..2022-09-08&type=Issues)
## 0.3.0
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.2.1...3e59b7ca4ebdbf3e1535b4be3a973f2f419ae49f))
### Maintenance and upkeep improvements
- Use alpha release of server 2.0 [#25](https://github.com/jupyter-server/jupyter_server_terminals/pull/25) ([@blink1073](https://github.com/blink1073))
- Switch to flit build backend [#24](https://github.com/jupyter-server/jupyter_server_terminals/pull/24) ([@blink1073](https://github.com/blink1073))
- Allow bot PRs to be auto-labeled [#23](https://github.com/jupyter-server/jupyter_server_terminals/pull/23) ([@blink1073](https://github.com/blink1073))
- \[pre-commit.ci\] pre-commit autoupdate [#22](https://github.com/jupyter-server/jupyter_server_terminals/pull/22) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- \[pre-commit.ci\] pre-commit autoupdate [#21](https://github.com/jupyter-server/jupyter_server_terminals/pull/21) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Add mypy check [#20](https://github.com/jupyter-server/jupyter_server_terminals/pull/20) ([@blink1073](https://github.com/blink1073))
- \[pre-commit.ci\] pre-commit autoupdate [#19](https://github.com/jupyter-server/jupyter_server_terminals/pull/19) ([@pre-commit-ci](https://github.com/pre-commit-ci))
- Clean up pre-commit [#18](https://github.com/jupyter-server/jupyter_server_terminals/pull/18) ([@blink1073](https://github.com/blink1073))
- \[pre-commit.ci\] pre-commit autoupdate [#17](https://github.com/jupyter-server/jupyter_server_terminals/pull/17) ([@pre-commit-ci](https://github.com/pre-commit-ci))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-04-03&to=2022-05-03&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-04-03..2022-05-03&type=Issues) | [@pre-commit-ci](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Apre-commit-ci+updated%3A2022-04-03..2022-05-03&type=Issues)
## 0.2.1
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.2.0...e33b367c81cfb42bf4b903a75f8cd2ae7f400f64))
### Bugs fixed
- Fix initialize method [#15](https://github.com/jupyter-server/jupyter_server_terminals/pull/15) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-04-03&to=2022-04-03&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-04-03..2022-04-03&type=Issues)
## 0.2.0
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/v0.1.0...22d210ea50fb27bcda9a2a781bef6790c509f9a8))
### Enhancements made
- More Cleanup [#12](https://github.com/jupyter-server/jupyter_server_terminals/pull/12) ([@blink1073](https://github.com/blink1073))
- Add authorization [#11](https://github.com/jupyter-server/jupyter_server_terminals/pull/11) ([@blink1073](https://github.com/blink1073))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2022-04-02&to=2022-04-03&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2022-04-02..2022-04-03&type=Issues)
## 0.1.0
([Full Changelog](https://github.com/jupyter-server/jupyter_server_terminals/compare/0.0.1...c849eb024b37e98004f9f2038a19d2227d0923a4))
### Enhancements made
- update last_activity when pty_read [#4](https://github.com/jupyter-server/jupyter_server_terminals/pull/4) ([@Wh1isper](https://github.com/Wh1isper))
- Refactor terminals into an ExtensionApp [#2](https://github.com/jupyter-server/jupyter_server_terminals/pull/2) ([@Zsailer](https://github.com/Zsailer))
### Bugs fixed
- Pin pywintpy and add missing documentation page [#6](https://github.com/jupyter-server/jupyter_server_terminals/pull/6) ([@blink1073](https://github.com/blink1073))
### Maintenance and upkeep improvements
- More Cleanup [#8](https://github.com/jupyter-server/jupyter_server_terminals/pull/8) ([@blink1073](https://github.com/blink1073))
- Clean up dependencies [#7](https://github.com/jupyter-server/jupyter_server_terminals/pull/7) ([@blink1073](https://github.com/blink1073))
- Initial setup [#1](https://github.com/jupyter-server/jupyter_server_terminals/pull/1) ([@blink1073](https://github.com/blink1073))
### Documentation improvements
- Fix links in readme [#3](https://github.com/jupyter-server/jupyter_server_terminals/pull/3) ([@jasonweill](https://github.com/jasonweill))
### Contributors to this release
([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_terminals/graphs/contributors?from=2021-12-26&to=2022-04-02&type=c))
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ablink1073+updated%3A2021-12-26..2022-04-02&type=Issues) | [@jasonweills](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Ajasonweill+updated%3A2021-12-26..2022-04-02&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3Awelcome+updated%3A2021-12-26..2022-04-02&type=Issues) | [@Wh1isper](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3AWh1isper+updated%3A2021-12-26..2022-04-02&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_terminals+involves%3AZsailer+updated%3A2021-12-26..2022-04-02&type=Issues)
jupyter_server_terminals-0.5.3/CONTRIBUTING.rst 0000664 0000000 0000000 00000011345 14574064204 0021340 0 ustar 00root root 0000000 0000000 General Jupyter contributor guidelines
======================================
If you're reading this section, you're probably interested in contributing to
Jupyter. Welcome and thanks for your interest in contributing!
Please take a look at the Contributor documentation, familiarize yourself with
using the Jupyter Server, and introduce yourself on the mailing list and
share what area of the project you are interested in working on.
For general documentation about contributing to Jupyter projects, see the
`Project Jupyter Contributor Documentation`__.
__ https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html
Setting Up a Development Environment
====================================
Installing Jupyter Server Terminals
-----------------------------------
The development version of the server requires `node `_ and `pip `_.
Once you have installed the dependencies mentioned above, use the following
steps::
pip install --upgrade pip
git clone https://github.com/jupyter/jupyter_server_terminals
cd jupyter_server_terminals
pip install -e .
If you are using a system-wide Python installation and you only want to install the server for you,
you can add ``--user`` to the install commands.
Once you have done this, you can launch the main branch of Jupyter server
from any directory in your system with::
jupyter server
Code Styling
-----------------------------
``jupyter_server_terminals`` has adopted automatic code formatting so you shouldn't
need to worry too much about your code style.
As long as your code is valid,
the pre-commit hook should take care of how it should look.
To install ``pre-commit``, run the following::
pip install pre-commit
pre-commit install
You can invoke the pre-commit hook by hand at any time with::
pre-commit run
which should run any autoformatting on your code
and tell you about any errors it couldn't fix automatically.
You may also install `black integration `_
into your text editor to format code automatically.
If you have already committed files before setting up the pre-commit
hook with ``pre-commit install``, you can fix everything up using
``pre-commit run --all-files``. You need to make the fixing commit
yourself after that.
Some of the hooks only run on CI by default, but you can invoke them by
running with the ``--hook-stage manual`` argument.
Troubleshooting the Installation
--------------------------------
If you do not see that your Jupyter Server is not running on dev mode, it's possible that you are
running other instances of Jupyter Server. You can try the following steps:
1. Uninstall all instances of the jupyter_server_terminals package. These include any installations you made using
pip or conda
2. Run ``python3 -m pip install -e .`` in the jupyter_server_terminals repository to install jupyter_server_terminals from there
3. Launch with ``python3 -m jupyter_server --port 8989``, and check that the browser is pointing to ``localhost:8989``
(rather than the default 8888). You don't necessarily have to launch with port 8989, as long as you use
a port that is neither the default nor in use, then it should be fine.
4. Verify the installation with the steps in the previous section.
Running Tests
=============
Install dependencies::
pip install -e .[test]
pip install -e examples/simple # to test the examples
To run the Python tests, use::
pytest jupyter_server_terminals
Building the Docs
=================
To build the documentation you'll need `Sphinx `_,
`pandoc `_ and a few other packages.
To install (and activate) a `conda environment`_ named ``jupyter_server_terminals_docs``
containing all the necessary packages (except pandoc), use::
conda env create -f docs/environment.yml
conda activate jupyter_server_terminals_docs
.. _conda environment:
https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-from-an-environment-yml-file
If you want to install the necessary packages with ``pip`` instead::
pip install -r docs/doc-requirements.txt
Once you have installed the required packages, you can build the docs with::
cd docs
make html
After that, the generated HTML files will be available at
``build/html/index.html``. You may view the docs in your browser.
You can automatically check if all hyperlinks are still valid::
make linkcheck
Windows users can find ``make.bat`` in the ``docs`` folder.
You should also have a look at the `Project Jupyter Documentation Guide`__.
__ https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html
jupyter_server_terminals-0.5.3/LICENSE 0000664 0000000 0000000 00000003000 14574064204 0017671 0 ustar 00root root 0000000 0000000 BSD 3-Clause License
- Copyright (c) 2021-, Jupyter Development Team
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
All rights reserved.
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.
jupyter_server_terminals-0.5.3/README.md 0000664 0000000 0000000 00000004213 14574064204 0020152 0 ustar 00root root 0000000 0000000 # Jupyter Server Terminals
[](https://github.com/jupyter-server/jupyter_server_terminals/actions?query=branch%3Amain++)
[](http://jupyter-server-terminals.readthedocs.io/en/latest/?badge=latest)
Jupyter Server Terminals is a Jupyter Server Extension providing support for terminals.
## Installation and Basic usage
To install the latest release locally, make sure you have
[pip installed](https://pip.readthedocs.io/en/stable/installing/) and run:
```
pip install jupyter_server_terminals
```
Jupyter Server Terminals currently supports Python>=3.6 on Linux, OSX and Windows.
### Testing
See [CONTRIBUTING](./CONTRIBUTING.rst#running-tests).
## Contributing
If you are interested in contributing to the project, see [CONTRIBUTING](./CONTRIBUTING.rst).
## 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.
```
jupyter_server_terminals-0.5.3/RELEASE.md 0000664 0000000 0000000 00000001662 14574064204 0020302 0 ustar 00root root 0000000 0000000 # Making a Jupyter Server Release
## Using `jupyter_releaser`
The recommended way to make a release is to use [`jupyter_releaser`](https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html).
## Manual Release
To create a manual release, perform the following steps:
### Set up
```bash
pip install pipx
git pull origin $(git branch --show-current)
git clean -dffx
```
### Update the version and apply the tag
```bash
echo "Enter new version"
read script_version
pipx run hatch version ${script_version}
git tag -a ${script_version} -m "${script_version}"
```
### Build the artifacts
```bash
rm -rf dist
pipx run build .
```
### Update the version back to dev
```bash
echo "Enter dev version"
read dev_version
pipx run hatch version ${dev_version}
git push origin $(git branch --show-current)
```
### Publish the artifacts to pypi
```bash
pipx run twine check dist/*
pipx run twine upload dist/*
```
jupyter_server_terminals-0.5.3/docs/ 0000775 0000000 0000000 00000000000 14574064204 0017623 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/docs/Makefile 0000664 0000000 0000000 00000001176 14574064204 0021270 0 ustar 00root root 0000000 0000000 # Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
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)
jupyter_server_terminals-0.5.3/docs/README.md 0000664 0000000 0000000 00000000271 14574064204 0021102 0 ustar 00root root 0000000 0000000 # Jupyter Server Terminals Docs Sources
Read [this page](https://jupyter-server-terminals.readthedocs.io/en/latest/contributors/contributing.html#building-the-docs) to build the docs.
jupyter_server_terminals-0.5.3/docs/make.bat 0000664 0000000 0000000 00000001444 14574064204 0021233 0 ustar 00root root 0000000 0000000 @ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
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.https://www.sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
jupyter_server_terminals-0.5.3/docs/source/ 0000775 0000000 0000000 00000000000 14574064204 0021123 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/docs/source/_static/ 0000775 0000000 0000000 00000000000 14574064204 0022551 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/docs/source/_static/jupyter_server_logo.svg 0000664 0000000 0000000 00000024320 14574064204 0027403 0 ustar 00root root 0000000 0000000
jupyter_server_terminals-0.5.3/docs/source/api.rst 0000664 0000000 0000000 00000001040 14574064204 0022421 0 ustar 00root root 0000000 0000000 --------
REST API
--------
The same Jupyter Server Terminals API spec, as found here, is available in an interactive form
`here (on swagger's petstore) `__.
The `OpenAPI Initiative`_ (fka Swaggerâ„¢) is a project used to describe
and document RESTful APIs.
.. openapi:: ../../jupyter_server_terminals/rest-api.yml
:examples:
.. _OpenAPI Initiative: https://www.openapis.org/
jupyter_server_terminals-0.5.3/docs/source/conf.py 0000664 0000000 0000000 00000027164 14574064204 0022434 0 ustar 00root root 0000000 0000000 # Jupyter Server documentation build configuration file, created by
# sphinx-quickstart on Mon Apr 13 09:51:11 2015.
#
# 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.
import os
import os.path as osp
import shutil
import sys
from packaging.version import parse as parse_version
HERE = osp.abspath(osp.dirname(__file__))
# 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.
# DEBUG for RTD
print("DEBUG:: sys.path")
print("================")
for item in sys.path:
print(item)
# add repo root to sys.path
# here = root/docs/source
here = os.path.abspath(os.path.dirname(__file__))
repo_root = os.path.dirname(os.path.dirname(here))
sys.path.insert(0, repo_root)
print("repo_root")
print("=====================")
print(repo_root)
# DEBUG for post insert on RTD
print("DEBUG:: Post insert to sys.path")
print("===============================")
for item in sys.path:
print(item)
# -- 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 = [
"myst_parser",
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.intersphinx",
"sphinx.ext.autosummary",
"sphinx.ext.mathjax",
"sphinxcontrib_github_alt",
"sphinxcontrib.openapi",
"sphinxemoji.sphinxemoji",
]
try:
import enchant # type:ignore[import] # noqa: F401
extensions += ["sphinxcontrib.spelling"]
except ImportError:
pass
myst_enable_extensions = ["html_image"]
# 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']
source_suffix = [".rst", ".ipynb"]
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = "index"
# General information about the project.
project = "Jupyter Server Terminals"
copyright = "2021, Jupyter Team, https://jupyter.org"
author = "The Jupyter Server Team"
# ghissue config
github_project_url = "https://github.com/jupyter/jupyter_server_terminals"
# 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.
#
__version__ = "0.3.1"
# The short X.Y version.
version_parsed = parse_version(__version__)
version = f"{version_parsed.major}.{version_parsed.minor}" # type:ignore[union-attr]
# The full version, including alpha/beta/rc tags.
release = __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 for these cases.
language = "en"
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "default"
# highlight_language = 'python3'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# # Add custom note for each doc page
# rst_prolog = ""
# rst_prolog += """
# .. important::
# This documentation covers Jupyter Server, an **early developer preview**,
# and is not suitable for general usage yet. Features and implementation are
# subject to change.
# For production use cases, please use the stable notebook server in the
# `Jupyter Notebook repo `_
# and `Jupyter Notebook documentation `_.
# """
# -- 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_rtd_theme'
html_theme = "pydata_sphinx_theme"
html_logo = "_static/jupyter_server_logo.svg"
# 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 = {"navigation_with_keys": False}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
# 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".
# NOTE: Sphinx's 'make html' builder will throw a warning about an unfound
# _static directory. Do not remove or comment out html_static_path
# since it is needed to properly generate _static in the build directory
html_static_path = ["_static"]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = "JupyterServerTerminalsdoc"
# -- Options for LaTeX output ---------------------------------------------
# latex_elements = {}
# 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,
"JupyterServerTerminals.tex",
"Jupyter Server Terminals Documentation",
"https://jupyter.org",
"manual",
),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- 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, "jupyterserverterminals", "Jupyter Server Terminals Documentation", [author], 1)
]
# If true, show URL addresses after external links.
# man_show_urls = False
# -- Options for link checks ----------------------------------------------
linkcheck_ignore = [r"http://127\.0\.0\.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,
"JupyterServerTerminals",
"Jupyter Server Terminals Documentation",
author,
"JupyterServerTerminals",
"One line description of project.",
"Miscellaneous",
),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
intersphinx_mapping = {
"jupyter": ("https://jupyter.readthedocs.io/en/latest/", None),
"jupyter_server": ("https://jupyter-server.readthedocs.io/en/latest/", None),
}
spelling_lang = "en_US"
spelling_word_list_filename = "spelling_wordlist.txt"
def setup(app):
dest = osp.join(HERE, "changelog.md")
shutil.copy(osp.join(HERE, "..", "..", "CHANGELOG.md"), dest)
jupyter_server_terminals-0.5.3/docs/source/contributors/ 0000775 0000000 0000000 00000000000 14574064204 0023660 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/docs/source/contributors/contributing.rst 0000664 0000000 0000000 00000000072 14574064204 0027120 0 ustar 00root root 0000000 0000000 .. highlight:: sh
.. include:: ../../../CONTRIBUTING.rst
jupyter_server_terminals-0.5.3/docs/source/index.rst 0000664 0000000 0000000 00000000774 14574064204 0022774 0 ustar 00root root 0000000 0000000 .. jupyter_server_terminals documentation master file, created by
sphinx-quickstart.
You can adapt this file completely to your liking, but it should at least
contain the root ``toctree``` directive.
Welcome to Jupyter Server Terminals documentation!
==================================================
.. toctree::
:maxdepth: 1
:caption: Contents:
changelog
api
contributors/contributing
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
jupyter_server_terminals-0.5.3/jupyter-config/ 0000775 0000000 0000000 00000000000 14574064204 0021640 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/jupyter-config/jupyter_server_terminals.json 0000664 0000000 0000000 00000000143 14574064204 0027677 0 ustar 00root root 0000000 0000000 {
"ServerApp": {
"jpserver_extensions": {
"jupyter_server_terminals": true
}
}
}
jupyter_server_terminals-0.5.3/jupyter_server_terminals/ 0000775 0000000 0000000 00000000000 14574064204 0024041 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/jupyter_server_terminals/__init__.py 0000664 0000000 0000000 00000001273 14574064204 0026155 0 ustar 00root root 0000000 0000000 from typing import Any, Dict, List
from ._version import __version__ # noqa:F401
try:
from jupyter_server._version import version_info
except ModuleNotFoundError:
msg = "Jupyter Server must be installed to use this extension."
raise ModuleNotFoundError(msg) from None
if int(version_info[0]) < 2: # type:ignore[call-overload]
msg = "Jupyter Server Terminals requires Jupyter Server 2.0+"
raise RuntimeError(msg)
from .app import TerminalsExtensionApp
def _jupyter_server_extension_points() -> List[Dict[str, Any]]: # pragma: no cover
return [
{
"module": "jupyter_server_terminals.app",
"app": TerminalsExtensionApp,
},
]
jupyter_server_terminals-0.5.3/jupyter_server_terminals/_version.py 0000664 0000000 0000000 00000000107 14574064204 0026235 0 ustar 00root root 0000000 0000000 """Version info for jupyter_server_terminals."""
__version__ = "0.5.3"
jupyter_server_terminals-0.5.3/jupyter_server_terminals/api_handlers.py 0000664 0000000 0000000 00000005436 14574064204 0027054 0 ustar 00root root 0000000 0000000 """API handlers for terminals."""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from jupyter_server.auth.decorator import authorized
from jupyter_server.base.handlers import APIHandler
from tornado import web
from .base import TerminalsMixin
AUTH_RESOURCE = "terminals"
class TerminalAPIHandler(APIHandler):
"""The base terminal handler."""
auth_resource = AUTH_RESOURCE
class TerminalRootHandler(TerminalsMixin, TerminalAPIHandler):
"""The root termanal API handler."""
@web.authenticated
@authorized
def get(self) -> None:
"""Get the list of terminals."""
models = self.terminal_manager.list()
self.finish(json.dumps(models))
@web.authenticated
@authorized
def post(self) -> None:
"""POST /terminals creates a new terminal and redirects to it"""
data = self.get_json_body() or {}
# if cwd is a relative path, it should be relative to the root_dir,
# but if we pass it as relative, it will we be considered as relative to
# the path jupyter_server was started in
if "cwd" in data:
cwd: Path | None = Path(data["cwd"])
assert cwd is not None
if not cwd.resolve().exists():
cwd = Path(self.settings["server_root_dir"]).expanduser() / cwd
if not cwd.resolve().exists():
cwd = None
if cwd is None:
server_root_dir = self.settings["server_root_dir"]
self.log.debug(
"Failed to find requested terminal cwd: %s\n"
" It was not found within the server root neither: %s.",
data.get("cwd"),
server_root_dir,
)
del data["cwd"]
else:
self.log.debug("Opening terminal in: %s", cwd.resolve())
data["cwd"] = str(cwd.resolve())
model = self.terminal_manager.create(**data)
self.finish(json.dumps(model))
class TerminalHandler(TerminalsMixin, TerminalAPIHandler):
"""A handler for a specific terminal."""
SUPPORTED_METHODS = ("GET", "DELETE", "OPTIONS") # type:ignore[assignment]
@web.authenticated
@authorized
def get(self, name: str) -> None:
"""Get a terminal by name."""
model = self.terminal_manager.get(name)
self.finish(json.dumps(model))
@web.authenticated
@authorized
async def delete(self, name: str) -> None:
"""Remove a terminal by name."""
await self.terminal_manager.terminate(name, force=True)
self.set_status(204)
self.finish()
default_handlers: list[tuple[str, type[Any]]] = [
(r"/api/terminals", TerminalRootHandler),
(r"/api/terminals/(\w+)", TerminalHandler),
]
jupyter_server_terminals-0.5.3/jupyter_server_terminals/app.py 0000664 0000000 0000000 00000012170 14574064204 0025174 0 ustar 00root root 0000000 0000000 """A terminals extension app."""
from __future__ import annotations
import os
import shlex
import sys
import typing as t
from shutil import which
from jupyter_core.utils import ensure_async
from jupyter_server.extension.application import ExtensionApp
from jupyter_server.transutils import trans
from traitlets import Type
from . import api_handlers, handlers
from .terminalmanager import TerminalManager
class TerminalsExtensionApp(ExtensionApp):
"""A terminals extension app."""
name = "jupyter_server_terminals"
terminal_manager_class: type[TerminalManager] = Type( # type:ignore[assignment]
default_value=TerminalManager, help="The terminal manager class to use."
).tag(config=True)
# Since use of terminals is also a function of whether the terminado package is
# available, this variable holds the "final indication" of whether terminal functionality
# should be considered (particularly during shutdown/cleanup). It is enabled only
# once both the terminals "service" can be initialized and terminals_enabled is True.
# Note: this variable is slightly different from 'terminals_available' in the web settings
# in that this variable *could* remain false if terminado is available, yet the terminal
# service's initialization still fails. As a result, this variable holds the truth.
terminals_available = False
def initialize_settings(self) -> None:
"""Initialize settings."""
if not self.serverapp or not self.serverapp.terminals_enabled:
self.settings.update({"terminals_available": False})
return
self.initialize_configurables()
self.settings.update(
{"terminals_available": True, "terminal_manager": self.terminal_manager}
)
def initialize_configurables(self) -> None:
"""Initialize configurables."""
default_shell = "powershell.exe" if os.name == "nt" else which("sh")
assert self.serverapp is not None
shell_override = self.serverapp.terminado_settings.get("shell_command")
if isinstance(shell_override, str):
shell_override = shlex.split(shell_override)
shell = (
[os.environ.get("SHELL") or default_shell] if shell_override is None else shell_override
)
# When the notebook server is not running in a terminal (e.g. when
# it's launched by a JupyterHub spawner), it's likely that the user
# environment hasn't been fully set up. In that case, run a login
# shell to automatically source /etc/profile and the like, unless
# the user has specifically set a preferred shell command.
if os.name != "nt" and shell_override is None and not sys.stdout.isatty():
shell.append("-l")
self.terminal_manager = self.terminal_manager_class(
shell_command=shell,
extra_env={
"JUPYTER_SERVER_ROOT": self.serverapp.root_dir,
"JUPYTER_SERVER_URL": self.serverapp.connection_url,
},
parent=self.serverapp,
)
self.terminal_manager.log = self.serverapp.log
def initialize_handlers(self) -> None:
"""Initialize handlers."""
if not self.serverapp:
# Already set `terminals_available` as `False` in `initialize_settings`
return
if not self.serverapp.terminals_enabled:
# webapp settings for backwards compat (used by nbclassic), #12
self.serverapp.web_app.settings["terminals_available"] = self.settings[
"terminals_available"
]
return
self.handlers.append(
(
r"/terminals/websocket/(\w+)",
handlers.TermSocket,
{"term_manager": self.terminal_manager},
)
)
self.handlers.extend(api_handlers.default_handlers)
assert self.serverapp is not None
self.serverapp.web_app.settings["terminal_manager"] = self.terminal_manager
self.serverapp.web_app.settings["terminals_available"] = self.settings[
"terminals_available"
]
def current_activity(self) -> dict[str, t.Any] | None:
"""Get current activity info."""
if self.terminals_available:
terminals = self.terminal_manager.terminals
if terminals:
return terminals
return None
async def cleanup_terminals(self) -> None:
"""Shutdown all terminals.
The terminals will shutdown themselves when this process no longer exists,
but explicit shutdown allows the TerminalManager to cleanup.
"""
if not self.terminals_available:
return
terminal_manager = self.terminal_manager
n_terminals = len(terminal_manager.list())
terminal_msg = trans.ngettext(
"Shutting down %d terminal", "Shutting down %d terminals", n_terminals
)
self.log.info("%s %% %s", terminal_msg, n_terminals)
await ensure_async(terminal_manager.terminate_all()) # type:ignore[arg-type]
async def stop_extension(self) -> None:
"""Stop the extension."""
await self.cleanup_terminals()
jupyter_server_terminals-0.5.3/jupyter_server_terminals/base.py 0000664 0000000 0000000 00000000745 14574064204 0025333 0 ustar 00root root 0000000 0000000 """Base classes."""
from __future__ import annotations
from typing import TYPE_CHECKING
from jupyter_server.extension.handler import ExtensionHandlerMixin
if TYPE_CHECKING:
from jupyter_server_terminals.terminalmanager import TerminalManager
class TerminalsMixin(ExtensionHandlerMixin):
"""An extension mixin for terminals."""
@property
def terminal_manager(self) -> TerminalManager:
return self.settings["terminal_manager"] # type:ignore[no-any-return]
jupyter_server_terminals-0.5.3/jupyter_server_terminals/handlers.py 0000664 0000000 0000000 00000005507 14574064204 0026222 0 ustar 00root root 0000000 0000000 """Tornado handlers for the terminal emulator."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import annotations
import typing as t
from jupyter_core.utils import ensure_async
from jupyter_server._tz import utcnow
from jupyter_server.auth.utils import warn_disabled_authorization
from jupyter_server.base.handlers import JupyterHandler
from jupyter_server.base.websocket import WebSocketMixin
from terminado.management import NamedTermManager
from terminado.websocket import TermSocket as BaseTermSocket
from tornado import web
from .base import TerminalsMixin
AUTH_RESOURCE = "terminals"
class TermSocket(TerminalsMixin, WebSocketMixin, JupyterHandler, BaseTermSocket):
"""A terminal websocket."""
auth_resource = AUTH_RESOURCE
def initialize( # type:ignore[override]
self, name: str, term_manager: NamedTermManager, **kwargs: t.Any
) -> None:
"""Initialize the socket."""
BaseTermSocket.initialize(self, term_manager, **kwargs)
TerminalsMixin.initialize(self, name)
def origin_check(self, origin: t.Any = None) -> bool:
"""Terminado adds redundant origin_check
Tornado already calls check_origin, so don't do anything here.
"""
return True
async def get(self, *args: t.Any, **kwargs: t.Any) -> None:
"""Get the terminal socket."""
user = self.current_user
if not user:
raise web.HTTPError(403)
# authorize the user.
if self.authorizer is None:
# Warn if an authorizer is unavailable.
warn_disabled_authorization() # type:ignore[unreachable]
elif not self.authorizer.is_authorized(self, user, "execute", self.auth_resource):
raise web.HTTPError(403)
if args[0] not in self.term_manager.terminals: # type:ignore[attr-defined]
raise web.HTTPError(404)
resp = super().get(*args, **kwargs)
if resp is not None:
await ensure_async(resp) # type:ignore[arg-type]
async def on_message(self, message: t.Any) -> None: # type:ignore[override]
"""Handle a socket message."""
await ensure_async(super().on_message(message)) # type:ignore[arg-type]
self._update_activity()
def write_message(self, message: t.Any, binary: bool = False) -> None: # type:ignore[override]
"""Write a message to the socket."""
super().write_message(message, binary=binary)
self._update_activity()
def _update_activity(self) -> None:
self.application.settings["terminal_last_activity"] = utcnow()
# terminal may not be around on deletion/cull
if self.term_name in self.terminal_manager.terminals:
self.terminal_manager.terminals[self.term_name].last_activity = utcnow() # type:ignore[attr-defined]
jupyter_server_terminals-0.5.3/jupyter_server_terminals/py.typed 0000664 0000000 0000000 00000000000 14574064204 0025526 0 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/jupyter_server_terminals/rest-api.yml 0000664 0000000 0000000 00000005745 14574064204 0026323 0 ustar 00root root 0000000 0000000 openapi: 3.0.1
info:
title: Jupyter Server Terminals API
description: Terminals API
contact:
name: Jupyter Project
url: https://jupyter.org
version: "1"
servers:
- url: /
paths:
/api/terminals:
get:
tags:
- terminals
summary: Get available terminals
responses:
200:
description: A list of all available terminal ids.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Terminal"
403:
description: Forbidden to access
content: {}
404:
description: Not found
content: {}
post:
tags:
- terminals
summary: Create a new terminal
responses:
200:
description: Successfully created a new terminal
content:
application/json:
schema:
$ref: "#/components/schemas/Terminal"
403:
description: Forbidden to access
content: {}
404:
description: Not found
content: {}
/api/terminals/{terminal_id}:
get:
tags:
- terminals
summary: Get a terminal session corresponding to an id.
parameters:
- name: terminal_id
in: path
description: ID of terminal session
required: true
schema:
type: string
responses:
200:
description: Terminal session with given id
content:
application/json:
schema:
$ref: "#/components/schemas/Terminal"
403:
description: Forbidden to access
content: {}
404:
description: Not found
content: {}
delete:
tags:
- terminals
summary: Delete a terminal session corresponding to an id.
parameters:
- name: terminal_id
in: path
description: ID of terminal session
required: true
schema:
type: string
responses:
204:
description: Successfully deleted terminal session
content: {}
403:
description: Forbidden to access
content: {}
404:
description: Not found
content: {}
components:
schemas:
Terminal:
required:
- name
type: object
properties:
name:
type: string
description: name of terminal
last_activity:
type: string
description: |
ISO 8601 timestamp for the last-seen activity on this terminal. Use
this to identify which terminals have been inactive since a given time.
Timestamps will be UTC, indicated 'Z' suffix.
description: A Terminal object
parameters:
terminal_id:
name: terminal_id
in: path
description: ID of terminal session
required: true
schema:
type: string
jupyter_server_terminals-0.5.3/jupyter_server_terminals/terminalmanager.py 0000664 0000000 0000000 00000015354 14574064204 0027571 0 ustar 00root root 0000000 0000000 """A MultiTerminalManager for use in the notebook webserver
- raises HTTPErrors
- creates REST API models
"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import annotations
import typing as t
from datetime import timedelta
from jupyter_server._tz import isoformat, utcnow
from jupyter_server.prometheus import metrics
from terminado.management import NamedTermManager, PtyWithClients
from tornado import web
from tornado.ioloop import IOLoop, PeriodicCallback
from traitlets import Integer
from traitlets.config import LoggingConfigurable
RUNNING_TOTAL = metrics.TERMINAL_CURRENTLY_RUNNING_TOTAL
MODEL = t.Dict[str, t.Any]
class TerminalManager(LoggingConfigurable, NamedTermManager): # type:ignore[misc]
"""A MultiTerminalManager for use in the notebook webserver"""
_culler_callback = None
_initialized_culler = False
cull_inactive_timeout = Integer(
0,
config=True,
help="""Timeout (in seconds) in which a terminal has been inactive and ready to be culled.
Values of 0 or lower disable culling.""",
)
cull_interval_default = 300 # 5 minutes
cull_interval = Integer(
cull_interval_default,
config=True,
help="""The interval (in seconds) on which to check for terminals exceeding the inactive timeout value.""",
)
# -------------------------------------------------------------------------
# Methods for managing terminals
# -------------------------------------------------------------------------
def create(self, **kwargs: t.Any) -> MODEL:
"""Create a new terminal."""
name, term = self.new_named_terminal(**kwargs)
# Monkey-patch last-activity, similar to kernels. Should we need
# more functionality per terminal, we can look into possible sub-
# classing or containment then.
term.last_activity = utcnow() # type:ignore[attr-defined]
model = self.get_terminal_model(name)
# Increase the metric by one because a new terminal was created
RUNNING_TOTAL.inc()
# Ensure culler is initialized
self._initialize_culler()
return model
def get(self, name: str) -> MODEL:
"""Get terminal 'name'."""
return self.get_terminal_model(name)
def list(self) -> list[MODEL]:
"""Get a list of all running terminals."""
models = [self.get_terminal_model(name) for name in self.terminals]
# Update the metric below to the length of the list 'terms'
RUNNING_TOTAL.set(len(models))
return models
async def terminate(self, name: str, force: bool = False) -> None:
"""Terminate terminal 'name'."""
self._check_terminal(name)
await super().terminate(name, force=force)
# Decrease the metric below by one
# because a terminal has been shutdown
RUNNING_TOTAL.dec()
async def terminate_all(self) -> None:
"""Terminate all terminals."""
terms = list(self.terminals)
for term in terms:
await self.terminate(term, force=True)
def get_terminal_model(self, name: str) -> MODEL:
"""Return a JSON-safe dict representing a terminal.
For use in representing terminals in the JSON APIs.
"""
self._check_terminal(name)
term = self.terminals[name]
return {
"name": name,
"last_activity": isoformat(term.last_activity), # type:ignore[attr-defined]
}
def _check_terminal(self, name: str) -> None:
"""Check a that terminal 'name' exists and raise 404 if not."""
if name not in self.terminals:
raise web.HTTPError(404, "Terminal not found: %s" % name)
def _initialize_culler(self) -> None:
"""Start culler if 'cull_inactive_timeout' is greater than zero.
Regardless of that value, set flag that we've been here.
"""
if not self._initialized_culler and self.cull_inactive_timeout > 0: # noqa: SIM102
if self._culler_callback is None:
_ = IOLoop.current()
if self.cull_interval <= 0: # handle case where user set invalid value
self.log.warning(
"Invalid value for 'cull_interval' detected (%s) - using default value (%s).",
self.cull_interval,
self.cull_interval_default,
)
self.cull_interval = self.cull_interval_default
self._culler_callback = PeriodicCallback(
self._cull_terminals, 1000 * self.cull_interval
)
self.log.info(
"Culling terminals with inactivity > %s seconds at %s second intervals ...",
self.cull_inactive_timeout,
self.cull_interval,
)
self._culler_callback.start()
self._initialized_culler = True
async def _cull_terminals(self) -> None:
self.log.debug(
"Polling every %s seconds for terminals inactive for > %s seconds...",
self.cull_interval,
self.cull_inactive_timeout,
)
# Create a separate list of terminals to avoid conflicting updates while iterating
for name in list(self.terminals):
try:
await self._cull_inactive_terminal(name)
except Exception as e:
self.log.exception(
"The following exception was encountered while checking the "
"activity of terminal %s: %s",
name,
e,
)
async def _cull_inactive_terminal(self, name: str) -> None:
try:
term = self.terminals[name]
except KeyError:
return # KeyErrors are somewhat expected since the terminal can be terminated as the culling check is made.
self.log.debug("name=%s, last_activity=%s", name, term.last_activity) # type:ignore[attr-defined]
if hasattr(term, "last_activity"):
dt_now = utcnow()
dt_inactive = dt_now - term.last_activity
# Compute idle properties
is_time = dt_inactive > timedelta(seconds=self.cull_inactive_timeout)
# Cull the kernel if all three criteria are met
if is_time:
inactivity = int(dt_inactive.total_seconds())
self.log.warning(
"Culling terminal '%s' due to %s seconds of inactivity.", name, inactivity
)
await self.terminate(name, force=True)
def pre_pty_read_hook(self, ptywclients: PtyWithClients) -> None:
"""The pre-pty read hook."""
ptywclients.last_activity = utcnow() # type:ignore[attr-defined]
jupyter_server_terminals-0.5.3/pyproject.toml 0000664 0000000 0000000 00000011376 14574064204 0021617 0 ustar 00root root 0000000 0000000 [build-system]
requires = ["hatchling>=1.5"]
build-backend = "hatchling.build"
[project]
name = "jupyter_server_terminals"
readme = "README.md"
dynamic = ["version"]
license = { file = "LICENSE" }
description = "A Jupyter Server Extension Providing Terminals."
keywords = ["ipython", "jupyter"]
classifiers = [
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11"
]
requires-python = ">=3.8"
dependencies = [
"pywinpty>=2.0.3;os_name=='nt'",
"terminado>=0.8.3",
]
[[project.authors]]
name = "Jupyter Development Team"
email = "jupyter@googlegroups.com"
[project.urls]
Homepage = "https://jupyter.org"
[project.optional-dependencies]
test = [
"jupyter_server>=2.0.0",
"pytest-jupyter[server]>=0.5.3",
"pytest>=7.0",
"pytest-timeout",
]
docs = [
"jinja2",
"jupyter_server",
"mistune<4.0", # https://github.com/jupyter/nbconvert/issues/1685"
"myst-parser",
"nbformat",
"packaging",
"tornado",
"pydata_sphinx_theme",
"sphinxcontrib-openapi",
"sphinxcontrib_github_alt",
"sphinxemoji",
"sphinxcontrib-spelling",
]
[tool.hatch.version]
path = "jupyter_server_terminals/_version.py"
[tool.hatch.build.targets.wheel.shared-data]
"jupyter-config" = "etc/jupyter/jupyter_server_config.d"
[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 jupyter_server_terminals --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/"
]
timeout = 300
# Restore this setting to debug failures
# timeout_method = "thread"
filterwarnings = [
"error",
# from tornado
"ignore:unclosed 100 characters)
"SIM105", # Use `contextlib.suppress(...)`
"T201", # `print` found
"S101", # Use of `assert` detected
]
unfixable = [
# Don't touch print statements
"T201",
# Don't touch noqa lines
"RUF100",
]
[tool.ruff.lint.per-file-ignores]
# B011: Do not call assert False since python -O removes these calls
# F841 local variable 'foo' is assigned to but never used
# S101 Use of `assert` detected
"tests/*" = ["B011", "F841"]
"docs/*" = ["PTH"]
[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 = ["GH102"]
jupyter_server_terminals-0.5.3/tests/ 0000775 0000000 0000000 00000000000 14574064204 0020035 5 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/tests/__init__.py 0000664 0000000 0000000 00000000000 14574064204 0022134 0 ustar 00root root 0000000 0000000 jupyter_server_terminals-0.5.3/tests/conftest.py 0000664 0000000 0000000 00000000063 14574064204 0022233 0 ustar 00root root 0000000 0000000 pytest_plugins = ["pytest_jupyter.jupyter_server"]
jupyter_server_terminals-0.5.3/tests/test_auth.py 0000664 0000000 0000000 00000010445 14574064204 0022413 0 ustar 00root root 0000000 0000000 """Tests for authorization"""
import asyncio
from typing import Dict
import pytest
from jupyter_server.auth.authorizer import Authorizer
from jupyter_server.auth.utils import HTTP_METHOD_TO_AUTH_ACTION, match_url_to_resource
from tornado.httpclient import HTTPClientError
from tornado.websocket import WebSocketHandler
from traitlets.config.loader import Config
class AuthorizerforTesting(Authorizer):
# Set these class attributes from within a test
# to verify that they match the arguments passed
# by the REST API.
permissions: Dict[str, str] = {} # noqa: RUF012
def normalize_url(self, path):
"""Drop the base URL and make sure path leads with a /"""
base_url = self.parent.base_url
# Remove base_url
if path.startswith(base_url):
path = path[len(base_url) :]
# Make sure path starts with /
if not path.startswith("/"):
path = "/" + path
return path
def is_authorized(self, handler, user, action, resource):
# Parse Request
method = "WEBSOCKET" if isinstance(handler, WebSocketHandler) else handler.request.method
url = self.normalize_url(handler.request.path)
# Map request parts to expected action and resource.
expected_action = HTTP_METHOD_TO_AUTH_ACTION[method]
expected_resource = match_url_to_resource(url)
# Assert that authorization layer returns the
# correct action + resource.
assert action == expected_action
assert resource == expected_resource
# Now, actually apply the authorization layer.
return all(
[
action in self.permissions.get("actions", []),
resource in self.permissions.get("resources", []),
]
)
@pytest.fixture()
def jp_server_config():
return Config(
{
"ServerApp": {
"jpserver_extensions": {"jupyter_server_terminals": True},
"authorizer_class": AuthorizerforTesting,
}
}
)
@pytest.fixture()
def send_request(jp_fetch, jp_ws_fetch):
"""Send to Jupyter Server and return response code."""
async def _(url, **fetch_kwargs):
fetch = jp_ws_fetch if url.endswith("channels") or "/websocket/" in url else jp_fetch
try:
r = await fetch(url, **fetch_kwargs, allow_nonstandard_methods=True)
code = r.code
except HTTPClientError as err:
code = err.code
else:
if fetch is jp_ws_fetch:
r.close()
print(code, url, fetch_kwargs)
return code
return _
HTTP_REQUESTS = [
{
"method": "POST",
"url": "/api/terminals",
"body": "",
},
{
"method": "GET",
"url": "/api/terminals",
},
{
"method": "GET",
"url": "/terminals/websocket/{term_name}",
},
{
"method": "DELETE",
"url": "/api/terminals/{term_name}",
},
]
HTTP_REQUESTS_PARAMETRIZED = [(req["method"], req["url"], req.get("body")) for req in HTTP_REQUESTS]
# -------- Test scenarios -----------
@pytest.mark.parametrize("method, url, body", HTTP_REQUESTS_PARAMETRIZED) # noqa: PT006
@pytest.mark.parametrize("allowed", (True, False)) # noqa: PT007
async def test_authorized_requests(
request,
io_loop,
send_request,
jp_serverapp,
method,
url,
body,
allowed,
):
term_manager = jp_serverapp.web_app.settings["terminal_manager"]
request.addfinalizer(lambda: io_loop.run_sync(term_manager.terminate_all))
term_model = term_manager.create()
term_name = term_model["name"]
url = url.format(term_name=term_name)
if allowed:
# Create a server with full permissions
permissions = {
"actions": ["read", "write", "execute"],
"resources": [
"terminals",
],
}
expected_codes = {200, 201, 204, None} # Websockets don't return a code
else:
permissions = {"actions": [], "resources": []}
expected_codes = {403}
jp_serverapp.authorizer.permissions = permissions
while True:
code = await send_request(url, body=body, method=method)
if code == 404:
await asyncio.sleep(1)
continue
assert code in expected_codes
break
jupyter_server_terminals-0.5.3/tests/test_disable_app.py 0000664 0000000 0000000 00000000711 14574064204 0023710 0 ustar 00root root 0000000 0000000 import pytest
from traitlets.config.loader import Config
@pytest.fixture()
def jp_server_config():
return Config({"ServerApp": {"terminals_enabled": False}})
async def test_not_enabled(jp_configurable_serverapp):
assert jp_configurable_serverapp().terminals_enabled is False
assert jp_configurable_serverapp().web_app.settings["terminals_available"] is False
assert "terminal_manager" not in jp_configurable_serverapp().web_app.settings
jupyter_server_terminals-0.5.3/tests/test_terminal.py 0000664 0000000 0000000 00000016114 14574064204 0023264 0 ustar 00root root 0000000 0000000 import asyncio
import json
import os
import shutil
import sys
from pathlib import Path
import pytest
from tornado.httpclient import HTTPClientError
from traitlets.config.loader import Config
@pytest.fixture()
def terminal_path(tmp_path):
subdir = tmp_path.joinpath("terminal_path")
subdir.mkdir()
yield subdir
shutil.rmtree(str(subdir), ignore_errors=True)
@pytest.fixture()
def terminal_root_dir(jp_root_dir):
subdir = jp_root_dir.joinpath("terminal_path")
subdir.mkdir()
yield subdir
shutil.rmtree(str(subdir), ignore_errors=True)
CULL_TIMEOUT = 10
CULL_INTERVAL = 3
@pytest.fixture()
def jp_server_config():
return Config(
{
"ServerApp": {
"TerminalManager": {
"cull_inactive_timeout": CULL_TIMEOUT,
"cull_interval": CULL_INTERVAL,
},
"jpserver_extensions": {"jupyter_server_terminals": True},
}
}
)
async def test_no_terminals(jp_fetch):
resp_list = await jp_fetch(
"api",
"terminals",
method="GET",
allow_nonstandard_methods=True,
)
data = json.loads(resp_list.body.decode())
assert len(data) == 0
async def test_terminal_create(jp_fetch):
resp = await jp_fetch(
"api",
"terminals",
method="POST",
allow_nonstandard_methods=True,
)
term = json.loads(resp.body.decode())
assert term["name"] == "1"
resp_list = await jp_fetch(
"api",
"terminals",
method="GET",
allow_nonstandard_methods=True,
)
data = json.loads(resp_list.body.decode())
assert len(data) == 1
del data[0]["last_activity"]
del term["last_activity"]
assert data[0] == term
async def test_terminal_create_with_kwargs(jp_fetch, terminal_path):
resp_create = await jp_fetch(
"api",
"terminals",
method="POST",
body=json.dumps({"cwd": str(terminal_path)}),
allow_nonstandard_methods=True,
)
data = json.loads(resp_create.body.decode())
term_name = data["name"]
resp_get = await jp_fetch(
"api",
"terminals",
term_name,
method="GET",
allow_nonstandard_methods=True,
)
data = json.loads(resp_get.body.decode())
assert data["name"] == term_name
async def test_terminal_create_with_cwd(jp_fetch, jp_ws_fetch, terminal_path):
resp = await jp_fetch(
"api",
"terminals",
method="POST",
body=json.dumps({"cwd": str(terminal_path)}),
allow_nonstandard_methods=True,
)
data = json.loads(resp.body.decode())
term_name = data["name"]
while True:
try:
ws = await jp_ws_fetch("terminals", "websocket", term_name)
break
except HTTPClientError as e:
if e.code != 404:
raise
await asyncio.sleep(1)
ws.write_message(json.dumps(["stdin", "pwd\r\n"]))
message_stdout = ""
while True:
try:
message = await asyncio.wait_for(ws.read_message(), timeout=5.0)
except asyncio.TimeoutError:
break
message = json.loads(message)
if message[0] == "stdout":
message_stdout += message[1]
ws.close()
assert Path(terminal_path).name in message_stdout
async def test_terminal_create_with_relative_cwd(
jp_fetch, jp_ws_fetch, jp_root_dir, terminal_root_dir
):
resp = await jp_fetch(
"api",
"terminals",
method="POST",
body=json.dumps({"cwd": str(terminal_root_dir.relative_to(jp_root_dir))}),
allow_nonstandard_methods=True,
)
data = json.loads(resp.body.decode())
term_name = data["name"]
while True:
try:
ws = await jp_ws_fetch("terminals", "websocket", term_name)
break
except HTTPClientError as e:
if e.code != 404:
raise
await asyncio.sleep(1)
ws.write_message(json.dumps(["stdin", "pwd\r\n"]))
message_stdout = ""
while True:
try:
message = await asyncio.wait_for(ws.read_message(), timeout=5.0)
except asyncio.TimeoutError:
break
message = json.loads(message)
if message[0] == "stdout":
message_stdout += message[1]
ws.close()
expected = terminal_root_dir.name if sys.platform == "win32" else str(terminal_root_dir)
assert expected in message_stdout
async def test_terminal_create_with_bad_cwd(jp_fetch, jp_ws_fetch):
non_existing_path = "/tmp/path/to/nowhere" # noqa: S108
resp = await jp_fetch(
"api",
"terminals",
method="POST",
body=json.dumps({"cwd": non_existing_path}),
allow_nonstandard_methods=True,
)
data = json.loads(resp.body.decode())
term_name = data["name"]
while True:
try:
ws = await jp_ws_fetch("terminals", "websocket", term_name)
break
except HTTPClientError as e:
if e.code != 404:
raise
await asyncio.sleep(1)
ws.write_message(json.dumps(["stdin", "pwd\r\n"]))
message_stdout = ""
while True:
try:
message = await asyncio.wait_for(ws.read_message(), timeout=5.0)
except asyncio.TimeoutError:
break
message = json.loads(message)
if message[0] == "stdout":
message_stdout += message[1]
ws.close()
assert non_existing_path not in message_stdout
async def test_app_config(jp_configurable_serverapp):
assert jp_configurable_serverapp().terminals_enabled is True
assert jp_configurable_serverapp().web_app.settings["terminals_available"] is True
assert jp_configurable_serverapp().web_app.settings["terminal_manager"]
async def test_culling_config(jp_configurable_serverapp):
terminal_mgr_config = jp_configurable_serverapp().config.ServerApp.TerminalManager
assert terminal_mgr_config.cull_inactive_timeout == CULL_TIMEOUT
assert terminal_mgr_config.cull_interval == CULL_INTERVAL
terminal_mgr_settings = jp_configurable_serverapp().web_app.settings["terminal_manager"]
assert terminal_mgr_settings.cull_inactive_timeout == CULL_TIMEOUT
assert terminal_mgr_settings.cull_interval == CULL_INTERVAL
@pytest.mark.skipif(os.name == "nt", reason="Not currently working on Windows")
async def test_culling(jp_fetch):
# POST request
resp = await jp_fetch(
"api",
"terminals",
method="POST",
allow_nonstandard_methods=True,
)
term = json.loads(resp.body.decode())
term_1 = term["name"]
last_activity = term["last_activity"]
culled = False
for _ in range(CULL_TIMEOUT + CULL_INTERVAL * 2):
try:
resp = await jp_fetch(
"api",
"terminals",
term_1,
method="GET",
allow_nonstandard_methods=True,
)
except HTTPClientError as e:
assert e.code == 404 # noqa: PT017
culled = True
break
else:
await asyncio.sleep(1)
assert culled