__init__.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. """Tornado handlers for the Lab view."""
  2. # Copyright (c) Jupyter Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. import glob
  5. import json
  6. import os
  7. from tornado import web
  8. from notebook.base.handlers import IPythonHandler, FileFindHandler
  9. from jinja2 import FileSystemLoader
  10. from notebook.utils import url_path_join as ujoin
  11. try:
  12. from ._version import __version__
  13. except ImportError as e:
  14. # when we are python 3 only, add 'from e' at the end to chain the exception.
  15. raise ImportError("No module named 'jupyter._version'. Build the jupyterlab package to generate this module, for example, with `pip install -e /path/to/jupyterlab/repo`.")
  16. #-----------------------------------------------------------------------------
  17. # Module globals
  18. #-----------------------------------------------------------------------------
  19. DEV_NOTE_NPM = """It looks like you're running JupyterLab from source.
  20. If you're working on the TypeScript sources of JupyterLab, try running
  21. npm run watch
  22. from the JupyterLab repo directory in another terminal window to have the
  23. system incrementally watch and build JupyterLab's TypeScript for you, as you
  24. make changes.
  25. """
  26. HERE = os.path.dirname(__file__)
  27. FILE_LOADER = FileSystemLoader(HERE)
  28. BUILT_FILES = os.path.join(HERE, 'build')
  29. PREFIX = '/lab'
  30. EXTENSION_PREFIX = '/labextension'
  31. def get_labextension_manifest_data_by_folder(folder):
  32. """Get the manifest data for a given lab extension folder
  33. """
  34. manifest_files = glob.glob(os.path.join(folder, '*.manifest'))
  35. manifests = {}
  36. for file in manifest_files:
  37. with open(file) as fid:
  38. manifest = json.load(fid)
  39. manifests[manifest['name']] = manifest
  40. return manifests
  41. def get_labextension_manifest_data_by_name(name):
  42. """Get the manifest data for a given lab extension folder
  43. """
  44. from .labextensions import _labextension_dirs
  45. for exts in _labextension_dirs():
  46. full_dest = os.path.join(exts, name)
  47. if os.path.exists(full_dest):
  48. return get_labextension_manifest_data_by_folder(full_dest)
  49. class LabHandler(IPythonHandler):
  50. """Render the Jupyter Lab View."""
  51. @web.authenticated
  52. def get(self):
  53. static_prefix = ujoin(self.base_url, PREFIX)
  54. labextensions = self.application.labextensions
  55. data = get_labextension_manifest_data_by_folder(BUILT_FILES)
  56. if 'main' not in data or 'extensions' not in data:
  57. msg = ('JupyterLab build artifacts not detected, please see ' +
  58. 'CONTRIBUTING.md for build instructions.')
  59. self.log.error(msg)
  60. self.write(self.render_template('error.html',
  61. status_code=500,
  62. status_message='JupyterLab Error',
  63. page_title='JupyterLab Error',
  64. message=msg))
  65. return
  66. main = data['main']['entry']
  67. bundles = [ujoin(static_prefix, name + '.bundle.js') for name in
  68. ['loader', 'main', 'extensions']]
  69. entries = [data['extensions']['entry']]
  70. # Only load CSS files if they exist.
  71. css_files = []
  72. for css_file in ['main.css', 'extensions.css']:
  73. if os.path.isfile(os.path.join(BUILT_FILES, css_file)):
  74. css_files.append(ujoin(static_prefix, css_file))
  75. # Gather the lab extension files and entry points.
  76. for name in labextensions:
  77. data = get_labextension_manifest_data_by_name(name)
  78. if data is None:
  79. self.log.warn('Could not locate extension: ' + name)
  80. continue
  81. for value in data.values():
  82. if value.get('entry', None):
  83. entries.append(value['entry'])
  84. bundles.append('%s/%s/%s' % (
  85. EXTENSION_PREFIX, name, value['files'][0]
  86. ))
  87. for fname in value['files']:
  88. if os.path.splitext(fname)[1] == '.css':
  89. css_files.append('%s/%s/%s' % (
  90. EXTENSION_PREFIX, name, fname
  91. ))
  92. self.write(self.render_template('lab.html',
  93. static_prefix=static_prefix,
  94. page_title='JupyterLab Alpha Preview',
  95. terminals_available=self.settings['terminals_available'],
  96. mathjax_url=self.mathjax_url,
  97. jupyterlab_main=main,
  98. jupyterlab_css=css_files,
  99. jupyterlab_bundles=bundles,
  100. plugin_entries=entries,
  101. mathjax_config='TeX-AMS_HTML-full,Safe',
  102. #mathjax_config=self.mathjax_config # for the next release of the notebook
  103. ))
  104. def get_template(self, name):
  105. return FILE_LOADER.load(self.settings['jinja2_env'], name)
  106. #-----------------------------------------------------------------------------
  107. # URL to handler mappings
  108. #-----------------------------------------------------------------------------
  109. default_handlers = [
  110. (PREFIX + r'/?', LabHandler),
  111. (PREFIX + r"/(.*)", FileFindHandler,
  112. {'path': BUILT_FILES}),
  113. ]
  114. def _jupyter_server_extension_paths():
  115. return [{
  116. "module": "jupyterlab"
  117. }]
  118. def load_jupyter_server_extension(nbapp):
  119. from jupyter_core.paths import jupyter_path
  120. from .labapp import get_labextensions
  121. base_dir = os.path.realpath(os.path.join(HERE, '..'))
  122. dev_mode = os.path.exists(os.path.join(base_dir, '.git'))
  123. if dev_mode:
  124. nbapp.log.info(DEV_NOTE_NPM)
  125. nbapp.log.info('JupyterLab alpha preview extension loaded from %s' % HERE)
  126. webapp = nbapp.web_app
  127. webapp.labextensions = get_labextensions(parent=nbapp)
  128. base_url = webapp.settings['base_url']
  129. webapp.add_handlers(".*$",
  130. [(ujoin(base_url, h[0]),) + h[1:] for h in default_handlers])
  131. labextension_handler = (
  132. r"%s/(.*)" % EXTENSION_PREFIX, FileFindHandler, {
  133. 'path': jupyter_path('labextensions'),
  134. 'no_cache_paths': ['/'], # don't cache anything in labbextensions
  135. }
  136. )
  137. webapp.add_handlers(".*$", [labextension_handler])