gh-76912: Raise OSError from any failure in getpass.getuser() (#29739)

* bpo-32731: Raise OSError from any failure in getpass.getuser()
Previously, if the username was not set in certain environment variables, ImportError escaped on Windows systems, and it was possible for KeyError to escape on other systems if getpwuid() failed.
This commit is contained in:
Jacob Walls 2023-11-27 13:05:55 -05:00 committed by GitHub
parent 936c503a44
commit 99a73c3465
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 7 deletions

View File

@ -46,7 +46,10 @@ The :mod:`getpass` module provides two functions:
:envvar:`USER`, :envvar:`!LNAME` and :envvar:`USERNAME`, in order, and
returns the value of the first one which is set to a non-empty string. If
none are set, the login name from the password database is returned on
systems which support the :mod:`pwd` module, otherwise, an exception is
raised.
systems which support the :mod:`pwd` module, otherwise, an :exc:`OSError`
is raised.
In general, this function should be preferred over :func:`os.getlogin()`.
.. versionchanged:: 3.13
Previously, various exceptions beyond just :exc:`OSError` were raised.

View File

@ -1032,6 +1032,10 @@ Changes in the Python API
recomended in the documentation.
(Contributed by Serhiy Storchaka in :gh:`106672`.)
* An :exc:`OSError` is now raised by :func:`getpass.getuser` for any failure to
retrieve a username, instead of :exc:`ImportError` on non-Unix platforms or
:exc:`KeyError` on Unix platforms where the password database is empty.
Build Changes
=============

View File

@ -156,7 +156,11 @@ def getuser():
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'):
@ -164,9 +168,12 @@ def getuser():
if user:
return user
# If this fails, the exception will "explain" why
try:
import pwd
return pwd.getpwuid(os.getuid())[0]
except (ImportError, KeyError) as e:
raise OSError('No username set in the environment') from e
# Bind the name getpass to the appropriate function
try:

View File

@ -26,7 +26,7 @@ class GetpassGetuserTest(unittest.TestCase):
environ.get.return_value = None
try:
getpass.getuser()
except ImportError: # in case there's no pwd module
except OSError: # in case there's no pwd module
pass
except KeyError:
# current user has no pwd entry
@ -47,7 +47,7 @@ class GetpassGetuserTest(unittest.TestCase):
getpass.getuser())
getpw.assert_called_once_with(42)
else:
self.assertRaises(ImportError, getpass.getuser)
self.assertRaises(OSError, getpass.getuser)
class GetpassRawinputTest(unittest.TestCase):

View File

@ -0,0 +1,3 @@
:func:`getpass.getuser` now raises :exc:`OSError` for all failures rather
than :exc:`ImportError` on systems lacking the :mod:`pwd` module or
:exc:`KeyError` if the password database is empty.