Summary
For reasons that aren’t clear to me, I’ve started encountering failures from the uv_keyring crate’s doctests in Fedora’s uv package since 0.11.3. It doesn’t seem like the issues are new; it seems like what’s new is that uv-keyring’s doctests are actually compiled and executed. I cannot easily say why that is, but I can reproduce the issue in a git checkout:
$ git checkout 0.11.3
$ cargo test -p uv-keyring
[…]
running 4 tests
test crates/uv-keyring/src/lib.rs - readme (line 422) ... FAILED
test crates/uv-keyring/src/mock.rs - mock (line 25) ... FAILED
test crates/uv-keyring/src/mock.rs - mock (line 11) ... FAILED
test crates/uv-keyring/src/lib.rs - (line 115) ... ok
failures:
---- crates/uv-keyring/src/lib.rs - readme (line 422) stdout ----
error[E0432]: unresolved import `keyring`
--> crates/uv-keyring/src/lib.rs:423:5
|
423 | use keyring::{Entry, Result};
| ^^^^^^^ use of unresolved module or unlinked crate `keyring`
|
= help: if you wanted to use a crate named `keyring`, use `cargo add keyring` to add it to your `Cargo.toml`
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> crates/uv-keyring/src/lib.rs:427:45
|
425 | fn main() -> Result<()> {
| ----------------------- this is not `async`
426 | let entry = Entry::new("my-service", "my-name")?;
427 | entry.set_password("topS3cr3tP4$$w0rd").await?;
| ^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> crates/uv-keyring/src/lib.rs:428:41
|
425 | fn main() -> Result<()> {
| ----------------------- this is not `async`
...
428 | let password = entry.get_password().await?;
| ^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> crates/uv-keyring/src/lib.rs:430:31
|
425 | fn main() -> Result<()> {
| ----------------------- this is not `async`
...
430 | entry.delete_credential().await?;
| ^^^^^ only allowed inside `async` functions and blocks
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0432, E0728.
For more information about an error, try `rustc --explain E0432`.
Couldn't compile the test.
---- crates/uv-keyring/src/mock.rs - mock (line 25) stdout ----
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `keyring`
--> crates/uv-keyring/src/mock.rs:26:5
|
26 | use keyring::{Entry, Error, mock, mock::MockCredential};
| ^^^^^^^ use of unresolved module or unlinked crate `keyring`
|
= help: if you wanted to use a crate named `keyring`, use `cargo add keyring` to add it to your `Cargo.toml`
error[E0432]: unresolved import `keyring`
--> crates/uv-keyring/src/mock.rs:26:5
|
26 | use keyring::{Entry, Error, mock, mock::MockCredential};
| ^^^^^^^ use of unresolved module or unlinked crate `keyring`
|
= help: if you wanted to use a crate named `keyring`, use `cargo add keyring` to add it to your `Cargo.toml`
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `keyring`
--> crates/uv-keyring/src/mock.rs:27:1
|
27 | keyring::set_default_credential_builder(mock::default_credential_builder());
| ^^^^^^^ use of unresolved module or unlinked crate `keyring`
|
= help: if you wanted to use a crate named `keyring`, use `cargo add keyring` to add it to your `Cargo.toml`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0432, E0433.
For more information about an error, try `rustc --explain E0432`.
Couldn't compile the test.
---- crates/uv-keyring/src/mock.rs - mock (line 11) stdout ----
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `keyring`
--> crates/uv-keyring/src/mock.rs:12:41
|
12 | keyring::set_default_credential_builder(keyring::mock::default_credential_builder());
| ^^^^^^^ use of unresolved module or unlinked crate `keyring`
|
= help: if you wanted to use a crate named `keyring`, use `cargo add keyring` to add it to your `Cargo.toml`
help: consider importing this module
|
11 + use uv_keyring::mock;
|
help: if you import `mock`, refer to it directly
|
12 - keyring::set_default_credential_builder(keyring::mock::default_credential_builder());
12 + keyring::set_default_credential_builder(mock::default_credential_builder());
|
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `keyring`
--> crates/uv-keyring/src/mock.rs:12:1
|
12 | keyring::set_default_credential_builder(keyring::mock::default_credential_builder());
| ^^^^^^^ use of unresolved module or unlinked crate `keyring`
|
= help: if you wanted to use a crate named `keyring`, use `cargo add keyring` to add it to your `Cargo.toml`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0433`.
Couldn't compile the test.
failures:
crates/uv-keyring/src/lib.rs - readme (line 422)
crates/uv-keyring/src/mock.rs - mock (line 11)
crates/uv-keyring/src/mock.rs - mock (line 25)
test result: FAILED. 1 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.79s
all doctests ran in 0.84s; merged doctests compilation took 0.05s
error: doctest failed, to rerun pass `-p uv-keyring --doc`
The first obvious issue here is that the uv_keyring crate still has several references to keyring::, from which it was forked. Since there is no dependency on https://crates.io/crates/keyring, we shouldn’t be surprised that these don’t compile. Working locally, I tried fixing these as follows:
From d366081e192967f0071d48695f6e379c4d00ca29 Mon Sep 17 00:00:00 2001
From: "Benjamin A. Beasley" <code@musicinmybrain.net>
Date: Tue, 7 Apr 2026 12:09:51 +0100
Subject: [PATCH 1/2] =?UTF-8?q?Change=20remaining=20uses=20of=20=E2=80=9Ck?=
=?UTF-8?q?eyring=E2=80=9D=20in=20uv-keyring=E2=80=99s=20doctests?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
crates/uv-keyring/README.md | 4 ++--
crates/uv-keyring/src/mock.rs | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/crates/uv-keyring/README.md b/crates/uv-keyring/README.md
index 613bff88a..f55de0536 100644
--- a/crates/uv-keyring/README.md
+++ b/crates/uv-keyring/README.md
@@ -19,7 +19,7 @@ platform's persistent credential store.) The password or secret can then be read
can then be removed using the `delete_credential` method.
```rust
-use keyring::{Entry, Result};
+use uv_keyring::{Entry, Result};
fn main() -> Result<()> {
let entry = Entry::new("my-service", "my-name")?;
@@ -33,7 +33,7 @@ fn main() -> Result<()> {
## Errors
-Creating and operating on entries can yield a `keyring::Error` which provides both a
+Creating and operating on entries can yield a `uv_keyring::Error` which provides both a
platform-independent code that classifies the error and, where relevant, underlying platform errors
or more information about what went wrong.
diff --git a/crates/uv-keyring/src/mock.rs b/crates/uv-keyring/src/mock.rs
index 891cb0291..0fffba903 100644
--- a/crates/uv-keyring/src/mock.rs
+++ b/crates/uv-keyring/src/mock.rs
@@ -10,7 +10,7 @@ in this store have no attributes at all.
To use this credential store instead of the default, make this call during
application startup _before_ creating any entries:
```rust
-keyring::set_default_credential_builder(keyring::mock::default_credential_builder());
+uv_keyring::set_default_credential_builder(uv_keyring::mock::default_credential_builder());
```
You can then create entries as you usually do, and call their usual methods
@@ -24,8 +24,8 @@ with the appropriate error. The next entry method called on the credential
will fail with the error you set. The error will then be cleared, so the next
call on the mock will operate as usual. Here's a complete example:
```rust
-# use keyring::{Entry, Error, mock, mock::MockCredential};
-# keyring::set_default_credential_builder(mock::default_credential_builder());
+# use uv_keyring::{Entry, Error, mock, mock::MockCredential};
+# uv_keyring::set_default_credential_builder(mock::default_credential_builder());
let entry = Entry::new("service", "user").unwrap();
let mock: &MockCredential = entry.get_credential().downcast_ref().unwrap();
mock.set_error(Error::Invalid("mock error".to_string(), "takes precedence".to_string()));
--
2.53.0
(The above diff has some triple backticks within the diff, which I broke up with zero width non-joiner characters so I could embed it cleanly in Markdown. Therefore, it won’t apply when copy-pasted into a file unless the triple backticks are restored.)
Fixing these occurrences of keyring:: got me a little further:
test crates/uv-keyring/src/lib.rs - readme (line 422) ... FAILED
test crates/uv-keyring/src/mock.rs - mock (line 25) ... FAILED
test crates/uv-keyring/src/mock.rs - mock (line 11) ... ok
test crates/uv-keyring/src/lib.rs - (line 115) ... ok
failures:
---- crates/uv-keyring/src/lib.rs - readme (line 422) stdout ----
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> crates/uv-keyring/src/lib.rs:428:45
|
426 | fn main() -> Result<()> {
| ----------------------- this is not `async`
427 | let entry = Entry::new("my-service", "my-name")?;
428 | entry.set_password("topS3cr3tP4$$w0rd").await?;
| ^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> crates/uv-keyring/src/lib.rs:429:41
|
426 | fn main() -> Result<()> {
| ----------------------- this is not `async`
...
429 | let password = entry.get_password().await?;
| ^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> crates/uv-keyring/src/lib.rs:431:31
|
426 | fn main() -> Result<()> {
| ----------------------- this is not `async`
...
431 | entry.delete_credential().await?;
| ^^^^^ only allowed inside `async` functions and blocks
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0728`.
Couldn't compile the test.
---- crates/uv-keyring/src/mock.rs - mock (line 25) stdout ----
error[E0599]: no method named `expect_err` found for opaque type `impl Future<Output = Result<(), uv_keyring::Error>>` in the current scope
--> crates/uv-keyring/src/mock.rs:32:28
|
32 | entry.set_password("test").expect_err("error will override");
| ^^^^^^^^^^
|
help: consider `await`ing on the `Future` and calling the method on its `Output`
|
32 | entry.set_password("test").await.expect_err("error will override");
| ++++++
help: there is a method `inspect_err` with a similar name
|
32 - entry.set_password("test").expect_err("error will override");
32 + entry.set_password("test").inspect_err("error will override");
|
error[E0599]: no method named `expect` found for opaque type `impl Future<Output = Result<(), uv_keyring::Error>>` in the current scope
--> crates/uv-keyring/src/mock.rs:33:28
|
33 | entry.set_password("test").expect("error has been cleared");
| ^^^^^^ method not found in `impl Future<Output = Result<(), uv_keyring::Error>>`
|
help: consider `await`ing on the `Future` and calling the method on its `Output`
|
33 | entry.set_password("test").await.expect("error has been cleared");
| ++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0599`.
Couldn't compile the test.
failures:
crates/uv-keyring/src/lib.rs - readme (line 422)
crates/uv-keyring/src/mock.rs - mock (line 25)
test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.85s
all doctests ran in 0.92s; merged doctests compilation took 0.06s
error: doctest failed, to rerun pass `-p uv-keyring --doc`
Looking at that example, this seems reasonable enough: compared to the original version in keyring, .await? calls were added, but no async context, so this isn’t really a correct example.
|
use keyring::{Entry, Result}; |
|
|
|
fn main() -> Result<()> { |
|
let entry = Entry::new("my-service", "my-name")?; |
|
entry.set_password("topS3cr3tP4$$w0rd").await?; |
|
let password = entry.get_password().await?; |
|
println!("My password is '{}'", password); |
|
entry.delete_credential().await?; |
|
Ok(()) |
|
} |
I tried working around this in the simplest possible way:
From b44e5f9a2e0a2cb0b557fc8dbbaff3ab5b83562c Mon Sep 17 00:00:00 2001
From: "Benjamin A. Beasley" <code@musicinmybrain.net>
Date: Tue, 7 Apr 2026 13:58:14 +0100
Subject: [PATCH 2/2] Fix missing async context in uv-keyring README example
---
crates/uv-keyring/Cargo.toml | 1 +
crates/uv-keyring/README.md | 10 ++++++----
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/crates/uv-keyring/Cargo.toml b/crates/uv-keyring/Cargo.toml
index a1339c5c1..18f9077f4 100644
--- a/crates/uv-keyring/Cargo.toml
+++ b/crates/uv-keyring/Cargo.toml
@@ -43,6 +43,7 @@ zeroize = { workspace = true }
doc-comment = "0.3"
env_logger = "0.11.5"
fastrand = { workspace = true }
+futures = { workspace = true }
[package.metadata.docs.rs]
default-target = "x86_64-unknown-linux-gnu"
diff --git a/crates/uv-keyring/README.md b/crates/uv-keyring/README.md
index f55de0536..e5f525627 100644
--- a/crates/uv-keyring/README.md
+++ b/crates/uv-keyring/README.md
@@ -23,10 +23,12 @@ use uv_keyring::{Entry, Result};
fn main() -> Result<()> {
let entry = Entry::new("my-service", "my-name")?;
- entry.set_password("topS3cr3tP4$$w0rd").await?;
- let password = entry.get_password().await?;
- println!("My password is '{}'", password);
- entry.delete_credential().await?;
+ futures::executor::block_on(async {
+ entry.set_password("topS3cr3tP4$$w0rd").await?;
+ let password = entry.get_password().await?;
+ println!("My password is '{}'", password);
+ entry.delete_credential().await?;
+ }
Ok(())
}
```
--
2.53.0
(Again, the above diff has triple backticks that I split up with zero width non-joiners to embed it in Markdown.)
I’m kind of on the right track here, but this approach doesn’t suffice: I get errors like the following.
---- crates/uv-keyring/src/lib.rs - readme (line 422) stdout ----
error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> crates/uv-keyring/src/lib.rs:429:54
|
428 | futures::executor::block_on(async {
| ----- this function should return `Result` or `Option` to accept `?`
429 | entry.set_password("topS3cr3tP4$$w0rd").await?;
| ^ cannot use the `?` operator in an async block that returns `()`
Plus, I haven’t dealt with crates/uv-keyring/src/mock.rs.
I’m not prepared to spend much more time investigating these tests at the moment, so I think I’m going to just skip compiling them and keep moving, but I would certainly appreciate it if someone more comfortable with async Rust could fix up these doctests so that cargo test -p uv-keyring actually works.
Platform
Fedora 45/Rawhide, x86_64
Version
uv 0.11.3
Python version
Python 3.14.3
Summary
For reasons that aren’t clear to me, I’ve started encountering failures from the
uv_keyringcrate’s doctests in Fedora’suvpackage since 0.11.3. It doesn’t seem like the issues are new; it seems like what’s new is thatuv-keyring’s doctests are actually compiled and executed. I cannot easily say why that is, but I can reproduce the issue in a git checkout:The first obvious issue here is that the
uv_keyringcrate still has several references tokeyring::, from which it was forked. Since there is no dependency on https://crates.io/crates/keyring, we shouldn’t be surprised that these don’t compile. Working locally, I tried fixing these as follows:(The above diff has some triple backticks within the diff, which I broke up with zero width non-joiner characters so I could embed it cleanly in Markdown. Therefore, it won’t apply when copy-pasted into a file unless the triple backticks are restored.)
Fixing these occurrences of
keyring::got me a little further:Looking at that example, this seems reasonable enough: compared to the original version in
keyring,.await?calls were added, but noasynccontext, so this isn’t really a correct example.uv/crates/uv-keyring/README.md
Lines 22 to 31 in 466a0f0
I tried working around this in the simplest possible way:
(Again, the above diff has triple backticks that I split up with zero width non-joiners to embed it in Markdown.)
I’m kind of on the right track here, but this approach doesn’t suffice: I get errors like the following.
Plus, I haven’t dealt with
crates/uv-keyring/src/mock.rs.I’m not prepared to spend much more time investigating these tests at the moment, so I think I’m going to just skip compiling them and keep moving, but I would certainly appreciate it if someone more comfortable with async Rust could fix up these doctests so that
cargo test -p uv-keyringactually works.Platform
Fedora 45/Rawhide, x86_64
Version
uv 0.11.3
Python version
Python 3.14.3