jupyter-builder 0.1.0a2__py3-none-any.whl → 0.1.0a3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,5 +9,5 @@ except ImportError:
9
9
  # the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs
10
10
  import warnings
11
11
 
12
- warnings.warn("Importing 'jupyter_builder' outside a proper installation.")
12
+ warnings.warn("Importing 'jupyter_builder' outside a proper installation.", stacklevel=1)
13
13
  __version__ = "dev"
@@ -4,6 +4,7 @@
4
4
  # Distributed under the terms of the Modified BSD License.
5
5
 
6
6
  from __future__ import annotations
7
+
7
8
  import os
8
9
  from copy import copy
9
10
 
@@ -15,9 +16,6 @@ from .debug_log_file_mixin import DebugLogFileMixin
15
16
 
16
17
  HERE = os.path.dirname(os.path.abspath(__file__))
17
18
 
18
-
19
- # from .federated_labextensions import build_labextension, develop_labextension_py, watch_labextension
20
-
21
19
  flags = dict(base_flags)
22
20
 
23
21
  develop_flags = copy(flags)
@@ -41,7 +41,8 @@ def _compare_ranges(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False
41
41
  # Set return_value to a sentinel value
42
42
  return_value = False
43
43
 
44
- # r1.set may be a list of ranges if the range involved an ||, so we need to test for overlaps between each pair.
44
+ # r1.set may be a list of ranges if the range involved an ||,
45
+ # so we need to test for overlaps between each pair.
45
46
  for r1set, r2set in itertools.product(r1.set, r2.set):
46
47
  x1 = r1set[0].semver
47
48
  x2 = r1set[-1].semver
@@ -47,18 +47,18 @@ class DebugLogFileMixin(Configurable):
47
47
  for line in msg:
48
48
  self.log.debug(line)
49
49
  if isinstance(ex, SystemExit):
50
- warnings.warn(f"An error occurred. See the log file for details: {log_path}")
50
+ warnings.warn(
51
+ f"An error occurred. See the log file for details: {log_path}", stacklevel=1
52
+ )
51
53
  raise
52
- warnings.warn("An error occurred.")
53
- warnings.warn(msg[-1].strip())
54
- warnings.warn(f"See the log file for details: {log_path}")
54
+ warnings.warn("An error occurred.", stacklevel=1)
55
+ warnings.warn(msg[-1].strip(), stacklevel=1)
56
+ warnings.warn(f"See the log file for details: {log_path}", stacklevel=1)
55
57
  self.exit(1)
56
58
  else:
57
59
  log.removeHandler(_debug_handler)
58
60
  _debug_handler.flush()
59
61
  _debug_handler.close()
60
- try:
62
+ with contextlib.suppress(FileNotFoundError):
61
63
  os.remove(log_path)
62
- except FileNotFoundError:
63
- pass
64
64
  log.removeHandler(_debug_handler)
@@ -5,9 +5,9 @@ import os
5
5
 
6
6
  from traitlets import Bool, Unicode
7
7
 
8
- from ..base_extension_app import BaseExtensionApp
9
- from ..core_path import default_core_path
10
- from ..federated_extensions import build_labextension
8
+ from jupyter_builder.base_extension_app import BaseExtensionApp
9
+ from jupyter_builder.core_path import default_core_path
10
+ from jupyter_builder.federated_extensions import build_labextension
11
11
 
12
12
  HERE = os.path.dirname(os.path.abspath(__file__))
13
13
 
@@ -27,7 +27,7 @@ class BuildLabExtensionApp(BaseExtensionApp):
27
27
  help="Directory containing core application package.json file",
28
28
  )
29
29
 
30
- aliases = {
30
+ aliases = { # noqa: RUF012
31
31
  "static-url": "BuildLabExtensionApp.static_url",
32
32
  "development": "BuildLabExtensionApp.development",
33
33
  "source-map": "BuildLabExtensionApp.source_map",
@@ -7,8 +7,8 @@ from copy import copy
7
7
  from jupyter_core.application import base_flags
8
8
  from traitlets import Bool, Unicode
9
9
 
10
- from ..base_extension_app import BaseExtensionApp
11
- from ..federated_extensions import develop_labextension_py
10
+ from jupyter_builder.base_extension_app import BaseExtensionApp
11
+ from jupyter_builder.federated_extensions import develop_labextension_py
12
12
 
13
13
  flags = dict(base_flags)
14
14
  develop_flags = copy(flags)
@@ -5,9 +5,9 @@ import os
5
5
 
6
6
  from traitlets import Bool, Unicode
7
7
 
8
- from ..base_extension_app import BaseExtensionApp
9
- from ..federated_extensions import watch_labextension
10
- from ..core_path import default_core_path
8
+ from jupyter_builder.base_extension_app import BaseExtensionApp
9
+ from jupyter_builder.core_path import default_core_path
10
+ from jupyter_builder.federated_extensions import watch_labextension
11
11
 
12
12
  HERE = os.path.dirname(os.path.abspath(__file__))
13
13
 
@@ -25,7 +25,7 @@ class WatchLabExtensionApp(BaseExtensionApp):
25
25
  help="Directory containing core application package.json file",
26
26
  )
27
27
 
28
- aliases = {
28
+ aliases = { # noqa: RUF012
29
29
  "core-path": "WatchLabExtensionApp.core_path",
30
30
  "development": "WatchLabExtensionApp.development",
31
31
  "source-map": "WatchLabExtensionApp.source_map",
@@ -25,7 +25,6 @@ from jupyter_core.paths import ENV_JUPYTER_PATH, SYSTEM_JUPYTER_PATH, jupyter_da
25
25
  from jupyter_core.utils import ensure_dir_exists
26
26
  from jupyter_server.extension.serverextension import ArgumentConflict
27
27
 
28
- # from jupyterlab_server.config import get_federated_extensions
29
28
  from .federated_extensions_requirements import get_federated_extensions
30
29
 
31
30
  try:
@@ -33,6 +32,8 @@ try:
33
32
  except ImportError:
34
33
  from tomli import load
35
34
 
35
+ from .core_path import default_core_path
36
+
36
37
  # from .commands import _test_overlap TO BE DONE -----------------------------
37
38
 
38
39
  DEPRECATED_ARGUMENT = object()
@@ -95,7 +96,7 @@ def develop_labextension( # noqa
95
96
  ensure_dir_exists(labext)
96
97
 
97
98
  if isinstance(path, (list, tuple)):
98
- msg = "path must be a string pointing to a single extension to install; call this function multiple times to install multiple extensions"
99
+ msg = "path must be a string pointing to a single extension to install; call this function multiple times to install multiple extensions" # noqa: E501
99
100
  raise TypeError(msg)
100
101
 
101
102
  if not destination:
@@ -104,7 +105,7 @@ def develop_labextension( # noqa
104
105
  full_dest = normpath(pjoin(labext, destination))
105
106
  if overwrite and os.path.lexists(full_dest):
106
107
  if logger:
107
- logger.info("Removing: %s" % full_dest)
108
+ logger.info("Removing: %s", full_dest)
108
109
  if os.path.isdir(full_dest) and not os.path.islink(full_dest):
109
110
  shutil.rmtree(full_dest)
110
111
  else:
@@ -124,14 +125,15 @@ def develop_labextension( # noqa
124
125
  if platform.platform().startswith("Windows"):
125
126
  msg = (
126
127
  "Symlinks can be activated on Windows 10 for Python version 3.8 or higher"
127
- " by activating the 'Developer Mode'. That may not be allowed by your administrators.\n"
128
+ " by activating the 'Developer Mode'. That may not be allowed by your administrators.\n" # noqa: E501
128
129
  "See https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development"
129
130
  )
130
131
  raise OSError(msg) from e
131
132
  raise
132
133
 
133
134
  elif not os.path.islink(full_dest):
134
- raise ValueError("%s exists and is not a symlink" % full_dest)
135
+ msg = f"{full_dest} exists and is not a symlink"
136
+ raise ValueError(msg)
135
137
 
136
138
  elif os.path.isdir(path):
137
139
  path = pjoin(os.path.abspath(path), "") # end in path separator
@@ -139,7 +141,7 @@ def develop_labextension( # noqa
139
141
  dest_dir = pjoin(full_dest, parent[len(path) :])
140
142
  if not os.path.exists(dest_dir):
141
143
  if logger:
142
- logger.info("Making directory: %s" % dest_dir)
144
+ logger.info("Making directory: %s", dest_dir)
143
145
  os.makedirs(dest_dir)
144
146
  for file_name in files:
145
147
  src = pjoin(parent, file_name)
@@ -152,7 +154,7 @@ def develop_labextension( # noqa
152
154
  return full_dest
153
155
 
154
156
 
155
- def develop_labextension_py(
157
+ def develop_labextension_py( # noqa: PLR0913
156
158
  module,
157
159
  user=False,
158
160
  sys_prefix=False,
@@ -195,10 +197,7 @@ def develop_labextension_py(
195
197
  return full_dests
196
198
 
197
199
 
198
- from .core_path import default_core_path
199
-
200
-
201
- def build_labextension(
200
+ def build_labextension( # noqa: PLR0913
202
201
  path, logger=None, development=False, static_url=None, source_map=False, core_path=None
203
202
  ):
204
203
  """Build a labextension in the given path"""
@@ -208,7 +207,7 @@ def build_labextension(
208
207
  ext_path = str(Path(path).resolve())
209
208
 
210
209
  if logger:
211
- logger.info("Building extension in %s" % path)
210
+ logger.info("Building extension in %s", path)
212
211
 
213
212
  builder = _ensure_builder(ext_path, core_path)
214
213
 
@@ -223,7 +222,7 @@ def build_labextension(
223
222
  subprocess.check_call(arguments, cwd=ext_path) # noqa S603
224
223
 
225
224
 
226
- def watch_labextension(
225
+ def watch_labextension( # noqa: PLR0913
227
226
  path, labextensions_path, logger=None, development=False, source_map=False, core_path=None
228
227
  ):
229
228
  """Watch a labextension in a given path"""
@@ -231,7 +230,7 @@ def watch_labextension(
231
230
  ext_path = str(Path(path).resolve())
232
231
 
233
232
  if logger:
234
- logger.info("Building extension in %s" % path)
233
+ logger.info("Building extension in %s", path)
235
234
 
236
235
  # Check to see if we need to create a symlink
237
236
  federated_extensions = get_federated_extensions(labextensions_path)
@@ -274,9 +273,8 @@ def _ensure_builder(ext_path, core_path):
274
273
  dep_version2 = ext_data.get("devDependencies", {}).get("@jupyterlab/builder")
275
274
  dep_version2 = dep_version2 or ext_data.get("dependencies", {}).get("@jupyterlab/builder")
276
275
  if dep_version2 is None:
277
- raise ValueError(
278
- "Extensions require a devDependency on @jupyterlab/builder@%s" % dep_version1
279
- )
276
+ msg = f"Extensions require a devDependency on @jupyterlab/builder@{dep_version1}"
277
+ raise ValueError(msg)
280
278
 
281
279
  # if we have installed from disk (version is a path), assume we know what
282
280
  # we are doing and do not check versions.
@@ -310,7 +308,7 @@ def _ensure_builder(ext_path, core_path):
310
308
  # )
311
309
 
312
310
  # if not overlap:
313
- # msg = f"Extensions require a devDependency on @jupyterlab/builder@{dep_version1}, you have a dependency on {dep_version2}"
311
+ # msg = f"Extensions require a devDependency on @jupyterlab/builder@{dep_version1}, you have a dependency on {dep_version2}" # noqa: E501
314
312
  # raise ValueError(msg)
315
313
 
316
314
  return osp.join(
@@ -339,10 +337,10 @@ def _should_copy(src, dest, logger=None):
339
337
  # we add a fudge factor to work around a bug in python 2.x
340
338
  # that was fixed in python 3.x: https://bugs.python.org/issue12904
341
339
  if logger:
342
- logger.warning("Out of date: %s" % dest)
340
+ logger.warning("Out of date: %s", dest)
343
341
  return True
344
342
  if logger:
345
- logger.info("Up to date: %s" % dest)
343
+ logger.info("Up to date: %s", dest)
346
344
  return False
347
345
 
348
346
 
@@ -388,9 +386,8 @@ def _get_labextension_dir(user=False, sys_prefix=False, prefix=None, labextensio
388
386
  ]
389
387
  conflicting_set = [f"{n}={v!r}" for n, v in conflicting if v]
390
388
  if len(conflicting_set) > 1:
391
- msg = "cannot specify more than one of user, sys_prefix, prefix, or labextensions_dir, but got: {}".format(
392
- ", ".join(conflicting_set)
393
- )
389
+ conflict = ", ".join(conflicting_set)
390
+ msg = f"cannot specify more than one of user, sys_prefix, prefix, or labextensions_dir, but got: {conflict}" # noqa: E501
394
391
  raise ArgumentConflict(msg)
395
392
  if user:
396
393
  labext = pjoin(jupyter_data_dir(), "labextensions")
@@ -449,8 +446,8 @@ def _get_labextension_metadata(module): # noqa
449
446
  if not package:
450
447
  try:
451
448
  package = (
452
- subprocess.check_output(
453
- [sys.executable, "setup.py", "--name"], # noqa S603
449
+ subprocess.check_output( # noqa: S603
450
+ [sys.executable, "setup.py", "--name"],
454
451
  cwd=mod_path,
455
452
  )
456
453
  .decode("utf8")
@@ -50,21 +50,21 @@ def get_federated_extensions(labextensions_path: list[str]) -> dict[str, Any]:
50
50
  with open(ext_path, encoding="utf-8") as fid:
51
51
  pkgdata = json.load(fid)
52
52
  if pkgdata["name"] not in federated_extensions:
53
- data = dict(
54
- name=pkgdata["name"],
55
- version=pkgdata["version"],
56
- description=pkgdata.get("description", ""),
57
- url=get_package_url(pkgdata),
58
- ext_dir=ext_dir,
59
- ext_path=osp.dirname(ext_path),
60
- is_local=False,
61
- dependencies=pkgdata.get("dependencies", dict()),
62
- jupyterlab=pkgdata.get("jupyterlab", dict()),
63
- )
53
+ data = {
54
+ "name": pkgdata["name"],
55
+ "version": pkgdata["version"],
56
+ "description": pkgdata.get("description", ""),
57
+ "url": get_package_url(pkgdata),
58
+ "ext_dir": ext_dir,
59
+ "ext_path": osp.dirname(ext_path),
60
+ "is_local": False,
61
+ "dependencies": pkgdata.get("dependencies", {}),
62
+ "jupyterlab": pkgdata.get("jupyterlab", {}),
63
+ }
64
64
 
65
65
  # Add repository info if available
66
66
  if "repository" in pkgdata and "url" in pkgdata.get("repository", {}):
67
- data["repository"] = dict(url=pkgdata.get("repository").get("url"))
67
+ data["repository"] = {"url": pkgdata.get("repository").get("url")}
68
68
 
69
69
  install_path = osp.join(osp.dirname(ext_path), "install.json")
70
70
  if osp.exists(install_path):
@@ -27,6 +27,329 @@
27
27
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
28
  # SOFTWARE.
29
29
 
30
+ import logging
31
+ import re
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+ SEMVER_SPEC_VERSION = "2.0.0"
36
+
37
+ string_type = str
38
+
39
+
40
+ class _R:
41
+ def __init__(self, i):
42
+ self.i = i
43
+
44
+ def __call__(self):
45
+ v = self.i
46
+ self.i += 1
47
+ return v
48
+
49
+ def value(self):
50
+ return self.i
51
+
52
+
53
+ class Extendlist(list):
54
+ def __setitem__(self, i, v):
55
+ try:
56
+ list.__setitem__(self, i, v)
57
+ except IndexError:
58
+ if len(self) == i:
59
+ self.append(v)
60
+ else:
61
+ raise
62
+
63
+
64
+ def list_get(xs, i):
65
+ try:
66
+ return xs[i]
67
+ except IndexError:
68
+ return None
69
+
70
+
71
+ R = _R(0)
72
+ src = Extendlist()
73
+ regexp = {}
74
+
75
+ # The following Regular Expressions can be used for tokenizing,
76
+ # validating, and parsing SemVer version strings.
77
+
78
+ # ## Numeric Identifier
79
+ # A single `0`, or a non-zero digit followed by zero or more digits.
80
+
81
+ NUMERICIDENTIFIER = R()
82
+ src[NUMERICIDENTIFIER] = "0|[1-9]\\d*"
83
+
84
+ NUMERICIDENTIFIERLOOSE = R()
85
+ src[NUMERICIDENTIFIERLOOSE] = "[0-9]+"
86
+
87
+
88
+ # ## Non-numeric Identifier
89
+ # Zero or more digits, followed by a letter or hyphen, and then zero or
90
+ # more letters, digits, or hyphens.
91
+
92
+ NONNUMERICIDENTIFIER = R()
93
+ src[NONNUMERICIDENTIFIER] = "\\d*[a-zA-Z-][a-zA-Z0-9-]*"
94
+
95
+ # ## Main Version
96
+ # Three dot-separated numeric identifiers.
97
+
98
+ MAINVERSION = R()
99
+ src[MAINVERSION] = (
100
+ "("
101
+ + src[NUMERICIDENTIFIER]
102
+ + ")\\."
103
+ + "("
104
+ + src[NUMERICIDENTIFIER]
105
+ + ")\\."
106
+ + "("
107
+ + src[NUMERICIDENTIFIER]
108
+ + ")"
109
+ )
110
+
111
+ MAINVERSIONLOOSE = R()
112
+ src[MAINVERSIONLOOSE] = (
113
+ "("
114
+ + src[NUMERICIDENTIFIERLOOSE]
115
+ + ")\\."
116
+ + "("
117
+ + src[NUMERICIDENTIFIERLOOSE]
118
+ + ")\\."
119
+ + "("
120
+ + src[NUMERICIDENTIFIERLOOSE]
121
+ + ")"
122
+ )
123
+
124
+
125
+ # ## Pre-release Version Identifier
126
+ # A numeric identifier, or a non-numeric identifier.
127
+
128
+ PRERELEASEIDENTIFIER = R()
129
+ src[PRERELEASEIDENTIFIER] = "(?:" + src[NUMERICIDENTIFIER] + "|" + src[NONNUMERICIDENTIFIER] + ")"
130
+
131
+ PRERELEASEIDENTIFIERLOOSE = R()
132
+ src[PRERELEASEIDENTIFIERLOOSE] = (
133
+ "(?:" + src[NUMERICIDENTIFIERLOOSE] + "|" + src[NONNUMERICIDENTIFIER] + ")"
134
+ )
135
+
136
+
137
+ # ## Pre-release Version
138
+ # Hyphen, followed by one or more dot-separated pre-release version
139
+ # identifiers.
140
+
141
+ PRERELEASE = R()
142
+ src[PRERELEASE] = (
143
+ "(?:-(" + src[PRERELEASEIDENTIFIER] + "(?:\\." + src[PRERELEASEIDENTIFIER] + ")*))"
144
+ )
145
+
146
+ PRERELEASELOOSE = R()
147
+ src[PRERELEASELOOSE] = (
148
+ "(?:-?(" + src[PRERELEASEIDENTIFIERLOOSE] + "(?:\\." + src[PRERELEASEIDENTIFIERLOOSE] + ")*))"
149
+ )
150
+
151
+ # ## Build Metadata Identifier
152
+ # Any combination of digits, letters, or hyphens.
153
+
154
+ BUILDIDENTIFIER = R()
155
+ src[BUILDIDENTIFIER] = "[0-9A-Za-z-]+"
156
+
157
+ # ## Build Metadata
158
+ # Plus sign, followed by one or more period-separated build metadata
159
+ # identifiers.
160
+
161
+ BUILD = R()
162
+ src[BUILD] = "(?:\\+(" + src[BUILDIDENTIFIER] + "(?:\\." + src[BUILDIDENTIFIER] + ")*))"
163
+
164
+ # ## Full Version String
165
+ # A main version, followed optionally by a pre-release version and
166
+ # build metadata.
167
+
168
+ # Note that the only major, minor, patch, and pre-release sections of
169
+ # the version string are capturing groups. The build metadata is not a
170
+ # capturing group, because it should not ever be used in version
171
+ # comparison.
172
+
173
+ FULL = R()
174
+ FULLPLAIN = "v?" + src[MAINVERSION] + src[PRERELEASE] + "?" + src[BUILD] + "?"
175
+
176
+ src[FULL] = "^" + FULLPLAIN + "$"
177
+
178
+ # like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
179
+ # also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
180
+ # common in the npm registry.
181
+ LOOSEPLAIN = "[v=\\s]*" + src[MAINVERSIONLOOSE] + src[PRERELEASELOOSE] + "?" + src[BUILD] + "?"
182
+
183
+ LOOSE = R()
184
+ src[LOOSE] = "^" + LOOSEPLAIN + "$"
185
+
186
+ GTLT = R()
187
+ src[GTLT] = "((?:<|>)?=?)"
188
+
189
+ # Something like "2.*" or "1.2.x".
190
+ # Note that "x.x" is a valid xRange identifier, meaning "any version"
191
+ # Only the first item is strictly required.
192
+ XRANGEIDENTIFIERLOOSE = R()
193
+ src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + "|x|X|\\*"
194
+ XRANGEIDENTIFIER = R()
195
+ src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + "|x|X|\\*"
196
+
197
+ XRANGEPLAIN = R()
198
+ src[XRANGEPLAIN] = (
199
+ "[v=\\s]*("
200
+ + src[XRANGEIDENTIFIER]
201
+ + ")"
202
+ + "(?:\\.("
203
+ + src[XRANGEIDENTIFIER]
204
+ + ")"
205
+ + "(?:\\.("
206
+ + src[XRANGEIDENTIFIER]
207
+ + ")"
208
+ + "(?:"
209
+ + src[PRERELEASE]
210
+ + ")?"
211
+ + src[BUILD]
212
+ + "?"
213
+ + ")?)?"
214
+ )
215
+
216
+ XRANGEPLAINLOOSE = R()
217
+ src[XRANGEPLAINLOOSE] = (
218
+ "[v=\\s]*("
219
+ + src[XRANGEIDENTIFIERLOOSE]
220
+ + ")"
221
+ + "(?:\\.("
222
+ + src[XRANGEIDENTIFIERLOOSE]
223
+ + ")"
224
+ + "(?:\\.("
225
+ + src[XRANGEIDENTIFIERLOOSE]
226
+ + ")"
227
+ + "(?:"
228
+ + src[PRERELEASELOOSE]
229
+ + ")?"
230
+ + src[BUILD]
231
+ + "?"
232
+ + ")?)?"
233
+ )
234
+
235
+ XRANGE = R()
236
+ src[XRANGE] = "^" + src[GTLT] + "\\s*" + src[XRANGEPLAIN] + "$"
237
+ XRANGELOOSE = R()
238
+ src[XRANGELOOSE] = "^" + src[GTLT] + "\\s*" + src[XRANGEPLAINLOOSE] + "$"
239
+
240
+ # Tilde ranges.
241
+ # Meaning is "reasonably at or greater than"
242
+ LONETILDE = R()
243
+ src[LONETILDE] = "(?:~>?)"
244
+
245
+ TILDETRIM = R()
246
+ src[TILDETRIM] = "(\\s*)" + src[LONETILDE] + "\\s+"
247
+ regexp[TILDETRIM] = re.compile(src[TILDETRIM], re.M)
248
+ tildeTrimReplace = r"\1~"
249
+
250
+ TILDE = R()
251
+ src[TILDE] = "^" + src[LONETILDE] + src[XRANGEPLAIN] + "$"
252
+ TILDELOOSE = R()
253
+ src[TILDELOOSE] = "^" + src[LONETILDE] + src[XRANGEPLAINLOOSE] + "$"
254
+
255
+ # Caret ranges.
256
+ # Meaning is "at least and backwards compatible with"
257
+ LONECARET = R()
258
+ src[LONECARET] = "(?:\\^)"
259
+
260
+ CARETTRIM = R()
261
+ src[CARETTRIM] = "(\\s*)" + src[LONECARET] + "\\s+"
262
+ regexp[CARETTRIM] = re.compile(src[CARETTRIM], re.M)
263
+ caretTrimReplace = r"\1^"
264
+
265
+ CARET = R()
266
+ src[CARET] = "^" + src[LONECARET] + src[XRANGEPLAIN] + "$"
267
+ CARETLOOSE = R()
268
+ src[CARETLOOSE] = "^" + src[LONECARET] + src[XRANGEPLAINLOOSE] + "$"
269
+
270
+ # A simple gt/lt/eq thing, or just "" to indicate "any version"
271
+ COMPARATORLOOSE = R()
272
+ src[COMPARATORLOOSE] = "^" + src[GTLT] + "\\s*(" + LOOSEPLAIN + ")$|^$"
273
+ COMPARATOR = R()
274
+ src[COMPARATOR] = "^" + src[GTLT] + "\\s*(" + FULLPLAIN + ")$|^$"
275
+
276
+
277
+ # An expression to strip any whitespace between the gtlt and the thing
278
+ # it modifies, so that `> 1.2.3` ==> `>1.2.3`
279
+ COMPARATORTRIM = R()
280
+ src[COMPARATORTRIM] = "(\\s*)" + src[GTLT] + "\\s*(" + LOOSEPLAIN + "|" + src[XRANGEPLAIN] + ")"
281
+
282
+ # this one has to use the /g flag
283
+ regexp[COMPARATORTRIM] = re.compile(src[COMPARATORTRIM], re.M)
284
+ comparatorTrimReplace = r"\1\2\3"
285
+
286
+
287
+ # Something like `1.2.3 - 1.2.4`
288
+ # Note that these all use the loose form, because they'll be
289
+ # checked against either the strict or loose comparator form
290
+ # later.
291
+ HYPHENRANGE = R()
292
+ src[HYPHENRANGE] = (
293
+ "^\\s*(" + src[XRANGEPLAIN] + ")" + "\\s+-\\s+" + "(" + src[XRANGEPLAIN] + ")" + "\\s*$"
294
+ )
295
+
296
+ HYPHENRANGELOOSE = R()
297
+ src[HYPHENRANGELOOSE] = (
298
+ "^\\s*("
299
+ + src[XRANGEPLAINLOOSE]
300
+ + ")"
301
+ + "\\s+-\\s+"
302
+ + "("
303
+ + src[XRANGEPLAINLOOSE]
304
+ + ")"
305
+ + "\\s*$"
306
+ )
307
+
308
+ # Star ranges basically just allow anything at all.
309
+ STAR = R()
310
+ src[STAR] = "(<|>)?=?\\s*\\*"
311
+
312
+ # version name recovery for convenient
313
+ RECOVERYVERSIONNAME = R()
314
+ _n = src[NUMERICIDENTIFIER]
315
+ _pre = src[PRERELEASELOOSE]
316
+ src[RECOVERYVERSIONNAME] = f"v?({_n})(?:\\.({_n}))?{_pre}?"
317
+
318
+ # Compile to actual regexp objects.
319
+ # All are flag-free, unless they were created above with a flag.
320
+ for i in range(R.value()):
321
+ logger.debug("genregxp %s %s", i, src[i])
322
+ if i not in regexp:
323
+ regexp[i] = re.compile(src[i])
324
+
325
+
326
+ def parse(version, loose):
327
+ r = regexp[LOOSE] if loose else regexp[FULL]
328
+ m = r.search(version)
329
+ if m:
330
+ return semver(version, loose)
331
+ else:
332
+ return None
333
+
334
+
335
+ def valid(version, loose):
336
+ v = parse(version, loose)
337
+ if v.version:
338
+ return v
339
+ else:
340
+ return None
341
+
342
+
343
+ def clean(version, loose):
344
+ s = parse(version, loose)
345
+ if s:
346
+ return s.version
347
+ else:
348
+ return None
349
+
350
+
351
+ NUMERIC = re.compile(r"^\d+$")
352
+
30
353
 
31
354
  def semver(version, loose):
32
355
  if isinstance(version, SemVer):
@@ -65,7 +388,7 @@ class SemVer:
65
388
  self.prerelease = []
66
389
  else:
67
390
  self.prerelease = [
68
- (int(id) if NUMERIC.search(id) else id) for id in m.group(3).split(".")
391
+ (int(id_) if NUMERIC.search(id_) else id_) for id_ in m.group(3).split(".")
69
392
  ]
70
393
  else:
71
394
  # these are actually numbers
@@ -77,7 +400,7 @@ class SemVer:
77
400
  self.prerelease = []
78
401
  else:
79
402
  self.prerelease = [
80
- (int(id) if NUMERIC.search(id) else id) for id in m.group(4).split(".")
403
+ (int(id_) if NUMERIC.search(id_) else id_) for id_ in m.group(4).split(".")
81
404
  ]
82
405
  if m.group(5):
83
406
  self.build = m.group(5).split(".")
@@ -116,7 +439,7 @@ class SemVer:
116
439
  or compare_identifiers(str(self.patch), str(other.patch))
117
440
  )
118
441
 
119
- def compare_pre(self, other):
442
+ def compare_pre(self, other): # noqa PLR0911
120
443
  if not isinstance(other, SemVer):
121
444
  other = make_semver(other, self.loose)
122
445
 
@@ -226,16 +549,88 @@ class SemVer:
226
549
  else:
227
550
  self.prerelease = [identifier, 0]
228
551
  else:
229
- raise ValueError(f"invalid increment argument: {release}")
552
+ msg = f"invalid increment argument: {release}"
553
+ raise ValueError(msg)
230
554
  self.format()
231
555
  self.raw = self.version
232
556
  return self
233
557
 
234
558
 
559
+ def inc(version, release, loose, identifier=None): # wow!
560
+ try:
561
+ return make_semver(version, loose).inc(release, identifier=identifier).version
562
+ except Exception as e:
563
+ logger.debug(e, exc_info=5)
564
+ return None
565
+
566
+
567
+ def compare_identifiers(a, b):
568
+ anum = NUMERIC.search(a)
569
+ bnum = NUMERIC.search(b)
570
+
571
+ if anum and bnum:
572
+ a = int(a)
573
+ b = int(b)
574
+
575
+ if anum and not bnum:
576
+ return -1
577
+ elif bnum and not anum:
578
+ return 1
579
+ elif a < b:
580
+ return -1
581
+ elif a > b:
582
+ return 1
583
+ else:
584
+ return 0
585
+
586
+
587
+ def rcompare_identifiers(a, b):
588
+ return compare_identifiers(b, a)
589
+
590
+
235
591
  def compare(a, b, loose):
236
592
  return make_semver(a, loose).compare(b)
237
593
 
238
594
 
595
+ def compare_loose(a, b):
596
+ return compare(a, b, True)
597
+
598
+
599
+ def rcompare(a, b, loose):
600
+ return compare(b, a, loose)
601
+
602
+
603
+ def make_key_function(loose):
604
+ def key_function(version):
605
+ v = make_semver(version, loose)
606
+ key = (v.major, v.minor, v.patch)
607
+ if v.prerelease: # noqa SIM108
608
+ key = key + tuple(v.prerelease)
609
+ else:
610
+ # NOT having a prerelease is > having one
611
+ key = (*key, float("inf"))
612
+
613
+ return key
614
+
615
+ return key_function
616
+
617
+
618
+ loose_key_function = make_key_function(True)
619
+ full_key_function = make_key_function(True)
620
+
621
+
622
+ def sort(list_, loose):
623
+ keyf = loose_key_function if loose else full_key_function
624
+ list_.sort(key=keyf)
625
+ return list_
626
+
627
+
628
+ def rsort(list_, loose):
629
+ keyf = loose_key_function if loose else full_key_function
630
+ list_.sort(key=keyf, reverse=True)
631
+ return list_
632
+
633
+
239
634
  def gt(a, b, loose):
240
635
  return compare(a, b, loose) > 0
241
636
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: jupyter_builder
3
- Version: 0.1.0a2
3
+ Version: 0.1.0a3
4
4
  Summary: JupyterLab build tools
5
5
  Project-URL: Homepage, https://jupyter.org
6
6
  Project-URL: Source, https://github.com/jupyterlab/jupyterlab_builder
@@ -58,7 +58,7 @@ Requires-Dist: build; extra == 'dev'
58
58
  Requires-Dist: hatch; extra == 'dev'
59
59
  Requires-Dist: mypy; extra == 'dev'
60
60
  Requires-Dist: pre-commit; extra == 'dev'
61
- Requires-Dist: ruff==0.4.7; extra == 'dev'
61
+ Requires-Dist: ruff==0.5.5; extra == 'dev'
62
62
  Provides-Extra: test
63
63
  Requires-Dist: copier<10,>=9.2; extra == 'test'
64
64
  Requires-Dist: coverage; extra == 'test'
@@ -0,0 +1,20 @@
1
+ jupyter_builder/__init__.py,sha256=i9jPM1fNuaGMXu7HCFm6KbNkedsu1J-LqVIcDeeoUCc,582
2
+ jupyter_builder/base_extension_app.py,sha256=w82d89smSMulUGlPDI_A4PVxRz2Zg7myC7NXcEevX4Y,1622
3
+ jupyter_builder/commands.py,sha256=DgG1GGBQ_NEKVreOX2JAnNjOtR-znxs-u56ZiokPvOo,3446
4
+ jupyter_builder/core_path.py,sha256=8cFbRg81aZj8LQiHFkXuHtlDffwDu4IlUypyaiI1gH8,245
5
+ jupyter_builder/debug_log_file_mixin.py,sha256=EVc25sTNjYRnHf9sPQHffR8O5apqG7SJlZq5T9EAfMM,2256
6
+ jupyter_builder/federated_extensions.py,sha256=VnrCOgG31Ed_m18gLsxWV5diU2vpj8lXSZpHzXoBoWQ,17226
7
+ jupyter_builder/federated_extensions_requirements.py,sha256=t3sD-WiO0Y4SOmn113-1aGhMzOqoQLCZAMnhliIM5vk,2997
8
+ jupyter_builder/jlpm.py,sha256=kYE6Pk9TADEhcxKkUXr6V0AhNdGDr5XnYO-D679R580,1233
9
+ jupyter_builder/jupyterlab_semver.py,sha256=8wQusESSz_3rmnJsWVVn13C4mM5mt5HAdAsAUCjrD8c,18563
10
+ jupyter_builder/main.py,sha256=PGZ4MGYG20yDqonoQg_vKkeCzCkKKnrCOtU056Wdvr4,2231
11
+ jupyter_builder/yarn.js,sha256=8EYGlNp3NZisReCOECOR_8DMDfMWLkfeZ-URewpzhq4,2221431
12
+ jupyter_builder/extension_commands/__init__.py,sha256=eXcK7cn7Qj8A1SBiMJ4ptlf2WFErhSxG9QSKFtENyhU,101
13
+ jupyter_builder/extension_commands/build.py,sha256=u_RQGl5_Pt2A7I2SdTk4tZ3hUNR83X4pFqigOzWXA6g,1638
14
+ jupyter_builder/extension_commands/develop.py,sha256=2B9jrjceulO9sE7-TqcyVtTrjKkk713LqRbN5oMmxYU,1724
15
+ jupyter_builder/extension_commands/watch.py,sha256=QIfIxX__6NfXeIla7BCr0doqqxA9rkd4ApKuCMk709A,1521
16
+ jupyter_builder-0.1.0a3.dist-info/METADATA,sha256=Il2z55hJFeIusPAATRJ0Wkn6NN3uXv0RmBqQqzmswUM,5300
17
+ jupyter_builder-0.1.0a3.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
+ jupyter_builder-0.1.0a3.dist-info/entry_points.txt,sha256=pQlwFs3R6-sOlkEDXzXwxu0tVNn4aBkaDJ8qRebDZko,95
19
+ jupyter_builder-0.1.0a3.dist-info/licenses/LICENSE,sha256=T4GK8L2cxFmaXUe48VaSUF3T6pnn14gWtH1rXdz5VkI,1532
20
+ jupyter_builder-0.1.0a3.dist-info/RECORD,,
@@ -1,66 +0,0 @@
1
- """JupyterLab Server config"""
2
-
3
- # Copyright (c) Jupyter Development Team.
4
- # Distributed under the terms of the Modified BSD License.
5
- from __future__ import annotations
6
-
7
- import json
8
- import os.path as osp
9
- from glob import iglob
10
- from itertools import chain
11
- from os.path import join as pjoin
12
- from typing import Any
13
-
14
- # -----------------------------------------------------------------------------
15
- # Module globals
16
- # -----------------------------------------------------------------------------
17
-
18
- DEFAULT_TEMPLATE_PATH = osp.join(osp.dirname(__file__), "templates")
19
-
20
-
21
- def get_package_url(data: dict[str, Any]) -> str:
22
- """Get the url from the extension data"""
23
- # homepage, repository are optional
24
- if "homepage" in data:
25
- url = data["homepage"]
26
- elif "repository" in data and isinstance(data["repository"], dict):
27
- url = data["repository"].get("url", "")
28
- else:
29
- url = ""
30
- return url
31
-
32
-
33
- def get_federated_extensions(labextensions_path: list[str]) -> dict[str, Any]:
34
- """Get the metadata about federated extensions"""
35
- federated_extensions = {}
36
- for ext_dir in labextensions_path:
37
- # extensions are either top-level directories, or two-deep in @org directories
38
- for ext_path in chain(
39
- iglob(pjoin(ext_dir, "[!@]*", "package.json")),
40
- iglob(pjoin(ext_dir, "@*", "*", "package.json")),
41
- ):
42
- with open(ext_path, encoding="utf-8") as fid:
43
- pkgdata = json.load(fid)
44
- if pkgdata["name"] not in federated_extensions:
45
- data = dict(
46
- name=pkgdata["name"],
47
- version=pkgdata["version"],
48
- description=pkgdata.get("description", ""),
49
- url=get_package_url(pkgdata),
50
- ext_dir=ext_dir,
51
- ext_path=osp.dirname(ext_path),
52
- is_local=False,
53
- dependencies=pkgdata.get("dependencies", dict()),
54
- jupyterlab=pkgdata.get("jupyterlab", dict()),
55
- )
56
-
57
- # Add repository info if available
58
- if "repository" in pkgdata and "url" in pkgdata.get("repository", {}):
59
- data["repository"] = dict(url=pkgdata.get("repository").get("url"))
60
-
61
- install_path = osp.join(osp.dirname(ext_path), "install.json")
62
- if osp.exists(install_path):
63
- with open(install_path, encoding="utf-8") as fid:
64
- data["install"] = json.load(fid)
65
- federated_extensions[data["name"]] = data
66
- return federated_extensions
@@ -1,21 +0,0 @@
1
- jupyter_builder/__init__.py,sha256=ucoo7W6O_PAP5ESIJ1klJViiKWeJbUqFCuc_QrW3XV8,568
2
- jupyter_builder/base_extension_app.py,sha256=NTtICU1zbc8n64Hd9tJ86FuYX7q5xqDVHhbmBAEINjw,1726
3
- jupyter_builder/commands.py,sha256=-h9brmCXhrKRMtefcqHEv4VnMREgWOkfU2PZmaxNraI,3440
4
- jupyter_builder/core_path.py,sha256=8cFbRg81aZj8LQiHFkXuHtlDffwDu4IlUypyaiI1gH8,245
5
- jupyter_builder/debug_log_file_mixin.py,sha256=816tIlPySoCbJak9Cj6eE57VjeQjz2jdySYsj4hqESw,2181
6
- jupyter_builder/federated_extensions.py,sha256=IaS7VIKlb09wgkIjjYhSXUJY8qYNpmCOMyLPWw3fKlI,17177
7
- jupyter_builder/federated_extensions_requirements.py,sha256=R-sAx1shGaGOwA9dIMPIc3kslEW2ih1w8RdrKWtZJ3c,2983
8
- jupyter_builder/jlpm.py,sha256=kYE6Pk9TADEhcxKkUXr6V0AhNdGDr5XnYO-D679R580,1233
9
- jupyter_builder/jupyterlab_semver.py,sha256=E7SKvf9ca4uDBWf_oSji5OHurycAIF8cUt4rwafHQto,9330
10
- jupyter_builder/jupyterlab_server_req.py,sha256=LKn_merwDkCT17OCsqTuOoRaX4uGGhyz-25wwiDkE2c,2613
11
- jupyter_builder/main.py,sha256=PGZ4MGYG20yDqonoQg_vKkeCzCkKKnrCOtU056Wdvr4,2231
12
- jupyter_builder/yarn.js,sha256=8EYGlNp3NZisReCOECOR_8DMDfMWLkfeZ-URewpzhq4,2221431
13
- jupyter_builder/extension_commands/__init__.py,sha256=eXcK7cn7Qj8A1SBiMJ4ptlf2WFErhSxG9QSKFtENyhU,101
14
- jupyter_builder/extension_commands/build.py,sha256=Px55wxLrOgh_OGzUebHw2cplepOn8WyU38gbqKvHTWk,1580
15
- jupyter_builder/extension_commands/develop.py,sha256=Ztl9qniWlxE86imNOpcNOLbPsZGRMhYQ3c_-_ozUICI,1696
16
- jupyter_builder/extension_commands/watch.py,sha256=OKuFk3N1vk2Yb-Cmy2yLOECCsNNn-qC0DcwSAkeyGGs,1463
17
- jupyter_builder-0.1.0a2.dist-info/METADATA,sha256=hBwpgheUzkezL5-z7yJALfmd3Y1ZpIPjnkeZHwQYZtQ,5300
18
- jupyter_builder-0.1.0a2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
19
- jupyter_builder-0.1.0a2.dist-info/entry_points.txt,sha256=pQlwFs3R6-sOlkEDXzXwxu0tVNn4aBkaDJ8qRebDZko,95
20
- jupyter_builder-0.1.0a2.dist-info/licenses/LICENSE,sha256=T4GK8L2cxFmaXUe48VaSUF3T6pnn14gWtH1rXdz5VkI,1532
21
- jupyter_builder-0.1.0a2.dist-info/RECORD,,