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

Simplify pytest configuration. #7786

Merged
merged 1 commit into from May 22, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 0 additions & 8 deletions src/python/pants/backend/python/tasks/pytest/plugin.py
Expand Up @@ -73,11 +73,6 @@ def is_conftest(itm):

def pytest_addoption(parser):
group = parser.getgroup('pants', 'Pants testing support')
group.addoption('--pants-rootdir-comm-path',
dest='rootdir_comm_path',
action='store',
metavar='PATH',
help='Path to a file to write the pytest rootdir to.')
group.addoption('--pants-sources-map-path',
dest='sources_map_path',
action='store',
Expand Down Expand Up @@ -105,9 +100,6 @@ def pytest_configure(config):
return

rootdir = str(config.rootdir)
rootdir_comm_path = config.getoption('rootdir_comm_path')
with open(rootdir_comm_path, 'w') as fp:
fp.write(rootdir)

sources_map_path = config.getoption('sources_map_path')
with open(sources_map_path) as fp:
Expand Down
10 changes: 0 additions & 10 deletions src/python/pants/backend/python/tasks/pytest_prep.py
Expand Up @@ -4,7 +4,6 @@

from __future__ import absolute_import, division, print_function, unicode_literals

import os
from builtins import object

import pkg_resources
Expand Down Expand Up @@ -72,14 +71,6 @@ def interpreter(self):
"""
return self._interpreter

@property
def config_path(self):
"""Return the absolute path of the `pytest.ini` config file in this pytest binary.

:rtype: str
"""
return os.path.join(self._pex.path(), 'pytest.ini')

@classmethod
def implementation_version(cls):
return super(PytestPrep, cls).implementation_version() + [('PytestPrep', 2)]
Expand All @@ -98,7 +89,6 @@ def _module_resource(cls, module_name, resource_relpath):
content=pkg_resources.resource_string(__name__, resource_relpath))

def extra_files(self):
yield self.ExtraFile.empty('pytest.ini')
yield self._module_resource(self.PytestBinary.pytest_plugin_module, 'pytest/plugin.py')
yield self._module_resource(self.PytestBinary.coverage_plugin_module, 'coverage/plugin.py')

Expand Down
41 changes: 20 additions & 21 deletions src/python/pants/backend/python/tasks/pytest_run.py
Expand Up @@ -80,7 +80,7 @@ class PytestResult(TestResult):
# This is returned by pytest when no tests are collected (EXIT_NOTESTSCOLLECTED).
# We already short-circuit test runs with no test _targets_ to return 0 emulated exit codes and
# we should do the same for cases when there are test targets but tests themselves have been
# de-selected out of band via `py.test -k`.
# de-selected out of band via `pytest -k`.
5
)

Expand Down Expand Up @@ -378,34 +378,33 @@ def _pants_pytest_plugin_args(self, sources_map):
# uses all arguments that look like paths to compute its rootdir, and we want
# it to pick the buildroot.
with temporary_dir(root_dir=self.workdir) as comm_dir:
rootdir_comm_path = os.path.join(comm_dir, 'pytest_rootdir.path')

def get_pytest_rootdir():
with open(rootdir_comm_path, 'r') as fp:
return fp.read()

sources_map_path = os.path.join(comm_dir, 'sources_map.json')
mode = 'w' if PY3 else 'wb'
with open(sources_map_path, mode) as fp:
json.dump(sources_map, fp)

renaming_args = [
'--pants-rootdir-comm-path', rootdir_comm_path,
'--pants-sources-map-path', sources_map_path
]

yield renaming_args + self._get_sharding_args(), get_pytest_rootdir
yield renaming_args + self._get_sharding_args()

@contextmanager
def _test_runner(self, workdirs, test_targets, sources_map):
pytest_binary = self.context.products.get_data(PytestPrep.PytestBinary)
with self._pants_pytest_plugin_args(sources_map) as (plugin_args, get_pytest_rootdir):
with self._pants_pytest_plugin_args(sources_map) as plugin_args:
with self._maybe_emit_coverage_data(workdirs,
test_targets,
pytest_binary.pex) as coverage_args:
yield (pytest_binary,
['-p', pytest_binary.pytest_plugin_module] + plugin_args + coverage_args,
get_pytest_rootdir)
pytest_rootdir = get_buildroot()
jsirois marked this conversation as resolved.
Show resolved Hide resolved
yield (
pytest_binary,
[
'--rootdir', pytest_rootdir,
'-p', pytest_binary.pytest_plugin_module
] + plugin_args + coverage_args,
pytest_rootdir
)

def _constrain_pytest_interpreter_search_path(self):
"""Return an environment for invoking a pex which ensures the use of the selected interpreter.
Expand All @@ -427,11 +426,11 @@ def _do_run_tests_with_args(self, pex, args):
try:
env = dict(os.environ)

# Ensure we don't leak source files or undeclared 3rdparty requirements into the py.test PEX
# Ensure we don't leak source files or undeclared 3rdparty requirements into the pytest PEX
# environment.
pythonpath = env.pop('PYTHONPATH', None)
if pythonpath:
self.context.log.warn('scrubbed PYTHONPATH={} from py.test environment'.format(pythonpath))
self.context.log.warn('scrubbed PYTHONPATH={} from pytest environment'.format(pythonpath))
# But allow this back door for users who do want to force something onto the test pythonpath,
# e.g., modules required during a debugging session.
extra_pythonpath = self.get_options().extra_pythonpath
Expand Down Expand Up @@ -502,9 +501,9 @@ def _get_failed_targets_from_junitxml(self, junitxml, targets, pytest_rootdir):
test_failed = testcase.getElementsByTagName('failure')
test_errored = testcase.getElementsByTagName('error')
if test_failed or test_errored:
# The file attribute is always relative to the py.test rootdir.
# The file attribute is always relative to the pytest rootdir.
pytest_relpath = testcase.getAttribute('file')
relsrc = os.path.join(buildroot_relpath, pytest_relpath)
relsrc = os.path.normpath(os.path.join(buildroot_relpath, pytest_relpath))
failed_target = relsrc_to_target.get(relsrc)
if failed_target:
failed_targets.add(failed_target)
Expand All @@ -521,7 +520,7 @@ def _get_target_from_test(self, test_info, targets, pytest_rootdir):
relsrc_to_target = self._map_relsrc_to_targets(targets)
buildroot_relpath = os.path.relpath(pytest_rootdir, get_buildroot())
pytest_relpath = test_info['file']
relsrc = os.path.join(buildroot_relpath, pytest_relpath)
relsrc = os.path.normpath(os.path.join(buildroot_relpath, pytest_relpath))
return relsrc_to_target.get(relsrc)

@contextmanager
Expand Down Expand Up @@ -610,7 +609,7 @@ def _run_pytest(self, fail_fast, test_targets, workdirs):

with self._test_runner(workdirs, test_targets, sources_map) as (pytest_binary,
test_args,
get_pytest_rootdir):
pytest_rootdir):
# Validate that the user didn't provide any passthru args that conflict
# with those we must set ourselves.
for arg in self.get_passthru_args():
Expand All @@ -622,7 +621,8 @@ def _run_pytest(self, fail_fast, test_targets, workdirs):
# N.B. the `--confcutdir` here instructs pytest to stop scanning for conftest.py files at the
# top of the buildroot. This prevents conftest.py files from outside (e.g. in users home dirs)
# from leaking into pants test runs. See: https://github.com/pantsbuild/pants/issues/2726
args = ['-c', pytest_binary.config_path,
args = ['-c', os.devnull, # Force an empty pytest.ini
'-o' 'cache_dir={}'.format(os.path.join(self.workdir, '.pytest_cache')),
'--junitxml', junitxml_path,
'--confcutdir', get_buildroot(),
'--continue-on-collection-errors']
Expand Down Expand Up @@ -654,7 +654,6 @@ def _run_pytest(self, fail_fast, test_targets, workdirs):
if not os.path.exists(junitxml_path):
return result

pytest_rootdir = get_pytest_rootdir()
failed_targets = self._get_failed_targets_from_junitxml(junitxml_path,
test_targets,
pytest_rootdir)
Expand Down