jupyter-builder 0.1.0a2__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.
- jupyter_builder/__init__.py +13 -0
- jupyter_builder/base_extension_app.py +65 -0
- jupyter_builder/commands.py +115 -0
- jupyter_builder/core_path.py +10 -0
- jupyter_builder/debug_log_file_mixin.py +64 -0
- jupyter_builder/extension_commands/__init__.py +2 -0
- jupyter_builder/extension_commands/build.py +56 -0
- jupyter_builder/extension_commands/develop.py +58 -0
- jupyter_builder/extension_commands/watch.py +54 -0
- jupyter_builder/federated_extensions.py +492 -0
- jupyter_builder/federated_extensions_requirements.py +74 -0
- jupyter_builder/jlpm.py +43 -0
- jupyter_builder/jupyterlab_semver.py +252 -0
- jupyter_builder/jupyterlab_server_req.py +66 -0
- jupyter_builder/main.py +54 -0
- jupyter_builder/yarn.js +878 -0
- jupyter_builder-0.1.0a2.dist-info/METADATA +119 -0
- jupyter_builder-0.1.0a2.dist-info/RECORD +21 -0
- jupyter_builder-0.1.0a2.dist-info/WHEEL +4 -0
- jupyter_builder-0.1.0a2.dist-info/entry_points.txt +3 -0
- jupyter_builder-0.1.0a2.dist-info/licenses/LICENSE +29 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
from ._version import __version__
|
|
6
|
+
except ImportError:
|
|
7
|
+
# Fallback when using the package in dev mode without installing
|
|
8
|
+
# in editable mode with pip. It is highly recommended to install
|
|
9
|
+
# the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
warnings.warn("Importing 'jupyter_builder' outside a proper installation.")
|
|
13
|
+
__version__ = "dev"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Jupyter LabExtension Entry Points."""
|
|
2
|
+
|
|
3
|
+
# Copyright (c) Jupyter Development Team.
|
|
4
|
+
# Distributed under the terms of the Modified BSD License.
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
import os
|
|
8
|
+
from copy import copy
|
|
9
|
+
|
|
10
|
+
from jupyter_core.application import JupyterApp, base_aliases, base_flags
|
|
11
|
+
from jupyter_core.paths import jupyter_path
|
|
12
|
+
from traitlets import List, Unicode, default
|
|
13
|
+
|
|
14
|
+
from .debug_log_file_mixin import DebugLogFileMixin
|
|
15
|
+
|
|
16
|
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# from .federated_labextensions import build_labextension, develop_labextension_py, watch_labextension
|
|
20
|
+
|
|
21
|
+
flags = dict(base_flags)
|
|
22
|
+
|
|
23
|
+
develop_flags = copy(flags)
|
|
24
|
+
develop_flags["overwrite"] = (
|
|
25
|
+
{"DevelopLabExtensionApp": {"overwrite": True}},
|
|
26
|
+
"Overwrite files",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
aliases = dict(base_aliases)
|
|
30
|
+
aliases["debug-log-path"] = "DebugLogFileMixin.debug_log_path"
|
|
31
|
+
|
|
32
|
+
# VERSION = get_app_version()
|
|
33
|
+
VERSION = 1
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class BaseExtensionApp(JupyterApp, DebugLogFileMixin):
|
|
37
|
+
version = VERSION
|
|
38
|
+
flags = flags
|
|
39
|
+
aliases = aliases
|
|
40
|
+
name = "lab"
|
|
41
|
+
|
|
42
|
+
labextensions_path = List(
|
|
43
|
+
Unicode(),
|
|
44
|
+
help="The standard paths to look in for prebuilt JupyterLab extensions",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# @default("labextensions_path")
|
|
48
|
+
# def _default_labextensions_path(self):
|
|
49
|
+
# lab = LabApp()
|
|
50
|
+
# lab.load_config_file()
|
|
51
|
+
# return lab.extra_labextensions_path + lab.labextensions_path
|
|
52
|
+
@default("labextensions_path")
|
|
53
|
+
def _default_labextensions_path(self) -> list[str]:
|
|
54
|
+
return jupyter_path("labextensions")
|
|
55
|
+
|
|
56
|
+
def start(self):
|
|
57
|
+
with self.debug_logging():
|
|
58
|
+
self.run_task()
|
|
59
|
+
|
|
60
|
+
def run_task(self):
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
def _log_format_default(self):
|
|
64
|
+
"""A default format for messages"""
|
|
65
|
+
return "%(message)s"
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""JupyterLab command handler"""
|
|
2
|
+
|
|
3
|
+
# Copyright (c) Jupyter Development Team.
|
|
4
|
+
# Distributed under the terms of the Modified BSD License.
|
|
5
|
+
|
|
6
|
+
import itertools
|
|
7
|
+
|
|
8
|
+
from .jupyterlab_semver import Range, gt, gte, lt, lte
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _test_overlap(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False):
|
|
12
|
+
"""Test whether two version specs overlap.
|
|
13
|
+
|
|
14
|
+
Returns `None` if we cannot determine compatibility,
|
|
15
|
+
otherwise whether there is an overlap
|
|
16
|
+
"""
|
|
17
|
+
cmp = _compare_ranges(
|
|
18
|
+
spec1, spec2, drop_prerelease1=drop_prerelease1, drop_prerelease2=drop_prerelease2
|
|
19
|
+
)
|
|
20
|
+
if cmp is None:
|
|
21
|
+
return
|
|
22
|
+
return cmp == 0
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _compare_ranges(spec1, spec2, drop_prerelease1=False, drop_prerelease2=False): # noqa
|
|
26
|
+
"""Test whether two version specs overlap.
|
|
27
|
+
|
|
28
|
+
Returns `None` if we cannot determine compatibility,
|
|
29
|
+
otherwise return 0 if there is an overlap, 1 if
|
|
30
|
+
spec1 is lower/older than spec2, and -1 if spec1
|
|
31
|
+
is higher/newer than spec2.
|
|
32
|
+
"""
|
|
33
|
+
# Test for overlapping semver ranges.
|
|
34
|
+
r1 = Range(spec1, True)
|
|
35
|
+
r2 = Range(spec2, True)
|
|
36
|
+
|
|
37
|
+
# If either range is empty, we cannot verify.
|
|
38
|
+
if not r1.range or not r2.range:
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
# Set return_value to a sentinel value
|
|
42
|
+
return_value = False
|
|
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.
|
|
45
|
+
for r1set, r2set in itertools.product(r1.set, r2.set):
|
|
46
|
+
x1 = r1set[0].semver
|
|
47
|
+
x2 = r1set[-1].semver
|
|
48
|
+
y1 = r2set[0].semver
|
|
49
|
+
y2 = r2set[-1].semver
|
|
50
|
+
|
|
51
|
+
if x1.prerelease and drop_prerelease1:
|
|
52
|
+
x1 = x1.inc("patch")
|
|
53
|
+
|
|
54
|
+
if y1.prerelease and drop_prerelease2:
|
|
55
|
+
y1 = y1.inc("patch")
|
|
56
|
+
|
|
57
|
+
o1 = r1set[0].operator
|
|
58
|
+
o2 = r2set[0].operator
|
|
59
|
+
|
|
60
|
+
# We do not handle (<) specifiers.
|
|
61
|
+
if o1.startswith("<") or o2.startswith("<"):
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
# Handle single value specifiers.
|
|
65
|
+
lx = lte if x1 == x2 else lt
|
|
66
|
+
ly = lte if y1 == y2 else lt
|
|
67
|
+
gx = gte if x1 == x2 else gt
|
|
68
|
+
gy = gte if x1 == x2 else gt
|
|
69
|
+
|
|
70
|
+
# Handle unbounded (>) specifiers.
|
|
71
|
+
def noop(x, y, z):
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
if x1 == x2 and o1.startswith(">"):
|
|
75
|
+
lx = noop
|
|
76
|
+
if y1 == y2 and o2.startswith(">"):
|
|
77
|
+
ly = noop
|
|
78
|
+
|
|
79
|
+
# Check for overlap.
|
|
80
|
+
if (
|
|
81
|
+
gte(x1, y1, True)
|
|
82
|
+
and ly(x1, y2, True)
|
|
83
|
+
or gy(x2, y1, True)
|
|
84
|
+
and ly(x2, y2, True)
|
|
85
|
+
or gte(y1, x1, True)
|
|
86
|
+
and lx(y1, x2, True)
|
|
87
|
+
or gx(y2, x1, True)
|
|
88
|
+
and lx(y2, x2, True)
|
|
89
|
+
):
|
|
90
|
+
# if we ever find an overlap, we can return immediately
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
if gte(y1, x2, True):
|
|
94
|
+
if return_value is False:
|
|
95
|
+
# We can possibly return 1
|
|
96
|
+
return_value = 1
|
|
97
|
+
elif return_value == -1:
|
|
98
|
+
# conflicting information, so we must return None
|
|
99
|
+
return_value = None
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
if gte(x1, y2, True):
|
|
103
|
+
if return_value is False:
|
|
104
|
+
return_value = -1
|
|
105
|
+
elif return_value == 1:
|
|
106
|
+
# conflicting information, so we must return None
|
|
107
|
+
return_value = None
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
msg = "Unexpected case comparing version ranges"
|
|
111
|
+
raise AssertionError(msg)
|
|
112
|
+
|
|
113
|
+
if return_value is False:
|
|
114
|
+
return_value = None
|
|
115
|
+
return return_value
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import contextlib
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import tempfile
|
|
9
|
+
import traceback
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
from traitlets import Unicode
|
|
13
|
+
from traitlets.config import Configurable
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DebugLogFileMixin(Configurable):
|
|
17
|
+
debug_log_path = Unicode("", config=True, help="Path to use for the debug log file")
|
|
18
|
+
|
|
19
|
+
@contextlib.contextmanager
|
|
20
|
+
def debug_logging(self):
|
|
21
|
+
log_path = self.debug_log_path
|
|
22
|
+
if os.path.isdir(log_path):
|
|
23
|
+
log_path = os.path.join(log_path, "jupyterlab-debug.log")
|
|
24
|
+
if not log_path:
|
|
25
|
+
handle, log_path = tempfile.mkstemp(prefix="jupyterlab-debug-", suffix=".log")
|
|
26
|
+
os.close(handle)
|
|
27
|
+
log = self.log
|
|
28
|
+
|
|
29
|
+
# Transfer current log level to the handlers:
|
|
30
|
+
for h in log.handlers:
|
|
31
|
+
h.setLevel(self.log_level)
|
|
32
|
+
log.setLevel("DEBUG")
|
|
33
|
+
|
|
34
|
+
# Create our debug-level file handler:
|
|
35
|
+
_debug_handler = logging.FileHandler(log_path, "w", "utf8", delay=True)
|
|
36
|
+
_log_formatter = self._log_formatter_cls(fmt=self.log_format, datefmt=self.log_datefmt)
|
|
37
|
+
_debug_handler.setFormatter(_log_formatter)
|
|
38
|
+
_debug_handler.setLevel("DEBUG")
|
|
39
|
+
|
|
40
|
+
log.addHandler(_debug_handler)
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
yield
|
|
44
|
+
except Exception as ex:
|
|
45
|
+
_, _, exc_traceback = sys.exc_info()
|
|
46
|
+
msg = traceback.format_exception(ex.__class__, ex, exc_traceback)
|
|
47
|
+
for line in msg:
|
|
48
|
+
self.log.debug(line)
|
|
49
|
+
if isinstance(ex, SystemExit):
|
|
50
|
+
warnings.warn(f"An error occurred. See the log file for details: {log_path}")
|
|
51
|
+
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}")
|
|
55
|
+
self.exit(1)
|
|
56
|
+
else:
|
|
57
|
+
log.removeHandler(_debug_handler)
|
|
58
|
+
_debug_handler.flush()
|
|
59
|
+
_debug_handler.close()
|
|
60
|
+
try:
|
|
61
|
+
os.remove(log_path)
|
|
62
|
+
except FileNotFoundError:
|
|
63
|
+
pass
|
|
64
|
+
log.removeHandler(_debug_handler)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from traitlets import Bool, Unicode
|
|
7
|
+
|
|
8
|
+
from ..base_extension_app import BaseExtensionApp
|
|
9
|
+
from ..core_path import default_core_path
|
|
10
|
+
from ..federated_extensions import build_labextension
|
|
11
|
+
|
|
12
|
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BuildLabExtensionApp(BaseExtensionApp):
|
|
16
|
+
description = "(developer) Build labextension"
|
|
17
|
+
|
|
18
|
+
static_url = Unicode("", config=True, help="Sets the url for static assets when building")
|
|
19
|
+
|
|
20
|
+
development = Bool(False, config=True, help="Build in development mode")
|
|
21
|
+
|
|
22
|
+
source_map = Bool(False, config=True, help="Generate source maps")
|
|
23
|
+
|
|
24
|
+
core_path = Unicode(
|
|
25
|
+
default_core_path(),
|
|
26
|
+
config=True,
|
|
27
|
+
help="Directory containing core application package.json file",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
aliases = {
|
|
31
|
+
"static-url": "BuildLabExtensionApp.static_url",
|
|
32
|
+
"development": "BuildLabExtensionApp.development",
|
|
33
|
+
"source-map": "BuildLabExtensionApp.source_map",
|
|
34
|
+
"core-path": "BuildLabExtensionApp.core_path",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def run_task(self):
|
|
38
|
+
self.extra_args = self.extra_args or [os.getcwd()]
|
|
39
|
+
build_labextension(
|
|
40
|
+
self.extra_args[0],
|
|
41
|
+
logger=self.log,
|
|
42
|
+
development=self.development,
|
|
43
|
+
static_url=self.static_url or None,
|
|
44
|
+
source_map=self.source_map,
|
|
45
|
+
core_path=self.core_path or None,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def main():
|
|
50
|
+
app = BuildLabExtensionApp()
|
|
51
|
+
app.initialize()
|
|
52
|
+
app.start()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
main()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from copy import copy
|
|
6
|
+
|
|
7
|
+
from jupyter_core.application import base_flags
|
|
8
|
+
from traitlets import Bool, Unicode
|
|
9
|
+
|
|
10
|
+
from ..base_extension_app import BaseExtensionApp
|
|
11
|
+
from ..federated_extensions import develop_labextension_py
|
|
12
|
+
|
|
13
|
+
flags = dict(base_flags)
|
|
14
|
+
develop_flags = copy(flags)
|
|
15
|
+
develop_flags["overwrite"] = (
|
|
16
|
+
{"DevelopLabExtensionApp": {"overwrite": True}},
|
|
17
|
+
"Overwrite files",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DevelopLabExtensionApp(BaseExtensionApp):
|
|
22
|
+
description = "(developer) Develop labextension"
|
|
23
|
+
|
|
24
|
+
flags = develop_flags
|
|
25
|
+
user = Bool(False, config=True, help="Whether to do a user install")
|
|
26
|
+
sys_prefix = Bool(True, config=True, help="Use the sys.prefix as the prefix")
|
|
27
|
+
overwrite = Bool(False, config=True, help="Whether to overwrite files") # flags
|
|
28
|
+
symlink = Bool(True, config=False, help="Whether to use a symlink")
|
|
29
|
+
|
|
30
|
+
labextensions_dir = Unicode(
|
|
31
|
+
"",
|
|
32
|
+
config=True,
|
|
33
|
+
help="Full path to labextensions dir (probably use prefix or user)",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def run_task(self):
|
|
37
|
+
"""Add config for this labextension"""
|
|
38
|
+
self.extra_args = self.extra_args or [os.getcwd()]
|
|
39
|
+
for arg in self.extra_args:
|
|
40
|
+
develop_labextension_py(
|
|
41
|
+
arg,
|
|
42
|
+
user=self.user,
|
|
43
|
+
sys_prefix=self.sys_prefix,
|
|
44
|
+
labextensions_dir=self.labextensions_dir,
|
|
45
|
+
logger=self.log,
|
|
46
|
+
overwrite=self.overwrite,
|
|
47
|
+
symlink=self.symlink,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main():
|
|
52
|
+
app = DevelopLabExtensionApp()
|
|
53
|
+
app.initialize()
|
|
54
|
+
app.start()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
main()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright (c) Jupyter Development Team.
|
|
2
|
+
# Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from traitlets import Bool, Unicode
|
|
7
|
+
|
|
8
|
+
from ..base_extension_app import BaseExtensionApp
|
|
9
|
+
from ..federated_extensions import watch_labextension
|
|
10
|
+
from ..core_path import default_core_path
|
|
11
|
+
|
|
12
|
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WatchLabExtensionApp(BaseExtensionApp):
|
|
16
|
+
description = "(developer) Watch labextension"
|
|
17
|
+
|
|
18
|
+
development = Bool(True, config=True, help="Build in development mode")
|
|
19
|
+
|
|
20
|
+
source_map = Bool(False, config=True, help="Generate source maps")
|
|
21
|
+
|
|
22
|
+
core_path = Unicode(
|
|
23
|
+
default_core_path(),
|
|
24
|
+
config=True,
|
|
25
|
+
help="Directory containing core application package.json file",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
aliases = {
|
|
29
|
+
"core-path": "WatchLabExtensionApp.core_path",
|
|
30
|
+
"development": "WatchLabExtensionApp.development",
|
|
31
|
+
"source-map": "WatchLabExtensionApp.source_map",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def run_task(self):
|
|
35
|
+
self.extra_args = self.extra_args or [os.getcwd()]
|
|
36
|
+
labextensions_path = self.labextensions_path
|
|
37
|
+
watch_labextension(
|
|
38
|
+
self.extra_args[0],
|
|
39
|
+
labextensions_path,
|
|
40
|
+
logger=self.log,
|
|
41
|
+
development=self.development,
|
|
42
|
+
source_map=self.source_map,
|
|
43
|
+
core_path=self.core_path or None,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def main():
|
|
48
|
+
app = WatchLabExtensionApp()
|
|
49
|
+
app.initialize()
|
|
50
|
+
app.start()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
main()
|