Skip to content

Commit c348b16

Browse files
authored
LicensesManager and API/CLI (#161)
* spdx license string * move handlers * add licenses_url to config * add licenses to extension app handlers * handle more spdx-like output of builder * linting * don't cache federated extensions, as they may be interactively installed * fix markdown mime, add download option * fix extension * add tests for licenses handler * add some debugging to header disposition check * add markdown mimetype if needed * consume most of the license CLI, remove special cases for dev_mode, etc * add CLI test for different formats * clean up systemexit testing * add top-level key for bundles * add license route to OpenAPI
1 parent d1bb603 commit c348b16

File tree

7 files changed

+615
-1
lines changed

7 files changed

+615
-1
lines changed

jupyterlab_server/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Distributed under the terms of the Modified BSD License.
33

44
from .app import LabServerApp
5+
from .licenses_app import LicensesApp
56
from .handlers import add_handlers, LabHandler, LabConfig
67
from .workspaces_handler import slugify, WORKSPACE_EXTENSION
78
from ._version import __version__
@@ -23,4 +24,4 @@ def _jupyter_server_extension_points():
2324
'module': 'jupyterlab_server',
2425
'app': LabServerApp
2526
}
26-
]
27+
]

jupyterlab_server/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ class LabConfig(HasTraits):
233233

234234
themes_url = Unicode(help='The theme url.').tag(config=True)
235235

236+
licenses_url = Unicode(help='The third-party licenses url.')
237+
236238
themes_dir = Unicode('',
237239
help=('The optional location of the themes '
238240
'directory. If given, a handler will be added '
@@ -278,6 +280,10 @@ def _default_listings_url(self):
278280
def _default_themes_url(self):
279281
return ujoin(self.app_url, 'api', 'themes/')
280282

283+
@default('licenses_url')
284+
def _default_licenses_url(self):
285+
return ujoin(self.app_url, 'api', 'licenses/')
286+
281287
@default('tree_url')
282288
def _default_tree_url(self):
283289
return ujoin(self.app_url, 'tree/')

jupyterlab_server/handlers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from .themes_handler import ThemesHandler
1919
from .translations_handler import TranslationsHandler
2020
from .workspaces_handler import WorkspacesHandler
21+
from .licenses_handler import LicensesHandler, LicensesManager
2122

2223
# -----------------------------------------------------------------------------
2324
# Module globals
@@ -257,6 +258,18 @@ def add_handlers(handlers, extension_app):
257258
}
258259
))
259260

261+
# Handle licenses.
262+
if extension_app.licenses_url:
263+
licenses_url = extension_app.licenses_url
264+
licenses_path = ujoin(licenses_url, '(.*)')
265+
handlers.append((
266+
licenses_path,
267+
LicensesHandler,
268+
{
269+
'manager': LicensesManager(parent=extension_app)
270+
}
271+
))
272+
260273
# Handle translations.
261274
if extension_app.translations_api_url:
262275
# Handle requests for the list of language packs available.

jupyterlab_server/licenses_app.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""A license reporting CLI
2+
3+
Mostly ready-to-use, the downstream must provide the location of the application's
4+
static resources. Licenses from an app's federated_extensions will also be discovered
5+
as configured in `labextensions_path` and `extra_labextensions_path`.
6+
7+
from traitlets import default
8+
from jupyterlab_server import LicensesApp
9+
10+
class MyLicensesApp(LicensesApp):
11+
version = "0.1.0"
12+
13+
@default("static_dir")
14+
def _default_static_dir(self):
15+
return "my-static/"
16+
17+
class MyApp(JupyterApp, LabConfig):
18+
...
19+
subcommands = dict(
20+
licenses=(MyLicensesApp, MyLicensesApp.description.splitlines()[0])
21+
)
22+
23+
"""
24+
from traitlets import Bool, Unicode, Enum, Instance
25+
from jupyter_core.application import JupyterApp, base_aliases, base_flags
26+
27+
from ._version import __version__
28+
from .config import LabConfig
29+
from .licenses_handler import LicensesManager
30+
31+
32+
class LicensesApp(JupyterApp, LabConfig):
33+
version = __version__
34+
35+
description = """
36+
Report frontend licenses
37+
"""
38+
39+
static_dir = Unicode(
40+
"", config=True, help="The static directory from which to show licenses"
41+
)
42+
43+
full_text = Bool(
44+
False, config=True, help="Also print out full license text (if available)"
45+
)
46+
47+
report_format = Enum(
48+
["markdown", "json", "csv"], "markdown", config=True, help="Reporter format"
49+
)
50+
51+
bundles_pattern = Unicode(
52+
".*", config=True, help="A regular expression of bundles to print"
53+
)
54+
55+
licenses_manager = Instance(LicensesManager)
56+
57+
aliases = {
58+
**base_aliases,
59+
"bundles": "LicensesApp.bundles_pattern",
60+
"report-format": "LicensesApp.report_format",
61+
}
62+
63+
flags = {
64+
**base_flags,
65+
"full-text": (
66+
{"LicensesApp": {"full_text": True}},
67+
"Print out full license text (if available)",
68+
),
69+
"json": (
70+
{"LicensesApp": {"report_format": "json"}},
71+
"Print out report as JSON (implies --full-text)",
72+
),
73+
"csv": (
74+
{"LicensesApp": {"report_format": "csv"}},
75+
"Print out report as CSV (implies --full-text)",
76+
),
77+
}
78+
79+
def initialize(self, *args, **kwargs):
80+
super().initialize(*args, **kwargs)
81+
self.init_licenses_manager()
82+
83+
def init_licenses_manager(self):
84+
self.licenses_manager = LicensesManager(
85+
labextensions_path=sum(
86+
[self.labextensions_path + self.extra_labextensions_path], []
87+
),
88+
parent=self,
89+
)
90+
91+
def start(self):
92+
report = self.licenses_manager.report(
93+
report_format=self.report_format,
94+
full_text=self.full_text,
95+
bundles_pattern=self.bundles_pattern,
96+
)[0]
97+
print(report)
98+
self.exit(0)

0 commit comments

Comments
 (0)