Skip to content

Commit faf66f4

Browse files
committed
update with review comments
1 parent 8f0ff5e commit faf66f4

File tree

7 files changed

+401
-165
lines changed

7 files changed

+401
-165
lines changed

.github/workflows/test.yaml

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ on:
2626
env:
2727
# avoid warnings about config paths
2828
JUPYTER_PLATFORM_DIRS: "1"
29+
# avoid looking at every version of pip ever released
30+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
2931

3032
jobs:
3133
build:
@@ -57,12 +59,7 @@ jobs:
5759
path: ./dist
5860

5961
test:
60-
name: |-
61-
${{ matrix.os }}
62-
${{ matrix.python-version }}
63-
s${{ matrix.jupyter_server-version }}
64-
lab${{ matrix.jupyterlab-version }}
65-
nb${{ matrix.notebook-version }}
62+
name: ${{ matrix.os }} ${{ matrix.python-version }} ${{ matrix.pip-extras }}
6663
needs: [build]
6764
timeout-minutes: 30
6865
runs-on: ${{ matrix.os }}
@@ -75,31 +72,16 @@ jobs:
7572
matrix:
7673
os: [ubuntu-22.04]
7774
python-version: ["3.8", "3.11"]
78-
jupyter_server-version: ["1", "2"]
79-
jupyterlab-version: ["3", "4"]
80-
include:
81-
# let jupyterlab-version 3 and 4 imply notebook-version 6 and 7
82-
# respectively, to avoid doubling the amount of test runs
83-
- jupyterlab-version: "3"
84-
notebook-version: "6"
85-
- jupyterlab-version: "4"
86-
notebook-version: "7"
75+
pip-extras: ["lab", "classic"]
76+
exclude:
8777
# windows should work for all test variations, but a limited selection
8878
# is run to avoid doubling the amount of test runs
89-
- os: windows-2022
90-
python-version: "3.8"
91-
jupyter_server-version: "1"
92-
jupyterlab-version: "3"
93-
notebook-version: "6"
9479
- os: windows-2022
9580
python-version: "3.11"
96-
jupyter_server-version: "2"
97-
jupyterlab-version: "4"
98-
notebook-version: "7"
99-
exclude:
100-
# jupyterlab-version 4 requires jupyter_server-version 2
101-
- jupyter_server-version: "1"
102-
jupyterlab-version: "4"
81+
pip-extras: classic
82+
- os: windows-2022
83+
python-version: "3.8"
84+
pip-extras: lab
10385

10486
steps:
10587
- uses: actions/checkout@v4
@@ -123,7 +105,7 @@ jobs:
123105
#
124106
# Pytest options are set in `pyproject.toml`.
125107
run: |
126-
pip install -vv $(ls ./dist/*.whl)\[acceptance\] 'jupyterlab~=${{ matrix.jupyterlab-version }}.0' 'jupyter_server~=${{ matrix.jupyter_server-version }}.0' 'notebook~=${{ matrix.notebook-version }}.0'
108+
pip install -vv $(ls ./dist/*.whl)\[acceptance,${{ matrix.pip-extras }}\]
127109
128110
- name: List Python packages
129111
run: |
@@ -136,19 +118,19 @@ jobs:
136118
jupyter server extension list 2>&1 | grep -iE "jupyter_server_proxy.*OK" -
137119
138120
- name: Check server extension for notebook v6
139-
if: matrix.notebook-version == '6'
121+
if: contains(matrix.pip-extras, 'classic')
140122
run: |
141123
jupyter serverextension list
142124
jupyter serverextension list 2>&1 | grep -iE "jupyter_server_proxy.*OK" -
143125
144126
- name: Check frontend extension for notebook v6
145-
if: matrix.notebook-version == '6'
127+
if: contains(matrix.pip-extras, 'classic')
146128
run: |
147129
jupyter nbextension list
148130
PYTHONUNBUFFERED=1 jupyter nbextension list 2>&1 | grep -A1 -iE '.*jupyter_server_proxy.*enabled' | grep -B1 -iE "Validating.*OK"
149131
150132
- name: Check frontend extension for notebook v7+
151-
if: matrix.notebook-version != '6'
133+
if: ${{ !contains(matrix.pip-extras, 'classic') }}
152134
run: |
153135
jupyter notebook extension list
154136
jupyter notebook extension list 2>&1 | grep -iE 'jupyter_server_proxy.*OK.*'
@@ -158,12 +140,12 @@ jobs:
158140
jupyter lab extension list
159141
jupyter lab extension list 2>&1 | grep -iE 'jupyter_server_proxy.*OK.*'
160142
143+
# we have installed a pre-built wheel and configured code coverage to
144+
# inspect "jupyter_server_proxy", by re-locating to another directory,
145+
# there is no confusion about "jupyter_server_proxy" referring to our
146+
# installed package rather than the local directory
161147
- name: Run tests
162148
run: |
163-
# we have installed a pre-built wheel and configured code coverage to
164-
# inspect "jupyter_server_proxy", by re-locating to another directory,
165-
# there is no confusion about "jupyter_server_proxy" referring to our
166-
# installed package rather than the local directory
167149
mkdir build
168150
cd build
169151
pytest -c ../pyproject.toml ../tests
@@ -173,7 +155,7 @@ jobs:
173155
uses: actions/upload-artifact@v3
174156
with:
175157
name: |-
176-
tests-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.jupyterlab-version }}-${{ github.run_number }}
158+
tests-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.pip-extras }}-${{ github.run_number }}
177159
path: |
178160
./build/pytest
179161
./build/coverage

CONTRIBUTING.md

Lines changed: 164 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,47 @@ the README.md file.
77

88
## Local development setup
99

10+
### `conda`
11+
12+
<details>
13+
14+
<summary>
15+
<i>
16+
Optional, but especially recommended on non-Linux platforms...
17+
</i>
18+
</summary>
19+
20+
Using the `conda` (or `mamba` or `micromamba`) package manager with packages from
21+
[`conda-forge`](https://conda-forge.org/feedstock-outputs) can help isolate development
22+
environments on nearly any operating system and architecture.
23+
24+
For example, after installing [`mambaforge`](https://conda-forge.org/miniforge),
25+
create a new environment with all heavy development and test dependencies:
26+
27+
```yaml
28+
mamba create --name=jupyter-server-proxy --channel=conda-forge "python=3.11" "nodejs=20" pip git geckodriver firefox
29+
mamba activate jupyter-server-proxy
30+
```
31+
32+
</details>
33+
1034
### Python package
1135

1236
```bash
1337
# Clone the repo to your local environment
1438
git clone https://github.com/jupyterhub/jupyter-server-proxy.git
1539
# Change directory to the jupyter-server-proxy directory
1640
cd jupyter-server-proxy
17-
# Install package in development mode
18-
pip install -e ".[test]"
19-
# Link your development version of the extension with JupyterLab
20-
jupyter labextension develop --overwrite .
41+
# Install package in development mode, with the latest Jupyter clients
42+
pip install -e ".[test,lab]"
43+
# Link your development version of the extension with JupyterLab and Notebook
44+
jlpm labextension develop --overwrite .
2145
# Server extension must be manually installed in develop mode
2246
jupyter server extension enable jupyter_server_proxy
2347
```
2448

49+
## Testing
50+
2551
Run the tests:
2652

2753
```bash
@@ -32,75 +58,171 @@ These generate test and coverage reports in `build/pytest` and `build/coverage`.
3258

3359
### Acceptance tests
3460

35-
If you have `robotframework-jupyterlibary` installed, the acceptance tests will run.
61+
In `tests/acceptance`, a number of
62+
[`.robot` files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html)
63+
emulate a user starting a Jupyter server, opening a real browser, clicking on
64+
screen elements, and seeing several working proxy servers in supported Jupyter clients.
3665

37-
To install these in addition to the [Python package](#python-package) test
38-
dependencies, run:
66+
These tests are slower and more resource intensive than the unit and integration
67+
tests, and generate additional screenshots, browser logs, server logs, and report
68+
HTML in `build/robot`.
3969

40-
```bash
41-
pip install -e ".[acceptance]"
42-
```
70+
#### Extra browser dependencies
4371

44-
In addition, compatible versions of:
72+
Compatible versions of [`geckodriver`](https://github.com/mozilla/geckodriver)
73+
and [`firefox`](https://www.mozilla.org/en-US/firefox) need to be on `$PATH`.
4574

46-
- `geckodriver`
47-
- `firefox`
75+
These can be provisioned by [a `conda`-compatible installer](#conda), a system
76+
package manager, or as a last resort, direct binary downloads.
4877

49-
Need to be on your `$PATH` and compatible with each other.
78+
#### Acceptance test dependencies
79+
80+
To install the additional dependencies beyond the [Python package](#python-package)
81+
test dependencies, and run the tests against the latest Jupyter clients:
82+
83+
```bash
84+
pip install -e ".[test,acceptance,lab]"
85+
pytest
86+
```
5087

5188
To run _only_ the acceptance tests, use the `-k` switch:
5289

5390
```bash
5491
pytest -k acceptance
5592
```
5693

57-
These are slower than the rest of the `pytest` tests, and generate screenshots,
58-
browser logs, server logs, and report HTML in `build/robot`.
94+
#### Older Jupyter Clients
95+
96+
To run the acceptance tests against the previous major versions of Notebook
97+
and JupyterLab, it is advisable to use a separate, isolated environment, testing the
98+
as-built assets from `pyproject-build`.
99+
100+
After creating and activating such an environment with `virtualenv` or [`conda`](#conda):
101+
102+
```bash
103+
pip install --find-links ./dist/ --no-index-url jupyter-server-proxy[test,acceptance,classic]
104+
```
105+
106+
## Frontend Development
107+
108+
To support a wide range of clients, both JupyterLab and Notebook Classic extensions
109+
are built and distributed, each with their own quirks.
110+
111+
### JupyterLab/Notebook extension
112+
113+
The `./labextension/` directory contains the extension for the
114+
[`lumino`](https://github.com/jupyterlab/lumino/)-based JupyterLab and Notebook
115+
clients.
116+
117+
#### `nodejs`
118+
119+
Building this extension requires a compatible version of
120+
[`nodejs`](https://nodejs.org/en/download/package-manager), with a supported, long
121+
term support (LTS) release recommended.
59122

60-
### JupyterLab extension
123+
#### `jlpm`
61124

62-
The `jlpm` command is JupyterLab's pinned version of `yarn` that is
63-
installed with JupyterLab.
125+
The `jlpm` command is a vendored, pinned version of the [`yarn`](https://yarnpkg.com)
126+
package manager. Installed with JupyterLab, it performs commands such
127+
as installing `npm` dependencies listed in `labextension/package.json`, building
128+
and watching the extension from source, and formatting web-related source code files.
64129

65-
> You may use `yarn` or `npm run` instead of `jlpm` below.
130+
#### The built Lab extension
131+
132+
During a [`pyproject-build`](https://pypi.org/project/build/)
133+
of the python package, a temporary JupyterLab and `jlpm` will be installed as part
134+
of the `build-system`, executing roughly the commands:
66135

67136
```bash
68137
cd labextension # Change to the root of the labextension
69-
jlpm # Install dependencies (or `npm i`)
138+
jlpm # Install dependencies
70139
jlpm build:prod # Build:
71-
# - `labextension/lib`
72-
# - `jupyter_server_proxy/labextension`
140+
# - `labextension/lib` with type checking
141+
# - `jupyter_server_proxy/labextension` with minimization
142+
```
143+
144+
During `pip install`, the built assets are copied to the user's
145+
`{sys.prefix}/share/jupyter/labextensions/@jupyterhub/jupyter-server-proxy` to be
146+
found by the application at startup.
147+
148+
#### Developing the Lab extension
149+
150+
For fine-grained access to the `jlpm` command and various build steps:
151+
152+
```bash
153+
pip install -e .[lab] # Ensure a compatible jlpm
154+
cd labextension # Change to the root of the labextension
155+
jlpm
73156
jlpm install:extension # Symlink into `{sys.prefix}/share/jupyter/labextensions`
74157
```
75158

76-
You can watch the source directory and automatically rebuild the `labextension/lib`
159+
Watch the source directory and automatically rebuild the `labextension/lib`
77160
and `jupyter_server_proxy/labextension` folders:
78161

79162
```bash
80163
cd labextension
81164
# Watch the source directory in one terminal, automatically rebuilding when needed
82-
jlpm run watch
165+
jlpm watch
83166
# Run JupyterLab in another terminal
84167
jupyter lab
85168
```
86169

87-
With the watch command running, every saved change will immediately be built locally
88-
and available in your running JupyterLab. Refresh JupyterLab to load the change in
89-
your browser (you may need to wait several seconds for the extension to be rebuilt).
170+
While running `jlpm watch`, every saved change to a `.ts` file will immediately be
171+
built locally and available in your running Jupyter client. "Hard" refresh JupyterLab or Notebook
172+
with <kbd>CTRL-F5</kbd> or <kbd>⌘-F5</kbd> to load the change in your browser
173+
(you may need to wait several seconds for the extension to be fully rebuilt).
174+
175+
#### Source Maps
176+
177+
By default, the `jlpm build` and `jlpm watch` commands generate
178+
[source maps](https://firefox-source-docs.mozilla.org/devtools-user/debugger/how_to/use_a_source_map/)
179+
for this extension to improve debugging using the browser development tools,
180+
often revealed by pressing <kbd>F12</kbd>.
90181

91-
By default, the `jlpm run build` command generates the source maps for this
92-
extension to make it easier to debug using the browser dev tools. To also generate
93-
source maps for the JupyterLab core extensions, you can run the following command:
182+
To also generate source maps for the JupyterLab core application, run the following command:
94183

95184
```bash
96185
jupyter lab build --minimize=False
97186
```
98187

99-
### Documentation
188+
### Notebook Classic extension
189+
190+
The files in `jupyter_server_proxy/static` extend the Notebook Classic application's
191+
_Tree_ page.
192+
193+
#### RequireJS
194+
195+
The Notebook Classic extension uses the [`require.js`](https://requirejs.org)
196+
dependency injection system, and presently uses no dependencies beyond what is
197+
provided by Notebook Classic.
198+
199+
#### The built Classic extension
200+
201+
During a user's `pip install`, the static assets are copied to
202+
`{sys.prefix}/share/jupyter/nbextensions/jupyter_server_proxy`, to be
203+
found by the application at startup.
204+
205+
#### Developing the Classic extension
206+
207+
While this extension is served as-is once installed, for live development the
208+
extension assets must be linked:
209+
210+
```bash
211+
pip install -e ".[classic]"
212+
jupyter nbextension install --symlink --sys-prefix --py jupyter_server_proxy
213+
```
214+
215+
After making changes, "hard" refresh the browser application, usually with
216+
<kbd>CTRL-F5</kbd> or <kbd>⌘-F5</kbd>.
217+
218+
## Documentation
100219

101220
The documentation uses a fairly standard [Sphinx](https://www.sphinx-doc.org)
102221
build chain, and requires `make` on Linux/MacOS, which cannot be installed with
103-
`pip`.
222+
`pip`
223+
224+
> `make` is available from [`conda-forge`](#conda) as `make` for Linux/OSX, and `m2-make`
225+
> on Windows
104226
105227
In addition to any system packages, building the documentation requires
106228
additional packages. To install the needed packages:
@@ -132,3 +254,12 @@ make linkcheck
132254
```bash
133255
make devenv
134256
```
257+
258+
## Linting
259+
260+
During continuous integration (CI) the `pre-commit` package is used to run a
261+
number of checks, with each tool in a private virtual environment. If it is able to,
262+
the CI bot will push to a PR with fixes.
263+
264+
By installing `pre-commit` with `pip` or `conda`, you can have this same experience,
265+
or inspect the configuration to try to recreate it yourself locally.

0 commit comments

Comments
 (0)