Repository: astral-sh/uv
File: crates/uv-build-backend/src/metadata.rs (Rust)

Code before:
    fn write_group<'a>(
        writer: &mut String,
        group: &str,
        entries: impl IntoIterator<Item = (&'a String, &'a String)>,
    ) -> Result<(), ValidationError> {
        if !group
            .chars()
            .next()
            .map(|c| c.is_alphanumeric() || c == '_')
            .unwrap_or(false)
            || !group
                .chars()
                .all(|c| c.is_alphanumeric() || c == '.' || c == '_')
        {
            return Err(ValidationError::InvalidGroup(group.to_string()));
        }

        let _ = writeln!(writer, "[{group}]");
        for (name, object_reference) in entries {
            if !name
                .chars()
                .all(|c| c.is_alphanumeric() || c == '.' || c == '-' || c == '_')
            {
                warn!(
                    "Entrypoint names should consist of letters, numbers, dots, underscores and \
                    dashes; non-complaint name: `{name}`"
                );
            }

            // TODO(konsti): Validate that the object references are valid Python identifiers.
            let _ = writeln!(writer, "{name} = {object_reference}");
        }
        writer.push('\n');
        Ok(())
    }
}

/// The `[project]` section of a pyproject.toml as specified in
/// <https://packaging.python.org/en/latest/specifications/pyproject-toml>.
///
/// This struct does not have schema export; the schema is shared between all Python tools, and we
/// should update the shared schema instead.
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
struct Project {
    /// The name of the project.
    name: PackageName,
    /// The version of the project.
    version: Version,
    /// The summary description of the project in one line.
    description: Option<String>,

Review comment (suggestion):
```suggestion
                    dashes; non-compliant name: `{name}`"
```

Code after:
    fn write_group<'a>(
        writer: &mut String,
        group: &str,
        entries: impl IntoIterator<Item = (&'a String, &'a String)>,
    ) -> Result<(), ValidationError> {
        if !group
            .chars()
            .next()
            .map(|c| c.is_alphanumeric() || c == '_')
            .unwrap_or(false)
            || !group
                .chars()
                .all(|c| c.is_alphanumeric() || c == '.' || c == '_')
        {
            return Err(ValidationError::InvalidGroup(group.to_string()));
        }

        let _ = writeln!(writer, "[{group}]");
        for (name, object_reference) in entries {
            if !name
                .chars()
                .all(|c| c.is_alphanumeric() || c == '.' || c == '-' || c == '_')
            {
                warn!(
                    "Entrypoint names should consist of letters, numbers, dots, underscores and \
                    dashes; non-compliant name: `{name}`"
                );
            }

            // TODO(konsti): Validate that the object references are valid Python identifiers.
            let _ = writeln!(writer, "{name} = {object_reference}");
        }
        writer.push('\n');
        Ok(())
    }
}

/// The `[project]` section of a pyproject.toml as specified in
/// <https://packaging.python.org/en/latest/specifications/pyproject-toml>.
///
/// This struct does not have schema export; the schema is shared between all Python tools, and we
/// should update the shared schema instead.
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
struct Project {
    /// The name of the project.
    name: PackageName,
    /// The version of the project.
    version: Version,
    /// The summary description of the project in one line.
    description: Option<String>,