From 62336ec9a4b48b80a2d4852ab2f16ad3eeb35aaf Mon Sep 17 00:00:00 2001 From: qwertimer1 Date: Fri, 12 Mar 2021 22:10:36 +1100 Subject: [PATCH 1/3] Began adding support for %python and %%python magics --- circuitpython_kernel/kernel.py | 46 ++++++++++ examples/Using_magics.ipynb | 158 +++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 examples/Using_magics.ipynb diff --git a/circuitpython_kernel/kernel.py b/circuitpython_kernel/kernel.py index 0c364f5..0e8c91f 100644 --- a/circuitpython_kernel/kernel.py +++ b/circuitpython_kernel/kernel.py @@ -54,10 +54,49 @@ def is_magic(self, line): KERNEL_LOGGER.debug(f"upload_delay set to {float(s_line[1])} s") except TypeError: pass + elif line.startswith("%python"): + #python line magic, runs what ever is on the line following the %python magic. + code = line.lstrip("%python") + code = code.lstrip(' ') + for item in code.split(";"): + item = item.lstrip(' ') #remove leading white space + try: + print(eval(item)) #does not print + except: + out = exec(item) + if out != None: + print(out) #does not print + else: return False return True + def is_cell_magic(self, code): + """Cell magic to run python code. + ----- + Cell shall begin with %%python followed by a new line + Will iteratively run each line of code. + """ + + if code.startswith("%%python"): + code = code.lstrip("%%python") + code = code.lstrip(' ') + data = code.splitlines(True) + for item in data: + + code = code.lstrip(' ') #this removes all preceeding white space, + #i need to figure out how to get for loops, etc working + try: + print(eval(item)) #does not print + except: + out = exec(item) + + if out != None: + print(out) #does not print + return True + else: + return False + @classmethod def is_comment(cls, line): """Returns true if the line of code is empty or a comment. @@ -86,6 +125,13 @@ def run_code(self, code): """ # make sure we are connected to the board self.board.connect() + ##cell check for python cell magics + python_cell = self.is_cell_magic(code) + + if python_cell == True: + out = [] + err = [] + return out, err # Send code to board & fetch results (if any) after each line sent for line in code.splitlines(False): if not self.is_magic(line) and not self.is_comment(line): diff --git a/examples/Using_magics.ipynb b/examples/Using_magics.ipynb new file mode 100644 index 0000000..e12afca --- /dev/null +++ b/examples/Using_magics.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ordered-violence", + "metadata": {}, + "source": [ + "# Tutorial using the inbuilt magics %python and %%python" + ] + }, + { + "cell_type": "markdown", + "id": "micro-palestine", + "metadata": {}, + "source": [ + "Ipython magics allow many things to be done inside jupyter notebooks from running bash scripts to running interactive plotting tools.\n", + "This tutorial looks at implementing simple magics command which allows the user to run Python code in the notebook whilst also running circuit python.\n", + "The 2 magics that are available to the user are `%python` and `%%python`:\\\n", + "\n", + "`%python` : is a line magic allowing a single line of python code to be run following the `%python` keyword\\\n", + "`%%python` : is a cell magic allowing the user to run the whole cell in python, rather than circuitpython.\\\n", + "\n", + "\n", + "Below is a quick example of this in play." + ] + }, + { + "cell_type": "markdown", + "id": "smooth-wesley", + "metadata": {}, + "source": [ + "To begin with we can make sure we are using the circuit python kernel by checking the top left corner of the page." + ] + }, + { + "cell_type": "markdown", + "id": "studied-knowing", + "metadata": {}, + "source": [ + "To show that the system is connected to the circuitpython we run the below command." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "mineral-herald", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "print(os.uname())" + ] + }, + { + "cell_type": "markdown", + "id": "prepared-object", + "metadata": {}, + "source": [ + "We can see from above the system is connected to the microcontroller." + ] + }, + { + "cell_type": "markdown", + "id": "remarkable-change", + "metadata": {}, + "source": [ + "Following this we can run a python line magic to import a single library. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "worse-pipeline", + "metadata": {}, + "outputs": [], + "source": [ + "%python import numpy" + ] + }, + { + "cell_type": "markdown", + "id": "radical-breath", + "metadata": {}, + "source": [ + "This line magics still works when we string code together with semicolons. Which we can see in the following cell." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "current-creativity", + "metadata": {}, + "outputs": [], + "source": [ + "%python import numpy as np; a = 2; b = 4; np.sum((a,b))" + ] + }, + { + "cell_type": "markdown", + "id": "sixth-commitment", + "metadata": {}, + "source": [ + "We can also run cell magics by adding the `%%python` which we see in the cell below." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "divine-spread", + "metadata": {}, + "outputs": [], + "source": [ + "%%python\n", + "import nbdev\n", + "import numpy as np\n", + "a = 2\n", + "b = 4\n", + "np.sum((a,b))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "compliant-syracuse", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "demanding-dover", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "CircuitPython", + "language": "python", + "name": "circuitpython" + }, + "language_info": { + "codemirror_mode": { + "name": "python", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "pygments_lexer": "python3", + "version": "3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 42f35f43996789ccbdce482976c3944b585274b4 Mon Sep 17 00:00:00 2001 From: qwertimer1 Date: Fri, 12 Mar 2021 22:21:01 +1100 Subject: [PATCH 2/3] Fixed error --- examples/using_magics_and_nbdev.ipynb | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 examples/using_magics_and_nbdev.ipynb diff --git a/examples/using_magics_and_nbdev.ipynb b/examples/using_magics_and_nbdev.ipynb new file mode 100644 index 0000000..363fcab --- /dev/null +++ b/examples/using_magics_and_nbdev.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} From 88e89ca32974647f2441675d7cf197071c1f4f7a Mon Sep 17 00:00:00 2001 From: qwertimer1 Date: Fri, 12 Mar 2021 23:00:00 +1100 Subject: [PATCH 3/3] adding tutorial for nbdev in jupyter notebook for circuitpython development --- examples/using_magics_and_nbdev.ipynb | 181 +++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 2 deletions(-) diff --git a/examples/using_magics_and_nbdev.ipynb b/examples/using_magics_and_nbdev.ipynb index 363fcab..11471d8 100644 --- a/examples/using_magics_and_nbdev.ipynb +++ b/examples/using_magics_and_nbdev.ipynb @@ -1,6 +1,183 @@ { - "cells": [], - "metadata": {}, + "cells": [ + { + "cell_type": "markdown", + "id": "requested-binding", + "metadata": {}, + "source": [ + "# Creating a workflow for jupyter notebook with nbdev" + ] + }, + { + "cell_type": "markdown", + "id": "musical-label", + "metadata": {}, + "source": [ + "## Getting started" + ] + }, + { + "cell_type": "markdown", + "id": "subtle-franklin", + "metadata": {}, + "source": [ + "To begin with a note to all users, this tutorial is meant to be implemented in your own jupyter notebook following the steps provided here. Without undertaking the steps in your own environment the script wont work." + ] + }, + { + "cell_type": "markdown", + "id": "explicit-corrections", + "metadata": {}, + "source": [ + "To develop a workflow that allows us to run REPL based circuit python and then create a code.py file as well as any other assorted library, we utilise an excellent package known as nbdev. Developed by the team at fastai. To get this package first install nbdev from pip." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "sitting-enhancement", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install nbdev" + ] + }, + { + "cell_type": "markdown", + "id": "running-infrared", + "metadata": {}, + "source": [ + "## Create repository\n", + "Once installed the next step is to create a new repo from the nbdev template https://github.com/fastai/nbdev_template/generate. (You need to be logged in to github). Fill in the requested info and click Create repository from template.\n", + "\n", + "## Edit settings.ini\n", + "\n", + "You will need to add some information to the settings.ini file to get the system working. Each setting can be changed as needed for your project\n", + "\n", + "```\n", + "# lib_name = your_project_name\n", + "# repo_name = name of github repo\n", + "# user = your_github_username\n", + "# description = A description of your project\n", + "# keywords = some keywords\n", + "# author = Your Name\n", + "# author_email = email@example.com\n", + "# copyright = Your Name or Company Name\n", + "# branch = The default branch of your GitHub repo (usually either master or main)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "senior-ownership", + "metadata": {}, + "source": [ + "## Build your first notebook" + ] + }, + { + "cell_type": "markdown", + "id": "minimal-palestinian", + "metadata": {}, + "source": [ + "Once done we can run jupyter notebook/lab. and open 00_core.ipynb. You will notice at the top the notebook says\n", + "`#default_exp core` Change this to `#default_exp code`, this creates a name for your main py file for the circuit python." + ] + }, + { + "cell_type": "markdown", + "id": "atmospheric-disclaimer", + "metadata": {}, + "source": [ + "Inside the notebook we want to change the kernel to CircuitPython by going to the Kernel tab and changing to the circuitpython kernel. Once done we can begin coding our circuit python library." + ] + }, + { + "cell_type": "markdown", + "id": "pending-christian", + "metadata": {}, + "source": [ + "To begin with we can place this python cell magic below the `default_exp` line to allow auto scripting of the notebook at any stage." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "standing-alliance", + "metadata": {}, + "outputs": [], + "source": [ + "%%python\n", + "from nbdev.export import notebook2script; notebook2script()" + ] + }, + { + "cell_type": "markdown", + "id": "gentle-syria", + "metadata": {}, + "source": [ + "The `%%python` magic runs everything in the cell. In this situation we could also run `%python from nbdev.export import notebook2script; notebook2script()` and it would still run the same." + ] + }, + { + "cell_type": "markdown", + "id": "discrete-afghanistan", + "metadata": {}, + "source": [ + "After this we are free to run whatever code we wish. To create exportable function or class blocks we add the `#export` keyword to the top of the cell. This tells nbdev.export which functions to search for in the notebook. \n", + "\n", + "The below code is for a simple blink script for the raspberrypi pico" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "entitled-protection", + "metadata": {}, + "outputs": [], + "source": [ + "#export\n", + "import time\n", + "import os\n", + "import board\n", + "import digitalio\n", + "led = digitalio.DigitalInOut(board.LED)\n", + "led.direction = digitalio.Direction.OUTPUT\n", + "for i in range(4):\n", + " led.value = True\n", + " time.sleep(0.5)\n", + " led.value = False\n", + " time.sleep(0.5)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "tough-wayne", + "metadata": {}, + "source": [ + "There are many more things we can begin to do with this development pipeline. But for now we are able to play with the repl environment and save our code to a code.py file. One final thing to note as of now we still have to manually move our file to the circuitpython microcontroller." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "CircuitPython", + "language": "python", + "name": "circuitpython" + }, + "language_info": { + "codemirror_mode": { + "name": "python", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "pygments_lexer": "python3", + "version": "3" + } + }, "nbformat": 4, "nbformat_minor": 5 }