summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/library/builtins.rst4
-rw-r--r--docs/library/uerrno.rst4
-rw-r--r--py/objexcept.c4
-rw-r--r--tests/basics/exception1.py5
-rw-r--r--tests/basics/subclass_native3.py20
-rw-r--r--tests/cpydiff/types_exception_attrs.py9
6 files changed, 39 insertions, 7 deletions
diff --git a/docs/library/builtins.rst b/docs/library/builtins.rst
index 365248dc7..3029cd9e3 100644
--- a/docs/library/builtins.rst
+++ b/docs/library/builtins.rst
@@ -176,10 +176,6 @@ Exceptions
.. exception:: OSError
- |see_cpython| `python:OSError`. MicroPython doesn't implement ``errno``
- attribute, instead use the standard way to access exception arguments:
- ``exc.args[0]``.
-
.. exception:: RuntimeError
.. exception:: StopIteration
diff --git a/docs/library/uerrno.rst b/docs/library/uerrno.rst
index def01362f..1d60c80e1 100644
--- a/docs/library/uerrno.rst
+++ b/docs/library/uerrno.rst
@@ -16,13 +16,13 @@ Constants
Error codes, based on ANSI C/POSIX standard. All error codes start with
"E". As mentioned above, inventory of the codes depends on
- :term:`MicroPython port`. Errors are usually accessible as ``exc.args[0]``
+ :term:`MicroPython port`. Errors are usually accessible as ``exc.errno``
where ``exc`` is an instance of `OSError`. Usage example::
try:
uos.mkdir("my_dir")
except OSError as exc:
- if exc.args[0] == uerrno.EEXIST:
+ if exc.errno == uerrno.EEXIST:
print("Directory already exists")
.. data:: errorcode
diff --git a/py/objexcept.c b/py/objexcept.c
index 885032c3e..f6bffec38 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -261,7 +261,9 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (attr == MP_QSTR_args) {
decompress_error_text_maybe(self);
dest[0] = MP_OBJ_FROM_PTR(self->args);
- } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {
+ } else if (attr == MP_QSTR_value || attr == MP_QSTR_errno) {
+ // These are aliases for args[0]: .value for StopIteration and .errno for OSError.
+ // For efficiency let these attributes apply to all exception instances.
dest[0] = mp_obj_exception_get_value(self_in);
}
}
diff --git a/tests/basics/exception1.py b/tests/basics/exception1.py
index d83764cb9..a0ca8a74e 100644
--- a/tests/basics/exception1.py
+++ b/tests/basics/exception1.py
@@ -1,3 +1,5 @@
+# test basic properties of exceptions
+
print(repr(IndexError()))
print(str(IndexError()))
@@ -12,3 +14,6 @@ s = StopIteration()
print(s.value)
s = StopIteration(1, 2, 3)
print(s.value)
+
+print(OSError().errno)
+print(OSError(1, "msg").errno)
diff --git a/tests/basics/subclass_native3.py b/tests/basics/subclass_native3.py
index 6745b77bb..ac5aabfed 100644
--- a/tests/basics/subclass_native3.py
+++ b/tests/basics/subclass_native3.py
@@ -1,6 +1,10 @@
+# test subclassing a native exception
+
+
class MyExc(Exception):
pass
+
e = MyExc(100, "Some error")
print(e)
print(repr(e))
@@ -20,3 +24,19 @@ try:
raise MyExc("Some error2")
except:
print("Caught user exception")
+
+
+class MyStopIteration(StopIteration):
+ pass
+
+
+print(MyStopIteration().value)
+print(MyStopIteration(1).value)
+
+
+class MyOSError(OSError):
+ pass
+
+
+print(MyOSError().errno)
+print(MyOSError(1, "msg").errno)
diff --git a/tests/cpydiff/types_exception_attrs.py b/tests/cpydiff/types_exception_attrs.py
new file mode 100644
index 000000000..ad72b62a6
--- /dev/null
+++ b/tests/cpydiff/types_exception_attrs.py
@@ -0,0 +1,9 @@
+"""
+categories: Types,Exception
+description: All exceptions have readable ``value`` and ``errno`` attributes, not just ``StopIteration`` and ``OSError``.
+cause: MicroPython is optimised to reduce code size.
+workaround: Only use ``value`` on ``StopIteration`` exceptions, and ``errno`` on ``OSError`` exceptions. Do not use or rely on these attributes on other exceptions.
+"""
+e = Exception(1)
+print(e.value)
+print(e.errno)