diff --git a/src/bin/sage-notebook b/src/bin/sage-notebook index 2e8b12e1a1c..24c7f735c2f 100755 --- a/src/bin/sage-notebook +++ b/src/bin/sage-notebook @@ -7,19 +7,20 @@ import ast import argparse import logging import textwrap + +from contextlib import contextmanager + logging.basicConfig() logger = logging.getLogger() from sage.misc.banner import banner - _system_jupyter_url = "https://doc.sagemath.org/html/en/installation/launching.html#setting-up-sagemath-as-a-jupyter-kernel-in-an-existing-jupyter-notebook-or-jupyterlab-installation" class NotebookJupyter(): def print_banner(self): - banner() print('Please wait while the Sage Jupyter Notebook server starts...') @classmethod @@ -45,7 +46,6 @@ class NotebookJupyter(): class NotebookJupyterlab(): def print_banner(self): - banner() print('Please wait while the Jupyterlab server starts...') @classmethod @@ -71,7 +71,6 @@ class NotebookJupyterlab(): class NotebookNbclassic(): def print_banner(self): - banner() print('Please wait while the Jupyterlab server starts...') @classmethod @@ -94,7 +93,6 @@ class NotebookNbclassic(): class NotebookRetrolab(): def print_banner(self): - banner() print('Please wait while the Jupyterlab server starts...') @classmethod @@ -118,7 +116,6 @@ class NotebookRetrolab(): class SageNBExport(NotebookJupyter): def print_banner(self): - banner() print('Please wait while the SageNB export server starts...') @classmethod @@ -172,7 +169,6 @@ EXAMPLES: """ - notebook_launcher = { 'default': NotebookJupyter, # change this to change the default 'ipython': NotebookJupyter, @@ -183,7 +179,6 @@ notebook_launcher = { 'export': SageNBExport, } - notebook_names = ', '.join(notebook_launcher.keys()) @@ -230,6 +225,34 @@ def trac_23428_browser_workaround(): os.environ['BROWSER'] = 'open' +@contextmanager +def sage_doc_server(): + from sage.env import SAGE_DOC_SERVER_URL + + if SAGE_DOC_SERVER_URL: + print(f'Sage doc server running at {SAGE_DOC_SERVER_URL}') + yield + else: + from functools import partial + from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer + from threading import Thread + + from sage.env import SAGE_DOC, SAGE_DOC_LOCAL_PORT as port + + server = ThreadingHTTPServer(('localhost', int(port)), + partial(SimpleHTTPRequestHandler, directory=SAGE_DOC)) + server_thread = Thread(target=server.serve_forever, name="sage_doc_server") + server_thread.start() + print(f'Sage doc server started running at http://localhost:{port}') + + try: + yield + finally: + server.shutdown() + server_thread.join() + print(f'Sage doc server stopped runnning at http://localhost:{port}') + + if __name__ == '__main__': parser = make_parser() args, unknown = parser.parse_known_args(sys.argv[1:]) @@ -270,4 +293,7 @@ if __name__ == '__main__': launcher.print_help() sys.exit(0) - launcher(unknown) + banner() + + with sage_doc_server(): + launcher(unknown) diff --git a/src/sage/env.py b/src/sage/env.py index d1a87df74ce..7e1522ff587 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -185,6 +185,10 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st SAGE_PKGS = var("SAGE_PKGS", join(SAGE_ROOT, "build", "pkgs")) SAGE_ROOT_GIT = var("SAGE_ROOT_GIT", join(SAGE_ROOT, ".git")) +# Sage doc server (local server with PORT if URL is not given) +SAGE_DOC_SERVER_URL = var("SAGE_DOC_SERVER_URL") +SAGE_DOC_LOCAL_PORT = var("SAGE_DOC_LOCAL_PORT", "8000") + # ~/.sage DOT_SAGE = var("DOT_SAGE", join(os.environ.get("HOME"), ".sage")) SAGE_STARTUP_FILE = var("SAGE_STARTUP_FILE", join(DOT_SAGE, "init.sage")) diff --git a/src/sage/repl/ipython_kernel/kernel.py b/src/sage/repl/ipython_kernel/kernel.py index a4642014e90..28e9e703348 100644 --- a/src/sage/repl/ipython_kernel/kernel.py +++ b/src/sage/repl/ipython_kernel/kernel.py @@ -93,40 +93,48 @@ def help_links(self): sage: sk = SageKernel.__new__(SageKernel) sage: sk.help_links [{'text': 'Sage Documentation', - 'url': 'kernelspecs/sagemath/doc/html/en/index.html'}, + 'url': 'http://localhost:8000/html/en/index.html'}, ...] """ - from sage.repl.ipython_kernel.install import SageKernelSpec - identifier = SageKernelSpec.identifier() - kernel_url = lambda x: 'kernelspecs/{0}/{1}'.format(identifier, x) + from sage.env import SAGE_DOC_SERVER_URL as url + + if url: + def doc_url(path): + return '{}/{}'.format(url, path) + else: + from sage.env import SAGE_DOC_LOCAL_PORT as port + + def doc_url(path): + return 'http://localhost:{}/{}'.format(port, path) + return [ { 'text': 'Sage Documentation', - 'url': kernel_url('doc/html/en/index.html'), + 'url': doc_url("html/en/index.html"), }, { 'text': 'Tutorial', - 'url': kernel_url('doc/html/en/tutorial/index.html'), + 'url': doc_url('html/en/tutorial/index.html'), }, { 'text': 'Thematic Tutorials', - 'url': kernel_url('doc/html/en/thematic_tutorials/index.html'), + 'url': doc_url('html/en/thematic_tutorials/index.html'), }, { 'text': 'FAQs', - 'url': kernel_url('doc/html/en/faq/index.html'), + 'url': doc_url('html/en/faq/index.html'), }, { 'text': 'PREP Tutorials', - 'url': kernel_url('doc/html/en/prep/index.html'), + 'url': doc_url('html/en/prep/index.html'), }, { 'text': 'Reference', - 'url': kernel_url('doc/html/en/reference/index.html'), + 'url': doc_url('html/en/reference/index.html'), }, { 'text': "Developer's Guide", - 'url': kernel_url('doc/html/en/developer/index.html'), + 'url': doc_url('html/en/developer/index.html'), }, { 'text': "Python",