extension.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. # ----------------------------------------------------------------------------
  6. # Module globals
  7. # ----------------------------------------------------------------------------
  8. import os
  9. DEV_NOTE = """You're running JupyterLab from source.
  10. If you're working on the TypeScript sources of JupyterLab, try running
  11. jupyter lab --dev-mode --watch
  12. to have the system incrementally watch and build JupyterLab for you, as you
  13. make changes.
  14. """
  15. CORE_NOTE = """
  16. Running the core application with no additional extensions or settings
  17. """
  18. def load_config(nbapp):
  19. """Load the JupyterLab configuration and defaults for a given application.
  20. """
  21. from jupyterlab_server import LabConfig
  22. from .commands import (
  23. get_app_dir,
  24. get_app_info,
  25. get_workspaces_dir,
  26. get_user_settings_dir,
  27. pjoin
  28. )
  29. app_dir = getattr(nbapp, 'app_dir', get_app_dir())
  30. info = get_app_info(app_dir)
  31. static_url = info['staticUrl']
  32. user_settings_dir = getattr(
  33. nbapp, 'user_settings_dir', get_user_settings_dir()
  34. )
  35. workspaces_dir = getattr(nbapp, 'workspaces_dir', get_workspaces_dir())
  36. config = LabConfig()
  37. config.app_dir = app_dir
  38. config.app_name = 'JupyterLab'
  39. config.app_namespace = 'jupyterlab'
  40. config.app_settings_dir = pjoin(app_dir, 'settings')
  41. config.app_version = info['version']
  42. config.cache_files = True
  43. config.schemas_dir = pjoin(app_dir, 'schemas')
  44. config.templates_dir = pjoin(app_dir, 'static')
  45. config.themes_dir = pjoin(app_dir, 'themes')
  46. config.user_settings_dir = user_settings_dir
  47. config.workspaces_dir = workspaces_dir
  48. if getattr(nbapp, 'override_static_url', ''):
  49. static_url = nbapp.override_static_url
  50. if getattr(nbapp, 'override_theme_url', ''):
  51. config.themes_url = nbapp.override_theme_url
  52. config.themes_dir = ''
  53. # shim for jupyterlab_server 0.3
  54. # XXX remove after next JLab release (current is 1.0.0a6)
  55. if static_url:
  56. if hasattr(config, 'static_url'):
  57. config.static_url = static_url
  58. else:
  59. config.public_url = static_url
  60. else:
  61. config.static_dir = pjoin(app_dir, 'static')
  62. return config
  63. def load_jupyter_server_extension(nbapp):
  64. """Load the JupyterLab server extension.
  65. """
  66. # Delay imports to speed up jlpmapp
  67. from json import dumps
  68. from jupyterlab_server import add_handlers
  69. from notebook.utils import url_path_join as ujoin, url_escape
  70. from notebook._version import version_info
  71. from tornado.ioloop import IOLoop
  72. from markupsafe import Markup
  73. from .handlers.build_handler import build_path, Builder, BuildHandler
  74. from .handlers.extension_manager_handler import (
  75. extensions_handler_path, ExtensionManager, ExtensionHandler
  76. )
  77. from .handlers.error_handler import ErrorHandler
  78. from .commands import (
  79. DEV_DIR, HERE, ensure_app, ensure_core, ensure_dev, watch,
  80. watch_dev, get_app_dir
  81. )
  82. web_app = nbapp.web_app
  83. logger = nbapp.log
  84. base_url = nbapp.base_url
  85. # Handle the app_dir
  86. app_dir = getattr(nbapp, 'app_dir', get_app_dir())
  87. # Check for core mode.
  88. core_mode = False
  89. if getattr(nbapp, 'core_mode', False) or app_dir.startswith(HERE):
  90. app_dir = HERE
  91. core_mode = True
  92. logger.info('Running JupyterLab in core mode')
  93. # Check for dev mode.
  94. dev_mode = False
  95. if getattr(nbapp, 'dev_mode', False) or app_dir.startswith(DEV_DIR):
  96. app_dir = DEV_DIR
  97. dev_mode = True
  98. logger.info('Running JupyterLab in dev mode')
  99. # Set the value on nbapp so it will get picked up in load_config
  100. nbapp.app_dir = app_dir
  101. config = load_config(nbapp)
  102. config.app_name = 'JupyterLab'
  103. config.app_namespace = 'jupyterlab'
  104. # shim for jupyterlab_server 0.3
  105. # XXX remove after next JLab release (current is 1.0.0a6)
  106. if hasattr(config, 'app_url'):
  107. config.app_url = '/lab'
  108. else:
  109. config.page_url = '/lab'
  110. config.cache_files = True
  111. # Check for watch.
  112. watch_mode = getattr(nbapp, 'watch', False)
  113. if watch_mode and core_mode:
  114. logger.warn('Cannot watch in core mode, did you mean --dev-mode?')
  115. watch_mode = False
  116. if core_mode and dev_mode:
  117. logger.warn('Conflicting modes, choosing dev_mode over core_mode')
  118. core_mode = False
  119. page_config = web_app.settings.setdefault('page_config_data', dict())
  120. page_config['buildAvailable'] = not core_mode and not dev_mode
  121. page_config['buildCheck'] = not core_mode and not dev_mode
  122. page_config['devMode'] = dev_mode
  123. page_config['token'] = nbapp.token
  124. # Export the version info tuple to a JSON array. This gets printed
  125. # inside double quote marks, so we render it to a JSON string of the
  126. # JSON data (so that we can call JSON.parse on the frontend on it).
  127. # We also have to wrap it in `Markup` so that it isn't escaped
  128. # by Jinja. Otherwise, if the version has string parts these will be
  129. # escaped and then will have to be unescaped on the frontend.
  130. page_config['notebookVersion'] = Markup(dumps(dumps(version_info))[1:-1])
  131. if nbapp.file_to_run and type(nbapp).__name__ == "LabApp":
  132. relpath = os.path.relpath(nbapp.file_to_run, nbapp.notebook_dir)
  133. uri = url_escape(ujoin('/lab/tree', *relpath.split(os.sep)))
  134. nbapp.default_url = uri
  135. nbapp.file_to_run = ''
  136. # Print messages.
  137. logger.info('JupyterLab extension loaded from %s' % HERE)
  138. logger.info('JupyterLab application directory is %s' % app_dir)
  139. build_url = ujoin(base_url, build_path)
  140. builder = Builder(logger, core_mode, app_dir)
  141. build_handler = (build_url, BuildHandler, {'builder': builder})
  142. handlers = [build_handler]
  143. errored = False
  144. if core_mode:
  145. logger.info(CORE_NOTE.strip())
  146. ensure_core(logger)
  147. elif dev_mode:
  148. if not watch_mode:
  149. ensure_dev(logger)
  150. logger.info(DEV_NOTE)
  151. # Make sure the app dir exists.
  152. else:
  153. msgs = ensure_app(app_dir)
  154. if msgs:
  155. [logger.error(msg) for msg in msgs]
  156. handler = (ujoin(base_url, '/lab'), ErrorHandler, { 'messages': msgs })
  157. handlers.append(handler)
  158. errored = True
  159. if watch_mode:
  160. logger.info('Starting JupyterLab watch mode...')
  161. # Set the ioloop in case the watch fails.
  162. nbapp.ioloop = IOLoop.current()
  163. if dev_mode:
  164. watch_dev(logger)
  165. else:
  166. watch(app_dir, logger)
  167. page_config['buildAvailable'] = False
  168. config.cache_files = False
  169. if not core_mode and not errored:
  170. ext_url = ujoin(base_url, extensions_handler_path)
  171. ext_manager = ExtensionManager(logger, app_dir)
  172. ext_handler = (ext_url, ExtensionHandler, {'manager': ext_manager})
  173. handlers.append(ext_handler)
  174. # Must add before the root server handlers to avoid shadowing.
  175. web_app.add_handlers('.*$', handlers)
  176. # If running under JupyterHub, add more metadata.
  177. if hasattr(nbapp, 'hub_prefix'):
  178. page_config['hubPrefix'] = nbapp.hub_prefix
  179. page_config['hubHost'] = nbapp.hub_host
  180. page_config['hubUser'] = nbapp.user
  181. api_token = os.getenv('JUPYTERHUB_API_TOKEN', '')
  182. page_config['token'] = api_token
  183. # Add the root handlers if we have not errored.
  184. if not errored:
  185. add_handlers(web_app, config)