MicroPython for Microcontrollers Module 14 – Versions: what changed and MicroPython 2.0
What changed in 1.24 to 1.29, and MicroPython 2.0
The MicroPython 1.24 to 1.29 changes that break existing code, how to find the ones for your board, and how to make the vfs move of MicroPython 2.0 today.
What you will learn
- Find the release notes and the versioned documentation that matter for your code and board
- Update code for the seven breaking changes between MicroPython 1.24 and 1.29
- Choose between a feature probe and a version check for a change between releases
- Prepare code for MicroPython 2.0 by importing mount and the Vfs classes from vfs
Before you start
What you’ll learn · Before you start
What you will learn
- Find the release notes and the versioned documentation that matter for your code and board
- Update code for the seven breaking changes between MicroPython 1.24 and 1.29
- Choose between a feature probe and a version check for a change between releases
- Prepare code for MicroPython 2.0 by importing mount and the Vfs classes from vfs
Before you start
On this page
Six MicroPython releases, 1.24 to 1.29, brought hundreds of changes, and seven of them can break code that worked
the day before: a sys.exit() that now restarts the board, an encoding name that now raises LookupError, an SD card
call whose return value turned its meaning around. Behind them MicroPython 2.0 is taking shape, with one API move
announced so far.
This lesson shows where a release’s notes put the changes for your board, walks through the seven breaking changes with the fix for each, separates the features you probe for from the behaviour you check by version, and makes the vfs move of 2.0 in code that runs on today’s releases.
Release notes put the breaking changes first, then every change by port
Each release has its notes on GitHub, under the tag of its version, such as v1.29.0. They open with an overview:
the new features, then a paragraph for each port that changed. Release 1.29 adds a section of its own for breaking
changes; earlier releases name theirs inside the overview, which makes them easy to miss. A table of firmware sizes
follows, and then the full list of changes, sorted by component: the core under “py core” and “extmod”, then
documentation, tests and tools, and at the end one block per port, “rp2 port”, “esp32 port” and so on. For code on one
board, read the overview, the breaking changes, and the blocks of the core and of your port.
Walk through the six releases of this lesson and the version after them:
- 1.24
RP2350 and ESP32-C6, and a soft reset on sys.exit() breaking change
Support for the RP2350 and the ESP32-C6, a RISC-V native emitter, network.ipconfig(), UART interrupts that behave alike across ports, and mpremote sha256sum with copies that skip unchanged files. Breaking: sys.exit() now soft-resets the board instead of dropping to the REPL.
- 1.25
ROMFS and the RISC-V inline assembler
The ROMFS filesystem with mpremote romfs, @micropython.asm_rv32, DTLS in the tls module, mpremote rm -r, and sys.implementation._build. Bus numbers became optional for I2C and SPI on rp2 and for I2C on esp32, and on stm32 buses are now released at a soft reset.
- 1.26
machine.I2CTarget and better floats
Python code can act as an I2C device, floats print in a form that reads back to the same value far more often, native code got faster, and assigning to a bytearray or memoryview slice no longer allocates. On ESP32 the vfs area is sized at start-up and PCNT, Counter and Encoder arrived.
- 1.27
Support tiers, ESP32-C5 and ESP32-P4
Every port now has a support tier. The ESP32-C5 and ESP32-P4 joined, the unix and windows ports gained the raw REPL, and most ports except esp32 gained hard callbacks for machine.Timer.
- 1.28
machine.CAN, PWM everywhere and t-strings
The machine.CAN class arrived with an stm32 implementation, PWM now works on every Tier 1 and Tier 2 microcontroller port, t-strings arrived at the full feature level, and weakref on the webassembly PyScript variant.
- 1.29
mem_backup(), c_module() and stricter text breaking change
machine.mem_backup(), c_module() in manifests, decoding errors "ignore" and "replace", TLS-PSK, a codeberg: alias in mpremote, and const() with type hints. Breaking: only utf-8 and ascii encodings; SDCard readblocks() and writeblocks() return 0 or a negative errno on esp32 and stm32; sys.platform is "nrf" on every nrf board; stm32 stm names drop _S and _NS.
- 2.0
In development, with no builds to download planned
The migration guide lists one change so far, the move of os.mount, os.umount and the Vfs classes into the vfs module, and goals for consistent machine APIs and for running .mpy files in place from the filesystem.
The timeline has 7 events, from 1.24 to 2.0.
The documentation is versioned too. docs.micropython.org/en/v1.29.0/ describes exactly that release, while
/en/latest/ follows the development branch, so link and read the version your boards run. On the board,
sys.implementation.version says which release it is, (1, 29, 0, '') for 1.29.0, a tuple that compares correctly.
Comparing versions as strings
os.uname().release >= "1.24" is true on 1.9.4, because strings compare letter by letter and “9” comes after “2”.
Compare tuples: sys.implementation.version >= (1, 24).
Checkpoint
Check: Reading release notes and versioned docs
Seven changes from 1.24 to 1.29 break code that worked before
These are the changes the release notes themselves call breaking change: A change in a new release after which code that worked before fails or behaves differently, without being changed itself. Release notes call such changes out so that they can be fixed before an upgrade. that reach Python code, with what each asks of it:
| Release | What changed | What to do |
|---|---|---|
| 1.24 | sys.exit() and raise SystemExit soft-reset the board, where they used to return to the REPL |
Stop a program by returning from its main function, never with sys.exit() in main.py |
| 1.25 | stm32 releases I2C and SPI buses at a soft reset | Create and initialise every bus when the program starts |
| 1.26 | nrf: enable_irq(state) takes the value disable_irq() returned |
Pass the state, as on every other port |
| 1.29 | Only “utf-8”, “utf8” and “ascii” are accepted as encodings; others raise LookupError instead of decoding as UTF-8 |
Fix the name, or decode Latin-1 by hand |
| 1.29 | esp32 and stm32: SDCard.readblocks() and writeblocks() return 0 or a negative number, no longer True on success |
Check results with a helper that works with both |
| 1.29 | sys.platform is “nrf” on every nrf board |
Test sys.platform == "nrf", and name the board with sys.implementation._machine |
| 1.29 | stm32 boards with Cortex-M33 or M55 cores: stm register names lose _S and _NS, so stm.RTC_S becomes stm.RTC |
Use the name without the ending; the firmware picks the secure or non-secure address |
The 1.29 section lists three more, for people who build firmware or write C rather than Python: the unix port’s
MICROPY_FORCE_32BIT option is gone, the powerpc port is merged into qemu, and stm32’s C function rng_get() is
renamed.
The 1.24 change is the one that turns a program into a reboot loop: a main.py that calls sys.exit() when a
sensor is missing now restarts, finds the sensor missing again and restarts again. The SD card change is the subtle
one. Code that checked if card.writeblocks(n, buf): now reads success, 0, as failure. And the first fix that comes
to mind is wrong in a way the trace shows:
Program · compat/sdcard_bug.py
for r in (True, False, 0, -5):
ok = r == 0 or r is True
print(r, ok) Variables
- just taken by the loop
- changed in this step
- passed by the loop
- read next
- where the loop stopped
Printed so far
Nothing printed yetTrue True False True 0 True -5 False
Every step was recorded from a run with Python 3.14.8 on macOS 26 arm64.
The drawing shows the variables when the program ends, and the program's 14 steps are listed below.
Change the program and run it here. Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Every step as text
- Start. No line has run yet, so there are no variables. Python starts with line 1.
- Line 1.
for r in (True, False, 0, -5):takes the item at position 0 of(True, False, 0, -5):risTrue. - Line 2.
ok = r == 0 or r is TruesetsoktoTrue. True, a success before 1.29, is not 0, so the check goes on to r is True and accepts it. - Line 3.
print(r, ok)printsTrue True. - Line 1.
for r in (True, False, 0, -5):takes the item at position 1 of(True, False, 0, -5):risFalse. - Line 2.
ok = r == 0 or r is Trueokkeeps its value,True. The bug False is a failure before 1.29, but False == 0 is true in Python, because bool is a kind of int: the failed write counts as a success. - Line 3.
print(r, ok)printsFalse True. - Line 1.
for r in (True, False, 0, -5):takes the item at position 2 of(True, False, 0, -5):ris0. - Line 2.
ok = r == 0 or r is Trueokkeeps its value,True. - Line 3.
print(r, ok)prints0 True. - Line 1.
for r in (True, False, 0, -5):takes the item at position 3 of(True, False, 0, -5):ris-5. - Line 2.
ok = r == 0 or r is TruesetsoktoFalse(it wasTrue). -5, a negative errno from 1.29, is neither 0 nor True, so it is reported as the failure it is. - Line 3.
print(r, ok)prints-5 False. - Line 1.
for r in (True, False, 0, -5):finds no item at position 4 of(True, False, 0, -5)(it has 4 items), so the loop ends. That was the last line, so the program ends. Three of the four answers are right and the one that matters most, a failed write, is wrong. Test is True and is False before comparing with 0.
r == 0 or r is True called a failed write of an old firmware, False, a success, because in Python False == 0.
The working check tests the two booleans first, then the number. The program below runs that check, the Latin-1
decoder and the vfs choice of the next sections, from one small module:
compat/what_changed.py
"""The compat module beside this file on three builds, imitated with their version tuples and their vfs module."""
import sys
import types
import compat
builds = {"1.22.2": (1, 22, 2, ""), "1.26.0": (1, 26, 0, ""), "1.29.0": (1, 29, 0, "")}
for name, ver in builds.items():
impl = types.SimpleNamespace(name="micropython", version=ver)
sys.modules["vfs"] = types.ModuleType("vfs") if ver >= (1, 23) else None # None: import vfs fails
print(name, "mount from", compat.load_vfs().__name__, end="; ")
try:
compat.requires((1, 26), "a slice assignment in a hard IRQ", impl=impl)
print("the IRQ handler may run")
except RuntimeError as e:
print(e)
for r in (True, False, None, 0, -5):
print("SDCard returned", repr(r), "-> ok:", compat.blocks_ok(r))
print(compat.latin1(b"Caf\xe9 at 21\xb0C"), "from Latin-1 bytes") Output
1.22.2 mount from os; a slice assignment in a hard IRQ needs MicroPython 1.26 or later, this is 1.22.2 1.26.0 mount from vfs; the IRQ handler may run 1.29.0 mount from vfs; the IRQ handler may run SDCard returned True -> ok: True SDCard returned False -> ok: False SDCard returned None -> ok: True SDCard returned 0 -> ok: True SDCard returned -5 -> ok: False Café at 21°C from Latin-1 bytes
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 what_changed.py
compat/compat.py
"""Calls that changed between MicroPython 1.24 and 1.29, and the 2.0 move of mount, made to work on every build."""
import sys
def load_vfs():
"""The module that holds mount(): vfs on 1.23 and later, the only place in 2.0; os on older builds."""
try:
import vfs
return vfs
except ImportError:
import os
return os
vfs = load_vfs()
def version(impl=None):
return tuple((impl or sys.implementation).version[:3])
def requires(minimum, name="this code", impl=None):
"""Raise a clear error on a build older than minimum, a tuple such as (1, 26)."""
have = version(impl)
if have < tuple(minimum):
raise RuntimeError("%s needs MicroPython %s or later, this is %s"
% (name, ".".join(map(str, minimum)), ".".join(map(str, have))))
def blocks_ok(result):
"""True when a block device read or write succeeded: True (esp32 and stm32 SDCard before 1.29), None or 0."""
if result is True or result is None: # test the bools first: False == 0 in Python
return True
if result is False:
return False
return result == 0 # from 1.29: 0, or a negative errno
def latin1(data):
"""Decode Latin-1 bytes by hand: 1.29 accepts only utf-8 and ascii, and raises LookupError for the rest."""
return "".join(chr(b) for b in data) # every Latin-1 byte is the code point of the same number Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
blocks_ok() accepts True, None and 0 as success and False and negative numbers as failure, so the same logger
runs on 1.28 and on 1.29. latin1() works because every Latin-1 byte is the Unicode code point of the same number,
so chr() of each byte decodes it, and b"Caf\xe9" becomes “Café” on a release that refuses the encoding name.
Testing a result that may be a bool against 0
if result == 0: is also true for False. Whenever a call may return a bool on one version and a number on
another, test is True and is False first.
Checkpoint
Check: The breaking changes of 1.24 to 1.29
Probe for new features; check the version only for changed behaviour
The feature-levels lesson’s rule holds across releases: ask the build for a feature with a feature probe: A short test a program runs to find out whether the Python under it has a feature: it compiles a snippet of new syntax, tries an import or looks up an attribute, inside try and except, and uses the answer to choose a code path. More in “Which Python is this? Feature levels and probes” instead of guessing from its version, because a release may leave a feature out of a smaller build. Most of the additions of 1.24 to 1.29 can be probed in one line:
| Added in | Feature | Probe |
|---|---|---|
| 1.24 | network.ipconfig() |
hasattr(network, "ipconfig") |
| 1.26 | machine.I2CTarget |
hasattr(machine, "I2CTarget") |
| 1.26 | machine.Counter, machine.Encoder on ESP32 |
hasattr(machine, "Counter") |
| 1.28 | machine.CAN, first on stm32 |
hasattr(machine, "CAN") |
| 1.28 | t-strings, at the full feature level | compile('t"x"', "probe", "eval") in a try |
| 1.29 | machine.mem_backup() |
hasattr(machine, "mem_backup") |
| 1.29 | rp2.DMATimer |
hasattr(rp2, "DMATimer") |
Some changes have nothing to probe: the code is the same and only its behaviour differs. Since 1.26, assigning to a
slice of a bytearray or memoryview no longer allocates, so it works in a hard interrupt handler with the heap
locked; before 1.26 the same line raised MemoryError there. For such a change, compare the version once at start-up
and fail clearly, as requires((1, 26), ...) in the compat module does: on the 1.22.2 build it raised an error that
names both versions.
Key idea
A feature that may be missing is a question for the build, answered by a probe; a behaviour that changed is a
question of the release, answered by sys.implementation.version.
Checkpoint
Check: Probes against version checks
MicroPython 2.0 moves mount into vfs, and you can move today
MicroPython 2.0 is the next major release, still in development, with no firmware to download; the migration guide
says it can be built by enabling MICROPY_PREVIEW_VERSION_2. Its goals are consistent machine APIs across ports,
running .mpy files straight from the filesystem without copying them into RAM, more flexible partitions, and code
that works on CPython and MicroPython alike. One change is listed so far: six names leave os for the vfs module.
The table shows where each of them lives, before, during and after the move:
| Names | Before 1.23 | 1.23 to 1.29 | 2.0 |
|---|---|---|---|
mount(), umount() |
os |
vfs, and os for old code |
vfs only |
VfsFat, VfsLfs1, VfsLfs2 |
os |
vfs, and os for old code |
vfs only |
VfsPosix |
os |
vfs, and os for old code |
vfs only |
The column for 1.23 to 1.29 is why the move can happen today: both modules answer there, and the os documentation
of 1.29 keeps the names in os only for backwards compatibility. So import them from vfs now. compat.load_vfs() tries
import vfs and falls back to os on builds older than 1.23, and the program above showed it: mount came from os
on the 1.22.2 build and from vfs on 1.26.0 and 1.29.0. Code written this way runs unchanged on every 1.x release
since 1.23 and on 2.0.
Watch the guide, not only the notes
The migration guide is not final: new items will appear there before 2.0 ships. Read it in the documentation of each new release, and move code as items appear, while both forms still work.
Checkpoint
Check: MicroPython 2.0 and the vfs move
Practise: a compat module for MicroPython 1.20 to 1.29
Write the three functions a fleet of boards on mixed releases needs: a version requirement with a clear error, a
choice between vfs and os, and a check of block-device results that works on both sides of 1.29. The sample
tests pass fake modules and version tuples instead of a board:
Exercise · Easy · Python
A compat module for MicroPython 1.20 to 1.29
Write the three functions of compat.py, which let one codebase run on boards from MicroPython 1.20 to 1.29.
requires(minimum, version, name="this code") takes two version tuples, such as (1, 26) and (1, 24, 1, ""), and raises RuntimeError when the version is older than the minimum; the message names both, as in "I2CTarget needs MicroPython 1.26 or later, this is 1.24.1". Compare only the first three numbers of version.
pick_vfs(found) takes a dict of what import found on the board, {"vfs": module or None, "os": module}, and returns the module to call mount() on: found["vfs"] when it is not None, otherwise found["os"] if it has a mount attribute, otherwise it raises ImportError.
blocks_ok(result) says whether a block device read or write succeeded on either side of 1.29: True, None and 0 mean success; False and negative numbers mean failure.
Starter code · compat.py
def requires(minimum, version, name="this code"):
"""Raise RuntimeError when version is older than minimum."""
def pick_vfs(found):
"""The module that holds mount(): vfs if present, else os if it has mount."""
return found["os"]
def blocks_ok(result):
"""True when a block device read or write succeeded, before or after 1.29."""
return result == 0 The sample tests · test_compat.py
import types
from compat import blocks_ok, pick_vfs, requires
def test_requires_passes():
"""allows the minimum and later versions"""
requires((1, 26), (1, 26, 0, ""))
requires((1, 26), (1, 29, 0, ""))
def test_requires_refuses():
"""refuses an older version with both versions in the message"""
try:
requires((1, 26), (1, 24, 1, ""), "I2CTarget")
except RuntimeError as e:
assert str(e) == "I2CTarget needs MicroPython 1.26 or later, this is 1.24.1"
else:
raise AssertionError("no RuntimeError")
def test_requires_not_strings():
"""compares numbers, so 1.9 is older than 1.24"""
try:
requires((1, 24), (1, 9, 4, ""))
except RuntimeError:
return
raise AssertionError("1.9.4 passed as 1.24 or later")
def test_pick_vfs():
"""prefers vfs, falls back to an os that has mount, and refuses otherwise"""
vfs = types.SimpleNamespace(mount=lambda *a: None)
old_os = types.SimpleNamespace(mount=lambda *a: None)
cpython_os = types.SimpleNamespace()
assert pick_vfs({"vfs": vfs, "os": old_os}) is vfs
assert pick_vfs({"vfs": None, "os": old_os}) is old_os
try:
pick_vfs({"vfs": None, "os": cpython_os})
except ImportError:
return
raise AssertionError("no ImportError")
def test_blocks_ok():
"""accepts both conventions and never mistakes False for 0"""
assert [blocks_ok(r) for r in (True, None, 0)] == [True, True, True]
assert [blocks_ok(r) for r in (False, -5, -110)] == [False, False, False] A hint
Tuples compare item by item, so tuple(version[:3]) < tuple(minimum) is the whole test; join the numbers with ".".join(map(str, ...)) for the message. In blocks_ok(), check result is True, result is None and result is False before you compare with 0.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Then check yourself on release notes, breaking changes, probes and 2.0:
Practice that adapts to you
Practise this lesson
8 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up (fresher): Where do you look to see what changed in a MicroPython release for your board?
Open the release’s notes on GitHub, under the tag of the version, such as v1.29.0. Read the overview, the breaking
changes, which 1.29 lists in a section of its own and earlier releases inside the overview, and in the detailed list
the blocks for the core, “py core” and “extmod”, and for your port, such as “rp2 port”. Then read the documentation of
that exact version at docs.micropython.org/en/v1.29.0/ rather than the latest, and check on the board with
sys.implementation.version which release it really runs.
Warm-up (fresher): What does MicroPython 2.0 change so far, and how can code prepare for it?
MicroPython 2.0 is still in development and has no builds to download. Its migration guide lists one change so far:
os.mount, os.umount and the Vfs classes move from os to the vfs module. Code prepares by importing them from
vfs today, which every release since 1.23 has, with a fallback to os for older builds. The guide is not final,
so reading it with each release shows the next moves early.
Warm-up (fresher): How do you check in code that a board runs MicroPython 1.24 or later?
Compare sys.implementation.version with a tuple: sys.implementation.version >= (1, 24). The version is a tuple
of the major, minor and micro numbers and a release level, such as (1, 29, 0, '') for 1.29.0, and tuples compare
number by number, so (1, 9, 4, '') counts as older than (1, 24). Comparing the strings of
os.uname().release gets it wrong, because “1.9.4” sorts after “1.24” letter by letter. Keep such a check for
behaviour that changed between releases; a feature that a build may leave out is probed instead, with hasattr()
or an import in a try.
Two longer questions about upgrades follow; each row leads to what it tests and a first step:
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Mid to senior
A fleet of ESP32 loggers moves from MicroPython 1.28 to 1.29. Afterwards every SD card write is reported as failed although the files are fine, and a parser of a vendor's text files raises LookupError. Diagnose both, and make the code correct on both releases while the fleet is half upgraded.
-
Fresher to mid
A product's main.py calls sys.exit() when its sensor does not answer. After an upgrade from 1.23 to 1.24, boards with a broken sensor reboot in a loop and never reach the REPL. Explain what changed and redesign the failure path.
Flashcards · 8 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
Where are a MicroPython release's breaking changes listed?
In its notes on GitHub under the version's tag, such as v1.29.0: 1.29 gives them a section of their own, earlier releases name them in the overview. Then read the py core, extmod and port blocks.
-
How do you check that a board runs 1.24 or later?
sys.implementation.version >= (1, 24): tuples compare number by number. Comparing the strings of os.uname().release makes 1.9.4 look newer than 1.24.
-
Why can sys.exit() in main.py cause a reboot loop since 1.24?
It soft-resets the board instead of returning to the REPL, so a main.py that exits when a sensor is missing restarts and exits again. Return from the main function instead.
-
What changed in SDCard.readblocks() and writeblocks() on esp32 and stm32 in 1.29?
They return 0 or a negative number, no longer True on success, so code that tests if card.writeblocks(n, buf): now reads success as failure.
-
Why can a test for 0 or True misjudge a block device's result across versions?
In Python False == 0, so a failed write on an older firmware counts as a success. Test is True and is False first, then the number.
-
When does code probe for a feature, and when does it check the version?
A feature a build may lack is probed, with hasattr(), an import or compile() in a try. Behaviour that changed between releases is checked with sys.implementation.version.
-
What is the one change listed so far for MicroPython 2.0?
mount(), umount() and the Vfs classes leave os for the vfs module. Import them from vfs today, which every release since 1.23 has.
-
How do you decode Latin-1 on 1.29, which refuses the encoding name?
A Latin-1 byte's value is also its Unicode code point, so chr() of each byte, joined, gives the text: b"Caf\xe9" becomes "Café".
Key takeaways
- A release’s notes give the overview and the breaking changes first, then every change by component and port; read the blocks of the core and of your port, in the documentation of the version you run.
- Seven changes from 1.24 to 1.29 break old code:
sys.exit()soft-resets, stm32 releases buses at a soft reset, nrf’senable_irq(state), only utf-8 and ascii, SDCard results of 0 or a negative number,sys.platform“nrf”, and stm32’sstmnames without_Sor_NS. - Check results that may be a bool on one version and a number on another with
is Trueandis Falsefirst, becauseFalse == 0. - Probe for features with
hasattr(),importorcompile(), and comparesys.implementation.versionas a tuple only for behaviour that changed. - MicroPython 2.0 is in development; its one listed change moves mount, umount and the Vfs classes to
vfs, which code can import today on any release since 1.23.
Terms in this lesson
- breaking change
- A change in a new release after which code that worked before fails or behaves differently, without being changed itself. Release notes call such changes out so that they can be fixed before an upgrade.
References
- MicroPython v1.24.0 release notes (MicroPython project)
- MicroPython v1.25.0 release notes (MicroPython project)
- MicroPython v1.26.0 release notes (MicroPython project)
- MicroPython v1.27.0 release notes (MicroPython project)
- MicroPython v1.28.0 release notes (MicroPython project)
- MicroPython v1.29.0 release notes (MicroPython project)
- MicroPython v1.23.0 release notes (the vfs module) (MicroPython project)
- MicroPython 2.0 Migration Guide (MicroPython project)
- vfs – virtual filesystem control (MicroPython project)
- os – basic "operating system" services (filesystem mounting) (MicroPython project)
- sys – system specific functions (sys.implementation, sys.platform) (MicroPython project)
- vfs.AbstractBlockDev return values (the vfs documentation) (MicroPython project)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress