Skip to content

Commit ee1a9de

Browse files
authored
Setup Proper Documentation (jupyterlab#69)
* fix-readme * include-flags * fix-lint * fix-test * look-for-home-in-env-too * set-cli-flags-in-advance-section
1 parent cad70cb commit ee1a9de

3 files changed

Lines changed: 115 additions & 80 deletions

File tree

README.md

Lines changed: 106 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,104 +5,132 @@
55
[![version on PyPI](https://img.shields.io/pypi/v/jupyter-builder.svg)](https://pypi.org/project/jupyter-builder/)
66
[![version on conda-forge](https://img.shields.io/conda/vn/conda-forge/jupyter-builder.svg)](https://anaconda.org/conda-forge/jupyter-builder)
77

8-
Build tools for JupyterLab (and remixes)
8+
Build tools for JupyterLab extensions — extracted from the core [JupyterLab](https://github.com/jupyterlab/jupyterlab) codebase to be maintained and used independently.
99

10-
> \[!NOTE\]
11-
> This started by the extraction of the builder tools included in
12-
> the core [JupyterLab](https://github.com/jupyterlab/jupyterlab) during a GSoC project. See [below](#gsoc-2024-anecdote) for more information.
10+
## Installation
1311

14-
## Why extracting the build tools?
15-
16-
- This would also solve some chicken-and-egg problems like jupyterlab/jupyterlab_pygments#23.
17-
- Isolating the builder functionalities will simplify the work
18-
of core and extension developers who can now focus on their respective parts of the
19-
codebase instead of the earlier intertwined code.
20-
- It will in particular reduce the need to update the maintenance tooling to produce extension compatible with newer version of Jupyter app.
21-
22-
## How to install the package?
23-
24-
Execute the following command in a terminal:
25-
26-
```
12+
```bash
2713
pip install jupyter_builder
2814
```
2915

30-
## What does it do?
31-
32-
- Provides a CLI for building Jupyter extensions. There are 3 subcommands
33-
- `build` : Builds the Jupyter extension JavaScript assets to be consumed by the Jupyter app.
34-
```
35-
jupyter-builder build <path to extension folder>
36-
```
37-
- `develop` : Install the Jupyter extension JavaScript assets in dev mode for consumption in the Jupyter app. It similar to [editable install mode of pip](https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs)
38-
```
39-
jupyter-builder develop --overwrite <path to extension folder>
40-
```
41-
- `watch` : Automatically rebuild the development JavaScript assets when one file is changed to ease development.
42-
```
43-
jupyter-builder watch <path to extension folder>
44-
```
45-
- Provides a NPM package manager: `jlpm`
16+
## CLI
4617

47-
## How to uninstall the package?
18+
### `build`
4819

49-
Execute the following command in a terminal:
20+
Compile the extension JavaScript assets for consumption by a Jupyter app.
5021

51-
```
52-
pip uninstall jupyter_builder
22+
```bash
23+
jupyter-builder build <path/to/extension>
5324
```
5425

55-
______________________________________________________________________
26+
### `develop`
5627

57-
## GSoC 2024 Anecdote
28+
Install extension assets in development mode (analogous to `pip install -e`). Uses a symlink by default.
5829

59-
> Written by [@cronan03](https://github.com/cronan03) - GSoC Contributor 2024
30+
```bash
31+
jupyter-builder develop <path/to/extension>
32+
```
6033

61-
### Goal
34+
### `watch`
6235

63-
The goals of this project are:
36+
Automatically rebuild development assets when source files change.
6437

65-
- to extract that tooling as a new separate package to ease maintenance (for core and extension developers)
66-
- update the existing package to use the new one
67-
- make it configurable to be reused for other applications.
38+
```bash
39+
jupyter-builder watch <path/to/extension>
40+
```
6841

69-
### What I did
42+
> For advanced configuration, see the [Advanced](#advanced) section for available flags.
7043
71-
1. Successfully created a CLI with the processes `develop`, `build` and `watch` mentioned above.
72-
1. Created extensive unit tests using `Pytest` to ensure the processes run efficiently on any OS.
73-
1. Reduced external dependencies by bringing `jlpm` and `jupyterlab.semver` to the package.
74-
1. Pre released the package. It can be found on Pypi here https://pypi.org/project/jupyter-builder/
75-
1. Initiated a solution to the issue https://github.com/jupyterlab/jupyterlab/issues/13456
44+
## `jlpm`
7645

77-
### What's left to do
46+
`jupyter-builder` ships `jlpm`, a Jupyter-aware Node.js package manager wrapper:
7847

79-
1. We should bring `@jupyterlab/builder` within this package and make it generic.
80-
For now the code lives there: https://github.com/jupyterlab/jupyterlab/tree/main/builder
81-
1. https://github.com/jupyterlab/jupyter-builder/blob/fffb100fc57ecb147bface4441f91bfd0cb6ff9a/jupyter_builder/federated_extensions.py#L296 which is responsible for checking version overlap has been temporarily ignored to make the build feature work.
82-
1. Update JupyterLab core to use this new package
48+
```bash
49+
jlpm install
50+
jlpm build
51+
```
8352

84-
### Merged PRs
53+
## Advanced
54+
55+
### CLI flags
56+
57+
<details>
58+
<summary><code>build</code></summary>
59+
60+
| Flag | Description |
61+
| ---------------------------- | ---------------------------------------------------------------------- |
62+
| `--development` | Build in development mode (default: `False`) |
63+
| `--source-map` | Generate source maps (default: `False`) |
64+
| `--static-url=<url>` | Set the URL for static assets |
65+
| `--core-version=<version>` | JupyterLab core version to build against |
66+
| `--core-package-file=<path>` | Path to a core application `package.json` (overrides `--core-version`) |
67+
68+
</details>
69+
70+
<details>
71+
<summary><code>develop</code></summary>
72+
73+
| Flag | Description |
74+
| ---------------------------- | -------------------------------------------- |
75+
| `--overwrite` | Overwrite existing files |
76+
| `--user` | Install to the user's directory |
77+
| `--sys-prefix` | Install under `sys.prefix` (default: `True`) |
78+
| `--labextensions-dir=<path>` | Install to a custom labextensions directory |
79+
80+
</details>
81+
82+
<details>
83+
<summary><code>watch</code></summary>
84+
85+
| Flag | Description |
86+
| ---------------------------- | ---------------------------------------------------------------------- |
87+
| `--development` | Build in development mode (default: `True`) |
88+
| `--source-map` | Generate source maps (default: `False`) |
89+
| `--core-version=<version>` | JupyterLab core version to build against |
90+
| `--core-package-file=<path>` | Path to a core application `package.json` (overrides `--core-version`) |
91+
92+
</details>
93+
94+
### Python API
95+
96+
```python
97+
from jupyter_builder.federated_extensions import (
98+
build_labextension,
99+
develop_labextension_py,
100+
watch_labextension,
101+
)
102+
103+
build_labextension(
104+
"/path/to/extension",
105+
development=False,
106+
source_map=False,
107+
static_url=None,
108+
core_version=None,
109+
core_package_file=None,
110+
)
111+
112+
develop_labextension_py(
113+
"/path/to/extension",
114+
overwrite=True,
115+
symlink=True,
116+
user=False,
117+
sys_prefix=True,
118+
)
119+
120+
watch_labextension(
121+
"/path/to/extension",
122+
labextensions_path=[...],
123+
development=True,
124+
source_map=False,
125+
)
126+
```
85127

86-
1. https://github.com/jupyterlab/jupyter-builder/pull/11
87-
- This PR focuses on extracting the `develop` feature which is responsible for installing the Jupyter extension JS assets in dev mode.
88-
- Considering the size of [labextension.py](https://github.com/jupyterlab/jupyterlab/blob/main/jupyterlab/labextensions.py), only features essential to Jupyter builder were added.
89-
- Each of the features will inherit from the class `BaseExtensionApp` present [here](https://github.com/jupyterlab/jupyter-builder/blob/main/jupyter_builder/base_extension_app.py)
90-
- The [federated_extensions.py](https://github.com/jupyterlab/jupyter-builder/blob/main/jupyter_builder/federated_extensions.py) sets up and executes commands to build, develop and waatch a JupyterLab extension. It resolves paths, constructs the appropriate command-line arguments, and executes the build process using `subprocess.check_call`. Optional parameters allow for customization of the build process, including logging, development mode, and source map generation.
91-
1. https://github.com/jupyterlab/jupyter-builder/pull/13
92-
- This PR focuses on extracting the `build` feature which is responsible for creating the Javascript assets which will be consumed by the Jupyter App.
93-
- It will always result in the creation of a file `static/style.js` in `<extension_folder>/myextension/labextension`.
94-
- Tests have been crafted using `Pytest` to check for the existence of files mentioned above on running the `build` command.
95-
1. https://github.com/jupyterlab/jupyter-builder/pull/18
96-
- The `watch` feature on running will rebuild the JS assets on being triggered. This happens on changing contents in `<extension_folder>/src/index.ts`
97-
- To test this feature we deliberately make a change in `index.ts` triggering `watch`. This replaces old JS assets with new ones having different hash values in the file names. We create 2 vectors of filenames before and after triggering `watch` which will tell us if it actually worked.
98-
1. https://github.com/jupyterlab/jupyter-builder/pull/20
99-
- To reduce external dependencies, we added `jlpm` to this package.
100-
- It existed [here](https://github.com/jupyterlab/jupyterlab/blob/main/jupyterlab/jlpmapp.py) with the [entrypoint](https://github.com/jupyterlab/jupyterlab/blob/e048f27548969c0e4403417ac04bc186f119128f/pyproject.toml#L60).
101-
1. https://github.com/jupyterlab/jupyter-builder/pull/22
102-
- Documented the working of the Jupyter builder along with installation guide.
128+
## Uninstall
129+
130+
```bash
131+
pip uninstall jupyter_builder
132+
```
103133

104-
### Challenges and Learning
134+
## Credits
105135

106-
1. One of the main challenges was starting this project from scratch with no pre existing code to rely on. I thank my mentor [@fcollonval](https://github.com/fcollonval) for creating the skeleton in https://github.com/jupyterlab/jupyter-builder/pull/2 which gave me a base to work on.
107-
1. Selecting relevant features for Jupyter builder from [labextension.py](https://github.com/jupyterlab/jupyterlab/blob/main/jupyterlab/labextensions.py) was really tough without a thorough understanding on which functions Jupyter builder would actually rely on.
108-
1. Creating tests for the `watch` feature was tricky as I had to carefully adjust sleep times to make sure the function was running before a change in `<extension_folder>/src/index.ts` was made. Otherwise the change happened before `watch` ran and never triggered it.
136+
This package was initially created during [GSoC 2024](https://summerofcode.withgoogle.com) by [@cronan03](https://github.com/cronan03), mentored by [@fcollonval](https://github.com/fcollonval).

jupyter_builder/core_path.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
import requests
1111

1212

13+
def _home_dir() -> Path:
14+
home = os.environ.get("HOME")
15+
return Path(home) if home else Path.home()
16+
17+
1318
def get_core_meta(
1419
version: Optional[str] = None, ext_path: Optional[Union[str, os.PathLike[str]]] = None
1520
) -> str:
@@ -22,7 +27,7 @@ def get_core_meta(
2227
return installed_core_meta
2328
requested_version = "main"
2429

25-
cache_root = Path.home() / ".cache" / "jupyterlab_builder" / "core"
30+
cache_root = _home_dir() / ".cache" / "jupyterlab_builder" / "core"
2631
cached_file = _get_cached_core_meta_file(cache_root, requested_version)
2732
if cached_file is not None:
2833
return str(cached_file)

tests/test_core_path.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,9 @@ def test_ensure_builder_reads_custom_core_package_file(tmp_path):
291291
ext_path = tmp_path / "ext"
292292
core_path_dir = tmp_path / "core-meta"
293293
core_package_file = core_path_dir / "core.package.json"
294+
# TODO: Once core starts using new @jupyter/builder, we need to update here.
294295
builder_dir = ext_path / "node_modules" / "@jupyterlab" / "builder"
296+
new_builder_dir = ext_path / "node_modules" / "@jupyter" / "builder"
295297

296298
builder_dir.mkdir(parents=True)
297299
core_path_dir.mkdir()
@@ -304,4 +306,4 @@ def test_ensure_builder_reads_custom_core_package_file(tmp_path):
304306

305307
builder_path = _ensure_builder(str(ext_path), str(core_package_file))
306308

307-
assert builder_path == str(builder_dir / "lib" / "build-labextension.js")
309+
assert builder_path == str(new_builder_dir / "lib" / "build-labextension.js")

0 commit comments

Comments
 (0)