Skip to content

fix(init): sanitize default package name derived from directory name#10975

Open
Socialpranker wants to merge 1 commit into
python-poetry:mainfrom
Socialpranker:sanitize-init-package-name
Open

fix(init): sanitize default package name derived from directory name#10975
Socialpranker wants to merge 1 commit into
python-poetry:mainfrom
Socialpranker:sanitize-init-package-name

Conversation

@Socialpranker

Copy link
Copy Markdown

Summary

Closes #10974.

poetry init/poetry new (which shares the same code path) used the current directory's name verbatim as the default package name. Per the PyPA name normalization spec, a valid name may only contain ASCII letters, numbers, period, underscore and hyphen — so a directory like my project with spaces produced a pyproject.toml with an invalid name = "my project with spaces" instead of name = "my-project-with-spaces".

This adds a small InitCommand._sanitize_package_name helper that replaces any disallowed character (including whitespace) with a hyphen, then reuses packaging.utils.canonicalize_name (already a dependency, already used elsewhere in this file for normalizing dependency names) to collapse/lowercase the result the same way it normalizes any other valid package name.

This only changes the default value derived from the directory name; an explicit --name/interactive value is left as-is, same as before.

Test plan

  • Added test_sanitize_package_name — parametrized unit test covering the reported case plus a few edge cases (repeated separators, mixed ./_, leading/trailing separators).
  • Added test_noninteractive_sanitizes_default_name_from_directory — reproduces the exact scenario from the issue (poetry init run non-interactively in a directory named my project with spaces), asserts the generated pyproject.toml has a valid name.
  • pytest tests/console/commands/test_init.py - 73 passed
  • pytest tests/console/commands/test_new.py - 24 passed (unaffected, NewCommand shares this code path)
  • ruff check / ruff format --check - clean
  • mypy src/poetry/console/commands/init.py - no issues

AI disclosure

This PR was written with the help of Claude Code (Claude Sonnet 5). All code was reviewed and tested by me before submission.

`poetry init`/`poetry new` used the current directory's name verbatim
as the default package name, which can contain spaces or other
characters that are invalid per the PyPA name format (only ASCII
letters, numbers, period, underscore and hyphen are allowed). This
produced a `pyproject.toml` with an invalid `[project] name`, e.g.
"my project with spaces" instead of "my-project-with-spaces".

Sanitize the derived name the same way `packaging.utils.canonicalize_name`
normalizes existing valid names, after first replacing any disallowed
characters (including whitespace) with a hyphen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Consider handling the edge case where the sanitized name becomes empty after replacing invalid characters and stripping hyphens, as this could happen for directory names containing only disallowed characters.
  • The _sanitize_package_name docstring currently describes the allowed character set for names but the canonicalization step produces only lowercase letters, numbers, and hyphens; clarifying that distinction would make the helper’s behavior easier to understand at a glance.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider handling the edge case where the sanitized name becomes empty after replacing invalid characters and stripping hyphens, as this could happen for directory names containing only disallowed characters.
- The `_sanitize_package_name` docstring currently describes the allowed character set for names but the canonicalization step produces only lowercase letters, numbers, and hyphens; clarifying that distinction would make the helper’s behavior easier to understand at a glance.

## Individual Comments

### Comment 1
<location path="src/poetry/console/commands/init.py" line_range="131" />
<code_context>
         name = self.option("name")
         if not name:
-            name = project_path.name.lower()
+            name = self._sanitize_package_name(project_path.name)

             if is_interactive:
</code_context>
<issue_to_address>
**issue:** Consider handling the case where sanitization produces an empty package name.

If `_sanitize_package_name` returns an empty string (e.g., when the directory name consists only of stripped characters), subsequent logic will operate on an invalid/empty project name. Please add a fallback for this case, such as raising an error or defaulting to a safe default name.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

name = self.option("name")
if not name:
name = project_path.name.lower()
name = self._sanitize_package_name(project_path.name)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Consider handling the case where sanitization produces an empty package name.

If _sanitize_package_name returns an empty string (e.g., when the directory name consists only of stripped characters), subsequent logic will operate on an invalid/empty project name. Please add a fallback for this case, such as raising an error or defaulting to a safe default name.

@Socialpranker

Copy link
Copy Markdown
Author

The macOS aarch64 (Python 3.11) / mypy check failed, but it looks like a CI infrastructure issue rather than a real failure — the job was cancelled after 17m26s with "The job was not acquired by Runner of type hosted even after multiple attempts", and the same mypy check passes on every other Python version/platform combination. Could someone with the right access re-run that job?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

init generates project with spaces in name

1 participant