Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

Commit 42874e2

Browse files
committed
fix: resolve Python packaging issues with hyphens in project slugs
- Fixed template directory structure to use underscores for Python modules - Updated all import statements to use underscore-based module names - Fixed class name generation to handle hyphens correctly - Renamed src/{{cookiecutter.project_slug}}/ to src/{{cookiecutter.project_slug.replace('-', '_')}}/ - Updated test files to import from underscore-based modules - Fixed pytest configuration to avoid template directory collection issues - Ensured generated projects with hyphens can be installed and run correctly This resolves entry point errors when generating projects with hyphens in the slug, such as 'test-package-full-quality', making them installable and functional.
1 parent 94a6ee1 commit 42874e2

9 files changed

Lines changed: 29 additions & 28 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This file prevents pytest from discovering test files in the template directory

{{cookiecutter.project_slug}}/pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,14 @@ Changelog = "https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutt
9797
{%- if cookiecutter.command_line_interface != "none" %}
9898

9999
[project.scripts]
100-
{{ cookiecutter.project_slug }} = "{{ cookiecutter.project_slug }}.cli:main"
100+
{{ cookiecutter.project_slug }} = "{{ cookiecutter.project_slug.replace('-', '_') }}.cli:main"
101101
{%- endif %}
102102

103103
[tool.setuptools.packages.find]
104104
where = ["src"]
105105

106106
[tool.setuptools.package-data]
107-
"{{ cookiecutter.project_slug }}" = ["py.typed"]
107+
"{{ cookiecutter.project_slug.replace('-', '_') }}" = ["py.typed"]
108108

109109
{%- if cookiecutter.use_pytest == "y" %}
110110

@@ -115,7 +115,7 @@ addopts = [
115115
"--strict-markers",
116116
"--strict-config",
117117
{%- if cookiecutter.use_coverage == "y" %}
118-
"--cov={{ cookiecutter.project_slug }}",
118+
"--cov={{ cookiecutter.project_slug.replace('-', '_') }}",
119119
"--cov-report=term-missing",
120120
"--cov-report=html",
121121
"--cov-report=xml",
@@ -135,7 +135,7 @@ markers = [
135135
{%- if cookiecutter.use_coverage == "y" %}
136136

137137
[tool.coverage.run]
138-
source = ["src/{{ cookiecutter.project_slug }}"]
138+
source = ["src/{{ cookiecutter.project_slug.replace('-', '_') }}"]
139139
omit = [
140140
"tests/*",
141141
"*/tests/*",

{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/__init__.py renamed to {{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug.replace('-', '_')}}/__init__.py

File renamed without changes.

{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/cli.py renamed to {{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug.replace('-', '_')}}/cli.py

File renamed without changes.

{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/core.py renamed to {{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug.replace('-', '_')}}/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def add_numbers(a: float, b: float) -> float:
4040
return a + b
4141

4242

43-
class {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}:
43+
class {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}:
4444
"""Main class for {{ cookiecutter.project_name }}."""
4545

4646
def __init__(self, name: str) -> None:

{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}/py.typed renamed to {{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug.replace('-', '_')}}/py.typed

File renamed without changes.

{{cookiecutter.project_slug}}/tests/test_cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{%- if cookiecutter.command_line_interface == "typer" %}
44
from typer.testing import CliRunner
55

6-
from {{ cookiecutter.project_slug }}.cli import app
6+
from {{ cookiecutter.project_slug.replace('-', '_') }}.cli import app
77

88

99
runner = CliRunner()
@@ -39,7 +39,7 @@ def test_cli_help():
3939
{%- elif cookiecutter.command_line_interface == "click" %}
4040
from click.testing import CliRunner
4141

42-
from {{ cookiecutter.project_slug }}.cli import main
42+
from {{ cookiecutter.project_slug.replace('-', '_') }}.cli import main
4343

4444

4545
runner = CliRunner()
@@ -69,7 +69,7 @@ def test_cli_greet_custom():
6969
import sys
7070
from unittest.mock import patch
7171

72-
from {{ cookiecutter.project_slug }}.cli import main, create_parser
72+
from {{ cookiecutter.project_slug.replace('-', '_') }}.cli import main, create_parser
7373

7474

7575
def test_parser_creation():

{{cookiecutter.project_slug}}/tests/test_core.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
import pytest
55

6-
from {{ cookiecutter.project_slug }}.core import (
7-
{{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }},
6+
from {{ cookiecutter.project_slug.replace('-', '_') }}.core import (
7+
{{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }},
88
add_numbers,
99
hello_world,
1010
)
@@ -31,7 +31,7 @@ def test_add_numbers():
3131

3232
def test_main_class():
3333
"""Test the main class."""
34-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("Test")
34+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("Test")
3535
assert instance.name == "Test"
3636
assert instance.greet() == "Hello, Test!"
3737
assert "Test" in repr(instance)
@@ -56,28 +56,28 @@ class TestMainClass:
5656

5757
def test_initialization(self):
5858
"""Test class initialization."""
59-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("TestName")
59+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("TestName")
6060
assert instance.name == "TestName"
6161

6262
def test_greet_method(self):
6363
"""Test the greet method."""
64-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("Developer")
64+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("Developer")
6565
result = instance.greet()
6666
assert result == "Hello, Developer!"
6767

6868
def test_repr_method(self):
6969
"""Test the __repr__ method."""
70-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("TestRepr")
70+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("TestRepr")
7171
repr_str = repr(instance)
7272
assert "TestRepr" in repr_str
7373
assert instance.__class__.__name__ in repr_str
7474

7575
{%- else %}
7676

77-
from {{ cookiecutter.project_slug }}.core import (
77+
from {{ cookiecutter.project_slug.replace('-', '_') }}.core import (
7878
add_numbers,
7979
hello_world,
80-
{{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }},
80+
{{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }},
8181
)
8282

8383

@@ -95,7 +95,7 @@ def test_add_numbers():
9595

9696
def test_main_class():
9797
"""Test the main class."""
98-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("Test")
98+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("Test")
9999
assert instance.name == "Test"
100100
assert instance.greet() == "Hello, Test!"
101101

{{cookiecutter.project_slug}}/tests/test_{{cookiecutter.project_slug}}.py renamed to {{cookiecutter.project_slug}}/tests/test_{{cookiecutter.project_slug.replace('-', '_')}}.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
{%- if cookiecutter.use_pytest == "y" %}
21
"""Tests for {{ cookiecutter.project_slug }} core functionality."""
2+
{%- if cookiecutter.use_pytest == "y" %}
33

44
import pytest
55

6-
from {{ cookiecutter.project_slug }}.core import (
7-
{{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }},
6+
from {{ cookiecutter.project_slug.replace('-', '_') }}.core import (
7+
{{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }},
88
add_numbers,
99
hello_world,
1010
)
@@ -31,7 +31,7 @@ def test_add_numbers():
3131

3232
def test_main_class():
3333
"""Test the main class."""
34-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("Test")
34+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("Test")
3535
assert instance.name == "Test"
3636
assert instance.greet() == "Hello, Test!"
3737
assert "Test" in repr(instance)
@@ -56,28 +56,28 @@ class TestMainClass:
5656

5757
def test_initialization(self):
5858
"""Test class initialization."""
59-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("TestName")
59+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("TestName")
6060
assert instance.name == "TestName"
6161

6262
def test_greet_method(self):
6363
"""Test the greet method."""
64-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("Developer")
64+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("Developer")
6565
result = instance.greet()
6666
assert result == "Hello, Developer!"
6767

6868
def test_repr_method(self):
6969
"""Test the __repr__ method."""
70-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("TestRepr")
70+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("TestRepr")
7171
repr_str = repr(instance)
7272
assert "TestRepr" in repr_str
7373
assert instance.__class__.__name__ in repr_str
74+
7475
{%- else %}
75-
"""Tests for {{ cookiecutter.project_slug }} core functionality."""
7676

77-
from {{ cookiecutter.project_slug }}.core import (
77+
from {{ cookiecutter.project_slug.replace('-', '_') }}.core import (
7878
add_numbers,
7979
hello_world,
80-
{{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }},
80+
{{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }},
8181
)
8282

8383

@@ -95,7 +95,7 @@ def test_add_numbers():
9595

9696
def test_main_class():
9797
"""Test the main class."""
98-
instance = {{ cookiecutter.project_slug.replace('_', ' ').title().replace(' ', '') }}("Test")
98+
instance = {{ cookiecutter.project_slug.replace('-', '_').replace('_', ' ').title().replace(' ', '') }}("Test")
9999
assert instance.name == "Test"
100100
assert instance.greet() == "Hello, Test!"
101101

0 commit comments

Comments
 (0)