coreconfig.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # coding: utf-8
  2. # Copyright (c) Jupyter Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. from collections import defaultdict
  5. from itertools import filterfalse
  6. import json
  7. import os.path as osp
  8. from .jlpmapp import HERE
  9. def pjoin(*args):
  10. """Join paths to create a real path.
  11. """
  12. return osp.abspath(osp.join(*args))
  13. def _get_default_core_data():
  14. """Get the data for the app template.
  15. """
  16. with open(pjoin(HERE, 'staging', 'package.json')) as fid:
  17. return json.load(fid)
  18. def _is_lab_package(name):
  19. """Whether a package name is in the lab namespace"""
  20. return name.startswith('@jupyterlab/')
  21. def _only_nonlab(collection):
  22. """Filter a dict/sequence to remove all lab packages
  23. This is useful to take the default values of e.g. singletons and filter
  24. away the '@jupyterlab/' namespace packages, but leave any others (e.g.
  25. lumino and react).
  26. """
  27. if isinstance(collection, dict):
  28. return dict(
  29. (k, v) for (k, v) in collection.items()
  30. if not _is_lab_package(k)
  31. )
  32. elif isinstance(collection, (list, tuple)):
  33. return list(filterfalse(_is_lab_package, collection))
  34. raise TypeError('collection arg should be either dict or list/tuple')
  35. class CoreConfig:
  36. """An object representing a core config.
  37. This enables custom lab application to override some parts of the core
  38. configuration of the build system.
  39. """
  40. def __init__(self):
  41. self._data = _get_default_core_data()
  42. def add(self, name, semver, extension=False, mime_extension=False):
  43. """Remove an extension/singleton.
  44. If neither extension or mimeExtension is True (the default)
  45. the package is added as a singleton dependency.
  46. name: string
  47. The npm package name
  48. semver: string
  49. The semver range for the package
  50. extension: bool
  51. Whether the package is an extension
  52. mime_extension: bool
  53. Whether the package is a MIME extension
  54. """
  55. data = self._data
  56. if not name:
  57. raise ValueError('Missing package name')
  58. if not semver:
  59. raise ValueError('Missing package semver')
  60. if name in data['resolutions']:
  61. raise ValueError('Package already present: %r' % (name,))
  62. data['resolutions'][name] = semver
  63. # If both mimeExtension and extensions are True, treat
  64. # as mime extension
  65. if mime_extension:
  66. data['jupyterlab']['mimeExtensions'][name] = ""
  67. data['dependencies'][name] = semver
  68. elif extension:
  69. data['jupyterlab']['extensions'][name] = ""
  70. data['dependencies'][name] = semver
  71. else:
  72. data['jupyterlab']['singletonPackages'].append(name)
  73. def remove(self, name):
  74. """Remove a package/extension.
  75. name: string
  76. The npm package name
  77. """
  78. data = self._data
  79. maps = (
  80. data['dependencies'],
  81. data['resolutions'],
  82. data['jupyterlab']['extensions'],
  83. data['jupyterlab']['mimeExtensions'],
  84. )
  85. for m in maps:
  86. try:
  87. del m[name]
  88. except KeyError:
  89. pass
  90. data['jupyterlab']['singletonPackages'].remove(name)
  91. def clear_packages(self, lab_only=True):
  92. """Clear the packages/extensions.
  93. """
  94. data = self._data
  95. # Clear all dependencies
  96. if lab_only:
  97. # Clear all "@jupyterlab/" dependencies
  98. data['dependencies'] = _only_nonlab(data['dependencies'])
  99. data['resolutions'] = _only_nonlab(data['resolutions'])
  100. data['jupyterlab']['extensions'] = _only_nonlab(
  101. data['jupyterlab']['extensions'])
  102. data['jupyterlab']['mimeExtensions'] = _only_nonlab(
  103. data['jupyterlab']['mimeExtensions'])
  104. data['jupyterlab']['singletonPackages'] = _only_nonlab(
  105. data['jupyterlab']['singletonPackages'])
  106. else:
  107. data['dependencies'] = {}
  108. data['resolutions'] = {}
  109. data['jupyterlab']['extensions'] = {}
  110. data['jupyterlab']['mimeExtensions'] = {}
  111. data['jupyterlab']['singletonPackages'] = []
  112. @property
  113. def extensions(self):
  114. """A dict mapping all extension names to their semver"""
  115. data = self._data
  116. return dict(
  117. (k, data['resolutions'][k])
  118. for k in data['jupyterlab']['extensions'].keys())
  119. @property
  120. def mime_extensions(self):
  121. """A dict mapping all MIME extension names to their semver"""
  122. data = self._data
  123. return dict(
  124. (k, data['resolutions'][k])
  125. for k in data['jupyterlab']['mimeExtensions'].keys())
  126. @property
  127. def singletons(self):
  128. """A dict mapping all singleton names to their semver"""
  129. data = self._data
  130. return dict(
  131. (k, data['resolutions'].get(k, None))
  132. for k in data['jupyterlab']['singletonPackages'])
  133. @property
  134. def static_dir(self):
  135. return self._data['jupyterlab']['staticDir']
  136. @static_dir.setter
  137. def static_dir(self, static_dir):
  138. self._data['jupyterlab']['staticDir'] = static_dir