Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
Based on the V2 docs as of f3908e2c295ec9e4ad9da47541021af1c948b827 and
upstream MicroPython docs for the few modules we don't have micro:bit
docs for.

Updated after merge of bbcmicrobit/micropython#725

Some notes on discrepancies in discrepancies.md. I'll make more tweaks
as I get feedback on issues raised.

`builtins` contain too many symbols for MicroPython. I'll fix that by
comparing with the introspection results in a subsequent commit.
  • Loading branch information
microbit-matt-hillsdon committed Sep 8, 2021
0 parents commit 5bd0649
Show file tree
Hide file tree
Showing 81 changed files with 7,808 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run build --if-present
- run: npm test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/typeshed.json
/node_modules/
*.rst
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"python.formatting.provider": "black",
"python.analysis.typeshedPaths": [
"/Users/mth/Development/microbit-foundation/micropython-microbit-stubs/typeshed/"
],
"python.analysis.typeCheckingMode": "basic"
}
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# micro:bit MicroPython stubs for editor support

## Credit and licensing

builtins and utility definitions are derived from [typeshed](https://github.com/python/typeshed). Further work is required to review these to ensure that we don't have stubs for definitions MicroPython does not support. These stubs don't provide documentation.

MicroPython and micro:bit stubs are based on the restructured text documentation for [micro:bit](https://github.com/bbcmicrobit/micropython/tree/v2-docs) and, where not otherwise covered in micro:bit-specific docs, [MicroPython](https://github.com/micropython/micropython/tree/master/docs/library). These stubs provide documentation.

Typeshed is Apache 2.0 licensed.

MicroPython is MIT Licensed and Copyright (c) 2013-2021 Damien P. George.
MicroPython for the micro:bit is MIT licensed and Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers (see https://github.com/bbcmicrobit/micropython/blob/v2-docs/AUTHORS).

23 changes: 23 additions & 0 deletions browser-package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
"""
Outputs a JSON file containing all the stubs and a Pyright config file.
This is intended for web apps that need the stubs client side.
"""
import os
import json

results = dict(files={})
for (source, prefix) in (("typeshed", "/typeshed/"), ("config", "/src/")):
for (dirpath, dirnames, filenames) in os.walk(source):
for f in sorted(filenames):
path = os.path.join(dirpath, f)
destination = os.path.join(
prefix, os.path.join(*path.split(os.path.sep)[1:])
)
print(f"{path} -> {destination}")
text = open(path, "r").read()
results["files"][destination] = text

with open("typeshed.json", "w") as f:
f.write(json.dumps(results, indent=2))
9 changes: 9 additions & 0 deletions config/pyrightconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"pythonVersion": "3.6",
"pythonPlatform": "Linux",
"typeCheckingMode": "basic",
"typeshedPath": "/typeshed/",
"reportMissingModuleSource": false,
"reportWildcardImportFromLibrary": false,
"verboseOutput": true
}
116 changes: 116 additions & 0 deletions discrepancies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Notes

These are working notes on discrepancies found when creating these stubs.

## Cross-cutting issues

Module docs throughout are a bit arbitrary and need review.

Various docs don't line up exactly because @overload is the best way to represent their typings so requires docs to be customised for each scenario.

## Module-specific issues

### gc

isenabled is undocumented in MicroPython docs (not added).

### audio

[AudioFrame.copyfrom](https://github.com/microbit-foundation/micropython-microbit-v2/blob/bca4dc5690998e8e5de07019a44185fc9b9ea080/src/codal_port/modaudio.c#L301) is undocumented (not added).

AudioFrame implements some operations that aren't clearly documented (e.g. you can add them, multiple by an integer). I added stubs for these as they're used in examples.

### uart

uart.readinto is misindented in the docs (minor).
there's a method documented as having been removed so I've omitted it from the stubs

### microbit

- image - type of buffer in second __init__ option
- text modified to split across __init__ definitions
- "Same as" language is unhelpful.
- __sub__ and __div__ added based on examples but not in docs.
- microphone - the doc style here is a bit different to elsewhere, might be less good in Pyright?

### micropython

- schedule is undocumented (I've not added it)
- micropython.schedule is missing from our docs. Why? It is on the device (checked on V2).

### neopixel

Has long but important module docstring with important warnings for the user.
I've removed the images and reproduced it otherwise in full.

Some complication with write/show. Fine for stubs but will need revisiting for docs.

ws2812_write is undocumented (here and in microbit module)
ORDER is undocumented

### pins (in microbit)

get_analog_period_microseconds isn't documented

pin_logo isn't really a pin... it just has:
CAPACITIVE
RESISTIVE
is_touched
set_touch_mode
how to model this? currently incorrectly a touch pin.

pins need class docs

NO_PULL etc. aren't available on MicroBitDigitalPin. You need to use the instances
to access. Can/should we model this?

### machine

mem16
mem32
mem8
are undocumented

### os

ilistdir and stat are undocumented (not added)

### radio

In the docs and stubs but not on a V2 (V1 not checked):

```
>>> radio.RATE_250KBIT
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'RATE_250KBIT'
```

It's commented out in the source: https://github.com/microbit-foundation/micropython-microbit-v2/blame/eba8995843ebc7246765b364710543c9ffee344a/src/codal_port/modradio.c#L269

I've added a note to the docstring for now.

### microphone

```python
>>> from microbit import *
>>> repr(microphone.current_event())
'None'
>>> repr(microphone.current_event())
"SoundEvent('loud')"
```

but [docs](https://microbit-micropython.readthedocs.io/en/v2-docs/microphone.html#microbit.microphone.current_event) (and for now stubs) claim it cannot return None

Raised https://github.com/microbit-foundation/micropython-microbit-v2/issues/86

## Interesting code failures

In waveforms.py

```python
frames = [ None ] * 32
```

...is a problematic initialization pattern for arrays. Can we relax the rules?
Is the pattern widespread? What options does Pyright have to relax behaviour around None?
22 changes: 22 additions & 0 deletions examples/micropython/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers, as listed
in the accompanying AUTHORS file

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
35 changes: 35 additions & 0 deletions examples/micropython/analog_watch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from microbit import *

hands = Image.ALL_CLOCKS

#A centre dot of brightness 2.
ticker_image = Image("2\n").crop(-2,-2,5,5)

#Adjust these to taste
MINUTE_BRIGHT = 0.1111
HOUR_BRIGHT = 0.55555

#Generate hands for 5 minute intervals
def fiveticks():
fivemins = 0
hours = 0
while True:
yield hands[fivemins]*MINUTE_BRIGHT + hands[hours]*HOUR_BRIGHT
fivemins = (fivemins+1)%12
hours = (hours + (fivemins == 0))%12

#Generate hands with ticker superimposed for 1 minute intervals.
def ticks():
on = True
for face in fiveticks():
for i in range(5):
if on:
yield face + ticker_image
else:
yield face - ticker_image
on = not on

#Run a clock speeded up 60 times, so we can watch the animation.
for tick in ticks():
display.show(tick)
sleep(1000)
57 changes: 57 additions & 0 deletions examples/micropython/asmleds.py.todo
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""
This script uses the inline assembler to make the LEDs light up
in a pattern based on how they are multiplexed in rows/cols.
"""

# row pins: 13, 14, 15
# col pins: 4..12 inclusive
# GPIO words starting at 0x50000500:
# RESERVED, OUT, OUTSET, OUTCLR, IN, DIR, DIRSET, DIRCLR

@micropython.asm_thumb
def led_cycle():
b(START)

# DELAY routine
label(DELAY)
mov(r3, 0xa0)
lsl(r3, r3, 11)
label(delay_loop)
sub(r3, 1)
bne(delay_loop)
bx(lr)

label(START)

cpsid('i') # disable interrupts so we control the display

mov(r0, 0x50) # r0=0x50
lsl(r0, r0, 16) # r0=0x500000
add(r0, 0x05) # r0=0x500005
lsl(r0, r0, 8) # r0=0x50000500 -- this points to GPIO registers
mov(r1, 0b111)
lsl(r1, r1, 13) # r1=0xe000
str(r1, [r0, 8]) # pull all rows high

mov(r1, 1 << 4) # r1 holds current col bit
mov(r2, 9) # r2 holds number of cols left
label(loop_on)
str(r1, [r0, 12]) # pull col low to turn LEDs on
bl(DELAY) # wait
lsl(r1, r1, 1) # shift to next col
sub(r2, 1) # decrease col counter
bne(loop_on) # loop while there are still cols left

mov(r1, 1 << 4) # r1 holds current col bit
mov(r2, 9) # r2 holds number of cols left
label(loop_off)
str(r1, [r0, 8]) # pull col high to turn LEDs off
bl(DELAY) # wait
lsl(r1, r1, 1) # shift to next col
sub(r2, 1) # decrease col counter
bne(loop_off) # loop while there are still cols left

cpsie('i') # enable interrupts

for i in range(4):
led_cycle()
28 changes: 28 additions & 0 deletions examples/micropython/bubble_level_2d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Two-dimensional bubble level which uses the accelerometer.
"""

from microbit import *

sensitivity = "medium" # Change to 'low', 'medium', or 'high' to adjust
divisors = {"low": 64, "medium": 32, "high": 16}


def clamp(number, min, max):
"""Returns number limited to range specified by min and max, inclusive"""
if number < min:
return min
elif number > max:
return max
else:
return number


while True:
x_grav, y_grav, _ = accelerometer.get_values()
# Map raw values from accelerometer to pixels on display
x_pixel = 4 - clamp(2 + x_grav // divisors.get(sensitivity), 0, 4) # type: ignore
y_pixel = 4 - clamp(2 + y_grav // divisors.get(sensitivity), 0, 4) # type: ignore
display.clear()
display.set_pixel(x_pixel, y_pixel, 9)
sleep(100)
21 changes: 21 additions & 0 deletions examples/micropython/compass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
compass.py
~~~~~~~~~~
Creates a compass.
The user will need to calibrate the compass first. The compass uses the
built-in clock images to display the position of the needle.
"""
from microbit import *


# Start calibrating
compass.calibrate()

# Try to keep the needle pointed in (roughly) the correct direction
while True:
sleep(100)
needle = ((15 - compass.heading()) // 30) % 12
display.show(Image.ALL_CLOCKS[needle])
Loading

0 comments on commit 5bd0649

Please sign in to comment.