Merge pull request #6545 from blueyed/terminalwriter

config: typing for create_terminal_writer, re-export TerminalWriter
This commit is contained in:
Daniel Hahler 2020-01-23 15:42:18 +01:00 committed by GitHub
commit 8ca8d25202
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 37 additions and 28 deletions

View File

@ -64,7 +64,7 @@ repos:
_code\.| _code\.|
builtin\.| builtin\.|
code\.| code\.|
io\.(BytesIO|saferepr)| io\.(BytesIO|saferepr|TerminalWriter)|
path\.local\.sysfind| path\.local\.sysfind|
process\.| process\.|
std\. std\.

View File

@ -29,6 +29,7 @@ import pluggy
import py import py
import _pytest import _pytest
from _pytest._io import TerminalWriter
from _pytest._io.saferepr import safeformat from _pytest._io.saferepr import safeformat
from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr
from _pytest.compat import overload from _pytest.compat import overload
@ -915,14 +916,14 @@ class TerminalRepr:
# FYI this is called from pytest-xdist's serialization of exception # FYI this is called from pytest-xdist's serialization of exception
# information. # information.
io = StringIO() io = StringIO()
tw = py.io.TerminalWriter(file=io) tw = TerminalWriter(file=io)
self.toterminal(tw) self.toterminal(tw)
return io.getvalue().strip() return io.getvalue().strip()
def __repr__(self) -> str: def __repr__(self) -> str:
return "<{} instance at {:0x}>".format(self.__class__, id(self)) return "<{} instance at {:0x}>".format(self.__class__, id(self))
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
raise NotImplementedError() raise NotImplementedError()
@ -933,7 +934,7 @@ class ExceptionRepr(TerminalRepr):
def addsection(self, name: str, content: str, sep: str = "-") -> None: def addsection(self, name: str, content: str, sep: str = "-") -> None:
self.sections.append((name, content, sep)) self.sections.append((name, content, sep))
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
for name, content, sep in self.sections: for name, content, sep in self.sections:
tw.sep(sep, name) tw.sep(sep, name)
tw.line(content) tw.line(content)
@ -953,7 +954,7 @@ class ExceptionChainRepr(ExceptionRepr):
self.reprtraceback = chain[-1][0] self.reprtraceback = chain[-1][0]
self.reprcrash = chain[-1][1] self.reprcrash = chain[-1][1]
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
for element in self.chain: for element in self.chain:
element[0].toterminal(tw) element[0].toterminal(tw)
if element[2] is not None: if element[2] is not None:
@ -970,7 +971,7 @@ class ReprExceptionInfo(ExceptionRepr):
self.reprtraceback = reprtraceback self.reprtraceback = reprtraceback
self.reprcrash = reprcrash self.reprcrash = reprcrash
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
self.reprtraceback.toterminal(tw) self.reprtraceback.toterminal(tw)
super().toterminal(tw) super().toterminal(tw)
@ -988,7 +989,7 @@ class ReprTraceback(TerminalRepr):
self.extraline = extraline self.extraline = extraline
self.style = style self.style = style
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
# the entries might have different styles # the entries might have different styles
for i, entry in enumerate(self.reprentries): for i, entry in enumerate(self.reprentries):
if entry.style == "long": if entry.style == "long":
@ -1020,7 +1021,7 @@ class ReprEntryNative(TerminalRepr):
def __init__(self, tblines: Sequence[str]) -> None: def __init__(self, tblines: Sequence[str]) -> None:
self.lines = tblines self.lines = tblines
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
tw.write("".join(self.lines)) tw.write("".join(self.lines))
@ -1039,7 +1040,7 @@ class ReprEntry(TerminalRepr):
self.reprfileloc = filelocrepr self.reprfileloc = filelocrepr
self.style = style self.style = style
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
if self.style == "short": if self.style == "short":
assert self.reprfileloc is not None assert self.reprfileloc is not None
self.reprfileloc.toterminal(tw) self.reprfileloc.toterminal(tw)
@ -1072,7 +1073,7 @@ class ReprFileLocation(TerminalRepr):
self.lineno = lineno self.lineno = lineno
self.message = message self.message = message
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
# filename and lineno output for each entry, # filename and lineno output for each entry,
# using an output format that most editors understand # using an output format that most editors understand
msg = self.message msg = self.message
@ -1087,7 +1088,7 @@ class ReprLocals(TerminalRepr):
def __init__(self, lines: Sequence[str]) -> None: def __init__(self, lines: Sequence[str]) -> None:
self.lines = lines self.lines = lines
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
for line in self.lines: for line in self.lines:
tw.line(line) tw.line(line)
@ -1096,7 +1097,7 @@ class ReprFuncArgs(TerminalRepr):
def __init__(self, args: Sequence[Tuple[str, object]]) -> None: def __init__(self, args: Sequence[Tuple[str, object]]) -> None:
self.args = args self.args = args
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
if self.args: if self.args:
linesofar = "" linesofar = ""
for name, value in self.args: for name, value in self.args:

View File

@ -0,0 +1,3 @@
# Reexport TerminalWriter from here instead of py, to make it easier to
# extend or swap our own implementation in the future.
from py.io import TerminalWriter as TerminalWriter # noqa: F401

View File

@ -17,6 +17,7 @@ from .pathlib import Path
from .pathlib import resolve_from_str from .pathlib import resolve_from_str
from .pathlib import rm_rf from .pathlib import rm_rf
from _pytest import nodes from _pytest import nodes
from _pytest._io import TerminalWriter
from _pytest.config import Config from _pytest.config import Config
from _pytest.main import Session from _pytest.main import Session
@ -418,7 +419,7 @@ def pytest_report_header(config):
def cacheshow(config, session): def cacheshow(config, session):
from pprint import pformat from pprint import pformat
tw = py.io.TerminalWriter() tw = TerminalWriter()
tw.line("cachedir: " + str(config.cache._cachedir)) tw.line("cachedir: " + str(config.cache._cachedir))
if not config.cache._cachedir.is_dir(): if not config.cache._cachedir.is_dir():
tw.line("cache is empty") tw.line("cache is empty")

View File

@ -36,6 +36,7 @@ from .findpaths import determine_setup
from .findpaths import exists from .findpaths import exists
from _pytest._code import ExceptionInfo from _pytest._code import ExceptionInfo
from _pytest._code import filter_traceback from _pytest._code import filter_traceback
from _pytest._io import TerminalWriter
from _pytest.compat import importlib_metadata from _pytest.compat import importlib_metadata
from _pytest.compat import TYPE_CHECKING from _pytest.compat import TYPE_CHECKING
from _pytest.outcomes import fail from _pytest.outcomes import fail
@ -73,7 +74,7 @@ def main(args=None, plugins=None) -> "Union[int, _pytest.main.ExitCode]":
config = _prepareconfig(args, plugins) config = _prepareconfig(args, plugins)
except ConftestImportFailure as e: except ConftestImportFailure as e:
exc_info = ExceptionInfo(e.excinfo) exc_info = ExceptionInfo(e.excinfo)
tw = py.io.TerminalWriter(sys.stderr) tw = TerminalWriter(sys.stderr)
tw.line( tw.line(
"ImportError while loading conftest '{e.path}'.".format(e=e), red=True "ImportError while loading conftest '{e.path}'.".format(e=e), red=True
) )
@ -99,7 +100,7 @@ def main(args=None, plugins=None) -> "Union[int, _pytest.main.ExitCode]":
finally: finally:
config._ensure_unconfigure() config._ensure_unconfigure()
except UsageError as e: except UsageError as e:
tw = py.io.TerminalWriter(sys.stderr) tw = TerminalWriter(sys.stderr)
for msg in e.args: for msg in e.args:
tw.line("ERROR: {}\n".format(msg), red=True) tw.line("ERROR: {}\n".format(msg), red=True)
return ExitCode.USAGE_ERROR return ExitCode.USAGE_ERROR
@ -1175,12 +1176,12 @@ def setns(obj, dic):
setattr(pytest, name, value) setattr(pytest, name, value)
def create_terminal_writer(config, *args, **kwargs): def create_terminal_writer(config: Config, *args, **kwargs) -> TerminalWriter:
"""Create a TerminalWriter instance configured according to the options """Create a TerminalWriter instance configured according to the options
in the config object. Every code which requires a TerminalWriter object in the config object. Every code which requires a TerminalWriter object
and has access to a config object should use this function. and has access to a config object should use this function.
""" """
tw = py.io.TerminalWriter(*args, **kwargs) tw = TerminalWriter(*args, **kwargs)
if config.option.color == "yes": if config.option.color == "yes":
tw.hasmarkup = True tw.hasmarkup = True
if config.option.color == "no": if config.option.color == "no":

View File

@ -13,13 +13,14 @@ from typing import Sequence
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
import py import py.path
import pytest import pytest
from _pytest import outcomes from _pytest import outcomes
from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ReprFileLocation from _pytest._code.code import ReprFileLocation
from _pytest._code.code import TerminalRepr from _pytest._code.code import TerminalRepr
from _pytest._io import TerminalWriter
from _pytest.compat import safe_getattr from _pytest.compat import safe_getattr
from _pytest.compat import TYPE_CHECKING from _pytest.compat import TYPE_CHECKING
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
@ -139,7 +140,7 @@ class ReprFailDoctest(TerminalRepr):
): ):
self.reprlocation_lines = reprlocation_lines self.reprlocation_lines = reprlocation_lines
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
for reprlocation, lines in self.reprlocation_lines: for reprlocation, lines in self.reprlocation_lines:
for line in lines: for line in lines:
tw.line(line) tw.line(line)

View File

@ -16,6 +16,7 @@ import py
import _pytest import _pytest
from _pytest._code.code import FormattedExcinfo from _pytest._code.code import FormattedExcinfo
from _pytest._code.code import TerminalRepr from _pytest._code.code import TerminalRepr
from _pytest._io import TerminalWriter
from _pytest.compat import _format_args from _pytest.compat import _format_args
from _pytest.compat import _PytestWrapper from _pytest.compat import _PytestWrapper
from _pytest.compat import get_real_func from _pytest.compat import get_real_func
@ -754,7 +755,7 @@ class FixtureLookupErrorRepr(TerminalRepr):
self.firstlineno = firstlineno self.firstlineno = firstlineno
self.argname = argname self.argname = argname
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
# tw.line("FixtureLookupError: %s" %(self.argname), red=True) # tw.line("FixtureLookupError: %s" %(self.argname), red=True)
for tbline in self.tblines: for tbline in self.tblines:
tw.line(tbline.rstrip()) tw.line(tbline.rstrip())

View File

@ -18,6 +18,7 @@ from _pytest._code.code import ReprFuncArgs
from _pytest._code.code import ReprLocals from _pytest._code.code import ReprLocals
from _pytest._code.code import ReprTraceback from _pytest._code.code import ReprTraceback
from _pytest._code.code import TerminalRepr from _pytest._code.code import TerminalRepr
from _pytest._io import TerminalWriter
from _pytest.compat import TYPE_CHECKING from _pytest.compat import TYPE_CHECKING
from _pytest.nodes import Node from _pytest.nodes import Node
from _pytest.outcomes import skip from _pytest.outcomes import skip
@ -80,7 +81,7 @@ class BaseReport:
.. versionadded:: 3.0 .. versionadded:: 3.0
""" """
tw = py.io.TerminalWriter(stringio=True) tw = TerminalWriter(stringio=True)
tw.hasmarkup = False tw.hasmarkup = False
self.toterminal(tw) self.toterminal(tw)
exc = tw.stringio.getvalue() exc = tw.stringio.getvalue()

View File

@ -12,6 +12,7 @@ import pytest
from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionInfo
from _pytest._code.code import FormattedExcinfo from _pytest._code.code import FormattedExcinfo
from _pytest._io import TerminalWriter
try: try:
@ -855,7 +856,7 @@ raise ValueError()
from _pytest._code.code import TerminalRepr from _pytest._code.code import TerminalRepr
class MyRepr(TerminalRepr): class MyRepr(TerminalRepr):
def toterminal(self, tw: py.io.TerminalWriter) -> None: def toterminal(self, tw: TerminalWriter) -> None:
tw.line("я") tw.line("я")
x = str(MyRepr()) x = str(MyRepr())
@ -1005,7 +1006,7 @@ raise ValueError()
""" """
) )
excinfo = pytest.raises(ValueError, mod.f) excinfo = pytest.raises(ValueError, mod.f)
tw = py.io.TerminalWriter(stringio=True) tw = TerminalWriter(stringio=True)
repr = excinfo.getrepr(**reproptions) repr = excinfo.getrepr(**reproptions)
repr.toterminal(tw) repr.toterminal(tw)
assert tw.stringio.getvalue() assert tw.stringio.getvalue()
@ -1225,7 +1226,7 @@ raise ValueError()
getattr(excinfo.value, attr).__traceback__ = None getattr(excinfo.value, attr).__traceback__ = None
r = excinfo.getrepr() r = excinfo.getrepr()
tw = py.io.TerminalWriter(stringio=True) tw = TerminalWriter(stringio=True)
tw.hasmarkup = False tw.hasmarkup = False
r.toterminal(tw) r.toterminal(tw)

View File

@ -1,7 +1,6 @@
import logging import logging
import py.io from _pytest._io import TerminalWriter
from _pytest.logging import ColoredLevelFormatter from _pytest.logging import ColoredLevelFormatter
@ -22,7 +21,7 @@ def test_coloredlogformatter():
class option: class option:
pass pass
tw = py.io.TerminalWriter() tw = TerminalWriter()
tw.hasmarkup = True tw.hasmarkup = True
formatter = ColoredLevelFormatter(tw, logfmt) formatter = ColoredLevelFormatter(tw, logfmt)
output = formatter.format(record) output = formatter.format(record)
@ -142,7 +141,7 @@ def test_colored_short_level():
class option: class option:
pass pass
tw = py.io.TerminalWriter() tw = TerminalWriter()
tw.hasmarkup = True tw.hasmarkup = True
formatter = ColoredLevelFormatter(tw, logfmt) formatter = ColoredLevelFormatter(tw, logfmt)
output = formatter.format(record) output = formatter.format(record)