.. This document was generated by tools/gen-cpydiff.py Core language ============= Generated Wed 03 Jan 2024 12:07:50 UTC Classes ------- .. _cpydiff_core_class_delnotimpl: 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__ | /bin/sh: ../ports/unix/micropython: No such file or directory | +-------------+-------------------------------------------------------------------+ .. _cpydiff_core_class_mro: 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 | /bin/sh: ../ports/unix/micropython: No such file or directory | +-------------+-------------------------------------------------------------------+ .. _cpydiff_core_class_supermultiple: When inheriting from multiple classes super() only calls one class ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Cause:** See :ref:`cpydiff_core_class_mro` **Workaround:** See :ref:`cpydiff_core_class_mro` 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__ | /bin/sh: ../ports/unix/micropython: No such file or directory | | B.__init__ | | | C.__init__ | | | A.__init__ | | +----------------+-------------------------------------------------------------------+ .. _cpydiff_core_class_superproperty: 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} | /bin/sh: ../ports/unix/micropython: No such file or directory | +---------------+-------------------------------------------------------------------+ Functions --------- .. _cpydiff_core_function_argcount: 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) | /bin/sh: ../ports/unix/micropython: No such file or directory | +---------------------------------------------------+-------------------------------------------------------------------+ .. _cpydiff_core_function_userattr: 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 | /bin/sh: ../ports/unix/micropython: No such file or directory | +-------------+-------------------------------------------------------------------+ Generator --------- .. _cpydiff_core_generator_noexit: 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 | /bin/sh: ../ports/unix/micropython: No such file or directory | | 1 | | | 2 | | | 3 | | | Exit | | +-------------+-------------------------------------------------------------------+ Runtime ------- .. _cpydiff_core_locals: 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} | /bin/sh: ../ports/unix/micropython: No such file or directory | +----------------+-------------------------------------------------------------------+ .. _cpydiff_core_locals_eval: 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 | /bin/sh: ../ports/unix/micropython: No such file or directory | | 2 | | +-------------+-------------------------------------------------------------------+ import ------ .. _cpydiff_core_import_all: __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 | /bin/sh: ../ports/unix/micropython: No such file or directory | +-------------+-------------------------------------------------------------------+ .. _cpydiff_core_import_path: __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/zhiwei/develop/delphinidae_V500R002/src/3dparty/source/micropython/tests/cpydiff/modules'] | /bin/sh: ../ports/unix/micropython: No such file or directory | +--------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------+ .. _cpydiff_core_import_prereg: 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 | /bin/sh: ../ports/unix/micropython: No such file or directory | | name 'xxx' is not defined | | | foo | | | name 'xxx' is not defined | | +-------------------------------+-------------------------------------------------------------------+ .. _cpydiff_core_import_split_ns_pkgs: 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 | /bin/sh: ../ports/unix/micropython: No such file or directory | +-------------------------------------------------------+-------------------------------------------------------------------+