Core Language

Generated Tue 13 Jun 2017 17:30:45 UTC

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:
append() takes exactly one argument (0 given)
function takes 2 positional arguments but 1 were given

Method Resolution Order (MRO) is not compliant with CPython

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)

Classes

Special method __del__ not implemented for user-defined classes (this is true for standard MicroPython but has been fixed in |short_port_name|, also deleting an object will finalize it immediately.)

Workaround: None needed for Satlink 3 and XLink 500

Sample code:

import gc

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

f = Foo()
del f

gc.collect()
CPy output: uPy output:
__del__
 

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

Cause: Depth first non-exhaustive method resolution order

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

Unpacking function arguments in non-last position isn’t detected as an error

Workaround: The syntax below is invalid, never use it in applications.

Sample code:

print(*(1, 2), 3)
CPy output: uPy output:
1 2 3
3 1 2

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 10, 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

import

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

Cause: MicroPython does’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:
['C:\\Users\\jon\\AppData\\Local\\Temp\\sl3-build\\src\\MicroPython\\test\\packages\\cpydiff\\modules']
../test/packages/cpydiff//modules

Failed to load modules are still registered as loaded

Cause: To make module handling more efficient, it’s not wrapped with exception handling.

Workaround: Test modules before production use; during development, test using LinkComm, issue “script test” at the command prompt, or from the repl del sys.modules["name"] will work. Worst-case reset the board.

Sample code:

import sys

try:
    from modules import foo
except NameError as e:
    print(e)
try:
    from modules import foo
    print('Should not get here')
except NameError as e:
    print(e)
CPy output: uPy output:
foo
name 'xxx' is not defined
foo
name 'xxx' is not defined
foo
name 'xxx' is not defined
Should not get here

MicroPython does’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 12, in <module>
ImportError: no module named 'subpkg.bar'