rye
rye copied to clipboard
Fall back to Twine's keyring support in publish command
From #741, Rye is unable to publish packages with Twine if users rely on keyring.
I'm not sure if the plan is to implement more of the publish logic ourselves. In case it's not or we're still far off from that, this PR offers a fix for #741 by updating the publish command logic to fall back to Twine's keyring support.
Changes:
- Dynamic dispatch of
--username
,--token
, and--repository-url
to allow keyring fallback. -
--skip-save-credentials
to prevent potential confusing behavior and provide users with an opt-out method. - Refactored the credentials resolution, prompting, and save credentials code
Testing:
- Publish configuration resolution tests
- Snapshots
- Manual (see below)
Manual testing:
testpypi-package on ξ main [?] is π¦ v0.4.0 via π took 34s
β― cat ~/.rye/credentials
[pypi]
token = <token>
username = "__token__"
repository-url = "https://upload.pypi.org/legacy/"
testpypi-package on ξ main [?] is π¦ v0.4.0 via π
β― rye publish -r 'testpypi'
Access token: <token>
Repository URL: https://test.pypi.org/legacy/
Uploading distributions to https://test.pypi.org/legacy/
Uploading testpypi_package-0.4.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
View at:
https://test.pypi.org/project/testpypi-package/0.4.0/
testpypi-package on ξ main [?] is π¦ v0.4.0 via π took 6s
β― rye publish -r 'testpypi'
? Decrypt with passphrase (optional) βΊ
testpypi-package on ξ main [?] is π¦ v0.4.0 via π
β― rye publish -r 'testpypi' --token <token>
? Encrypt with passphrase (optional) βΊ
testpypi-package on ξ main [?] is π¦ v0.4.0 via π
β― cat ~/.rye/credentials
[pypi]
repository-url = "https://upload.pypi.org/legacy/"
[testpypi]
username = "__token__"
repository-url = "https://test.pypi.org/legacy/"
Edit: Cleaned up the description for latest changes.
For posterity, Konsti suggested to use maturin
for inspiration if anyone is interested in taking that up.
FYI: This solution works for me when I try to publish to a private repo:
~/Code/rye/target/debug/rye publish --repository rye-development-repo --repository-url https://europe-west4-python.pkg.dev/personal-projects-393014/rye-development-repo/ --username _json_key_base64 --token <KEY> dist/* -y
So instead of letting twine read the .pypirc
everything is supplied from the commandline, but I guess that is totally fine. It will at least let me use rye in my github actions instead of having a regular python flow and using twine directly.
Just one thought. In this case you pass the repository-url
-argument to twine if you were not able to resolve the credentials. Would it possible to use the repository
instead? In that case it should work for me using something like:
rye publish --repository <name>
. Or what was the reason for passing the repository-url
?
I wish I would be able to help out more, but I have learn more Rust. Might be something I can do on the side, if no one else takes this on.
Thanks a lot @cnpryer for you help!
Thanks for checking it out!
If there's interest in this I'd like to:
- PR
--non-interactive
- User only directly interacts with Rye. - Use something like
resolve_credentials(cmd)
to clean that up - Require groups of options: Rye either resolves the credentials on its own or the user bypasses Rye for Twine defaults.
Ideally you can do this when it's done and it'll hand off the repository url + username inputs to Twine.
rye publish --repository-url <url> --username <usr> --skip-credentials-save -y
And if you decide to save the username and repo url in Rye's credentials file, then if no token is resolved next time it'd just hand off those same inputs again.
If I can I'll add tests for the credentials resolution. Something like first CLI, then ENV, then Rye or Twine.
To be honest I think the best way to leave this would be to specifically only dish out for Twine's keyring support and then do something more robust.
I'm not really in love with this, but if there's a way to quickly fix this issue for you I'm happy to add to this.
For posterity, Konsti suggested to use
maturin
for inspiration if anyone is interested in taking that up.
Maybe also worth considering ditching twine
for maturin
?
Maybe also worth considering ditching
twine
formaturin
?
If that's where you want to go with it. I do like the token experience we're going for, but if there's a way to easily incorporate another common and secure method maybe we can start with this?
I was thinking at the least:
- Attempt to resolve configuration from ~/.rye/credentials
- Override with CLI
- If token is not resolved but a repository url and a username are resolved then only dispatch that to Twine.
That way to start at least we're supporting the current token process, CLI-override, and keyring via Twine.
I'll clean up what's going on in this PR, mark this ready for a review, and then we can figure out what makes sense.
I think this is a good start. Is there any chance you could add basic tests for this? Maybe by mocking up a dummy endpoint.
I think this is a good start. Is there any chance you could add basic tests for this? Maybe by mocking up a dummy endpoint.
Yea I looked at Twine's tests out of the same interest. I also looked around uv's. I'll try to look at that more today if I can.
For now I'll mark this as ready in case you wanted to play around with it. Also happy to set up a simple test for resolve_repository_credentials
. Let me know what you'd prefer to prioritize.
Would be great to add a basic test in. This is the type of code that is easy to break.
Would be great to add a basic test in. This is the type of code that is easy to break.
I tried to crank that out real quick. I didn't finish. I'll come back to it again later. Converting to draft until then.
Also, I meant to ask, would you want to just offer --config-file
dispatch to provide .pypirc
support as well? If --config-file
is passed it'd just swap in that file for when it reads the credentials file.
I can do that in a follow up PR.
Edit: See #792
I'll mark this as ready for review, but we could probably add a few more tests. I can come back to this later this week or over the weekend and do another review along with add more tests.
I plan to use a combo of snapshots and manual testing to wrap this up. Before marking this as ready I'll try to split some of this up into separate commits to make review easier. A few tests included so far need to be addressed.
rejected:
rye/tests/test_publish.rs:12 (publish)
rye/tests/test_publish.rs:28 (publish_yes)
rye/tests/test_publish.rs:134 (publish_from_credentials_found_repo_with_username_yes)
For example test_publish
will fail with ''
repository name.
program: rye
args:
- publish
- "--skip-save-credentials"
env:
RYE_HOME: /Users/chrispryer/github/rye/target/debug/rye-test-dir/home
__RYE_UV_EXCLUDE_NEWER: "2023-11-18T12:00:00Z"
UV_CACHE_DIR: /var/folders/x5/94x0_4tj6hz4682vh8l4fv1m0000gn/T/.rye-tests---T2AHyq/uv-cache
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-old snapshot
+new results
βββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
0 0 β success: falseβ
1 1 β exit_code: 1β
2 2 β ----- stdout -----β
3 β+No access token found, generate one at: https://pypi.org/manage/account/token/β
3 4 β β
4 5 β ----- stderr -----β
5 β-error: no configuration was found for repository 'none'
6 β+Access token: Repository URL: error: failed to resolve configuration for repository ''β
βββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Hey @golgor I think I'm getting closer to wrapping up this PR. Are you interested in testing this branch?
@cnpryer Of course.
It still doesn't work as originally expected, i.e. if I only provide a repository name it will pass only the repository name to twine. It still does work if I use the following arguments:
rye publish --repository rye-development-repo --repository-url <URL> --username <USERNAME> --token <PASSWORD> --skip-save-credentials -y
.
I debugged it and found that if I made some changes I could make it work with the following arguments (as expected, and what works with original twine):
rye publish --repository rye-development-repo --skip-save-credentials -y
I debugged this by using the following debug setup:
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'rye'",
"cargo": {
"args": [
"build",
"--bin=rye",
"--package=rye"
],
"filter": {
"name": "rye",
"kind": "bin"
}
},
"args": ["publish", "--repository", "rye-development-repo", "--skip-save-credentials","-y"],
"cwd": "/home/golgor/Code/toolsense-flespi"
},
I don't know if these changes breaks anything else though.
Change 1
In the method resolve_with_defaults
for Credentials
struct I had to remove the .or(Some(DEFAULT_USERNAME.to_string())),
. The reason is that I do not want to provide a username, as that should be fetched from the .pypirc and this methods sets the username to __token__
.
The final method is then:
impl Credentials {
fn resolve_with_defaults(self) -> Self {
Self {
username: self.username,
password: self.password,
}
}
}
Change 2
I added an additional option for the function config_is_keyring_ready
to return true
also in the case of only supplying a repository-name:
fn config_is_keyring_ready(config: &PublishConfig) -> bool {
config.credentials.username.is_some() && config.repository.url.is_some()
|| config.repository.name.is_some()
}
Change 3
As I only want to provide the repository name to twine, I added this to the publish_cmd
just before :
if let Some(name) = config.repository.name {
publish_cmd.arg("--repository").arg(name);
}
The result is the command I need to be passed to twine:
It is quite complicated already. That was the reason why I raised the idea in Discord of trying to isolate the use-cases in the beginning of the function instead of trying to figure it out on per argument basis as it is now. As I see it, we have three different use-cases:
-
rye publish
-> publish to pypi. Implement logic for storing credentials here ("Pretty much the entire function now") -
rye publish --repository
-> publish to custom repo, rely on .pypirc. (Pretty much directly pass arguments to twine) -
rye publish --repository <NAME> --repository-url <URL> --username <USERNAME> -- token <PASSWORD/TOKEN>
-> Publish to any repo, provide all necessary information on the command line. I guess this would be the path the first time publishing to Pypi, as there are no saved credentials?
We have four pieces of important information, repo name, repo url, username and password. An example match-case for this could look like this:
pub fn publish_pypi(_cmd: &Args) {
println!("Publish to Pypi");
}
pub fn publish_custom(name: &str) {
println!("Publish to {name}!");
}
pub fn publish_from_cli(name: &str, _url: &Url, username: &str, _token: &str) {
println!("Publish to {name} with username: {username} and token: ***!");
}
pub fn execute(cmd: Args) -> Result<(), Error> {
match (
cmd.repository.as_ref(),
cmd.repository_url.as_ref(),
cmd.username.as_ref(),
cmd.token.as_ref(),
) {
(None, None, None, None) => publish_pypi(&cmd),
(Some(repo_name), None, None, None) => publish_custom(repo_name),
(Some(repo_name), Some(repo_url), Some(username), Some(token)) => {
publish_from_cli(repo_name, repo_url, username, token)
}
_other => bail!("Not enough information!"),
}
}
Wow thanks for trying it out so quickly! Please don't feel obligated to do that haha. I really appreciate it though.
To recap, the goal of this specific PR is to:
- Support username and repository url via Twine's keyring support
- Add tests for the publish command
It still doesn't work as originally expected, i.e. if I only provide a repository name it will pass only the repository name to twine. It still does work if I use the following arguments:
rye publish --repository rye-development-repo --repository-url <URL> --username <USERNAME> --token <PASSWORD> --skip-save-credentials -y.
Does this work for you with your setup if you were to use this command?
rye publish -r rye-development-repo --repositiry-url url --username usr -y --skip-save-credentials
Thanks for sharing your process. That's super helpful.
Change 1
In the method resolve_with_defaults for Credentials struct I had to remove the .or(Some(DEFAULT_USERNAME.to_string())),. The reason is that I do not want to provide a username, as that should be fetched from the .pypirc and this methods sets the username to token.
Ideally if --username is used upfront for now this should work. Let me know if it doesn't. I'd love to add ~/.pypirc import or some support (#792) in a follow up PR if there's interest.
It is quite complicated already. That was the reason why I raised the idea in Discord of trying to isolate the use-cases in the beginning of the function instead of trying to figure it out on per argument basis as it is now. As I see it, we have three different use-cases:
I agree. But I think in your case we would probably want to either fully support using ~/.pypirc as configuration or import from it. Currently we default to "__token__"
for missing usernames. That'd minimize your interface the most, wouldn't it?
No worries, doing some testing like this is a great opportunity for me to learn more Rust, which is something I like to do!
During all these tests I used the --skip-save-credentials and I checked the ~/.rye/credentials between each command and it was empty.
~/Code/rye/target/debug/rye publish -r rye-development-repo --repository-url https://europe-west4-python.pkg.dev/personal-projects-393014/rye-development-repo/ --username _json_key_base64 -y --skip-save-credentials
Uploading distributions to https://europe-west4-python.pkg.dev/personal-projects-393014/rye-development-repo/
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
This seems to be an error generated by twine. If I remove the -y
I will get prompted for a token, and if I paste my password there, it uploads correctly. The credentials file is still empty after this.
If I try it with only supplying the repo name and the username (notice the missing -y
):
~/Code/rye/target/debug/rye publish -r rye-development-repo --username _json_key_base64 --skip-save-credentials
I get prompted by the twine to supply both password and URL. If I add the -y
, this happens:
~/Code/rye/target/debug/rye publish -r rye-development-repo --username _json_key_base64 --skip-save-credentials -y
error: failed to resolve configuration for repository 'rye-development-repo'
This seems to be an error from rye, more specifically from the config_is_ready
-function.
I agree. But I think in your case we would probably want to either fully support using ~/.pypirc as configuration or import from it. Currently we default to "token" for missing usernames. That'd minimize your interface the most, wouldn't it?
Yeah, that is the main issue now basically. If I change the code to also allow an empty username (None), and add repository-name as optional input to twine, everything works fine for me with only:
rye publish -r rye-development-repo
There are a number of ways to make this work and as long as you depend on twine I would say it makes sense to use it as much as possible. I.e. not parsing the .pypirc yourself, but rely on twine to do it. As it looks like now, if twine is supplied with only a repo name, it looks in the .pypirc if it can find a match. If it is supplied with anything extra, it seems to fall back to some other mode and not touch the .pypirc, which is confusing for sure... Not sure if this is documented anywhere.
But then the .pypirc seems to be a standard toml-file, so maybe not that much work to read from that one and then supply all the arguments as necessary to twine. It will decouple twine functionality and it will probably make it easier in the future if rye intends to replace twine by its own uploading feature.
I'm more than happy to help out with #792 as well as I already got a setup of everything to help you out.
I get prompted by the twine to supply both password and URL. If I add the -y, this happens:
~/Code/rye/target/debug/rye publish -r rye-development-repo --username _json_key_base64 --skip-save-credentials -y error: failed to resolve configuration for repository 'rye-development-repo'
So I believe this would fail because you're supplying a repository name and a username but not repository url.
This seems to be an error from rye, more specifically from the config_is_ready-function.
I'm curious if you have some suggestions. Here's what I wanted from that function:
- Config has everything I need
- Config has what I need for keyring (username, url)
So in this case it has username but it doesn't have a url.
I also would keep in mind that the way we currently dish out like this to Twine may change. It may be that we want to use another tool or do it ourselves. So I would be hesitant to spend a significant amount of effort on this just yet.
On the other hand, loading configuration data from ~/.pypirc or CLI seems like a reasonable next step since it'd be helpful regardless of the tool or implementation.
If you're interested in that after this PR I can help you with it, but we'd want to start by syncing up in #792. It's still just a feature request at the moment.
Change 2
I added an additional option for the function config_is_keyring_ready to return true also in the case of only supplying a repository-name:
fn config_is_keyring_ready(config: &PublishConfig) -> bool { config.credentials.username.is_some() && config.repository.url.is_some() || config.repository.name.is_some() }
Unfortunately, there are two problems with this that I see.
One is that we are intentionally avoiding having Twine operate with just a repository name. Having two tools do the resolution like that feels like it could become hard to maintain.
So the idea is that either Rye has configuration, Rye can establish sufficient configuration, or attempt the keyring fallback.
The other issue is that I don't believe this is compatible with the resolution I mentioned above.
config.credentials.username.is_some() && config.repository.url.is_some()
|| config.repository.name.is_some()
If url is missing and username is some, but the repository name is some, we don't have a url to dispatch. We wouldn't be able to fallback to keyring setup either.
@cnpryer I'm not too familiar with the publish flow. Do you think this is in a state where it makes sense merging?
It's been a bit. So I'll come in here soon and write something up to confirm it's ready for a merge. Thanks for the ping.
I'll aim to get back in here this weekend.
So right now the flow this PR will implement will look like this from a fresh environment:
By default Rye doesn't initialize with a credentials file (this is fine).
β― cat ~/.rye/credentials
cat: /Users/chrispryer/.rye/credentials: No such file or directory
Since we've prioritize auth token usage, your basic usage will invoke a prompt for the token if one isn't provided or found.
β― rye publish -r 'testpypi' --repository-url https://test.pypi.org/legacy/
Access token:
You can pass -y
to skip this and it will attempt the keyring fallback.
Returning to this after a while, my initial reaction to this was that I'd expect for us to use the keyring backend if an entry is already set up. So it's up to you, but in order to do that we'd want to modify this PR to prioritize the keyring backend.
That way the basic usage will avoid prompting the user if they have already set up keyring for the provided repository url.
As for the state of this change and making sure it's definitely ready to be merged I'm going to treat this like it's a PR I want to merge into my own repo. To do that I'll do a full review this weekend and manually verify different use cases.
I added some testing here, but it's not the best.
I've organized the changes into commits for an easier read and provided some details about each change. The refactor makes the diff difficult to reason about since large portions of the cli/publish.rs file is modified in order to make this easier to implement (and maintain).
I'll do a full review either tomorrow or Sunday.
@mitsuhiko At this stage the PR should be ready. I'll keep an eye out for any reported issues.
One comment though is what I mentioned here.
Returning to this after a while, my initial reaction to this was that I'd expect for us to use the keyring backend if an entry is already set up. So it's up to you, but in order to do that we'd want to modify this PR to prioritize the keyring backend.
If we are still looking to prioritize Rye's token management then I'd say let's just see if users provide feedback to prioritize keyring. I'll add some documentation on this. You can allow Rye to perform the fallback if you pass -y
.
Expand the details below if you'd like to see all the manual testing I just did. Last example uses the encrypted token. Encrypt/decrypt prompts aren't persisted in the output. The "keychain" error is from exiting my keyring prompt.
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials
No access token found, generate one at: https://pypi.org/manage/account/token/
Access token:
Repository URL:
Uploading distributions to https://upload.pypi.org/legacy/
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials -y
Uploading distributions to https://upload.pypi.org/legacy/
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials -y -r pypi
Uploading distributions to https://upload.pypi.org/legacy/
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials -y -r testpypi
error: failed to resolve configuration for repository 'testpypi'
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials -r pypi
No access token found, generate one at: https://pypi.org/manage/account/token/
Access token:
Uploading distributions to https://upload.pypi.org/legacy/
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials -r testpypi
Access token:
Repository URL:
error: failed to resolve configuration for repository 'testpypi'
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials -r pypi --repository-url https://upload.pypi.org/legacy/
No access token found, generate one at: https://pypi.org/manage/account/token/
Access token:
Uploading distributions to https://upload.pypi.org/legacy/
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish --skip-save-credentials -r testpypi --repository-url https://test.pypi.org/legacy/
Access token:
Uploading distributions to https://test.pypi.org/legacy/
WARNING Error getting password from keyring
Traceback (most recent call last):
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/__init__.py", line 61, in get_password
return api.find_generic_password(self.keychain, service, username)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/api.py", line 156, in find_generic_password
Error.raise_for_status(status)
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/api.py", line 119, in raise_for_status
raise KeychainDenied(status, "Keychain Access Denied")
keyring.backends.macOS.api.KeychainDenied: (-128, 'Keychain Access Denied')
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/twine/auth.py", line 74, in get_password_from_keyring
return cast(str, keyring.get_password(system, username))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/core.py", line 56, in get_password
return get_keyring().get_password(service_name, username)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/__init__.py", line 21, in wrapper
return func(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/__init__.py", line 65, in get_password
raise KeyringLocked(f"Can't get password from keychain: {e}") from e
keyring.errors.KeyringLocked: Can't get password from keychain: (-128, 'Keychain Access Denied')
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
testpypi-package on ξ main [?] is π¦ v0.3.0 via π took 14s
β― rye publish --skip-save-credentials -r testpypi --repository-url https://test.pypi.org/legacy/ -y
Uploading distributions to https://test.pypi.org/legacy/
WARNING Error getting password from keyring
Traceback (most recent call last):
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/__init__.py", line 61, in get_password
return api.find_generic_password(self.keychain, service, username)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/api.py", line 156, in find_generic_password
Error.raise_for_status(status)
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/api.py", line 119, in raise_for_status
raise KeychainDenied(status, "Keychain Access Denied")
keyring.backends.macOS.api.KeychainDenied: (-128, 'Keychain Access Denied')
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/twine/auth.py", line 74, in get_password_from_keyring
return cast(str, keyring.get_password(system, username))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/core.py", line 56, in get_password
return get_keyring().get_password(service_name, username)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/__init__.py", line 21, in wrapper
return func(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/chrispryer/.rye/self/lib/python3.12/site-packages/keyring/backends/macOS/__init__.py", line 65, in get_password
raise KeyringLocked(f"Can't get password from keychain: {e}") from e
keyring.errors.KeyringLocked: Can't get password from keychain: (-128, 'Keychain Access Denied')
ERROR NonInteractive: Credential not found for password.
error: failed to publish files
testpypi-package on ξ main [?] is π¦ v0.3.0 via π took 2s
β― rye publish --skip-save-credentials -r testpypi --repository-url https://test.pypi.org/legacy/ --token <token>
Uploading distributions to https://test.pypi.org/legacy/
Uploading testpypi_package-0.3.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.3.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
View at:
https://test.pypi.org/project/testpypi-package/0.3.0/
https://test.pypi.org/project/testpypi-package/0.4.0/
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― touch ~/.rye/credentials
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― vim ~/.rye/credentials
testpypi-package on ξ main [?] is π¦ v0.3.0 via π took 1m11s
β― cat ~/.rye/credentials
[testpypi]
token = <token>
repository-url = "https://test.pypi.org/legacy/"
testpypi-package on ξ main [?] is π¦ v0.3.0 via π took 9s
β― rye publish -r testpypi
Uploading distributions to https://test.pypi.org/legacy/
Uploading testpypi_package-0.3.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.3.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
View at:
https://test.pypi.org/project/testpypi-package/0.4.0/
https://test.pypi.org/project/testpypi-package/0.3.0/
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rm ~/.rye/credentials
testpypi-package on ξ main [?] is π¦ v0.3.0 via π
β― rye publish -r testpypi
Access token: <token>
Repository URL: https://test.pypi.org/legacy/
Uploading distributions to https://test.pypi.org/legacy/
Uploading testpypi_package-0.3.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.3.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
View at:
https://test.pypi.org/project/testpypi-package/0.3.0/
https://test.pypi.org/project/testpypi-package/0.4.0/
testpypi-package on ξ main [?] is π¦ v0.3.0 via π took 20s
β― cat ~/.rye/credentials
[testpypi]
token = "6167652d656e6372797074696f6e2e6f72672f76310a2d3e207363727970742035536667707a4e6a376e332b386954314248734847412031340a65555330347952705a4a7a33704c5263354c4f7241376c586b6d4e6d7972436644516e673943726e78326f0a2d2d2d206f53796b526f786878474867584d4438776a6164343962646f65786c4e41647275366b397a6d7545666e770ae1cd5b9ba93084c57995eecec9b7f1a734ad58118c50a03beeb1862d1a52ec56f2e4eeeac4881b5df3829d78ee4dd93630cea2347b98065d45233851907910e7d9aab8c4650c973bf781fed0acea133c7ed674237b50959775ac9005ed59bc22a96c016edaa85d88b35b8d52e71b6c929b17336eb671568f468f4281f8d179d30dd8780a1450f205ba8cf57cac9aa71b5b3f3be7da96a6879ef5b543f9e792d5923ba21f718f09bd75ed2d6b895c9e21fc854fabda863118f14a8fb24643729214ab24e9a5d7e2e2c4c4085fd23f12612646370ab206de521db8c0815b7bb73d3d01a3bee5321731656573aede351fafb862c014c83ac04575c9419d070bc33c"
username = "__token__"
repository-url = "https://test.pypi.org/legacy/"
testpypi-package on ξ main [?] is π¦ v0.3.0 via π took 2s
β― rye publish -r testpypi
Uploading distributions to https://test.pypi.org/legacy/
Uploading testpypi_package-0.3.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0-py3-none-any.whl
100% ββββββββββββββββββββββββββββββββββββββββ 4.3/4.3 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.3.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
Uploading testpypi_package-0.4.0.tar.gz
100% ββββββββββββββββββββββββββββββββββββββββ 3.9/3.9 kB β’ 00:00 β’ ?
View at:
https://test.pypi.org/project/testpypi-package/0.4.0/
https://test.pypi.org/project/testpypi-package/0.3.0/
I really want to ensure is that we are reliably providing encryption if the user opts into it. I did some extra testing around this, but I'll do some more over the next couple of days.
Any chance that Twine's --config-file
option could be dispatched as well?
In my current use-case, this would support the TwineAuthenticate@1
task from Azure Pipelines
Any chance that Twine's
--config-file
option could be dispatched as well? In my current use-case, this would support theTwineAuthenticate@1
task from Azure Pipelines
Feel free to mention that here
- #792
@charliermarsh can I do anything to help make this easier to review and consider? I have time this weekend to work on this.
The majority of this change is a refactor of the publish command's code. Would you prefer I undo the keyring support to start with just the refactor?
I understand some logic might be upstreamed to uv
, but I'd prefer if contributors PR any future changes on top of this code rather than its code on main
. It should be more extendable.
Hey @cnpryer, would you still be interested in merging this? Would be useful for me too!