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

WIP: Revert "deps: py!=1.8.2,py!=1.9.0" #393

Open
wants to merge 16 commits into
base: my-master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: "ubuntu-py38"
python: "3.8"
os: ubuntu-latest
tox_env: "py38-numpy-oldattrs-twisted-coverage"
tox_env: "py38-numpy-oldattrs-oldpluggy-twisted-coverage"
- name: "ubuntu-pypy3"
python: "pypy3"
os: ubuntu-latest
Expand Down
30 changes: 18 additions & 12 deletions src/_pytest/assertion/rewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from typing import Set
from typing import Tuple

import py.path

from _pytest._io.saferepr import safeformat
from _pytest._io.saferepr import saferepr
from _pytest._version import version
Expand All @@ -27,10 +29,15 @@
format_explanation as _format_explanation,
)
from _pytest.compat import fspath
from _pytest.compat import TYPE_CHECKING
from _pytest.pathlib import fnmatch_ex
from _pytest.pathlib import Path
from _pytest.pathlib import PurePath

if TYPE_CHECKING:
from _pytest.assertion import AssertionState
from _pytest.main import Session

# pytest caches rewritten pycs in pycache dirs
PYTEST_TAG = "{}-pytest-{}".format(sys.implementation.cache_tag, version)
PYC_EXT = ".py" + (__debug__ and "c" or "o")
Expand All @@ -46,7 +53,7 @@ def __init__(self, config):
self.fnpats = config.getini("python_files")
except ValueError:
self.fnpats = ["test_*.py", "*_test.py"]
self.session = None
self.session = None # type: Optional[Session]
self._rewritten_names = set() # type: Set[str]
self._must_rewrite = set() # type: Set[str]
# flag to guard against trying to rewrite a pyc file while we are already writing another pyc file,
Expand All @@ -56,7 +63,7 @@ def __init__(self, config):
self._marked_for_rewrite_cache = {} # type: Dict[str, bool]
self._session_paths_checked = False

def set_session(self, session):
def set_session(self, session: "Optional[Session]") -> None:
self.session = session
self._session_paths_checked = False

Expand Down Expand Up @@ -90,7 +97,7 @@ def find_spec(self, name, path=None, target=None):
else:
fn = spec.origin

if not self._should_rewrite(name, fn, state):
if not self._should_rewrite(name, py.path.local(fn), state):
return None

return importlib.util.spec_from_file_location(
Expand Down Expand Up @@ -182,30 +189,29 @@ def _early_rewrite_bailout(self, name, state):
state.trace("early skip of rewriting module: {}".format(name))
return True

def _should_rewrite(self, name, fn, state):
def _should_rewrite(self, name: str, path: "py.path.local", state: "AssertionState") -> bool:
# always rewrite conftest files
if os.path.basename(fn) == "conftest.py":
state.trace("rewriting conftest file: {!r}".format(fn))
if path.basename == "conftest.py":
state.trace("rewriting conftest file: {}".format(path))
return True

if self.session is not None:
if self.session.isinitpath(fn):
if self.session.isinitpath(path):
state.trace(
"matched test file (was specified on cmdline): {!r}".format(fn)
"matched test file (was specified on cmdline): {}".format(path)
)
return True

# modules not passed explicitly on the command line are only
# rewritten if they match the naming convention for test files
fn_path = PurePath(fn)
for pat in self.fnpats:
if fnmatch_ex(pat, fn_path):
state.trace("matched test file {!r}".format(fn))
if fnmatch_ex(pat, path):
state.trace("matched test file {}".format(path))
return True

return self._is_marked_for_rewrite(name, state)

def _is_marked_for_rewrite(self, name: str, state):
def _is_marked_for_rewrite(self, name: str, state: "AssertionState") -> bool:
try:
return self._marked_for_rewrite_cache[name]
except KeyError:
Expand Down
16 changes: 10 additions & 6 deletions src/_pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@


if TYPE_CHECKING:
from typing import Generator
from typing import Set
from typing import Type
from typing_extensions import Literal

Expand Down Expand Up @@ -458,7 +460,7 @@ def pytest_runtest_logreport(self, report):

pytest_collectreport = pytest_runtest_logreport

def isinitpath(self, path):
def isinitpath(self, path: "py.path.local") -> bool:
return path in self._initialpaths

def gethookproxy(self, fspath: py.path.local):
Expand Down Expand Up @@ -538,7 +540,9 @@ def collect(self):
self._collection_node_cache3.clear()
self._collection_pkg_roots.clear()

def _collect(self, argpath, names):
def _collect(
self, argpath: "py.path.local", names: "List[str]"
) -> "Generator[Union[nodes.Item, nodes.Collector], None, None]":
from _pytest.python import Package

# Start with a Session root, and delve to argpath item (dir or file)
Expand Down Expand Up @@ -566,15 +570,15 @@ def _collect(self, argpath, names):
if argpath.check(dir=1):
assert not names, "invalid arg {!r}".format((argpath, names))

seen_dirs = set()
seen_dirs = set() # type: Set[py.path.local]
for path in argpath.visit(
fil=self._visit_filter, rec=self._recurse, bf=True, sort=True
):
dirpath = path.dirpath()
if dirpath not in seen_dirs:
# Collect packages first.
seen_dirs.add(dirpath)
pkginit = dirpath.join("__init__.py")
pkginit = path.dirpath().join("__init__.py")
if pkginit.exists():
for x in self._collectfile(pkginit):
yield x
Expand All @@ -597,7 +601,7 @@ def _collect(self, argpath, names):
if argpath in self._collection_node_cache1:
col = self._collection_node_cache1[argpath]
else:
collect_root = self._collection_pkg_roots.get(argpath.dirname, self)
collect_root = self._collection_pkg_roots.get(argpath.dirpath(), self)
col = collect_root._collectfile(argpath, handle_dupes=False)
if col:
self._collection_node_cache1[argpath] = col
Expand All @@ -614,7 +618,7 @@ def _collect(self, argpath, names):
# file in it, which gets ignored by the default
# "python_files" option.
pass
return
return None
yield from m

@staticmethod
Expand Down
6 changes: 0 additions & 6 deletions src/_pytest/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from posixpath import sep as posix_sep
from typing import Iterable
from typing import Iterator
from typing import Set
from typing import TypeVar
from typing import Union

Expand Down Expand Up @@ -362,11 +361,6 @@ def fnmatch_ex(pattern: str, path) -> bool:
return fnmatch.fnmatch(name, pattern)


def parts(s: str) -> Set[str]:
parts = s.split(sep)
return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))}


def _shorten_path(path: str, relative_to: str = None) -> str:
if not os.path.isabs(path):
return path
Expand Down
24 changes: 14 additions & 10 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@
from _pytest.mark.structures import normalize_mark_list
from _pytest.outcomes import fail
from _pytest.outcomes import skip
from _pytest.pathlib import parts
from _pytest.warning_types import PytestCollectionWarning
from _pytest.warning_types import PytestUnhandledCoroutineWarning

if TYPE_CHECKING:
from typing import Iterator
from typing import Set

from _pytest._io import TerminalWriter


Expand Down Expand Up @@ -605,30 +607,32 @@ def setup(self):
def gethookproxy(self, fspath: py.path.local):
return super()._gethookproxy(fspath)

def isinitpath(self, path):
def isinitpath(self, path: "py.path.local") -> bool:
assert isinstance(path, py.path.local), repr(path)
return path in self.session._initialpaths

def collect(self):
def collect(self) -> "Iterator[Union[nodes.Item, nodes.Collector]]":
this_path = self.fspath.dirpath()
init_module = this_path.join("__init__.py")
if init_module.check(file=1) and path_matches_patterns(
init_module, self.config.getini("python_files")
):
yield Module.from_parent(self, fspath=init_module)
pkg_prefixes = set()

pkg_prefixes = set() # type: Set[py.path.local]
for path in this_path.visit(rec=self._recurse, bf=True, sort=True):
# We will visit our own __init__.py file, in which case we skip it.
is_file = path.isfile()
if is_file:
if path.basename == "__init__.py" and path.dirpath() == this_path:
continue

parts_ = parts(path.strpath)
if any(
pkg_prefix in parts_ and pkg_prefix.join("__init__.py") != path
for pkg_prefix in pkg_prefixes
):
continue
parts_ = path.parts()
if any(
pkg_prefix in parts_ and pkg_prefix.join("__init__.py") != path
for pkg_prefix in pkg_prefixes
):
continue

if is_file:
yield from self._collectfile(path)
Expand Down
15 changes: 10 additions & 5 deletions testing/test_assertrewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@
from _pytest.assertion.rewrite import PYC_TAIL
from _pytest.assertion.rewrite import PYTEST_TAG
from _pytest.assertion.rewrite import rewrite_asserts
from _pytest.compat import TYPE_CHECKING
from _pytest.config import ExitCode
from _pytest.pathlib import Path
from _pytest.pytester import Testdir

if TYPE_CHECKING:
from typing import List
from typing import Set


def setup_module(mod):
mod._old_reprcompare = util._reprcompare
Expand Down Expand Up @@ -1250,14 +1255,14 @@ def spy_write_pyc(*args, **kwargs):

class TestEarlyRewriteBailout:
@pytest.fixture
def hook(self, pytestconfig, monkeypatch, testdir):
def hook(self, pytestconfig, monkeypatch, testdir) -> AssertionRewritingHook:
"""Returns a patched AssertionRewritingHook instance so we can configure its initial paths and track
if PathFinder.find_spec has been called.
"""
import importlib.machinery

self.find_spec_calls = []
self.initial_paths = set()
self.find_spec_calls = [] # type: List[str]
self.initial_paths = set() # type: Set[py.path.local]

class StubSession:
_initialpaths = self.initial_paths
Expand All @@ -1273,11 +1278,11 @@ def spy_find_spec(name, path):
# use default patterns, otherwise we inherit pytest's testing config
hook.fnpats[:] = ["test_*.py", "*_test.py"]
monkeypatch.setattr(hook, "_find_spec", spy_find_spec)
hook.set_session(StubSession())
hook.set_session(StubSession()) # type: ignore[arg-type]
testdir.syspathinsert()
return hook

def test_basic(self, testdir, hook):
def test_basic(self, testdir: "Testdir", hook: AssertionRewritingHook) -> None:
"""
Ensure we avoid calling PathFinder.find_spec when we know for sure a certain
module will not be rewritten to optimize assertion rewriting (#3918).
Expand Down
3 changes: 1 addition & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,14 @@ deps =
doctesting: PyYAML
grouped: pytest-test-groups
oldattrs: attrs==17.4.0
oldpluggy: pluggy==0.13.1
numpy: numpy
pexpect: pexpect
pluggymaster: git+https://github.com/pytest-dev/pluggy.git@master
pygments: pygments
twisted: {env:_PYTEST_TOX_TWISTED:twisted}
xdist: pytest-xdist>=1.13
{env:_PYTEST_TOX_EXTRA_DEP:}
# Pin pylib for Windows (pending investigation of test failures).
py>=1.5.0,!=1.8.2,<1.9.0 ; sys_platform == 'win32'

[testenv:upstream]
skip_install = True
Expand Down