diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8d13930..07582ef 100755 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,6 +35,7 @@ jobs: - "3.9" - "3.10" - "3.11" + - "3.12" runs-on: ubuntu-latest @@ -58,23 +59,22 @@ jobs: ${{ runner.os }}-python ${{ runner.os }}- - - name: Upgrade pip - run: python -m pip install --upgrade pip setuptools wheel - - name: Install dependencies run: | - pip install --upgrade -r requirements.txt -r requirements-test.txt - pip install -e . + pip install -e "."" pip freeze - name: Show help run: jupyter kernelgateway --help - name: Run tests - run: pytest -vv -W default --cov kernel_gateway --cov-branch --cov-report term-missing:skip-covered + run: hatch run cov:test env: ASYNC_TEST_TIMEOUT: 10 + - name: Build docs + run: hatch run docs:build + - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 with: diff --git a/Makefile b/Makefile deleted file mode 100644 index 392cd75..0000000 --- a/Makefile +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -.PHONY: help build clean nuke dev dev-http docs install bdist sdist test release - -SA:=source activate -ENV:=kernel-gateway-dev -SHELL:=/bin/bash - -help: -# http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html - @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -build: -env: ## Make a dev environment - conda create -y -n $(ENV) -c conda-forge --file requirements.txt \ - --file requirements-test.txt - source activate $(ENV) && \ - pip install -r requirements-doc.txt && \ - pip install -e . - -activate: ## eval `make activate` - @echo "$(SA) $(ENV)" - -clean: ## Make a clean source tree - -rm -rf dist - -rm -rf build - -rm -rf *.egg-info - -find kernel_gateway -name __pycache__ -exec rm -fr {} \; - -find kernel_gateway -name '*.pyc' -exec rm -fr {} \; - -$(SA) $(ENV) && make -C docs clean - -nuke: ## Make clean + remove conda env - -conda env remove -n $(ENV) -y - -dev: ## Make a server in jupyter_websocket mode - $(SA) $(ENV) && python kernel_gateway - -dev-http: ## Make a server in notebook_http mode - $(SA) $(ENV) && python kernel_gateway \ - --KernelGatewayApp.api='kernel_gateway.notebook_http' \ - --KernelGatewayApp.seed_uri=etc/api_examples/api_intro.ipynb - -docs: ## Make HTML documentation - $(SA) $(ENV) && make -C docs html - -install: ## Make a conda env with dist/*.whl and dist/*.tar.gz installed - -conda env remove -y -n $(ENV)-install - conda create -y -n $(ENV)-install python=3 pip - $(SA) $(ENV)-install && \ - pip install dist/*.whl && \ - jupyter kernelgateway --help && \ - pip uninstall -y jupyter_kernel_gateway - conda env remove -y -n $(ENV)-install - - conda create -y -n $(ENV)-install python=3 pip - $(SA) $(ENV)-install && \ - pip install dist/*.tar.gz && \ - jupyter kernelgateway --help && \ - pip uninstall -y jupyter_kernel_gateway - conda env remove -y -n $(ENV)-install - -bdist: ## Make a dist/*.whl binary distribution - $(SA) $(ENV) && python setup.py bdist_wheel $(POST_SDIST) \ - && rm -rf *.egg-info - -sdist: ## Make a dist/*.tar.gz source distribution - $(SA) $(ENV) && python setup.py sdist $(POST_SDIST) \ - && rm -rf *.egg-info - -test: TEST?= -test: ## Make a python3 test run -ifeq ($(TEST),) - $(SA) $(ENV) && pytest -vv -else -# e.g., make test TEST="test_gatewayapp.py::TestGatewayAppConfig" - $(SA) $(ENV) && pytest -vv kernel_gateway/tests/$(TEST) -endif - -release: POST_SDIST=register upload -release: bdist sdist ## Make a wheel + source release on PyPI diff --git a/docs/source/conf.py b/docs/source/conf.py index 47bc0a7..1994193 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -35,6 +35,8 @@ "myst_parser" ] +myst_enable_extensions = ["attrs_block", "attrs_inline"] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -71,7 +73,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -362,7 +364,7 @@ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/3/': None} +intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} # Read The Docs # on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org diff --git a/docs/source/http-mode.md b/docs/source/http-mode.md index 7eebc5b..67b3203 100644 --- a/docs/source/http-mode.md +++ b/docs/source/http-mode.md @@ -46,6 +46,8 @@ The `REQUEST` object currently contains the following properties: * `path` - An object of key-value pairs representing path parameters and their values. * `headers` - An object of key-value pairs where a key is a HTTP header name and a value is the HTTP header value. If there are multiple values are specified for a header, the value will be an array. +{#request-content-type-and-request-body-processing} + ### Request Content-Type and Request Body Processing If the HTTP request to the kernel gateway has a `Content-Type` header the value of `REQUEST.body` may change. Below is the list of outcomes for various mime-types: diff --git a/kernel_gateway/_version.py b/kernel_gateway/_version.py index a4d06db..9440320 100644 --- a/kernel_gateway/_version.py +++ b/kernel_gateway/_version.py @@ -3,6 +3,17 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -version_info = (2, 6, 0, 'dev0') +import re +from typing import List -__version__ = '.'.join(map(str, version_info)) +# Version string must appear intact for automatic versioning +__version__ = "2.6.0.dev0" + +# Build up version_info tuple for backwards compatibility +pattern = r"(?P\d+).(?P\d+).(?P\d+)(?P.*)" +match = re.match(pattern, __version__) +assert match is not None +parts: List[object] = [int(match[part]) for part in ["major", "minor", "patch"]] +if match["rest"]: + parts.append(match["rest"]) +version_info = tuple(parts) diff --git a/kernel_gateway/gatewayapp.py b/kernel_gateway/gatewayapp.py index 508721e..2441751 100644 --- a/kernel_gateway/gatewayapp.py +++ b/kernel_gateway/gatewayapp.py @@ -16,7 +16,6 @@ import ssl import threading from base64 import encodebytes -from distutils.util import strtobool import nbformat from jupyter_server.services.kernels.kernelmanager import MappingKernelManager @@ -189,7 +188,7 @@ def expose_headers_default(self): ) @default('trust_xheaders') def trust_xheaders_default(self): - return strtobool(os.getenv(self.trust_xheaders_env, 'False')) + return os.getenv(self.trust_xheaders_env, 'False').lower() == 'true' max_age_env = 'KG_MAX_AGE' diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3c019bf --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,87 @@ +[build-system] +requires = ["hatchling>=1.5"] +build-backend = "hatchling.build" + +[project] +name = "jupyter-kernel-gateway" +dynamic = ["version"] +description = "A web server for spawning and communicating with Jupyter kernels" +readme = "README.md" +license = "BSD" +requires-python = ">=3.8" +authors = [ + { name = "Jupyter Development Team", email = "jupyter@googlegroups.com" }, +] +keywords = [ + "Cloud", + "Interactive", + "Interpreter", + "Kernel", + "Web", +] +classifiers = [ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +dependencies = [ + "jupyter_client>=7.4.4", + "jupyter_core>=4.12,!=5.0.*", + "jupyter_server>=2.0", + "requests>=2.7,<3.0", + "tornado>=6.2.0", + "traitlets>=5.6.0", +] + +[project.scripts] +jupyter-kernelgateway = "kernel_gateway:launch_instance" + +[project.urls] +Homepage = "http://github.com/jupyter-incubator/kernel_gateway" + +[project.optional-dependencies] +test = [ + "coverage", + "pytest", + "pytest-cov", + "pytest_jupyter", + "pytest-timeout", + "ipykernel", +] +docs = [ + "sphinx_rtd_theme", + "sphinx", + "myst-parser", +] + +[tool.hatch.version] +path = "kernel_gateway/_version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/kernel_gateway", +] + +[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}" + +[tool.hatch.envs.cov] +features = ["test"] +dependencies = ["coverage[toml]", "pytest-cov"] +[tool.hatch.envs.cov.scripts] +test = "python -m pytest -vv --cov kernel_gateway --cov-branch --cov-report term-missing:skip-covered {args}" diff --git a/requirements-doc.txt b/requirements-doc.txt deleted file mode 100644 index 1a45a28..0000000 --- a/requirements-doc.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx_rtd_theme -sphinx -myst-parser diff --git a/requirements-test.txt b/requirements-test.txt deleted file mode 100644 index 6284dfd..0000000 --- a/requirements-test.txt +++ /dev/null @@ -1,6 +0,0 @@ -coverage -pytest -pytest-cov -pytest_jupyter -pytest-timeout -ipykernel diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f5e545d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -jupyter_core>=4.12 -jupyter_client>=7.4.4 -jupyter_server>=2.12.2 -traitlets>=5.6.0 -tornado>=6.2.0 -requests>=2.7,<3.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 63be602..0000000 --- a/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[bdist_wheel] -universal=0 - -[metadata] -license_file = LICENSE.md diff --git a/setup.py b/setup.py index afdc0e0..8bf1ba9 100644 --- a/setup.py +++ b/setup.py @@ -1,91 +1,2 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import sys from setuptools import setup - -here = os.path.abspath(os.path.dirname(__file__)) - -version_ns = {} -with open(os.path.join(here, 'kernel_gateway', '_version.py')) as f: - exec(f.read(), {}, version_ns) - -setup_args = dict( - name='jupyter_kernel_gateway', - author='Jupyter Development Team', - author_email='jupyter@googlegroups.com', - url='http://github.com/jupyter-incubator/kernel_gateway', - description='A web server for spawning and communicating with Jupyter kernels', - long_description='''\ -Jupyter Kernel Gateway is a web server that supports different mechanisms for -spawning and communicating with Jupyter kernels, such as: - -* A Jupyter Notebook server-compatible HTTP API used for requesting kernels - and talking the `Jupyter kernel protocol `_ - with the kernels over Websockets -* A HTTP API defined by annotated notebook cells that maps HTTP verbs and - resources to code to execute on a kernel - -The server launches kernels in its local process/filesystem space. It can be -containerized and scaled out using common technologies like -`tmpnb `_, -`Cloud Foundry `_, and -`Kubernetes `_. -''', - version=version_ns['__version__'], - license='BSD', - platforms="Linux, Mac OS X, Windows", - keywords=['Interactive', 'Interpreter', 'Kernel', 'Web', 'Cloud'], - packages=[ - 'kernel_gateway', - 'kernel_gateway.base', - 'kernel_gateway.jupyter_websocket', - 'kernel_gateway.notebook_http', - 'kernel_gateway.notebook_http.cell', - 'kernel_gateway.notebook_http.swagger', - 'kernel_gateway.services', - 'kernel_gateway.services.kernels', - 'kernel_gateway.services.kernelspecs', - 'kernel_gateway.services.sessions', - ], - scripts=[ - 'scripts/jupyter-kernelgateway' - ], - install_requires=[ - 'jupyter_client>=7.4.4', - 'jupyter_core>=4.12,!=5.0.*', - 'jupyter_server>=2.0', - 'traitlets>=5.6.0', - 'tornado>=6.2.0', - 'requests>=2.7,<3.0' - ], - python_requires='>=3.8', - classifiers=[ - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - ], - include_package_data=True, -) - -if 'setuptools' in sys.modules: - # setupstools turns entrypoint scripts into executables on windows - setup_args['entry_points'] = { - 'console_scripts': [ - 'jupyter-kernelgateway = kernel_gateway:launch_instance' - ] - } - # Don't bother installing the .py scripts if if we're using entrypoints - setup_args.pop('scripts', None) - -if __name__ == '__main__': - setup(**setup_args) +setup()