Skip to content

Commit 7ff91d8

Browse files
authored
Merge pull request #6313 from nicoddemus/egg-rewrite-6301
Fix assertion rewriting module detection for egg dists
2 parents 42fb1f7 + c7f9fda commit 7ff91d8

File tree

3 files changed

+64
-6
lines changed

3 files changed

+64
-6
lines changed

changelog/6301.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix assertion rewriting for egg-based distributions and ``editable`` installs (``pip install --editable``).

src/_pytest/config/__init__.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,16 +630,67 @@ def __repr__(self):
630630

631631

632632
def _iter_rewritable_modules(package_files):
633+
"""
634+
Given an iterable of file names in a source distribution, return the "names" that should
635+
be marked for assertion rewrite (for example the package "pytest_mock/__init__.py" should
636+
be added as "pytest_mock" in the assertion rewrite mechanism.
637+
638+
This function has to deal with dist-info based distributions and egg based distributions
639+
(which are still very much in use for "editable" installs).
640+
641+
Here are the file names as seen in a dist-info based distribution:
642+
643+
pytest_mock/__init__.py
644+
pytest_mock/_version.py
645+
pytest_mock/plugin.py
646+
pytest_mock.egg-info/PKG-INFO
647+
648+
Here are the file names as seen in an egg based distribution:
649+
650+
src/pytest_mock/__init__.py
651+
src/pytest_mock/_version.py
652+
src/pytest_mock/plugin.py
653+
src/pytest_mock.egg-info/PKG-INFO
654+
LICENSE
655+
setup.py
656+
657+
We have to take in account those two distribution flavors in order to determine which
658+
names should be considered for assertion rewriting.
659+
660+
More information:
661+
https://github.com/pytest-dev/pytest-mock/issues/167
662+
"""
663+
package_files = list(package_files)
664+
seen_some = False
633665
for fn in package_files:
634666
is_simple_module = "/" not in fn and fn.endswith(".py")
635667
is_package = fn.count("/") == 1 and fn.endswith("__init__.py")
636668
if is_simple_module:
637669
module_name, _ = os.path.splitext(fn)
638-
yield module_name
670+
# we ignore "setup.py" at the root of the distribution
671+
if module_name != "setup":
672+
seen_some = True
673+
yield module_name
639674
elif is_package:
640675
package_name = os.path.dirname(fn)
676+
seen_some = True
641677
yield package_name
642678

679+
if not seen_some:
680+
# at this point we did not find any packages or modules suitable for assertion
681+
# rewriting, so we try again by stripping the first path component (to account for
682+
# "src" based source trees for example)
683+
# this approach lets us have the common case continue to be fast, as egg-distributions
684+
# are rarer
685+
new_package_files = []
686+
for fn in package_files:
687+
parts = fn.split("/")
688+
new_fn = "/".join(parts[1:])
689+
if new_fn:
690+
new_package_files.append(new_fn)
691+
if new_package_files:
692+
yield from _iter_rewritable_modules(new_package_files)
693+
643694

644695
class Config:
645696
"""

testing/test_config.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -422,15 +422,21 @@ def test_confcutdir_check_isdir(self, testdir):
422422
@pytest.mark.parametrize(
423423
"names, expected",
424424
[
425+
# dist-info based distributions root are files as will be put in PYTHONPATH
425426
(["bar.py"], ["bar"]),
426-
(["foo", "bar.py"], []),
427-
(["foo", "bar.pyc"], []),
428-
(["foo", "__init__.py"], ["foo"]),
429-
(["foo", "bar", "__init__.py"], []),
427+
(["foo/bar.py"], ["bar"]),
428+
(["foo/bar.pyc"], []),
429+
(["foo/__init__.py"], ["foo"]),
430+
(["bar/__init__.py", "xz.py"], ["bar", "xz"]),
431+
(["setup.py"], []),
432+
# egg based distributions root contain the files from the dist root
433+
(["src/bar/__init__.py"], ["bar"]),
434+
(["src/bar/__init__.py", "setup.py"], ["bar"]),
435+
(["source/python/bar/__init__.py", "setup.py"], ["bar"]),
430436
],
431437
)
432438
def test_iter_rewritable_modules(self, names, expected):
433-
assert list(_iter_rewritable_modules(["/".join(names)])) == expected
439+
assert list(_iter_rewritable_modules(names)) == expected
434440

435441

436442
class TestConfigFromdictargs:

0 commit comments

Comments
 (0)