Skip to content

Commit

Permalink
Merge branch 'my-master' into mm-revert-from_parent
Browse files Browse the repository at this point in the history
  • Loading branch information
blueyed committed Sep 2, 2020
2 parents 12cd31e + 390945c commit 57e6725
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 43 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
# LsofFdLeakChecker itself.
# (https://github.com/blueyed/pytest/issues/195)
tox_env: "py38-lsof-pexpect-coverage"
pytest_addopts: "-m 'uses_pexpect or integration' --run-integration-tests"
pytest_addopts: "-m 'uses_pexpect or integration'"
script_prefix: "env -u COLUMNS"

# Coverage for:
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
dist: trusty
env:
- TOXENV=py35-coverage
- PYTEST_ADDOPTS="-ra --durations=50 -m 'py35_specific or acceptance_tests'"
- PYTEST_ADDOPTS="-ra --durations=50 -m 'py35_specific or acceptance_tests or integration'"
before_install:
- python -m pip install -U pip==19.3.1
# Coverage for Python 3.9
Expand Down
1 change: 1 addition & 0 deletions changelog/6981.deprecation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The forwarding attributes from `pytest.collect.X` (to `pytest.X`) are deprecated (`pytest.collect` was not a module since 3.0.7-161-gae234786e (in 2017) already).
47 changes: 29 additions & 18 deletions src/_pytest/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
import re
import sys
import warnings
from contextlib import contextmanager
from inspect import Parameter
from inspect import signature
Expand Down Expand Up @@ -34,6 +35,7 @@


if TYPE_CHECKING:
from typing import List
from types import ModuleType # noqa: F401 (used in type string)
from typing import Type # noqa: F401 (used in type string)

Expand Down Expand Up @@ -340,25 +342,34 @@ def safe_isclass(obj: object) -> bool:
def _setup_collect_fakemodule() -> "ModuleType":
"""Setup pytest.collect fake module for backward compatibility."""
from types import ModuleType
import _pytest.nodes

collect_fakemodule_attributes = (
("Collector", _pytest.nodes.Collector),
("Module", _pytest.python.Module),
("Function", _pytest.python.Function),
("Instance", _pytest.python.Instance),
("Session", _pytest.main.Session),
("Item", _pytest.nodes.Item),
("Class", _pytest.python.Class),
("File", _pytest.nodes.File),
("_fillfuncargs", _pytest.fixtures.fillfixtures),
)

mod = ModuleType("pytest.collect")
mod.__all__ = [] # type: ignore # used for setns (obsolete?)
for attr_name, value in collect_fakemodule_attributes:
setattr(mod, attr_name, value)
return mod
import _pytest.nodes
from _pytest.deprecated import PYTEST_COLLECT_MODULE

collect_fakemodule_attributes = {
"Collector": _pytest.nodes.Collector,
"Module": _pytest.python.Module,
"Function": _pytest.python.Function,
"Instance": _pytest.python.Instance,
"Session": _pytest.main.Session,
"Item": _pytest.nodes.Item,
"Class": _pytest.python.Class,
"File": _pytest.nodes.File,
"_fillfuncargs": _pytest.fixtures.fillfixtures,
}

class FakeCollectModule(ModuleType):
def __init__(self) -> None:
super().__init__("pytest.collect")
self.__all__ = [] # type: List[str] # backward compatibility.

def __getattr__(self, name: str) -> Any:
if name in collect_fakemodule_attributes:
warnings.warn(PYTEST_COLLECT_MODULE.format(name=name), stacklevel=2)
return collect_fakemodule_attributes[name]
raise AttributeError(name)

return FakeCollectModule()


class CaptureIO(io.TextIOWrapper):
Expand Down
6 changes: 6 additions & 0 deletions src/_pytest/deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
"pytest_faulthandler",
}

PYTEST_COLLECT_MODULE = UnformattedWarning(
PytestDeprecationWarning,
"pytest.collect.{name} was moved to pytest.{name}\n"
"Please update to the new name.",
)

FUNCARGNAMES = PytestDeprecationWarning(
"The `funcargnames` attribute was an alias for `fixturenames`, "
"since pytest 2.3 - use the newer attribute instead."
Expand Down
6 changes: 6 additions & 0 deletions testing/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import List

import pytest
from _pytest.mark.legacy import matchmark
from _pytest.pytester import RunResult


Expand Down Expand Up @@ -41,6 +42,11 @@ def pytest_runtest_setup(item):
if any(item.nodeid == arg for arg in item.config.invocation_params.args):
return

# Run the test if selected by mark explicitly.
markexpr = item.config.option.markexpr
if markexpr and matchmark(item, markexpr):
return

pytest.skip("Not running {} test (use {})".format(mark, option))


Expand Down
24 changes: 24 additions & 0 deletions testing/deprecated_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@
from _pytest import deprecated


@pytest.mark.parametrize(
"attribute",
(
"Collector",
"Module",
"Function",
"Instance",
"Session",
"Item",
"Class",
"File",
"_fillfuncargs",
),
)
def test_pytest_collect_module_deprecated(attribute: str) -> None:
msg = str(deprecated.PYTEST_COLLECT_MODULE.format(name=attribute))
with pytest.warns(DeprecationWarning, match=msg) as wr:
getattr(pytest.collect, attribute)
assert len(wr) == 1
assert wr[0].filename == __file__
f_lineno = inspect.currentframe().f_lineno # type: ignore[union-attr]
assert wr[0].lineno == f_lineno - 3


@pytest.mark.filterwarnings("default")
def test_resultlog_is_deprecated(testdir):
result = testdir.runpytest("--help")
Expand Down
40 changes: 20 additions & 20 deletions testing/python/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,37 +864,37 @@ def __world(): pass
modcol.collect()
assert values == ["_hello"]

def test_issue2369_collect_module_fileext(self, testdir):
"""Ensure we can collect files with weird file extensions as Python
def test_issue2369_collect_module_fileext(self, testdir: "Testdir") -> None:
"""Ensure we can collect files with custom file extensions as Python
modules (#2369)"""
# We'll implement a little finder and loader to import files containing
# Python source code whose file extension is ".narf".
testdir.makeconftest(
"""
import sys, os, imp
from importlib.machinery import SourceFileLoader
from importlib.util import spec_from_file_location
import os
import sys
from _pytest.python import Module
class Loader(object):
def load_module(self, name):
return imp.load_source(name, name + ".narf")
class Finder(object):
def find_module(self, name, path=None):
if os.path.exists(name + ".narf"):
return Loader()
class Finder:
@classmethod
def find_spec(cls, fullname, path=None, target=None):
location = os.path.abspath(fullname + ".narf")
if os.path.exists(location):
return spec_from_file_location(
fullname,
location,
loader=SourceFileLoader(fullname, location),
)
sys.meta_path.append(Finder())
def pytest_collect_file(path, parent):
if path.ext == ".narf":
return Module(path, parent)"""
)
testdir.makefile(
".narf",
"""\
def test_something():
assert 1 + 1 == 2""",
)
# Use runpytest_subprocess, since we're futzing with sys.meta_path.
result = testdir.runpytest_subprocess()
testdir.makefile(".narf", "def test_pass(): pass")
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*1 passed*"])


Expand Down
16 changes: 13 additions & 3 deletions testing/test_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,35 @@ def test_no_warnings(module: str) -> None:
# fmt: on


def test_pytest_collect_attribute(_sys_snapshot):
@pytest.mark.filterwarnings(
"ignore:pytest.collect.Item was moved to pytest.Item:pytest.PytestDeprecationWarning",
)
def test_pytest_collect_attribute(_sys_snapshot) -> None:
from types import ModuleType

del sys.modules["pytest"]

import pytest

assert isinstance(pytest.collect, ModuleType)
assert pytest.collect.Item is pytest.Item
assert pytest.collect.Item is pytest.Item # type: ignore[attr-defined]

with pytest.raises(ImportError):
import pytest.collect

from pytest import collect

with pytest.raises(AttributeError):
collect.doesnotexist # type: ignore[attr-defined]


def test_pytest___get_attr__(_sys_snapshot) -> None:
if sys.version_info >= (3, 7):
with pytest.raises(AttributeError, match=r"^doesnotexist$"):
pytest.doesnotexist
else:
with pytest.raises(AttributeError, match=r"doesnotexist"):
pytest.doesnotexist
pytest.doesnotexist # type: ignore[attr-defined]


def test_pytest_circular_import(testdir: Testdir, symlink_or_skip) -> None:
Expand Down

0 comments on commit 57e6725

Please sign in to comment.