mirror of https://github.com/astral-sh/uv
Add `uv auth` commands (`login`, `logout`, and `token`) (#15539)
Picks up the work from - #14559 - https://github.com/astral-sh/uv/pull/14896 There are some high-level changes from those pull requests 1. We do not stash seen credentials in the keyring automatically 2. We use `auth login` and `auth logout` (for future consistency) 3. We add a `token` command for showing the credential that will be used As well as many smaller changes to API, messaging, testing, etc. --------- Co-authored-by: John Mumm <jtfmumm@gmail.com>
This commit is contained in:
parent
f76e0fe5e6
commit
460ea6e9eb
|
|
@ -2,3 +2,10 @@
|
||||||
# Mark tests that take longer than 10s as slow.
|
# Mark tests that take longer than 10s as slow.
|
||||||
# Terminate after 120s as a stop-gap measure to terminate on deadlock.
|
# Terminate after 120s as a stop-gap measure to terminate on deadlock.
|
||||||
slow-timeout = { period = "10s", terminate-after = 12 }
|
slow-timeout = { period = "10s", terminate-after = 12 }
|
||||||
|
|
||||||
|
[test-groups]
|
||||||
|
serial = { max-threads = 1 }
|
||||||
|
|
||||||
|
[[profile.default.overrides]]
|
||||||
|
filter = 'test(native_keyring)'
|
||||||
|
test-group = 'serial'
|
||||||
|
|
|
||||||
|
|
@ -5089,9 +5089,11 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"test-log",
|
"test-log",
|
||||||
|
"thiserror 2.0.16",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uv-keyring",
|
||||||
"uv-once-map",
|
"uv-once-map",
|
||||||
"uv-redacted",
|
"uv-redacted",
|
||||||
"uv-small-str",
|
"uv-small-str",
|
||||||
|
|
@ -5407,6 +5409,7 @@ dependencies = [
|
||||||
"uv-pep440",
|
"uv-pep440",
|
||||||
"uv-pep508",
|
"uv-pep508",
|
||||||
"uv-platform-tags",
|
"uv-platform-tags",
|
||||||
|
"uv-redacted",
|
||||||
"uv-static",
|
"uv-static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ uv-git-types = { path = "crates/uv-git-types" }
|
||||||
uv-globfilter = { path = "crates/uv-globfilter" }
|
uv-globfilter = { path = "crates/uv-globfilter" }
|
||||||
uv-install-wheel = { path = "crates/uv-install-wheel", default-features = false }
|
uv-install-wheel = { path = "crates/uv-install-wheel", default-features = false }
|
||||||
uv-installer = { path = "crates/uv-installer" }
|
uv-installer = { path = "crates/uv-installer" }
|
||||||
|
uv-keyring = { path = "crates/uv-keyring" }
|
||||||
uv-logging = { path = "crates/uv-logging" }
|
uv-logging = { path = "crates/uv-logging" }
|
||||||
uv-macros = { path = "crates/uv-macros" }
|
uv-macros = { path = "crates/uv-macros" }
|
||||||
uv-metadata = { path = "crates/uv-metadata" }
|
uv-metadata = { path = "crates/uv-metadata" }
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
uv-keyring = { workspace = true, features = ["apple-native", "secret-service", "windows-native"] }
|
||||||
uv-once-map = { workspace = true }
|
uv-once-map = { workspace = true }
|
||||||
uv-redacted = { workspace = true }
|
uv-redacted = { workspace = true }
|
||||||
uv-small-str = { workspace = true }
|
uv-small-str = { workspace = true }
|
||||||
|
|
@ -28,6 +29,7 @@ rust-netrc = { workspace = true }
|
||||||
rustc-hash = { workspace = true }
|
rustc-hash = { workspace = true }
|
||||||
schemars = { workspace = true, optional = true }
|
schemars = { workspace = true, optional = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
|
thiserror = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
use std::{io::Write, process::Stdio};
|
use std::{io::Write, process::Stdio};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tracing::{instrument, trace, warn};
|
use tracing::{debug, instrument, trace, warn};
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
|
|
||||||
use crate::credentials::Credentials;
|
use crate::credentials::Credentials;
|
||||||
|
|
||||||
|
/// Service name prefix for storing credentials in a keyring.
|
||||||
|
static UV_SERVICE_PREFIX: &str = "uv:";
|
||||||
|
|
||||||
/// A backend for retrieving credentials from a keyring.
|
/// A backend for retrieving credentials from a keyring.
|
||||||
///
|
///
|
||||||
/// See pip's implementation for reference
|
/// See pip's implementation for reference
|
||||||
|
|
@ -15,15 +18,47 @@ pub struct KeyringProvider {
|
||||||
backend: KeyringProviderBackend,
|
backend: KeyringProviderBackend,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub(crate) enum KeyringProviderBackend {
|
pub enum Error {
|
||||||
/// Use the `keyring` command to fetch credentials.
|
#[error(transparent)]
|
||||||
|
Keyring(#[from] uv_keyring::Error),
|
||||||
|
|
||||||
|
#[error("The '{0}' keyring provider does not support storing credentials")]
|
||||||
|
StoreUnsupported(KeyringProviderBackend),
|
||||||
|
|
||||||
|
#[error("The '{0}' keyring provider does not support removing credentials")]
|
||||||
|
RemoveUnsupported(KeyringProviderBackend),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum KeyringProviderBackend {
|
||||||
|
/// Use a native system keyring integration for credentials.
|
||||||
|
Native,
|
||||||
|
/// Use the external `keyring` command for credentials.
|
||||||
Subprocess,
|
Subprocess,
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
Dummy(Vec<(String, &'static str, &'static str)>),
|
Dummy(Vec<(String, &'static str, &'static str)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for KeyringProviderBackend {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Native => write!(f, "native"),
|
||||||
|
Self::Subprocess => write!(f, "subprocess"),
|
||||||
|
#[cfg(test)]
|
||||||
|
Self::Dummy(_) => write!(f, "dummy"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl KeyringProvider {
|
impl KeyringProvider {
|
||||||
|
/// Create a new [`KeyringProvider::Native`].
|
||||||
|
pub fn native() -> Self {
|
||||||
|
Self {
|
||||||
|
backend: KeyringProviderBackend::Native,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new [`KeyringProvider::Subprocess`].
|
/// Create a new [`KeyringProvider::Subprocess`].
|
||||||
pub fn subprocess() -> Self {
|
pub fn subprocess() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -31,6 +66,84 @@ impl KeyringProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Store credentials for the given [`DisplaySafeUrl`] to the keyring.
|
||||||
|
///
|
||||||
|
/// Only [`KeyringProviderBackend::Native`] is supported at this time.
|
||||||
|
#[instrument(skip_all, fields(url = % url.to_string(), username))]
|
||||||
|
pub async fn store(
|
||||||
|
&self,
|
||||||
|
url: &DisplaySafeUrl,
|
||||||
|
credentials: &Credentials,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
let Some(username) = credentials.username() else {
|
||||||
|
trace!("Unable to store credentials in keyring for {url} due to missing username");
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
let Some(password) = credentials.password() else {
|
||||||
|
trace!("Unable to store credentials in keyring for {url} due to missing password");
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
match &self.backend {
|
||||||
|
KeyringProviderBackend::Native => {
|
||||||
|
self.store_native(url.as_str(), username, password).await?;
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
KeyringProviderBackend::Subprocess => {
|
||||||
|
Err(Error::StoreUnsupported(self.backend.clone()))
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
KeyringProviderBackend::Dummy(_) => Err(Error::StoreUnsupported(self.backend.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Store credentials to the system keyring.
|
||||||
|
#[instrument(skip(self))]
|
||||||
|
async fn store_native(
|
||||||
|
&self,
|
||||||
|
service: &str,
|
||||||
|
username: &str,
|
||||||
|
password: &str,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let prefixed_service = format!("{UV_SERVICE_PREFIX}{service}");
|
||||||
|
let entry = uv_keyring::Entry::new(&prefixed_service, username)?;
|
||||||
|
entry.set_password(password).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove credentials for the given [`DisplaySafeUrl`] and username from the keyring.
|
||||||
|
///
|
||||||
|
/// Only [`KeyringProviderBackend::Native`] is supported at this time.
|
||||||
|
#[instrument(skip_all, fields(url = % url.to_string(), username))]
|
||||||
|
pub async fn remove(&self, url: &DisplaySafeUrl, username: &str) -> Result<(), Error> {
|
||||||
|
match &self.backend {
|
||||||
|
KeyringProviderBackend::Native => {
|
||||||
|
self.remove_native(url.as_str(), username).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
KeyringProviderBackend::Subprocess => {
|
||||||
|
Err(Error::RemoveUnsupported(self.backend.clone()))
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
KeyringProviderBackend::Dummy(_) => Err(Error::RemoveUnsupported(self.backend.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove credentials from the system keyring for the given `service_name`/`username`
|
||||||
|
/// pair.
|
||||||
|
#[instrument(skip(self))]
|
||||||
|
async fn remove_native(
|
||||||
|
&self,
|
||||||
|
service_name: &str,
|
||||||
|
username: &str,
|
||||||
|
) -> Result<(), uv_keyring::Error> {
|
||||||
|
let prefixed_service = format!("{UV_SERVICE_PREFIX}{service_name}");
|
||||||
|
let entry = uv_keyring::Entry::new(&prefixed_service, username)?;
|
||||||
|
entry.delete_credential().await?;
|
||||||
|
trace!("Removed credentials for {username}@{service_name} from system keyring");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Fetch credentials for the given [`Url`] from the keyring.
|
/// Fetch credentials for the given [`Url`] from the keyring.
|
||||||
///
|
///
|
||||||
/// Returns [`None`] if no password was found for the username or if any errors
|
/// Returns [`None`] if no password was found for the username or if any errors
|
||||||
|
|
@ -55,6 +168,7 @@ impl KeyringProvider {
|
||||||
// <https://github.com/pypa/pip/blob/ae5fff36b0aad6e5e0037884927eaa29163c0611/src/pip/_internal/network/auth.py#L376C1-L379C14>
|
// <https://github.com/pypa/pip/blob/ae5fff36b0aad6e5e0037884927eaa29163c0611/src/pip/_internal/network/auth.py#L376C1-L379C14>
|
||||||
trace!("Checking keyring for URL {url}");
|
trace!("Checking keyring for URL {url}");
|
||||||
let mut credentials = match self.backend {
|
let mut credentials = match self.backend {
|
||||||
|
KeyringProviderBackend::Native => self.fetch_native(url.as_str(), username).await,
|
||||||
KeyringProviderBackend::Subprocess => {
|
KeyringProviderBackend::Subprocess => {
|
||||||
self.fetch_subprocess(url.as_str(), username).await
|
self.fetch_subprocess(url.as_str(), username).await
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +186,7 @@ impl KeyringProvider {
|
||||||
};
|
};
|
||||||
trace!("Checking keyring for host {host}");
|
trace!("Checking keyring for host {host}");
|
||||||
credentials = match self.backend {
|
credentials = match self.backend {
|
||||||
|
KeyringProviderBackend::Native => self.fetch_native(&host, username).await,
|
||||||
KeyringProviderBackend::Subprocess => self.fetch_subprocess(&host, username).await,
|
KeyringProviderBackend::Subprocess => self.fetch_subprocess(&host, username).await,
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
KeyringProviderBackend::Dummy(ref store) => {
|
KeyringProviderBackend::Dummy(ref store) => {
|
||||||
|
|
@ -175,6 +290,32 @@ impl KeyringProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self))]
|
||||||
|
async fn fetch_native(
|
||||||
|
&self,
|
||||||
|
service: &str,
|
||||||
|
username: Option<&str>,
|
||||||
|
) -> Option<(String, String)> {
|
||||||
|
let prefixed_service = format!("{UV_SERVICE_PREFIX}{service}");
|
||||||
|
let username = username?;
|
||||||
|
let Ok(entry) = uv_keyring::Entry::new(&prefixed_service, username) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
match entry.get_password().await {
|
||||||
|
Ok(password) => return Some((username.to_string(), password)),
|
||||||
|
Err(uv_keyring::Error::NoEntry) => {
|
||||||
|
debug!("No entry found in system keyring for {service}");
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn_user_once!(
|
||||||
|
"Unable to fetch credentials for {service} from system keyring: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn fetch_dummy(
|
fn fetch_dummy(
|
||||||
store: &Vec<(String, &'static str, &'static str)>,
|
store: &Vec<(String, &'static str, &'static str)>,
|
||||||
|
|
|
||||||
|
|
@ -375,6 +375,7 @@ impl AuthMiddleware {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_ok_and(|response| response.error_for_status_ref().is_ok())
|
.is_ok_and(|response| response.error_for_status_ref().is_ok())
|
||||||
{
|
{
|
||||||
|
// TODO(zanieb): Consider also updating the system keyring after successful use
|
||||||
trace!("Updating cached credentials for {url} to {credentials:?}");
|
trace!("Updating cached credentials for {url} to {credentials:?}");
|
||||||
self.cache().insert(&url, credentials);
|
self.cache().insert(&url, credentials);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use clap::{Args, Parser, Subcommand};
|
||||||
use uv_cache::CacheArgs;
|
use uv_cache::CacheArgs;
|
||||||
use uv_configuration::{
|
use uv_configuration::{
|
||||||
ExportFormat, IndexStrategy, KeyringProviderType, PackageNameSpecifier, ProjectBuildBackend,
|
ExportFormat, IndexStrategy, KeyringProviderType, PackageNameSpecifier, ProjectBuildBackend,
|
||||||
TargetTriple, TrustedHost, TrustedPublishing, VersionControlSystem,
|
Service, TargetTriple, TrustedHost, TrustedPublishing, VersionControlSystem,
|
||||||
};
|
};
|
||||||
use uv_distribution_types::{
|
use uv_distribution_types::{
|
||||||
ConfigSettingEntry, ConfigSettingPackageEntry, Index, IndexUrl, Origin, PipExtraIndex,
|
ConfigSettingEntry, ConfigSettingPackageEntry, Index, IndexUrl, Origin, PipExtraIndex,
|
||||||
|
|
@ -399,6 +399,13 @@ impl From<ColorChoice> for anstream::ColorChoice {
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum Commands {
|
pub enum Commands {
|
||||||
|
/// Manage authentication.
|
||||||
|
#[command(
|
||||||
|
after_help = "Use `uv help auth` for more details.",
|
||||||
|
after_long_help = ""
|
||||||
|
)]
|
||||||
|
Auth(AuthNamespace),
|
||||||
|
|
||||||
/// Manage Python projects.
|
/// Manage Python projects.
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
Project(Box<ProjectCommand>),
|
Project(Box<ProjectCommand>),
|
||||||
|
|
@ -4386,6 +4393,22 @@ pub struct FormatArgs {
|
||||||
pub extra_args: Vec<String>,
|
pub extra_args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct AuthNamespace {
|
||||||
|
#[command(subcommand)]
|
||||||
|
pub command: AuthCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
pub enum AuthCommand {
|
||||||
|
/// Login to a service
|
||||||
|
Login(AuthLoginArgs),
|
||||||
|
/// Logout of a service
|
||||||
|
Logout(AuthLogoutArgs),
|
||||||
|
/// Show the authentication token for a service
|
||||||
|
Token(AuthTokenArgs),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
pub struct ToolNamespace {
|
pub struct ToolNamespace {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
|
|
@ -5501,6 +5524,76 @@ pub struct PythonPinArgs {
|
||||||
pub rm: bool,
|
pub rm: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct AuthLogoutArgs {
|
||||||
|
/// The service to logout of.
|
||||||
|
pub service: Service,
|
||||||
|
|
||||||
|
/// The username to logout.
|
||||||
|
#[arg(long, short)]
|
||||||
|
pub username: Option<String>,
|
||||||
|
|
||||||
|
/// The keyring provider to use for storage of credentials.
|
||||||
|
///
|
||||||
|
/// Only `--keyring-provider native` is supported for `logout`, which uses the system keyring
|
||||||
|
/// via an integration built into uv.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
value_enum,
|
||||||
|
env = EnvVars::UV_KEYRING_PROVIDER,
|
||||||
|
)]
|
||||||
|
pub keyring_provider: Option<KeyringProviderType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct AuthLoginArgs {
|
||||||
|
/// The service to login to.
|
||||||
|
pub service: Service,
|
||||||
|
|
||||||
|
/// The username to use for the service.
|
||||||
|
#[arg(long, short, conflicts_with = "token")]
|
||||||
|
pub username: Option<String>,
|
||||||
|
|
||||||
|
/// The password to use for the service.
|
||||||
|
#[arg(long, conflicts_with = "token")]
|
||||||
|
pub password: Option<String>,
|
||||||
|
|
||||||
|
/// The token to use for the service.
|
||||||
|
///
|
||||||
|
/// The username will be set to `__token__`.
|
||||||
|
#[arg(long, short, conflicts_with = "username", conflicts_with = "password")]
|
||||||
|
pub token: Option<String>,
|
||||||
|
|
||||||
|
/// The keyring provider to use for storage of credentials.
|
||||||
|
///
|
||||||
|
/// Only `--keyring-provider native` is supported for `login`, which uses the system keyring via
|
||||||
|
/// an integration built into uv.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
value_enum,
|
||||||
|
env = EnvVars::UV_KEYRING_PROVIDER,
|
||||||
|
)]
|
||||||
|
pub keyring_provider: Option<KeyringProviderType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct AuthTokenArgs {
|
||||||
|
/// The service to lookup.
|
||||||
|
pub service: Service,
|
||||||
|
|
||||||
|
/// The username to lookup.
|
||||||
|
#[arg(long, short)]
|
||||||
|
pub username: Option<String>,
|
||||||
|
|
||||||
|
/// The keyring provider to use for reading credentials.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
value_enum,
|
||||||
|
env = EnvVars::UV_KEYRING_PROVIDER,
|
||||||
|
)]
|
||||||
|
pub keyring_provider: Option<KeyringProviderType>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
pub struct GenerateShellCompletionArgs {
|
pub struct GenerateShellCompletionArgs {
|
||||||
/// The shell to generate the completion script for
|
/// The shell to generate the completion script for
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ use tracing::{debug, trace};
|
||||||
use url::ParseError;
|
use url::ParseError;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use uv_auth::Credentials;
|
use uv_auth::{AuthMiddleware, Credentials, Indexes};
|
||||||
use uv_auth::{AuthMiddleware, Indexes};
|
|
||||||
use uv_configuration::{KeyringProviderType, TrustedHost};
|
use uv_configuration::{KeyringProviderType, TrustedHost};
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_pep508::MarkerEnvironment;
|
use uv_pep508::MarkerEnvironment;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ uv-normalize = { workspace = true }
|
||||||
uv-pep440 = { workspace = true }
|
uv-pep440 = { workspace = true }
|
||||||
uv-pep508 = { workspace = true, features = ["schemars"] }
|
uv-pep508 = { workspace = true, features = ["schemars"] }
|
||||||
uv-platform-tags = { workspace = true }
|
uv-platform-tags = { workspace = true }
|
||||||
|
uv-redacted = { workspace = true }
|
||||||
uv-static = { workspace = true }
|
uv-static = { workspace = true }
|
||||||
clap = { workspace = true, features = ["derive"], optional = true }
|
clap = { workspace = true, features = ["derive"], optional = true }
|
||||||
either = { workspace = true }
|
either = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
use std::str::FromStr;
|
||||||
use uv_auth::{self, KeyringProvider};
|
use uv_auth::{self, KeyringProvider};
|
||||||
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
/// Keyring provider type to use for credential lookup.
|
/// Keyring provider type to use for credential lookup.
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
|
@ -9,6 +11,8 @@ pub enum KeyringProviderType {
|
||||||
/// Do not use keyring for credential lookup.
|
/// Do not use keyring for credential lookup.
|
||||||
#[default]
|
#[default]
|
||||||
Disabled,
|
Disabled,
|
||||||
|
/// Use a native integration with the system keychain for credential lookup.
|
||||||
|
Native,
|
||||||
/// Use the `keyring` command for credential lookup.
|
/// Use the `keyring` command for credential lookup.
|
||||||
Subprocess,
|
Subprocess,
|
||||||
// /// Not yet implemented
|
// /// Not yet implemented
|
||||||
|
|
@ -22,7 +26,60 @@ impl KeyringProviderType {
|
||||||
pub fn to_provider(&self) -> Option<KeyringProvider> {
|
pub fn to_provider(&self) -> Option<KeyringProvider> {
|
||||||
match self {
|
match self {
|
||||||
Self::Disabled => None,
|
Self::Disabled => None,
|
||||||
|
Self::Native => Some(KeyringProvider::native()),
|
||||||
Self::Subprocess => Some(KeyringProvider::subprocess()),
|
Self::Subprocess => Some(KeyringProvider::subprocess()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for KeyringProviderType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Disabled => write!(f, "disabled"),
|
||||||
|
Self::Native => write!(f, "native"),
|
||||||
|
Self::Subprocess => write!(f, "subprocess"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A service URL that wraps [`DisplaySafeUrl`] for CLI usage.
|
||||||
|
///
|
||||||
|
/// This type provides automatic URL parsing and validation when used as a CLI argument,
|
||||||
|
/// eliminating the need for manual parsing in command functions.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Service(DisplaySafeUrl);
|
||||||
|
|
||||||
|
impl Service {
|
||||||
|
/// Get the underlying [`DisplaySafeUrl`].
|
||||||
|
pub fn url(&self) -> &DisplaySafeUrl {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert into the underlying [`DisplaySafeUrl`].
|
||||||
|
pub fn into_url(self) -> DisplaySafeUrl {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Service {
|
||||||
|
type Err = url::ParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
// First try parsing as-is
|
||||||
|
match DisplaySafeUrl::parse(s) {
|
||||||
|
Ok(url) => Ok(Self(url)),
|
||||||
|
Err(url::ParseError::RelativeUrlWithoutBase) => {
|
||||||
|
// If it's a relative URL, try prepending https://
|
||||||
|
let with_https = format!("https://{s}");
|
||||||
|
DisplaySafeUrl::parse(&with_https).map(Service)
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Service {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,19 @@ pub fn password(prompt: &str, term: &Term) -> std::io::Result<String> {
|
||||||
Ok(input)
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prompt the user for username in the given [`Term`].
|
||||||
|
pub fn username(prompt: &str, term: &Term) -> std::io::Result<String> {
|
||||||
|
term.write_str(prompt)?;
|
||||||
|
term.show_cursor()?;
|
||||||
|
term.flush()?;
|
||||||
|
|
||||||
|
let input = term.read_line()?;
|
||||||
|
|
||||||
|
term.clear_line()?;
|
||||||
|
|
||||||
|
Ok(input)
|
||||||
|
}
|
||||||
|
|
||||||
/// Prompt the user for input text in the given [`Term`].
|
/// Prompt the user for input text in the given [`Term`].
|
||||||
///
|
///
|
||||||
/// This is a slimmed-down version of `dialoguer::Input`.
|
/// This is a slimmed-down version of `dialoguer::Input`.
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ bitflags::bitflags! {
|
||||||
const EXTRA_BUILD_DEPENDENCIES = 1 << 6;
|
const EXTRA_BUILD_DEPENDENCIES = 1 << 6;
|
||||||
const DETECT_MODULE_CONFLICTS = 1 << 7;
|
const DETECT_MODULE_CONFLICTS = 1 << 7;
|
||||||
const FORMAT = 1 << 8;
|
const FORMAT = 1 << 8;
|
||||||
|
const NATIVE_KEYRING = 1 << 9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +37,7 @@ impl PreviewFeatures {
|
||||||
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
|
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
|
||||||
Self::DETECT_MODULE_CONFLICTS => "detect-module-conflicts",
|
Self::DETECT_MODULE_CONFLICTS => "detect-module-conflicts",
|
||||||
Self::FORMAT => "format",
|
Self::FORMAT => "format",
|
||||||
|
Self::NATIVE_KEYRING => "native-keyring",
|
||||||
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,6 +84,7 @@ impl FromStr for PreviewFeatures {
|
||||||
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
|
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
|
||||||
"detect-module-conflicts" => Self::DETECT_MODULE_CONFLICTS,
|
"detect-module-conflicts" => Self::DETECT_MODULE_CONFLICTS,
|
||||||
"format" => Self::FORMAT,
|
"format" => Self::FORMAT,
|
||||||
|
"native-keyring" => Self::NATIVE_KEYRING,
|
||||||
_ => {
|
_ => {
|
||||||
warn_user_once!("Unknown preview feature: `{part}`");
|
warn_user_once!("Unknown preview feature: `{part}`");
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ ignored = [
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["performance", "uv-distribution/static", "default-tests"]
|
default = ["performance", "uv-distribution/static", "default-tests"]
|
||||||
|
keyring-tests = []
|
||||||
# Use better memory allocators, etc.
|
# Use better memory allocators, etc.
|
||||||
performance = ["performance-memory-allocator"]
|
performance = ["performance-memory-allocator"]
|
||||||
performance-memory-allocator = ["dep:uv-performance-memory-allocator"]
|
performance-memory-allocator = ["dep:uv-performance-memory-allocator"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
use anyhow::{Result, bail};
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use console::Term;
|
||||||
|
use uv_auth::Credentials;
|
||||||
|
use uv_configuration::{KeyringProviderType, Service};
|
||||||
|
|
||||||
|
use crate::{commands::ExitStatus, printer::Printer};
|
||||||
|
|
||||||
|
/// Login to a service.
|
||||||
|
pub(crate) async fn login(
|
||||||
|
service: Service,
|
||||||
|
username: Option<String>,
|
||||||
|
password: Option<String>,
|
||||||
|
token: Option<String>,
|
||||||
|
keyring_provider: Option<KeyringProviderType>,
|
||||||
|
printer: Printer,
|
||||||
|
) -> Result<ExitStatus> {
|
||||||
|
let url = service.url();
|
||||||
|
let display_url = username
|
||||||
|
.as_ref()
|
||||||
|
.map(|username| format!("{username}@{url}"))
|
||||||
|
.unwrap_or_else(|| url.to_string());
|
||||||
|
|
||||||
|
let username = if let Some(username) = username {
|
||||||
|
username
|
||||||
|
} else if token.is_some() {
|
||||||
|
String::from("__token__")
|
||||||
|
} else {
|
||||||
|
let term = Term::stderr();
|
||||||
|
if term.is_term() {
|
||||||
|
let prompt = "username: ";
|
||||||
|
uv_console::username(prompt, &term)?
|
||||||
|
} else {
|
||||||
|
bail!("No username provided; did you mean to provide `--username` or `--token`?");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Be helpful about incompatible `keyring-provider` settings
|
||||||
|
let Some(keyring_provider) = &keyring_provider else {
|
||||||
|
bail!(
|
||||||
|
"Logging in requires setting `keyring-provider = {}` for credentials to be retrieved in subsequent commands",
|
||||||
|
KeyringProviderType::Native
|
||||||
|
);
|
||||||
|
};
|
||||||
|
let provider = match keyring_provider {
|
||||||
|
KeyringProviderType::Native => keyring_provider.to_provider().unwrap(),
|
||||||
|
KeyringProviderType::Disabled | KeyringProviderType::Subprocess => {
|
||||||
|
bail!(
|
||||||
|
"Cannot login with `keyring-provider = {keyring_provider}`, use `keyring-provider = {}` instead",
|
||||||
|
KeyringProviderType::Native
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: It would be preferable to accept the value of --password or --token
|
||||||
|
// from stdin, perhaps checking here for `-` as an indicator to read stdin. We
|
||||||
|
// could then warn if the password is provided as a plaintext argument.
|
||||||
|
let password = if let Some(password) = password {
|
||||||
|
password
|
||||||
|
} else if let Some(token) = token {
|
||||||
|
token
|
||||||
|
} else {
|
||||||
|
let term = Term::stderr();
|
||||||
|
if term.is_term() {
|
||||||
|
let prompt = "password: ";
|
||||||
|
uv_console::password(prompt, &term)?
|
||||||
|
} else {
|
||||||
|
bail!("No password provided; did you mean to provide `--password` or `--token`?");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO(zanieb): Add support for other authentication schemes here, e.g., `Credentials::Bearer`
|
||||||
|
let credentials = Credentials::basic(Some(username), Some(password));
|
||||||
|
provider.store(url, &credentials).await?;
|
||||||
|
|
||||||
|
writeln!(printer.stderr(), "Logged in to {display_url}")?;
|
||||||
|
|
||||||
|
Ok(ExitStatus::Success)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
use anyhow::{Context, Result, bail};
|
||||||
|
use std::{borrow::Cow, fmt::Write};
|
||||||
|
use uv_configuration::{KeyringProviderType, Service};
|
||||||
|
|
||||||
|
use crate::{commands::ExitStatus, printer::Printer};
|
||||||
|
|
||||||
|
/// Logout from a service.
|
||||||
|
///
|
||||||
|
/// If no username is provided, defaults to `__token__`.
|
||||||
|
pub(crate) async fn logout(
|
||||||
|
service: Service,
|
||||||
|
username: Option<String>,
|
||||||
|
keyring_provider: Option<KeyringProviderType>,
|
||||||
|
printer: Printer,
|
||||||
|
) -> Result<ExitStatus> {
|
||||||
|
let url = service.url();
|
||||||
|
let display_url = username
|
||||||
|
.as_ref()
|
||||||
|
.map(|username| format!("{username}@{url}"))
|
||||||
|
.unwrap_or_else(|| url.to_string());
|
||||||
|
let username = username
|
||||||
|
.map(Cow::Owned)
|
||||||
|
.unwrap_or(Cow::Borrowed("__token__"));
|
||||||
|
|
||||||
|
// Unlike login, we'll default to the native provider if none is requested since it's the only
|
||||||
|
// valid option and it doesn't matter if the credentials are available in subsequent commands.
|
||||||
|
let keyring_provider = keyring_provider.unwrap_or(KeyringProviderType::Native);
|
||||||
|
|
||||||
|
// Be helpful about incompatible `keyring-provider` settings
|
||||||
|
let provider = match keyring_provider {
|
||||||
|
KeyringProviderType::Native => keyring_provider.to_provider().unwrap(),
|
||||||
|
KeyringProviderType::Disabled | KeyringProviderType::Subprocess => {
|
||||||
|
bail!(
|
||||||
|
"Cannot logout with `keyring-provider = {keyring_provider}`, use `keyring-provider = {}` instead",
|
||||||
|
KeyringProviderType::Native
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
provider
|
||||||
|
.remove(url, &username)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("Unable to remove credentials for {display_url}"))?;
|
||||||
|
|
||||||
|
writeln!(printer.stderr(), "Logged out of {display_url}")?;
|
||||||
|
|
||||||
|
Ok(ExitStatus::Success)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub(crate) mod login;
|
||||||
|
pub(crate) mod logout;
|
||||||
|
pub(crate) mod token;
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result, bail};
|
||||||
|
|
||||||
|
use uv_configuration::{KeyringProviderType, Service};
|
||||||
|
|
||||||
|
use crate::{Printer, commands::ExitStatus};
|
||||||
|
|
||||||
|
/// Show the token that will be used for a service.
|
||||||
|
pub(crate) async fn token(
|
||||||
|
service: Service,
|
||||||
|
username: Option<String>,
|
||||||
|
keyring_provider: Option<KeyringProviderType>,
|
||||||
|
printer: Printer,
|
||||||
|
) -> Result<ExitStatus> {
|
||||||
|
// Determine the keyring provider to use
|
||||||
|
let Some(keyring_provider) = &keyring_provider else {
|
||||||
|
bail!("Retrieving credentials requires setting a `keyring-provider`");
|
||||||
|
};
|
||||||
|
let Some(provider) = keyring_provider.to_provider() else {
|
||||||
|
bail!("Cannot retrieve credentials with `keyring-provider = {keyring_provider}`");
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = service.url();
|
||||||
|
let display_url = username
|
||||||
|
.as_ref()
|
||||||
|
.map(|username| format!("{username}@{url}"))
|
||||||
|
.unwrap_or_else(|| url.to_string());
|
||||||
|
|
||||||
|
let credentials = provider
|
||||||
|
.fetch(url, Some(username.as_deref().unwrap_or("__token__")))
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("Failed to fetch credentials for {display_url}"))?;
|
||||||
|
|
||||||
|
let Some(password) = credentials.password() else {
|
||||||
|
bail!(
|
||||||
|
"No {} found for {display_url}",
|
||||||
|
if username.is_some() {
|
||||||
|
"password"
|
||||||
|
} else {
|
||||||
|
"token"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
writeln!(printer.stdout(), "{password}")?;
|
||||||
|
Ok(ExitStatus::Success)
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,9 @@ use anyhow::Context;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
pub(crate) use auth::login::login as auth_login;
|
||||||
|
pub(crate) use auth::logout::logout as auth_logout;
|
||||||
|
pub(crate) use auth::token::token as auth_token;
|
||||||
pub(crate) use build_frontend::build_frontend;
|
pub(crate) use build_frontend::build_frontend;
|
||||||
pub(crate) use cache_clean::cache_clean;
|
pub(crate) use cache_clean::cache_clean;
|
||||||
pub(crate) use cache_dir::cache_dir;
|
pub(crate) use cache_dir::cache_dir;
|
||||||
|
|
@ -65,6 +68,7 @@ pub(crate) use venv::venv;
|
||||||
|
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
|
|
||||||
|
mod auth;
|
||||||
pub(crate) mod build_backend;
|
pub(crate) mod build_backend;
|
||||||
mod build_frontend;
|
mod build_frontend;
|
||||||
mod cache_clean;
|
mod cache_clean;
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ use uv_cache_info::Timestamp;
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
use uv_cli::SelfUpdateArgs;
|
use uv_cli::SelfUpdateArgs;
|
||||||
use uv_cli::{
|
use uv_cli::{
|
||||||
BuildBackendCommand, CacheCommand, CacheNamespace, Cli, Commands, PipCommand, PipNamespace,
|
AuthCommand, AuthNamespace, BuildBackendCommand, CacheCommand, CacheNamespace, Cli, Commands,
|
||||||
ProjectCommand, PythonCommand, PythonNamespace, SelfCommand, SelfNamespace, ToolCommand,
|
PipCommand, PipNamespace, ProjectCommand, PythonCommand, PythonNamespace, SelfCommand,
|
||||||
ToolNamespace, TopLevelArgs, compat::CompatArgs,
|
SelfNamespace, ToolCommand, ToolNamespace, TopLevelArgs, compat::CompatArgs,
|
||||||
};
|
};
|
||||||
use uv_client::BaseClientBuilder;
|
use uv_client::BaseClientBuilder;
|
||||||
use uv_configuration::min_stack_size;
|
use uv_configuration::min_stack_size;
|
||||||
|
|
@ -439,6 +439,41 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
.retries_from_env()?;
|
.retries_from_env()?;
|
||||||
|
|
||||||
match *cli.command {
|
match *cli.command {
|
||||||
|
Commands::Auth(AuthNamespace {
|
||||||
|
command: AuthCommand::Login(args),
|
||||||
|
}) => {
|
||||||
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||||
|
let args = settings::AuthLoginSettings::resolve(args, filesystem);
|
||||||
|
show_settings!(args);
|
||||||
|
|
||||||
|
commands::auth_login(
|
||||||
|
args.service,
|
||||||
|
args.username,
|
||||||
|
args.password,
|
||||||
|
args.token,
|
||||||
|
args.keyring_provider,
|
||||||
|
printer,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Commands::Auth(AuthNamespace {
|
||||||
|
command: AuthCommand::Logout(args),
|
||||||
|
}) => {
|
||||||
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||||
|
let args = settings::AuthLogoutSettings::resolve(args, filesystem);
|
||||||
|
show_settings!(args);
|
||||||
|
|
||||||
|
commands::auth_logout(args.service, args.username, args.keyring_provider, printer).await
|
||||||
|
}
|
||||||
|
Commands::Auth(AuthNamespace {
|
||||||
|
command: AuthCommand::Token(args),
|
||||||
|
}) => {
|
||||||
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||||
|
let args = settings::AuthTokenSettings::resolve(args, filesystem);
|
||||||
|
show_settings!(args);
|
||||||
|
|
||||||
|
commands::auth_token(args.service, args.username, args.keyring_provider, printer).await
|
||||||
|
}
|
||||||
Commands::Help(args) => commands::help(
|
Commands::Help(args) => commands::help(
|
||||||
args.command.unwrap_or_default().as_slice(),
|
args.command.unwrap_or_default().as_slice(),
|
||||||
printer,
|
printer,
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@ use std::str::FromStr;
|
||||||
use uv_cache::{CacheArgs, Refresh};
|
use uv_cache::{CacheArgs, Refresh};
|
||||||
use uv_cli::comma::CommaSeparatedRequirements;
|
use uv_cli::comma::CommaSeparatedRequirements;
|
||||||
use uv_cli::{
|
use uv_cli::{
|
||||||
AddArgs, ColorChoice, ExternalCommand, GlobalArgs, InitArgs, ListFormat, LockArgs, Maybe,
|
AddArgs, AuthLoginArgs, AuthLogoutArgs, AuthTokenArgs, ColorChoice, ExternalCommand,
|
||||||
PipCheckArgs, PipCompileArgs, PipFreezeArgs, PipInstallArgs, PipListArgs, PipShowArgs,
|
GlobalArgs, InitArgs, ListFormat, LockArgs, Maybe, PipCheckArgs, PipCompileArgs, PipFreezeArgs,
|
||||||
PipSyncArgs, PipTreeArgs, PipUninstallArgs, PythonFindArgs, PythonInstallArgs, PythonListArgs,
|
PipInstallArgs, PipListArgs, PipShowArgs, PipSyncArgs, PipTreeArgs, PipUninstallArgs,
|
||||||
PythonListFormat, PythonPinArgs, PythonUninstallArgs, PythonUpgradeArgs, RemoveArgs, RunArgs,
|
PythonFindArgs, PythonInstallArgs, PythonListArgs, PythonListFormat, PythonPinArgs,
|
||||||
SyncArgs, SyncFormat, ToolDirArgs, ToolInstallArgs, ToolListArgs, ToolRunArgs,
|
PythonUninstallArgs, PythonUpgradeArgs, RemoveArgs, RunArgs, SyncArgs, SyncFormat, ToolDirArgs,
|
||||||
ToolUninstallArgs, TreeArgs, VenvArgs, VersionArgs, VersionBump, VersionFormat,
|
ToolInstallArgs, ToolListArgs, ToolRunArgs, ToolUninstallArgs, TreeArgs, VenvArgs, VersionArgs,
|
||||||
|
VersionBump, VersionFormat,
|
||||||
};
|
};
|
||||||
use uv_cli::{
|
use uv_cli::{
|
||||||
AuthorFrom, BuildArgs, ExportArgs, FormatArgs, PublishArgs, PythonDirArgs,
|
AuthorFrom, BuildArgs, ExportArgs, FormatArgs, PublishArgs, PythonDirArgs,
|
||||||
|
|
@ -24,7 +25,8 @@ use uv_configuration::{
|
||||||
BuildIsolation, BuildOptions, Concurrency, DependencyGroups, DryRun, EditableMode,
|
BuildIsolation, BuildOptions, Concurrency, DependencyGroups, DryRun, EditableMode,
|
||||||
ExportFormat, ExtrasSpecification, HashCheckingMode, IndexStrategy, InstallOptions,
|
ExportFormat, ExtrasSpecification, HashCheckingMode, IndexStrategy, InstallOptions,
|
||||||
KeyringProviderType, NoBinary, NoBuild, ProjectBuildBackend, Reinstall, RequiredVersion,
|
KeyringProviderType, NoBinary, NoBuild, ProjectBuildBackend, Reinstall, RequiredVersion,
|
||||||
SourceStrategy, TargetTriple, TrustedHost, TrustedPublishing, Upgrade, VersionControlSystem,
|
Service, SourceStrategy, TargetTriple, TrustedHost, TrustedPublishing, Upgrade,
|
||||||
|
VersionControlSystem,
|
||||||
};
|
};
|
||||||
use uv_distribution_types::{
|
use uv_distribution_types::{
|
||||||
ConfigSettings, DependencyMetadata, ExtraBuildVariables, Index, IndexLocations, IndexUrl,
|
ConfigSettings, DependencyMetadata, ExtraBuildVariables, Index, IndexLocations, IndexUrl,
|
||||||
|
|
@ -3483,6 +3485,101 @@ impl PublishSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The resolved settings to use for an invocation of the `uv auth logout` CLI.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct AuthLogoutSettings {
|
||||||
|
pub(crate) service: Service,
|
||||||
|
pub(crate) username: Option<String>,
|
||||||
|
|
||||||
|
// Both CLI and configuration.
|
||||||
|
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthLogoutSettings {
|
||||||
|
/// Resolve the [`AuthLogoutSettings`] from the CLI and filesystem configuration.
|
||||||
|
pub(crate) fn resolve(args: AuthLogoutArgs, filesystem: Option<FilesystemOptions>) -> Self {
|
||||||
|
let Options { top_level, .. } = filesystem
|
||||||
|
.map(FilesystemOptions::into_options)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let ResolverInstallerSchema {
|
||||||
|
keyring_provider, ..
|
||||||
|
} = top_level;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
service: args.service,
|
||||||
|
username: args.username,
|
||||||
|
keyring_provider,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The resolved settings to use for an invocation of the `uv auth token` CLI.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct AuthTokenSettings {
|
||||||
|
pub(crate) service: Service,
|
||||||
|
pub(crate) username: Option<String>,
|
||||||
|
|
||||||
|
// Both CLI and configuration.
|
||||||
|
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthTokenSettings {
|
||||||
|
/// Resolve the [`AuthTokenSettings`] from the CLI and filesystem configuration.
|
||||||
|
pub(crate) fn resolve(args: AuthTokenArgs, filesystem: Option<FilesystemOptions>) -> Self {
|
||||||
|
let Options { top_level, .. } = filesystem
|
||||||
|
.map(FilesystemOptions::into_options)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let ResolverInstallerSchema {
|
||||||
|
keyring_provider, ..
|
||||||
|
} = top_level;
|
||||||
|
|
||||||
|
let keyring_provider = args.keyring_provider.combine(keyring_provider);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
service: args.service,
|
||||||
|
username: args.username,
|
||||||
|
keyring_provider,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The resolved settings to use for an invocation of the `uv auth set` CLI.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct AuthLoginSettings {
|
||||||
|
pub(crate) service: Service,
|
||||||
|
pub(crate) username: Option<String>,
|
||||||
|
pub(crate) password: Option<String>,
|
||||||
|
pub(crate) token: Option<String>,
|
||||||
|
|
||||||
|
// Both CLI and configuration.
|
||||||
|
pub(crate) keyring_provider: Option<KeyringProviderType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthLoginSettings {
|
||||||
|
/// Resolve the [`AuthLoginSettings`] from the CLI and filesystem configuration.
|
||||||
|
pub(crate) fn resolve(args: AuthLoginArgs, filesystem: Option<FilesystemOptions>) -> Self {
|
||||||
|
let Options { top_level, .. } = filesystem
|
||||||
|
.map(FilesystemOptions::into_options)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let ResolverInstallerSchema {
|
||||||
|
keyring_provider, ..
|
||||||
|
} = top_level;
|
||||||
|
|
||||||
|
let keyring_provider = args.keyring_provider.combine(keyring_provider);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
service: args.service,
|
||||||
|
username: args.username,
|
||||||
|
password: args.password,
|
||||||
|
token: args.token,
|
||||||
|
keyring_provider,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Environment variables that are not exposed as CLI arguments.
|
// Environment variables that are not exposed as CLI arguments.
|
||||||
mod env {
|
mod env {
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,733 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use assert_cmd::assert::OutputAssertExt;
|
||||||
|
use assert_fs::{fixture::PathChild, prelude::FileWriteStr};
|
||||||
|
use uv_static::EnvVars;
|
||||||
|
|
||||||
|
use crate::common::{TestContext, uv_snapshot, venv_bin_path};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_package_native_keyring() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12").with_real_home();
|
||||||
|
|
||||||
|
// Clear state before the test
|
||||||
|
context
|
||||||
|
.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
// Configure `pyproject.toml` with native keyring provider.
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(indoc::indoc! { r#"
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0.0"
|
||||||
|
requires-python = ">=3.11, <4"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
keyring-provider = "native"
|
||||||
|
"#
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Try to add a package without credentials.
|
||||||
|
uv_snapshot!(context.add().arg("anyio").arg("--default-index").arg("https://public@pypi-proxy.fly.dev/basic-auth/simple"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because anyio was not found in the package registry and your project depends on anyio, we can conclude that your project's requirements are unsatisfiable.
|
||||||
|
|
||||||
|
hint: An index URL (https://pypi-proxy.fly.dev/basic-auth/simple) could not be queried due to a lack of valid authentication credentials (401 Unauthorized).
|
||||||
|
help: If you want to add the package regardless of the failed resolution, provide the `--frozen` flag to skip locking and syncing.
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Login to the index
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("heron"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to add the original package without credentials again. This should use
|
||||||
|
// credentials storied in the system keyring.
|
||||||
|
uv_snapshot!(context.add().arg("anyio").arg("--default-index").arg("https://public@pypi-proxy.fly.dev/basic-auth/simple"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 4 packages in [TIME]
|
||||||
|
Prepared 3 packages in [TIME]
|
||||||
|
Installed 3 packages in [TIME]
|
||||||
|
+ anyio==4.3.0
|
||||||
|
+ idna==3.6
|
||||||
|
+ sniffio==1.3.1
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Logout of the index
|
||||||
|
uv_snapshot!(context.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged out of public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Authentication should fail again
|
||||||
|
uv_snapshot!(context.add().arg("iniconfig").arg("--default-index").arg("https://public@pypi-proxy.fly.dev/basic-auth/simple"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because iniconfig was not found in the package registry and your project depends on iniconfig, we can conclude that your project's requirements are unsatisfiable.
|
||||||
|
|
||||||
|
hint: An index URL (https://pypi-proxy.fly.dev/basic-auth/simple) could not be queried due to a lack of valid authentication credentials (401 Unauthorized).
|
||||||
|
help: If you want to add the package regardless of the failed resolution, provide the `--frozen` flag to skip locking and syncing.
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn token_native_keyring() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&[]).with_real_home();
|
||||||
|
|
||||||
|
// Clear state before the test
|
||||||
|
context
|
||||||
|
.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
// Without a service name
|
||||||
|
uv_snapshot!(context.auth_token(), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the following required arguments were not provided:
|
||||||
|
<SERVICE>
|
||||||
|
|
||||||
|
Usage: uv auth token --cache-dir [CACHE_DIR] <SERVICE>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
");
|
||||||
|
|
||||||
|
// Without a keyring provider...
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Retrieving credentials requires setting a `keyring-provider`
|
||||||
|
");
|
||||||
|
|
||||||
|
// Without persisted credentials
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Failed to fetch credentials for https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
// Without persisted credentials (with a username in the request)
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Failed to fetch credentials for public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
// Login to the index
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("heron")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Show the credentials
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
heron
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
");
|
||||||
|
|
||||||
|
// Without the username
|
||||||
|
// TODO(zanieb): Add a hint here if we can?
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Failed to fetch credentials for https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
// With a mismatched username
|
||||||
|
// TODO(zanieb): Add a hint here if we can?
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("private")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Failed to fetch credentials for private@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
// Login to the index with a token
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--token")
|
||||||
|
.arg("heron")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Retrieve the token without a username
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
heron
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn token_subprocess_keyring() {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
// Without a keyring on the PATH
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://public@pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("subprocess"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Failed to fetch credentials for https://****@pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Install our keyring plugin
|
||||||
|
context
|
||||||
|
.pip_install()
|
||||||
|
.arg(
|
||||||
|
context
|
||||||
|
.workspace_root
|
||||||
|
.join("scripts")
|
||||||
|
.join("packages")
|
||||||
|
.join("keyring_test_plugin"),
|
||||||
|
)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
// Without credentials available
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://public@pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("subprocess")
|
||||||
|
.env(EnvVars::PATH, venv_bin_path(&context.venv)), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Keyring request for __token__@https://public@pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
Keyring request for __token__@pypi-proxy.fly.dev
|
||||||
|
error: Failed to fetch credentials for https://****@pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Without a username
|
||||||
|
// TODO(zanieb): Add a hint here if we can?
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://public@pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("subprocess")
|
||||||
|
.env(EnvVars::KEYRING_TEST_CREDENTIALS, r#"{"pypi-proxy.fly.dev": {"public": "heron"}}"#)
|
||||||
|
.env(EnvVars::PATH, venv_bin_path(&context.venv)), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Keyring request for __token__@https://public@pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
Keyring request for __token__@pypi-proxy.fly.dev
|
||||||
|
error: Failed to fetch credentials for https://****@pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// With the correct username
|
||||||
|
uv_snapshot!(context.auth_token()
|
||||||
|
.arg("https://public@pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("subprocess")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.env(EnvVars::KEYRING_TEST_CREDENTIALS, r#"{"pypi-proxy.fly.dev": {"public": "heron"}}"#)
|
||||||
|
.env(EnvVars::PATH, venv_bin_path(&context.venv)), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
heron
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Keyring request for public@https://public@pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
Keyring request for public@pypi-proxy.fly.dev
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn login_native_keyring() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&[]).with_real_home();
|
||||||
|
|
||||||
|
// Clear state before the test
|
||||||
|
context
|
||||||
|
.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
// Without a service name
|
||||||
|
uv_snapshot!(context.auth_login(), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the following required arguments were not provided:
|
||||||
|
<SERVICE>
|
||||||
|
|
||||||
|
Usage: uv auth login --cache-dir [CACHE_DIR] <SERVICE>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
");
|
||||||
|
|
||||||
|
// Without a username (or token)
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: No username provided; did you mean to provide `--username` or `--token`?
|
||||||
|
");
|
||||||
|
|
||||||
|
// Without a password
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: No password provided; did you mean to provide `--password` or `--token`?
|
||||||
|
");
|
||||||
|
|
||||||
|
// Without a keyring provider
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--token")
|
||||||
|
.arg("foo"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Logging in requires setting `keyring-provider = native` for credentials to be retrieved in subsequent commands
|
||||||
|
");
|
||||||
|
|
||||||
|
// Successful
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("heron")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn login_token_native_keyring() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&[]).with_real_home();
|
||||||
|
|
||||||
|
// Clear state before the test
|
||||||
|
context
|
||||||
|
.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("__token__")
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
// Successful with token
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--token")
|
||||||
|
.arg("test-token")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn logout_native_keyring() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&[]).with_real_home();
|
||||||
|
|
||||||
|
// Clear state before the test
|
||||||
|
context
|
||||||
|
.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
// Without a service name
|
||||||
|
uv_snapshot!(context.auth_logout(), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the following required arguments were not provided:
|
||||||
|
<SERVICE>
|
||||||
|
|
||||||
|
Usage: uv auth logout --cache-dir [CACHE_DIR] <SERVICE>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
");
|
||||||
|
|
||||||
|
// Logout without a keyring provider
|
||||||
|
uv_snapshot!(context.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged out of https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
// Logout before logging in (without a username)
|
||||||
|
uv_snapshot!(context.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Unable to remove credentials for https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
Caused by: No matching entry found in secure storage
|
||||||
|
");
|
||||||
|
|
||||||
|
// Logout before logging in (with a username)
|
||||||
|
uv_snapshot!(context.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Unable to remove credentials for public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
Caused by: No matching entry found in secure storage
|
||||||
|
");
|
||||||
|
|
||||||
|
// Login with a username
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("heron")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Logout without a username
|
||||||
|
// TODO(zanieb): Add a hint here if we can?
|
||||||
|
uv_snapshot!(context.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Unable to remove credentials for https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
Caused by: No matching entry found in secure storage
|
||||||
|
");
|
||||||
|
|
||||||
|
// Logout with a username
|
||||||
|
uv_snapshot!(context.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("public")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged out of public@https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn logout_token_native_keyring() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&[]).with_real_home();
|
||||||
|
|
||||||
|
// Clear state before the test
|
||||||
|
context
|
||||||
|
.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
// Login with a token
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--token")
|
||||||
|
.arg("test-token")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Logout without a username
|
||||||
|
uv_snapshot!(context.auth_logout()
|
||||||
|
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged out of https://pypi-proxy.fly.dev/basic-auth/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn login_url_parsing() {
|
||||||
|
let context = TestContext::new_with_versions(&[]).with_real_home();
|
||||||
|
|
||||||
|
// A domain-only service name gets https:// prepended
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("example.com")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to test@https://example.com/
|
||||||
|
");
|
||||||
|
|
||||||
|
// When including a protocol explicitly, it is retained
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("http://example.com")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to test@http://example.com/
|
||||||
|
");
|
||||||
|
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("https://example.com")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to test@https://example.com/
|
||||||
|
");
|
||||||
|
|
||||||
|
// A domain-only service with a path also gets https:// prepended
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("example.com/simple")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Logged in to test@https://example.com/simple
|
||||||
|
");
|
||||||
|
|
||||||
|
// An invalid URL is rejected
|
||||||
|
uv_snapshot!(context.auth_login()
|
||||||
|
.arg("not a valid url")
|
||||||
|
.arg("--username")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--password")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--keyring-provider")
|
||||||
|
.arg("native"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: invalid value 'not a valid url' for '<SERVICE>': invalid international domain name
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
@ -1274,6 +1274,42 @@ impl TestContext {
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a `uv auth login` command.
|
||||||
|
pub fn auth_login(&self) -> Command {
|
||||||
|
let mut command = Self::new_command();
|
||||||
|
command.arg("auth").arg("login");
|
||||||
|
self.add_shared_options(&mut command, false);
|
||||||
|
command
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `uv auth logout` command.
|
||||||
|
pub fn auth_logout(&self) -> Command {
|
||||||
|
let mut command = Self::new_command();
|
||||||
|
command.arg("auth").arg("logout");
|
||||||
|
self.add_shared_options(&mut command, false);
|
||||||
|
command
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `uv auth token` command.
|
||||||
|
pub fn auth_token(&self) -> Command {
|
||||||
|
let mut command = Self::new_command();
|
||||||
|
command.arg("auth").arg("token");
|
||||||
|
self.add_shared_options(&mut command, false);
|
||||||
|
command
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set `HOME` to the real home directory.
|
||||||
|
///
|
||||||
|
/// We need this for testing commands which use the macOS keychain.
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_real_home(mut self) -> Self {
|
||||||
|
if let Some(home) = env::var_os(EnvVars::HOME) {
|
||||||
|
self.extra_env
|
||||||
|
.push((EnvVars::HOME.to_string().into(), home));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Run the given python code and check whether it succeeds.
|
/// Run the given python code and check whether it succeeds.
|
||||||
pub fn assert_command(&self, command: &str) -> Assert {
|
pub fn assert_command(&self, command: &str) -> Assert {
|
||||||
self.python_command()
|
self.python_command()
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ fn help() {
|
||||||
Usage: uv [OPTIONS] <COMMAND>
|
Usage: uv [OPTIONS] <COMMAND>
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|
auth Manage authentication
|
||||||
run Run a command or script
|
run Run a command or script
|
||||||
init Create a new project
|
init Create a new project
|
||||||
add Add dependencies to the project
|
add Add dependencies to the project
|
||||||
|
|
@ -97,6 +98,7 @@ fn help_flag() {
|
||||||
Usage: uv [OPTIONS] <COMMAND>
|
Usage: uv [OPTIONS] <COMMAND>
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|
auth Manage authentication
|
||||||
run Run a command or script
|
run Run a command or script
|
||||||
init Create a new project
|
init Create a new project
|
||||||
add Add dependencies to the project
|
add Add dependencies to the project
|
||||||
|
|
@ -176,6 +178,7 @@ fn help_short_flag() {
|
||||||
Usage: uv [OPTIONS] <COMMAND>
|
Usage: uv [OPTIONS] <COMMAND>
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|
auth Manage authentication
|
||||||
run Run a command or script
|
run Run a command or script
|
||||||
init Create a new project
|
init Create a new project
|
||||||
add Add dependencies to the project
|
add Add dependencies to the project
|
||||||
|
|
@ -874,6 +877,7 @@ fn help_unknown_subcommand() {
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
error: There is no command `foobar` for `uv`. Did you mean one of:
|
error: There is no command `foobar` for `uv`. Did you mean one of:
|
||||||
|
auth
|
||||||
run
|
run
|
||||||
init
|
init
|
||||||
add
|
add
|
||||||
|
|
@ -902,6 +906,7 @@ fn help_unknown_subcommand() {
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
error: There is no command `foo bar` for `uv`. Did you mean one of:
|
error: There is no command `foo bar` for `uv`. Did you mean one of:
|
||||||
|
auth
|
||||||
run
|
run
|
||||||
init
|
init
|
||||||
add
|
add
|
||||||
|
|
@ -959,6 +964,7 @@ fn help_with_global_option() {
|
||||||
Usage: uv [OPTIONS] <COMMAND>
|
Usage: uv [OPTIONS] <COMMAND>
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|
auth Manage authentication
|
||||||
run Run a command or script
|
run Run a command or script
|
||||||
init Create a new project
|
init Create a new project
|
||||||
add Add dependencies to the project
|
add Add dependencies to the project
|
||||||
|
|
@ -1081,6 +1087,7 @@ fn help_with_no_pager() {
|
||||||
Usage: uv [OPTIONS] <COMMAND>
|
Usage: uv [OPTIONS] <COMMAND>
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|
auth Manage authentication
|
||||||
run Run a command or script
|
run Run a command or script
|
||||||
init Create a new project
|
init Create a new project
|
||||||
add Add dependencies to the project
|
add Add dependencies to the project
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
pub(crate) mod common;
|
pub(crate) mod common;
|
||||||
|
|
||||||
|
#[cfg(feature = "keyring-tests")]
|
||||||
|
mod auth;
|
||||||
|
|
||||||
mod branching_urls;
|
mod branching_urls;
|
||||||
|
|
||||||
#[cfg(all(feature = "python", feature = "pypi"))]
|
#[cfg(all(feature = "python", feature = "pypi"))]
|
||||||
|
|
|
||||||
|
|
@ -7684,7 +7684,7 @@ fn preview_features() {
|
||||||
show_settings: true,
|
show_settings: true,
|
||||||
preview: Preview {
|
preview: Preview {
|
||||||
flags: PreviewFeatures(
|
flags: PreviewFeatures(
|
||||||
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT,
|
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_KEYRING,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
python_preference: Managed,
|
python_preference: Managed,
|
||||||
|
|
@ -7908,7 +7908,7 @@ fn preview_features() {
|
||||||
show_settings: true,
|
show_settings: true,
|
||||||
preview: Preview {
|
preview: Preview {
|
||||||
flags: PreviewFeatures(
|
flags: PreviewFeatures(
|
||||||
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT,
|
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_KEYRING,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
python_preference: Managed,
|
python_preference: Managed,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ uv [OPTIONS] <COMMAND>
|
||||||
|
|
||||||
<h3 class="cli-reference">Commands</h3>
|
<h3 class="cli-reference">Commands</h3>
|
||||||
|
|
||||||
<dl class="cli-reference"><dt><a href="#uv-run"><code>uv run</code></a></dt><dd><p>Run a command or script</p></dd>
|
<dl class="cli-reference"><dt><a href="#uv-auth"><code>uv auth</code></a></dt><dd><p>Manage authentication</p></dd>
|
||||||
|
<dt><a href="#uv-run"><code>uv run</code></a></dt><dd><p>Run a command or script</p></dd>
|
||||||
<dt><a href="#uv-init"><code>uv init</code></a></dt><dd><p>Create a new project</p></dd>
|
<dt><a href="#uv-init"><code>uv init</code></a></dt><dd><p>Create a new project</p></dd>
|
||||||
<dt><a href="#uv-add"><code>uv add</code></a></dt><dd><p>Add dependencies to the project</p></dd>
|
<dt><a href="#uv-add"><code>uv add</code></a></dt><dd><p>Add dependencies to the project</p></dd>
|
||||||
<dt><a href="#uv-remove"><code>uv remove</code></a></dt><dd><p>Remove dependencies from the project</p></dd>
|
<dt><a href="#uv-remove"><code>uv remove</code></a></dt><dd><p>Remove dependencies from the project</p></dd>
|
||||||
|
|
@ -33,6 +34,238 @@ uv [OPTIONS] <COMMAND>
|
||||||
<dt><a href="#uv-help"><code>uv help</code></a></dt><dd><p>Display documentation for a command</p></dd>
|
<dt><a href="#uv-help"><code>uv help</code></a></dt><dd><p>Display documentation for a command</p></dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
## uv auth
|
||||||
|
|
||||||
|
Manage authentication
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Usage</h3>
|
||||||
|
|
||||||
|
```
|
||||||
|
uv auth [OPTIONS] <COMMAND>
|
||||||
|
```
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Commands</h3>
|
||||||
|
|
||||||
|
<dl class="cli-reference"><dt><a href="#uv-auth-login"><code>uv auth login</code></a></dt><dd><p>Login to a service</p></dd>
|
||||||
|
<dt><a href="#uv-auth-logout"><code>uv auth logout</code></a></dt><dd><p>Logout of a service</p></dd>
|
||||||
|
<dt><a href="#uv-auth-token"><code>uv auth token</code></a></dt><dd><p>Show the authentication token for a service</p></dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
### uv auth login
|
||||||
|
|
||||||
|
Login to a service
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Usage</h3>
|
||||||
|
|
||||||
|
```
|
||||||
|
uv auth login [OPTIONS] <SERVICE>
|
||||||
|
```
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Arguments</h3>
|
||||||
|
|
||||||
|
<dl class="cli-reference"><dt id="uv-auth-login--service"><a href="#uv-auth-login--service"<code>SERVICE</code></a></dt><dd><p>The service to login to</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Options</h3>
|
||||||
|
|
||||||
|
<dl class="cli-reference"><dt id="uv-auth-login--allow-insecure-host"><a href="#uv-auth-login--allow-insecure-host"><code>--allow-insecure-host</code></a>, <code>--trusted-host</code> <i>allow-insecure-host</i></dt><dd><p>Allow insecure connections to a host.</p>
|
||||||
|
<p>Can be provided multiple times.</p>
|
||||||
|
<p>Expects to receive either a hostname (e.g., <code>localhost</code>), a host-port pair (e.g., <code>localhost:8080</code>), or a URL (e.g., <code>https://localhost</code>).</p>
|
||||||
|
<p>WARNING: Hosts included in this list will not be verified against the system's certificate store. Only use <code>--allow-insecure-host</code> in a secure network with verified sources, as it bypasses SSL verification and could expose you to MITM attacks.</p>
|
||||||
|
<p>May also be set with the <code>UV_INSECURE_HOST</code> environment variable.</p></dd><dt id="uv-auth-login--cache-dir"><a href="#uv-auth-login--cache-dir"><code>--cache-dir</code></a> <i>cache-dir</i></dt><dd><p>Path to the cache directory.</p>
|
||||||
|
<p>Defaults to <code>$XDG_CACHE_HOME/uv</code> or <code>$HOME/.cache/uv</code> on macOS and Linux, and <code>%LOCALAPPDATA%\uv\cache</code> on Windows.</p>
|
||||||
|
<p>To view the location of the cache directory, run <code>uv cache dir</code>.</p>
|
||||||
|
<p>May also be set with the <code>UV_CACHE_DIR</code> environment variable.</p></dd><dt id="uv-auth-login--color"><a href="#uv-auth-login--color"><code>--color</code></a> <i>color-choice</i></dt><dd><p>Control the use of color in output.</p>
|
||||||
|
<p>By default, uv will automatically detect support for colors when writing to a terminal.</p>
|
||||||
|
<p>Possible values:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>auto</code>: Enables colored output only when the output is going to a terminal or TTY with support</li>
|
||||||
|
<li><code>always</code>: Enables colored output regardless of the detected environment</li>
|
||||||
|
<li><code>never</code>: Disables colored output</li>
|
||||||
|
</ul></dd><dt id="uv-auth-login--config-file"><a href="#uv-auth-login--config-file"><code>--config-file</code></a> <i>config-file</i></dt><dd><p>The path to a <code>uv.toml</code> file to use for configuration.</p>
|
||||||
|
<p>While uv configuration can be included in a <code>pyproject.toml</code> file, it is not allowed in this context.</p>
|
||||||
|
<p>May also be set with the <code>UV_CONFIG_FILE</code> environment variable.</p></dd><dt id="uv-auth-login--directory"><a href="#uv-auth-login--directory"><code>--directory</code></a> <i>directory</i></dt><dd><p>Change to the given directory prior to running the command.</p>
|
||||||
|
<p>Relative paths are resolved with the given directory as the base.</p>
|
||||||
|
<p>See <code>--project</code> to only change the project root directory.</p>
|
||||||
|
</dd><dt id="uv-auth-login--help"><a href="#uv-auth-login--help"><code>--help</code></a>, <code>-h</code></dt><dd><p>Display the concise help for this command</p>
|
||||||
|
</dd><dt id="uv-auth-login--keyring-provider"><a href="#uv-auth-login--keyring-provider"><code>--keyring-provider</code></a> <i>keyring-provider</i></dt><dd><p>The keyring provider to use for storage of credentials.</p>
|
||||||
|
<p>Only <code>--keyring-provider native</code> is supported for <code>login</code>, which uses the system keyring via an integration built into uv.</p>
|
||||||
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
|
</ul></dd><dt id="uv-auth-login--managed-python"><a href="#uv-auth-login--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
||||||
|
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
||||||
|
<p>May also be set with the <code>UV_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-auth-login--native-tls"><a href="#uv-auth-login--native-tls"><code>--native-tls</code></a></dt><dd><p>Whether to load TLS certificates from the platform's native certificate store.</p>
|
||||||
|
<p>By default, uv loads certificates from the bundled <code>webpki-roots</code> crate. The <code>webpki-roots</code> are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).</p>
|
||||||
|
<p>However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.</p>
|
||||||
|
<p>May also be set with the <code>UV_NATIVE_TLS</code> environment variable.</p></dd><dt id="uv-auth-login--no-cache"><a href="#uv-auth-login--no-cache"><code>--no-cache</code></a>, <code>--no-cache-dir</code>, <code>-n</code></dt><dd><p>Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_CACHE</code> environment variable.</p></dd><dt id="uv-auth-login--no-config"><a href="#uv-auth-login--no-config"><code>--no-config</code></a></dt><dd><p>Avoid discovering configuration files (<code>pyproject.toml</code>, <code>uv.toml</code>).</p>
|
||||||
|
<p>Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p></dd><dt id="uv-auth-login--no-managed-python"><a href="#uv-auth-login--no-managed-python"><code>--no-managed-python</code></a></dt><dd><p>Disable use of uv-managed Python versions.</p>
|
||||||
|
<p>Instead, uv will search for a suitable Python version on the system.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-auth-login--no-progress"><a href="#uv-auth-login--no-progress"><code>--no-progress</code></a></dt><dd><p>Hide all progress outputs.</p>
|
||||||
|
<p>For example, spinners or progress bars.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_PROGRESS</code> environment variable.</p></dd><dt id="uv-auth-login--no-python-downloads"><a href="#uv-auth-login--no-python-downloads"><code>--no-python-downloads</code></a></dt><dd><p>Disable automatic downloads of Python.</p>
|
||||||
|
</dd><dt id="uv-auth-login--offline"><a href="#uv-auth-login--offline"><code>--offline</code></a></dt><dd><p>Disable network access.</p>
|
||||||
|
<p>When disabled, uv will only use locally cached data and locally available files.</p>
|
||||||
|
<p>May also be set with the <code>UV_OFFLINE</code> environment variable.</p></dd><dt id="uv-auth-login--password"><a href="#uv-auth-login--password"><code>--password</code></a> <i>password</i></dt><dd><p>The password to use for the service</p>
|
||||||
|
</dd><dt id="uv-auth-login--project"><a href="#uv-auth-login--project"><code>--project</code></a> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
|
||||||
|
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (<code>.venv</code>).</p>
|
||||||
|
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
|
||||||
|
<p>See <code>--directory</code> to change the working directory entirely.</p>
|
||||||
|
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
|
||||||
|
<p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-auth-login--quiet"><a href="#uv-auth-login--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
|
||||||
|
<p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p>
|
||||||
|
</dd><dt id="uv-auth-login--token"><a href="#uv-auth-login--token"><code>--token</code></a>, <code>-t</code> <i>token</i></dt><dd><p>The token to use for the service.</p>
|
||||||
|
<p>The username will be set to <code>__token__</code>.</p>
|
||||||
|
</dd><dt id="uv-auth-login--username"><a href="#uv-auth-login--username"><code>--username</code></a>, <code>-u</code> <i>username</i></dt><dd><p>The username to use for the service</p>
|
||||||
|
</dd><dt id="uv-auth-login--verbose"><a href="#uv-auth-login--verbose"><code>--verbose</code></a>, <code>-v</code></dt><dd><p>Use verbose output.</p>
|
||||||
|
<p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (<a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives">https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives</a>)</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
### uv auth logout
|
||||||
|
|
||||||
|
Logout of a service
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Usage</h3>
|
||||||
|
|
||||||
|
```
|
||||||
|
uv auth logout [OPTIONS] <SERVICE>
|
||||||
|
```
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Arguments</h3>
|
||||||
|
|
||||||
|
<dl class="cli-reference"><dt id="uv-auth-logout--service"><a href="#uv-auth-logout--service"<code>SERVICE</code></a></dt><dd><p>The service to logout of</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Options</h3>
|
||||||
|
|
||||||
|
<dl class="cli-reference"><dt id="uv-auth-logout--allow-insecure-host"><a href="#uv-auth-logout--allow-insecure-host"><code>--allow-insecure-host</code></a>, <code>--trusted-host</code> <i>allow-insecure-host</i></dt><dd><p>Allow insecure connections to a host.</p>
|
||||||
|
<p>Can be provided multiple times.</p>
|
||||||
|
<p>Expects to receive either a hostname (e.g., <code>localhost</code>), a host-port pair (e.g., <code>localhost:8080</code>), or a URL (e.g., <code>https://localhost</code>).</p>
|
||||||
|
<p>WARNING: Hosts included in this list will not be verified against the system's certificate store. Only use <code>--allow-insecure-host</code> in a secure network with verified sources, as it bypasses SSL verification and could expose you to MITM attacks.</p>
|
||||||
|
<p>May also be set with the <code>UV_INSECURE_HOST</code> environment variable.</p></dd><dt id="uv-auth-logout--cache-dir"><a href="#uv-auth-logout--cache-dir"><code>--cache-dir</code></a> <i>cache-dir</i></dt><dd><p>Path to the cache directory.</p>
|
||||||
|
<p>Defaults to <code>$XDG_CACHE_HOME/uv</code> or <code>$HOME/.cache/uv</code> on macOS and Linux, and <code>%LOCALAPPDATA%\uv\cache</code> on Windows.</p>
|
||||||
|
<p>To view the location of the cache directory, run <code>uv cache dir</code>.</p>
|
||||||
|
<p>May also be set with the <code>UV_CACHE_DIR</code> environment variable.</p></dd><dt id="uv-auth-logout--color"><a href="#uv-auth-logout--color"><code>--color</code></a> <i>color-choice</i></dt><dd><p>Control the use of color in output.</p>
|
||||||
|
<p>By default, uv will automatically detect support for colors when writing to a terminal.</p>
|
||||||
|
<p>Possible values:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>auto</code>: Enables colored output only when the output is going to a terminal or TTY with support</li>
|
||||||
|
<li><code>always</code>: Enables colored output regardless of the detected environment</li>
|
||||||
|
<li><code>never</code>: Disables colored output</li>
|
||||||
|
</ul></dd><dt id="uv-auth-logout--config-file"><a href="#uv-auth-logout--config-file"><code>--config-file</code></a> <i>config-file</i></dt><dd><p>The path to a <code>uv.toml</code> file to use for configuration.</p>
|
||||||
|
<p>While uv configuration can be included in a <code>pyproject.toml</code> file, it is not allowed in this context.</p>
|
||||||
|
<p>May also be set with the <code>UV_CONFIG_FILE</code> environment variable.</p></dd><dt id="uv-auth-logout--directory"><a href="#uv-auth-logout--directory"><code>--directory</code></a> <i>directory</i></dt><dd><p>Change to the given directory prior to running the command.</p>
|
||||||
|
<p>Relative paths are resolved with the given directory as the base.</p>
|
||||||
|
<p>See <code>--project</code> to only change the project root directory.</p>
|
||||||
|
</dd><dt id="uv-auth-logout--help"><a href="#uv-auth-logout--help"><code>--help</code></a>, <code>-h</code></dt><dd><p>Display the concise help for this command</p>
|
||||||
|
</dd><dt id="uv-auth-logout--keyring-provider"><a href="#uv-auth-logout--keyring-provider"><code>--keyring-provider</code></a> <i>keyring-provider</i></dt><dd><p>The keyring provider to use for storage of credentials.</p>
|
||||||
|
<p>Only <code>--keyring-provider native</code> is supported for <code>logout</code>, which uses the system keyring via an integration built into uv.</p>
|
||||||
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
|
</ul></dd><dt id="uv-auth-logout--managed-python"><a href="#uv-auth-logout--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
||||||
|
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
||||||
|
<p>May also be set with the <code>UV_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-auth-logout--native-tls"><a href="#uv-auth-logout--native-tls"><code>--native-tls</code></a></dt><dd><p>Whether to load TLS certificates from the platform's native certificate store.</p>
|
||||||
|
<p>By default, uv loads certificates from the bundled <code>webpki-roots</code> crate. The <code>webpki-roots</code> are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).</p>
|
||||||
|
<p>However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.</p>
|
||||||
|
<p>May also be set with the <code>UV_NATIVE_TLS</code> environment variable.</p></dd><dt id="uv-auth-logout--no-cache"><a href="#uv-auth-logout--no-cache"><code>--no-cache</code></a>, <code>--no-cache-dir</code>, <code>-n</code></dt><dd><p>Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_CACHE</code> environment variable.</p></dd><dt id="uv-auth-logout--no-config"><a href="#uv-auth-logout--no-config"><code>--no-config</code></a></dt><dd><p>Avoid discovering configuration files (<code>pyproject.toml</code>, <code>uv.toml</code>).</p>
|
||||||
|
<p>Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p></dd><dt id="uv-auth-logout--no-managed-python"><a href="#uv-auth-logout--no-managed-python"><code>--no-managed-python</code></a></dt><dd><p>Disable use of uv-managed Python versions.</p>
|
||||||
|
<p>Instead, uv will search for a suitable Python version on the system.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-auth-logout--no-progress"><a href="#uv-auth-logout--no-progress"><code>--no-progress</code></a></dt><dd><p>Hide all progress outputs.</p>
|
||||||
|
<p>For example, spinners or progress bars.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_PROGRESS</code> environment variable.</p></dd><dt id="uv-auth-logout--no-python-downloads"><a href="#uv-auth-logout--no-python-downloads"><code>--no-python-downloads</code></a></dt><dd><p>Disable automatic downloads of Python.</p>
|
||||||
|
</dd><dt id="uv-auth-logout--offline"><a href="#uv-auth-logout--offline"><code>--offline</code></a></dt><dd><p>Disable network access.</p>
|
||||||
|
<p>When disabled, uv will only use locally cached data and locally available files.</p>
|
||||||
|
<p>May also be set with the <code>UV_OFFLINE</code> environment variable.</p></dd><dt id="uv-auth-logout--project"><a href="#uv-auth-logout--project"><code>--project</code></a> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
|
||||||
|
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (<code>.venv</code>).</p>
|
||||||
|
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
|
||||||
|
<p>See <code>--directory</code> to change the working directory entirely.</p>
|
||||||
|
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
|
||||||
|
<p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-auth-logout--quiet"><a href="#uv-auth-logout--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
|
||||||
|
<p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p>
|
||||||
|
</dd><dt id="uv-auth-logout--username"><a href="#uv-auth-logout--username"><code>--username</code></a>, <code>-u</code> <i>username</i></dt><dd><p>The username to logout</p>
|
||||||
|
</dd><dt id="uv-auth-logout--verbose"><a href="#uv-auth-logout--verbose"><code>--verbose</code></a>, <code>-v</code></dt><dd><p>Use verbose output.</p>
|
||||||
|
<p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (<a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives">https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives</a>)</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
### uv auth token
|
||||||
|
|
||||||
|
Show the authentication token for a service
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Usage</h3>
|
||||||
|
|
||||||
|
```
|
||||||
|
uv auth token [OPTIONS] <SERVICE>
|
||||||
|
```
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Arguments</h3>
|
||||||
|
|
||||||
|
<dl class="cli-reference"><dt id="uv-auth-token--service"><a href="#uv-auth-token--service"<code>SERVICE</code></a></dt><dd><p>The service to lookup</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<h3 class="cli-reference">Options</h3>
|
||||||
|
|
||||||
|
<dl class="cli-reference"><dt id="uv-auth-token--allow-insecure-host"><a href="#uv-auth-token--allow-insecure-host"><code>--allow-insecure-host</code></a>, <code>--trusted-host</code> <i>allow-insecure-host</i></dt><dd><p>Allow insecure connections to a host.</p>
|
||||||
|
<p>Can be provided multiple times.</p>
|
||||||
|
<p>Expects to receive either a hostname (e.g., <code>localhost</code>), a host-port pair (e.g., <code>localhost:8080</code>), or a URL (e.g., <code>https://localhost</code>).</p>
|
||||||
|
<p>WARNING: Hosts included in this list will not be verified against the system's certificate store. Only use <code>--allow-insecure-host</code> in a secure network with verified sources, as it bypasses SSL verification and could expose you to MITM attacks.</p>
|
||||||
|
<p>May also be set with the <code>UV_INSECURE_HOST</code> environment variable.</p></dd><dt id="uv-auth-token--cache-dir"><a href="#uv-auth-token--cache-dir"><code>--cache-dir</code></a> <i>cache-dir</i></dt><dd><p>Path to the cache directory.</p>
|
||||||
|
<p>Defaults to <code>$XDG_CACHE_HOME/uv</code> or <code>$HOME/.cache/uv</code> on macOS and Linux, and <code>%LOCALAPPDATA%\uv\cache</code> on Windows.</p>
|
||||||
|
<p>To view the location of the cache directory, run <code>uv cache dir</code>.</p>
|
||||||
|
<p>May also be set with the <code>UV_CACHE_DIR</code> environment variable.</p></dd><dt id="uv-auth-token--color"><a href="#uv-auth-token--color"><code>--color</code></a> <i>color-choice</i></dt><dd><p>Control the use of color in output.</p>
|
||||||
|
<p>By default, uv will automatically detect support for colors when writing to a terminal.</p>
|
||||||
|
<p>Possible values:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>auto</code>: Enables colored output only when the output is going to a terminal or TTY with support</li>
|
||||||
|
<li><code>always</code>: Enables colored output regardless of the detected environment</li>
|
||||||
|
<li><code>never</code>: Disables colored output</li>
|
||||||
|
</ul></dd><dt id="uv-auth-token--config-file"><a href="#uv-auth-token--config-file"><code>--config-file</code></a> <i>config-file</i></dt><dd><p>The path to a <code>uv.toml</code> file to use for configuration.</p>
|
||||||
|
<p>While uv configuration can be included in a <code>pyproject.toml</code> file, it is not allowed in this context.</p>
|
||||||
|
<p>May also be set with the <code>UV_CONFIG_FILE</code> environment variable.</p></dd><dt id="uv-auth-token--directory"><a href="#uv-auth-token--directory"><code>--directory</code></a> <i>directory</i></dt><dd><p>Change to the given directory prior to running the command.</p>
|
||||||
|
<p>Relative paths are resolved with the given directory as the base.</p>
|
||||||
|
<p>See <code>--project</code> to only change the project root directory.</p>
|
||||||
|
</dd><dt id="uv-auth-token--help"><a href="#uv-auth-token--help"><code>--help</code></a>, <code>-h</code></dt><dd><p>Display the concise help for this command</p>
|
||||||
|
</dd><dt id="uv-auth-token--keyring-provider"><a href="#uv-auth-token--keyring-provider"><code>--keyring-provider</code></a> <i>keyring-provider</i></dt><dd><p>The keyring provider to use for reading credentials</p>
|
||||||
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
|
</ul></dd><dt id="uv-auth-token--managed-python"><a href="#uv-auth-token--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
||||||
|
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
||||||
|
<p>May also be set with the <code>UV_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-auth-token--native-tls"><a href="#uv-auth-token--native-tls"><code>--native-tls</code></a></dt><dd><p>Whether to load TLS certificates from the platform's native certificate store.</p>
|
||||||
|
<p>By default, uv loads certificates from the bundled <code>webpki-roots</code> crate. The <code>webpki-roots</code> are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).</p>
|
||||||
|
<p>However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.</p>
|
||||||
|
<p>May also be set with the <code>UV_NATIVE_TLS</code> environment variable.</p></dd><dt id="uv-auth-token--no-cache"><a href="#uv-auth-token--no-cache"><code>--no-cache</code></a>, <code>--no-cache-dir</code>, <code>-n</code></dt><dd><p>Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_CACHE</code> environment variable.</p></dd><dt id="uv-auth-token--no-config"><a href="#uv-auth-token--no-config"><code>--no-config</code></a></dt><dd><p>Avoid discovering configuration files (<code>pyproject.toml</code>, <code>uv.toml</code>).</p>
|
||||||
|
<p>Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p></dd><dt id="uv-auth-token--no-managed-python"><a href="#uv-auth-token--no-managed-python"><code>--no-managed-python</code></a></dt><dd><p>Disable use of uv-managed Python versions.</p>
|
||||||
|
<p>Instead, uv will search for a suitable Python version on the system.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-auth-token--no-progress"><a href="#uv-auth-token--no-progress"><code>--no-progress</code></a></dt><dd><p>Hide all progress outputs.</p>
|
||||||
|
<p>For example, spinners or progress bars.</p>
|
||||||
|
<p>May also be set with the <code>UV_NO_PROGRESS</code> environment variable.</p></dd><dt id="uv-auth-token--no-python-downloads"><a href="#uv-auth-token--no-python-downloads"><code>--no-python-downloads</code></a></dt><dd><p>Disable automatic downloads of Python.</p>
|
||||||
|
</dd><dt id="uv-auth-token--offline"><a href="#uv-auth-token--offline"><code>--offline</code></a></dt><dd><p>Disable network access.</p>
|
||||||
|
<p>When disabled, uv will only use locally cached data and locally available files.</p>
|
||||||
|
<p>May also be set with the <code>UV_OFFLINE</code> environment variable.</p></dd><dt id="uv-auth-token--project"><a href="#uv-auth-token--project"><code>--project</code></a> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
|
||||||
|
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (<code>.venv</code>).</p>
|
||||||
|
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
|
||||||
|
<p>See <code>--directory</code> to change the working directory entirely.</p>
|
||||||
|
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
|
||||||
|
<p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-auth-token--quiet"><a href="#uv-auth-token--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
|
||||||
|
<p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p>
|
||||||
|
</dd><dt id="uv-auth-token--username"><a href="#uv-auth-token--username"><code>--username</code></a>, <code>-u</code> <i>username</i></dt><dd><p>The username to lookup</p>
|
||||||
|
</dd><dt id="uv-auth-token--verbose"><a href="#uv-auth-token--verbose"><code>--verbose</code></a>, <code>-v</code></dt><dd><p>Use verbose output.</p>
|
||||||
|
<p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (<a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives">https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives</a>)</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
## uv run
|
## uv run
|
||||||
|
|
||||||
Run a command or script.
|
Run a command or script.
|
||||||
|
|
@ -149,6 +382,7 @@ uv run [OPTIONS] [COMMAND]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-run--link-mode"><a href="#uv-run--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-run--link-mode"><a href="#uv-run--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -554,6 +788,7 @@ uv add [OPTIONS] <PACKAGES|--requirements <REQUIREMENTS>>
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-add--link-mode"><a href="#uv-add--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-add--link-mode"><a href="#uv-add--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -754,6 +989,7 @@ uv remove [OPTIONS] <PACKAGES>...
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-remove--link-mode"><a href="#uv-remove--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-remove--link-mode"><a href="#uv-remove--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -936,6 +1172,7 @@ uv version [OPTIONS] [VALUE]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-version--link-mode"><a href="#uv-version--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-version--link-mode"><a href="#uv-version--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -1134,6 +1371,7 @@ uv sync [OPTIONS]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-sync--link-mode"><a href="#uv-sync--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-sync--link-mode"><a href="#uv-sync--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -1379,6 +1617,7 @@ uv lock [OPTIONS]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-lock--link-mode"><a href="#uv-lock--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-lock--link-mode"><a href="#uv-lock--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>This option is only used when building source distributions.</p>
|
<p>This option is only used when building source distributions.</p>
|
||||||
|
|
@ -1558,6 +1797,7 @@ uv export [OPTIONS]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-export--link-mode"><a href="#uv-export--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-export--link-mode"><a href="#uv-export--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>This option is only used when building source distributions.</p>
|
<p>This option is only used when building source distributions.</p>
|
||||||
|
|
@ -1752,6 +1992,7 @@ uv tree [OPTIONS]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-tree--link-mode"><a href="#uv-tree--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-tree--link-mode"><a href="#uv-tree--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>This option is only used when building source distributions.</p>
|
<p>This option is only used when building source distributions.</p>
|
||||||
|
|
@ -2095,6 +2336,7 @@ uv tool run [OPTIONS] [COMMAND]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-tool-run--link-mode"><a href="#uv-tool-run--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-tool-run--link-mode"><a href="#uv-tool-run--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -2316,6 +2558,7 @@ uv tool install [OPTIONS] <PACKAGE>
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-tool-install--link-mode"><a href="#uv-tool-install--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-tool-install--link-mode"><a href="#uv-tool-install--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -2529,6 +2772,7 @@ uv tool upgrade [OPTIONS] <NAME>...
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-tool-upgrade--link-mode"><a href="#uv-tool-upgrade--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-tool-upgrade--link-mode"><a href="#uv-tool-upgrade--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -3749,6 +3993,7 @@ uv pip compile [OPTIONS] <SRC_FILE|--group <GROUP>>
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-pip-compile--link-mode"><a href="#uv-pip-compile--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-pip-compile--link-mode"><a href="#uv-pip-compile--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>This option is only used when building source distributions.</p>
|
<p>This option is only used when building source distributions.</p>
|
||||||
|
|
@ -4044,6 +4289,7 @@ uv pip sync [OPTIONS] <SRC_FILE>...
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-pip-sync--link-mode"><a href="#uv-pip-sync--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-pip-sync--link-mode"><a href="#uv-pip-sync--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -4317,6 +4563,7 @@ uv pip install [OPTIONS] <PACKAGE|--requirements <REQUIREMENTS>|--editable <EDIT
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-pip-install--link-mode"><a href="#uv-pip-install--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-pip-install--link-mode"><a href="#uv-pip-install--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
<p>Defaults to <code>clone</code> (also known as Copy-on-Write) on macOS, and <code>hardlink</code> on Linux and Windows.</p>
|
||||||
|
|
@ -4563,6 +4810,7 @@ uv pip uninstall [OPTIONS] <PACKAGE|--requirements <REQUIREMENTS>>
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-pip-uninstall--managed-python"><a href="#uv-pip-uninstall--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
</ul></dd><dt id="uv-pip-uninstall--managed-python"><a href="#uv-pip-uninstall--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
||||||
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
||||||
|
|
@ -4741,6 +4989,7 @@ uv pip list [OPTIONS]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-pip-list--managed-python"><a href="#uv-pip-list--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
</ul></dd><dt id="uv-pip-list--managed-python"><a href="#uv-pip-list--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
||||||
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
||||||
|
|
@ -4916,6 +5165,7 @@ uv pip tree [OPTIONS]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-pip-tree--managed-python"><a href="#uv-pip-tree--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
</ul></dd><dt id="uv-pip-tree--managed-python"><a href="#uv-pip-tree--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
||||||
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
||||||
|
|
@ -5157,6 +5407,7 @@ uv venv [OPTIONS] [PATH]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-venv--link-mode"><a href="#uv-venv--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-venv--link-mode"><a href="#uv-venv--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>This option is only used for installing seed packages.</p>
|
<p>This option is only used for installing seed packages.</p>
|
||||||
|
|
@ -5313,6 +5564,7 @@ uv build [OPTIONS] [SRC]
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-build--link-mode"><a href="#uv-build--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
</ul></dd><dt id="uv-build--link-mode"><a href="#uv-build--link-mode"><code>--link-mode</code></a> <i>link-mode</i></dt><dd><p>The method to use when installing packages from the global cache.</p>
|
||||||
<p>This option is only used when building source distributions.</p>
|
<p>This option is only used when building source distributions.</p>
|
||||||
|
|
@ -5465,6 +5717,7 @@ uv publish --publish-url https://upload.pypi.org/legacy/ --check-url https://pyp
|
||||||
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
<p>May also be set with the <code>UV_KEYRING_PROVIDER</code> environment variable.</p><p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
<li><code>disabled</code>: Do not use keyring for credential lookup</li>
|
||||||
|
<li><code>native</code>: Use a native integration with the system keychain for credential lookup</li>
|
||||||
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
<li><code>subprocess</code>: Use the <code>keyring</code> command for credential lookup</li>
|
||||||
</ul></dd><dt id="uv-publish--managed-python"><a href="#uv-publish--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
</ul></dd><dt id="uv-publish--managed-python"><a href="#uv-publish--managed-python"><code>--managed-python</code></a></dt><dd><p>Require use of uv-managed Python versions.</p>
|
||||||
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
<p>By default, uv prefers using Python versions it manages. However, it will use system Python versions if a uv-managed Python is not installed. This option disables use of system Python versions.</p>
|
||||||
|
|
|
||||||
|
|
@ -1144,6 +1144,11 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "disabled"
|
"const": "disabled"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Use a native integration with the system keychain for credential lookup.",
|
||||||
|
"type": "string",
|
||||||
|
"const": "native"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Use the `keyring` command for credential lookup.",
|
"description": "Use the `keyring` command for credential lookup.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue