Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pytest stdout capturing #397

Merged
merged 2 commits into from
Apr 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions brownie/_cli/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
--network [name] Use a specific network (default {CONFIG['network']['default']})

Pytest Options:
-s Disable stdout capture when running tests
-n [numprocesses] Number of workers to use for xdist distributed testing,
set to 'auto' for automatic detection of number of CPUs
--durations [num] show slowest setup/test durations (num=0 for all)
Expand Down
40 changes: 40 additions & 0 deletions brownie/test/managers/runner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/python3

import builtins
import json
import sys
import warnings

import pytest
Expand All @@ -10,6 +12,7 @@
from brownie.exceptions import VirtualMachineError
from brownie.network.state import _get_current_dependencies
from brownie.test import coverage, output
from brownie.utils import color

from .base import PytestBrownieBase
from .utils import convert_outcome
Expand Down Expand Up @@ -56,11 +59,41 @@ def __exit__(self, exc_type, exc_value, traceback):
) from None


class PytestPrinter:
"""
Custom printer for test execution.

Produces more-readable output when stdout capture is disabled.
"""

_builtins_print = builtins.print

def start(self):
self.first_line = True
builtins.print = self

def __call__(self, text):
if self.first_line:
self.first_line = False
sys.stdout.write(f"{color('yellow')}RUNNING{color}\n")
sys.stdout.write(f"{text}\n")
sys.stdout.flush()

def finish(self, nodeid):
if not self.first_line:
sys.stdout.write(f"{nodeid} ")
sys.stdout.flush()
builtins.print = self._builtins_print


class PytestBrownieRunner(PytestBrownieBase):
def __init__(self, config, project):
super().__init__(config, project)
brownie.reverts = RevertContextManager
pytest.reverts = revert_deprecation
self.printer = None
if config.getoption("capture") == "no":
self.printer = PytestPrinter()

def pytest_generate_tests(self, metafunc):
# module_isolation always runs before other module scoped functions
Expand Down Expand Up @@ -122,6 +155,9 @@ def _make_nodemap(self, ids):

def pytest_runtest_protocol(self, item):
# does not run on master
if self.printer:
self.printer.start()

path, test = self._test_id(item.nodeid)
if path not in self.results:
if path in self.tests and ARGV["update"]:
Expand Down Expand Up @@ -164,6 +200,10 @@ def pytest_runtest_logreport(self, report):
"results": "".join(self.results[path]),
}

def pytest_report_teststatus(self, report):
if self.printer and report.when == "call":
self.printer.finish(report.nodeid)

def pytest_sessionfinish(self):
self._sessionfinish("build/tests.json")
if ARGV["gas"]:
Expand Down
4 changes: 4 additions & 0 deletions brownie/test/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def pytest_configure(config):
active_project.load_config()
active_project._add_to_main_namespace()

# enable verbose output if stdout capture is disabled
if config.getoption("capture") == "no":
config.option.verbose = True

if config.getoption("numprocesses"):
Plugin = PytestBrownieMaster
elif hasattr(config, "workerinput"):
Expand Down
9 changes: 9 additions & 0 deletions tests/test/plugin/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
test_source = """
def test_stuff(BrownieTester, accounts):
c = accounts[0].deploy(BrownieTester, True)
print('oh hai mark')
c.doNothing({'from': accounts[0]})"""


Expand Down Expand Up @@ -41,3 +42,11 @@ def test_coverage_save_report(plugintester):
next(path.glob("*")).open("w").write("this isn't json, is it?")
plugintester.runpytest("-C")
assert [i.name for i in path.glob("*")] == ["coverage.json"]


def test_stdout_capture(plugintester):
result = plugintester.runpytest("-s")
output = result.stdout.str()

assert output.count("::test_stuff") == 2
assert "oh hai mark" in output