diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 4ca459031cdf..acc80adb29f9 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -2314,6 +2314,17 @@ impl ExternalCommand { } } +#[derive(Debug, Default, Copy, Clone, clap::ValueEnum)] +pub enum AuthorFrom { + /// Fetch the author information from some sources (e.g., Git) automatically. + #[default] + Auto, + /// Fetch the author information from Git configuration only. + Git, + /// Do not infer the author information. + None, +} + #[derive(Args)] #[allow(clippy::struct_excessive_bools)] pub struct InitArgs { @@ -2400,13 +2411,13 @@ pub struct InitArgs { #[arg(long)] pub no_readme: bool, - /// Do not fill in the `authors` field in the `pyproject.toml`. - #[arg(long)] - pub no_authors: bool, - /// Fill in the `authors` field in the `pyproject.toml`. - #[arg(long, overrides_with = "no_authors", hide = true)] - pub authors: bool, + /// + /// By default, uv will attempt to infer the author information from some sources (e.g., Git) (`auto`). + /// Use `--author-from git` to only infer from Git configuration. + /// Use `--author-from none` to avoid inferring the author information. + #[arg(long, value_enum)] + pub author_from: Option, /// Do not create a `.python-version` file for the project. /// diff --git a/crates/uv/src/commands/project/init.rs b/crates/uv/src/commands/project/init.rs index 96e4afb4bb42..ef22f246972f 100644 --- a/crates/uv/src/commands/project/init.rs +++ b/crates/uv/src/commands/project/init.rs @@ -7,6 +7,7 @@ use owo_colors::OwoColorize; use tracing::{debug, warn}; use uv_cache::Cache; +use uv_cli::AuthorFrom; use uv_client::{BaseClientBuilder, Connectivity}; use uv_configuration::{VersionControlError, VersionControlSystem}; use uv_fs::{Simplified, CWD}; @@ -37,7 +38,7 @@ pub(crate) async fn init( init_kind: InitKind, vcs: Option, no_readme: bool, - with_authors: Option, + author_from: Option, no_pin_python: bool, python: Option, no_workspace: bool, @@ -64,7 +65,7 @@ pub(crate) async fn init( printer, no_workspace, no_readme, - with_authors, + author_from, no_pin_python, package, native_tls, @@ -114,7 +115,7 @@ pub(crate) async fn init( project_kind, vcs, no_readme, - with_authors, + author_from, no_pin_python, python, no_workspace, @@ -169,7 +170,7 @@ async fn init_script( printer: Printer, no_workspace: bool, no_readme: bool, - with_authors: Option, + author_from: Option, no_pin_python: bool, package: bool, native_tls: bool, @@ -180,8 +181,8 @@ async fn init_script( if no_readme { warn_user_once!("`--no_readme` is a no-op for Python scripts, which are standalone"); } - if with_authors.is_some() { - warn_user_once!("`--no_authors` is a no-op for Python scripts, which are standalone"); + if author_from.is_some() { + warn_user_once!("`--author-from` is a no-op for Python scripts, which are standalone"); } if package { warn_user_once!("`--package` is a no-op for Python scripts, which are standalone"); @@ -245,7 +246,7 @@ async fn init_project( project_kind: InitProjectKind, vcs: Option, no_readme: bool, - with_authors: Option, + author_from: Option, no_pin_python: bool, python: Option, no_workspace: bool, @@ -484,7 +485,7 @@ async fn init_project( &requires_python, python_request.as_ref(), vcs, - with_authors, + author_from, no_readme, package, ) @@ -574,7 +575,7 @@ impl InitProjectKind { requires_python: &RequiresPython, python_request: Option<&PythonRequest>, vcs: Option, - with_authors: Option, + author_from: Option, no_readme: bool, package: bool, ) -> Result<()> { @@ -586,7 +587,7 @@ impl InitProjectKind { requires_python, python_request, vcs, - with_authors, + author_from, no_readme, package, ) @@ -599,7 +600,7 @@ impl InitProjectKind { requires_python, python_request, vcs, - with_authors, + author_from, no_readme, package, ) @@ -616,18 +617,21 @@ impl InitProjectKind { requires_python: &RequiresPython, python_request: Option<&PythonRequest>, vcs: Option, - with_authors: Option, + author_from: Option, no_readme: bool, package: bool, ) -> Result<()> { fs_err::create_dir_all(path)?; // Do no fill in `authors` for non-packaged applications unless explicitly requested. - let author = if with_authors.unwrap_or(package) { - get_author_info(path) - } else { - None - }; + let author_from = author_from.unwrap_or_else(|| { + if package { + AuthorFrom::default() + } else { + AuthorFrom::None + } + }); + let author = get_author_info(path, author_from); // Create the `pyproject.toml` let mut pyproject = pyproject_project(name, requires_python, author.as_ref(), no_readme); @@ -705,7 +709,7 @@ impl InitProjectKind { requires_python: &RequiresPython, python_request: Option<&PythonRequest>, vcs: Option, - with_authors: Option, + author_from: Option, no_readme: bool, package: bool, ) -> Result<()> { @@ -715,11 +719,7 @@ impl InitProjectKind { fs_err::create_dir_all(path)?; - let author = if with_authors.unwrap_or(true) { - get_author_info(path) - } else { - None - }; + let author = get_author_info(path, author_from.unwrap_or_default()); // Create the `pyproject.toml` let mut pyproject = pyproject_project(name, requires_python, author.as_ref(), no_readme); @@ -880,10 +880,15 @@ fn init_vcs(path: &Path, vcs: Option) -> Result<()> { /// Try to get the author information. /// /// Currently, this only tries to get the author information from git. -fn get_author_info(path: &Path) -> Option { - match get_author_from_git(path) { - Ok(author) => return Some(author), - Err(err) => warn!("Failed to get author from git: {err}"), +fn get_author_info(path: &Path, author_from: AuthorFrom) -> Option { + if matches!(author_from, AuthorFrom::None) { + return None; + } + if matches!(author_from, AuthorFrom::Auto | AuthorFrom::Git) { + match get_author_from_git(path) { + Ok(author) => return Some(author), + Err(err) => warn!("Failed to get author from git: {err}"), + } } None diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index daef9bb199db..ac6b219a17a4 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1195,7 +1195,7 @@ async fn run_project( args.kind, args.vcs, args.no_readme, - args.with_authors, + args.author_from, args.no_pin_python, args.python, args.no_workspace, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index be9cac7980ad..9639c72ed470 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -8,7 +8,7 @@ use url::Url; use uv_cache::{CacheArgs, Refresh}; use uv_cli::{ options::{flag, resolver_installer_options, resolver_options}, - BuildArgs, ExportArgs, PublishArgs, ToolUpgradeArgs, + AuthorFrom, BuildArgs, ExportArgs, PublishArgs, ToolUpgradeArgs, }; use uv_cli::{ AddArgs, ColorChoice, ExternalCommand, GlobalArgs, InitArgs, ListFormat, LockArgs, Maybe, @@ -164,7 +164,7 @@ pub(crate) struct InitSettings { pub(crate) kind: InitKind, pub(crate) vcs: Option, pub(crate) no_readme: bool, - pub(crate) with_authors: Option, + pub(crate) author_from: Option, pub(crate) no_pin_python: bool, pub(crate) no_workspace: bool, pub(crate) python: Option, @@ -185,8 +185,7 @@ impl InitSettings { script, vcs, no_readme, - no_authors, - authors, + author_from, no_pin_python, no_workspace, python, @@ -209,7 +208,7 @@ impl InitSettings { kind, vcs, no_readme, - with_authors: flag(authors, no_authors), + author_from, no_pin_python, no_workspace, python, diff --git a/crates/uv/tests/init.rs b/crates/uv/tests/init.rs index 69f3eead794d..8ec8d3d22ca3 100644 --- a/crates/uv/tests/init.rs +++ b/crates/uv/tests/init.rs @@ -2254,7 +2254,7 @@ fn init_git_not_installed() { } #[test] -fn init_with_author() -> Result<()> { +fn init_with_author() { let context = TestContext::new("3.12"); // Create a Git repository and set the author. @@ -2282,7 +2282,7 @@ fn init_with_author() -> Result<()> { // `authors` is not filled for non-package application by default, context.init().arg("foo").assert().success(); - let pyproject = fs_err::read_to_string(context.temp_dir.join("foo/pyproject.toml"))?; + let pyproject = context.read("foo/pyproject.toml"); insta::with_settings!({ filters => context.filters(), }, { @@ -2299,14 +2299,15 @@ fn init_with_author() -> Result<()> { ); }); - // use `--authors` to explicitly fill it. + // use `--author-from auto` to explicitly fill it. context .init() .arg("bar") - .arg("--authors") + .arg("--author-from") + .arg("auto") .assert() .success(); - let pyproject = fs_err::read_to_string(context.temp_dir.join("bar/pyproject.toml"))?; + let pyproject = context.read("bar/pyproject.toml"); insta::with_settings!({ filters => context.filters(), }, { @@ -2328,7 +2329,7 @@ fn init_with_author() -> Result<()> { // Fill `authors` for library by default, context.init().arg("baz").arg("--lib").assert().success(); - let pyproject = fs_err::read_to_string(context.temp_dir.join("baz/pyproject.toml"))?; + let pyproject = context.read("baz/pyproject.toml"); insta::with_settings!({ filters => context.filters(), }, { @@ -2352,15 +2353,16 @@ fn init_with_author() -> Result<()> { ); }); - // use `--no-authors` to prevent it. + // use `--authors-from none` to prevent it. context .init() .arg("qux") .arg("--lib") - .arg("--no-authors") + .arg("--author-from") + .arg("none") .assert() .success(); - let pyproject = fs_err::read_to_string(context.temp_dir.join("qux/pyproject.toml"))?; + let pyproject = context.read("qux/pyproject.toml"); insta::with_settings!({ filters => context.filters(), }, { @@ -2380,6 +2382,4 @@ fn init_with_author() -> Result<()> { "# ); }); - - Ok(()) } diff --git a/docs/reference/cli.md b/docs/reference/cli.md index e164f53d061b..cee9f195fded 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -439,6 +439,19 @@ uv init [OPTIONS] [PATH]

By default, an application is not intended to be built and distributed as a Python package. The --package option can be used to create an application that is distributable, e.g., if you want to distribute a command-line interface via PyPI.

+
--author-from author-from

Fill in the authors field in the pyproject.toml.

+ +

By default, uv will attempt to infer the author information from some sources (e.g., Git) (auto). Use --author-from git to only infer from Git configuration. Use --author-from none to avoid inferring the author information.

+ +

Possible values:

+ +
    +
  • auto: Fetch the author information from some sources (e.g., Git) automatically
  • + +
  • git: Fetch the author information from Git configuration only
  • + +
  • none: Do not infer the author information
  • +
--cache-dir cache-dir

Path to the cache directory.

Defaults to $HOME/Library/Caches/uv on macOS, $XDG_CACHE_HOME/uv or $HOME/.cache/uv on Linux, and %LOCALAPPDATA%\uv\cache on Windows.

@@ -484,8 +497,6 @@ uv init [OPTIONS] [PATH]

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.

May also be set with the UV_NATIVE_TLS environment variable.

-
--no-authors

Do not fill in the authors field in the pyproject.toml

-
--no-cache, -n

Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation

May also be set with the UV_NO_CACHE environment variable.