.. This document was generated by tools/gen-cpydiff.py

Core language
=============
Generated Wed 11 Nov 2020 02:26:58 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_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/damien/proj/mp/kookaberry/dpgeorge-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 |
+-------------------------------------------------------+-------------------------------------------------------------------+