capture: `CaptureResult` can be a namedtuple again (#10678)
mypy now supports generic NamedTuple.
This commit is contained in:
parent
5a23eeff7a
commit
6a714d7b70
|
@ -1,6 +1,6 @@
|
||||||
"""Per-test stdout/stderr capturing mechanism."""
|
"""Per-test stdout/stderr capturing mechanism."""
|
||||||
|
import collections
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -10,7 +10,7 @@ from typing import Any
|
||||||
from typing import AnyStr
|
from typing import AnyStr
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
from typing import Iterator
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import TextIO
|
from typing import TextIO
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
@ -492,59 +492,24 @@ class FDCapture(FDCaptureBinary):
|
||||||
# MultiCapture
|
# MultiCapture
|
||||||
|
|
||||||
|
|
||||||
# This class was a namedtuple, but due to mypy limitation[0] it could not be
|
# Generic NamedTuple only supported since Python 3.11.
|
||||||
# made generic, so was replaced by a regular class which tries to emulate the
|
if sys.version_info >= (3, 11) or TYPE_CHECKING:
|
||||||
# pertinent parts of a namedtuple. If the mypy limitation is ever lifted, can
|
|
||||||
# make it a namedtuple again.
|
|
||||||
# [0]: https://github.com/python/mypy/issues/685
|
|
||||||
@final
|
|
||||||
@functools.total_ordering
|
|
||||||
class CaptureResult(Generic[AnyStr]):
|
|
||||||
"""The result of :method:`CaptureFixture.readouterr`."""
|
|
||||||
|
|
||||||
__slots__ = ("out", "err")
|
@final
|
||||||
|
class CaptureResult(NamedTuple, Generic[AnyStr]):
|
||||||
|
"""The result of :method:`CaptureFixture.readouterr`."""
|
||||||
|
|
||||||
def __init__(self, out: AnyStr, err: AnyStr) -> None:
|
out: AnyStr
|
||||||
self.out: AnyStr = out
|
err: AnyStr
|
||||||
self.err: AnyStr = err
|
|
||||||
|
|
||||||
def __len__(self) -> int:
|
else:
|
||||||
return 2
|
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[AnyStr]:
|
class CaptureResult(
|
||||||
return iter((self.out, self.err))
|
collections.namedtuple("CaptureResult", ["out", "err"]), Generic[AnyStr]
|
||||||
|
):
|
||||||
|
"""The result of :method:`CaptureFixture.readouterr`."""
|
||||||
|
|
||||||
def __getitem__(self, item: int) -> AnyStr:
|
__slots__ = ()
|
||||||
return tuple(self)[item]
|
|
||||||
|
|
||||||
def _replace(
|
|
||||||
self, *, out: Optional[AnyStr] = None, err: Optional[AnyStr] = None
|
|
||||||
) -> "CaptureResult[AnyStr]":
|
|
||||||
return CaptureResult(
|
|
||||||
out=self.out if out is None else out, err=self.err if err is None else err
|
|
||||||
)
|
|
||||||
|
|
||||||
def count(self, value: AnyStr) -> int:
|
|
||||||
return tuple(self).count(value)
|
|
||||||
|
|
||||||
def index(self, value) -> int:
|
|
||||||
return tuple(self).index(value)
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if not isinstance(other, (CaptureResult, tuple)):
|
|
||||||
return NotImplemented
|
|
||||||
return tuple(self) == tuple(other)
|
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
|
||||||
return hash(tuple(self))
|
|
||||||
|
|
||||||
def __lt__(self, other: object) -> bool:
|
|
||||||
if not isinstance(other, (CaptureResult, tuple)):
|
|
||||||
return NotImplemented
|
|
||||||
return tuple(self) < tuple(other)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"CaptureResult(out={self.out!r}, err={self.err!r})"
|
|
||||||
|
|
||||||
|
|
||||||
class MultiCapture(Generic[AnyStr]):
|
class MultiCapture(Generic[AnyStr]):
|
||||||
|
|
Loading…
Reference in New Issue