6
6
import sys
7
7
from io import UnsupportedOperation
8
8
from tempfile import TemporaryFile
9
+ from typing import Any
10
+ from typing import AnyStr
9
11
from typing import Generator
12
+ from typing import Generic
13
+ from typing import Iterator
10
14
from typing import Optional
11
15
from typing import TextIO
12
16
from typing import Tuple
@@ -495,30 +499,32 @@ def writeorg(self, data):
495
499
# make it a namedtuple again.
496
500
# [0]: https://github.com/python/mypy/issues/685
497
501
@functools .total_ordering
498
- class CaptureResult :
502
+ class CaptureResult ( Generic [ AnyStr ]) :
499
503
"""The result of :method:`CaptureFixture.readouterr`."""
500
504
501
505
__slots__ = ("out" , "err" )
502
506
503
- def __init__ (self , out , err ) -> None :
504
- self .out = out
505
- self .err = err
507
+ def __init__ (self , out : AnyStr , err : AnyStr ) -> None :
508
+ self .out = out # type: AnyStr
509
+ self .err = err # type: AnyStr
506
510
507
511
def __len__ (self ) -> int :
508
512
return 2
509
513
510
- def __iter__ (self ):
514
+ def __iter__ (self ) -> Iterator [ AnyStr ] :
511
515
return iter ((self .out , self .err ))
512
516
513
- def __getitem__ (self , item : int ):
517
+ def __getitem__ (self , item : int ) -> AnyStr :
514
518
return tuple (self )[item ]
515
519
516
- def _replace (self , out = None , err = None ) -> "CaptureResult" :
520
+ def _replace (
521
+ self , * , out : Optional [AnyStr ] = None , err : Optional [AnyStr ] = None
522
+ ) -> "CaptureResult[AnyStr]" :
517
523
return CaptureResult (
518
524
out = self .out if out is None else out , err = self .err if err is None else err
519
525
)
520
526
521
- def count (self , value ) -> int :
527
+ def count (self , value : AnyStr ) -> int :
522
528
return tuple (self ).count (value )
523
529
524
530
def index (self , value ) -> int :
@@ -541,7 +547,7 @@ def __repr__(self) -> str:
541
547
return "CaptureResult(out={!r}, err={!r})" .format (self .out , self .err )
542
548
543
549
544
- class MultiCapture :
550
+ class MultiCapture ( Generic [ AnyStr ]) :
545
551
_state = None
546
552
_in_suspended = False
547
553
@@ -564,7 +570,7 @@ def start_capturing(self) -> None:
564
570
if self .err :
565
571
self .err .start ()
566
572
567
- def pop_outerr_to_orig (self ):
573
+ def pop_outerr_to_orig (self ) -> Tuple [ AnyStr , AnyStr ] :
568
574
"""Pop current snapshot out/err capture and flush to orig streams."""
569
575
out , err = self .readouterr ()
570
576
if out :
@@ -605,7 +611,7 @@ def stop_capturing(self) -> None:
605
611
if self .in_ :
606
612
self .in_ .done ()
607
613
608
- def readouterr (self ) -> CaptureResult :
614
+ def readouterr (self ) -> CaptureResult [ AnyStr ] :
609
615
if self .out :
610
616
out = self .out .snap ()
611
617
else :
@@ -617,7 +623,7 @@ def readouterr(self) -> CaptureResult:
617
623
return CaptureResult (out , err )
618
624
619
625
620
- def _get_multicapture (method : "_CaptureMethod" ) -> MultiCapture :
626
+ def _get_multicapture (method : "_CaptureMethod" ) -> MultiCapture [ str ] :
621
627
if method == "fd" :
622
628
return MultiCapture (in_ = FDCapture (0 ), out = FDCapture (1 ), err = FDCapture (2 ))
623
629
elif method == "sys" :
@@ -655,8 +661,8 @@ class CaptureManager:
655
661
656
662
def __init__ (self , method : "_CaptureMethod" ) -> None :
657
663
self ._method = method
658
- self ._global_capturing = None # type: Optional[MultiCapture]
659
- self ._capture_fixture = None # type: Optional[CaptureFixture]
664
+ self ._global_capturing = None # type: Optional[MultiCapture[str] ]
665
+ self ._capture_fixture = None # type: Optional[CaptureFixture[Any] ]
660
666
661
667
def __repr__ (self ) -> str :
662
668
return "<CaptureManager _method={!r} _global_capturing={!r} _capture_fixture={!r}>" .format (
@@ -705,13 +711,13 @@ def resume(self) -> None:
705
711
self .resume_global_capture ()
706
712
self .resume_fixture ()
707
713
708
- def read_global_capture (self ):
714
+ def read_global_capture (self ) -> CaptureResult [ str ] :
709
715
assert self ._global_capturing is not None
710
716
return self ._global_capturing .readouterr ()
711
717
712
718
# Fixture Control
713
719
714
- def set_fixture (self , capture_fixture : "CaptureFixture" ) -> None :
720
+ def set_fixture (self , capture_fixture : "CaptureFixture[Any] " ) -> None :
715
721
if self ._capture_fixture :
716
722
current_fixture = self ._capture_fixture .request .fixturename
717
723
requested_fixture = capture_fixture .request .fixturename
@@ -810,14 +816,14 @@ def pytest_internalerror(self) -> None:
810
816
self .stop_global_capturing ()
811
817
812
818
813
- class CaptureFixture :
819
+ class CaptureFixture ( Generic [ AnyStr ]) :
814
820
"""Object returned by the :py:func:`capsys`, :py:func:`capsysbinary`,
815
821
:py:func:`capfd` and :py:func:`capfdbinary` fixtures."""
816
822
817
823
def __init__ (self , captureclass , request : SubRequest ) -> None :
818
824
self .captureclass = captureclass
819
825
self .request = request
820
- self ._capture = None # type: Optional[MultiCapture]
826
+ self ._capture = None # type: Optional[MultiCapture[AnyStr] ]
821
827
self ._captured_out = self .captureclass .EMPTY_BUFFER
822
828
self ._captured_err = self .captureclass .EMPTY_BUFFER
823
829
@@ -836,7 +842,7 @@ def close(self) -> None:
836
842
self ._capture .stop_capturing ()
837
843
self ._capture = None
838
844
839
- def readouterr (self ):
845
+ def readouterr (self ) -> CaptureResult [ AnyStr ] :
840
846
"""Read and return the captured output so far, resetting the internal
841
847
buffer.
842
848
@@ -875,15 +881,15 @@ def disabled(self) -> Generator[None, None, None]:
875
881
876
882
877
883
@pytest .fixture
878
- def capsys (request : SubRequest ) -> Generator [CaptureFixture , None , None ]:
884
+ def capsys (request : SubRequest ) -> Generator [CaptureFixture [ str ] , None , None ]:
879
885
"""Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``.
880
886
881
887
The captured output is made available via ``capsys.readouterr()`` method
882
888
calls, which return a ``(out, err)`` namedtuple.
883
889
``out`` and ``err`` will be ``text`` objects.
884
890
"""
885
891
capman = request .config .pluginmanager .getplugin ("capturemanager" )
886
- capture_fixture = CaptureFixture (SysCapture , request )
892
+ capture_fixture = CaptureFixture [ str ] (SysCapture , request )
887
893
capman .set_fixture (capture_fixture )
888
894
capture_fixture ._start ()
889
895
yield capture_fixture
@@ -892,15 +898,15 @@ def capsys(request: SubRequest) -> Generator[CaptureFixture, None, None]:
892
898
893
899
894
900
@pytest .fixture
895
- def capsysbinary (request : SubRequest ) -> Generator [CaptureFixture , None , None ]:
901
+ def capsysbinary (request : SubRequest ) -> Generator [CaptureFixture [ bytes ] , None , None ]:
896
902
"""Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``.
897
903
898
904
The captured output is made available via ``capsysbinary.readouterr()``
899
905
method calls, which return a ``(out, err)`` namedtuple.
900
906
``out`` and ``err`` will be ``bytes`` objects.
901
907
"""
902
908
capman = request .config .pluginmanager .getplugin ("capturemanager" )
903
- capture_fixture = CaptureFixture (SysCaptureBinary , request )
909
+ capture_fixture = CaptureFixture [ bytes ] (SysCaptureBinary , request )
904
910
capman .set_fixture (capture_fixture )
905
911
capture_fixture ._start ()
906
912
yield capture_fixture
@@ -909,15 +915,15 @@ def capsysbinary(request: SubRequest) -> Generator[CaptureFixture, None, None]:
909
915
910
916
911
917
@pytest .fixture
912
- def capfd (request : SubRequest ) -> Generator [CaptureFixture , None , None ]:
918
+ def capfd (request : SubRequest ) -> Generator [CaptureFixture [ str ] , None , None ]:
913
919
"""Enable text capturing of writes to file descriptors ``1`` and ``2``.
914
920
915
921
The captured output is made available via ``capfd.readouterr()`` method
916
922
calls, which return a ``(out, err)`` namedtuple.
917
923
``out`` and ``err`` will be ``text`` objects.
918
924
"""
919
925
capman = request .config .pluginmanager .getplugin ("capturemanager" )
920
- capture_fixture = CaptureFixture (FDCapture , request )
926
+ capture_fixture = CaptureFixture [ str ] (FDCapture , request )
921
927
capman .set_fixture (capture_fixture )
922
928
capture_fixture ._start ()
923
929
yield capture_fixture
@@ -926,15 +932,15 @@ def capfd(request: SubRequest) -> Generator[CaptureFixture, None, None]:
926
932
927
933
928
934
@pytest .fixture
929
- def capfdbinary (request : SubRequest ) -> Generator [CaptureFixture , None , None ]:
935
+ def capfdbinary (request : SubRequest ) -> Generator [CaptureFixture [ bytes ] , None , None ]:
930
936
"""Enable bytes capturing of writes to file descriptors ``1`` and ``2``.
931
937
932
938
The captured output is made available via ``capfd.readouterr()`` method
933
939
calls, which return a ``(out, err)`` namedtuple.
934
940
``out`` and ``err`` will be ``byte`` objects.
935
941
"""
936
942
capman = request .config .pluginmanager .getplugin ("capturemanager" )
937
- capture_fixture = CaptureFixture (FDCaptureBinary , request )
943
+ capture_fixture = CaptureFixture [ bytes ] (FDCaptureBinary , request )
938
944
capman .set_fixture (capture_fixture )
939
945
capture_fixture ._start ()
940
946
yield capture_fixture
0 commit comments