extension.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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_jupyter_server_extension(nbapp):
  19. """Load the JupyterLab server extension.
  20. """
  21. # Delay imports to speed up jlpmapp
  22. from json import dumps
  23. from jupyterlab_launcher import add_handlers, LabConfig
  24. from notebook.utils import url_path_join as ujoin, url_escape
  25. from notebook._version import version_info
  26. from tornado.ioloop import IOLoop
  27. from markupsafe import Markup
  28. from .build_handler import build_path, Builder, BuildHandler
  29. from .extension_manager_handler import (
  30. extensions_handler_path, ExtensionManager, ExtensionHandler
  31. )
  32. from .commands import (
  33. get_app_dir, get_user_settings_dir, watch, ensure_dev, watch_dev,
  34. pjoin, DEV_DIR, HERE, get_app_info, ensure_core, get_workspaces_dir
  35. )
  36. web_app = nbapp.web_app
  37. logger = nbapp.log
  38. config = LabConfig()
  39. app_dir = getattr(nbapp, 'app_dir', get_app_dir())
  40. user_settings_dir = getattr(
  41. nbapp, 'user_settings_dir', get_user_settings_dir()
  42. )
  43. workspaces_dir = getattr(
  44. nbapp, 'workspaces_dir', get_workspaces_dir()
  45. )
  46. # Print messages.
  47. logger.info('JupyterLab extension loaded from %s' % HERE)
  48. logger.info('JupyterLab application directory is %s' % app_dir)
  49. config.app_name = 'JupyterLab Beta'
  50. config.app_namespace = 'jupyterlab'
  51. config.page_url = '/lab'
  52. config.cache_files = True
  53. # Check for core mode.
  54. core_mode = False
  55. if getattr(nbapp, 'core_mode', False) or app_dir.startswith(HERE):
  56. core_mode = True
  57. logger.info('Running JupyterLab in core mode')
  58. # Check for dev mode.
  59. dev_mode = False
  60. if getattr(nbapp, 'dev_mode', False) or app_dir.startswith(DEV_DIR):
  61. dev_mode = True
  62. logger.info('Running JupyterLab in dev mode')
  63. # Check for watch.
  64. watch_mode = getattr(nbapp, 'watch', False)
  65. if watch_mode and core_mode:
  66. logger.warn('Cannot watch in core mode, did you mean --dev-mode?')
  67. watch_mode = False
  68. if core_mode and dev_mode:
  69. logger.warn('Conflicting modes, choosing dev_mode over core_mode')
  70. core_mode = False
  71. page_config = web_app.settings.setdefault('page_config_data', dict())
  72. page_config['buildAvailable'] = not core_mode and not dev_mode
  73. page_config['buildCheck'] = not core_mode and not dev_mode
  74. page_config['token'] = nbapp.token
  75. page_config['devMode'] = dev_mode
  76. # Export the version info tuple to a JSON array. This gets printed
  77. # inside double quote marks, so we render it to a JSON string of the
  78. # JSON data (so that we can call JSON.parse on the frontend on it).
  79. # We also have to wrap it in `Markup` so that it isn't escaped
  80. # by Jinja. Otherwise, if the version has string parts these will be
  81. # escaped and then will have to be unescaped on the frontend.
  82. page_config['notebookVersion'] = Markup(dumps(dumps(version_info))[1:-1])
  83. if nbapp.file_to_run and type(nbapp).__name__ == "LabApp":
  84. relpath = os.path.relpath(nbapp.file_to_run, nbapp.notebook_dir)
  85. uri = url_escape(ujoin('/lab/tree', *relpath.split(os.sep)))
  86. nbapp.default_url = uri
  87. nbapp.file_to_run = ''
  88. if core_mode:
  89. app_dir = HERE
  90. logger.info(CORE_NOTE.strip())
  91. ensure_core(logger)
  92. elif dev_mode:
  93. app_dir = DEV_DIR
  94. ensure_dev(logger)
  95. if not watch_mode:
  96. logger.info(DEV_NOTE)
  97. config.app_settings_dir = pjoin(app_dir, 'settings')
  98. config.schemas_dir = pjoin(app_dir, 'schemas')
  99. config.themes_dir = pjoin(app_dir, 'themes')
  100. config.workspaces_dir = workspaces_dir
  101. info = get_app_info(app_dir)
  102. config.app_version = info['version']
  103. public_url = info['publicUrl']
  104. if public_url:
  105. config.public_url = public_url
  106. else:
  107. config.static_dir = pjoin(app_dir, 'static')
  108. config.user_settings_dir = user_settings_dir
  109. # The templates end up in the built static directory.
  110. config.templates_dir = pjoin(app_dir, 'static')
  111. if watch_mode:
  112. logger.info('Starting JupyterLab watch mode...')
  113. # Set the ioloop in case the watch fails.
  114. nbapp.ioloop = IOLoop.current()
  115. if dev_mode:
  116. watch_dev(logger)
  117. else:
  118. watch(app_dir, logger)
  119. page_config['buildAvailable'] = False
  120. config.cache_files = False
  121. base_url = web_app.settings['base_url']
  122. build_url = ujoin(base_url, build_path)
  123. builder = Builder(logger, core_mode, app_dir)
  124. build_handler = (build_url, BuildHandler, {'builder': builder})
  125. handlers = [build_handler]
  126. if not core_mode:
  127. ext_url = ujoin(base_url, extensions_handler_path)
  128. ext_manager = ExtensionManager(logger, app_dir)
  129. ext_handler = (ext_url, ExtensionHandler, {'manager': ext_manager})
  130. handlers.append(ext_handler)
  131. # Must add before the launcher handlers to avoid shadowing.
  132. web_app.add_handlers('.*$', handlers)
  133. add_handlers(web_app, config)