Skip to content
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
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ Niclas Olofsson
Nicolas Delaby
Nicolas Simonds
Nico Vidal
Nigel Tan
Nikesh Chavhan
Nikolay Kondratyev
Nipunn Koorapati
Expand Down
2 changes: 2 additions & 0 deletions changelog/7786.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Tests with Unicode names no longer fail when the environment encoding cannot represent their names.
``PYTEST_CURRENT_TEST`` uses readable backslash escapes for those names.
8 changes: 7 additions & 1 deletion src/_pytest/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,13 @@ def _update_current_test_var(
value = f"{item.nodeid} ({when})"
# don't allow null bytes on environment variables (see #2644, #2957)
value = value.replace("\x00", "(null)")
os.environ[var_name] = value
try:
os.environ[var_name] = value
except UnicodeEncodeError:
encoding = sys.getfilesystemencoding()
os.environ[var_name] = value.encode(encoding, "backslashreplace").decode(
encoding
)
else:
os.environ.pop(var_name)

Expand Down
57 changes: 57 additions & 0 deletions testing/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,63 @@ def test(fix):
assert "PYTEST_CURRENT_TEST" not in os.environ


@pytest.mark.parametrize(
("utf8_mode", "expected_name"),
[("0", r"test_caf\xe9_\u4e2d\u6587"), ("1", "test_café_中文")],
)
def test_current_test_env_var_non_ascii(
pytester: Pytester,
monkeypatch: MonkeyPatch,
utf8_mode: str,
expected_name: str,
) -> None:
monkeypatch.setenv("LC_ALL", "C")
monkeypatch.setenv("PYTHONCOERCECLOCALE", "0")
monkeypatch.setenv("PYTHONUTF8", utf8_mode)
expected_encoding = "utf-8" if utf8_mode == "1" else "ascii"
probe = pytester.runpython_c("import sys; print(sys.getfilesystemencoding())")
assert probe.ret == ExitCode.OK
if probe.stdout.str().strip() != expected_encoding:
pytest.skip(f"{expected_encoding} filesystem encoding is unavailable")
expected_nodeid = "test_current_test_env_var_non_ascii.py::" + expected_name
pytester.makeconftest(
"""
import os

def pytest_unconfigure():
assert "PYTEST_CURRENT_TEST" not in os.environ
"""
)
pytester.makepyfile(
f"""
import os
import subprocess
import sys
import pytest

expected_nodeid = {expected_nodeid!r}

@pytest.fixture
def check_current_test():
assert os.environ["PYTEST_CURRENT_TEST"] == expected_nodeid + " (setup)"
yield
assert os.environ["PYTEST_CURRENT_TEST"] == expected_nodeid + " (teardown)"

def test_café_中文(check_current_test):
assert sys.getfilesystemencoding() == {expected_encoding!r}
assert os.environ["PYTEST_CURRENT_TEST"] == expected_nodeid + " (call)"
inherited = subprocess.check_output(
[sys.executable, "-c", "import os\\nprint(os.environ['PYTEST_CURRENT_TEST'])"],
encoding=sys.getfilesystemencoding(),
)
assert inherited.strip() == expected_nodeid + " (call)"
"""
)
result = pytester.runpytest_subprocess()
result.assert_outcomes(passed=1, warnings=0)
assert result.ret == ExitCode.OK


class TestReportContents:
"""Test user-level API of ``TestReport`` objects."""

Expand Down
Loading