diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 402018f..0806833 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,7 @@ jobs: hatch run cov:test || hatch run test:test --lf - name: Coverage run: | - pip install codecov + pip install codecov coverage[toml] codecov check_release: @@ -58,13 +58,9 @@ jobs: - uses: actions/checkout@v3 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: - python_version: "3.8" - - uses: jupyterlab/maintainer-tools/.github/actions/install-minimums@v1 - with: - only_create_file: 1 + dependency_type: minimum - name: Run the unit tests run: | - export PIP_CONSTRAINT="./contraints_file.txt" hatch run test:nowarn || hatch run test:nowarn --lf test_prereleases: @@ -75,10 +71,9 @@ jobs: - uses: actions/checkout@v3 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: - python_version: "3.11" + dependency_type: pre - name: Run the tests run: | - export PIP_PRE=1 hatch run test:nowarn || hatch run test:nowarn --lf make_sdist: diff --git a/.gitignore b/.gitignore index 7b8da97..5766d3b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ IGNORE ORIG SUBMIT doc/_build/ +doc/changelog.md diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 16ba1a6..ea4e189 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,7 +49,7 @@ repos: rev: v1.0.0 hooks: - id: doc8 - args: [--max-line-length=200] + args: ["--max-line-length=200", "--ignore-path=doc/index.rst"] stages: [manual] - repo: https://github.com/john-hen/Flake8-pyproject diff --git a/README.md b/README.md new file mode 100644 index 0000000..eed2465 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# Terminado + +[![Build Status](https://github.com/jupyter/terminado/actions/workflows/test.yml/badge.svg?query=branch%3Amain++)](https://github.com/jupyter/terminado/actions/workflows/test.yml/badge.svg?query=branch%3Amain++) +[![codecov](https://codecov.io/gh/jupyter/terminado/branch/main/graph/badge.svg?token=Ih2XfDqyD1)](https://codecov.io/gh/jupyter/terminado) +[![Documentation Status](https://readthedocs.org/projects/terminado/badge/?version=latest)](http://terminado.readthedocs.io/en/latest/?badge=latest) + +This is a [Tornado](http://tornadoweb.org/) websocket backend for the +[Xterm.js](https://xtermjs.org/) Javascript terminal emulator library. + +It evolved out of [pyxterm](https://github.com/mitotic/pyxterm), which +was part of [GraphTerm](https://github.com/mitotic/graphterm) (as +lineterm.py), v0.57.0 (2014-07-18), and ultimately derived from the +public-domain [Ajaxterm](http://antony.lesuisse.org/software/ajaxterm/) +code, v0.11 (2008-11-13) (also on Github as part of +[QWeb](https://github.com/antonylesuisse/qweb)). + +Modules: + +- `terminado.management`: controls launching virtual terminals, + connecting them to Tornado's event loop, and closing them down. +- `terminado.websocket`: Provides a websocket handler for + communicating with a terminal. +- `terminado.uimodule`: Provides a `Terminal` Tornado [UI + Module](http://www.tornadoweb.org/en/stable/guide/templates.html#ui-modules). + +JS: + +- `terminado/_static/terminado.js`: A lightweight wrapper to set up a + term.js terminal with a websocket. + +Local Installation: + +> $ pip install -e .\[test\] + +Usage example: + +```python +import os.path +import tornado.web +import tornado.ioloop +# This demo requires tornado_xstatic and XStatic-term.js +import tornado_xstatic + +import terminado +STATIC_DIR = os.path.join(os.path.dirname(terminado.__file__), "_static") + +class TerminalPageHandler(tornado.web.RequestHandler): + def get(self): + return self.render("termpage.html", static=self.static_url, + xstatic=self.application.settings['xstatic_url'], + ws_url_path="/websocket") + +if __name__ == '__main__': + term_manager = terminado.SingleTermManager(shell_command=['bash']) + handlers = [ + (r"/websocket", terminado.TermSocket, + {'term_manager': term_manager}), + (r"/", TerminalPageHandler), + (r"/xstatic/(.*)", tornado_xstatic.XStaticFileHandler, + {'allowed_modules': ['termjs']}) + ] + app = tornado.web.Application(handlers, static_path=STATIC_DIR, + xstatic_url = tornado_xstatic.url_maker('/xstatic/')) + # Serve at http://localhost:8765/ N.B. Leaving out 'localhost' here will + # work, but it will listen on the public network interface as well. + # Given what terminado does, that would be rather a security hole. + app.listen(8765, 'localhost') + try: + tornado.ioloop.IOLoop.instance().start() + finally: + term_manager.shutdown() +``` + +See the [demos +directory](https://github.com/takluyver/terminado/tree/master/demos) for +more examples. This is a simplified version of the `single.py` demo. + +Run the unit tests with: + +> $ pytest diff --git a/README.rst b/README.rst deleted file mode 100644 index 4803b8c..0000000 --- a/README.rst +++ /dev/null @@ -1,74 +0,0 @@ -This is a `Tornado `_ websocket backend for the -`Xterm.js `_ Javascript terminal emulator -library. - -It evolved out of `pyxterm `_, which was -part of `GraphTerm `_ (as lineterm.py), -v0.57.0 (2014-07-18), and ultimately derived from the public-domain `Ajaxterm -`_ code, v0.11 (2008-11-13) (also -on Github as part of `QWeb `_). - -Modules: - -* ``terminado.management``: controls launching virtual terminals, - connecting them to Tornado's event loop, and closing them down. -* ``terminado.websocket``: Provides a websocket handler for communicating with - a terminal. -* ``terminado.uimodule``: Provides a ``Terminal`` Tornado `UI Module - `_. - -JS: - -* ``terminado/_static/terminado.js``: A lightweight wrapper to set up a - term.js terminal with a websocket. - -Local Installation: - - $ pip install -e .[test] - - -Usage example: - -.. code:: python - - import os.path - import tornado.web - import tornado.ioloop - # This demo requires tornado_xstatic and XStatic-term.js - import tornado_xstatic - - import terminado - STATIC_DIR = os.path.join(os.path.dirname(terminado.__file__), "_static") - - class TerminalPageHandler(tornado.web.RequestHandler): - def get(self): - return self.render("termpage.html", static=self.static_url, - xstatic=self.application.settings['xstatic_url'], - ws_url_path="/websocket") - - if __name__ == '__main__': - term_manager = terminado.SingleTermManager(shell_command=['bash']) - handlers = [ - (r"/websocket", terminado.TermSocket, - {'term_manager': term_manager}), - (r"/", TerminalPageHandler), - (r"/xstatic/(.*)", tornado_xstatic.XStaticFileHandler, - {'allowed_modules': ['termjs']}) - ] - app = tornado.web.Application(handlers, static_path=STATIC_DIR, - xstatic_url = tornado_xstatic.url_maker('/xstatic/')) - # Serve at http://localhost:8765/ N.B. Leaving out 'localhost' here will - # work, but it will listen on the public network interface as well. - # Given what terminado does, that would be rather a security hole. - app.listen(8765, 'localhost') - try: - tornado.ioloop.IOLoop.instance().start() - finally: - term_manager.shutdown() - -See the `demos directory `_ -for more examples. This is a simplified version of the ``single.py`` demo. - -Run the unit tests with: - - $ pytest diff --git a/doc/conf.py b/doc/conf.py index db34a7f..37fe527 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -11,16 +11,17 @@ # 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 -HERE = os.path.dirname(__file__) -sys.path.insert(0, os.path.join(HERE, "..")) +HERE = osp.dirname(__file__) +sys.path.insert(0, osp.join(HERE, "..")) # 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. -# sys.path.insert(0, os.path.abspath('.')) +# documentation root, use osp.abspath to make it absolute, like shown here. +# sys.path.insert(0, osp.abspath('.')) # -- General configuration ------------------------------------------------ @@ -31,19 +32,11 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + "myst_parser", "sphinx.ext.autodoc", "sphinx.ext.intersphinx", ] -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix of source filenames. -source_suffix = ".rst" - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - # The master toctree document. master_doc = "index" @@ -56,7 +49,7 @@ # built documents. # # Get information from _version.py and use it to generate version and release -_version_py = os.path.join(HERE, "../terminado/_version.py") +_version_py = osp.join(HERE, "../terminado/_version.py") version_ns: dict = {} exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) # The short X.Y version. @@ -263,3 +256,8 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {"tornado": ("http://www.tornadoweb.org/en/stable/", None)} + + +def setup(app): + dest = osp.join(HERE, "changelog.md") + shutil.copy(osp.join(HERE, "..", "CHANGELOG.md"), dest) diff --git a/doc/index.rst b/doc/index.rst index 69cd971..072980c 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -4,18 +4,19 @@ Terminado Contents: .. toctree:: - :maxdepth: 2 + :maxdepth: 1 websocket uimodule - releasenotes + changelog .. seealso:: `Connecting Xterm.js to Terminado `_ From the Xterm.js docs -.. include:: ../README.rst +.. include:: ../README.md + :parser: myst_parser.sphinx_ Indices and tables diff --git a/doc/releasenotes.rst b/doc/releasenotes.rst deleted file mode 100644 index 023d244..0000000 --- a/doc/releasenotes.rst +++ /dev/null @@ -1,16 +0,0 @@ -Release notes -============= - -0.7 ---- - -- :meth:`terminado.TermSocket.open` now calls the ``open()`` method on the - parent class using ``super()``. This allows a mixin class; for instance, to - periodically send ping messages to keep a connection open. -- When a websocket client disconnects from a terminal managed by - :class:`~.UniqueTermManager`, the ``SIGHUP`` signal is sent to the process - group, not just the main process. -- Fixed :meth:`terminado.NamedTermManager.kill` to use the signal number passed - to it. -- Switched to Flit packaging. -- README and requirements for demos. diff --git a/pyproject.toml b/pyproject.toml index f845456..a0345e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,7 @@ build-backend = "hatchling.build" [project] name = "terminado" dynamic = ["version"] +readme = "README.md" license = { file = "LICENSE" } description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." classifiers = [ "Environment :: Web Environment", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3", "Topic :: Terminals :: Terminal Emulators/X Terminals",] @@ -15,16 +16,12 @@ dependencies = [ "ptyprocess;os_name!='nt'", "pywinpty>=1.1.0;os_name=='nt'", "t name = "Jupyter Development Team" email = "jupyter@googlegroups.com" -[project.readme] -file = "README.rst" -content-type = "text/x-rst" - [project.urls] Homepage = "https://github.com/jupyter/terminado" [project.optional-dependencies] test = [ "pytest>=7.0", "pre-commit", "pytest-timeout",] -docs = [ "sphinx", "pydata-sphinx-theme" ] +docs = [ "sphinx", "pydata-sphinx-theme", "myst_parser"] [tool.hatch.version] path = "terminado/_version.py"