Skip to content

Commit

Permalink
Show more helpful messages for invalid passwords (#815)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
bhrutledge committed Oct 10, 2021
1 parent 040a62c commit 9d26a5f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog/815.feature.rst
@@ -0,0 +1 @@
Show more helpful messages for invalid passwords.
14 changes: 14 additions & 0 deletions docs/index.rst
Expand Up @@ -88,6 +88,20 @@ Using Twine
4. Done!

.. _entering-credentials:

.. note::

Like many other command line tools, Twine does not show any characters when
you enter your password.

If you're using Windows and trying to paste your username, password, or
token in the Command Prompt or PowerShell, ``Ctrl-V`` and ``Shift+Insert``
won't work. Instead, you can use "Edit > Paste" from the window menu, or
enable "Use Ctrl+Shift+C/V as Copy/Paste" in "Properties". This is a
`known issue <https://bugs.python.org/issue37426>`_ with Python's
``getpass`` module.

More documentation on using Twine to upload packages to PyPI is in
the `Python Packaging User Guide`_.

Expand Down
24 changes: 24 additions & 0 deletions tests/test_auth.py
@@ -1,3 +1,4 @@
import getpass
import logging

import pytest
Expand Down Expand Up @@ -202,3 +203,26 @@ def test_logs_config_values(config, caplog):
"username set from config file",
"password set from config file",
]


@pytest.mark.parametrize(
"password, warning",
[
("", "Your password is empty"),
("\x16", "Your password contains control characters"),
("entered\x16pw", "Your password contains control characters"),
],
)
def test_warns_for_empty_password(
password,
warning,
monkeypatch,
entered_username,
config,
caplog,
):
monkeypatch.setattr(getpass, "getpass", lambda prompt: password)

assert auth.Resolver(config, auth.CredentialInput()).password == password

assert caplog.messages[0].startswith(f" {warning}")
23 changes: 22 additions & 1 deletion twine/utils.py
Expand Up @@ -18,6 +18,7 @@
import logging
import os
import os.path
import unicodedata
from typing import Any, Callable, DefaultDict, Dict, Optional, Sequence, Union
from urllib.parse import urlparse
from urllib.parse import urlunparse
Expand Down Expand Up @@ -240,11 +241,31 @@ def get_userpass_value(
if cli_value is not None:
logger.info(f"{key} set by command options")
return cli_value

elif config.get(key) is not None:
logger.info(f"{key} set from config file")
return config[key]

elif prompt_strategy:
return prompt_strategy()
warning = ""
value = prompt_strategy()

if not value:
warning = f"Your {key} is empty"
elif any(unicodedata.category(c).startswith("C") for c in value):
# See https://www.unicode.org/reports/tr44/#General_Category_Values
# Most common case is "\x16" when pasting in Windows Command Prompt
warning = f"Your {key} contains control characters"

if warning:
logger.warning(f" {warning}. Did you enter it correctly?")
logger.warning(
" See https://twine.readthedocs.io/#entering-credentials "
"for more information."
)

return value

else:
return None

Expand Down

0 comments on commit 9d26a5f

Please sign in to comment.