├── tests ├── test_package │ ├── test_package │ │ ├── __init__.py │ │ └── hey.py │ ├── pyproject.toml │ └── environment-3.yml ├── environment-2.yml ├── environment-1.yml └── test_xeus_python_env.py ├── setup.py ├── docs ├── changelog.md ├── environment.yml ├── build-environment.yml ├── installation.md ├── conf.py ├── deploy.md ├── index.md ├── migration.md ├── configuration.md └── xeus-python.svg ├── ui-tests ├── jupyter_lite_config.json ├── jupyter-lite.json ├── test │ ├── general.test.ts-snapshots │ │ ├── launcher-firefox-linux.png │ │ └── launcher-chromium-linux.png │ ├── utils.ts │ ├── general.test.ts │ ├── execute.test.ts │ └── files.test.ts ├── .yarnrc.yml ├── build.py ├── playwright.config.js └── package.json ├── .prettierignore ├── style ├── logos │ ├── python-logo-32x32.png │ └── python-logo-64x64.png ├── base.css ├── index.js └── index.css ├── .yarnrc.yml ├── .eslintignore ├── .readthedocs.yaml ├── install.json ├── README.md ├── src ├── declarations.d.ts └── index.ts ├── environment.yml ├── RELEASE.md ├── .github └── workflows │ ├── enforce-label.yml │ ├── check-release.yml │ ├── rtd-preview.yml │ ├── prep-release.yml │ ├── publish-release.yml │ ├── playwright-update.yml │ ├── ui-tests.yml │ └── build.yml ├── tsconfig.json ├── .copier-answers.yml ├── worker.webpack.config.js ├── webpack.config.js ├── jupyterlite_xeus_python ├── __init__.py ├── env_build_addon.py └── build.py ├── .eslintrc.js ├── LICENSE ├── .gitignore ├── pyproject.toml ├── package.json └── CHANGELOG.md /tests/test_package/test_package/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | __import__("setuptools").setup() 2 | -------------------------------------------------------------------------------- /tests/test_package/test_package/hey.py: -------------------------------------------------------------------------------- 1 | print("Hey") 2 | -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 | ```{include} ../CHANGELOG.md 2 | 3 | ``` 4 | -------------------------------------------------------------------------------- /tests/test_package/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "test-package" 3 | version = "0.1.0" 4 | -------------------------------------------------------------------------------- /ui-tests/jupyter_lite_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "LiteBuildConfig": { 3 | "output_dir": "ui-tests-app" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | **/node_modules 3 | **/lib 4 | **/package.json 5 | jupyterlite_xeus_python 6 | _output 7 | -------------------------------------------------------------------------------- /style/logos/python-logo-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlite/xeus-python-kernel/HEAD/style/logos/python-logo-32x32.png -------------------------------------------------------------------------------- /style/logos/python-logo-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlite/xeus-python-kernel/HEAD/style/logos/python-logo-64x64.png -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | enableImmutableInstalls: false 2 | enableInlineBuilds: false 3 | enableTelemetry: false 4 | httpTimeout: 60000 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | coverage 4 | **/*.d.ts 5 | tests 6 | src/worker.ts 7 | src/web_worker_kernel.ts 8 | 9 | # TODO: remove 10 | ui-tests 11 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: "ubuntu-20.04" 5 | tools: 6 | python: "mambaforge-4.10" 7 | 8 | conda: 9 | environment: docs/build-environment.yml 10 | -------------------------------------------------------------------------------- /ui-tests/jupyter-lite.json: -------------------------------------------------------------------------------- 1 | { 2 | "jupyter-lite-schema-version": 0, 3 | "jupyter-config-data": { 4 | "appName": "JupyterLite UI Tests", 5 | "exposeAppInBrowser": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ui-tests/test/general.test.ts-snapshots/launcher-firefox-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlite/xeus-python-kernel/HEAD/ui-tests/test/general.test.ts-snapshots/launcher-firefox-linux.png -------------------------------------------------------------------------------- /ui-tests/test/general.test.ts-snapshots/launcher-chromium-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jupyterlite/xeus-python-kernel/HEAD/ui-tests/test/general.test.ts-snapshots/launcher-chromium-linux.png -------------------------------------------------------------------------------- /tests/test_package/environment-3.yml: -------------------------------------------------------------------------------- 1 | name: xeus-python-kernel-3 2 | channels: 3 | - https://repo.mamba.pm/emscripten-forge 4 | - conda-forge 5 | dependencies: 6 | - numpy 7 | - pip: 8 | - . 9 | -------------------------------------------------------------------------------- /ui-tests/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | enableImmutableInstalls: false 2 | enableInlineBuilds: false 3 | enableTelemetry: false 4 | httpTimeout: 60000 5 | nodeLinker: node-modules 6 | npmRegistryServer: 'https://registry.yarnpkg.com' 7 | -------------------------------------------------------------------------------- /tests/environment-2.yml: -------------------------------------------------------------------------------- 1 | name: xeus-python-kernel-2 2 | channels: 3 | - https://repo.mamba.pm/emscripten-forge 4 | - conda-forge 5 | dependencies: 6 | - pip: 7 | # Installing NumPy with pip should fail 8 | - numpy 9 | -------------------------------------------------------------------------------- /install.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageManager": "python", 3 | "packageName": "jupyterlite-xeus-python", 4 | "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupyterlite-xeus-python" 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jupyterlite-xeus-python 2 | 3 | > ⚠️ 4 | > jupyterlite-xeus-python is DEPRECATED. 5 | > Please use https://github.com/jupyterlite/xeus. 6 | > See [the migration guide](https://xeus-python-kernel.readthedocs.io/en/latest/migration.html). 7 | -------------------------------------------------------------------------------- /src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Thorsten Beier 2 | // Copyright (c) JupyterLite Contributors 3 | // Distributed under the terms of the Modified BSD License. 4 | 5 | declare module '*.png' { 6 | const value: string; 7 | export default value; 8 | } 9 | -------------------------------------------------------------------------------- /docs/environment.yml: -------------------------------------------------------------------------------- 1 | name: xeus-python-kernel-docs 2 | channels: 3 | - https://repo.mamba.pm/emscripten-forge 4 | - conda-forge 5 | dependencies: 6 | - numpy 7 | - matplotlib 8 | - pillow 9 | - ipywidgets 10 | - pip: 11 | - ipycanvas 12 | -------------------------------------------------------------------------------- /style/base.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | | Copyright (c) Thorsten Beier 3 | | Copyright (c) Jupyter Development Team. 4 | | Distributed under the terms of the Modified BSD License. 5 | |---------------------------------------------------------------------------- */ 6 | -------------------------------------------------------------------------------- /style/index.js: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | | Copyright (c) Thorsten Beier 3 | | Copyright (c) Jupyter Development Team. 4 | | Distributed under the terms of the Modified BSD License. 5 | |----------------------------------------------------------------------------*/ 6 | 7 | import './base.css'; 8 | -------------------------------------------------------------------------------- /style/index.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------- 2 | | Copyright (c) Thorsten Beier 3 | | Copyright (c) Jupyter Development Team. 4 | | Distributed under the terms of the Modified BSD License. 5 | |---------------------------------------------------------------------------- */ 6 | 7 | @import url('base.css'); 8 | -------------------------------------------------------------------------------- /tests/environment-1.yml: -------------------------------------------------------------------------------- 1 | name: xeus-python-kernel-1 2 | channels: 3 | - https://repo.mamba.pm/emscripten-forge 4 | - conda-forge 5 | dependencies: 6 | - numpy 7 | - matplotlib 8 | - pillow 9 | - ipywidgets 10 | - pip: 11 | # Installing a python package that ships a lab extension under share/ 12 | - ipycanvas 13 | # Installing a pure python package 14 | - py2vega 15 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: xeus-python-kernel 2 | channels: 3 | - conda-forge 4 | - conda-forge/label/jupyterlite_core_alpha 5 | dependencies: 6 | - python 7 | - build 8 | - pip 9 | - jupyterlab >=4.0,<5 10 | - jupyterlite-core >=0.2.0a1,<0.3.0 11 | - traitlets 12 | - requests 13 | - typer 14 | - pytest 15 | - empack >=3,<4 16 | - nodejs=20 17 | - mamba 18 | - black 19 | - ruff 20 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Making a new release of `jupyterlite-xeus-python` 2 | 3 | The recommended way to make a release is to use [`jupyter_releaser`](https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html). 4 | 5 | This repository contains the two workflows located under https://github.com/jupyterlite/xeus-python-kernel/actions: 6 | 7 | - Step 1: Prep Release 8 | - Step 2: Publish Release 9 | -------------------------------------------------------------------------------- /.github/workflows/enforce-label.yml: -------------------------------------------------------------------------------- 1 | name: Enforce PR label 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request: 8 | types: [labeled, unlabeled, opened, edited, synchronize] 9 | jobs: 10 | enforce-label: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | pull-requests: write 14 | steps: 15 | - name: enforce-triage-label 16 | uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1 17 | -------------------------------------------------------------------------------- /ui-tests/build.py: -------------------------------------------------------------------------------- 1 | """ 2 | Custom script to build the UI tests app and load the Galata extension 3 | """ 4 | 5 | from pathlib import Path 6 | from subprocess import run 7 | 8 | import jupyterlab 9 | 10 | extra_labextensions_path = str(Path(jupyterlab.__file__).parent / "galata") 11 | cmd = f"jupyter lite build --FederatedExtensionAddon.extra_labextensions_path={extra_labextensions_path}" 12 | 13 | run( 14 | cmd, 15 | check=True, 16 | shell=True, 17 | ) 18 | -------------------------------------------------------------------------------- /docs/build-environment.yml: -------------------------------------------------------------------------------- 1 | name: xeus-python-kernel-docs 2 | 3 | channels: 4 | - conda-forge 5 | - conda-forge/label/jupyterlite_core_alpha 6 | 7 | dependencies: 8 | - python=3.10 9 | - pip 10 | - nodejs=20 11 | - click 12 | - typer 13 | - linkify-it-py 14 | - myst-parser 15 | - pydata-sphinx-theme 16 | - jupyterlab >=4.0.5,<5 17 | - jupyterlite-core >=0.2.0a1,<0.3.0 18 | - jupyterlite-sphinx >=0.9.1 19 | - empack >=3.1.0 20 | - pip: 21 | - .. 22 | -------------------------------------------------------------------------------- /ui-tests/test/utils.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) JupyterLite Contributors 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | /** 5 | * Workaround for Galata being stuck when testing on Firefox: 6 | * https://github.com/jupyterlab/jupyterlab/issues/15093 7 | */ 8 | export async function firefoxWaitForApplication({ baseURL }, use, testInfo) { 9 | const waitIsReady = async (page): Promise => { 10 | await page.waitForSelector('.jp-LauncherCard'); 11 | }; 12 | await use(waitIsReady); 13 | } 14 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | (installation)= 2 | 3 | # Installation 4 | 5 | You can install `jupyterlite-xeus-python` with conda/mamba 6 | 7 | ``` 8 | mamba install -c conda-forge jupyterlite-xeus-python 9 | ``` 10 | 11 | Or with `pip`: 12 | 13 | ``` 14 | pip install jupyterlite-xeus-python 15 | ``` 16 | 17 | Once you have installed `jupyterlite-xeus-python`, you can use it as a kernel in JupyterLite. You can use the `jupyter lite` command line interface to build a JupyterLite application to start using the `xeus-python` kernel: 18 | 19 | ```bash 20 | jupyter lite build 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | extensions = [ 2 | "jupyterlite_sphinx", 3 | "myst_parser", 4 | ] 5 | 6 | myst_enable_extensions = [ 7 | "linkify", 8 | ] 9 | 10 | master_doc = "index" 11 | source_suffix = ".rst" 12 | 13 | project = "jupyterlite-xeus-python" 14 | copyright = "JupyterLite Team" 15 | author = "JupyterLite Team" 16 | 17 | exclude_patterns = [] 18 | 19 | html_theme = "pydata_sphinx_theme" 20 | 21 | jupyterlite_dir = "." 22 | 23 | html_theme_options = { 24 | "logo": { 25 | "image_light": "xeus-python.svg", 26 | "image_dark": "xeus-python.svg", 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "composite": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "incremental": true, 8 | "jsx": "react", 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "noEmitOnError": true, 12 | "noImplicitAny": false, 13 | "noUnusedLocals": true, 14 | "preserveWatchOutput": true, 15 | "resolveJsonModule": true, 16 | "outDir": "lib", 17 | "rootDir": "src", 18 | "strict": true, 19 | "strictNullChecks": true, 20 | "target": "ES2019" 21 | }, 22 | "include": ["src/*"] 23 | } 24 | -------------------------------------------------------------------------------- /.copier-answers.yml: -------------------------------------------------------------------------------- 1 | # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY 2 | _commit: v4.2.1 3 | _src_path: https://github.com/jupyterlab/extension-template 4 | author_email: '' 5 | author_name: JupyterLite Contributors 6 | data_format: string 7 | file_extension: '' 8 | has_binder: false 9 | has_settings: false 10 | kind: frontend 11 | labextension_name: '@jupyterlite/xeus-python-kernel' 12 | mimetype: '' 13 | mimetype_name: '' 14 | project_short_description: A Python kernel for JupyterLite, powered by Xeus 15 | python_name: jupyterlite-xeus-python 16 | repository: https://github.com/jupyterlite/xeus-python-kernel 17 | test: false 18 | viewer_name: '' 19 | 20 | -------------------------------------------------------------------------------- /worker.webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const rules = [ 3 | { 4 | test: /\.js$/, 5 | exclude: /node_modules/, 6 | loader: 'source-map-loader' 7 | } 8 | ]; 9 | 10 | const resolve = { 11 | fallback: { 12 | fs: false, 13 | child_process: false, 14 | crypto: false 15 | }, 16 | extensions: ['.js'] 17 | }; 18 | 19 | module.exports = [ 20 | { 21 | entry: './lib/worker.js', 22 | output: { 23 | filename: 'worker.js', 24 | path: path.resolve(__dirname, 'lib'), 25 | libraryTarget: 'amd' 26 | }, 27 | module: { 28 | rules 29 | }, 30 | devtool: 'source-map', 31 | resolve 32 | } 33 | ]; 34 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | plugins: [ 5 | new CopyPlugin({ 6 | patterns: [ 7 | { 8 | from: 'src/xpython_wasm.wasm', 9 | to: '.' 10 | }, 11 | { 12 | from: 'src/xpython_wasm.js', 13 | to: '.' 14 | }, 15 | { 16 | from: 'src/*.gz', 17 | to: './[name].gz' 18 | }, 19 | { 20 | from: 'src/*.js', 21 | to: './[name].js' 22 | }, 23 | { 24 | from: 'src/empack_env_meta.json', 25 | to: '.' 26 | } 27 | ] 28 | }) 29 | ] 30 | }; 31 | -------------------------------------------------------------------------------- /jupyterlite_xeus_python/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from ._version import __version__ 3 | except ImportError: 4 | # Fallback when using the package in dev mode without installing 5 | # in editable mode with pip. It is highly recommended to install 6 | # the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs 7 | import warnings 8 | 9 | warnings.warn( 10 | "Importing 'jupyterlite-xeus-python' outside a proper installation.", stacklevel=2 11 | ) 12 | __version__ = "dev" 13 | 14 | 15 | def _jupyter_labextension_paths(): 16 | return [{"src": "labextension", "dest": "@jupyterlite/xeus-python-kernel"}] 17 | -------------------------------------------------------------------------------- /docs/deploy.md: -------------------------------------------------------------------------------- 1 | (deploy)= 2 | 3 | # Deploy your own 4 | 5 | ## On Github Pages 6 | 7 | In order to make your own JupyterLite deployment, you can use the [xeus-python-demo repository template](https://github.com/jupyterlite/xeus-python-demo) 8 | that allows you to easily make a JupyteLite deployment on Github pages with xeus-python as default kernel. 9 | 10 | This template repository contains an `environment.yml` file where you can specify the packages you need. You can also add Notebooks to the `content` folder. 11 | 12 | ## In Sphinx documentation 13 | 14 | You can make a JupyterLite deployment with xeus-python installed using the [jupyterlite-sphinx extension](https://github.com/jupyterlite/jupyterlite-sphinx) 15 | -------------------------------------------------------------------------------- /ui-tests/playwright.config.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('@jupyterlab/galata/lib/playwright-config'); 2 | 3 | module.exports = { 4 | ...baseConfig, 5 | retries: 1, 6 | use: { 7 | acceptDownloads: true, 8 | appPath: '', 9 | autoGoto: false, 10 | baseURL: 'http://localhost:8000', 11 | trace: 'retain-on-failure', 12 | video: 'retain-on-failure', 13 | 14 | waitForApplication: async ({ baseURL }, use, testInfo) => { 15 | const waitIsReady = async page => { 16 | await page.waitForSelector('.jp-LauncherCard'); 17 | }; 18 | await use(waitIsReady); 19 | } 20 | }, 21 | webServer: [ 22 | { 23 | command: 'jlpm run start', 24 | port: 8000, 25 | timeout: 120 * 1000, 26 | reuseExistingServer: true 27 | } 28 | ] 29 | }; 30 | -------------------------------------------------------------------------------- /.github/workflows/check-release.yml: -------------------------------------------------------------------------------- 1 | name: Check Release 2 | on: 3 | push: 4 | branches: ["main"] 5 | pull_request: 6 | branches: ["*"] 7 | 8 | jobs: 9 | check_release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | - name: Base Setup 15 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 16 | - name: Check Release 17 | uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2 18 | with: 19 | 20 | token: ${{ secrets.GITHUB_TOKEN }} 21 | 22 | - name: Upload Distributions 23 | uses: actions/upload-artifact@v3 24 | with: 25 | name: jupyterlite-xeus-python-releaser-dist-${{ github.run_number }} 26 | path: .jupyter_releaser_checkout/dist 27 | -------------------------------------------------------------------------------- /ui-tests/test/general.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) JupyterLite Contributors 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | import { test } from '@jupyterlab/galata'; 5 | 6 | import { expect } from '@playwright/test'; 7 | 8 | import { firefoxWaitForApplication } from './utils'; 9 | 10 | test.use({ waitForApplication: firefoxWaitForApplication }); 11 | 12 | test.describe('General', () => { 13 | test.beforeEach(async ({ page }) => { 14 | await page.goto('lab/index.html'); 15 | }); 16 | 17 | test('Kernel is registered', async ({ page }) => { 18 | const imageName = 'launcher.png'; 19 | const launcherElement = await page.$('.jp-Launcher-body'); 20 | if (!launcherElement) { 21 | throw new Error('Launcher not found'); 22 | } 23 | expect(await launcherElement.screenshot()).toMatchSnapshot(imageName); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ui-tests/test/execute.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) JupyterLite Contributors 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | import { test } from '@jupyterlab/galata'; 5 | 6 | import { expect } from '@playwright/test'; 7 | 8 | import { firefoxWaitForApplication } from './utils'; 9 | 10 | test.use({ waitForApplication: firefoxWaitForApplication }); 11 | 12 | test.describe('Code execution', () => { 13 | test.beforeEach(async ({ page }) => { 14 | await page.goto('lab/index.html'); 15 | }); 16 | 17 | test('Basic code execution', async ({ page }) => { 18 | await page.notebook.createNew(); 19 | await page.notebook.setCell(0, 'code', '2 + 2'); 20 | await page.notebook.run(); 21 | const output = await page.notebook.getCellTextOutput(0); 22 | 23 | expect(output).toBeTruthy(); 24 | expect(output![0]).toBe('4'); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /ui-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jupyterlite/jupyterlite-xeus-python-ui-tests", 3 | "private": true, 4 | "version": "0.1.0", 5 | "author": "JupyterLite Contributors", 6 | "license": "BSD-3-Clause", 7 | "description": "JupyterLite Xeus Python UI Tests", 8 | "scripts": { 9 | "build": "python build.py", 10 | "clean": "rimraf .jupyterlite.doit.db ui-tests-app", 11 | "clean:snapshots": "rimraf -g \"test/**/*-snapshots/*.png\"", 12 | "start": "cd ui-tests-app && python -m http.server -b 127.0.0.1 8000", 13 | "test": "playwright test", 14 | "test:report": "http-server ./playwright-report -a localhost -o", 15 | "test:update": "playwright test --update-snapshots" 16 | }, 17 | "dependencies": { 18 | "@jupyterlab/galata": "~5.0.5", 19 | "@playwright/test": "^1.36.2" 20 | }, 21 | "devDependencies": { 22 | "rimraf": "^5" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/rtd-preview.yml: -------------------------------------------------------------------------------- 1 | name: RTD Preview 2 | on: 3 | pull_request_target: 4 | types: [opened] 5 | 6 | permissions: 7 | pull-requests: write 8 | 9 | jobs: 10 | binder: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Comment on the PR with the RTD preview 14 | uses: actions/github-script@v6 15 | with: 16 | github-token: ${{secrets.GITHUB_TOKEN}} 17 | script: | 18 | var PR_NUMBER = context.issue.number 19 | github.rest.issues.createComment({ 20 | issue_number: context.issue.number, 21 | owner: context.repo.owner, 22 | repo: context.repo.repo, 23 | body: `[![lite-badge](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://xeus-python-kernel--${PR_NUMBER}.org.readthedocs.build/en/${PR_NUMBER}/lite/lab/index.html) :point_left: Try it on ReadTheDocs` 24 | }) 25 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # xeus-python in JupyterLite 🚀🪐 2 | 3 | The [xeus-python](https://github.com/jupyter-xeus/xeus-python) kernel compiled to WebAssembly and installable in JupyterLite! 4 | 5 | > [!WARNING] 6 | > jupyterlite-xeus-python is DEPRECATED. 7 | > Please see {ref}`migration`. 8 | 9 | Features: 10 | 11 | - all IPython features included (magics, matplotlib inline `etc`) 12 | - code completion 13 | - code inspection 14 | - interactive widgets (ipywidgets, ipyleaflet, bqplot, ipycanvas `etc`) 15 | - JupyterLite custom file-system mounting 16 | 17 | How does it compare to the [Pyodide kernel](https://github.com/jupyterlite/pyodide-kernel) for JupyterLite? 18 | 19 | - `from time import sleep` works! 20 | - starts faster! 21 | - it's lighter by default! 22 | - pre-installed packages! No more piplite (see {ref}`configuration` page) 23 | - no more piplite, but we will be working on a mambalite, stay tuned :D 24 | 25 | ```{eval-rst} 26 | .. replite:: 27 | :kernel: xeus-python 28 | :height: 600px 29 | 30 | print("Hello from xeus-python!") 31 | ``` 32 | 33 | ```{toctree} 34 | :caption: Usage 35 | :maxdepth: 2 36 | 37 | installation 38 | deploy 39 | configuration 40 | migration 41 | changelog 42 | ``` 43 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'eslint:recommended', 4 | 'plugin:@typescript-eslint/eslint-recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:prettier/recommended' 7 | ], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { 10 | project: 'tsconfig.json', 11 | sourceType: 'module' 12 | }, 13 | plugins: ['@typescript-eslint'], 14 | rules: { 15 | '@typescript-eslint/naming-convention': [ 16 | 'error', 17 | { 18 | selector: 'interface', 19 | format: ['PascalCase'], 20 | custom: { 21 | regex: '^I[A-Z]', 22 | match: true 23 | } 24 | } 25 | ], 26 | '@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }], 27 | '@typescript-eslint/no-explicit-any': 'off', 28 | '@typescript-eslint/no-namespace': 'off', 29 | '@typescript-eslint/no-use-before-define': 'off', 30 | '@typescript-eslint/no-empty-interface': 'off', 31 | '@typescript-eslint/quotes': [ 32 | 'error', 33 | 'single', 34 | { avoidEscape: true, allowTemplateLiterals: false } 35 | ], 36 | curly: ['error', 'all'], 37 | eqeqeq: 'error', 38 | 'prefer-arrow-callback': 'error' 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /.github/workflows/prep-release.yml: -------------------------------------------------------------------------------- 1 | name: "Step 1: Prep Release" 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version_spec: 6 | description: "New Version Specifier" 7 | default: "next" 8 | required: false 9 | branch: 10 | description: "The branch to target" 11 | required: false 12 | post_version_spec: 13 | description: "Post Version Specifier" 14 | required: false 15 | since: 16 | description: "Use PRs with activity since this date or git reference" 17 | required: false 18 | since_last_stable: 19 | description: "Use PRs with activity since the last stable git tag" 20 | required: false 21 | type: boolean 22 | jobs: 23 | prep_release: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 27 | 28 | - name: Prep Release 29 | id: prep-release 30 | uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2 31 | with: 32 | token: ${{ secrets.ADMIN_GITHUB_TOKEN }} 33 | version_spec: ${{ github.event.inputs.version_spec }} 34 | post_version_spec: ${{ github.event.inputs.post_version_spec }} 35 | target: ${{ github.event.inputs.target }} 36 | branch: ${{ github.event.inputs.branch }} 37 | since: ${{ github.event.inputs.since }} 38 | since_last_stable: ${{ github.event.inputs.since_last_stable }} 39 | 40 | - name: "** Next Step **" 41 | run: | 42 | echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}" 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Thorsten Beier 4 | Copyright (c) 2021-2023, JupyterLite Contributors 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: "Step 2: Publish Release" 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | branch: 6 | description: "The target branch" 7 | required: false 8 | release_url: 9 | description: "The URL of the draft GitHub release" 10 | required: false 11 | steps_to_skip: 12 | description: "Comma separated list of steps to skip" 13 | required: false 14 | 15 | jobs: 16 | publish_release: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 20 | 21 | - name: Populate Release 22 | id: populate-release 23 | uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2 24 | with: 25 | token: ${{ secrets.ADMIN_GITHUB_TOKEN }} 26 | target: ${{ github.event.inputs.target }} 27 | branch: ${{ github.event.inputs.branch }} 28 | release_url: ${{ github.event.inputs.release_url }} 29 | steps_to_skip: ${{ github.event.inputs.steps_to_skip }} 30 | 31 | - name: Finalize Release 32 | id: finalize-release 33 | env: 34 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} 35 | PYPI_TOKEN_MAP: ${{ secrets.PYPI_TOKEN_MAP }} 36 | TWINE_USERNAME: __token__ 37 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 38 | uses: jupyter-server/jupyter-releaser/.github/actions/finalize-release@v2 39 | with: 40 | token: ${{ secrets.ADMIN_GITHUB_TOKEN }} 41 | target: ${{ github.event.inputs.target }} 42 | release_url: ${{ steps.populate-release.outputs.release_url }} 43 | 44 | - name: "** Next Step **" 45 | if: ${{ success() }} 46 | run: | 47 | echo "Verify the final release" 48 | echo ${{ steps.finalize-release.outputs.release_url }} 49 | 50 | - name: "** Failure Message **" 51 | if: ${{ failure() }} 52 | run: | 53 | echo "Failed to Publish the Draft Release Url:" 54 | echo ${{ steps.populate-release.outputs.release_url }} 55 | -------------------------------------------------------------------------------- /.github/workflows/playwright-update.yml: -------------------------------------------------------------------------------- 1 | name: Update Playwright Snapshots 2 | 3 | on: 4 | issue_comment: 5 | types: [created, edited] 6 | 7 | permissions: 8 | contents: write 9 | pull-requests: write 10 | 11 | jobs: 12 | update-snapshots: 13 | if: 14 | ${{ github.event.issue.pull_request && contains(github.event.comment.body, 'update 15 | playwright snapshots') }} 16 | runs-on: ubuntu-latest 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | browser: [firefox, chromium] 21 | 22 | steps: 23 | - name: React to the triggering comment 24 | run: | 25 | gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions --raw-field 'content=+1' 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | 32 | - name: Checkout the branch from the PR that triggered the job 33 | run: | 34 | # PR branch remote must be checked out using https URL 35 | git config --global hub.protocol https 36 | 37 | gh pr checkout ${{ github.event.issue.number }} 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | 41 | - name: Base Setup 42 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 43 | 44 | - name: Build 45 | run: | 46 | # TODO: install addon 47 | 48 | # disable git hooks 49 | git config core.hooksPath no-hooks 50 | 51 | - name: Install the test dependencies 52 | run: | 53 | cd ui-tests 54 | jlpm 55 | jlpm build 56 | jlpm playwright install 57 | 58 | - name: Update snapshots 59 | uses: jupyterlab/maintainer-tools/.github/actions/update-snapshots@v1 60 | with: 61 | github_token: ${{ secrets.GITHUB_TOKEN }} 62 | npm_client: jlpm 63 | test_folder: ui-tests 64 | start_server_script: 'null' 65 | update_script: test:update --browser ${{ matrix.browser }} 66 | env: 67 | DEBUG: pw:webserver 68 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Thorsten Beier 2 | // Copyright (c) JupyterLite Contributors 3 | // Distributed under the terms of the Modified BSD License. 4 | 5 | import { 6 | IServiceWorkerManager, 7 | JupyterLiteServer, 8 | JupyterLiteServerPlugin 9 | } from '@jupyterlite/server'; 10 | import { IBroadcastChannelWrapper } from '@jupyterlite/contents'; 11 | import { IKernel, IKernelSpecs } from '@jupyterlite/kernel'; 12 | 13 | import { WebWorkerKernel } from './web_worker_kernel'; 14 | 15 | import logo32 from '!!file-loader?context=.!../style/logos/python-logo-32x32.png'; 16 | import logo64 from '!!file-loader?context=.!../style/logos/python-logo-64x64.png'; 17 | 18 | const server_kernel: JupyterLiteServerPlugin = { 19 | id: '@jupyterlite/xeus-python-kernel-extension:kernel', 20 | autoStart: true, 21 | requires: [IKernelSpecs], 22 | optional: [IServiceWorkerManager, IBroadcastChannelWrapper], 23 | activate: ( 24 | app: JupyterLiteServer, 25 | kernelspecs: IKernelSpecs, 26 | serviceWorker?: IServiceWorkerManager, 27 | broadcastChannel?: IBroadcastChannelWrapper 28 | ) => { 29 | kernelspecs.register({ 30 | spec: { 31 | name: 'xeus-python', 32 | display_name: 'Python (XPython)', 33 | language: 'python', 34 | argv: [], 35 | resources: { 36 | 'logo-32x32': logo32, 37 | 'logo-64x64': logo64 38 | } 39 | }, 40 | create: async (options: IKernel.IOptions): Promise => { 41 | const mountDrive = !!( 42 | serviceWorker?.enabled && broadcastChannel?.enabled 43 | ); 44 | 45 | if (mountDrive) { 46 | console.info( 47 | 'xeus-python contents will be synced with Jupyter Contents' 48 | ); 49 | } else { 50 | console.warn( 51 | 'xeus-python contents will NOT be synced with Jupyter Contents' 52 | ); 53 | } 54 | 55 | return new WebWorkerKernel({ 56 | ...options, 57 | mountDrive 58 | }); 59 | } 60 | }); 61 | } 62 | }; 63 | 64 | const plugins: JupyterLiteServerPlugin[] = [server_kernel]; 65 | 66 | export default plugins; 67 | -------------------------------------------------------------------------------- /ui-tests/test/files.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) JupyterLite Contributors 2 | // Distributed under the terms of the Modified BSD License. 3 | 4 | import { test } from '@jupyterlab/galata'; 5 | 6 | import { expect } from '@playwright/test'; 7 | 8 | import { firefoxWaitForApplication } from './utils'; 9 | 10 | test.use({ waitForApplication: firefoxWaitForApplication }); 11 | 12 | test.describe('File system', () => { 13 | test.beforeEach(async ({ page }) => { 14 | await page.goto('lab/index.html'); 15 | }); 16 | 17 | // this test can take a while due to the time take to type the inputs 18 | test.setTimeout(60000 * 3); 19 | 20 | test('Create files from the notebook and open them in JupyterLab', async ({ 21 | page 22 | }) => { 23 | const notebook = await page.notebook.createNew(); 24 | if (!notebook) { 25 | throw new Error('Notebook could not be created'); 26 | } 27 | 28 | // add cells for manipulating files 29 | const filename = 'test.txt'; 30 | const content = 'Hello, world!'; 31 | await page.notebook.setCell(0, 'code', 'import os\nos.listdir()'); 32 | await page.notebook.addCell('code', 'from pathlib import Path'); 33 | await page.notebook.addCell('code', `p = Path("${filename}")`); 34 | await page.notebook.addCell('code', `p.write_text("${content}")`); 35 | await page.notebook.addCell('code', 'p.exists()'); 36 | await page.notebook.addCell('code', 'os.listdir()'); 37 | 38 | // execute the cells 39 | await page.notebook.run(); 40 | 41 | // the first cell output should contain the name of the notebook 42 | const output = await page.notebook.getCellTextOutput(0); 43 | expect(output).toBeTruthy(); 44 | expect(output![0]).toContain(notebook); 45 | 46 | // the last cell output should contain the name of the created file 47 | const output2 = await page.notebook.getCellTextOutput(5); 48 | expect(output2).toBeTruthy(); 49 | expect(output2![0]).toContain(filename); 50 | 51 | await page.notebook.close(); 52 | 53 | // open the created file from the file browser 54 | await page.waitForSelector(`.jp-DirListing-content >> text="${filename}"`); 55 | await page.filebrowser.open(filename); 56 | 57 | // check the file contents 58 | const line = await page 59 | .locator(`.jp-FileEditor .cm-line >> text="${content}"`) 60 | .innerText(); 61 | expect(line).toBe(content); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /docs/migration.md: -------------------------------------------------------------------------------- 1 | (migration)= 2 | 3 | # **jupyterlite-xeus-python** deprecation 4 | 5 | **jupyterlite-xeus-python** is being deprecated over [jupyterlite-xeus](https://github.com/jupyterlite/xeus) as of January 2024, you will find in this page migration steps to this new package. 6 | 7 | **jupyterlite-xeus** is a generalized approach of installing xeus-based kernels into a JupyterLite deployment. Using this new library, the main entry point is an `environment.yml` file, specifying your kernel environment including kernels and runtime dependencies. 8 | 9 | Example of an `environment.yml`: 10 | 11 | ```yml 12 | name: my-jupyterlite-env 13 | channels: 14 | - https://repo.mamba.pm/emscripten-forge 15 | - conda-forge 16 | dependencies: 17 | - xeus-python 18 | - xeus-lua 19 | - numpy 20 | - matplotlib 21 | - pip: 22 | - ipywidgets 23 | ``` 24 | 25 | # Migrating to **jupyterlite-xeus** 26 | 27 | ## Base setup 28 | 29 | Considering you have a simple setup where you install **jupyterlite-xeus-python** and have an **environment.yml** file with your dependencies: 30 | 31 | You will now need to install **jupyterlite-xeus** in your build environment instead of **jupyterlite-xeus-python**, and the diff for your **environment.yml** should look like the following (adding **xeus-python** explicitely in the runtime): 32 | 33 | ```diff 34 | name: my-jupyterlite-env 35 | channels: 36 | - https://repo.mamba.pm/emscripten-forge 37 | - conda-forge 38 | dependencies: 39 | + - xeus-python 40 | - numpy 41 | - matplotlib 42 | ``` 43 | 44 | See https://github.com/jupyterlite/xeus-python-demo for a deployment using **jupyterlite-xeus**. 45 | 46 | ## CLI options 47 | 48 | Considering you are using more options from **jupyterlite-xeus-python** like **empack_config**: 49 | 50 | - The **xeus_python_version** option is removed, you need to specify the xeus-python version you need in your **environment.yml** file 51 | - The **empack_config** option is still supported: `jupyter lite build --XeusPythonEnv.empack_config=./file.yml` becomes `jupyter lite build --XeusAddon.empack_config=./file.yml` 52 | - The **pin_packages** option is removed. 53 | - The **packages** option is removed, you need to specify your dependencies in **environment.yml** only 54 | - The **environment_file** is still supported: `jupyter lite build --XeusPythonEnv.environment_file=./file.yml` becomes `jupyter lite build --XeusAddon.environment_file=./file.yml`. Defaults to **environment.yml**. 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bundle.* 2 | lib/ 3 | node_modules/ 4 | *.egg-info/ 5 | .ipynb_checkpoints 6 | *.tsbuildinfo 7 | /*.tar.gz 8 | # Created by https://www.gitignore.io/api/python 9 | # Edit at https://www.gitignore.io/?templates=python 10 | 11 | ### Python ### 12 | # Byte-compiled / optimized / DLL files 13 | __pycache__/ 14 | *.py[cod] 15 | *$py.class 16 | 17 | # C extensions 18 | *.so 19 | 20 | # Distribution / packaging 21 | .Python 22 | build/ 23 | develop-eggs/ 24 | dist/ 25 | downloads/ 26 | eggs/ 27 | .eggs/ 28 | lib/ 29 | lib64/ 30 | parts/ 31 | sdist/ 32 | var/ 33 | wheels/ 34 | pip-wheel-metadata/ 35 | share/python-wheels/ 36 | .installed.cfg 37 | *.egg 38 | MANIFEST 39 | 40 | # PyInstaller 41 | # Usually these files are written by a python script from a template 42 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 43 | *.manifest 44 | *.spec 45 | 46 | # Installer logs 47 | pip-log.txt 48 | pip-delete-this-directory.txt 49 | 50 | # Unit test / coverage reports 51 | htmlcov/ 52 | .tox/ 53 | .nox/ 54 | .coverage 55 | .coverage.* 56 | .cache 57 | nosetests.xml 58 | coverage.xml 59 | *.cover 60 | .hypothesis/ 61 | .pytest_cache/ 62 | 63 | # Translations 64 | *.mo 65 | *.pot 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | .spyproject 88 | 89 | # Rope project settings 90 | .ropeproject 91 | 92 | # Mr Developer 93 | .mr.developer.cfg 94 | .project 95 | .pydevproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | .dmypy.json 103 | dmypy.json 104 | 105 | # Pyre type checker 106 | .pyre/ 107 | 108 | # End of https://www.gitignore.io/api/python 109 | 110 | # OSX files 111 | .DS_Store 112 | 113 | _output 114 | *.doit.db 115 | 116 | # Generated files 117 | src/python_data.js 118 | src/*.data 119 | src/*.js 120 | src/xpython_wasm.js 121 | src/xpython_wasm.wasm 122 | src/xpython_wasm.hash 123 | src/worker.ts 124 | src/web_worker_kernel.ts 125 | src/*.tar.gz 126 | src/empack_env_meta.json 127 | *.js.map 128 | 129 | # Labextension 130 | jupyterlite_xeus_python/labextension 131 | 132 | # Version file is handled by hatchling 133 | jupyterlite_xeus_python/_version.py 134 | 135 | # venv 136 | .venv 137 | 138 | # Yarn 3 139 | .pnp* 140 | .yarn 141 | 142 | # UI tests 143 | ui-tests/playwright-report 144 | ui-tests/test-results 145 | ui-tests/ui-tests-app 146 | 147 | # Lint 148 | .eslintcache 149 | .stylelintcache 150 | -------------------------------------------------------------------------------- /.github/workflows/ui-tests.yml: -------------------------------------------------------------------------------- 1 | name: UI Tests 2 | 3 | on: [push, pull_request] 4 | 5 | defaults: 6 | run: 7 | shell: bash -l {0} 8 | 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Install Conda environment with Micromamba 19 | uses: mamba-org/setup-micromamba@v1 20 | with: 21 | micromamba-version: '1.5.1-0' 22 | environment-file: environment.yml 23 | cache-environment: true 24 | 25 | - name: Install jupyterlite-xeus-python 26 | run: | 27 | jlpm 28 | jlpm run build 29 | python -m pip install -v . 30 | 31 | - name: Build UI tests 32 | run: | 33 | cd ui-tests 34 | jlpm 35 | # Build the JupyterLite website 36 | jlpm build 37 | 38 | - name: Upload the JupyterLite website 39 | uses: actions/upload-artifact@v3 40 | with: 41 | name: jupyterlite-xeus-python-ui-tests-app-${{ github.run_number }} 42 | path: ./ui-tests/ui-tests-app 43 | 44 | ui-tests: 45 | needs: [build] 46 | name: Visual Regression 47 | runs-on: ubuntu-latest 48 | strategy: 49 | fail-fast: false 50 | matrix: 51 | browser: [firefox, chromium] 52 | steps: 53 | - name: Checkout 54 | uses: actions/checkout@v4 55 | 56 | - uses: actions/download-artifact@v3 57 | with: 58 | name: jupyterlite-xeus-python-ui-tests-app-${{ github.run_number }} 59 | path: ./ui-tests/ui-tests-app 60 | 61 | - name: Base Setup 62 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 63 | 64 | - name: Install dependencies and browser 65 | run: | 66 | # Install JupyterLab to get jlpm 67 | python -m pip install jupyterlab~=4.0 68 | cd ui-tests 69 | jlpm 70 | jlpm playwright install ${{ matrix.browser }} --with-deps 71 | 72 | - name: Test 73 | run: | 74 | cd ui-tests 75 | jlpm run test --browser ${{ matrix.browser }} 76 | 77 | - name: Upload Playwright Test assets 78 | if: always() 79 | uses: actions/upload-artifact@v3 80 | with: 81 | name: jupyterlite-xeux-python-${{ matrix.browser }}-test-assets 82 | path: | 83 | ui-tests/test-results 84 | 85 | - name: Upload Playwright Test report 86 | if: always() 87 | uses: actions/upload-artifact@v3 88 | with: 89 | name: jupyterlite-xeus-python-${{ matrix.browser }}-test-report 90 | path: | 91 | ui-tests/playwright-report 92 | 93 | - name: Update snapshots 94 | if: failure() 95 | run: | 96 | cd ui-tests 97 | # remove previous snapshots from other browser 98 | jlpm run clean:snapshots 99 | # generate new snapshots 100 | jlpm run test:update --browser ${{ matrix.browser }} 101 | 102 | - name: Upload updated snapshots 103 | if: failure() 104 | uses: actions/upload-artifact@v3 105 | with: 106 | name: jupyterlite-xeus-python-${{ matrix.browser }}-updated-snapshots 107 | path: ui-tests/test 108 | -------------------------------------------------------------------------------- /tests/test_xeus_python_env.py: -------------------------------------------------------------------------------- 1 | """Test creating Python envs for jupyterlite-xeus-python.""" 2 | 3 | import os 4 | from pathlib import Path 5 | 6 | import pytest 7 | from jupyterlite_core.app import LiteStatusApp 8 | 9 | from jupyterlite_xeus_python.env_build_addon import XeusPythonEnv 10 | 11 | 12 | def test_python_env(): 13 | app = LiteStatusApp(log_level="DEBUG") 14 | app.initialize() 15 | manager = app.lite_manager 16 | 17 | addon = XeusPythonEnv(manager) 18 | addon.packages = ["numpy", "ipyleaflet"] 19 | 20 | for _step in addon.post_build(manager): 21 | pass 22 | 23 | # Check env 24 | assert os.path.isdir("/tmp/xeus-python-kernel/envs/xeus-python-kernel") 25 | 26 | assert os.path.isfile("/tmp/xeus-python-kernel/envs/xeus-python-kernel/bin/xpython_wasm.js") 27 | assert os.path.isfile("/tmp/xeus-python-kernel/envs/xeus-python-kernel/bin/xpython_wasm.wasm") 28 | 29 | # Check empack output 30 | assert os.path.isfile(Path(addon.cwd.name) / "empack_env_meta.json") 31 | 32 | os.remove(Path(addon.cwd.name) / "empack_env_meta.json") 33 | 34 | 35 | def test_python_env_from_file_1(): 36 | app = LiteStatusApp(log_level="DEBUG") 37 | app.initialize() 38 | manager = app.lite_manager 39 | 40 | addon = XeusPythonEnv(manager) 41 | addon.environment_file = "environment-1.yml" 42 | 43 | for _step in addon.post_build(manager): 44 | pass 45 | 46 | # Check env 47 | assert os.path.isdir("/tmp/xeus-python-kernel/envs/xeus-python-kernel-1") 48 | 49 | assert os.path.isfile("/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/bin/xpython_wasm.js") 50 | assert os.path.isfile("/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/bin/xpython_wasm.wasm") 51 | 52 | # Checking pip packages 53 | assert os.path.isdir("/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/lib/python3.11") 54 | assert os.path.isdir( 55 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/lib/python3.11/site-packages" 56 | ) 57 | assert os.path.isdir( 58 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/lib/python3.11/site-packages/ipywidgets" 59 | ) 60 | assert os.path.isdir( 61 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/lib/python3.11/site-packages/ipycanvas" 62 | ) 63 | assert os.path.isdir( 64 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/lib/python3.11/site-packages/py2vega" 65 | ) 66 | 67 | # Checking labextensions 68 | assert os.path.isdir( 69 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/share/jupyter/labextensions/@jupyter-widgets/jupyterlab-manager" 70 | ) 71 | assert os.path.isdir( 72 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-1/share/jupyter/labextensions/ipycanvas" 73 | ) 74 | 75 | # Check empack output 76 | assert os.path.isfile(Path(addon.cwd.name) / "empack_env_meta.json") 77 | 78 | os.remove(Path(addon.cwd.name) / "empack_env_meta.json") 79 | 80 | 81 | def test_python_env_from_file_3(): 82 | app = LiteStatusApp(log_level="DEBUG") 83 | app.initialize() 84 | manager = app.lite_manager 85 | 86 | addon = XeusPythonEnv(manager) 87 | addon.environment_file = "test_package/environment-3.yml" 88 | 89 | for _step in addon.post_build(manager): 90 | pass 91 | 92 | # Test 93 | assert os.path.isdir( 94 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-3/lib/python3.11/site-packages/test_package" 95 | ) 96 | assert os.path.isfile( 97 | "/tmp/xeus-python-kernel/envs/xeus-python-kernel-3/lib/python3.11/site-packages/test_package/hey.py" 98 | ) 99 | 100 | os.remove(Path(addon.cwd.name) / "empack_env_meta.json") 101 | 102 | 103 | def test_python_env_from_file_2(): 104 | app = LiteStatusApp(log_level="DEBUG") 105 | app.initialize() 106 | manager = app.lite_manager 107 | 108 | addon = XeusPythonEnv(manager) 109 | addon.environment_file = "environment-2.yml" 110 | 111 | with pytest.raises(RuntimeError, match="Cannot install binary PyPI package"): 112 | for _step in addon.post_build(manager): 113 | pass 114 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | (configuration)= 2 | 3 | # Configuration 4 | 5 | ## Pre-installed packages 6 | 7 | `xeus-python` allows you to pre-install packages in the Python runtime. You can pre-install packages by adding an `environment.yml` file in the JupyterLite build directory, this file will be found automatically by xeus-python which will pre-build the environment when running `jupyter lite build`. 8 | 9 | Furthermore, this automatically installs any labextension that it founds, for example installing ipyleaflet will make ipyleaflet work without the need to manually install the jupyter-leaflet labextension. 10 | 11 | Say you want to install `NumPy`, `Matplotlib` and `ipycanvas`, it can be done by creating the `environment.yml` file with the following content: 12 | 13 | ```yaml 14 | name: xeus-python-kernel 15 | channels: 16 | - https://repo.mamba.pm/emscripten-forge 17 | - conda-forge 18 | dependencies: 19 | - numpy 20 | - matplotlib 21 | - ipycanvas 22 | ``` 23 | 24 | Then you only need to build JupyterLite: 25 | 26 | ``` 27 | jupyter lite build 28 | ``` 29 | 30 | You can also pick another name for that environment file (_e.g._ `custom.yml`), by doing so, you will need to specify that name to xeus-python: 31 | 32 | ``` 33 | jupyter lite build --XeusPythonEnv.environment_file=custom.yml 34 | ``` 35 | 36 | ```{warning} 37 | It is common to provide `pip` dependencies in a conda environment file. This is currently **partially supported** by xeus-python. See "pip packages" section. 38 | ``` 39 | 40 | Then those packages are usable directly: 41 | 42 | ```{eval-rst} 43 | .. replite:: 44 | :kernel: xeus-python 45 | :height: 600px 46 | :prompt: Try it! 47 | 48 | %matplotlib inline 49 | 50 | import matplotlib.pyplot as plt 51 | import numpy as np 52 | 53 | fig = plt.figure() 54 | plt.plot(np.sin(np.linspace(0, 20, 100))) 55 | plt.show(); 56 | ``` 57 | 58 | ### pip packages 59 | 60 | ⚠ This feature is experimental. You won't have the same user-experience as when using conda/mamba in a "normal" setup ⚠ 61 | 62 | `xeus-python` provides a way to install packages with pip. 63 | 64 | There are a couple of limitations that you should be aware of: 65 | 66 | - it can **only** install **pure Python packages** (Python code + data files) 67 | - it **does not install the package dependencies**, you should make sure to install them yourself using conda-forge/emscripten-forge. 68 | - it does not work (yet?) using `-r requirements.txt` in your environment file 69 | 70 | For example, if you were to install `ipycanvas` from PyPI, you would need to install the ipycanvas dependencies for it to work (`pillow`, `numpy` and `ipywidgets`): 71 | 72 | ```yaml 73 | name: xeus-python-kernel 74 | channels: 75 | - https://repo.mamba.pm/emscripten-forge 76 | - conda-forge 77 | dependencies: 78 | - numpy 79 | - pillow 80 | - ipywidgets 81 | - pip: 82 | - ipycanvas 83 | ``` 84 | 85 | You can also install a local Python package, this is very practical if you want to embed 86 | a jupyterlite deployment in your Package documentation, allowing to test the very latest dev version: 87 | 88 | ```yaml 89 | name: xeus-python-kernel 90 | channels: 91 | - https://repo.mamba.pm/emscripten-forge 92 | - conda-forge 93 | dependencies: 94 | - pip: 95 | - .. 96 | ``` 97 | 98 | ## Advanced Configuration 99 | 100 | ```{warning} 101 | This section is mostly for reference and should not be needed for regular use of the `jupyterlite-xeus-python` kernel. 102 | ``` 103 | 104 | ### Provide a custom `empack_config.yaml` 105 | 106 | Packages sometimes ship more data than needed for the package to work (tests, documentation, data files etc). This is fine on a regular installation of the package, but in the emscripten case when running in the browser this means that starting the kernel would download more files. 107 | For this reason, `empack` filters out anything that is not required for the Python code to run. It does it by following a set of filtering rules available in this file: https://github.com/emscripten-forge/empack/blob/main/config/empack_config.yaml. 108 | 109 | But this default filtering could break some packages. In that case you would probably want to either contribute to the default empack config, or provide your own set of filtering rules. 110 | 111 | The xeus-python kernel supports passing a custom `empack_config.yaml`. This file can be used to override the default filter rules set by the underlying `empack` tool used for packing the environment. 112 | 113 | If you would like to provide additional rules for including or excluding files in the packed environment, create a `empack_config.yaml` with the following content as an example: 114 | 115 | ```yaml 116 | packages: 117 | xarray: 118 | include_patterns: 119 | - pattern: '**/*.py' 120 | - pattern: '**/static/css/*.css' 121 | - pattern: '**/static/html/*.html' 122 | ``` 123 | 124 | This example defines a set of custom rules for the `xarray` package to make sure it includes some static files that should be available from the kernel. 125 | 126 | You can use this file when building JupyterLite: 127 | 128 | ```shell 129 | jupyter lite build --XeusPythonEnv.empack_config=empack_config.yaml 130 | ``` 131 | 132 | ```{note} 133 | Filtering files helps reduce the size of the assets to download and as a consequence reduce network traffic. 134 | ``` 135 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["hatchling>=1.5.0", "jupyterlab>=4.0.0,<5", "empack>=3.0,<4", "hatch-nodejs-version>=0.3.2"] 3 | build-backend = "hatchling.build" 4 | 5 | [project] 6 | name = "jupyterlite-xeus-python" 7 | readme = "README.md" 8 | license = { file = "LICENSE" } 9 | requires-python = ">=3.8" 10 | classifiers = [ 11 | "Framework :: Jupyter", 12 | "Framework :: Jupyter :: JupyterLab", 13 | "Framework :: Jupyter :: JupyterLab :: 4", 14 | "Framework :: Jupyter :: JupyterLab :: Extensions", 15 | "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt", 16 | "License :: OSI Approved :: BSD License", 17 | "Programming Language :: Python", 18 | "Programming Language :: Python :: 3", 19 | "Programming Language :: Python :: 3.8", 20 | "Programming Language :: Python :: 3.9", 21 | "Programming Language :: Python :: 3.10", 22 | "Programming Language :: Python :: 3.11", 23 | ] 24 | dependencies = [ 25 | "traitlets", 26 | "jupyterlite-core>=0.2.0rc0,<0.3", 27 | "requests", 28 | "empack>=3.1,<4", 29 | "typer", 30 | ] 31 | dynamic = ["version", "description", "authors", "urls", "keywords"] 32 | 33 | [project.optional-dependencies] 34 | dev = [ 35 | "black", 36 | "ruff==0.0.292", 37 | ] 38 | 39 | [project.scripts] 40 | jupyterlite-xeus-python-build = "jupyterlite_xeus_python.build:start" 41 | 42 | [project.entry-points."jupyterlite.addon.v0"] 43 | jupyterlite-xeus-python = "jupyterlite_xeus_python.env_build_addon:XeusPythonEnv" 44 | 45 | [tool.hatch.version] 46 | source = "nodejs" 47 | 48 | [tool.hatch.metadata.hooks.nodejs] 49 | fields = ["description", "authors", "urls"] 50 | 51 | [tool.hatch.build.targets.sdist] 52 | artifacts = ["jupyterlite_xeus_python/labextension"] 53 | exclude = [".github"] 54 | 55 | [tool.hatch.build.targets.wheel.shared-data] 56 | "jupyterlite_xeus_python/labextension" = "share/jupyter/labextensions/@jupyterlite/xeus-python-kernel" 57 | "install.json" = "share/jupyter/labextensions/@jupyterlite/xeus-python-kernel/install.json" 58 | 59 | [tool.hatch.build.hooks.version] 60 | path = "jupyterlite_xeus_python/_version.py" 61 | 62 | [tool.hatch.build.hooks.jupyter-builder] 63 | dependencies = ["hatch-jupyter-builder>=0.5"] 64 | build-function = "hatch_jupyter_builder.npm_builder" 65 | ensured-targets = [ 66 | "jupyterlite_xeus_python/labextension/static/style.js", 67 | "jupyterlite_xeus_python/labextension/static/empack_env_meta.json", 68 | "jupyterlite_xeus_python/labextension/static/xpython_wasm.js", 69 | "jupyterlite_xeus_python/labextension/static/xpython_wasm.wasm", 70 | "jupyterlite_xeus_python/labextension/package.json", 71 | ] 72 | skip-if-exists = [ 73 | "jupyterlite_xeus_python/labextension/static/style.js", 74 | "jupyterlite_xeus_python/labextension/static/empack_env_meta.json", 75 | "jupyterlite_xeus_python/labextension/static/xpython_wasm.js", 76 | "jupyterlite_xeus_python/labextension/static/xpython_wasm.wasm", 77 | "jupyterlite_xeus_python/labextension/package.json", 78 | ] 79 | 80 | [tool.hatch.build.hooks.jupyter-builder.build-kwargs] 81 | build_cmd = "build:prod" 82 | npm = ["jlpm"] 83 | source_dir = "src" 84 | build_dir = "jupyterlite_xeus_python/labextension" 85 | 86 | [tool.hatch.build.hooks.jupyter-builder.editable-build-kwargs] 87 | build_cmd = "install:extension" 88 | npm = ["jlpm"] 89 | source_dir = "src" 90 | build_dir = "jupyterlite_xeus_python/labextension" 91 | 92 | [tool.jupyter-releaser.options] 93 | version_cmd = "hatch version" 94 | 95 | [tool.jupyter-releaser.hooks] 96 | before-build-npm = [ 97 | "python -m pip install 'jupyterlab>=4.0.0,<5' empack~=3.0", 98 | "jlpm", 99 | "jlpm build:prod" 100 | ] 101 | before-build-python = ["jlpm clean:all"] 102 | 103 | [tool.check-wheel-contents] 104 | ignore = ["W002"] 105 | 106 | [tool.black] 107 | line-length = 100 108 | target-version = ["py38"] 109 | 110 | [tool.ruff] 111 | target-version = "py38" 112 | exclude = [ 113 | "*/tests/*", 114 | "docs", 115 | ] 116 | line-length = 100 117 | select = [ 118 | "A", "B", "C", "DTZ", "E", "EM", "F", "FBT", "I", "ICN", "ISC", "N", 119 | "PLC", "PLE", "PLR", "PLW", "Q", "RUF", "S", "SIM", "T", "TID", "UP", 120 | "W", "YTT", 121 | ] 122 | ignore = [ 123 | "D100", 124 | "D104", 125 | # Q000 Single quotes found but double quotes preferred 126 | "Q000", 127 | # FBT001 Boolean positional arg in function definition 128 | "FBT001", "FBT002", "FBT003", 129 | # C408 Unnecessary `dict` call (rewrite as a literal) 130 | "C408", "C416", 131 | # allow for using print() 132 | "T201", 133 | # PLR0913 Too many arguments to function call 134 | "PLR0913", 135 | # extended flake8 ignore 136 | "D104", "D100", "EM101", 137 | # Probable insecure usage of temporary file or directory 138 | "S108", 139 | # RUF012 Mutable class attributes should be annotated with `typing.ClassVar` 140 | "RUF012", 141 | ] 142 | 143 | [tool.ruff.per-file-ignores] 144 | # S101 Use of `assert` detected 145 | # F841 Local variable `foo` is assigned to but never used 146 | # PLR2004 Magic value used in comparison 147 | "tests/*" = ["S101", "F841", "PLR2004"] 148 | 149 | # B008 Do not perform function call `typer.Option` in argument defaults 150 | # E501 Line too long 151 | # S603 `subprocess` call: check for execution of untrusted input 152 | "jupyterlite_xeus_python/build.py" = ["B008", "E501", "S603"] 153 | 154 | # E501 Line too long 155 | # S602 `subprocess` call with `shell=True` identified, security issue 156 | "ui-tests/build.py" = ["E501", "S602"] 157 | -------------------------------------------------------------------------------- /jupyterlite_xeus_python/env_build_addon.py: -------------------------------------------------------------------------------- 1 | """a JupyterLite addon for creating the env for xeus-python""" 2 | import json 3 | import os 4 | from pathlib import Path 5 | from tempfile import TemporaryDirectory 6 | 7 | from jupyterlite_core.addons.federated_extensions import FederatedExtensionAddon 8 | from jupyterlite_core.constants import ( 9 | FEDERATED_EXTENSIONS, 10 | JUPYTERLITE_JSON, 11 | LAB_EXTENSIONS, 12 | SHARE_LABEXTENSIONS, 13 | UTF8, 14 | ) 15 | from traitlets import List, Unicode 16 | 17 | from .build import XEUS_PYTHON_VERSION, build_and_pack_emscripten_env 18 | 19 | JUPYTERLITE_XEUS_PYTHON = "@jupyterlite/xeus-python-kernel" 20 | 21 | 22 | class PackagesList(List): 23 | def from_string(self, s): 24 | return s.split(",") 25 | 26 | 27 | class XeusPythonEnv(FederatedExtensionAddon): 28 | __all__ = ["post_build"] 29 | 30 | xeus_python_version = Unicode(XEUS_PYTHON_VERSION).tag( 31 | config=True, description="The xeus-python version to use" 32 | ) 33 | 34 | empack_config = Unicode( 35 | "", 36 | config=True, 37 | description="The path or URL to the empack config file", 38 | ) 39 | 40 | pin_packages = PackagesList([]).tag( 41 | description="This property is not supposed to be used, unless you know what you're doing.", 42 | ) 43 | 44 | packages = PackagesList([]).tag( 45 | config=True, 46 | description="A comma-separated list of packages to install in the xeus-python env", 47 | ) 48 | 49 | environment_file = Unicode( 50 | "environment.yml", 51 | config=True, 52 | description='The path to the environment file. Defaults to "environment.yml"', 53 | ) 54 | 55 | def __init__(self, *args, **kwargs): 56 | super().__init__(*args, **kwargs) 57 | 58 | self.cwd = TemporaryDirectory() 59 | 60 | def post_build(self, manager): 61 | """yield a doit task to create the emscripten-32 env and grab anything we need from it""" 62 | # Install the jupyterlite-xeus-python ourselves 63 | for pkg_json in self.env_extensions(self.labextensions_path): 64 | pkg_data = json.loads(pkg_json.read_text(**UTF8)) 65 | if pkg_data.get("name") == JUPYTERLITE_XEUS_PYTHON: 66 | yield from self.safe_copy_extension(pkg_json) 67 | 68 | env_prefix = build_and_pack_emscripten_env( 69 | xeus_python_version=self.xeus_python_version, 70 | packages=[*self.packages, *self.pin_packages], 71 | environment_file=Path(self.manager.lite_dir) / self.environment_file, 72 | empack_config=self.empack_config, 73 | output_path=self.cwd.name, 74 | log=self.log, 75 | ) 76 | 77 | # Find the federated extensions in the emscripten-env and install them 78 | for pkg_json in self.env_extensions(env_prefix / SHARE_LABEXTENSIONS): 79 | yield from self.safe_copy_extension(pkg_json) 80 | 81 | # TODO Currently we're shamelessly overwriting the 82 | # python_data.{js,data} into the jupyterlite-xeus-python labextension. 83 | # We should really find a nicer way. 84 | # (make jupyterlite-xeus-python extension somewhat configurable?) 85 | dest = self.output_extensions / "@jupyterlite" / "xeus-python-kernel" / "static" 86 | 87 | # copy *.tar.gz for all side packages 88 | for item in Path(self.cwd.name).iterdir(): 89 | if item.suffix == ".gz": 90 | file = item.name 91 | yield dict( 92 | name=f"xeus:copy:{file}", 93 | actions=[(self.copy_one, [item, dest / file])], 94 | ) 95 | 96 | for file in [ 97 | "empack_env_meta.json", 98 | "xpython_wasm.js", 99 | "xpython_wasm.wasm", 100 | ]: 101 | yield dict( 102 | name=f"xeus:copy:{file}", 103 | actions=[(self.copy_one, [Path(self.cwd.name) / file, dest / file])], 104 | ) 105 | 106 | jupyterlite_json = manager.output_dir / JUPYTERLITE_JSON 107 | lab_extensions_root = manager.output_dir / LAB_EXTENSIONS 108 | lab_extensions = self.env_extensions(lab_extensions_root) 109 | 110 | yield dict( 111 | name="patch:xeus", 112 | doc=f"ensure {JUPYTERLITE_JSON} includes the federated_extensions", 113 | file_dep=[*lab_extensions, jupyterlite_json], 114 | actions=[(self.patch_jupyterlite_json, [jupyterlite_json])], 115 | ) 116 | 117 | def safe_copy_extension(self, pkg_json): 118 | """Copy a labextension, and overwrite it 119 | if it's already in the output 120 | """ 121 | pkg_path = pkg_json.parent 122 | stem = json.loads(pkg_json.read_text(**UTF8))["name"] 123 | dest = self.output_extensions / stem 124 | file_dep = [ 125 | p for p in pkg_path.rglob("*") if not (p.is_dir() or self.is_ignored_sourcemap(p.name)) 126 | ] 127 | 128 | yield dict( 129 | name=f"xeus:copy:ext:{stem}", 130 | file_dep=file_dep, 131 | actions=[(self.copy_one, [pkg_path, dest])], 132 | ) 133 | 134 | def dedupe_federated_extensions(self, config): 135 | if FEDERATED_EXTENSIONS not in config: 136 | return 137 | 138 | named = {} 139 | 140 | # Making sure to dedupe extensions by keeping the most recent ones 141 | for ext in config[FEDERATED_EXTENSIONS]: 142 | if os.path.exists(self.output_extensions / ext["name"] / ext["load"]): 143 | named[ext["name"]] = ext 144 | 145 | config[FEDERATED_EXTENSIONS] = sorted(named.values(), key=lambda x: x["name"]) 146 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: main 6 | pull_request: 7 | branches: '*' 8 | 9 | defaults: 10 | run: 11 | shell: bash -l {0} 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Install Conda environment with Micromamba 21 | uses: mamba-org/setup-micromamba@v1 22 | with: 23 | micromamba-version: '1.5.1-0' 24 | environment-file: environment.yml 25 | cache-environment: true 26 | 27 | - name: Lint 28 | run: | 29 | set -eux 30 | jlpm 31 | jlpm run build 32 | jlpm run lint:check 33 | 34 | build: 35 | runs-on: ubuntu-latest 36 | steps: 37 | - name: Checkout 38 | uses: actions/checkout@v4 39 | 40 | - name: Install Conda environment with Micromamba 41 | uses: mamba-org/setup-micromamba@v1 42 | with: 43 | micromamba-version: '1.5.1-0' 44 | environment-file: environment.yml 45 | cache-environment: true 46 | 47 | - name: Build the extension 48 | run: | 49 | set -eux 50 | python -m build 51 | 52 | - name: Upload extension packages 53 | uses: actions/upload-artifact@v3 54 | with: 55 | name: jupyterlite-xeus-python-dist-${{ github.run_number }} 56 | path: dist 57 | if-no-files-found: error 58 | 59 | test_isolated: 60 | needs: build 61 | runs-on: ubuntu-latest 62 | 63 | steps: 64 | - name: Install Python 65 | uses: actions/setup-python@v4 66 | with: 67 | python-version: '3.10' 68 | architecture: 'x64' 69 | - uses: actions/download-artifact@v3 70 | with: 71 | name: jupyterlite-xeus-python-dist-${{ github.run_number }} 72 | - name: Install and Test 73 | run: | 74 | set -eux 75 | # Remove NodeJS, twice to take care of system and locally installed node versions. 76 | sudo rm -rf $(which node) 77 | sudo rm -rf $(which node) 78 | 79 | pip install "jupyterlab>=4.0.0,<5" jupyterlite_xeus_python*.whl 80 | 81 | jupyter labextension list 82 | jupyter labextension list 2>&1 | grep -ie "@jupyterlite/xeus-python-kernel.*OK" 83 | 84 | python -m jupyterlab.browser_check --no-browser-test 85 | 86 | 87 | python-tests-mamba-python: 88 | needs: build 89 | runs-on: ubuntu-latest 90 | 91 | steps: 92 | - name: Checkout 93 | uses: actions/checkout@v4 94 | 95 | - uses: actions/download-artifact@v2 96 | with: 97 | name: jupyterlite-xeus-python-dist-${{ github.run_number }} 98 | path: ./dist 99 | 100 | - name: Install Conda environment with Micromamba 101 | uses: mamba-org/setup-micromamba@v1 102 | with: 103 | micromamba-version: '1.5.1-0' 104 | environment-file: environment.yml 105 | cache-environment: true 106 | 107 | - name: Make sure the Mamba Python API is available 108 | run: | 109 | mamba install mamba 110 | python -c "from mamba.api import create" 111 | 112 | - name: Install 113 | run: pip install jupyterlite_xeus_python*.tar.gz 114 | working-directory: dist 115 | 116 | - name: Run tests 117 | run: pytest -rP test_xeus_python_env.py 118 | working-directory: tests 119 | 120 | python-tests-mamba: 121 | needs: build 122 | runs-on: ubuntu-latest 123 | 124 | steps: 125 | - name: Checkout 126 | uses: actions/checkout@v4 127 | 128 | - uses: actions/download-artifact@v2 129 | with: 130 | name: jupyterlite-xeus-python-dist-${{ github.run_number }} 131 | path: ./dist 132 | 133 | - name: Install Conda environment with Micromamba 134 | uses: mamba-org/setup-micromamba@v1 135 | with: 136 | micromamba-version: '1.5.1-0' 137 | environment-file: environment.yml 138 | cache-environment: true 139 | 140 | - name: Install 141 | run: pip install jupyterlite_xeus_python*.tar.gz 142 | working-directory: dist 143 | 144 | - name: Run tests 145 | run: pytest -rP test_xeus_python_env.py 146 | working-directory: tests 147 | 148 | python-tests-micromamba: 149 | needs: build 150 | runs-on: ubuntu-latest 151 | 152 | steps: 153 | - name: Checkout 154 | uses: actions/checkout@v4 155 | 156 | - uses: actions/download-artifact@v2 157 | with: 158 | name: jupyterlite-xeus-python-dist-${{ github.run_number }} 159 | path: ./dist 160 | 161 | - name: Install Conda environment with Micromamba 162 | uses: mamba-org/setup-micromamba@v1 163 | with: 164 | micromamba-version: '1.5.1-0' 165 | environment-file: environment.yml 166 | cache-environment: true 167 | 168 | - name: Install 169 | run: pip install jupyterlite_xeus_python*.tar.gz 170 | working-directory: dist 171 | 172 | - name: Run tests 173 | run: pytest -rP test_xeus_python_env.py 174 | working-directory: tests 175 | 176 | python-tests-conda: 177 | needs: build 178 | runs-on: ubuntu-latest 179 | 180 | steps: 181 | - name: Checkout 182 | uses: actions/checkout@v4 183 | 184 | - uses: actions/download-artifact@v2 185 | with: 186 | name: jupyterlite-xeus-python-dist-${{ github.run_number }} 187 | path: ./dist 188 | 189 | - name: Install Conda environment with Micromamba 190 | uses: mamba-org/setup-micromamba@v1 191 | with: 192 | micromamba-version: '1.5.1-0' 193 | environment-file: environment.yml 194 | cache-environment: true 195 | 196 | - name: Install 197 | run: pip install jupyterlite_xeus_python*.tar.gz 198 | working-directory: dist 199 | 200 | - name: Run tests 201 | run: pytest -rP test_xeus_python_env.py 202 | working-directory: tests 203 | 204 | 205 | check_links: 206 | name: Check Links 207 | runs-on: ubuntu-latest 208 | timeout-minutes: 15 209 | steps: 210 | - uses: actions/checkout@v3 211 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 212 | - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1 -------------------------------------------------------------------------------- /docs/xeus-python.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 29 | 30 | 31 | 55 | 62 | 68 | 76 | 82 | 88 | 94 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jupyterlite/xeus-python-kernel", 3 | "version": "1.0.0", 4 | "description": "A Python kernel for JupyterLite, powered by Xeus", 5 | "keywords": [ 6 | "jupyter", 7 | "jupyterlab", 8 | "jupyterlite-extension", 9 | "jupyterlite" 10 | ], 11 | "homepage": "https://github.com/jupyterlite/xeus-python-kernel", 12 | "bugs": { 13 | "url": "https://github.com/jupyterlite/xeus-python-kernel/issues" 14 | }, 15 | "license": "BSD-3-Clause", 16 | "author": "JupyterLite Contributors", 17 | "files": [ 18 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf,wasm}", 19 | "style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}" 20 | ], 21 | "main": "lib/index.js", 22 | "types": "lib/index.d.ts", 23 | "style": "style/index.css", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/jupyterlite/xeus-python-kernel.git" 27 | }, 28 | "scripts": { 29 | "copy-files": "copyfiles -u 1 src/xpython_wasm.wasm src/xpython_wasm.js src/python_data.js src/*.tar.gz src/*.js src/*.json lib", 30 | "build:worker": "webpack --config worker.webpack.config.js --mode=development", 31 | "build": "jlpm run build:xeus-python && jlpm run build:lib && jlpm run build:worker && jlpm run copy-files && jlpm run build:labextension:dev", 32 | "build:xeus-python": "python jupyterlite_xeus_python/build.py --output-path src --build-worker", 33 | "build:worker:prod": "webpack --config worker.webpack.config.js --mode=production", 34 | "build:prod": "jlpm run clean && jlpm run build:xeus-python && jlpm run build:lib:prod && jlpm run build:worker:prod && jlpm run copy-files && jlpm run build:labextension", 35 | "build:labextension": "jupyter labextension build .", 36 | "build:labextension:dev": "jupyter labextension build --development True .", 37 | "build:lib": "tsc --sourceMap", 38 | "build:lib:prod": "tsc", 39 | "clean": "jlpm clean:lib", 40 | "clean:lib": "rimraf lib tsconfig.tsbuildinfo", 41 | "clean:lintcache": "rimraf .eslintcache .stylelintcache", 42 | "clean:labextension": "rimraf jupyterlite_xeus_python/labextension jupyterlite_xeus_python/_version.py", 43 | "clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache", 44 | "eslint": "jlpm eslint:check --fix", 45 | "eslint:check": "eslint . --cache --ext .ts,.tsx", 46 | "install:extension": "jlpm build", 47 | "lint": "jlpm stylelint && jlpm prettier && jlpm eslint && jlpm lint:py", 48 | "lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check && jlpm lint:py:check", 49 | "lint:py": "jlpm lint:py:black && jlpm lint:py:ruff --fix-only", 50 | "lint:py:check": "jlpm lint:py:black:check && jlpm lint:py:ruff:check", 51 | "lint:py:black": "black .", 52 | "lint:py:black:check": "black . --check", 53 | "lint:py:ruff": "ruff .", 54 | "lint:py:ruff:check": "ruff check .", 55 | "prettier": "jlpm prettier:base --write --list-different", 56 | "prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"", 57 | "prettier:check": "jlpm prettier:base --check", 58 | "stylelint": "jlpm stylelint:check --fix", 59 | "stylelint:check": "stylelint --cache \"style/**/*.css\"", 60 | "watch": "run-p watch:src watch:labextension", 61 | "watch:src": "tsc -w --sourceMap", 62 | "watch:labextension": "jupyter labextension watch ." 63 | }, 64 | "dependencies": { 65 | "@jupyterlab/coreutils": "^6", 66 | "@jupyterlab/services": "^7", 67 | "@jupyterlite/contents": "^0.2.0-alpha.1", 68 | "@jupyterlite/kernel": "^0.2.0-alpha.1", 69 | "@jupyterlite/server": "^0.2.0-alpha.1", 70 | "@lumino/coreutils": "^2", 71 | "@lumino/signaling": "^2", 72 | "comlink": "^4.3.1" 73 | }, 74 | "devDependencies": { 75 | "@jupyterlab/builder": "^4.0.5", 76 | "@types/json-schema": "^7.0.11", 77 | "@types/react": "^18.0.26", 78 | "@types/react-addons-linked-state-mixin": "^0.14.22", 79 | "@typescript-eslint/eslint-plugin": "^6.1.0", 80 | "@typescript-eslint/parser": "^6.1.0", 81 | "copy-webpack-plugin": "^9.0.1", 82 | "copyfiles": "^2.4.1", 83 | "eslint": "^8.36.0", 84 | "eslint-config-prettier": "^8.8.0", 85 | "eslint-plugin-prettier": "^5.0.0", 86 | "file-loader": "^6.2.0", 87 | "npm-run-all": "^4.1.5", 88 | "prettier": "^3.0.0", 89 | "rimraf": "^5.0.1", 90 | "shx": "^0.3.0", 91 | "source-map-loader": "^1.0.2", 92 | "style-loader": "^3.3.1", 93 | "stylelint": "^15.10.1", 94 | "stylelint-config-recommended": "^13.0.0", 95 | "stylelint-config-standard": "^34.0.0", 96 | "stylelint-csstree-validator": "^3.0.0", 97 | "stylelint-prettier": "^4.0.0", 98 | "typescript": "~5.0.2", 99 | "webpack": "^5.87.0", 100 | "webpack-cli": "^5.1.4", 101 | "yjs": "^13.5.0" 102 | }, 103 | "sideEffects": [ 104 | "style/*.css", 105 | "style/index.js" 106 | ], 107 | "styleModule": "style/index.js", 108 | "publishConfig": { 109 | "access": "public" 110 | }, 111 | "jupyterlab": { 112 | "extension": true, 113 | "outputDir": "jupyterlite_xeus_python/labextension", 114 | "webpackConfig": "./webpack.config.js", 115 | "sharedPackages": { 116 | "@jupyterlite/kernel": { 117 | "bundled": false, 118 | "singleton": true 119 | }, 120 | "@jupyterlite/server": { 121 | "bundled": false, 122 | "singleton": true 123 | }, 124 | "@jupyterlite/contents": { 125 | "bundled": false, 126 | "singleton": true 127 | } 128 | } 129 | }, 130 | "jupyterlite": { 131 | "liteExtension": true 132 | }, 133 | "eslintIgnore": [ 134 | "node_modules", 135 | "dist", 136 | "coverage", 137 | "**/*.d.ts" 138 | ], 139 | "eslintConfig": { 140 | "extends": [ 141 | "eslint:recommended", 142 | "plugin:@typescript-eslint/eslint-recommended", 143 | "plugin:@typescript-eslint/recommended", 144 | "plugin:prettier/recommended" 145 | ], 146 | "parser": "@typescript-eslint/parser", 147 | "parserOptions": { 148 | "project": "tsconfig.json", 149 | "sourceType": "module" 150 | }, 151 | "plugins": [ 152 | "@typescript-eslint" 153 | ], 154 | "rules": { 155 | "@typescript-eslint/naming-convention": [ 156 | "error", 157 | { 158 | "selector": "interface", 159 | "format": [ 160 | "PascalCase" 161 | ], 162 | "custom": { 163 | "regex": "^I[A-Z]", 164 | "match": true 165 | } 166 | } 167 | ], 168 | "@typescript-eslint/no-unused-vars": [ 169 | "warn", 170 | { 171 | "args": "none" 172 | } 173 | ], 174 | "@typescript-eslint/no-explicit-any": "off", 175 | "@typescript-eslint/no-namespace": "off", 176 | "@typescript-eslint/no-use-before-define": "off", 177 | "@typescript-eslint/quotes": [ 178 | "error", 179 | "single", 180 | { 181 | "avoidEscape": true, 182 | "allowTemplateLiterals": false 183 | } 184 | ], 185 | "curly": [ 186 | "error", 187 | "all" 188 | ], 189 | "eqeqeq": "error", 190 | "prefer-arrow-callback": "error" 191 | } 192 | }, 193 | "prettier": { 194 | "singleQuote": true, 195 | "trailingComma": "none", 196 | "arrowParens": "avoid", 197 | "endOfLine": "auto", 198 | "overrides": [ 199 | { 200 | "files": "package.json", 201 | "options": { 202 | "tabWidth": 4 203 | } 204 | } 205 | ] 206 | }, 207 | "stylelint": { 208 | "extends": [ 209 | "stylelint-config-recommended", 210 | "stylelint-config-standard", 211 | "stylelint-prettier/recommended" 212 | ], 213 | "plugins": [ 214 | "stylelint-csstree-validator" 215 | ], 216 | "rules": { 217 | "csstree/validator": true, 218 | "property-no-vendor-prefix": null, 219 | "selector-no-vendor-prefix": null, 220 | "value-no-vendor-prefix": null 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /jupyterlite_xeus_python/build.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | import shutil 4 | import sys 5 | from pathlib import Path 6 | from subprocess import run 7 | from tempfile import TemporaryDirectory 8 | from typing import List, Optional 9 | from urllib.parse import urlparse 10 | 11 | import requests 12 | import typer 13 | import yaml 14 | from empack.file_patterns import PkgFileFilter, pkg_file_filter_from_yaml 15 | from empack.pack import DEFAULT_CONFIG_PATH, pack_env 16 | 17 | try: 18 | from mamba.api import create as mamba_create 19 | 20 | MAMBA_PYTHON_AVAILABLE = True 21 | except ImportError: 22 | MAMBA_PYTHON_AVAILABLE = False 23 | 24 | MAMBA_COMMAND = shutil.which("mamba") 25 | MICROMAMBA_COMMAND = shutil.which("micromamba") 26 | CONDA_COMMAND = shutil.which("conda") 27 | 28 | PYTHON_MAJOR = 3 29 | PYTHON_MINOR = 11 30 | PYTHON_VERSION = f"{PYTHON_MAJOR}.{PYTHON_MINOR}" 31 | 32 | XEUS_PYTHON_VERSION = "0.15.10" 33 | 34 | CHANNELS = [ 35 | "https://repo.mamba.pm/emscripten-forge", 36 | "conda-forge", 37 | ] 38 | 39 | PLATFORM = "emscripten-wasm32" 40 | DEFAULT_REQUEST_TIMEOUT = 1 # in minutes 41 | 42 | 43 | def create_env( 44 | env_name, 45 | root_prefix, 46 | specs, 47 | channels, 48 | ): 49 | """Create the emscripten environment with the given specs.""" 50 | prefix_path = Path(root_prefix) / "envs" / env_name 51 | 52 | if MAMBA_PYTHON_AVAILABLE: 53 | mamba_create( 54 | env_name=env_name, 55 | base_prefix=root_prefix, 56 | specs=specs, 57 | channels=channels, 58 | target_platform=PLATFORM, 59 | ) 60 | return 61 | 62 | channels_args = [] 63 | for channel in channels: 64 | channels_args.extend(["-c", channel]) 65 | 66 | if MAMBA_COMMAND: 67 | # Mamba needs the directory to exist already 68 | prefix_path.mkdir(parents=True, exist_ok=True) 69 | return _create_env_with_config(MAMBA_COMMAND, prefix_path, specs, channels_args) 70 | 71 | if MICROMAMBA_COMMAND: 72 | run( 73 | [ 74 | MICROMAMBA_COMMAND, 75 | "create", 76 | "--yes", 77 | "--no-pyc", 78 | "--root-prefix", 79 | root_prefix, 80 | "--name", 81 | env_name, 82 | f"--platform={PLATFORM}", 83 | *channels_args, 84 | *specs, 85 | ], 86 | check=True, 87 | ) 88 | return 89 | 90 | if CONDA_COMMAND: 91 | return _create_env_with_config(CONDA_COMMAND, prefix_path, specs, channels_args) 92 | 93 | raise RuntimeError( 94 | """Failed to create the virtual environment for xeus-python, 95 | please make sure at least mamba, micromamba or conda is installed. 96 | """ 97 | ) 98 | 99 | 100 | def _create_env_with_config(conda, prefix_path, specs, channels_args): 101 | run( 102 | [conda, "create", "--yes", "--prefix", prefix_path, *channels_args], 103 | check=True, 104 | ) 105 | _create_config(prefix_path) 106 | run( 107 | [ 108 | conda, 109 | "install", 110 | "--yes", 111 | "--prefix", 112 | prefix_path, 113 | *channels_args, 114 | *specs, 115 | ], 116 | check=True, 117 | ) 118 | 119 | 120 | def _create_config(prefix_path): 121 | with open(prefix_path / ".condarc", "w") as fobj: 122 | fobj.write(f"subdir: {PLATFORM}") 123 | os.environ["CONDARC"] = str(prefix_path / ".condarc") 124 | 125 | 126 | def _install_pip_dependencies(prefix_path, dependencies, log=None): 127 | # Why is this so damn complicated? 128 | # Isn't it easier to download the .whl ourselves? pip is hell 129 | 130 | if log is not None: 131 | log.warning( 132 | """ 133 | Installing pip dependencies. This is very much experimental so use 134 | this feature at your own risks. 135 | Note that you can only install pure-python packages. 136 | pip is being run with the --no-deps option to not pull undesired 137 | system-specific dependencies, so please install your package dependencies 138 | from emscripten-forge or conda-forge. 139 | """ 140 | ) 141 | 142 | # Installing with pip in another prefix that has a different Python version IS NOT POSSIBLE 143 | # So we need to do this whole mess "manually" 144 | pkg_dir = TemporaryDirectory() 145 | 146 | run( 147 | [ 148 | sys.executable, 149 | "-m", 150 | "pip", 151 | "install", 152 | *dependencies, 153 | # Install in a tmp directory while we process it 154 | "--target", 155 | pkg_dir.name, 156 | # Specify the right Python version 157 | "--python-version", 158 | PYTHON_VERSION, 159 | # No dependency installed 160 | "--no-deps", 161 | "--no-input", 162 | "--verbose", 163 | ], 164 | check=True, 165 | ) 166 | 167 | # We need to read the RECORD and try to be smart about what goes 168 | # under site-packages and what goes where 169 | packages_dist_info = Path(pkg_dir.name).glob("*.dist-info") 170 | 171 | for package_dist_info in packages_dist_info: 172 | with open(package_dist_info / "RECORD") as record: 173 | record_content = record.read() 174 | record_csv = csv.reader(record_content.splitlines()) 175 | all_files = [_file[0] for _file in record_csv] 176 | 177 | # List of tuples: (path: str, inside_site_packages: bool) 178 | files = [(_file, not _file.startswith("../../")) for _file in all_files] 179 | 180 | # Why? 181 | fixed_record_data = record_content.replace("../../", "../../../") 182 | 183 | # OVERWRITE RECORD file 184 | with open(package_dist_info / "RECORD", "w") as record: 185 | record.write(fixed_record_data) 186 | 187 | non_supported_files = [".so", ".a", ".dylib", ".lib", ".exe.dll"] 188 | 189 | # COPY files under `prefix_path` 190 | for _file, inside_site_packages in files: 191 | path = Path(_file) 192 | 193 | # FAIL if .so / .a / .dylib / .lib / .exe / .dll 194 | if path.suffix in non_supported_files: 195 | raise RuntimeError( 196 | "Cannot install binary PyPI package, only pure Python packages are supported" 197 | ) 198 | 199 | file_path = _file[6:] if not inside_site_packages else _file 200 | install_path = ( 201 | prefix_path 202 | if not inside_site_packages 203 | else prefix_path / "lib" / f"python{PYTHON_VERSION}" / "site-packages" 204 | ) 205 | 206 | src_path = Path(pkg_dir.name) / file_path 207 | dest_path = install_path / file_path 208 | 209 | os.makedirs(dest_path.parent, exist_ok=True) 210 | 211 | shutil.copy(src_path, dest_path) 212 | 213 | 214 | def build_and_pack_emscripten_env( # noqa: C901, PLR0912, PLR0915 215 | python_version: str = PYTHON_VERSION, 216 | xeus_python_version: str = XEUS_PYTHON_VERSION, 217 | packages: Optional[List[str]] = None, 218 | environment_file: str = "", 219 | root_prefix: str = "/tmp/xeus-python-kernel", 220 | env_name: str = "xeus-python-kernel", 221 | empack_config: str = "", 222 | output_path: str = ".", 223 | build_worker: bool = False, 224 | force: bool = False, 225 | log=None, 226 | ): 227 | """Build a conda environment for the emscripten platform and pack it with empack.""" 228 | if packages is None: 229 | packages = [] 230 | channels = CHANNELS 231 | specs = [ 232 | f"python={python_version}", 233 | "xeus-lite>=1.0.0,<1.0.3", 234 | "xeus-python" if not xeus_python_version else f"xeus-python={xeus_python_version}", 235 | *packages, 236 | ] 237 | bail_early = True 238 | 239 | if packages or xeus_python_version or environment_file: 240 | bail_early = False 241 | 242 | pip_dependencies = [] 243 | 244 | # Process environment.yml file 245 | if environment_file and Path(environment_file).exists(): 246 | env_file = Path(environment_file) 247 | 248 | bail_early = False 249 | 250 | with open(env_file) as f: 251 | env_data = yaml.safe_load(f) 252 | 253 | if env_data.get("name") is not None: 254 | env_name = env_data["name"] 255 | 256 | channels = env_data.get("channels", CHANNELS) 257 | 258 | if env_data.get("dependencies") is not None: 259 | dependencies = env_data["dependencies"] 260 | 261 | for dependency in dependencies: 262 | if isinstance(dependency, str) and dependency not in specs: 263 | specs.append(dependency) 264 | elif isinstance(dependency, dict) and dependency.get("pip") is not None: 265 | # If it's a local Python package, make its path relative to the environment file 266 | pip_dependencies = [ 267 | ( 268 | (env_file.parent / pip_dep).resolve() 269 | if os.path.isdir(env_file.parent / pip_dep) 270 | else pip_dep 271 | ) 272 | for pip_dep in dependency["pip"] 273 | ] 274 | 275 | # Bail early if there is nothing to do 276 | if bail_early and not force: 277 | return "" 278 | 279 | orig_config = os.environ.get("CONDARC") 280 | 281 | # Cleanup tmp dir in case it's not empty 282 | shutil.rmtree(Path(root_prefix) / "envs", ignore_errors=True) 283 | Path(root_prefix).mkdir(parents=True, exist_ok=True) 284 | 285 | output_path = Path(output_path).resolve() 286 | output_path.mkdir(parents=True, exist_ok=True) 287 | 288 | prefix_path = Path(root_prefix) / "envs" / env_name 289 | 290 | try: 291 | # Create emscripten env with the given packages 292 | create_env(env_name, root_prefix, specs, channels) 293 | 294 | # Install pip dependencies 295 | if pip_dependencies: 296 | _install_pip_dependencies(prefix_path, pip_dependencies, log=log) 297 | 298 | pack_kwargs = {} 299 | 300 | # Download env filter config 301 | if empack_config: 302 | empack_config_is_url = urlparse(empack_config).scheme in ("http", "https") 303 | if empack_config_is_url: 304 | empack_config_content = requests.get( 305 | empack_config, timeout=DEFAULT_REQUEST_TIMEOUT 306 | ).content 307 | pack_kwargs["file_filters"] = PkgFileFilter.parse_obj( 308 | yaml.safe_load(empack_config_content) 309 | ) 310 | else: 311 | pack_kwargs["file_filters"] = pkg_file_filter_from_yaml(empack_config) 312 | else: 313 | pack_kwargs["file_filters"] = pkg_file_filter_from_yaml(DEFAULT_CONFIG_PATH) 314 | 315 | # Pack the environment 316 | pack_env( 317 | env_prefix=prefix_path, 318 | relocate_prefix="/", 319 | outdir=output_path, 320 | use_cache=False, 321 | **pack_kwargs, 322 | ) 323 | 324 | # Copy xeus-python output 325 | for file in ["xpython_wasm.js", "xpython_wasm.wasm"]: 326 | shutil.copyfile(prefix_path / "bin" / file, Path(output_path) / file) 327 | 328 | # Copy worker code and process it 329 | if build_worker: 330 | shutil.copytree( 331 | prefix_path / "share" / "xeus-lite", 332 | Path(output_path), 333 | dirs_exist_ok=True, 334 | ) 335 | 336 | with open(Path(output_path) / "worker.ts") as fobj: 337 | worker = fobj.read() 338 | 339 | worker = worker.replace("XEUS_KERNEL_FILE", "'xpython_wasm.js'") 340 | worker = worker.replace("LANGUAGE_DATA_FILE", "'python_data.js'") 341 | worker = worker.replace( 342 | "importScripts(DATA_FILE);", 343 | """ 344 | await globalThis.Module.bootstrap_from_empack_packed_environment( 345 | `./empack_env_meta.json`, /* packages_json_url */ 346 | ".", /* package_tarballs_root_url */ 347 | false /* verbose */ 348 | ); 349 | """, 350 | ) 351 | with open(Path(output_path) / "worker.ts", "w") as fobj: 352 | fobj.write(worker) 353 | 354 | except Exception as e: 355 | raise e 356 | finally: 357 | if orig_config is not None: 358 | os.environ["CONDARC"] = orig_config 359 | elif "CONDARC" in os.environ: 360 | del os.environ["CONDARC"] 361 | 362 | return prefix_path 363 | 364 | 365 | def main( 366 | python_version: str = PYTHON_VERSION, 367 | xeus_python_version: str = XEUS_PYTHON_VERSION, 368 | packages: List[str] = typer.Option([], help="The list of packages you want to install"), 369 | environment_file: str = typer.Option( 370 | "", help="The path to the environment.yml file you want to use" 371 | ), 372 | root_prefix: str = "/tmp/xeus-python-kernel", 373 | env_name: str = "xeus-python-kernel", 374 | empack_config: str = typer.Option( 375 | "", 376 | help="The empack config file to use. If not provided, the default empack config will be used", 377 | ), 378 | output_path: str = typer.Option( 379 | ".", 380 | help="The directory where to output the packed environment", 381 | ), 382 | build_worker: bool = typer.Option( 383 | False, 384 | help="Whether or not to build the TypeScript worker code for using xeus-python in JupyterLite", 385 | ), 386 | ): 387 | """Build and pack an emscripten environment.""" 388 | return build_and_pack_emscripten_env( 389 | python_version, 390 | xeus_python_version, 391 | packages, 392 | environment_file, 393 | root_prefix, 394 | env_name, 395 | empack_config, 396 | output_path, 397 | build_worker, 398 | force=True, 399 | ) 400 | 401 | 402 | def start(): 403 | typer.run(main) 404 | 405 | 406 | if __name__ == "__main__": 407 | start() 408 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | 5 | ## 1.0.0 6 | 7 | No merged PRs 8 | 9 | 10 | 11 | ## 1.0.0b0 12 | 13 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v1.0.0a3...48860dd7ea57b5e293f4e9f3e8c604fe7096d49a)) 14 | 15 | ### Bugs fixed 16 | 17 | - Pin xeus-lite [#194](https://github.com/jupyterlite/xeus-python-kernel/pull/194) ([@martinRenou](https://github.com/martinRenou)) 18 | 19 | ### Contributors to this release 20 | 21 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-10-18&to=2023-12-06&type=c)) 22 | 23 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-10-18..2023-12-06&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-10-18..2023-12-06&type=Issues) 24 | 25 | ## 1.0.0a3 26 | 27 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v1.0.0a2...90f5ac56c5a0ea0a5c1d21da16b11bb49ae18d28)) 28 | 29 | ### Maintenance and upkeep improvements 30 | 31 | - Add more `skip-if-exists`, fix wheel packaging [#181](https://github.com/jupyterlite/xeus-python-kernel/pull/181) ([@jtpio](https://github.com/jtpio)) 32 | 33 | ### Contributors to this release 34 | 35 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-10-17&to=2023-10-18&type=c)) 36 | 37 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-10-17..2023-10-18&type=Issues) 38 | 39 | ## 1.0.0a2 40 | 41 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v1.0.0a1...e5d5d48763484fd4b6e84ff7fcf3ff26f8c3fd22)) 42 | 43 | ### Maintenance and upkeep improvements 44 | 45 | - Add `enforce-label` workflow [#180](https://github.com/jupyterlite/xeus-python-kernel/pull/180) ([@jtpio](https://github.com/jtpio)) 46 | - Add missing `ensured-targets` [#179](https://github.com/jupyterlite/xeus-python-kernel/pull/179) ([@jtpio](https://github.com/jtpio)) 47 | - Start `ui-tests` [#167](https://github.com/jupyterlite/xeus-python-kernel/pull/167) ([@jtpio](https://github.com/jtpio)) 48 | 49 | ### Documentation improvements 50 | 51 | - Include the changelog in the docs [#173](https://github.com/jupyterlite/xeus-python-kernel/pull/173) ([@jtpio](https://github.com/jtpio)) 52 | 53 | ### Contributors to this release 54 | 55 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-10-11&to=2023-10-17&type=c)) 56 | 57 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-10-11..2023-10-17&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-10-11..2023-10-17&type=Issues) 58 | 59 | ## 1.0.0a1 60 | 61 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v1.0.0a0...2f336570200a6fec5f82c302ed6c5fda80598535)) 62 | 63 | ### Enhancements made 64 | 65 | - Python 3.11 and new emscripten-wasm32 platform [#164](https://github.com/jupyterlite/xeus-python-kernel/pull/164) ([@martinRenou](https://github.com/martinRenou)) 66 | 67 | ### Maintenance and upkeep improvements 68 | 69 | - Adopt `ruff`, `black`, fix various issues [#169](https://github.com/jupyterlite/xeus-python-kernel/pull/169) ([@jtpio](https://github.com/jtpio)) 70 | - Align repo with the extension template [#168](https://github.com/jupyterlite/xeus-python-kernel/pull/168) ([@jtpio](https://github.com/jtpio)) 71 | 72 | ### Contributors to this release 73 | 74 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-09-27&to=2023-10-11&type=c)) 75 | 76 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-09-27..2023-10-11&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-09-27..2023-10-11&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-09-27..2023-10-11&type=Issues) 77 | 78 | ## 1.0.0a0 79 | 80 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.9.6...8ed06f083b2e325af748e256e8a5e7118ec29a7e)) 81 | 82 | ### Maintenance and upkeep improvements 83 | 84 | - Update to JupyterLab 4 and JupyterLite 0.2.0 [#155](https://github.com/jupyterlite/xeus-python-kernel/pull/155) ([@jtpio](https://github.com/jtpio)) 85 | 86 | ### Contributors to this release 87 | 88 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-09-27&to=2023-09-27&type=c)) 89 | 90 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-09-27..2023-09-27&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-09-27..2023-09-27&type=Issues) 91 | 92 | ## 0.9.6 93 | 94 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.9.5...48c2518812d748377609a2d2da7b16b4ae417f9f)) 95 | 96 | ### Maintenance and upkeep improvements 97 | 98 | - Bound requirement of jupyterlite [#160](https://github.com/jupyterlite/xeus-python-kernel/pull/160) ([@martinRenou](https://github.com/martinRenou)) 99 | 100 | ### Contributors to this release 101 | 102 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-09-26&to=2023-09-27&type=c)) 103 | 104 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-09-26..2023-09-27&type=Issues) 105 | 106 | ## 0.9.5 107 | 108 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.9.4...a89bdd1a4568027fc6e4e7a640a6e77b4d5c3a43)) 109 | 110 | ### Bugs fixed 111 | 112 | - Make sure to share all packages coming from jupyterlite [#158](https://github.com/jupyterlite/xeus-python-kernel/pull/158) ([@martinRenou](https://github.com/martinRenou)) 113 | 114 | ### Maintenance and upkeep improvements 115 | 116 | - Use `mamba-org/setup-micromamba` in more places [#159](https://github.com/jupyterlite/xeus-python-kernel/pull/159) ([@jtpio](https://github.com/jtpio)) 117 | - Use `mamba-org/setup-micromamba` GitHub Action [#157](https://github.com/jupyterlite/xeus-python-kernel/pull/157) ([@jtpio](https://github.com/jtpio)) 118 | 119 | ### Documentation improvements 120 | 121 | - Install `jupyterlite-sphinx` from conda forge [#156](https://github.com/jupyterlite/xeus-python-kernel/pull/156) ([@jtpio](https://github.com/jtpio)) 122 | 123 | ### Contributors to this release 124 | 125 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-08-22&to=2023-09-26&type=c)) 126 | 127 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-08-22..2023-09-26&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-08-22..2023-09-26&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-08-22..2023-09-26&type=Issues) 128 | 129 | ## 0.9.4 130 | 131 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.9.3...fcc8d031c54efedb1c38e8f36cd20ceedd277218)) 132 | 133 | ### Maintenance and upkeep improvements 134 | 135 | - Bumped @jupyterlite packages [#150](https://github.com/jupyterlite/xeus-python-kernel/pull/150) ([@andeplane](https://github.com/andeplane)) 136 | 137 | ### Other merged PRs 138 | 139 | - Strict respect of channels specified in env file [#149](https://github.com/jupyterlite/xeus-python-kernel/pull/149) ([@martinRenou](https://github.com/martinRenou)) 140 | 141 | ### Contributors to this release 142 | 143 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-08-03&to=2023-08-22&type=c)) 144 | 145 | [@andeplane](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Aandeplane+updated%3A2023-08-03..2023-08-22&type=Issues) | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-08-03..2023-08-22&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-08-03..2023-08-22&type=Issues) 146 | 147 | ## 0.9.3 148 | 149 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.9.2...3f74831afeb265c8c2aed1398314181073527dad)) 150 | 151 | ### Documentation improvements 152 | 153 | - Add documentation for installing local pip packages [#146](https://github.com/jupyterlite/xeus-python-kernel/pull/146) ([@martinRenou](https://github.com/martinRenou)) 154 | - Add more docs about pip installation limitations [#144](https://github.com/jupyterlite/xeus-python-kernel/pull/144) ([@martinRenou](https://github.com/martinRenou)) 155 | 156 | ### Other merged PRs 157 | 158 | - Fix version number [#147](https://github.com/jupyterlite/xeus-python-kernel/pull/147) ([@martinRenou](https://github.com/martinRenou)) 159 | - More testing [#143](https://github.com/jupyterlite/xeus-python-kernel/pull/143) ([@martinRenou](https://github.com/martinRenou)) 160 | - Compute local package dir when pip install [#142](https://github.com/jupyterlite/xeus-python-kernel/pull/142) ([@martinRenou](https://github.com/martinRenou)) 161 | 162 | ### Contributors to this release 163 | 164 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-07-24&to=2023-08-03&type=c)) 165 | 166 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-07-24..2023-08-03&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-07-24..2023-08-03&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-07-24..2023-08-03&type=Issues) 167 | 168 | ## 0.9.2 169 | 170 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.9.1...70717e5981fcefd9f0cff7c8eb567cdbe928bef7)) 171 | 172 | ### Documentation improvements 173 | 174 | - Remove outdated README part [#141](https://github.com/jupyterlite/xeus-python-kernel/pull/141) ([@martinRenou](https://github.com/martinRenou)) 175 | 176 | ### Other merged PRs 177 | 178 | - Add support for pip dependencies [#102](https://github.com/jupyterlite/xeus-python-kernel/pull/102) ([@martinRenou](https://github.com/martinRenou)) 179 | 180 | ### Contributors to this release 181 | 182 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-07-20&to=2023-07-24&type=c)) 183 | 184 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-07-20..2023-07-24&type=Issues) 185 | 186 | ## 0.9.1 187 | 188 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.9.0...f6e764fac2ca525be9686b0bddd1dcdf5590162c)) 189 | 190 | ### Maintenance and upkeep improvements 191 | 192 | - Provide a way for Voici to pin packages [#139](https://github.com/jupyterlite/xeus-python-kernel/pull/139) ([@martinRenou](https://github.com/martinRenou)) 193 | 194 | ### Documentation improvements 195 | 196 | - Add mamba install instructions [#136](https://github.com/jupyterlite/xeus-python-kernel/pull/136) ([@martinRenou](https://github.com/martinRenou)) 197 | 198 | ### Contributors to this release 199 | 200 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-06-19&to=2023-07-20&type=c)) 201 | 202 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-06-19..2023-07-20&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-06-19..2023-07-20&type=Issues) 203 | 204 | ## 0.9.0 205 | 206 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.8.1...da52ac042abcd300c782e128b319719c6c197d9d)) 207 | 208 | ### Merged PRs 209 | 210 | - use empack 3.0 [#134](https://github.com/jupyterlite/xeus-python-kernel/pull/134) ([@DerThorsten](https://github.com/DerThorsten)) 211 | 212 | ### Contributors to this release 213 | 214 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-05-02&to=2023-06-19&type=c)) 215 | 216 | [@DerThorsten](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3ADerThorsten+updated%3A2023-05-02..2023-06-19&type=Issues) 217 | 218 | ## 0.8.1 219 | 220 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.8.0...9af9419ab2cdf54605627c870e25391128113538)) 221 | 222 | ### Bugs fixed 223 | 224 | - Pin xeus-python to a known working version [#129](https://github.com/jupyterlite/xeus-python-kernel/pull/129) ([@martinRenou](https://github.com/martinRenou)) 225 | 226 | ### Documentation improvements 227 | 228 | - Add advanced section to the docs for providing a custom `empack_config.yaml` [#127](https://github.com/jupyterlite/xeus-python-kernel/pull/127) ([@jtpio](https://github.com/jtpio)) 229 | - Convert docs to Markdown [#125](https://github.com/jupyterlite/xeus-python-kernel/pull/125) ([@jtpio](https://github.com/jtpio)) 230 | 231 | ### Contributors to this release 232 | 233 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-04-06&to=2023-05-02&type=c)) 234 | 235 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-04-06..2023-05-02&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-04-06..2023-05-02&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-04-06..2023-05-02&type=Issues) 236 | 237 | ## 0.8.0 238 | 239 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.7.0...b7c186310b2d9158be2630b409f1df8c2b450714)) 240 | 241 | ### Maintenance and upkeep improvements 242 | 243 | - Update to `jupyterlite-core==0.1.0b20` [#118](https://github.com/jupyterlite/xeus-python-kernel/pull/118) ([@jtpio](https://github.com/jtpio)) 244 | 245 | ### Other merged PRs 246 | 247 | - Update to jlite 0.1.0 [#123](https://github.com/jupyterlite/xeus-python-kernel/pull/123) ([@martinRenou](https://github.com/martinRenou)) 248 | 249 | ### Contributors to this release 250 | 251 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-03-15&to=2023-04-06&type=c)) 252 | 253 | [@github-actions](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Agithub-actions+updated%3A2023-03-15..2023-04-06&type=Issues) | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-03-15..2023-04-06&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-03-15..2023-04-06&type=Issues) 254 | 255 | ## 0.7.0 256 | 257 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.6.3...aaad404083bef58d3421a4dab26e30c818fbb9c9)) 258 | 259 | ### Maintenance and upkeep improvements 260 | 261 | - Add ReadTheDocs preview CI workflow [#115](https://github.com/jupyterlite/xeus-python-kernel/pull/115) ([@jtpio](https://github.com/jtpio)) 262 | - Depend on `jupyterlite-core` [#114](https://github.com/jupyterlite/xeus-python-kernel/pull/114) ([@jtpio](https://github.com/jtpio)) 263 | 264 | ### Contributors to this release 265 | 266 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-02-15&to=2023-03-15&type=c)) 267 | 268 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-02-15..2023-03-15&type=Issues) 269 | 270 | ## 0.6.3 271 | 272 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.6.2...0ee60d33bb46a158e6f63d52e5e5fe809d47d6dd)) 273 | 274 | ### Maintenance and upkeep improvements 275 | 276 | - Update to `check-release@v2` [#113](https://github.com/jupyterlite/xeus-python-kernel/pull/113) ([@jtpio](https://github.com/jtpio)) 277 | - Add releaser workflows to the repo [#109](https://github.com/jupyterlite/xeus-python-kernel/pull/109) ([@jtpio](https://github.com/jtpio)) 278 | 279 | ### Other merged PRs 280 | 281 | - Update jupyterlite and empack [#112](https://github.com/jupyterlite/xeus-python-kernel/pull/112) ([@martinRenou](https://github.com/martinRenou)) 282 | 283 | ### Contributors to this release 284 | 285 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2023-02-09&to=2023-02-15&type=c)) 286 | 287 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2023-02-09..2023-02-15&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2023-02-09..2023-02-15&type=Issues) 288 | 289 | ## 0.6.2 290 | 291 | ### Docs 292 | 293 | - Update xeus-python in docs [#99](https://github.com/jupyterlite/xeus-python-kernel/pull/99) ([@martinRenou](https://github.com/martinRenou)) 294 | - Add docs for making deployments [#101](https://github.com/jupyterlite/xeus-python-kernel/pull/101) ([@martinRenou](https://github.com/martinRenou)) 295 | - Get rid of the dockerfile and make a dev install in the docs [#104](https://github.com/jupyterlite/xeus-python-kernel/pull/104) ([@martinRenou](https://github.com/martinRenou)) 296 | - Update to jupyterlite==0.1.0b17 in the docs [#106](https://github.com/jupyterlite/xeus-python-kernel/pull/106) ([@jtpio](https://github.com/jtpio)) 297 | 298 | ### Improvements 299 | 300 | - Use shutil.which() in subprocess.check_call() when executing mamba/micromamba/conda [#103](https://github.com/jupyterlite/xeus-python-kernel/pull/103) ([@vasiljevic](https://github.com/vasiljevic)) 301 | - New emscripten + Fix CI [#108](https://github.com/jupyterlite/xeus-python-kernel/pull/108) ([@DerThorsten](https://github.com/DerThorsten)) 302 | 303 | ## 0.6.1 304 | 305 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.6.0...a566a1154db4df359575395ef7b76735c4e27d94)) 306 | 307 | ### Merged PRs 308 | 309 | - Fix docs [#97](https://github.com/jupyterlite/xeus-python-kernel/pull/97) ([@martinRenou](https://github.com/martinRenou)) 310 | - Add support for environment.yml file [#96](https://github.com/jupyterlite/xeus-python-kernel/pull/96) ([@martinRenou](https://github.com/martinRenou)) 311 | - Hard pin jupyterlite-xeus-python in docs [#95](https://github.com/jupyterlite/xeus-python-kernel/pull/95) ([@martinRenou](https://github.com/martinRenou)) 312 | 313 | ### Contributors to this release 314 | 315 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-12-21&to=2022-12-22&type=c)) 316 | 317 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-12-21..2022-12-22&type=Issues) 318 | 319 | ## 0.6.0 320 | 321 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.5.6...398a03532c11d843830b74e7707ef322a88589db)) 322 | 323 | ### Merged PRs 324 | 325 | - Pin hard jupyterlite in docs [#93](https://github.com/jupyterlite/xeus-python-kernel/pull/93) ([@martinRenou](https://github.com/martinRenou)) 326 | - Make the service worker optional [#92](https://github.com/jupyterlite/xeus-python-kernel/pull/92) ([@martinRenou](https://github.com/martinRenou)) 327 | - Specify linux/amd64 for docker image [#91](https://github.com/jupyterlite/xeus-python-kernel/pull/91) ([@jzavala-gonzalez](https://github.com/jzavala-gonzalez)) 328 | - Update empack to 2.0.2 [#89](https://github.com/jupyterlite/xeus-python-kernel/pull/89) ([@martinRenou](https://github.com/martinRenou)) 329 | - Fixed file names in sed command [#88](https://github.com/jupyterlite/xeus-python-kernel/pull/88) ([@JohanMabille](https://github.com/JohanMabille)) 330 | - Cache xeus-python build [#87](https://github.com/jupyterlite/xeus-python-kernel/pull/87) ([@martinRenou](https://github.com/martinRenou)) 331 | - Upgraded to xeus-python 0.15 [#86](https://github.com/jupyterlite/xeus-python-kernel/pull/86) ([@JohanMabille](https://github.com/JohanMabille)) 332 | - Fix typo in doc/index.rst [#78](https://github.com/jupyterlite/xeus-python-kernel/pull/78) ([@lesteve](https://github.com/lesteve)) 333 | 334 | ### Contributors to this release 335 | 336 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-08-30&to=2022-12-21&type=c)) 337 | 338 | [@JohanMabille](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AJohanMabille+updated%3A2022-08-30..2022-12-21&type=Issues) | [@jzavala-gonzalez](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajzavala-gonzalez+updated%3A2022-08-30..2022-12-21&type=Issues) | [@lesteve](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Alesteve+updated%3A2022-08-30..2022-12-21&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-08-30..2022-12-21&type=Issues) 339 | 340 | ## 0.5.6 341 | 342 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.5.5...fd6ab092a2820d3bd619792623d22599263ca580)) 343 | 344 | ### Bug fix 345 | 346 | - Fix caching issue [#73](https://github.com/jupyterlite/xeus-python-kernel/pull/73) ([@martinRenou](https://github.com/martinRenou)) 347 | 348 | ### Contributors to this release 349 | 350 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-08-17&to=2022-08-30&type=c)) 351 | 352 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-08-17..2022-08-30&type=Issues) 353 | 354 | ## 0.5.5 355 | 356 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.5.4...2e2458ec83390d03616c4a7bc2d96950cb6510fe)) 357 | 358 | ### Bugs fixed 359 | 360 | - Update jupyterlite [#68](https://github.com/jupyterlite/xeus-python-kernel/pull/68) ([@martinRenou](https://github.com/martinRenou)) 361 | 362 | ### Contributors to this release 363 | 364 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-08-16&to=2022-08-17&type=c)) 365 | 366 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-08-16..2022-08-17&type=Issues) 367 | 368 | ## 0.5.4 369 | 370 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.5.3...66ea4178110c6ce99dc75edaebe61164122ad85d)) 371 | 372 | ### Maintenance 373 | 374 | - Use file-loader for the png files [#65](https://github.com/jupyterlite/xeus-python-kernel/pull/65) ([@martinRenou](https://github.com/martinRenou)) 375 | 376 | ### Documentation 377 | 378 | - Docs: Disable other kernels [#64](https://github.com/jupyterlite/xeus-python-kernel/pull/64) ([@martinRenou](https://github.com/martinRenou)) 379 | 380 | ### Contributors to this release 381 | 382 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-08-05&to=2022-08-16&type=c)) 383 | 384 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-08-05..2022-08-16&type=Issues) 385 | 386 | ## 0.5.3 387 | 388 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.5.2...7d1a9e87d2ec0243ef871e07238fcd3602ad7878)) 389 | 390 | ### Enhancements made 391 | 392 | - Update to empack 1 with support for loading custom empack config [#62](https://github.com/jupyterlite/xeus-python-kernel/pull/62) ([@martinRenou](https://github.com/martinRenou)) 393 | 394 | ### Contributors to this release 395 | 396 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-08-04&to=2022-08-05&type=c)) 397 | 398 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-08-04..2022-08-05&type=Issues) 399 | 400 | ## 0.5.2 401 | 402 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.5.1...8901f99213d6eb01be6e06dd4ba35821972c2f5e)) 403 | 404 | ### Maintenance and upkeep improvements 405 | 406 | - Fix typo in `initFileSystem` method name [#52](https://github.com/jupyterlite/xeus-python-kernel/pull/52) ([@jtpio](https://github.com/jtpio)) 407 | 408 | ### Documentation improvements 409 | 410 | - Remove leading space in the replite default example [#49](https://github.com/jupyterlite/xeus-python-kernel/pull/49) ([@jtpio](https://github.com/jtpio)) 411 | 412 | ### Other merged PRs 413 | 414 | - Update empack to 0.8.2 [#59](https://github.com/jupyterlite/xeus-python-kernel/pull/59) ([@martinRenou](https://github.com/martinRenou)) 415 | - Remove print statement [#58](https://github.com/jupyterlite/xeus-python-kernel/pull/58) ([@martinRenou](https://github.com/martinRenou)) 416 | 417 | ### Contributors to this release 418 | 419 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-06-28&to=2022-08-04&type=c)) 420 | 421 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2022-06-28..2022-08-04&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-06-28..2022-08-04&type=Issues) 422 | 423 | ## 0.5.1 424 | 425 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.5.0...974e729e0a90981e7a7c11a2428c13730a4a8d90)) 426 | 427 | ### Bugs fixed 428 | 429 | - Add a deduplication phase that make sure the latest copied labextension is used [#46](https://github.com/jupyterlite/xeus-python-kernel/pull/46) ([@martinRenou](https://github.com/martinRenou)) 430 | - Fix plugin id [#43](https://github.com/jupyterlite/xeus-python-kernel/pull/43) ([@jtpio](https://github.com/jtpio)) 431 | 432 | ### Maintenance and upkeep improvements 433 | 434 | - Simplify the kernel spec [#44](https://github.com/jupyterlite/xeus-python-kernel/pull/44) ([@jtpio](https://github.com/jtpio)) 435 | 436 | ### Documentation improvements 437 | 438 | - Update README with config options [#45](https://github.com/jupyterlite/xeus-python-kernel/pull/45) ([@martinRenou](https://github.com/martinRenou)) 439 | - Build docs for 0.5.0 [#42](https://github.com/jupyterlite/xeus-python-kernel/pull/42) ([@martinRenou](https://github.com/martinRenou)) 440 | 441 | ### Contributors to this release 442 | 443 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-06-27&to=2022-06-28&type=c)) 444 | 445 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2022-06-27..2022-06-28&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-06-27..2022-06-28&type=Issues) 446 | 447 | ## 0.5.0 448 | 449 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.4.2...7c8676a97cf64b8c3d34bfa83de4536a86744358)) 450 | 451 | ### Enhancements made 452 | 453 | - Rename kernel to match classic xeus-python [#38](https://github.com/jupyterlite/xeus-python-kernel/pull/38) ([@martinRenou](https://github.com/martinRenou)) 454 | - Cleanup worker on dispose [#36](https://github.com/jupyterlite/xeus-python-kernel/pull/36) ([@martinRenou](https://github.com/martinRenou)) 455 | 456 | ### Bugs fixed 457 | 458 | - Fix post_build so that it populates the jupyter-lite.json properly [#40](https://github.com/jupyterlite/xeus-python-kernel/pull/40) ([@martinRenou](https://github.com/martinRenou)) 459 | 460 | ### Maintenance and upkeep improvements 461 | 462 | - Update empack [#39](https://github.com/jupyterlite/xeus-python-kernel/pull/39) ([@martinRenou](https://github.com/martinRenou)) 463 | 464 | ### Other merged PRs 465 | 466 | - Update docs so that it uses 0.4.2 [#31](https://github.com/jupyterlite/xeus-python-kernel/pull/31) ([@martinRenou](https://github.com/martinRenou)) 467 | 468 | ### Contributors to this release 469 | 470 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-06-21&to=2022-06-27&type=c)) 471 | 472 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2022-06-21..2022-06-27&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-06-21..2022-06-27&type=Issues) 473 | 474 | ## 0.4.2 475 | 476 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.4.1...782da3882c5797985fe40fa40c730c1e59e3d06a)) 477 | 478 | ### Bugs fixed 479 | 480 | - Fix temporary directories cleanup so that it happens after the tasks [#34](https://github.com/jupyterlite/xeus-python-kernel/pull/34) ([@martinRenou](https://github.com/martinRenou)) 481 | 482 | ### Contributors to this release 483 | 484 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-06-20&to=2022-06-21&type=c)) 485 | 486 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-06-20..2022-06-21&type=Issues) 487 | 488 | ## 0.4.1 489 | 490 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.4.0...ca6a45ea13d665865e76cbf4741b3c193002237e)) 491 | 492 | ### Bugs fixed 493 | 494 | - Make sure xeus-python kernel emscripten build runs after the FederatedExtension addon [#32](https://github.com/jupyterlite/xeus-python-kernel/pull/32) ([@martinRenou](https://github.com/martinRenou)) 495 | 496 | ### Contributors to this release 497 | 498 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-06-20&to=2022-06-20&type=c)) 499 | 500 | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-06-20..2022-06-20&type=Issues) 501 | 502 | ## 0.4.0 503 | 504 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/v0.3.0...0da0c11690c0d065c2f33b63d88064aec0b79529)) 505 | 506 | ### Enhancements made 507 | 508 | - Update jupyterlite and enable file-system access [#27](https://github.com/jupyterlite/xeus-python-kernel/pull/27) ([@martinRenou](https://github.com/martinRenou)) 509 | - Fix conflicts with sys prefix packages and ignore ignore_sys_prefix flag [#23](https://github.com/jupyterlite/xeus-python-kernel/pull/23) ([@martinRenou](https://github.com/martinRenou)) 510 | - Toplevel await [#25](https://github.com/jupyterlite/xeus-python-kernel/pull/25) ([@DerThorsten](https://github.com/DerThorsten)) 511 | - Make xeus-python version configurable [#24](https://github.com/jupyterlite/xeus-python-kernel/pull/24) ([@martinRenou](https://github.com/martinRenou)) 512 | - Fix hanging jupyterlite build via jupyterlite-sphinx [#21](https://github.com/jupyterlite/xeus-python-kernel/pull/21) ([@benbovy](https://github.com/benbovy)) 513 | 514 | ### Documentation improvements 515 | 516 | - Improve docs [#28](https://github.com/jupyterlite/xeus-python-kernel/pull/28) ([@martinRenou](https://github.com/martinRenou)) 517 | - Update docs using 0.3.0 [#19](https://github.com/jupyterlite/xeus-python-kernel/pull/19) ([@martinRenou](https://github.com/martinRenou)) 518 | 519 | ### Contributors to this release 520 | 521 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-05-24&to=2022-06-20&type=c)) 522 | 523 | [@benbovy](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Abenbovy+updated%3A2022-05-24..2022-06-20&type=Issues) | [@bollwyvl](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Abollwyvl+updated%3A2022-05-24..2022-06-20&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Adavidbrochart+updated%3A2022-05-24..2022-06-20&type=Issues) | [@DerThorsten](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3ADerThorsten+updated%3A2022-05-24..2022-06-20&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-05-24..2022-06-20&type=Issues) 524 | 525 | ## 0.3.0 526 | 527 | ([Full Changelog](https://github.com/jupyterlite/xeus-python-kernel/compare/8166fc63fd8b4f56b39431e810dabbeae842ea83...280c7c60b77d19a161de8256ccda7b77235f5690)) 528 | 529 | ### Merged PRs 530 | 531 | - Reduce sdist size [#17](https://github.com/jupyterlite/xeus-python-kernel/pull/17) ([@martinRenou](https://github.com/martinRenou)) 532 | - Update emsdk and empack [#16](https://github.com/jupyterlite/xeus-python-kernel/pull/16) ([@martinRenou](https://github.com/martinRenou)) 533 | - Remove duplication of the labextension [#15](https://github.com/jupyterlite/xeus-python-kernel/pull/15) ([@martinRenou](https://github.com/martinRenou)) 534 | - Rebuild with latest empack [#13](https://github.com/jupyterlite/xeus-python-kernel/pull/13) ([@martinRenou](https://github.com/martinRenou)) 535 | - Add back Changelog [#11](https://github.com/jupyterlite/xeus-python-kernel/pull/11) ([@martinRenou](https://github.com/martinRenou)) 536 | 537 | ### Contributors to this release 538 | 539 | ([GitHub contributors page for this release](https://github.com/jupyterlite/xeus-python-kernel/graphs/contributors?from=2022-05-19&to=2022-05-24&type=c)) 540 | 541 | [@jtpio](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3Ajtpio+updated%3A2022-05-19..2022-05-24&type=Issues) | [@martinRenou](https://github.com/search?q=repo%3Ajupyterlite%2Fxeus-python-kernel+involves%3AmartinRenou+updated%3A2022-05-19..2022-05-24&type=Issues) 542 | 543 | ## v0.2.0 544 | 545 | ### What's Changed 546 | 547 | - Add docs by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/4 548 | - Fix build by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/5 549 | - Add Matplotlib to the env by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/7 550 | - Do not use xeus-python's master branch by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/8 551 | - Simplify dockerfile by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/9 552 | - Xeus python build addon by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/10 553 | 554 | **Full Changelog**: https://github.com/jupyterlite/xeus-python-kernel/compare/0.1.0...0.2.0 555 | 556 | ## v0.1.0 557 | 558 | ### Contributions 559 | 560 | - Initial version by @DerThorsten in https://github.com/jupyterlite/xeus-python-kernel/commit/d28dbc1ec9c1dca3f861d79ee5930054c00d5998 561 | - Remove sleep + renames according to https://github.com/jupyter-xeus/xeus-python/pull/530 by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/1 562 | - Fix README by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/2 563 | - Add Docker build by @martinRenou in https://github.com/jupyterlite/xeus-python-kernel/pull/3 564 | 565 | ### Contributors 566 | 567 | - @DerThorsten started the project 568 | - @martinRenou made their first contribution in https://github.com/jupyterlite/xeus-python-kernel/pull/1 569 | 570 | **Full Changelog**: https://github.com/jupyterlite/xeus-python-kernel/commits/0.1.0 571 | --------------------------------------------------------------------------------