From e367fdea32a82a7c7f78b5914c99954f6571faa4 Mon Sep 17 00:00:00 2001 From: "Kirill Lukonin (Evil Wireless Man)" Date: Mon, 14 Sep 2026 23:41:24 +0300 Subject: [PATCH] python-stdlib/errno: Use the values of the built-in errno module. This module replaced the built-in errno module rather than extending it, and the values it defines are the Linux/x86 ones. errno is an extensible built-in, so a file on sys.path wins outright: installing this package left errno.ETIMEDOUT at 110 on a port whose headers say 145 (Linux/mips) or 60 (macOS), while the number OSError carries still came from those headers. errno.errorcode disappeared with it. Found on an OpenWrt mips target, where the package is installed into /usr/lib/micropython, which is on the default sys.path. Import the built-in module at the end of the file, under its u-prefixed name so that the import does not find this file again. Placed last it overrides the table above, which stays as the fallback for the names the built-in module does not provide. Drop EAFNOSUPPORT. It is not in the default MICROPY_PY_ERRNO_LIST, so the value here is the one that gets used, and 97 is right only for Linux/x86: newlib has 106, Linux/mips 124, macOS 47. What is left in the table is codes 1 to 34, which glibc, musl, newlib and py/mperrno.h agree on, and four codes the default list supplies anyway. Signed-off-by: Kirill Lukonin (Evil Wireless Man) --- python-stdlib/errno/errno.py | 13 ++++++++--- python-stdlib/errno/manifest.py | 2 +- python-stdlib/errno/test_errno.py | 38 +++++++++++++++++++++++++++++++ tools/ci.sh | 1 + 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 python-stdlib/errno/test_errno.py diff --git a/python-stdlib/errno/errno.py b/python-stdlib/errno/errno.py index c513a7f14..91d844a80 100644 --- a/python-stdlib/errno/errno.py +++ b/python-stdlib/errno/errno.py @@ -32,8 +32,15 @@ EPIPE = 32 # Broken pipe EDOM = 33 # Math argument out of domain of func ERANGE = 34 # Math result not representable -EAFNOSUPPORT = 97 # Address family not supported by protocol -ECONNRESET = 104 # Connection timed out -ENOTCONN = 107 # Not connected +ECONNRESET = 104 # Connection reset by peer +ENOTCONN = 107 # Transport endpoint is not connected ETIMEDOUT = 110 # Connection timed out EINPROGRESS = 115 # Operation now in progress + +# Override the table above with the built-in module's values, which come from +# this port's system headers. The u-prefix reaches the built-in module. +try: + from uerrno import * +except ImportError: + # Built without MICROPY_PY_ERRNO. + pass diff --git a/python-stdlib/errno/manifest.py b/python-stdlib/errno/manifest.py index 075d3403d..3a71c2d82 100644 --- a/python-stdlib/errno/manifest.py +++ b/python-stdlib/errno/manifest.py @@ -1,3 +1,3 @@ -metadata(version="0.2.0") +metadata(version="0.3.0") module("errno.py") diff --git a/python-stdlib/errno/test_errno.py b/python-stdlib/errno/test_errno.py new file mode 100644 index 000000000..2b39257e5 --- /dev/null +++ b/python-stdlib/errno/test_errno.py @@ -0,0 +1,38 @@ +# The values the built-in errno module provides come from the system headers +# the port was built against, and they differ between operating systems and +# between architectures: ETIMEDOUT is 110 on Linux/x86, 145 on Linux/mips and +# 60 on macOS. This module must not override them with a table of its own. + +import errno + +try: + import uerrno +except ImportError: + # Built without MICROPY_PY_ERRNO, so there is nothing to compare against. + print("SKIP") + raise SystemExit + + +# Every name the built-in module provides has to come through unchanged. +names = [name for name in dir(uerrno) if name.startswith("E")] +assert names, dir(uerrno) +for name in names: + theirs = getattr(uerrno, name) + ours = getattr(errno, name, None) + assert ours is not None, "errno.%s is missing, uerrno.%s is %d" % (name, name, theirs) + assert ours == theirs, "errno.%s is %d, uerrno.%s is %d" % (name, ours, name, theirs) + +# errorcode has to survive too: mp_errno_to_str() looks names up in it, and it +# is what makes str(OSError(errno.ENOENT)) readable. +if hasattr(uerrno, "errorcode"): + assert isinstance(errno.errorcode, dict), errno.errorcode + for code, name in errno.errorcode.items(): + assert getattr(errno, name) == code, "errorcode[%d] is %s" % (code, name) + +# The names the built-in module does not provide are filled in by this module. +# Codes 1 to 34 are the same on every platform MicroPython runs on. +assert errno.EPERM == 1, errno.EPERM +assert errno.ESRCH == 3, errno.ESRCH +assert errno.ENOTBLK == 15, errno.ENOTBLK +assert errno.EDOM == 33, errno.EDOM +assert errno.ERANGE == 34, errno.ERANGE diff --git a/tools/ci.sh b/tools/ci.sh index 7ee7eb4d1..10f16b6ae 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -65,6 +65,7 @@ function ci_package_tests_run { python-stdlib/base64/test_base64.py \ python-stdlib/binascii/test_binascii.py \ python-stdlib/collections-defaultdict/test_defaultdict.py \ + python-stdlib/errno/test_errno.py \ python-stdlib/functools/test_partial.py \ python-stdlib/functools/test_reduce.py \ python-stdlib/heapq/test_heapq.py \