labapp.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. # coding: utf-8
  2. """A tornado based Jupyter lab server."""
  3. # Copyright (c) Jupyter Development Team.
  4. # Distributed under the terms of the Modified BSD License.
  5. import os
  6. from tornado import web
  7. from notebook.notebookapp import NotebookApp
  8. from traitlets import Unicode
  9. from notebook.base.handlers import IPythonHandler, FileFindHandler
  10. from jinja2 import FileSystemLoader
  11. from notebook.utils import url_path_join as ujoin
  12. from jupyter_core.paths import jupyter_path
  13. from ._version import __version__
  14. from .labextensions import (
  15. find_labextension, validate_labextension_folder,
  16. get_labextension_manifest_data_by_name,
  17. get_labextension_manifest_data_by_folder,
  18. get_labextension_config_python, CONFIG_SECTION
  19. )
  20. #-----------------------------------------------------------------------------
  21. # Module globals
  22. #-----------------------------------------------------------------------------
  23. DEV_NOTE_NPM = """It looks like you're running JupyterLab from source.
  24. If you're working on the TypeScript sources of JupyterLab, try running
  25. npm run watch
  26. from the JupyterLab repo directory in another terminal window to have the
  27. system incrementally watch and build JupyterLab's TypeScript for you, as you
  28. make changes.
  29. """
  30. HERE = os.path.dirname(__file__)
  31. FILE_LOADER = FileSystemLoader(HERE)
  32. BUILT_FILES = os.path.join(HERE, 'build')
  33. PREFIX = '/lab'
  34. EXTENSION_PREFIX = '/labextension'
  35. class LabHandler(IPythonHandler):
  36. """Render the Jupyter Lab View."""
  37. def initialize(self, labextensions):
  38. self.labextensions = labextensions
  39. @web.authenticated
  40. def get(self):
  41. static_prefix = ujoin(self.base_url, PREFIX)
  42. labextensions = self.labextensions
  43. data = get_labextension_manifest_data_by_folder(BUILT_FILES)
  44. if 'main' not in data:
  45. msg = ('JupyterLab build artifacts not detected, please see ' +
  46. 'CONTRIBUTING.md for build instructions.')
  47. self.log.error(msg)
  48. self.write(self.render_template('error.html',
  49. status_code=500,
  50. status_message='JupyterLab Error',
  51. page_title='JupyterLab Error',
  52. message=msg))
  53. return
  54. main = data['main']['entry']
  55. bundles = [ujoin(static_prefix, name + '.bundle.js') for name in
  56. ['loader', 'main']]
  57. entries = []
  58. # Only load CSS files if they exist.
  59. css_files = []
  60. for css_file in ['main.css']:
  61. if os.path.isfile(os.path.join(BUILT_FILES, css_file)):
  62. css_files.append(ujoin(static_prefix, css_file))
  63. config = dict(
  64. static_prefix=static_prefix,
  65. page_title='JupyterLab Alpha Preview',
  66. mathjax_url=self.mathjax_url,
  67. jupyterlab_main=main,
  68. jupyterlab_css=css_files,
  69. jupyterlab_bundles=bundles,
  70. plugin_entries=entries,
  71. mathjax_config='TeX-AMS_HTML-full,Safe',
  72. #mathjax_config=self.mathjax_config # for the next release of the notebook
  73. )
  74. configData = dict(
  75. terminalsAvailable=self.settings.get('terminals_available', False),
  76. )
  77. extension_prefix = ujoin(self.base_url, EXTENSION_PREFIX)
  78. # Gather the lab extension files and entry points.
  79. for (name, data) in sorted(labextensions.items()):
  80. for value in data.values():
  81. if not isinstance(value, dict):
  82. continue
  83. if value.get('entry', None):
  84. entries.append(value['entry'])
  85. bundles.append('%s/%s/%s' % (
  86. extension_prefix, name, value['files'][0]
  87. ))
  88. for fname in value['files']:
  89. if os.path.splitext(fname)[1] == '.css':
  90. css_files.append('%s/%s/%s' % (
  91. extension_prefix, name, fname
  92. ))
  93. python_module = data.get('python_module', None)
  94. if python_module:
  95. try:
  96. value = get_labextension_config_python(python_module)
  97. configData.update(value)
  98. except Exception as e:
  99. self.log.error(e)
  100. config['jupyterlab_config'] = configData
  101. self.write(self.render_template('lab.html', **config))
  102. def get_template(self, name):
  103. return FILE_LOADER.load(self.settings['jinja2_env'], name)
  104. def load_jupyter_server_extension(nbapp):
  105. """Load the JupyterLab server extension.
  106. """
  107. # Print messages.
  108. nbapp.log.info('JupyterLab alpha preview extension loaded from %s' % HERE)
  109. base_dir = os.path.realpath(os.path.join(HERE, '..'))
  110. dev_mode = os.path.exists(os.path.join(base_dir, '.git'))
  111. if dev_mode:
  112. nbapp.log.info(DEV_NOTE_NPM)
  113. # Get the appropriate lab config.
  114. lab_config = nbapp.config.get(CONFIG_SECTION, {})
  115. web_app = nbapp.web_app
  116. # Add the lab extensions to the web app.
  117. out = dict()
  118. for (name, ext_config) in lab_config.labextensions.items():
  119. if not ext_config['enabled']:
  120. continue
  121. folder = find_labextension(name)
  122. if folder is None:
  123. continue
  124. warnings = validate_labextension_folder(name, folder)
  125. if warnings:
  126. continue
  127. data = get_labextension_manifest_data_by_name(name)
  128. if data is None:
  129. continue
  130. data['python_module'] = ext_config.get('python_module', None)
  131. out[name] = data
  132. # Add the handlers to the web app
  133. default_handlers = [
  134. (PREFIX + r'/?', LabHandler, {
  135. 'labextensions': out
  136. }),
  137. (PREFIX + r"/(.*)", FileFindHandler,
  138. {'path': BUILT_FILES}),
  139. ]
  140. base_url = web_app.settings['base_url']
  141. web_app.add_handlers(".*$",
  142. [(ujoin(base_url, h[0]),) + h[1:] for h in default_handlers])
  143. extension_prefix = ujoin(base_url, EXTENSION_PREFIX)
  144. labextension_handler = (
  145. r"%s/(.*)" % extension_prefix, FileFindHandler, {
  146. 'path': jupyter_path('labextensions'),
  147. 'no_cache_paths': ['/'], # don't cache anything in labbextensions
  148. }
  149. )
  150. web_app.add_handlers(".*$", [labextension_handler])
  151. class LabApp(NotebookApp):
  152. version = __version__
  153. description = """
  154. JupyterLab - An extensible computational environment for Jupyter.
  155. This launches a Tornado based HTML Server that serves up an
  156. HTML5/Javascript JupyterLab client.
  157. """
  158. examples = """
  159. jupyter lab # start JupyterLab
  160. jupyter lab --certfile=mycert.pem # use SSL/TLS certificate
  161. """
  162. subcommands = dict()
  163. default_url = Unicode('/lab', config=True,
  164. help="The default URL to redirect to from `/`")
  165. #-----------------------------------------------------------------------------
  166. # Main entry point
  167. #-----------------------------------------------------------------------------
  168. main = launch_new_instance = LabApp.launch_instance