Source code for pykern.pytest_plugin

# -*- coding: utf-8 -*-
u"""PyTest plugin to setup pkconfig and add pkunit fixtures

This plugin will only be "active" if the in the package
imports `pykern.pksetup`. This module turns on ``pytest-xdist``'s
``--boxed`` option. It also calls `pykern.pkconfig.append_load_path`,
which modifies global state.

:copyright: Copyright (c) 2016 RadiaSoft LLC.  All Rights Reserved.
from __future__ import absolute_import, division, print_function
import pytest
# Do not import anything from pykern here

#: Is py.test being run in a package with a that imports pksetup
_uses_pykern = False

#: Initialized below
_no_recurse = None

[docs]@pytest.hookimpl(tryfirst=True) def pytest_ignore_collect(path, config): """Ignore _work and _data directories """ if not _uses_pykern: return False global _no_recurse if not _no_recurse: import re _no_recurse = re.compile(r'(_work|_data)$') return bool(
[docs]@pytest.hookimpl(tryfirst=True) def pytest_configure(config): """See if package uses `pykern`, and set options accordingly Args: config (_pytest.config.Config): used for options """ root_d = _setup_py_parser() if not root_d: return import os if not os.environ.get('PYKERN_PKDEBUG_OUTPUT'): # Work around # xdist/forked don't allow capture. It's too hard to debug # without seeing output os.environ['PYKERN_PKDEBUG_OUTPUT'] = '/dev/stderr' from pykern import pkconfig pkconfig.append_load_path(root_d.basename) import os if hasattr(os, 'fork'): config._parser.parse_setoption( # run each test file in a separate process # the native trace works better, e.g. for emacs ['--forked', '--tb=native'], config.option, namespace=config.option, )
[docs]@pytest.hookimpl(tryfirst=True) def pytest_runtest_protocol(item, *args, **kwargs): """Make sure work directory is empty for a module. If `item` is in a module not seen before, it removes the `pkunit.work_dir`. Args: item (Item): pytest test item (case) Returns: None: always so that the next hook runs the item. """ if not _uses_pykern: return from pykern import pkunit # Seems to be the only way to get the module under test m = item._request.module is_new = m != pkunit.module_under_test pkunit.module_under_test = m if is_new: from pykern import pkio pkio.unchecked_remove(pkunit.work_dir())
def _setup_py_parser(): """Look for and set `_uses_pykern` Returns: str: root dir containing or None """ global _uses_pykern import py.path prev_p = None p = py.path.local() while prev_p != p: prev_p = p s = p.join('') if s.check(file=True): break p = py.path.local(p.dirname) else: return None _uses_pykern = _setup_py_contains_pykern(s) if _uses_pykern: return p return None def _setup_py_contains_pykern(setup_py): """Parses to see if it imports pykern This is hacky, but good enough because pykern and pksetup are unique names. If someone comments out with a multiline string, it's not super dangerous. Args: setup_py (py.path): file name Returns: bool: True if imports pykern and pksetup """ import re with open(str(setup_py)) as f: return bool( r'^\s*(from|import)\s+pykern\b.*\bpksetup\b',, flags=re.MULTILINE, ), )