mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
Allow overriding module name for uv build backend (#11884)
Thank you for uv, it has game-changer capabilities in the field of Python package and environment maangement! ## Summary This is a small PR adding the option `module-name` (`tool.uv.build-backend.module-name`) to the uv build backend ( https://github.com/astral-sh/uv/issues/8779 ). Currently, the uv build backend will assume that the module name matches the (dash to underdash-transformed) package name. In some packaging scenarios this is not the case, and currently there exists no possibility to override it, which this PR addresses. From the main issue ( https://github.com/astral-sh/uv/issues/8779 ) I could not tell if there is any extensive roadmap or plans how to implement more complex scenarios, hence this PR as a suggestion for a small feature with a big impact for certain scenarios. I am new to Rust, I hope the borrow/reference usage is correct. ## Test Plan So far I tested this at an example, if desired I can look into extending the tests. Fixes #11428 --------- Co-authored-by: konstin <konstin@mailbox.org>
This commit is contained in:
parent
1ab1945dd9
commit
c57dd1a4a8
10 changed files with 303 additions and 13 deletions
|
@ -15,6 +15,7 @@ use thiserror::Error;
|
|||
use tracing::debug;
|
||||
use uv_fs::Simplified;
|
||||
use uv_globfilter::PortableGlobError;
|
||||
use uv_pypi_types::IdentifierParseError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
|
@ -24,6 +25,8 @@ pub enum Error {
|
|||
Toml(#[from] toml::de::Error),
|
||||
#[error("Invalid pyproject.toml")]
|
||||
Validation(#[from] ValidationError),
|
||||
#[error(transparent)]
|
||||
Identifier(#[from] IdentifierParseError),
|
||||
#[error("Unsupported glob expression in: `{field}`")]
|
||||
PortableGlob {
|
||||
field: String,
|
||||
|
|
|
@ -17,7 +17,7 @@ use uv_pep440::{Version, VersionSpecifiers};
|
|||
use uv_pep508::{
|
||||
ExtraOperator, MarkerExpression, MarkerTree, MarkerValueExtra, Requirement, VersionOrUrl,
|
||||
};
|
||||
use uv_pypi_types::{Metadata23, VerbatimParsedUrl};
|
||||
use uv_pypi_types::{Identifier, Metadata23, VerbatimParsedUrl};
|
||||
|
||||
use crate::serde_verbatim::SerdeVerbatim;
|
||||
use crate::Error;
|
||||
|
@ -803,7 +803,7 @@ pub(crate) struct ToolUv {
|
|||
/// When building the source distribution, the following files and directories are included:
|
||||
/// * `pyproject.toml`
|
||||
/// * The module under `tool.uv.build-backend.module-root`, by default
|
||||
/// `src/<project_name_with_underscores>/**`.
|
||||
/// `src/<module-name or project_name_with_underscores>/**`.
|
||||
/// * `project.license-files` and `project.readme`.
|
||||
/// * All directories under `tool.uv.build-backend.data`.
|
||||
/// * All patterns from `tool.uv.build-backend.source-include`.
|
||||
|
@ -812,7 +812,7 @@ pub(crate) struct ToolUv {
|
|||
///
|
||||
/// When building the wheel, the following files and directories are included:
|
||||
/// * The module under `tool.uv.build-backend.module-root`, by default
|
||||
/// `src/<project_name_with_underscores>/**`.
|
||||
/// `src/<module-name or project_name_with_underscores>/**`.
|
||||
/// * `project.license-files` and `project.readme`, as part of the project metadata.
|
||||
/// * Each directory under `tool.uv.build-backend.data`, as data directories.
|
||||
///
|
||||
|
@ -846,6 +846,15 @@ pub(crate) struct BuildBackendSettings {
|
|||
/// using the flat layout over the src layout.
|
||||
pub(crate) module_root: PathBuf,
|
||||
|
||||
/// The name of the module directory inside `module-root`.
|
||||
///
|
||||
/// The default module name is the package name with dots and dashes replaced by underscores.
|
||||
///
|
||||
/// Note that using this option runs the risk of creating two packages with different names but
|
||||
/// the same module names. Installing such packages together leads to unspecified behavior,
|
||||
/// often with corrupted files or directory trees.
|
||||
pub(crate) module_name: Option<Identifier>,
|
||||
|
||||
/// Glob expressions which files and directories to additionally include in the source
|
||||
/// distribution.
|
||||
///
|
||||
|
@ -877,6 +886,7 @@ impl Default for BuildBackendSettings {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
module_root: PathBuf::from("src"),
|
||||
module_name: None,
|
||||
source_include: Vec::new(),
|
||||
default_excludes: true,
|
||||
source_exclude: Vec::new(),
|
||||
|
|
|
@ -8,11 +8,13 @@ use globset::{Glob, GlobSet};
|
|||
use std::io;
|
||||
use std::io::{BufReader, Cursor};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use tar::{EntryType, Header};
|
||||
use tracing::{debug, trace};
|
||||
use uv_distribution_filename::{SourceDistExtension, SourceDistFilename};
|
||||
use uv_fs::Simplified;
|
||||
use uv_globfilter::{parse_portable_glob, GlobDirFilter};
|
||||
use uv_pypi_types::Identifier;
|
||||
use uv_warnings::warn_user_once;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
|
@ -65,11 +67,21 @@ fn source_dist_matcher(
|
|||
let mut includes: Vec<String> = settings.source_include;
|
||||
// pyproject.toml is always included.
|
||||
includes.push(globset::escape("pyproject.toml"));
|
||||
|
||||
let module_name = if let Some(module_name) = settings.module_name {
|
||||
module_name
|
||||
} else {
|
||||
// Should never error, the rules for package names (in dist-info formatting) are stricter
|
||||
// than those for identifiers
|
||||
Identifier::from_str(pyproject_toml.name().as_dist_info_name().as_ref())?
|
||||
};
|
||||
debug!("Module name: `{:?}`", module_name);
|
||||
|
||||
// The wheel must not include any files included by the source distribution (at least until we
|
||||
// have files generated in the source dist -> wheel build step).
|
||||
let import_path = &settings
|
||||
.module_root
|
||||
.join(pyproject_toml.name().as_dist_info_name().as_ref())
|
||||
.join(module_name.as_ref())
|
||||
.portable_display()
|
||||
.to_string();
|
||||
includes.push(format!("{}/**", globset::escape(import_path)));
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::io::{BufReader, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{io, mem};
|
||||
|
||||
use fs_err::File;
|
||||
use globset::{GlobSet, GlobSetBuilder};
|
||||
use itertools::Itertools;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::io::{BufReader, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::{io, mem};
|
||||
use tracing::{debug, trace};
|
||||
use walkdir::WalkDir;
|
||||
use zip::{CompressionMethod, ZipWriter};
|
||||
|
@ -14,6 +14,7 @@ use uv_distribution_filename::WheelFilename;
|
|||
use uv_fs::Simplified;
|
||||
use uv_globfilter::{parse_portable_glob, GlobDirFilter};
|
||||
use uv_platform_tags::{AbiTag, LanguageTag, PlatformTag};
|
||||
use uv_pypi_types::Identifier;
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::metadata::{BuildBackendSettings, DEFAULT_EXCLUDES};
|
||||
|
@ -128,7 +129,17 @@ fn write_wheel(
|
|||
return Err(Error::AbsoluteModuleRoot(settings.module_root.clone()));
|
||||
}
|
||||
let strip_root = source_tree.join(settings.module_root);
|
||||
let module_root = strip_root.join(pyproject_toml.name().as_dist_info_name().as_ref());
|
||||
|
||||
let module_name = if let Some(module_name) = settings.module_name {
|
||||
module_name
|
||||
} else {
|
||||
// Should never error, the rules for package names (in dist-info formatting) are stricter
|
||||
// than those for identifiers
|
||||
Identifier::from_str(pyproject_toml.name().as_dist_info_name().as_ref())?
|
||||
};
|
||||
debug!("Module name: `{:?}`", module_name);
|
||||
|
||||
let module_root = strip_root.join(module_name.as_ref());
|
||||
if !module_root.join("__init__.py").is_file() {
|
||||
return Err(Error::MissingModule(module_root));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue