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: #9298 - add testing and debugging for the pycache_prefix #9317

179 changes: 90 additions & 89 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,48 +31,48 @@ jobs:
fail-fast: false
matrix:
name: [
"windows-py36",
"windows-py37",
"windows-py37-pluggy",
# "windows-py36",
# "windows-py37",
# "windows-py37-pluggy",
"windows-py38",
"windows-py39",
"windows-py310",

"ubuntu-py36",
"ubuntu-py37",
"ubuntu-py37-pluggy",
"ubuntu-py37-freeze",
"ubuntu-py38",
"ubuntu-py39",
"ubuntu-py310",
"ubuntu-pypy3",

"macos-py37",
"macos-py38",

"docs",
"doctesting",
"plugins",
# "ubuntu-py36",
# "ubuntu-py37",
# "ubuntu-py37-pluggy",
# "ubuntu-py37-freeze",
# "ubuntu-py38",
# "ubuntu-py39",
# "ubuntu-py310",
# "ubuntu-pypy3",
#
# "macos-py37",
# "macos-py38",
#
# "docs",
# "doctesting",
# "plugins",
]

include:
- name: "windows-py36"
python: "3.6"
os: windows-latest
tox_env: "py36-xdist"
- name: "windows-py37"
python: "3.7"
os: windows-latest
tox_env: "py37-numpy"
- name: "windows-py37-pluggy"
python: "3.7"
os: windows-latest
tox_env: "py37-pluggymain-xdist"
# - name: "windows-py36"
# python: "3.6"
# os: windows-latest
# tox_env: "py36-xdist"
# - name: "windows-py37"
# python: "3.7"
# os: windows-latest
# tox_env: "py37-numpy"
# - name: "windows-py37-pluggy"
# python: "3.7"
# os: windows-latest
# tox_env: "py37-pluggymain-xdist"
- name: "windows-py38"
python: "3.8"
os: windows-latest
tox_env: "py38-unittestextras"
use_coverage: true
#use_coverage: true
- name: "windows-py39"
python: "3.9"
os: windows-latest
Expand All @@ -82,70 +82,71 @@ jobs:
os: windows-latest
tox_env: "py310-xdist"

- name: "ubuntu-py36"
python: "3.6"
os: ubuntu-latest
tox_env: "py36-xdist"
- name: "ubuntu-py37"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-lsof-numpy-pexpect"
use_coverage: true
- name: "ubuntu-py37-pluggy"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-pluggymain-xdist"
- name: "ubuntu-py37-freeze"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-freeze"
- name: "ubuntu-py38"
python: "3.8"
os: ubuntu-latest
tox_env: "py38-xdist"
- name: "ubuntu-py39"
python: "3.9"
os: ubuntu-latest
tox_env: "py39-xdist"
- name: "ubuntu-py310"
python: "3.10-dev"
os: ubuntu-latest
tox_env: "py310-xdist"
- name: "ubuntu-pypy3"
python: "pypy-3.7"
os: ubuntu-latest
tox_env: "pypy3-xdist"

- name: "macos-py37"
python: "3.7"
os: macos-latest
tox_env: "py37-xdist"
- name: "macos-py38"
python: "3.8"
os: macos-latest
tox_env: "py38-xdist"
use_coverage: true

- name: "plugins"
python: "3.7"
os: ubuntu-latest
tox_env: "plugins"

- name: "docs"
python: "3.7"
os: ubuntu-latest
tox_env: "docs"
- name: "doctesting"
python: "3.7"
os: ubuntu-latest
tox_env: "doctesting"
use_coverage: true
# - name: "ubuntu-py36"
# python: "3.6"
# os: ubuntu-latest
# tox_env: "py36-xdist"
# - name: "ubuntu-py37"
# python: "3.7"
# os: ubuntu-latest
# tox_env: "py37-lsof-numpy-pexpect"
# use_coverage: true
# - name: "ubuntu-py37-pluggy"
# python: "3.7"
# os: ubuntu-latest
# tox_env: "py37-pluggymain-xdist"
# - name: "ubuntu-py37-freeze"
# python: "3.7"
# os: ubuntu-latest
# tox_env: "py37-freeze"
# - name: "ubuntu-py38"
# python: "3.8"
# os: ubuntu-latest
# tox_env: "py38-xdist"
# - name: "ubuntu-py39"
# python: "3.9"
# os: ubuntu-latest
# tox_env: "py39-xdist"
# - name: "ubuntu-py310"
# python: "3.10-dev"
# os: ubuntu-latest
# tox_env: "py310-xdist"
# - name: "ubuntu-pypy3"
# python: "pypy-3.7"
# os: ubuntu-latest
# tox_env: "pypy3-xdist"
#
# - name: "macos-py37"
# python: "3.7"
# os: macos-latest
# tox_env: "py37-xdist"
# - name: "macos-py38"
# python: "3.8"
# os: macos-latest
# tox_env: "py38-xdist"
# use_coverage: true
#
# - name: "plugins"
# python: "3.7"
# os: ubuntu-latest
# tox_env: "plugins"
#
# - name: "docs"
# python: "3.7"
# os: ubuntu-latest
# tox_env: "docs"
# - name: "doctesting"
# python: "3.7"
# os: ubuntu-latest
# tox_env: "doctesting"
# use_coverage: true

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha }}

- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v2
Expand Down
25 changes: 24 additions & 1 deletion src/_pytest/assertion/rewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,33 @@ def exec_module(self, module: types.ModuleType) -> None:
# atomic. POSIX's atomic rename comes in handy.
write = not sys.dont_write_bytecode
cache_dir = get_cache_dir(fn)
track_debug = getattr(sys, "TRACK_REWRITE", False)
if track_debug:
print("exec_module:")
print(f" cache_dir: {cache_dir}")
print(f" write (dont_write_bytecode): {write}")
if write:
ok = try_makedirs(cache_dir)
if not ok:
write = False
if track_debug:
print(f" write: {write} (read-only dir!)")
state.trace(f"read only directory: {cache_dir}")

if track_debug:
print(f" write (final): {write}")
cache_name = fn.name[:-3] + PYC_TAIL
pyc = cache_dir / cache_name
# Notice that even if we're in a read-only directory, I'm going
# to check for a cached pyc. This may not be optimal...
co = _read_pyc(fn, pyc, state.trace)
if track_debug:
print(f" co = {co}")
if co is None:
state.trace(f"rewriting {fn!r}")
if track_debug:
print(f" rewriting {fn!r} to:")
print(f" {pyc}")
source_stat, co = _rewrite_test(fn, self.config)
if write:
self._writing_pyc = True
Expand Down Expand Up @@ -313,15 +327,23 @@ def _write_pyc(
source_stat: os.stat_result,
pyc: Path,
) -> bool:
track_debug = getattr(sys, "TRACK_REWRITE", False)
if track_debug:
print(f" write_pyc: parent exists? {pyc.parent.is_dir()}")
try:
with atomic_write(os.fspath(pyc), mode="wb", overwrite=True) as fp:
_write_pyc_fp(fp, source_stat, co)
except OSError as e:
state.trace(f"error writing pyc file at {pyc}: {e}")
if track_debug:
print(f" write_pyc: error! {e}")

# we ignore any failure to write the cache file
# there are many reasons, permission-denied, pycache dir being a
# file etc.
return False
if track_debug:
print(" write_pyc: success")
return True


Expand Down Expand Up @@ -1128,7 +1150,8 @@ def get_cache_dir(file_path: Path) -> Path:
# path = '/home/user/proj/test_app.py'
# we want:
# '/tmp/pycs/home/user/proj'
return Path(sys.pycache_prefix) / Path(*file_path.parts[1:-1])
# HACK skip some parts to check if long paths are a problem.
return Path(sys.pycache_prefix) / Path(*file_path.parts[1:-1:2])
else:
# classic pycache directory
return file_path.parent / "__pycache__"
25 changes: 17 additions & 8 deletions testing/test_assertrewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import importlib
import marshal
import os
import pprint
import py_compile
import stat
import sys
Expand Down Expand Up @@ -1734,8 +1735,9 @@ def test_sys_pycache_prefix_integration(
) -> None:
"""Integration test for sys.pycache_prefix (#4730)."""
pycache_prefix = tmp_path / "my/pycs"
monkeypatch.setattr(sys, "pycache_prefix", str(pycache_prefix))
monkeypatch.setattr(sys, "pycache_prefix", os.fspath(pycache_prefix))
monkeypatch.setattr(sys, "dont_write_bytecode", False)
monkeypatch.setattr(sys, "TRACK_REWRITE", True, raising=False)

pytester.makepyfile(
**{
Expand All @@ -1747,7 +1749,9 @@ def test_foo():
"src/bar/__init__.py": "",
}
)
result = pytester.runpytest()
result = pytester.runpytest_inprocess("-s")
pprint.pprint(list(tmp_path.glob("**/*.*")))

assert result.ret == 0

test_foo = pytester.path.joinpath("src/test_foo.py")
Expand All @@ -1757,13 +1761,18 @@ def test_foo():

# test file: rewritten, custom pytest cache tag
test_foo_pyc = get_cache_dir(test_foo) / ("test_foo" + PYC_TAIL)
print(f"** test pyc: {test_foo_pyc}")
assert test_foo_pyc.is_file()

# normal file: not touched by pytest, normal cache tag
bar_init_pyc = get_cache_dir(bar_init) / "__init__.{cache_tag}.pyc".format(
cache_tag=sys.implementation.cache_tag
)
assert bar_init_pyc.is_file()
assert 0, "lets fail on purpose to see paths in all platforms"

# # normal file: not touched by pytest, normal cache tag
# bar_init_pyc = (
# get_cache_dir( # type:ignore[unreachable]
# bar_init
# )
# / f"__init__.{sys.implementation.cache_tag}.pyc"
# )
# assert bar_init_pyc.is_file()


class TestReprSizeVerbosity:
Expand Down
6 changes: 2 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ envlist =

[testenv]
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:{env:_PYTEST_TOX_DEFAULT_POSARGS:}}
doctesting: {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules --pyargs _pytest
coverage: coverage combine
coverage: coverage report -m
pytest -k test_sys_pycache_prefix_integration -ra

passenv = USER USERNAME COVERAGE_* PYTEST_ADDOPTS TERM SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST
setenv =
_PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:}
Expand Down