mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-26 12:09:12 +00:00
Autogenerate possible values for enums in reference documentation (#5137)
## Summary For example:  Closes https://github.com/astral-sh/uv/issues/5129.
This commit is contained in:
parent
3e93255ac9
commit
a191f84929
8 changed files with 218 additions and 62 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -5070,6 +5070,7 @@ dependencies = [
|
||||||
name = "uv-settings"
|
name = "uv-settings"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"clap",
|
||||||
"dirs-sys",
|
"dirs-sys",
|
||||||
"distribution-types",
|
"distribution-types",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
|
@ -216,7 +216,18 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parents: &[S
|
||||||
output.push_str("\n\n");
|
output.push_str("\n\n");
|
||||||
output.push_str(&format!("**Default value**: `{}`\n", field.default));
|
output.push_str(&format!("**Default value**: `{}`\n", field.default));
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
output.push_str(&format!("**Type**: `{}`\n", field.value_type));
|
if let Some(possible_values) = field
|
||||||
|
.possible_values
|
||||||
|
.as_ref()
|
||||||
|
.filter(|values| !values.is_empty())
|
||||||
|
{
|
||||||
|
output.push_str("**Possible values**:\n\n");
|
||||||
|
for value in possible_values {
|
||||||
|
output.push_str(format!("- {value}\n").as_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output.push_str(&format!("**Type**: `{}`\n", field.value_type));
|
||||||
|
}
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
output.push_str("**Example usage**:\n\n");
|
output.push_str("**Example usage**:\n\n");
|
||||||
output.push_str(&format_tab(
|
output.push_str(&format_tab(
|
||||||
|
|
|
@ -8,7 +8,7 @@ use syn::meta::ParseNestedMeta;
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{
|
use syn::{
|
||||||
AngleBracketedGenericArguments, Attribute, Data, DataStruct, DeriveInput, ExprLit, Field,
|
AngleBracketedGenericArguments, Attribute, Data, DataStruct, DeriveInput, ExprLit, Field,
|
||||||
Fields, Lit, LitStr, Meta, Path, PathArguments, PathSegment, Type, TypePath,
|
Fields, GenericArgument, Lit, LitStr, Meta, Path, PathArguments, PathSegment, Type, TypePath,
|
||||||
};
|
};
|
||||||
use textwrap::dedent;
|
use textwrap::dedent;
|
||||||
|
|
||||||
|
@ -194,6 +194,7 @@ fn handle_option(field: &Field, attr: &Attribute) -> syn::Result<proc_macro2::To
|
||||||
value_type,
|
value_type,
|
||||||
example,
|
example,
|
||||||
scope,
|
scope,
|
||||||
|
possible_values,
|
||||||
} = parse_field_attributes(attr)?;
|
} = parse_field_attributes(attr)?;
|
||||||
let kebab_name = LitStr::new(&ident.to_string().replace('_', "-"), ident.span());
|
let kebab_name = LitStr::new(&ident.to_string().replace('_', "-"), ident.span());
|
||||||
|
|
||||||
|
@ -224,6 +225,25 @@ fn handle_option(field: &Field, attr: &Attribute) -> syn::Result<proc_macro2::To
|
||||||
quote!(None)
|
quote!(None)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let possible_values = if possible_values == Some(true) {
|
||||||
|
let inner_type = get_inner_type_if_option(&field.ty).unwrap_or(&field.ty);
|
||||||
|
let inner_type = quote!(#inner_type);
|
||||||
|
quote!(
|
||||||
|
Some(
|
||||||
|
<#inner_type as clap::ValueEnum>::value_variants()
|
||||||
|
.iter()
|
||||||
|
.filter_map(clap::ValueEnum::to_possible_value)
|
||||||
|
.map(|value| uv_options_metadata::PossibleValue {
|
||||||
|
name: value.get_name().to_string(),
|
||||||
|
help: value.get_help().map(ToString::to_string),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
quote!(None)
|
||||||
|
};
|
||||||
|
|
||||||
Ok(quote_spanned!(
|
Ok(quote_spanned!(
|
||||||
ident.span() => {
|
ident.span() => {
|
||||||
visit.record_field(#kebab_name, uv_options_metadata::OptionField{
|
visit.record_field(#kebab_name, uv_options_metadata::OptionField{
|
||||||
|
@ -232,7 +252,8 @@ fn handle_option(field: &Field, attr: &Attribute) -> syn::Result<proc_macro2::To
|
||||||
value_type: &#value_type,
|
value_type: &#value_type,
|
||||||
example: &#example,
|
example: &#example,
|
||||||
scope: #scope,
|
scope: #scope,
|
||||||
deprecated: #deprecated
|
deprecated: #deprecated,
|
||||||
|
possible_values: #possible_values,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
@ -244,6 +265,7 @@ struct FieldAttributes {
|
||||||
value_type: String,
|
value_type: String,
|
||||||
example: String,
|
example: String,
|
||||||
scope: Option<String>,
|
scope: Option<String>,
|
||||||
|
possible_values: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_field_attributes(attribute: &Attribute) -> syn::Result<FieldAttributes> {
|
fn parse_field_attributes(attribute: &Attribute) -> syn::Result<FieldAttributes> {
|
||||||
|
@ -251,6 +273,7 @@ fn parse_field_attributes(attribute: &Attribute) -> syn::Result<FieldAttributes>
|
||||||
let mut value_type = None;
|
let mut value_type = None;
|
||||||
let mut example = None;
|
let mut example = None;
|
||||||
let mut scope = None;
|
let mut scope = None;
|
||||||
|
let mut possible_values = None;
|
||||||
|
|
||||||
attribute.parse_nested_meta(|meta| {
|
attribute.parse_nested_meta(|meta| {
|
||||||
if meta.path.is_ident("default") {
|
if meta.path.is_ident("default") {
|
||||||
|
@ -262,6 +285,8 @@ fn parse_field_attributes(attribute: &Attribute) -> syn::Result<FieldAttributes>
|
||||||
} else if meta.path.is_ident("example") {
|
} else if meta.path.is_ident("example") {
|
||||||
let example_text = get_string_literal(&meta, "value_type", "option")?.value();
|
let example_text = get_string_literal(&meta, "value_type", "option")?.value();
|
||||||
example = Some(dedent(&example_text).trim_matches('\n').to_string());
|
example = Some(dedent(&example_text).trim_matches('\n').to_string());
|
||||||
|
} else if meta.path.is_ident("possible_values") {
|
||||||
|
possible_values = get_bool_literal(&meta, "possible_values", "option")?;
|
||||||
} else {
|
} else {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
meta.path.span(),
|
meta.path.span(),
|
||||||
|
@ -292,6 +317,7 @@ fn parse_field_attributes(attribute: &Attribute) -> syn::Result<FieldAttributes>
|
||||||
value_type,
|
value_type,
|
||||||
example,
|
example,
|
||||||
scope,
|
scope,
|
||||||
|
possible_values,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +344,23 @@ fn parse_deprecated_attribute(attribute: &Attribute) -> syn::Result<DeprecatedAt
|
||||||
Ok(deprecated)
|
Ok(deprecated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_inner_type_if_option(ty: &Type) -> Option<&Type> {
|
||||||
|
if let Type::Path(type_path) = ty {
|
||||||
|
if type_path.path.segments.len() == 1 && type_path.path.segments[0].ident == "Option" {
|
||||||
|
if let PathArguments::AngleBracketed(angle_bracketed_args) =
|
||||||
|
&type_path.path.segments[0].arguments
|
||||||
|
{
|
||||||
|
if angle_bracketed_args.args.len() == 1 {
|
||||||
|
if let GenericArgument::Type(inner_type) = &angle_bracketed_args.args[0] {
|
||||||
|
return Some(inner_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn get_string_literal(
|
fn get_string_literal(
|
||||||
meta: &ParseNestedMeta,
|
meta: &ParseNestedMeta,
|
||||||
meta_name: &str,
|
meta_name: &str,
|
||||||
|
@ -351,6 +394,32 @@ fn get_string_literal(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bool_literal(
|
||||||
|
meta: &ParseNestedMeta,
|
||||||
|
meta_name: &str,
|
||||||
|
attribute_name: &str,
|
||||||
|
) -> syn::Result<Option<bool>> {
|
||||||
|
let expr: syn::Expr = meta.value()?.parse()?;
|
||||||
|
|
||||||
|
let mut value = &expr;
|
||||||
|
while let syn::Expr::Group(e) = value {
|
||||||
|
value = &e.expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let syn::Expr::Lit(ExprLit {
|
||||||
|
lit: Lit::Bool(lit),
|
||||||
|
..
|
||||||
|
}) = value
|
||||||
|
{
|
||||||
|
Ok(Some(lit.value))
|
||||||
|
} else {
|
||||||
|
Err(syn::Error::new(
|
||||||
|
expr.span(),
|
||||||
|
format!("expected {attribute_name} attribute to be a boolean: `{meta_name} = true`"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct DeprecatedAttribute {
|
struct DeprecatedAttribute {
|
||||||
since: Option<String>,
|
since: Option<String>,
|
||||||
|
|
|
@ -119,6 +119,7 @@ impl OptionSet {
|
||||||
/// example: "",
|
/// example: "",
|
||||||
/// scope: None,
|
/// scope: None,
|
||||||
/// deprecated: None,
|
/// deprecated: None,
|
||||||
|
/// possible_values: None
|
||||||
/// });
|
/// });
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
@ -141,7 +142,8 @@ impl OptionSet {
|
||||||
/// value_type: "bool",
|
/// value_type: "bool",
|
||||||
/// example: "",
|
/// example: "",
|
||||||
/// scope: None,
|
/// scope: None,
|
||||||
/// deprecated: None
|
/// deprecated: None,
|
||||||
|
/// possible_values: None
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// visit.record_set("format", Nested::metadata());
|
/// visit.record_set("format", Nested::metadata());
|
||||||
|
@ -158,7 +160,8 @@ impl OptionSet {
|
||||||
/// value_type: "bool",
|
/// value_type: "bool",
|
||||||
/// example: "",
|
/// example: "",
|
||||||
/// scope: None,
|
/// scope: None,
|
||||||
/// deprecated: None
|
/// deprecated: None,
|
||||||
|
/// possible_values: None
|
||||||
/// });
|
/// });
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
@ -190,7 +193,8 @@ impl OptionSet {
|
||||||
/// value_type: "bool",
|
/// value_type: "bool",
|
||||||
/// example: "",
|
/// example: "",
|
||||||
/// scope: None,
|
/// scope: None,
|
||||||
/// deprecated: None
|
/// deprecated: None,
|
||||||
|
/// possible_values: None
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// impl OptionsMetadata for WithOptions {
|
/// impl OptionsMetadata for WithOptions {
|
||||||
|
@ -213,7 +217,8 @@ impl OptionSet {
|
||||||
/// value_type: "bool",
|
/// value_type: "bool",
|
||||||
/// example: "",
|
/// example: "",
|
||||||
/// scope: None,
|
/// scope: None,
|
||||||
/// deprecated: None
|
/// deprecated: None,
|
||||||
|
/// possible_values: None
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// struct Root;
|
/// struct Root;
|
||||||
|
@ -226,7 +231,8 @@ impl OptionSet {
|
||||||
/// value_type: "bool",
|
/// value_type: "bool",
|
||||||
/// example: "",
|
/// example: "",
|
||||||
/// scope: None,
|
/// scope: None,
|
||||||
/// deprecated: None
|
/// deprecated: None,
|
||||||
|
/// possible_values: None
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// visit.record_set("format", Nested::metadata());
|
/// visit.record_set("format", Nested::metadata());
|
||||||
|
@ -388,6 +394,7 @@ pub struct OptionField {
|
||||||
pub scope: Option<&'static str>,
|
pub scope: Option<&'static str>,
|
||||||
pub example: &'static str,
|
pub example: &'static str,
|
||||||
pub deprecated: Option<Deprecated>,
|
pub deprecated: Option<Deprecated>,
|
||||||
|
pub possible_values: Option<Vec<PossibleValue>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||||
|
@ -400,8 +407,22 @@ impl Display for OptionField {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "{}", self.doc)?;
|
writeln!(f, "{}", self.doc)?;
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
|
|
||||||
writeln!(f, "Default value: {}", self.default)?;
|
writeln!(f, "Default value: {}", self.default)?;
|
||||||
writeln!(f, "Type: {}", self.value_type)?;
|
|
||||||
|
if let Some(possible_values) = self
|
||||||
|
.possible_values
|
||||||
|
.as_ref()
|
||||||
|
.filter(|values| !values.is_empty())
|
||||||
|
{
|
||||||
|
writeln!(f, "Possible values:")?;
|
||||||
|
writeln!(f)?;
|
||||||
|
for value in possible_values {
|
||||||
|
writeln!(f, "- {value}")?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeln!(f, "Type: {}", self.value_type)?;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(deprecated) = &self.deprecated {
|
if let Some(deprecated) = &self.deprecated {
|
||||||
write!(f, "Deprecated")?;
|
write!(f, "Deprecated")?;
|
||||||
|
@ -420,3 +441,21 @@ impl Display for OptionField {
|
||||||
writeln!(f, "Example usage:\n```toml\n{}\n```", self.example)
|
writeln!(f, "Example usage:\n```toml\n{}\n```", self.example)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A possible value for an enum, similar to Clap's `PossibleValue` type (but without a dependency
|
||||||
|
/// on Clap).
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Serialize)]
|
||||||
|
pub struct PossibleValue {
|
||||||
|
pub name: String,
|
||||||
|
pub help: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PossibleValue {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "`\"{}\"`", self.name)?;
|
||||||
|
if let Some(help) = &self.help {
|
||||||
|
write!(f, ": {help}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,18 +14,19 @@ workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
distribution-types = { workspace = true, features = ["schemars"] }
|
distribution-types = { workspace = true, features = ["schemars"] }
|
||||||
install-wheel-rs = { workspace = true, features = ["schemars"] }
|
install-wheel-rs = { workspace = true, features = ["schemars", "clap"] }
|
||||||
pep508_rs = { workspace = true }
|
pep508_rs = { workspace = true }
|
||||||
pypi-types = { workspace = true }
|
pypi-types = { workspace = true }
|
||||||
uv-configuration = { workspace = true, features = ["schemars"] }
|
uv-configuration = { workspace = true, features = ["schemars", "clap"] }
|
||||||
uv-fs = { workspace = true }
|
uv-fs = { workspace = true }
|
||||||
uv-macros = { workspace = true }
|
uv-macros = { workspace = true }
|
||||||
uv-normalize = { workspace = true, features = ["schemars"] }
|
uv-normalize = { workspace = true, features = ["schemars"] }
|
||||||
uv-options-metadata = { workspace = true }
|
uv-options-metadata = { workspace = true }
|
||||||
uv-python = { workspace = true, features = ["schemars"] }
|
uv-python = { workspace = true, features = ["schemars", "clap"] }
|
||||||
uv-resolver = { workspace = true, features = ["schemars"] }
|
uv-resolver = { workspace = true, features = ["schemars", "clap"] }
|
||||||
uv-warnings = { workspace = true }
|
uv-warnings = { workspace = true }
|
||||||
|
|
||||||
|
clap = { workspace = true }
|
||||||
dirs-sys = { workspace = true }
|
dirs-sys = { workspace = true }
|
||||||
fs-err = { workspace = true }
|
fs-err = { workspace = true }
|
||||||
schemars = { workspace = true, optional = true }
|
schemars = { workspace = true, optional = true }
|
||||||
|
@ -35,4 +36,4 @@ toml = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.cargo-shear]
|
[package.metadata.cargo-shear]
|
||||||
ignored = ["uv-options-metadata"]
|
ignored = ["uv-options-metadata", "clap"]
|
||||||
|
|
|
@ -120,7 +120,8 @@ pub struct GlobalOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
python-preference = "managed"
|
python-preference = "managed"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub python_preference: Option<PythonPreference>,
|
pub python_preference: Option<PythonPreference>,
|
||||||
/// Whether to automatically download Python when required.
|
/// Whether to automatically download Python when required.
|
||||||
|
@ -129,7 +130,8 @@ pub struct GlobalOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
python-fetch = \"automatic\"
|
python-fetch = \"automatic\"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub python_fetch: Option<PythonFetch>,
|
pub python_fetch: Option<PythonFetch>,
|
||||||
}
|
}
|
||||||
|
@ -255,18 +257,13 @@ pub struct ResolverInstallerOptions {
|
||||||
/// limit resolutions to those present on that first index (`first-match`). This prevents
|
/// limit resolutions to those present on that first index (`first-match`). This prevents
|
||||||
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||||
/// same name to a secondary.
|
/// same name to a secondary.
|
||||||
///
|
|
||||||
/// Possible values:
|
|
||||||
///
|
|
||||||
/// - `"first-index"`: Only use results from the first index that returns a match for a given package name.
|
|
||||||
/// - `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next.
|
|
||||||
/// - `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index.
|
|
||||||
#[option(
|
#[option(
|
||||||
default = "\"first-index\"",
|
default = "\"first-index\"",
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
index-strategy = "unsafe-best-match"
|
index-strategy = "unsafe-best-match"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub index_strategy: Option<IndexStrategy>,
|
pub index_strategy: Option<IndexStrategy>,
|
||||||
/// Attempt to use `keyring` for authentication for index URLs.
|
/// Attempt to use `keyring` for authentication for index URLs.
|
||||||
|
@ -290,7 +287,8 @@ pub struct ResolverInstallerOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
resolution = "lowest-direct"
|
resolution = "lowest-direct"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub resolution: Option<ResolutionMode>,
|
pub resolution: Option<ResolutionMode>,
|
||||||
/// The strategy to use when considering pre-release versions.
|
/// The strategy to use when considering pre-release versions.
|
||||||
|
@ -303,7 +301,8 @@ pub struct ResolverInstallerOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
prerelease = "allow"
|
prerelease = "allow"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub prerelease: Option<PreReleaseMode>,
|
pub prerelease: Option<PreReleaseMode>,
|
||||||
/// Settings to pass to the PEP 517 build backend, specified as `KEY=VALUE` pairs.
|
/// Settings to pass to the PEP 517 build backend, specified as `KEY=VALUE` pairs.
|
||||||
|
@ -336,7 +335,8 @@ pub struct ResolverInstallerOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
link-mode = "copy"
|
link-mode = "copy"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub link_mode: Option<LinkMode>,
|
pub link_mode: Option<LinkMode>,
|
||||||
/// Compile Python files to bytecode after installation.
|
/// Compile Python files to bytecode after installation.
|
||||||
|
@ -590,18 +590,13 @@ pub struct PipOptions {
|
||||||
/// limit resolutions to those present on that first index (`first-match`). This prevents
|
/// limit resolutions to those present on that first index (`first-match`). This prevents
|
||||||
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
/// "dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||||
/// same name to a secondary.
|
/// same name to a secondary.
|
||||||
///
|
|
||||||
/// Possible values:
|
|
||||||
///
|
|
||||||
/// - `"first-index"`: Only use results from the first index that returns a match for a given package name.
|
|
||||||
/// - `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next.
|
|
||||||
/// - `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index.
|
|
||||||
#[option(
|
#[option(
|
||||||
default = "\"first-index\"",
|
default = "\"first-index\"",
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
index-strategy = "unsafe-best-match"
|
index-strategy = "unsafe-best-match"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub index_strategy: Option<IndexStrategy>,
|
pub index_strategy: Option<IndexStrategy>,
|
||||||
/// Attempt to use `keyring` for authentication for index URLs.
|
/// Attempt to use `keyring` for authentication for index URLs.
|
||||||
|
@ -734,7 +729,8 @@ pub struct PipOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
resolution = "lowest-direct"
|
resolution = "lowest-direct"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub resolution: Option<ResolutionMode>,
|
pub resolution: Option<ResolutionMode>,
|
||||||
/// The strategy to use when considering pre-release versions.
|
/// The strategy to use when considering pre-release versions.
|
||||||
|
@ -747,7 +743,8 @@ pub struct PipOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
prerelease = "allow"
|
prerelease = "allow"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub prerelease: Option<PreReleaseMode>,
|
pub prerelease: Option<PreReleaseMode>,
|
||||||
/// Write the requirements generated by `uv pip compile` to the given `requirements.txt` file.
|
/// Write the requirements generated by `uv pip compile` to the given `requirements.txt` file.
|
||||||
|
@ -966,7 +963,8 @@ pub struct PipOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
annotation-style = "line"
|
annotation-style = "line"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub annotation_style: Option<AnnotationStyle>,
|
pub annotation_style: Option<AnnotationStyle>,
|
||||||
/// The method to use when installing packages from the global cache.
|
/// The method to use when installing packages from the global cache.
|
||||||
|
@ -978,7 +976,8 @@ pub struct PipOptions {
|
||||||
value_type = "str",
|
value_type = "str",
|
||||||
example = r#"
|
example = r#"
|
||||||
link-mode = "copy"
|
link-mode = "copy"
|
||||||
"#
|
"#,
|
||||||
|
possible_values = true
|
||||||
)]
|
)]
|
||||||
pub link_mode: Option<LinkMode>,
|
pub link_mode: Option<LinkMode>,
|
||||||
/// Compile Python files to bytecode after installation.
|
/// Compile Python files to bytecode after installation.
|
||||||
|
|
|
@ -189,15 +189,13 @@ limit resolutions to those present on that first index (`first-match`). This pre
|
||||||
"dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
"dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||||
same name to a secondary.
|
same name to a secondary.
|
||||||
|
|
||||||
Possible values:
|
|
||||||
|
|
||||||
- `"first-index"`: Only use results from the first index that returns a match for a given package name.
|
|
||||||
- `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next.
|
|
||||||
- `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index.
|
|
||||||
|
|
||||||
**Default value**: `"first-index"`
|
**Default value**: `"first-index"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"first-index"`: Only use results from the first index that returns a match for a given package name
|
||||||
|
- `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next
|
||||||
|
- `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -284,7 +282,11 @@ Windows.
|
||||||
|
|
||||||
**Default value**: `"clone" (macOS) or "hardlink" (Linux, Windows)`
|
**Default value**: `"clone" (macOS) or "hardlink" (Linux, Windows)`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"clone"`: Clone (i.e., copy-on-write) packages from the wheel into the site packages
|
||||||
|
- `"copy"`: Copy packages from the wheel into the site packages
|
||||||
|
- `"hardlink"`: Hard link packages from the wheel into the site packages
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -556,7 +558,13 @@ declared specifiers (`if-necessary-or-explicit`).
|
||||||
|
|
||||||
**Default value**: `"if-necessary-or-explicit"`
|
**Default value**: `"if-necessary-or-explicit"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"disallow"`: Disallow all pre-release versions
|
||||||
|
- `"allow"`: Allow all pre-release versions
|
||||||
|
- `"if-necessary"`: Allow pre-release versions if all versions of a package are pre-release
|
||||||
|
- `"explicit"`: Allow pre-release versions for first-party packages with explicit pre-release markers in their version requirements
|
||||||
|
- `"if-necessary-or-explicit"`: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -606,7 +614,10 @@ Whether to automatically download Python when required.
|
||||||
|
|
||||||
**Default value**: `"automatic"`
|
**Default value**: `"automatic"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"automatic"`: Automatically fetch managed Python installations when needed
|
||||||
|
- `"manual"`: Do not automatically fetch managed Python installations; require explicit installation
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -632,7 +643,13 @@ those that are downloaded and installed by uv.
|
||||||
|
|
||||||
**Default value**: `"installed"`
|
**Default value**: `"installed"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"only-managed"`: Only use managed Python installations; never use system Python installations
|
||||||
|
- `"installed"`: Prefer installed Python installations, only download managed Python installations if no system Python installation is found
|
||||||
|
- `"managed"`: Prefer managed Python installations over system Python installations, even if fetching is required
|
||||||
|
- `"system"`: Prefer system Python installations over managed Python installations
|
||||||
|
- `"only-system"`: Only use system Python installations; never use managed Python installations
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -710,7 +727,11 @@ By default, uv will use the latest compatible version of each package (`highest`
|
||||||
|
|
||||||
**Default value**: `"highest"`
|
**Default value**: `"highest"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"highest"`: Resolve the highest compatible version of each package
|
||||||
|
- `"lowest"`: Resolve the lowest compatible version of each package
|
||||||
|
- `"lowest-direct"`: Resolve the lowest compatible version of any direct dependencies, and the highest compatible version of any transitive dependencies
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -852,7 +873,10 @@ source of each package.
|
||||||
|
|
||||||
**Default value**: `"split"`
|
**Default value**: `"split"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"line"`: Render the annotations on a single, comma-separated line
|
||||||
|
- `"split"`: Render each annotation on its own line
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -1372,15 +1396,13 @@ limit resolutions to those present on that first index (`first-match`). This pre
|
||||||
"dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
"dependency confusion" attacks, whereby an attack can upload a malicious package under the
|
||||||
same name to a secondary.
|
same name to a secondary.
|
||||||
|
|
||||||
Possible values:
|
|
||||||
|
|
||||||
- `"first-index"`: Only use results from the first index that returns a match for a given package name.
|
|
||||||
- `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next.
|
|
||||||
- `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index.
|
|
||||||
|
|
||||||
**Default value**: `"first-index"`
|
**Default value**: `"first-index"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"first-index"`: Only use results from the first index that returns a match for a given package name
|
||||||
|
- `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next
|
||||||
|
- `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -1497,7 +1519,11 @@ Windows.
|
||||||
|
|
||||||
**Default value**: `"clone" (macOS) or "hardlink" (Linux, Windows)`
|
**Default value**: `"clone" (macOS) or "hardlink" (Linux, Windows)`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"clone"`: Clone (i.e., copy-on-write) packages from the wheel into the site packages
|
||||||
|
- `"copy"`: Copy packages from the wheel into the site packages
|
||||||
|
- `"hardlink"`: Hard link packages from the wheel into the site packages
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -1906,7 +1932,13 @@ declared specifiers (`if-necessary-or-explicit`).
|
||||||
|
|
||||||
**Default value**: `"if-necessary-or-explicit"`
|
**Default value**: `"if-necessary-or-explicit"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"disallow"`: Disallow all pre-release versions
|
||||||
|
- `"allow"`: Allow all pre-release versions
|
||||||
|
- `"if-necessary"`: Allow pre-release versions if all versions of a package are pre-release
|
||||||
|
- `"explicit"`: Allow pre-release versions for first-party packages with explicit pre-release markers in their version requirements
|
||||||
|
- `"if-necessary-or-explicit"`: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
@ -2121,7 +2153,11 @@ By default, uv will use the latest compatible version of each package (`highest`
|
||||||
|
|
||||||
**Default value**: `"highest"`
|
**Default value**: `"highest"`
|
||||||
|
|
||||||
**Type**: `str`
|
**Possible values**:
|
||||||
|
|
||||||
|
- `"highest"`: Resolve the highest compatible version of each package
|
||||||
|
- `"lowest"`: Resolve the lowest compatible version of each package
|
||||||
|
- `"lowest-direct"`: Resolve the lowest compatible version of any direct dependencies, and the highest compatible version of any transitive dependencies
|
||||||
|
|
||||||
**Example usage**:
|
**Example usage**:
|
||||||
|
|
||||||
|
|
4
uv.schema.json
generated
4
uv.schema.json
generated
|
@ -71,7 +71,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"index-strategy": {
|
"index-strategy": {
|
||||||
"description": "The strategy to use when resolving against multiple index URLs.\n\nBy default, uv will stop at the first index on which a given package is available, and limit resolutions to those present on that first index (`first-match`). This prevents \"dependency confusion\" attacks, whereby an attack can upload a malicious package under the same name to a secondary.\n\nPossible values:\n\n- `\"first-index\"`: Only use results from the first index that returns a match for a given package name. - `\"unsafe-first-match\"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next. - `\"unsafe-best-match\"`: Search for every package name across all indexes, preferring the \"best\" version found. If a package version is in multiple indexes, only look at the entry for the first index.",
|
"description": "The strategy to use when resolving against multiple index URLs.\n\nBy default, uv will stop at the first index on which a given package is available, and limit resolutions to those present on that first index (`first-match`). This prevents \"dependency confusion\" attacks, whereby an attack can upload a malicious package under the same name to a secondary.",
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/IndexStrategy"
|
"$ref": "#/definitions/IndexStrategy"
|
||||||
|
@ -638,7 +638,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"index-strategy": {
|
"index-strategy": {
|
||||||
"description": "The strategy to use when resolving against multiple index URLs.\n\nBy default, uv will stop at the first index on which a given package is available, and limit resolutions to those present on that first index (`first-match`). This prevents \"dependency confusion\" attacks, whereby an attack can upload a malicious package under the same name to a secondary.\n\nPossible values:\n\n- `\"first-index\"`: Only use results from the first index that returns a match for a given package name. - `\"unsafe-first-match\"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next. - `\"unsafe-best-match\"`: Search for every package name across all indexes, preferring the \"best\" version found. If a package version is in multiple indexes, only look at the entry for the first index.",
|
"description": "The strategy to use when resolving against multiple index URLs.\n\nBy default, uv will stop at the first index on which a given package is available, and limit resolutions to those present on that first index (`first-match`). This prevents \"dependency confusion\" attacks, whereby an attack can upload a malicious package under the same name to a secondary.",
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/IndexStrategy"
|
"$ref": "#/definitions/IndexStrategy"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue