From 26ea6ca204919367515d1f88e21596c4a810b201 Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Wed, 1 Jul 2020 08:40:40 -0700 Subject: [PATCH] Add Binder support for easier experimenting/testing/discussion (#117) Co-authored-by: Chris Holdgraf Co-authored-by: Matthias Bussonnier --- README.md | 2 + binder/README.md | 32 +++++++++ binder/apt.txt | 24 +++++++ binder/postBuild | 44 ++++++++++++ binder/workspace.json | 1 + playground-622.ipynb | 158 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 261 insertions(+) create mode 100644 binder/README.md create mode 100644 binder/apt.txt create mode 100644 binder/postBuild create mode 100644 binder/workspace.json create mode 100644 playground-622.ipynb diff --git a/README.md b/README.md index fffd22e..f3ddbd8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Pattern Matching ================ +[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/gvanrossum/patma/master?urlpath=lab/tree/playground-622.ipynb) + This repo contains an issue tracker, examples, and early work related to [PEP 622: Structural Pattern Matching](https://www.python.org/dev/peps/pep-0622). Updates to the PEP itself should be made in the diff --git a/binder/README.md b/binder/README.md new file mode 100644 index 0000000..13e79ec --- /dev/null +++ b/binder/README.md @@ -0,0 +1,32 @@ +# Binder support for PEP-622 examples + +This directory offers [Binder](https://mybinder.org) support for these [PEP-622](https://www.python.org/dev/peps/pep-0622) examples, which depend on a currently experimental build of Python 3.10. It is intended to facilitate testing and discussion of this proposed change to Python so that users can play with the proposed syntax without having to build and install everything themselves. + +This directory contains all the necessary tools for Binder support, all other content related to PEP-622 is in the rest of the repo and doesn't need binder. This repo uses two binder tools for setup: + +1. An `apt.txt` file listing useful packages needed for the build. +2. A `postBuild` script that builds/installs CPython 3.10 from the right branch and then updates that installation with some necessary dependencies for testing/running the examples. + + +## Build notes + +Since testing the pattern matching features requires a custom Python build, we start from a standard Binder image and then build Python 3.10 in the container. Python 3.10 is new enough that we need to build PyZMQ from the master branch, and use IPython master to have a 3.10-based kernel for Jupyter, and tab completion will not be working until a fix is done upstream in _parso_ which his used for jedi. But we can still use 3.10 at the command-line to test the examples, and take advantage of the JupyterLab UI for easy experimentation (terminals, text editors, etc). + +The [experimental build of CPython 3.10](https://github.com/brandtbucher/cpython) (branch `patma`) needed for this is installed in `$HOME/.local/bin`, and the source of the build is available in `/tmp/cpython`, in case the user wants to experiment with it. + +The build dependencies listed in apt.txt can be found by using the `apt-rdepends` package: + +``` +apt-rdepends --build-depends --follow=DEPENDS python3-defaults | grep Build-Depends | awk -F ' +' '{print $3}' +``` + +Normally this container will run automatically and provide a usable URL with Jupyter in it if `jupyter-repo2docker .` is run at the top of the repository. But if anything goes wrong and you need to debug, you can find the image ID of the repo with `docker images` and then run it interactively (with root privileges) by using: + +``` +docker run --interactive --tty --entrypoint=/bin/bash -e GRANT_SUDO=yes --user root --login +``` + + +## ToDo + +As IPython, pyzmq and other dependencies are released with Python 3.10 compatibility, this repo can be updated to have a proper 3.10 kernel using released versions. diff --git a/binder/apt.txt b/binder/apt.txt new file mode 100644 index 0000000..ca94d3a --- /dev/null +++ b/binder/apt.txt @@ -0,0 +1,24 @@ +# Python3 build dependencies, generated via (note that to run this, apt-rdepends +# needs to be installed first): +# apt-rdepends --build-depends --follow=DEPENDS python3-defaults | grep Build-Depends | awk -F ' +' '{print $3}' + +debhelper +docbook-xml +docbook-xsl +dpkg-dev +lsb-release +python3-docutils +python3-minimal +python3.8 +w3m +xsltproc + +# Working tools for minimal dev work + +build-essential +emacs-nox +vim-tiny +git +python3 +python3-dev +ca-certificates diff --git a/binder/postBuild b/binder/postBuild new file mode 100644 index 0000000..71a121c --- /dev/null +++ b/binder/postBuild @@ -0,0 +1,44 @@ +#!/bin/bash + +# Update to a current JupyterLab for a better user experience +conda update jupyterlab + +# Binder repo post-build script to deploy the resulting container with a custom +# build of Python 3.10 that can be used to test PEP 622. +# More here: https://www.python.org/dev/peps/pep-0622 + +# Get correct branch of CPython to test PEP 622 with +cd /tmp +git clone https://github.com/brandtbucher/cpython.git +cd cpython +git checkout --track remotes/origin/patma + +# Build Python to go into $HOME/.local +export $PATH=$HOME/.local/bin:$PATH + +# The usual `onfigure, make, make install` dance +./configure --prefix=$HOME/.local && make -j && make install + +# Remove the 'python3' binary to avoid accidental collisions with the system +# one. On the filesystem, this python will only be accessible as 'python3.10' +# or via the convenience symlink 'py10'. +rm $HOME/.local/bin/python3 +ln -s $HOME/.local/bin/python3.10 $HOME/.local/bin/py10 + +# For interactive usage we also make 'python' point to the new 3.10 +echo 'alias python=python3.10' >> ~/.bashrc + +# Add the patma repo requirements packages so the repo is ready to use +python3.10 -m pip install -r $HOME/requirements.pip + +# Install IPython as kernel with our 3.10 Python. Note - currently this +# requires builds from master of both ipython and pyzmq. +python3.10 -m pip install git+https://github.com/ipython/ipython +python3.10 -m pip install Cython +python3.10 -m pip install git+https://github.com/zeromq/pyzmq + +python3.10 -m pip install ipykernel +python3.10 -m ipykernel install --user + +# Setup a workspace +jupyter lab workspaces import ~/binder/workspace.json diff --git a/binder/workspace.json b/binder/workspace.json new file mode 100644 index 0000000..12a37a3 --- /dev/null +++ b/binder/workspace.json @@ -0,0 +1 @@ +{"data":{"layout-restorer:data":{"main":{"dock":{"type":"tab-area","currentIndex":2,"widgets":["markdownviewer-widget:README.md","markdownviewer-widget:EXAMPLES.md","notebook:playground-622.ipynb"]},"mode":"multiple-document","current":"notebook:playground-622.ipynb"},"left":{"collapsed":false,"current":"filebrowser","widgets":["filebrowser","running-sessions","command-palette","jp-property-inspector","tab-manager","juputerlab-toc","extensionmanager.main-view"]},"right":{"collapsed":true,"widgets":[]}},"@jupyterlab/settingeditor-extension:plugin":{"sizes":[0.25,0.75],"container":{"editor":"raw","plugin":"@jupyterlab/terminal-extension:plugin","sizes":[0.5,0.5]}},"markdownviewer-widget:EXAMPLES.md":{"data":{"path":"EXAMPLES.md","factory":"Markdown Preview"}},"markdownviewer-widget:README.md":{"data":{"path":"README.md","factory":"Markdown Preview"}},"notebook:playground-622.ipynb":{"data":{"path":"playground-622.ipynb","factory":"Notebook"}}},"metadata":{"id":"/lab"}} diff --git a/playground-622.ipynb b/playground-622.ipynb new file mode 100644 index 0000000..7261f1a --- /dev/null +++ b/playground-622.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A PEP 622 Playground\n", + "\n", + "The purpose of this notebook is to facilitate interactive exploration of the proposed new syntax for _Structural Pattern Matching_ in Python 3.10, as described in [PEP-622](https://www.python.org/dev/peps/pep-0622).\n", + "\n", + "This notebook should be run with a kernel that uses a suitable version of Python with support for this PEP's new syntax. We start by making a quick sanity check that we're running at least version 3.10 of Python, if that's not the case you need to check your runtime environment.\n", + "\n", + "_Note:_ If you are new to Jupyter Notebooks, code cells (like the one below) can be executed by typing `Shift-Enter` inside the cell, or by using the \"play\" button (right-pointing triangle in the toolbar above)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "assert sys.version_info[:2] >= (3, 10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With that out of the way, let's introduce a very basic example that illustrates the syntax (and whether the cell below runs cleanly will be a good test that you have the right version of Python installed).\n", + "\n", + "We define a `dataclass` called `Point`, and a `whereis` function that matches points in different parts of the x-y plane:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from dataclasses import dataclass\n", + "\n", + "@dataclass\n", + "class Point:\n", + " x: int\n", + " y: int\n", + "\n", + "def whereis(point):\n", + " match point:\n", + " case Point(0, 0):\n", + " print(\"Origin\")\n", + " case Point(0, y):\n", + " print(f\"Y={y}\")\n", + " case Point(x, 0):\n", + " print(f\"X={x}\")\n", + " case Point():\n", + " print(\"Somewhere else\")\n", + " case _:\n", + " print(\"Not a point\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this definition we can now test various kinds of points:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "X=1\n" + ] + } + ], + "source": [ + "whereis(Point(1, 0))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Origin\n" + ] + } + ], + "source": [ + "whereis(Point(0, 0))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Not a point\n" + ] + } + ], + "source": [ + "whereis(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Now start playing!\n", + "\n", + "You can explore these ideas further below. The `examples` directory contains some more sample code that you can run at the terminal (you can open a new terminal with the '+' icon or from the File menu), or you can try your own. The PEP contains full details on the syntax." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.0a0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}