Skip to content

Commit 9d26a5f

Browse files
authored
Show more helpful messages for invalid passwords (#815)
* Show asterisks for password * Revert "Show asterisks for password" This reverts commit f60db37. * Show warnings for username and password * Add note to docs about entering credentials * Add changelog entry
1 parent 040a62c commit 9d26a5f

File tree

4 files changed

+61
-1
lines changed

4 files changed

+61
-1
lines changed

changelog/815.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Show more helpful messages for invalid passwords.

docs/index.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ Using Twine
8888
8989
4. Done!
9090

91+
.. _entering-credentials:
92+
93+
.. note::
94+
95+
Like many other command line tools, Twine does not show any characters when
96+
you enter your password.
97+
98+
If you're using Windows and trying to paste your username, password, or
99+
token in the Command Prompt or PowerShell, ``Ctrl-V`` and ``Shift+Insert``
100+
won't work. Instead, you can use "Edit > Paste" from the window menu, or
101+
enable "Use Ctrl+Shift+C/V as Copy/Paste" in "Properties". This is a
102+
`known issue <https://bugs.python.org/issue37426>`_ with Python's
103+
``getpass`` module.
104+
91105
More documentation on using Twine to upload packages to PyPI is in
92106
the `Python Packaging User Guide`_.
93107

tests/test_auth.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import getpass
12
import logging
23

34
import pytest
@@ -202,3 +203,26 @@ def test_logs_config_values(config, caplog):
202203
"username set from config file",
203204
"password set from config file",
204205
]
206+
207+
208+
@pytest.mark.parametrize(
209+
"password, warning",
210+
[
211+
("", "Your password is empty"),
212+
("\x16", "Your password contains control characters"),
213+
("entered\x16pw", "Your password contains control characters"),
214+
],
215+
)
216+
def test_warns_for_empty_password(
217+
password,
218+
warning,
219+
monkeypatch,
220+
entered_username,
221+
config,
222+
caplog,
223+
):
224+
monkeypatch.setattr(getpass, "getpass", lambda prompt: password)
225+
226+
assert auth.Resolver(config, auth.CredentialInput()).password == password
227+
228+
assert caplog.messages[0].startswith(f" {warning}")

twine/utils.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import logging
1919
import os
2020
import os.path
21+
import unicodedata
2122
from typing import Any, Callable, DefaultDict, Dict, Optional, Sequence, Union
2223
from urllib.parse import urlparse
2324
from urllib.parse import urlunparse
@@ -240,11 +241,31 @@ def get_userpass_value(
240241
if cli_value is not None:
241242
logger.info(f"{key} set by command options")
242243
return cli_value
244+
243245
elif config.get(key) is not None:
244246
logger.info(f"{key} set from config file")
245247
return config[key]
248+
246249
elif prompt_strategy:
247-
return prompt_strategy()
250+
warning = ""
251+
value = prompt_strategy()
252+
253+
if not value:
254+
warning = f"Your {key} is empty"
255+
elif any(unicodedata.category(c).startswith("C") for c in value):
256+
# See https://www.unicode.org/reports/tr44/#General_Category_Values
257+
# Most common case is "\x16" when pasting in Windows Command Prompt
258+
warning = f"Your {key} contains control characters"
259+
260+
if warning:
261+
logger.warning(f" {warning}. Did you enter it correctly?")
262+
logger.warning(
263+
" See https://twine.readthedocs.io/#entering-credentials "
264+
"for more information."
265+
)
266+
267+
return value
268+
248269
else:
249270
return None
250271

0 commit comments

Comments
 (0)