This is the documentation for the latest development branch of MicroPython and may refer to features that are not available in released versions.

If you are looking for the documentation for a specific release, use the drop-down menu on the left and select the desired version.

Core language

Generated Wed 29 Nov 2023 09:31:31 UTC

f-strings don’t support concatenation with adjacent literals if the adjacent literals contain braces or are f-strings

Cause: MicroPython is optimised for code space.

Workaround: Use the + operator between literal strings when either or both are f-strings

Sample code:

x, y = 1, 2
print("aa" f"{x}")  # works
print(f"{x}" "ab")  # works
print("a{}a" f"{x}")  # fails
print(f"{x}" "a{}b")  # fails
print(f"{x}" f"{y}")  # fails

CPy output:

uPy output:

aa1
1ab
a{}a1
1a{}b
12
Traceback (most recent call last):
  File "<stdin>", line 13
SyntaxError: invalid syntax

f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets

Cause: MicroPython is optimised for code space.

Workaround: Always use balanced braces and brackets in expressions inside f-strings

Sample code:

print(f'{"hello { world"}')
print(f'{"hello ] world"}')

CPy output:

uPy output:

hello { world
hello ] world
Traceback (most recent call last):
  File "<stdin>", line 9
SyntaxError: invalid syntax

Raw f-strings are not supported

Cause: MicroPython is optimised for code space.

Sample code:

rf"hello"

CPy output:

uPy output:

Traceback (most recent call last):
  File "<stdin>", line 8
SyntaxError: raw f-strings are not supported

f-strings don’t support !a conversions

Cause: MicropPython does not implement ascii()

Workaround: None

Sample code:

f"{'unicode text'!a}"

CPy output:

uPy output:

Traceback (most recent call last):
  File "<stdin>", line 8
SyntaxError: invalid syntax

Classes

Special method __del__ not implemented for user-defined classes

Sample code:

import gc


class Foo:
    def __del__(self):
        print("__del__")


f = Foo()
del f

gc.collect()

CPy output:

uPy output:

__del__

Method Resolution Order (MRO) is not compliant with CPython

Cause: Depth first non-exhaustive method resolution order

Workaround: Avoid complex class hierarchies with multiple inheritance and complex method overrides. Keep in mind that many languages don’t support multiple inheritance at all.

Sample code:

class Foo:
    def __str__(self):
        return "Foo"


class C(tuple, Foo):
    pass


t = C((1, 2, 3))
print(t)

CPy output:

uPy output:

Foo
(1, 2, 3)

When inheriting from multiple classes super() only calls one class

Cause: See Method Resolution Order (MRO) is not compliant with CPython

Workaround: See Method Resolution Order (MRO) is not compliant with CPython

Sample code:

class A:
    def __init__(self):
        print("A.__init__")


class B(A):
    def __init__(self):
        print("B.__init__")
        super().__init__()


class C(A):
    def __init__(self):
        print("C.__init__")
        super().__init__()


class D(B, C):
    def __init__(self):
        print("D.__init__")
        super().__init__()


D()

CPy output:

uPy output:

D.__init__
B.__init__
C.__init__
A.__init__
D.__init__
B.__init__
A.__init__

Calling super() getter property in subclass will return a property object, not the value

Sample code:

class A:
    @property
    def p(self):
        return {"a": 10}


class AA(A):
    @property
    def p(self):
        return super().p


a = AA()
print(a.p)

CPy output:

uPy output:

{'a': 10}
<property>

Functions

Error messages for methods may display unexpected argument counts

Cause: MicroPython counts “self” as an argument.

Workaround: Interpret error messages with the information above in mind.

Sample code:

try:
    [].append()
except Exception as e:
    print(e)

CPy output:

uPy output:

list.append() takes exactly one argument (0 given)
function takes 2 positional arguments but 1 were given

Function objects do not have the __module__ attribute

Cause: MicroPython is optimized for reduced code size and RAM usage.

Workaround: Use sys.modules[function.__globals__['__name__']] for non-builtin modules.

Sample code:

def f():
    pass


print(f.__module__)

CPy output:

uPy output:

__main__
Traceback (most recent call last):
  File "<stdin>", line 13, in <module>
AttributeError: 'function' object has no attribute '__module__'

User-defined attributes for functions are not supported

Cause: MicroPython is highly optimized for memory usage.

Workaround: Use external dictionary, e.g. FUNC_X[f] = 0.

Sample code:

def f():
    pass


f.x = 0
print(f.x)

CPy output:

uPy output:

0
Traceback (most recent call last):
  File "<stdin>", line 13, in <module>
AttributeError: 'function' object has no attribute 'x'

Generator

Context manager __exit__() not called in a generator which does not run to completion

Sample code:

class foo(object):
    def __enter__(self):
        print("Enter")

    def __exit__(self, *args):
        print("Exit")


def bar(x):
    with foo():
        while True:
            x += 1
            yield x


def func():
    g = bar(0)
    for _ in range(3):
        print(next(g))


func()

CPy output:

uPy output:

Enter
1
2
3
Exit
Enter
1
2
3

Runtime

Local variables aren’t included in locals() result

Cause: MicroPython doesn’t maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can’t be accessed by a name.

Sample code:

def test():
    val = 2
    print(locals())


test()

CPy output:

uPy output:

{'val': 2}
{'test': <function test at 0x7f3e1d3e8260>, '__name__': '__main__', '__file__': '<stdin>'}

Code running in eval() function doesn’t have access to local variables

Cause: MicroPython doesn’t maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can’t be accessed by a name. Effectively, eval(expr) in MicroPython is equivalent to eval(expr, globals(), globals()).

Sample code:

val = 1


def test():
    val = 2
    print(val)
    eval("print(val)")


test()

CPy output:

uPy output:

2
2
2
1

import

__all__ is unsupported in __init__.py in MicroPython.

Cause: Not implemented.

Workaround: Manually import the sub-modules directly in __init__.py using from . import foo, bar.

Sample code:

from modules3 import *

foo.hello()

CPy output:

uPy output:

hello
Traceback (most recent call last):
  File "<stdin>", line 9, in <module>
NameError: name 'foo' isn't defined

__path__ attribute of a package has a different type (single string instead of list of strings) in MicroPython

Cause: MicroPython doesn’t support namespace packages split across filesystem. Beyond that, MicroPython’s import system is highly optimized for minimal memory usage.

Workaround: Details of import handling is inherently implementation dependent. Don’t rely on such details in portable applications.

Sample code:

import modules

print(modules.__path__)

CPy output:

uPy output:

['/home/micropython/micropython-autodocs/tests/cpydiff/modules']
../tests/cpydiff/modules

MicroPython doesn’t support namespace packages split across filesystem.

Cause: MicroPython’s import system is highly optimized for simplicity, minimal memory usage, and minimal filesystem search overhead.

Workaround: Don’t install modules belonging to the same namespace package in different directories. For MicroPython, it’s recommended to have at most 3-component module search paths: for your current application, per-user (writable), system-wide (non-writable).

Sample code:

import sys

sys.path.append(sys.path[1] + "/modules")
sys.path.append(sys.path[1] + "/modules2")

import subpkg.foo
import subpkg.bar

print("Two modules of a split namespace package imported")

CPy output:

uPy output:

Two modules of a split namespace package imported
Traceback (most recent call last):
  File "<stdin>", line 13, in <module>
ImportError: no module named 'subpkg.bar'