-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Bug report generated by co-pilot EXCEPT me having to edit a bunch since it was confusing and too much blabbing:
Summary:
On Python 3.13 and 3.14 (RC) under Windows, pytest fails early with OSError: No username set in the environment
if none of LOGNAME, USER, LNAME, USERNAME are present. The failure originates in _pytest/tmpdir.get_user(), which only catches ImportError and KeyError, but Python 3.13 changed getpass.getuser() to raise OSError when no username can be derived. This was previously tolerated.
Environment:
- OS: Windows 10/11 (64-bit)
- Python: 3.13.0 / 3.14.0rc3 (installed via uv python install 3.13 3.14)
- Pytest: 7.4.3 (also reproduced with latest 7.x)
- Invocation context: Subprocess without username env vars (custom runner; uv seems to sanitize environment)
Relevant Python change:
Per Python 3.13 getpass.py (getuser docstring): Behavior changed to consistently raise OSError when no environment user identifiers exist and pwd (Unix-only) is not available.
Observed Error (truncated): OSError: No username set in the environment File .../Lib/getpass.py:236, in getuser raise OSError('No username set in the environment') from e
Pytest stack location: _in _pytest/tmpdir.py: get_user() calls getpass.getuser() without handling OSError.
Minimal Reproduction (Windows, Python 3.13+):
Create a clean directory with a trivial test file:
echo "def test_ok(): pass" > test_sample.py
Launch Python with some variables cleared:
- LOGNAME, USER, LNAME, USERNAME all set to ""
Execute:
python -c "import os, subprocess; [os.environ.pop(v,None) for v in ['LOGNAME','USER','LNAME','USERNAME']]; import pytest; raise SystemExit(pytest.main(['-q']))"
Result:
pytest crashes with OSError before collection finishes.
def getuser():
"""Get the username from the environment or password database.
First try various environment variables, then the password
database. This works on Windows as long as USERNAME is set.
Any failure to find a username raises OSError.
.. versionchanged:: 3.13
Previously, various exceptions beyond just :exc:`OSError`
were raised.
"""
for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
user = os.environ.get(name)
if user:
return user
try:
> import pwd
E ModuleNotFoundError: No module named 'pwd'
C:\Users\shg\AppData\Roaming\uv\python\cpython-3.13.5-windows-x86_64-none\Lib\getpass.py:172: ModuleNotFoundError
The above exception was the direct cause of the following exception:
def getuser():
"""Get the username from the environment or password database.
First try various environment variables, then the password
database. This works on Windows as long as USERNAME is set.
Any failure to find a username raises OSError.
.. versionchanged:: 3.13
Previously, various exceptions beyond just :exc:`OSError`
were raised.
"""
for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
user = os.environ.get(name)
if user:
return user
try:
import pwd
return pwd.getpwuid(os.getuid())[0]
except (ImportError, KeyError) as e:
> raise OSError('No username set in the environment') from e
E OSError: No username set in the environment
Actual: Session aborts with uncaught OSError.
Root Cause:
Python 3.13 tighten semantics:
getpass.getuser() now raises OSError when no identifier found. Pytest’s get_user only catches ImportError and KeyError: except (ImportError, KeyError): return None Missing OSError handling lets the exception propagate.
Proposed Fix: Expand exception clause to include OSError.
Rationale:
Restores pre-3.13 resilient behavior.
Narrow catch still specific to getpass failure modes; avoids masking unrelated errors.
Workaround (for users now): Set an env var before running pytest
e.g. in conftest.py:
import os
if not any(os.environ.get(n) for n in ('LOGNAME','USER','LNAME','USERNAME')): os.environ['USERNAME'] = 'tester'
Or inject in tox.ini: [testenv] setenv = USERNAME = tester
Impact:
Any Windows/CI environment invoking pytest under Python 3.13+ without a username env var will fail until patched. Silent in earlier versions because getpass.getuser() returned a fallback or raised only ImportError/KeyError.
Regression Risk: Low. Adding OSError aligns with documented new behavior. Does not affect normal environments where env vars are present.