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