jupyterlab-env-sync 1.0.0__tar.gz

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.
Files changed (62) hide show
  1. jupyterlab_env_sync-1.0.0/.devcontainer/Dockerfile +158 -0
  2. jupyterlab_env_sync-1.0.0/.devcontainer/README.md +5 -0
  3. jupyterlab_env_sync-1.0.0/.devcontainer/devcontainer.json +46 -0
  4. jupyterlab_env_sync-1.0.0/.devcontainer/docker-compose.yaml +35 -0
  5. jupyterlab_env_sync-1.0.0/.gitignore +140 -0
  6. jupyterlab_env_sync-1.0.0/.prettierignore +7 -0
  7. jupyterlab_env_sync-1.0.0/.vscode/debug.env +13 -0
  8. jupyterlab_env_sync-1.0.0/.vscode/launch.json +55 -0
  9. jupyterlab_env_sync-1.0.0/.vscode/settings.json +8 -0
  10. jupyterlab_env_sync-1.0.0/.yarnrc.yml +1 -0
  11. jupyterlab_env_sync-1.0.0/CHANGELOG.md +25 -0
  12. jupyterlab_env_sync-1.0.0/LICENSE +29 -0
  13. jupyterlab_env_sync-1.0.0/PKG-INFO +188 -0
  14. jupyterlab_env_sync-1.0.0/README.md +126 -0
  15. jupyterlab_env_sync-1.0.0/Todo.md +13 -0
  16. jupyterlab_env_sync-1.0.0/babel.config.js +1 -0
  17. jupyterlab_env_sync-1.0.0/conftest.py +19 -0
  18. jupyterlab_env_sync-1.0.0/install.json +5 -0
  19. jupyterlab_env_sync-1.0.0/jest.config.js +49 -0
  20. jupyterlab_env_sync-1.0.0/jupyter-config/server-config/jupyterlab-env-sync.json +7 -0
  21. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/__init__.py +28 -0
  22. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/_version.py +4 -0
  23. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/env_store.py +115 -0
  24. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/handlers.py +73 -0
  25. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/package.json +212 -0
  26. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/schemas/jupyterlab-env-sync/package.json.orig +207 -0
  27. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/schemas/jupyterlab-env-sync/plugin.json +8 -0
  28. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/static/347.e27f14d722982387653c.js +1 -0
  29. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/static/456.f73d93de8f6f5c4af2af.js +1 -0
  30. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/static/remoteEntry.5dc387c184ecd73aa600.js +1 -0
  31. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/static/style.js +4 -0
  32. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/labextension/static/third-party-licenses.json +16 -0
  33. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/startup_hooks.py +104 -0
  34. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/tests/__init__.py +1 -0
  35. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/tests/conftest.py +1 -0
  36. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/tests/test_env_store.py +116 -0
  37. jupyterlab_env_sync-1.0.0/jupyterlab-env-sync/tests/test_handlers.py +77 -0
  38. jupyterlab_env_sync-1.0.0/minio-browser-screenshot.gif +0 -0
  39. jupyterlab_env_sync-1.0.0/notebooks/.keep +0 -0
  40. jupyterlab_env_sync-1.0.0/package-lock.json +26586 -0
  41. jupyterlab_env_sync-1.0.0/package.json +207 -0
  42. jupyterlab_env_sync-1.0.0/pyproject.toml +79 -0
  43. jupyterlab_env_sync-1.0.0/schema/plugin.json +8 -0
  44. jupyterlab_env_sync-1.0.0/src/__tests__/jupyterlab-env-sync.spec.ts +52 -0
  45. jupyterlab_env_sync-1.0.0/src/env_sync.ts +96 -0
  46. jupyterlab_env_sync-1.0.0/src/index.ts +20 -0
  47. jupyterlab_env_sync-1.0.0/src/kernel_inject.ts +102 -0
  48. jupyterlab_env_sync-1.0.0/src/terminal_restart.ts +42 -0
  49. jupyterlab_env_sync-1.0.0/src/tokens.ts +18 -0
  50. jupyterlab_env_sync-1.0.0/style/base.css +1 -0
  51. jupyterlab_env_sync-1.0.0/style/index.css +1 -0
  52. jupyterlab_env_sync-1.0.0/style/index.js +1 -0
  53. jupyterlab_env_sync-1.0.0/tsconfig.json +26 -0
  54. jupyterlab_env_sync-1.0.0/ui-tests/README.md +148 -0
  55. jupyterlab_env_sync-1.0.0/ui-tests/jupyter_server_test_config.py +20 -0
  56. jupyterlab_env_sync-1.0.0/ui-tests/package-lock.json +4712 -0
  57. jupyterlab_env_sync-1.0.0/ui-tests/package.json +14 -0
  58. jupyterlab_env_sync-1.0.0/ui-tests/playwright.config.js +14 -0
  59. jupyterlab_env_sync-1.0.0/ui-tests/tests/jupyterlab-env-sync.spec.ts +213 -0
  60. jupyterlab_env_sync-1.0.0/ui-tests/yarn.lock +5959 -0
  61. jupyterlab_env_sync-1.0.0/webpack.config.js +11 -0
  62. jupyterlab_env_sync-1.0.0/yarn.lock +11812 -0
@@ -0,0 +1,158 @@
1
+ FROM debian:bookworm-slim AS jupyter
2
+
3
+ LABEL author=aristide
4
+
5
+ SHELL [ "/bin/bash", "-c" ]
6
+ ENV SHELL=/bin/bash
7
+ # Replace shell with bash so we can source files
8
+ RUN rm /bin/sh && ln -s /bin/bash /bin/sh
9
+
10
+ # Set debconf to run non-interactively
11
+ RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
12
+
13
+ RUN apt-get update \
14
+ && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
15
+ # For frappe framework
16
+ git \
17
+ mariadb-client \
18
+ postgresql-client \
19
+ gettext-base \
20
+ wget \
21
+ # for PDF
22
+ libssl-dev \
23
+ fonts-cantarell \
24
+ xfonts-75dpi \
25
+ xfonts-base \
26
+ # weasyprint dependencies
27
+ libpango-1.0-0 \
28
+ libharfbuzz0b \
29
+ libpangoft2-1.0-0 \
30
+ libpangocairo-1.0-0 \
31
+ # to work inside the container
32
+ locales \
33
+ build-essential \
34
+ cron \
35
+ curl \
36
+ vim \
37
+ sudo \
38
+ iputils-ping \
39
+ watch \
40
+ tree \
41
+ nano \
42
+ less \
43
+ software-properties-common \
44
+ bash-completion \
45
+ # For psycopg2
46
+ libpq-dev \
47
+ # Other
48
+ libffi-dev \
49
+ liblcms2-dev \
50
+ libldap2-dev \
51
+ libmariadb-dev \
52
+ libsasl2-dev \
53
+ libtiff5-dev \
54
+ libwebp-dev \
55
+ redis-tools \
56
+ rlwrap \
57
+ tk8.6-dev \
58
+ ssh-client \
59
+ # VSCode container requirements
60
+ net-tools \
61
+ # For pyenv build dependencies
62
+ # https://github.com/frappe/frappe_docker/issues/840#issuecomment-1185206895
63
+ make \
64
+ # For pandas
65
+ libbz2-dev \
66
+ # For bench execute
67
+ libsqlite3-dev \
68
+ # For other dependencies
69
+ zlib1g-dev \
70
+ libreadline-dev \
71
+ llvm \
72
+ libncurses5-dev \
73
+ libncursesw5-dev \
74
+ xz-utils \
75
+ tk-dev \
76
+ liblzma-dev \
77
+ file \
78
+ && rm -rf /var/lib/apt/lists/*
79
+
80
+ # Create new user with home directory, improve docker compatibility with UID/GID 1000,
81
+ # add user to sudo group, allow passwordless sudo, switch to that user
82
+ # and change directory to user home directory
83
+ RUN groupadd -g 1000 jupyter \
84
+ && useradd --no-log-init -r -m -u 1000 -g 1000 -G sudo jupyter \
85
+ && echo "jupyter ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
86
+
87
+ USER jupyter
88
+ WORKDIR /home/jupyter
89
+
90
+ # Install Python via pyenv
91
+ ENV PYENV_ROOT=/home/jupyter/.pyenv
92
+ ENV PATH=$PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
93
+ ENV PYTHON_VERSION=3.12.7
94
+
95
+ # From https://github.com/pyenv/pyenv#basic-github-checkout
96
+ RUN git clone --depth 1 https://github.com/pyenv/pyenv.git .pyenv \
97
+ && pyenv install $PYTHON_VERSION \
98
+ && PYENV_VERSION=$PYTHON_VERSION pip install --no-cache-dir virtualenv \
99
+ && pyenv global $PYTHON_VERSION \
100
+ && sed -Ei -e '/^([^#]|$)/ {a export PYENV_ROOT="/home/jupyter/.pyenv" a export PATH="$PYENV_ROOT/bin:$PATH" a ' -e ':a' -e '$!{n;ba};}' ~/.profile \
101
+ && echo 'eval "$(pyenv init --path)"' >>~/.profile \
102
+ && echo 'eval "$(pyenv init -)"' >>~/.bashrc
103
+
104
+ # Clone and install bench in the local user home directory
105
+ # For development, bench source is located in ~/.bench
106
+ ENV PATH=/home/jupyter/.local/bin:$PATH
107
+
108
+ # Install Node via nvm
109
+ ENV NODE_VERSION=18.20.4
110
+ ENV NVM_DIR=/home/jupyter/.nvm
111
+ ENV PATH=${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
112
+
113
+ RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash \
114
+ && . ${NVM_DIR}/nvm.sh \
115
+ && npm install -g yarn \
116
+ && nvm install ${NODE_VERSION} \
117
+ && nvm use v${NODE_VERSION} \
118
+ && npm install -g yarn \
119
+ && nvm alias default v${NODE_VERSION} \
120
+ && rm -rf ${NVM_DIR}/.cache \
121
+ && echo 'export NVM_DIR="/home/jupyter/.nvm"' >>~/.bashrc \
122
+ && echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm' >> ~/.bashrc \
123
+ && echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion' >> ~/.bashrc
124
+
125
+ # Install mc client
126
+ RUN mkdir -p /home/jupyter/.local/bin \
127
+ && curl https://dl.min.io/client/mc/release/linux-amd64/mc -o /home/jupyter/.local/bin/mc \
128
+ && chmod +x /home/jupyter/.local/bin/mc
129
+
130
+ # Install JupyterLab 4 and hatch build tools
131
+ RUN pip install --no-cache-dir \
132
+ "jupyterlab>=4.0.0,<5" \
133
+ "hatchling>=1.5.0" \
134
+ "hatch-jupyter-builder>=0.5" \
135
+ "hatch-nodejs-version>=0.3.2"
136
+
137
+ # Install Claude Code CLI
138
+ RUN curl -fsSL https://claude.ai/install.sh | bash
139
+
140
+ EXPOSE 8888 9999
141
+
142
+ ENV PATH=/home/jupyter/.pyenv/versions/$PYTHON_VERSION/bin:$PATH
143
+
144
+ FROM jupyter AS jupyter-test
145
+
146
+ # Print version and verify bashrc is properly sourced so that everything works
147
+ # in the interactive shell and Dockerfile
148
+
149
+ RUN node --version \
150
+ && npm --version \
151
+ && yarn --version \
152
+ && python --version \
153
+ && jupyter lab --version \
154
+ && claude --version
155
+
156
+ RUN bash -c "node --version" \
157
+ && bash -c "npm --version" \
158
+ && bash -c "yarn --version"
@@ -0,0 +1,5 @@
1
+ # build image
2
+
3
+ ```bash
4
+ docker build -t aristidetm/labextension-dev .
5
+ ```
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "Jupyterlab Extension",
3
+ "remoteUser": "jupyter",
4
+ "forwardPorts": [8888, 9999, 9000, 9001],
5
+ "portsAttributes": {
6
+ "8888": {
7
+ "label": "Jupyter Lab",
8
+ "onAutoForward": "openBrowser",
9
+ "protocol": "http",
10
+ "url": "http://localhost:8888/lab"
11
+ },
12
+ "9001": {
13
+ "label": "MinIO Console",
14
+ "onAutoForward": "notify"
15
+ }
16
+ },
17
+ "customizations": {
18
+ "vscode": {
19
+ "openExternal": true,
20
+ "defaultUrl": "/lab",
21
+ "extensions": [
22
+ "ms-python.python",
23
+ "ms-vscode.live-server",
24
+ "visualstudioexptteam.vscodeintellicode",
25
+ "esbenp.prettier-vscode"
26
+ ],
27
+ "settings": {
28
+ "terminal.integrated.profiles.linux": {
29
+ "jupyter bash": {
30
+ "path": "/bin/bash"
31
+ }
32
+ },
33
+ "terminal.integrated.defaultProfile.linux": "jupyter bash",
34
+ "debug.node.autoAttach": "disabled"
35
+ }
36
+ }
37
+ },
38
+ "dockerComposeFile": "./docker-compose.yaml",
39
+ "service": "jupyter-minio",
40
+ "workspaceFolder": "/workspace",
41
+ "shutdownAction": "stopCompose",
42
+ "mounts": [
43
+ "source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/jupyter/.ssh,type=bind,consistency=cached"
44
+ ],
45
+ "postCreateCommand": "pip install -e . && jupyter labextension develop . --overwrite && jupyter server extension enable jupyterlab-env-sync && jlpm build"
46
+ }
@@ -0,0 +1,35 @@
1
+ version: '3.7'
2
+
3
+ # Settings and configurations that are common for all containers
4
+ services:
5
+ minio:
6
+ image: quay.io/minio/minio:RELEASE.2024-08-29T01-40-52Z
7
+ command: server --console-address ":9001" /data
8
+ ports:
9
+ - 0.0.0.0:9000:9000
10
+ - 0.0.0.0:9001:9001
11
+ environment:
12
+ MINIO_ROOT_USER: minioadmin
13
+ MINIO_ROOT_PASSWORD: minioadmin
14
+ healthcheck:
15
+ test: ["CMD", "mc", "ready", "local"]
16
+ interval: 5s
17
+ timeout: 5s
18
+ retries: 5
19
+ volumes:
20
+ - data:/data
21
+
22
+ jupyter-minio:
23
+ image: aristidetm/labextension-dev
24
+ volumes:
25
+ - ..:/workspace
26
+ working_dir: /workspace
27
+ ports:
28
+ - 0.0.0.0:8888:8888
29
+ - 0.0.0.0:9999:9999
30
+ command: sleep infinity
31
+ depends_on:
32
+ - minio
33
+
34
+ volumes:
35
+ data:
@@ -0,0 +1,140 @@
1
+ *.bundle.*
2
+ lib/
3
+ node_modules/
4
+ *.log
5
+ .eslintcache
6
+ .stylelintcache
7
+ *.egg-info/
8
+ .ipynb_checkpoints
9
+ *.tsbuildinfo
10
+ jupyterlab-env-sync/labextension
11
+ # Version file is handled by hatchling
12
+ # jupyterlab-env-sync/_version.py
13
+
14
+ # Integration tests
15
+ ui-tests/test-results/
16
+ ui-tests/playwright-report/
17
+
18
+ # Created by https://www.gitignore.io/api/python
19
+ # Edit at https://www.gitignore.io/?templates=python
20
+
21
+ ### Python ###
22
+ # Byte-compiled / optimized / DLL files
23
+ __pycache__/
24
+ *.py[cod]
25
+ *$py.class
26
+
27
+ # C extensions
28
+ *.so
29
+
30
+ # Distribution / packaging
31
+ .Python
32
+ build/
33
+ develop-eggs/
34
+ dist/
35
+ downloads/
36
+ eggs/
37
+ .eggs/
38
+ lib/
39
+ lib64/
40
+ parts/
41
+ sdist/
42
+ var/
43
+ wheels/
44
+ pip-wheel-metadata/
45
+ share/python-wheels/
46
+ .installed.cfg
47
+ *.egg
48
+ MANIFEST
49
+ .venv
50
+ .virtual_documents
51
+
52
+ # PyInstaller
53
+ # Usually these files are written by a python script from a template
54
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
55
+ *.manifest
56
+ *.spec
57
+
58
+ # Installer logs
59
+ pip-log.txt
60
+ pip-delete-this-directory.txt
61
+
62
+ # Unit test / coverage reports
63
+ htmlcov/
64
+ .tox/
65
+ .nox/
66
+ .coverage
67
+ .coverage.*
68
+ .cache
69
+ nosetests.xml
70
+ coverage/
71
+ coverage.xml
72
+ *.cover
73
+ .hypothesis/
74
+ .pytest_cache/
75
+
76
+ # Translations
77
+ *.mo
78
+ *.pot
79
+
80
+ # Scrapy stuff:
81
+ .scrapy
82
+
83
+ # Sphinx documentation
84
+ docs/_build/
85
+
86
+ # PyBuilder
87
+ target/
88
+
89
+ # pyenv
90
+ .python-version
91
+
92
+ # celery beat schedule file
93
+ celerybeat-schedule
94
+
95
+ # SageMath parsed files
96
+ *.sage.py
97
+
98
+ # Spyder project settings
99
+ .spyderproject
100
+ .spyproject
101
+
102
+ # Rope project settings
103
+ .ropeproject
104
+
105
+ # Mr Developer
106
+ .mr.developer.cfg
107
+ .project
108
+ .pydevproject
109
+
110
+ # mkdocs documentation
111
+ /site
112
+
113
+ # mypy
114
+ .mypy_cache/
115
+ .dmypy.json
116
+ dmypy.json
117
+
118
+ # Pyre type checker
119
+ .pyre/
120
+
121
+ # End of https://www.gitignore.io/api/python
122
+
123
+ # OSX files
124
+ .DS_Store
125
+ notebooks/*
126
+ !notebooks/.keep
127
+ .secrets
128
+
129
+ # others
130
+ .Trash*
131
+
132
+ # Claude Code
133
+ .claude/
134
+
135
+ # Yarn
136
+ .yarn/
137
+
138
+ # Error logs
139
+ errors/
140
+ scope/
@@ -0,0 +1,7 @@
1
+ node_modules
2
+ **/node_modules
3
+ **/lib
4
+ **/package.json
5
+ !/package.json
6
+ jupyterlab-env-sync
7
+ .venv
@@ -0,0 +1,13 @@
1
+ # set VIRTUAL_ENV to the root of your venv
2
+ VIRTUAL_ENV="/home/jupyter/.pyenv/versions/3.11.9"
3
+
4
+ # jupyter env vars
5
+ JUPYTER_CONFIG_DIR="${VIRTUAL_ENV}/etc/jupyter"
6
+ JUPYTER_DATA_DIR="${VIRTUAL_ENV}/share/jupyter"
7
+ JUPYTER_PATH="${VIRTUAL_ENV}/share/jupyter"
8
+ JUPYTER_RUNTIME_DIR="${JUPYTER_PATH}/runtime"
9
+
10
+ # jupyterlab env vars
11
+ JUPYTERLAB_DIR="${VIRTUAL_ENV}/share/jupyter/lab"
12
+ JUPYTERLAB_SETTINGS_DIR="${JUPYTERLAB_DIR}/settings"
13
+ JUPYTERLAB_WORKSPACES_DIR="${JUPYTERLAB_DIR}/workspaces"
@@ -0,0 +1,55 @@
1
+ {
2
+ // To debug jupyterlab running in a venv or conda env:
3
+ // - set up Python env in your workspace as per https://code.visualstudio.com/docs/python/environments
4
+ // - add an "envFile" prop to each backend config pointing to .vscode/debug.env
5
+ // - configure the .vscode/debug.env file as needed
6
+ "version": "0.2.0",
7
+ "configurations": [
8
+ {
9
+ "name": "jlpm watch",
10
+ "type": "node-terminal",
11
+ "request": "launch",
12
+ "command": "jlpm watch"
13
+ },
14
+ {
15
+ "name": "jlab backend",
16
+ "type": "python",
17
+ "request": "launch",
18
+ "args": [
19
+ "--notebook-dir=notebooks",
20
+ "--no-browser",
21
+ "--NotebookApp.token=''",
22
+ "--port=9999",
23
+ "--ip=0.0.0.0",
24
+ "--log-level=ERROR"
25
+ ],
26
+ "justMyCode": false,
27
+ "module": "jupyterlab.labapp",
28
+ "presentation": {
29
+ "hidden": true
30
+ }
31
+ },
32
+ {
33
+ "name": "jlab frontend",
34
+ "type": "chrome",
35
+ "request": "launch",
36
+ "timeout": 180000,
37
+ "url": "http://localhost:9999/lab",
38
+ // set webroot to the parent dir of your project's top level package.json
39
+ "webRoot": "${workspaceFolder}",
40
+ "presentation": {
41
+ "hidden": true
42
+ }
43
+ }
44
+ ],
45
+ "compounds": [
46
+ {
47
+ "name": "jlab debug",
48
+ "configurations": ["jlab backend", "jlab frontend"]
49
+ },
50
+ {
51
+ "name": "jlab debug (watch)",
52
+ "configurations": ["jlpm watch", "jlab backend", "jlab frontend"]
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "python.defaultInterpreterPath": "/home/jupyter/.pyenv/versions/3.12.7/bin/python",
3
+ "[python]": {
4
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
5
+ "editor.formatOnSave": true
6
+ },
7
+ "files.eol": "\n"
8
+ }
@@ -0,0 +1 @@
1
+ nodeLinker: node-modules
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ <!-- <START NEW CHANGELOG ENTRY> -->
4
+
5
+ ## 1.0.0
6
+
7
+ ### New Features
8
+
9
+ - **IEnvSync token** — public API for consumer extensions to set, reset, and query environment variables (`setVar`, `resetVar`, `getAll`, `getByExtension`, `resetAllByExtension`)
10
+ - **Server-side persistence** — REST API (`GET/PUT/DELETE /jupyterlab-env-sync/env`) backed by a JSON file in the Jupyter runtime directory; also mutates `os.environ` so new processes inherit values
11
+ - **Kernel propagation** — injects env var changes into all running Python, R, and Julia kernels via silent `requestExecute`
12
+ - **Terminal restart** — shuts down and reopens terminals when variables change, with a toast notification
13
+ - **Startup hooks** — installs IPython, R, and Julia startup scripts so new kernels automatically load overrides
14
+ - **Multi-extension ownership** — tracks which extension set each variable; `resetAllByExtension` only cleans up that extension's keys
15
+ - **Spawner-aware reset** — captures the original spawner value on first override and restores it on reset
16
+ - **Conflict resolution** — last-write-wins with a logged warning when extensions target the same key
17
+
18
+ ### Tests
19
+
20
+ - Python unit tests for `EnvStore` (set, reset, ownership, spawner restoration)
21
+ - Python integration tests for REST handlers via `pytest-jupyter`
22
+ - TypeScript unit tests for kernel injection snippet generation (Python, R, Julia)
23
+ - Playwright UI tests for REST API and kernel propagation
24
+
25
+ <!-- <END NEW CHANGELOG ENTRY> -->
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2024, Aristide Mendo'o
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.