Skip to content

WIP: Always pass errno argument for OSError subclasses #109720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
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
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

Expand Down Expand Up @@ -139,7 +141,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))

def send_signal(self, signal):
self._check_proc()
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 @@ -452,7 +453,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
6 changes: 4 additions & 2 deletions Lib/asyncio/sslproto.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import collections
import enum
import errno
import os
import warnings
try:
import ssl
Expand Down Expand Up @@ -458,7 +460,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 @@ -550,7 +552,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
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 @@ -164,7 +165,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
6 changes: 4 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 warnings
import weakref
Expand Down Expand Up @@ -492,7 +494,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 @@ -605,7 +607,7 @@ async def _wait_for_one():
f = await done.get()
if f is None:
# Dummy value from _on_timeout().
raise exceptions.TimeoutError
raise exceptions.TimeoutError(errno.ETIMEDOUT, os.strerror(errno.ETIMEDOUT))
return f.result() # May raise f.exception().

for f in todo:
Expand Down
3 changes: 2 additions & 1 deletion 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
from typing import final, Optional, Type
Expand Down Expand Up @@ -108,7 +109,7 @@ async def __aexit__(
if self._task.uncancel() <= self._cancelling and exc_type is exceptions.CancelledError:
# Since there are no new cancel requests, we're
# handling this.
raise TimeoutError from exc_val
raise TimeoutError(errno.ETIMEDOUT, 'timed out') from exc_val
elif self._state is _State.ENTERED:
self._state = _State.EXITED

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 @@ -676,7 +676,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 @@ -237,6 +239,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 @@ -455,7 +458,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 @@ -491,7 +494,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
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
3 changes: 2 additions & 1 deletion Lib/importlib/resources/abc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import abc
import errno
import io
import itertools
import os
Expand Down Expand Up @@ -164,7 +165,7 @@ def open_resource(self, resource: StrPath) -> io.BufferedReader:
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
@@ -1,4 +1,5 @@
import collections
import errno
import itertools
import pathlib
import operator
Expand Down Expand Up @@ -39,7 +40,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 @@ -65,9 +69,11 @@ def __init__(self, *paths):
self._paths = list(map(pathlib.Path, 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 @@ -76,10 +82,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 @@ -115,7 +121,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, List

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 @@ -63,7 +63,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
3 changes: 2 additions & 1 deletion Lib/multiprocessing/heap.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import bisect
from collections import defaultdict
import errno
import mmap
import os
import sys
Expand Down Expand Up @@ -45,7 +46,7 @@ def __init__(self, size):
# We have reopened a preexisting mmap.
buf.close()
else:
raise FileExistsError('Cannot find name for new mmap')
raise FileExistsError(errno.EEXIST, 'Cannot find name for new mmap')
self.name = name
self.buffer = buf
self._state = (self.size, self.name)
Expand Down
5 changes: 3 additions & 2 deletions Lib/multiprocessing/pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#

import collections
import errno
import itertools
import os
import queue
Expand Down Expand Up @@ -767,7 +768,7 @@ def wait(self, timeout=None):
def get(self, timeout=None):
self.wait(timeout)
if not self.ready():
raise TimeoutError
raise TimeoutError(errno.ETIMEDOUT, os.strerror(errno.ETIMEDOUT))
if self._success:
return self._value
else:
Expand Down Expand Up @@ -865,7 +866,7 @@ def next(self, timeout=None):
if self._index == self._length:
self._pool = None
raise StopIteration from None
raise TimeoutError from None
raise TimeoutError(errno.ETIMEDOUT, os.strerror(errno.ETIMEDOUT)) from None

success, value = item
if success:
Expand Down
3 changes: 2 additions & 1 deletion Lib/multiprocessing/synchronize.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition', 'Event'
]

import errno
import threading
import sys
import tempfile
Expand Down Expand Up @@ -62,7 +63,7 @@ def __init__(self, kind, value, maxvalue, *, ctx):
else:
break
else:
raise FileExistsError('cannot find name for semaphore')
raise FileExistsError(errno.EEXIST, 'cannot find name for semaphore')

util.debug('created semlock with handle %s' % sl.handle)
self._make_methods()
Expand Down
5 changes: 3 additions & 2 deletions Lib/py_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

import enum
import errno
import importlib._bootstrap_external
import importlib.machinery
import importlib.util
Expand Down Expand Up @@ -133,11 +134,11 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
if os.path.islink(cfile):
msg = ('{} is a symlink and will be changed into a regular file if '
'import writes a byte-compiled file to it')
raise FileExistsError(msg.format(cfile))
raise FileExistsError(errno.EEXIST, msg.format(cfile))
elif os.path.exists(cfile) and not os.path.isfile(cfile):
msg = ('{} is a non-regular file and will be changed into a regular '
'one if import writes a byte-compiled file to it')
raise FileExistsError(msg.format(cfile))
raise FileExistsError(errno.EEXIST, msg.format(cfile))
loader = importlib.machinery.SourceFileLoader('<py_compile>', file)
source_bytes = loader.get_data(file)
try:
Expand Down
8 changes: 4 additions & 4 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def copyfile(src, dst, *, follow_symlinks=True):
# Issue 43219, raise a less confusing exception
except IsADirectoryError as e:
if not os.path.exists(dst):
raise FileNotFoundError(f'Directory does not exist: {dst}') from e
raise FileNotFoundError(errno.ENOENT, 'Directory does not exist', dst) from e
else:
raise

Expand Down Expand Up @@ -872,9 +872,9 @@ def move(src, dst, copy_function=copy2):
if (_is_immutable(src)
or (not os.access(src, os.W_OK) and os.listdir(src)
and sys.platform == 'darwin')):
raise PermissionError("Cannot move the non-empty directory "
"'%s': Lacking write permission to '%s'."
% (src, src))
raise PermissionError(errno.EACCES,
"Cannot move the non-empty directory: "
"Lacking write permission", src)
copytree(src, real_dst, copy_function=copy_function,
symlinks=True)
rmtree(src)
Expand Down
2 changes: 1 addition & 1 deletion Lib/socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ def _sendfile_use_sendfile(self, file, offset=0, count=None):
try:
while True:
if timeout and not selector_select(timeout):
raise TimeoutError('timed out')
raise TimeoutError(errno.ETIMEDOUT, os.strerror(errno.ETIMEDOUT))
if count:
blocksize = count - total_sent
if blocksize <= 0:
Expand Down
Loading