From a20c768e29af58c0be13cfdb16c980a4a5857ea5 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Tue, 23 Nov 2021 22:17:13 -0500 Subject: [PATCH 1/7] 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. --- Doc/library/getpass.rst | 4 ++-- Lib/getpass.py | 13 ++++++++----- Lib/test/test_getpass.py | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Doc/library/getpass.rst b/Doc/library/getpass.rst index 82b11919a3d2bf..bf6161688ad042 100644 --- a/Doc/library/getpass.rst +++ b/Doc/library/getpass.rst @@ -45,7 +45,7 @@ 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()`. diff --git a/Lib/getpass.py b/Lib/getpass.py index 6970d8adfbab36..8c6f6e2cc46bfe 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -155,8 +155,8 @@ 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. - + database. This works on Windows as long as USERNAME is set; + if not, it raises OSError. """ for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'): @@ -164,9 +164,12 @@ def getuser(): if user: return user - # If this fails, the exception will "explain" why - import pwd - return pwd.getpwuid(os.getuid())[0] + 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: diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index 3452e46213a76c..8cad6cede96d56 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -26,7 +26,7 @@ def test_username_priorities_of_env_values(self, environ): 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 self.assertEqual( environ.get.call_args_list, @@ -44,7 +44,7 @@ def test_username_falls_back_to_pwd(self, environ): getpass.getuser()) getpw.assert_called_once_with(42) else: - self.assertRaises(ImportError, getpass.getuser) + self.assertRaises(OSError, getpass.getuser) class GetpassRawinputTest(unittest.TestCase): From c304c29a0988e5a18e4e916891d5679285d3a941 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Tue, 23 Nov 2021 22:23:25 -0500 Subject: [PATCH 2/7] add blurb --- .../next/Library/2021-11-23-22-22-49.bpo-32731.kNOASr.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2021-11-23-22-22-49.bpo-32731.kNOASr.rst diff --git a/Misc/NEWS.d/next/Library/2021-11-23-22-22-49.bpo-32731.kNOASr.rst b/Misc/NEWS.d/next/Library/2021-11-23-22-22-49.bpo-32731.kNOASr.rst new file mode 100644 index 00000000000000..92f3b870c11131 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-11-23-22-22-49.bpo-32731.kNOASr.rst @@ -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. From 40072cfaeda66469557bedd2ec7bab4e3404e48e Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Wed, 24 Nov 2021 18:44:59 -0500 Subject: [PATCH 3/7] Add change notices --- Doc/whatsnew/3.11.rst | 4 ++++ Lib/getpass.py | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 9751f894f9a9a5..16da20c0da3750 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -167,6 +167,10 @@ Other Language Changes protocols correspondingly. (Contributed by Serhiy Storchaka in :issue:`12022`.) +# 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. + Other CPython Implementation Changes ==================================== diff --git a/Lib/getpass.py b/Lib/getpass.py index 8c6f6e2cc46bfe..3b4dcffb2587f6 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -155,8 +155,13 @@ 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; - if not, it raises OSError. + database. This works on Windows as long as USERNAME is set. + Any failure to find a username raises OSError. + + .. versionchanged:: 3.11 + Failure to find a username raises :exc:`OSError` instead of + :exc:`ImportError` on non-Unix platforms or :exc:`KeyError` + on Unix platforms if the password database is empty. """ for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'): From 60418ff426a1ba01c4da7a5b94abafc01166f9a7 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Wed, 24 Nov 2021 18:45:44 -0500 Subject: [PATCH 4/7] typo --- Doc/whatsnew/3.11.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 16da20c0da3750..34e54050074457 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -167,7 +167,7 @@ Other Language Changes protocols correspondingly. (Contributed by Serhiy Storchaka in :issue:`12022`.) -# An :exc:`OSError` is now raised by :func:`getpass.getuser` for any failure to +* 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. From 81e22a78b7641b9c934f66f5a83fbdb349b37d6f Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Tue, 7 Jun 2022 08:38:32 -0400 Subject: [PATCH 5/7] clarify wording --- Lib/getpass.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/getpass.py b/Lib/getpass.py index aab1590d9eb72e..0d1f8ce168b35b 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -160,8 +160,8 @@ def getuser(): .. versionchanged:: 3.12 Failure to find a username raises :exc:`OSError` instead of - :exc:`ImportError` on non-Unix platforms or :exc:`KeyError` - on Unix platforms if the password database is empty. + :exc:`ImportError` on non-Unix platforms and instead of + :exc:`KeyError` on Unix platforms if the password database is empty. """ for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'): From 85351c5dc575386208d118069e9c136aca9ad5eb Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 19 Nov 2023 08:21:02 -0500 Subject: [PATCH 6/7] Bump notes to 3.13 --- Doc/whatsnew/3.12.rst | 4 ---- Doc/whatsnew/3.13.rst | 4 ++++ Lib/getpass.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8cc2d05c998a81..8b7a043d068e5c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1799,10 +1799,6 @@ Changes in the Python API select from a larger range than ``randrange(10**25)``. (Originally suggested by Serhiy Storchaka :gh:`86388`.) -* 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. - * :class:`argparse.ArgumentParser` changed encoding and error handler for reading arguments from file (e.g. ``fromfile_prefix_chars`` option) from default text encoding (e.g. :func:`locale.getpreferredencoding(False) `) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 4d05bce34ef847..a66681097b325e 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -1017,6 +1017,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 ============= diff --git a/Lib/getpass.py b/Lib/getpass.py index 1c89335338c4e4..7ed7d942147e3e 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -158,7 +158,7 @@ def getuser(): database. This works on Windows as long as USERNAME is set. Any failure to find a username raises OSError. - .. versionchanged:: 3.12 + .. versionchanged:: 3.13 Failure to find a username raises :exc:`OSError` instead of :exc:`ImportError` on non-Unix platforms and instead of :exc:`KeyError` on Unix platforms if the password database is empty. From 7d3de4e6f3936971584dbe05c2e956d80cca2800 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 19 Nov 2023 19:03:28 -0500 Subject: [PATCH 7/7] Simplify docstring and add versionchanged --- Doc/library/getpass.rst | 3 +++ Lib/getpass.py | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/library/getpass.rst b/Doc/library/getpass.rst index 6bff1272fcaff1..54c84d45a59856 100644 --- a/Doc/library/getpass.rst +++ b/Doc/library/getpass.rst @@ -50,3 +50,6 @@ The :mod:`getpass` module provides two functions: 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. diff --git a/Lib/getpass.py b/Lib/getpass.py index 7ed7d942147e3e..bd0097ced94c5e 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -159,9 +159,8 @@ def getuser(): Any failure to find a username raises OSError. .. versionchanged:: 3.13 - Failure to find a username raises :exc:`OSError` instead of - :exc:`ImportError` on non-Unix platforms and instead of - :exc:`KeyError` on Unix platforms if the password database is empty. + Previously, various exceptions beyond just :exc:`OSError` + were raised. """ for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):