Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Include/internal/pycore_pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ PyAPI_FUNC(void) _PyErr_SetString(
PyObject *exception,
const char *string);

/*
* Raise an OSError subclass with an explicit errno value, so that the
* resulting exception has a meaningful errno attribute. msg is used as
* strerror. Prefer PyErr_SetFromErrno() when the C errno is already set.
*/
PyAPI_FUNC(void) _PyErr_SetOSErrorWithMessage(
PyObject *exception,
int err,
const char *msg);

/*
* Set an exception with the error message decoded from the current locale
* encoding (LC_CTYPE).
Expand Down
2 changes: 1 addition & 1 deletion Lib/_pyio.py
Original file line number Diff line number Diff line change
Expand Up @@ -2626,7 +2626,7 @@ def read(self, size=None):
if size < 0:
chunk = self.buffer.read()
if chunk is None:
raise BlockingIOError("Read returned None.")
raise BlockingIOError(errno.EAGAIN, "Read returned None.")
# Read everything.
result = (self._get_decoded_chars() +
decoder.decode(chunk, final=True))
Expand Down
3 changes: 2 additions & 1 deletion Lib/asyncio/base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1183,7 +1183,8 @@ async def create_connection(
', '.join(str(exc) for exc in exceptions)))
else:
# No exceptions were collected, raise a timeout error
raise TimeoutError('create_connection failed')
raise TimeoutError(errno.ETIMEDOUT,
'create_connection failed')
finally:
exceptions = None

Expand Down
4 changes: 3 additions & 1 deletion Lib/asyncio/base_subprocess.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import collections
import errno
import os
import subprocess
import warnings
import os
Expand Down Expand Up @@ -148,7 +150,7 @@ def get_pipe_transport(self, fd):

def _check_proc(self):
if self._proc is None:
raise ProcessLookupError()
raise ProcessLookupError(errno.ESRCH, os.strerror(errno.ESRCH))

if sys.platform == 'win32':
def send_signal(self, signal):
Expand Down
3 changes: 2 additions & 1 deletion Lib/asyncio/proactor_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

__all__ = 'BaseProactorEventLoop',

import errno
import io
import os
import socket
Expand Down Expand Up @@ -449,7 +450,7 @@ def _pipe_closed(self, fut):
assert fut is self._read_fut, (fut, self._read_fut)
self._read_fut = None
if self._write_fut is not None:
self._force_close(BrokenPipeError())
self._force_close(BrokenPipeError(errno.EPIPE, os.strerror(errno.EPIPE)))
else:
self.close()

Expand Down
9 changes: 6 additions & 3 deletions Lib/asyncio/sslproto.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import collections
import enum
import errno
import os
import warnings
try:
import ssl
Expand Down Expand Up @@ -464,7 +466,7 @@ def eof_received(self):
logger.debug("%r received EOF", self)

if self._state == SSLProtocolState.DO_HANDSHAKE:
self._on_handshake_complete(ConnectionResetError)
self._on_handshake_complete(ConnectionResetError(errno.ECONNRESET, os.strerror(errno.ECONNRESET)))

elif self._state == SSLProtocolState.WRAPPED:
self._set_state(SSLProtocolState.FLUSHING)
Expand Down Expand Up @@ -556,7 +558,7 @@ def _check_handshake_timeout(self):
f"{self._ssl_handshake_timeout} seconds: "
f"aborting the connection"
)
self._fatal_error(ConnectionAbortedError(msg))
self._fatal_error(ConnectionAbortedError(errno.ECONNABORTED, msg))

def _do_handshake(self):
try:
Expand Down Expand Up @@ -644,7 +646,8 @@ def _check_shutdown_timeout(self):
)
):
self._transport._force_close(
exceptions.TimeoutError('SSL shutdown timed out'))
exceptions.TimeoutError(errno.ETIMEDOUT,
'SSL shutdown timed out'))

def _do_flush(self):
self._do_read()
Expand Down
3 changes: 2 additions & 1 deletion Lib/asyncio/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
'open_connection', 'start_server')

import collections
import errno
import socket
import sys
import warnings
Expand Down Expand Up @@ -163,7 +164,7 @@ def connection_lost(self, exc):

async def _drain_helper(self):
if self._connection_lost:
raise ConnectionResetError('Connection lost')
raise ConnectionResetError(errno.ECONNRESET, 'Connection lost')
if not self._paused:
return
waiter = self._loop.create_future()
Expand Down
7 changes: 5 additions & 2 deletions Lib/asyncio/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@

import concurrent.futures
import contextvars
import errno
import functools
import inspect
import itertools
import math
import os
import types
import weakref
from types import GenericAlias
Expand Down Expand Up @@ -480,7 +482,7 @@ async def wait_for(fut, timeout):
try:
return fut.result()
except exceptions.CancelledError as exc:
raise TimeoutError from exc
raise TimeoutError(errno.ETIMEDOUT, os.strerror(errno.ETIMEDOUT)) from exc

async with timeouts.timeout(timeout):
return await fut
Expand Down Expand Up @@ -613,7 +615,8 @@ async def _wait_for_one(self, resolve=False):
f = await self._done.get()
if f is None:
# Dummy value from _handle_timeout().
raise exceptions.TimeoutError
raise exceptions.TimeoutError(errno.ETIMEDOUT,
os.strerror(errno.ETIMEDOUT))
return f.result() if resolve else f


Expand Down
5 changes: 3 additions & 2 deletions Lib/asyncio/timeouts.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import enum
import errno

from types import TracebackType

Expand Down Expand Up @@ -112,7 +113,7 @@ async def __aexit__(
# Since there are no new cancel requests, we're
# handling this.
if issubclass(exc_type, exceptions.CancelledError):
raise TimeoutError from exc_val
raise TimeoutError(errno.ETIMEDOUT, 'timed out') from exc_val
elif exc_val is not None:
self._insert_timeout_error(exc_val)
if isinstance(exc_val, ExceptionGroup):
Expand All @@ -134,7 +135,7 @@ def _on_timeout(self) -> None:
def _insert_timeout_error(exc_val: BaseException) -> None:
while exc_val.__context__ is not None:
if isinstance(exc_val.__context__, exceptions.CancelledError):
te = TimeoutError()
te = TimeoutError(errno.ETIMEDOUT, 'timed out')
te.__context__ = te.__cause__ = exc_val.__context__
exc_val.__context__ = te
break
Expand Down
2 changes: 1 addition & 1 deletion Lib/asyncio/unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ def _read_ready(self):
if self._loop.get_debug():
logger.info("%r was closed by peer", self)
if self._buffer:
self._close(BrokenPipeError())
self._close(BrokenPipeError(errno.EPIPE, os.strerror(errno.EPIPE)))
else:
self._close()

Expand Down
7 changes: 5 additions & 2 deletions Lib/concurrent/futures/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
__author__ = 'Brian Quinlan (brian@sweetapp.com)'

import collections
import errno
import logging
import os
import threading
import time
import types
Expand Down Expand Up @@ -231,6 +233,7 @@ def as_completed(fs, timeout=None):
wait_timeout = end_time - time.monotonic()
if wait_timeout < 0:
raise TimeoutError(
errno.ETIMEDOUT,
'%d (of %d) futures unfinished' % (
len(pending), total_futures))

Expand Down Expand Up @@ -460,7 +463,7 @@ def result(self, timeout=None):
elif self._state == FINISHED:
return self.__get_result()
else:
raise TimeoutError()
raise TimeoutError(errno.ETIMEDOUT, os.strerror(errno.ETIMEDOUT))
finally:
# Break a reference cycle with the exception in self._exception
self = None
Expand Down Expand Up @@ -496,7 +499,7 @@ def exception(self, timeout=None):
elif self._state == FINISHED:
return self._exception
else:
raise TimeoutError()
raise TimeoutError(errno.ETIMEDOUT, os.strerror(errno.ETIMEDOUT))

# The following methods should only be used by Executors and in tests.
def set_running_or_notify_cancel(self):
Expand Down
5 changes: 4 additions & 1 deletion Lib/hashlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
'031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'
"""

import errno

# This tuple and __get_builtin_constructor() must be modified if a new
# always available algorithm is added.
__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
Expand Down Expand Up @@ -253,7 +255,8 @@ def file_digest(fileobj, digest, /, *, _bufsize=2**18):
while True:
size = fileobj.readinto(buf)
if size is None:
raise BlockingIOError("I/O operation would block.")
raise BlockingIOError(errno.EAGAIN,
"I/O operation would block.")
if size == 0:
break # EOF
digestobj.update(view[:size])
Expand Down
3 changes: 2 additions & 1 deletion Lib/importlib/resources/_adapters.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import errno
from contextlib import suppress
from io import TextIOWrapper

Expand Down Expand Up @@ -136,7 +137,7 @@ def name(self):
return self._path[-1]

def open(self, mode='r', *args, **kwargs):
raise FileNotFoundError("Can't open orphan path")
raise FileNotFoundError(errno.ENOENT, "Can't open orphan path")

def __init__(self, spec):
self.spec = spec
Expand Down
11 changes: 6 additions & 5 deletions Lib/importlib/resources/abc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import abc
import errno
import itertools
import os
import pathlib
Expand Down Expand Up @@ -34,7 +35,7 @@ def open_resource(self, resource: Text) -> BinaryIO:
# This deliberately raises FileNotFoundError instead of
# NotImplementedError so that if this method is accidentally called,
# it'll still do the right thing.
raise FileNotFoundError
raise FileNotFoundError(errno.ENOENT, 'No such resource')

@abc.abstractmethod
def resource_path(self, resource: Text) -> Text:
Expand All @@ -47,20 +48,20 @@ def resource_path(self, resource: Text) -> Text:
# This deliberately raises FileNotFoundError instead of
# NotImplementedError so that if this method is accidentally called,
# it'll still do the right thing.
raise FileNotFoundError
raise FileNotFoundError(errno.ENOENT, 'No such resource')

@abc.abstractmethod
def is_resource(self, path: Text) -> bool:
"""Return True if the named 'path' is a resource.

Files are resources, directories are not.
"""
raise FileNotFoundError
raise FileNotFoundError(errno.ENOENT, 'No such resource')

@abc.abstractmethod
def contents(self) -> Iterable[str]:
"""Return an iterable of entries in `package`."""
raise FileNotFoundError
raise FileNotFoundError(errno.ENOENT, 'No such resource')


class TraversalError(Exception):
Expand Down Expand Up @@ -180,7 +181,7 @@ def open_resource(self, resource: StrPath) -> BinaryIO:
return self.files().joinpath(resource).open('rb')

def resource_path(self, resource: Any) -> NoReturn:
raise FileNotFoundError(resource)
raise FileNotFoundError(errno.ENOENT, 'No such resource', resource)

def is_resource(self, path: StrPath) -> bool:
return self.files().joinpath(path).is_file()
Expand Down
20 changes: 13 additions & 7 deletions Lib/importlib/resources/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import collections
import contextlib
import errno
import itertools
import operator
import pathlib
Expand Down Expand Up @@ -46,7 +47,10 @@ def open_resource(self, resource):
try:
return super().open_resource(resource)
except KeyError as exc:
raise FileNotFoundError(exc.args[0])
if resource == exc.args[0]:
raise FileNotFoundError(errno.ENOENT, 'No such resource', resource)
else:
raise FileNotFoundError(errno.ENOENT, exc.args[0])

def is_resource(self, path):
"""
Expand All @@ -72,9 +76,11 @@ def __init__(self, *paths):
self._paths = list(map(_ensure_traversable, remove_duplicates(paths)))
if not self._paths:
message = 'MultiplexedPath must contain at least one path'
raise FileNotFoundError(message)
if not all(path.is_dir() for path in self._paths):
raise NotADirectoryError('MultiplexedPath only supports directories')
raise FileNotFoundError(errno.ENOENT, message)
for path in self._paths:
if not path.is_dir():
message = 'MultiplexedPath only supports directories'
raise NotADirectoryError(errno.ENOTDIR, message, path)

def iterdir(self):
children = (child for path in self._paths for child in path.iterdir())
Expand All @@ -83,10 +89,10 @@ def iterdir(self):
return map(self._follow, (locs for name, locs in groups))

def read_bytes(self):
raise FileNotFoundError(f'{self} is not a file')
raise FileNotFoundError(errno.ENOENT, f'{self} is not a file')

def read_text(self, *args, **kwargs):
raise FileNotFoundError(f'{self} is not a file')
raise FileNotFoundError(errno.ENOENT, f'{self} is not a file')

def is_dir(self):
return True
Expand Down Expand Up @@ -122,7 +128,7 @@ def _follow(cls, children):
return next(one_file)

def open(self, *args, **kwargs):
raise FileNotFoundError(f'{self} is not a file')
raise FileNotFoundError(errno.ENOENT, f'{self} is not a file')

@property
def name(self):
Expand Down
4 changes: 3 additions & 1 deletion Lib/importlib/resources/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
"""

import abc
import errno
import io
import itertools
import os
from typing import BinaryIO

from .abc import Traversable, TraversableResources
Expand Down Expand Up @@ -67,7 +69,7 @@ def iterdir(self):
return itertools.chain(files, dirs)

def open(self, *args, **kwargs):
raise IsADirectoryError()
raise IsADirectoryError(errno.EISDIR, os.strerror(errno.EISDIR))


class ResourceHandle(Traversable):
Expand Down
2 changes: 1 addition & 1 deletion Lib/logging/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non

if isinstance(fname, str):
if not os.path.exists(fname):
raise FileNotFoundError(f"{fname} doesn't exist")
raise FileNotFoundError(errno.ENOENT, 'No such file', fname)
elif not os.path.getsize(fname):
raise RuntimeError(f'{fname} is an empty file')

Expand Down
Loading
Loading