Skip to content

Commit

Permalink
Restore test isolation by allowing username override for PyPI (#1131)
Browse files Browse the repository at this point in the history
Closes #1121
  • Loading branch information
jaraco authored Nov 29, 2024
1 parent dd61356 commit 03bcad6
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 21 deletions.
1 change: 1 addition & 0 deletions changelog/1121.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Username for PyPI and Test PyPI now defaults to __token__ but no longer overrides a username configured in the environment or supplied on the command line. Workflows still supplying anything other than __token__ for the username when uploading to PyPI or Test PyPI will now fail. Either supply __token__ or do not supply a username at all.
5 changes: 2 additions & 3 deletions tests/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,15 @@ def none_register(*args, **settings_kwargs):
monkeypatch.setattr(register, "register", replaced_register)
testenv = {
"TWINE_REPOSITORY": repo,
# Ignored because the TWINE_REPOSITORY is PyPI/TestPyPI
"TWINE_USERNAME": "this-is-ignored",
"TWINE_USERNAME": "pypiuser",
"TWINE_PASSWORD": "pypipassword",
"TWINE_CERT": "/foo/bar.crt",
}
with helpers.set_env(**testenv):
cli.dispatch(["register", helpers.WHEEL_FIXTURE])
register_settings = replaced_register.calls[0].args[0]
assert "pypipassword" == register_settings.password
assert "__token__" == register_settings.username
assert "pypiuser" == register_settings.username
assert "/foo/bar.crt" == register_settings.cacert


Expand Down
5 changes: 2 additions & 3 deletions tests/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,16 +564,15 @@ def none_upload(*args, **settings_kwargs):
monkeypatch.setattr(upload, "upload", replaced_upload)
testenv = {
"TWINE_REPOSITORY": repo,
# Ignored because TWINE_REPOSITORY is PyPI/TestPyPI
"TWINE_USERNAME": "this-is-ignored",
"TWINE_USERNAME": "pypiuser",
"TWINE_PASSWORD": "pypipassword",
"TWINE_CERT": "/foo/bar.crt",
}
with helpers.set_env(**testenv):
cli.dispatch(["upload", "path/to/file"])
upload_settings = replaced_upload.calls[0].args[0]
assert "pypipassword" == upload_settings.password
assert "__token__" == upload_settings.username
assert "pypiuser" == upload_settings.username
assert "/foo/bar.crt" == upload_settings.cacert


Expand Down
30 changes: 15 additions & 15 deletions twine/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ def choose(cls, interactive: bool) -> Type["Resolver"]:
@property
@functools.lru_cache()
def username(self) -> Optional[str]:
if cast(str, self.config["repository"]).startswith(
(utils.DEFAULT_REPOSITORY, utils.TEST_REPOSITORY)
):
# As of 2024-01-01, PyPI requires API tokens for uploads, meaning
# that the username is invariant.
return "__token__"
if self.is_pypi() and not self.input.username:
# Default username.
self.input.username = "__token__"

return utils.get_userpass_value(
self.input.username,
Expand Down Expand Up @@ -111,20 +108,23 @@ def password_from_keyring_or_prompt(self) -> str:
logger.info("password set from keyring")
return password

# As of 2024-01-01, PyPI requires API tokens for uploads;
# specialize the prompt to clarify that an API token must be provided.
if cast(str, self.config["repository"]).startswith(
(utils.DEFAULT_REPOSITORY, utils.TEST_REPOSITORY)
):
prompt = "API token"
else:
prompt = "password"
# Prompt for API token when required.
what = "API token" if self.is_pypi() else "password"

return self.prompt(prompt, getpass.getpass)
return self.prompt(what, getpass.getpass)

def prompt(self, what: str, how: Callable[..., str]) -> str:
return how(f"Enter your {what}: ")

def is_pypi(self) -> bool:
"""As of 2024-01-01, PyPI requires API tokens for uploads."""
return cast(str, self.config["repository"]).startswith(
(
utils.DEFAULT_REPOSITORY,
utils.TEST_REPOSITORY,
)
)


class Private(Resolver):
def prompt(self, what: str, how: Optional[Callable[..., str]] = None) -> str:
Expand Down

0 comments on commit 03bcad6

Please sign in to comment.