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