classification
Title: EnvironmentError does not set errno unless strerror is set
Type: Stage: resolved
Components: Versions: Python 3.8, Python 3.7, Python 3.6, Python 3.4, Python 3.5, Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: eryksun, giampaolo.rodola, serhiy.storchaka
Priority: normal Keywords:

Created on 2018-05-26 11:06 by giampaolo.rodola, last changed 2018-05-26 17:12 by eryksun. This issue is now closed.

Messages (4)
msg317737 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2018-05-26 11:06
>>> import errno
>>> OSError(errno.EBADF).errno
>>> OSError(errno.EBADF, "yo").errno
9
>>> IOError(errno.EBADF).errno
>>> IOError(errno.EBADF, "yo").errno
9
>>> EnvironmentError(errno.EBADF).errno
>>> 
>>> EnvironmentError(errno.EBADF, "yo").errno
9

This is a bit annoying mainly when mocking fs-related functions in order to raise specific OSError exceptions.
msg317739 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-05-26 12:31
This is a documented behavior. If OSError is called with a single argument, it is interpreted as the error message (as in most other exceptions). But if it is called with 2 to 5 arguments, the first argument is interpreted as the errno.

https://docs.python.org/3/library/exceptions.html#OSError

>>> ValueError('Invalid command')
ValueError('Invalid command')
>>> str(ValueError('Invalid command'))
'Invalid command'
>>> OSError('Invalid command')
OSError('Invalid command')
>>> str(OSError('Invalid command'))
'Invalid command'
>>> import errno
>>> OSError(errno.EBADF, 'Invalid command')
OSError(9, 'Invalid command')
>>> str(OSError(errno.EBADF, 'Invalid command'))
'[Errno 9] Invalid command'
msg317740 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2018-05-26 12:32
My bad, should have read the doc, sorry. =)
msg317744 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2018-05-26 17:12
This behavior is inherited from BaseException:

https://docs.python.org/3/library/exceptions.html#BaseException

    >>> str(BaseException())
    ''
    >>> str(BaseException('spam'))
    'spam'
    >>> str(BaseException('spam', 'eggs'))
    "('spam', 'eggs')"

Python 2 OSError special cases 2-3 arguments:

    >>> str(OSError(*'123'))
    "[Errno 1] 2: '3'"

    >>> str(OSError(*'1234'))
    "('1', '2', '3', '4')"

Python 3 OSError special cases 2-5 arguments (adding winerror and filename2):

    >>> str(OSError(*'12345'))
    "[Errno 1] 2: '3' -> '5'"

    >>> str(OSError(*'123456'))
    "('1', '2', '3', '4', '5', '6')"

The base behavior is implemented by BaseException_str in Objects/exceptions.c:

    static PyObject *
    BaseException_str(PyBaseExceptionObject *self)
    {
        switch (PyTuple_GET_SIZE(self->args)) {
        case 0:
            return PyUnicode_FromString("");
        case 1:
            return PyObject_Str(PyTuple_GET_ITEM(self->args, 0));
        default:
            return PyObject_Str(self->args);
        }
    }
History
Date User Action Args
2018-05-26 17:12:53eryksunsetnosy: + eryksun
messages: + msg317744
2018-05-26 12:32:41giampaolo.rodolasetstatus: open -> closed
resolution: not a bug
messages: + msg317740

stage: resolved
2018-05-26 12:31:10serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg317739
2018-05-26 11:06:26giampaolo.rodolacreate