coreconfig.py 5.1 KB

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