.. This document was generated by tools/gen-cpydiff.py Core Language ============= Generated Sun 02 Jul 2017 11:35:54 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** 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__ | D.__init__ | | B.__init__ | B.__init__ | | C.__init__ | A.__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} | | +---------------+----------------+ 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 "", line 10, in | | | 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 | Enter | | 1 | 1 | | 2 | 2 | | 3 | 3 | | Exit | | +-------------+-------------+ 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: | +------------------------------------------------------------------+-------------------------------+ | :: | :: | | | | | ['/home/micropython/micropython-docs/tests/cpydiff/modules'] | ../tests/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, use ``del sys.modules["name"]``, or just soft or hard 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 | foo | | name 'xxx' is not defined | name 'xxx' is not defined | | foo | Should not get here | | name 'xxx' is not defined | | +-------------------------------+-------------------------------+ **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 "", line 12, in | | | ImportError: no module named 'subpkg.bar' | +-------------------------------------------------------+-----------------------------------------------+