@@ -120,10 +120,9 @@ impl FilesystemOptions {
120120 . ok ( )
121121 . and_then ( |content| toml:: from_str :: < PyProjectToml > ( & content) . ok ( ) )
122122 {
123- if pyproject. tool . is_some_and ( |tool| tool. uv . is_some ( ) ) {
124- warn_user ! (
125- "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."
126- ) ;
123+ if let Some ( options) = pyproject. tool . as_ref ( ) . and_then ( |tool| tool. uv . as_ref ( ) )
124+ {
125+ warn_uv_toml_masked_fields ( options) ;
127126 }
128127 }
129128
@@ -269,6 +268,253 @@ fn validate_uv_toml(path: &Path, options: &Options) -> Result<(), Error> {
269268 Ok ( ( ) )
270269}
271270
271+ /// Validate that an [`Options`] contains no fields that `uv.toml` would mask
272+ ///
273+ /// This is essentially the inverse of [`validated_uv_toml`][].
274+ fn warn_uv_toml_masked_fields ( options : & Options ) {
275+ let Options {
276+ globals :
277+ GlobalOptions {
278+ required_version,
279+ native_tls,
280+ offline,
281+ no_cache,
282+ cache_dir,
283+ preview,
284+ python_preference,
285+ python_downloads,
286+ concurrent_downloads,
287+ concurrent_builds,
288+ concurrent_installs,
289+ allow_insecure_host,
290+ } ,
291+ top_level :
292+ ResolverInstallerOptions {
293+ index,
294+ index_url,
295+ extra_index_url,
296+ no_index,
297+ find_links,
298+ index_strategy,
299+ keyring_provider,
300+ resolution,
301+ prerelease,
302+ fork_strategy,
303+ dependency_metadata,
304+ config_settings,
305+ no_build_isolation,
306+ no_build_isolation_package,
307+ exclude_newer,
308+ link_mode,
309+ compile_bytecode,
310+ no_sources,
311+ upgrade,
312+ upgrade_package,
313+ reinstall,
314+ reinstall_package,
315+ no_build,
316+ no_build_package,
317+ no_binary,
318+ no_binary_package,
319+ } ,
320+ install_mirrors :
321+ PythonInstallMirrors {
322+ python_install_mirror,
323+ pypy_install_mirror,
324+ python_downloads_json_url,
325+ } ,
326+ publish :
327+ PublishOptions {
328+ publish_url,
329+ trusted_publishing,
330+ check_url,
331+ } ,
332+ add : AddOptions { add_bounds } ,
333+ pip,
334+ cache_keys,
335+ override_dependencies,
336+ constraint_dependencies,
337+ build_constraint_dependencies,
338+ environments,
339+ required_environments,
340+ conflicts : _,
341+ workspace : _,
342+ sources : _,
343+ dev_dependencies : _,
344+ default_groups : _,
345+ dependency_groups : _,
346+ managed : _,
347+ package : _,
348+ build_backend : _,
349+ } = options;
350+
351+ let mut masked_fields = vec ! [ ] ;
352+
353+ if required_version. is_some ( ) {
354+ masked_fields. push ( "required-version" ) ;
355+ }
356+ if native_tls. is_some ( ) {
357+ masked_fields. push ( "native-tls" ) ;
358+ }
359+ if offline. is_some ( ) {
360+ masked_fields. push ( "offline" ) ;
361+ }
362+ if no_cache. is_some ( ) {
363+ masked_fields. push ( "no-cache" ) ;
364+ }
365+ if cache_dir. is_some ( ) {
366+ masked_fields. push ( "cache-dir" ) ;
367+ }
368+ if preview. is_some ( ) {
369+ masked_fields. push ( "preview" ) ;
370+ }
371+ if python_preference. is_some ( ) {
372+ masked_fields. push ( "python-preference" ) ;
373+ }
374+ if python_downloads. is_some ( ) {
375+ masked_fields. push ( "python-downloads" ) ;
376+ }
377+ if concurrent_downloads. is_some ( ) {
378+ masked_fields. push ( "concurrent-downloads" ) ;
379+ }
380+ if concurrent_builds. is_some ( ) {
381+ masked_fields. push ( "concurrent-builds" ) ;
382+ }
383+ if concurrent_installs. is_some ( ) {
384+ masked_fields. push ( "concurrent-installs" ) ;
385+ }
386+ if allow_insecure_host. is_some ( ) {
387+ masked_fields. push ( "allow-insecure-host" ) ;
388+ }
389+ if index. is_some ( ) {
390+ masked_fields. push ( "index" ) ;
391+ }
392+ if index_url. is_some ( ) {
393+ masked_fields. push ( "index-url" ) ;
394+ }
395+ if extra_index_url. is_some ( ) {
396+ masked_fields. push ( "extra-index-url" ) ;
397+ }
398+ if no_index. is_some ( ) {
399+ masked_fields. push ( "no-index" ) ;
400+ }
401+ if find_links. is_some ( ) {
402+ masked_fields. push ( "find-links" ) ;
403+ }
404+ if index_strategy. is_some ( ) {
405+ masked_fields. push ( "index-strategy" ) ;
406+ }
407+ if keyring_provider. is_some ( ) {
408+ masked_fields. push ( "keyring-provider" ) ;
409+ }
410+ if resolution. is_some ( ) {
411+ masked_fields. push ( "resolution" ) ;
412+ }
413+ if prerelease. is_some ( ) {
414+ masked_fields. push ( "prerelease" ) ;
415+ }
416+ if fork_strategy. is_some ( ) {
417+ masked_fields. push ( "fork-strategy" ) ;
418+ }
419+ if dependency_metadata. is_some ( ) {
420+ masked_fields. push ( "dependency-metadata" ) ;
421+ }
422+ if config_settings. is_some ( ) {
423+ masked_fields. push ( "config-settings" ) ;
424+ }
425+ if no_build_isolation. is_some ( ) {
426+ masked_fields. push ( "no-build-isolation" ) ;
427+ }
428+ if no_build_isolation_package. is_some ( ) {
429+ masked_fields. push ( "no-build-isolation-package" ) ;
430+ }
431+ if exclude_newer. is_some ( ) {
432+ masked_fields. push ( "exclude-newer" ) ;
433+ }
434+ if link_mode. is_some ( ) {
435+ masked_fields. push ( "link-mode" ) ;
436+ }
437+ if compile_bytecode. is_some ( ) {
438+ masked_fields. push ( "compile-bytecode" ) ;
439+ }
440+ if no_sources. is_some ( ) {
441+ masked_fields. push ( "no-sources" ) ;
442+ }
443+ if upgrade. is_some ( ) {
444+ masked_fields. push ( "upgrade" ) ;
445+ }
446+ if upgrade_package. is_some ( ) {
447+ masked_fields. push ( "upgrade-package" ) ;
448+ }
449+ if reinstall. is_some ( ) {
450+ masked_fields. push ( "reinstall" ) ;
451+ }
452+ if reinstall_package. is_some ( ) {
453+ masked_fields. push ( "reinstall-package" ) ;
454+ }
455+ if no_build. is_some ( ) {
456+ masked_fields. push ( "no-build" ) ;
457+ }
458+ if no_build_package. is_some ( ) {
459+ masked_fields. push ( "no-build-package" ) ;
460+ }
461+ if no_binary. is_some ( ) {
462+ masked_fields. push ( "no-binary" ) ;
463+ }
464+ if no_binary_package. is_some ( ) {
465+ masked_fields. push ( "no-binary-package" ) ;
466+ }
467+ if python_install_mirror. is_some ( ) {
468+ masked_fields. push ( "python-install-mirror" ) ;
469+ }
470+ if pypy_install_mirror. is_some ( ) {
471+ masked_fields. push ( "pypy-install-mirror" ) ;
472+ }
473+ if python_downloads_json_url. is_some ( ) {
474+ masked_fields. push ( "python-downloads-json-url" ) ;
475+ }
476+ if publish_url. is_some ( ) {
477+ masked_fields. push ( "publish-url" ) ;
478+ }
479+ if trusted_publishing. is_some ( ) {
480+ masked_fields. push ( "trusted-publishing" ) ;
481+ }
482+ if check_url. is_some ( ) {
483+ masked_fields. push ( "check-url" ) ;
484+ }
485+ if add_bounds. is_some ( ) {
486+ masked_fields. push ( "add-bounds" ) ;
487+ }
488+ if pip. is_some ( ) {
489+ masked_fields. push ( "pip" ) ;
490+ }
491+ if cache_keys. is_some ( ) {
492+ masked_fields. push ( "cache_keys" ) ;
493+ }
494+ if override_dependencies. is_some ( ) {
495+ masked_fields. push ( "override-dependencies" ) ;
496+ }
497+ if constraint_dependencies. is_some ( ) {
498+ masked_fields. push ( "constraint-dependencies" ) ;
499+ }
500+ if build_constraint_dependencies. is_some ( ) {
501+ masked_fields. push ( "build-constraint-dependencies" ) ;
502+ }
503+ if environments. is_some ( ) {
504+ masked_fields. push ( "environments" ) ;
505+ }
506+ if required_environments. is_some ( ) {
507+ masked_fields. push ( "required-environments" ) ;
508+ }
509+ if !masked_fields. is_empty ( ) {
510+ let field_listing = masked_fields. join ( "\n - " ) ;
511+ warn_user ! (
512+ "Found both a `uv.toml` file and a `[tool.uv]` section in an adjacent `pyproject.toml`. The following fields from `[tool.uv]` will be ignored in favor of the `uv.toml` file:\n - {}" ,
513+ field_listing,
514+ ) ;
515+ }
516+ }
517+
272518#[ derive( thiserror:: Error , Debug ) ]
273519pub enum Error {
274520 #[ error( transparent) ]
0 commit comments