Skip to content

py/objexcept: Support errno attribute on OSError exceptions.#7136

Merged
dpgeorge merged 4 commits into
micropython:masterfrom
dpgeorge:py-oserror-errno
Apr 23, 2021
Merged

py/objexcept: Support errno attribute on OSError exceptions.#7136
dpgeorge merged 4 commits into
micropython:masterfrom
dpgeorge:py-oserror-errno

Conversation

@dpgeorge
Copy link
Copy Markdown
Member

This PR adds the errno attribute to exceptions, so code can retrieve errno codes from an OSError using exc.errno.

This is an alternative implementation of #2407, which generated a lot of controversy at the time (4.5 years ago).

The reason to post this PR is to hopefully finish the discussion about adding/not adding this feature, and finally close #2407.

The implementation here is a simpler version of #2407 which simply lets errno (and the existing value) attributes to work on any exception instance (they both alias args[0]). This is for efficiency and to keep code size down. As I see it, the pros and cons of adding errno are:

Pros:

  • more compatible with CPython, less difference to document and learn
  • OSError().errno will correctly return None, whereas the current way of doing it via OSError().args[0] will raise an IndexError
  • actually reduces code size on most bare-metal ports (because they already have the errno qstr)
  • for Python code that uses exc.errno the generated bytecode is 2 bytes smaller and more efficient to execute (compared with exc.args[0]); so bytecode loaded to RAM saves 2 bytes RAM for each use of this attribute, and bytecode that is frozen saves 2 bytes flash/ROM for each use
  • it's easier/shorter to type, and saves 2 bytes of space in .py files that use it (for each use)

Cons:

  • increases code size by 4-8 bytes on minimal ports that don't enable the uerrno module (due to the additional qstr)
  • all exceptions now have .errno and .value attributes (this is specific to the implementation here)

Feedback/comments welcome!


Code size change of this PR:

   bare-arm:    +4 +0.006% 
minimal x86:    +8 +0.005% 
   unix x64:    +0 +0.000% 
unix nanbox:   +20 +0.004% 
      stm32:   -12 -0.003% PYBV10
     cc3200:   -16 -0.009% 
    esp8266:    -4 -0.001% GENERIC
      esp32:    -8 -0.001% GENERIC
        nrf:    +0 +0.000% pca10040
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
        rp2:   -24 -0.005% PICO

@dpgeorge dpgeorge added the py-core Relates to py/ directory in source label Apr 20, 2021
@jimmo
Copy link
Copy Markdown
Member

jimmo commented Apr 20, 2021

I've explained the args[0] thing many times (e.g. on the forums, in-person training, etc), it would be great to just support errno. +1 on all the "pro" reasons you've posted.

@stinos
Copy link
Copy Markdown
Contributor

stinos commented Apr 20, 2021

+1 because the cons are almost a no-brainer. Perhaps add more explicit documentation for the errno/value always being there, like in the 'cpython diffs'?

@dpgeorge
Copy link
Copy Markdown
Member Author

Perhaps add more explicit documentation for the errno/value always being there, like in the 'cpython diffs'?

Done.

@dpgeorge
Copy link
Copy Markdown
Member Author

I pushed a commit which changes the tests to use .errno where appropriate.

This commit adds the errno attribute to exceptions, so code can retrieve
errno codes from an OSError using exc.errno.

The implementation here simply lets `errno` (and the existing `value`)
attributes work on any exception instance (they both alias args[0]).  This
is for efficiency and to keep code size down.  The pros and cons of this
are:

Pros:
- more compatible with CPython, less difference to document and learn
- OSError().errno will correctly return None, whereas the current way of
  doing it via OSError().args[0] will raise an IndexError
- it reduces code size on most bare-metal ports (because they already have
  the errno qstr)
- for Python code that uses exc.errno the generated bytecode is 2 bytes
  smaller and more efficient to execute (compared with exc.args[0]); so
  bytecode loaded to RAM saves 2 bytes RAM for each use of this attribute,
  and bytecode that is frozen saves 2 bytes flash/ROM for each use
- it's easier/shorter to type, and saves 2 bytes of space in .py files that
  use it (for each use)

Cons:
- increases code size by 4-8 bytes on minimal ports that don't already have
  the `errno` qstr
- all exceptions now have .errno and .value attributes (a cpydiff test is
  added to address this)

See also micropython#2407.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
@dpgeorge dpgeorge merged commit 3123f69 into micropython:master Apr 23, 2021
@dpgeorge dpgeorge deleted the py-oserror-errno branch April 23, 2021 12:39
tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Nov 16, 2022
.. and explain why, because it wasn't clear to past-me.

Actually tested on a pico w :)

Closes: micropython#7136
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

py-core Relates to py/ directory in source

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants