_pytest._py.error: mypy typing

This commit is contained in:
Anthony Sottile 2022-10-19 13:08:48 -04:00
parent 382209d9e9
commit eebbfc65c9
1 changed files with 32 additions and 26 deletions

View File

@ -1,14 +1,23 @@
""" """create errno-specific classes for IO or os calls."""
create errno-specific classes for IO or os calls. from __future__ import annotations
"""
import errno import errno
import os import os
import sys import sys
from typing import Callable
from typing import TYPE_CHECKING
from typing import TypeVar
if TYPE_CHECKING:
from typing_extensions import ParamSpec
P = ParamSpec("P")
R = TypeVar("R")
class Error(EnvironmentError): class Error(EnvironmentError):
def __repr__(self): def __repr__(self) -> str:
return "{}.{} {!r}: {} ".format( return "{}.{} {!r}: {} ".format(
self.__class__.__module__, self.__class__.__module__,
self.__class__.__name__, self.__class__.__name__,
@ -17,7 +26,7 @@ class Error(EnvironmentError):
# repr(self.args) # repr(self.args)
) )
def __str__(self): def __str__(self) -> str:
s = "[{}]: {}".format( s = "[{}]: {}".format(
self.__class__.__doc__, self.__class__.__doc__,
" ".join(map(str, self.args)), " ".join(map(str, self.args)),
@ -44,10 +53,9 @@ class ErrorMaker:
subclass EnvironmentError. subclass EnvironmentError.
""" """
Error = Error _errno2class: dict[int, type[Error]] = {}
_errno2class = {}
def __getattr__(self, name): def __getattr__(self, name: str) -> type[Error]:
if name[0] == "_": if name[0] == "_":
raise AttributeError(name) raise AttributeError(name)
eno = getattr(errno, name) eno = getattr(errno, name)
@ -55,12 +63,12 @@ class ErrorMaker:
setattr(self, name, cls) setattr(self, name, cls)
return cls return cls
def _geterrnoclass(self, eno): def _geterrnoclass(self, eno: int) -> type[Error]:
try: try:
return self._errno2class[eno] return self._errno2class[eno]
except KeyError: except KeyError:
clsname = errno.errorcode.get(eno, "UnknownErrno%d" % (eno,)) clsname = errno.errorcode.get(eno, "UnknownErrno%d" % (eno,))
errorcls = type(Error)( errorcls = type(
clsname, clsname,
(Error,), (Error,),
{"__module__": "py.error", "__doc__": os.strerror(eno)}, {"__module__": "py.error", "__doc__": os.strerror(eno)},
@ -68,36 +76,34 @@ class ErrorMaker:
self._errno2class[eno] = errorcls self._errno2class[eno] = errorcls
return errorcls return errorcls
def checked_call(self, func, *args, **kwargs): def checked_call(
"""call a function and raise an errno-exception if applicable.""" self, func: Callable[P, R], *args: P.args, **kwargs: P.kwargs
) -> R:
"""Call a function and raise an errno-exception if applicable."""
__tracebackhide__ = True __tracebackhide__ = True
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except self.Error: except Error:
raise raise
except OSError: except OSError as value:
cls, value, tb = sys.exc_info()
if not hasattr(value, "errno"): if not hasattr(value, "errno"):
raise raise
__tracebackhide__ = False
errno = value.errno errno = value.errno
try: if sys.platform == "win32":
if not isinstance(value, WindowsError):
raise NameError
except NameError:
# we are not on Windows, or we got a proper OSError
cls = self._geterrnoclass(errno)
else:
try: try:
cls = self._geterrnoclass(_winerrnomap[errno]) cls = self._geterrnoclass(_winerrnomap[errno])
except KeyError: except KeyError:
raise value raise value
else:
# we are not on Windows, or we got a proper OSError
cls = self._geterrnoclass(errno)
raise cls(f"{func.__name__}{args!r}") raise cls(f"{func.__name__}{args!r}")
__tracebackhide__ = True
_error_maker = ErrorMaker() _error_maker = ErrorMaker()
checked_call = _error_maker.checked_call
def __getattr__(attr): def __getattr__(attr: str) -> type[Error]:
return getattr(_error_maker, attr) return getattr(_error_maker, attr) # type: ignore[no-any-return]