Warn when unused pyproject.toml configuration is detected (#5025)

## Summary

Closes https://github.com/astral-sh/uv/issues/5022.
This commit is contained in:
Charlie Marsh 2024-07-12 17:50:04 -04:00 committed by GitHub
parent 6a6168ec78
commit 5f851d1d19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 188 additions and 6 deletions

View file

@ -92,6 +92,20 @@ impl FilesystemOptions {
let options: Options = toml::from_str(&content)
.map_err(|err| Error::UvToml(path.user_display().to_string(), err))?;
// If the directory also contains a `[tool.uv]` table in a `pyproject.toml` file,
// warn.
let pyproject = dir.as_ref().join("pyproject.toml");
if let Some(pyproject) = fs_err::read_to_string(pyproject)
.ok()
.and_then(|content| toml::from_str::<PyProjectToml>(&content).ok())
{
if pyproject.tool.is_some_and(|tool| tool.uv.is_some()) {
warn_user!(
"Found both a `uv.toml` file and a `[tool.uv]` section in an adjacent `pyproject.toml`. The `[tool.uv]` section will be ignored in favor of the `uv.toml` file."
);
}
}
debug!("Found workspace configuration at `{}`", path.display());
return Ok(Some(Self(options)));
}

View file

@ -58,7 +58,7 @@ pub(crate) mod version;
#[instrument(skip_all)]
async fn run(cli: Cli) -> Result<ExitStatus> {
// enable flag to pick up warnings generated by workspace loading.
// Enable flag to pick up warnings generated by workspace loading.
if !cli.global_args.quiet {
uv_warnings::enable();
}
@ -72,16 +72,16 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
// found, this file is combined with the user configuration file. In this case, we don't
// search for `pyproject.toml` files, since we're not in a workspace.
let filesystem = if let Some(config_file) = cli.config_file.as_ref() {
Some(uv_settings::FilesystemOptions::from_file(config_file)?)
Some(FilesystemOptions::from_file(config_file)?)
} else if cli.global_args.isolated {
None
} else if let Ok(project) = Workspace::discover(&env::current_dir()?, None).await {
let project = uv_settings::FilesystemOptions::from_directory(project.install_path())?;
let user = uv_settings::FilesystemOptions::user()?;
let project = FilesystemOptions::from_directory(project.install_path())?;
let user = FilesystemOptions::user()?;
project.combine(user)
} else {
let project = uv_settings::FilesystemOptions::find(env::current_dir()?)?;
let user = uv_settings::FilesystemOptions::user()?;
let project = FilesystemOptions::find(env::current_dir()?)?;
let user = FilesystemOptions::user()?;
project.combine(user)
};

View file

@ -2458,3 +2458,171 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
Ok(())
}
/// Read from both a `uv.toml` and `pyproject.toml` file in the current directory.
#[test]
#[cfg_attr(
windows,
ignore = "Configuration tests are not yet supported on Windows"
)]
fn resolve_both() -> anyhow::Result<()> {
let context = TestContext::new("3.12");
// Write a `uv.toml` file to the directory.
let config = context.temp_dir.child("uv.toml");
config.write_str(indoc::indoc! {r#"
[pip]
resolution = "lowest-direct"
generate-hashes = true
index-url = "https://pypi.org/simple"
"#})?;
// Write a `pyproject.toml` file to the directory
let config = context.temp_dir.child("pyproject.toml");
config.write_str(indoc::indoc! {r#"
[project]
name = "example"
version = "0.0.0"
[tool.uv.pip]
resolution = "highest"
extra-index-url = ["https://test.pypi.org/simple"]
"#})?;
let requirements_in = context.temp_dir.child("requirements.in");
requirements_in.write_str("anyio>3.0.0")?;
// Resolution should succeed, but warn that the `pip` section in `pyproject.toml` is ignored.
uv_snapshot!(context.filters(), command(&context)
.arg("--show-settings")
.arg("requirements.in"), @r###"
success: true
exit_code: 0
----- stdout -----
GlobalSettings {
quiet: false,
verbose: 0,
color: Auto,
native_tls: false,
connectivity: Online,
isolated: false,
show_settings: true,
preview: Disabled,
python_preference: OnlySystem,
python_fetch: Automatic,
}
CacheSettings {
no_cache: false,
cache_dir: Some(
"[CACHE_DIR]/",
),
}
PipCompileSettings {
src_file: [
"requirements.in",
],
constraint: [],
override: [],
overrides_from_workspace: [],
refresh: None(
Timestamp(
SystemTime {
tv_sec: [TIME],
tv_nsec: [TIME],
},
),
),
settings: PipSettings {
index_locations: IndexLocations {
index: Some(
Pypi(
VerbatimUrl {
url: Url {
scheme: "https",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"pypi.org",
),
),
port: None,
path: "/simple",
query: None,
fragment: None,
},
given: Some(
"https://pypi.org/simple",
),
},
),
),
extra_index: [],
flat_index: [],
no_index: false,
},
python: None,
system: false,
extras: None,
break_system_packages: false,
target: None,
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
},
allow_empty_requirements: false,
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
prerelease: IfNecessaryOrExplicit,
output_file: None,
no_strip_extras: false,
no_strip_markers: false,
no_annotate: false,
no_header: false,
custom_compile_command: None,
generate_hashes: true,
setup_py: Pep517,
config_setting: ConfigSettings(
{},
),
python_version: None,
python_platform: None,
universal: false,
exclude_newer: Some(
ExcludeNewer(
2024-03-25T00:00:00Z,
),
),
no_emit_package: [],
emit_index_url: false,
emit_find_links: false,
emit_build_options: false,
emit_marker_expression: false,
emit_index_annotation: false,
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
require_hashes: false,
upgrade: None,
reinstall: None,
concurrency: Concurrency {
downloads: 50,
builds: 16,
installs: 8,
},
},
}
----- stderr -----
warning: Found both a `uv.toml` file and a `[tool.uv]` section in an adjacent `pyproject.toml`. The `[tool.uv]` section will be ignored in favor of the `uv.toml` file.
"###
);
Ok(())
}