Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion copier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ template_mode:
"Welcome to the pyOpenSci package template.
Please select the type of template that you want to create today."
choices:
"MINIMAL: I want a minimal setup (package, tests and docs; typing); linting not included).": "minimal"
"MINIMAL: I want a minimal setup (package, tests and docs); linting & typing not included).": "minimal"
"FULL DEFAULT: I want to use the default settings but I want it setup for me.": "full"
"FULL CUSTOM: I want it all but I want to fully customize all template elements.": "custom"

Expand Down
50 changes: 15 additions & 35 deletions template/pyproject.toml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ authors = [
{ name = "{{ author_name }}"{% if author_email %}, email = "{{ author_email }}"{% endif %} },
]
license = "{{ license }}"
requires-python = ">= 3.10" # Adjust based on the minimum version of Python that you support
requires-python = ">= 3.11" # Adjust based on the minimum version of Python that you support
readme = {"file" = "README.md", "content-type" = "text/markdown"}
# Please consult https://pypi.org/classifiers/ for a full list.
classifiers = [
Expand Down Expand Up @@ -67,12 +67,10 @@ Documentation = "https://{{ project_slug }}.readthedocs.io"
Documentation = "{{ dev_platform_url }}/{{ username }}/{{ project_slug }}/blob/main/README.md"
{%- endif %}
{%- endif %}
# Note: update this url when you have published your package to pypi. (or delete it)
Download = "https://pypi.org/project/{{ project_slug }}/#files"

[project.optional-dependencies]
# The groups below should be in the [development-groups] table
# They are here now because hatch hasn't released support for them but plans to
# in Mid November 2025.
[dependency-groups]
dev = [
"hatch",
"pre-commit",
Expand All @@ -90,11 +88,11 @@ docs = [
{%- if documentation == "sphinx" %}
"sphinx~=8.0",
"myst-parser>=4.0",
"pydata-sphinx-theme~=0.16",
"pydata-sphinx-theme>=0.16",
"sphinx-autobuild>=2024.10.3",
"sphinx-autoapi>=3.6.0",
"sphinx_design>=0.6.1",
"sphinx-copybutton>=0.5.2",
"sphinx-design>=0.6.1",
{%- elif documentation == "mkdocs" %}
"mkdocs-material ~=9.5",
"mkdocstrings[python] ~=0.24",
Expand All @@ -111,9 +109,6 @@ build = [
tests = [
"pytest",
"pytest-cov",
"pytest-raises",
"pytest-randomly",
"pytest-xdist",
]
{%- endif %}

Expand Down Expand Up @@ -243,23 +238,7 @@ exclude = "_version.py"
{%- endif -%}

{% if use_types %}
# TODO: Adjust mypy configuration.
#[tool.mypy]
#plugins = [
# "pydantic.mypy",
#]

# Stop mypy from complaining about missing types from imports.
#[[tool.mypy.overrides]]
#module = [
# "pandas",
#]
#ignore_missing_imports = true

#[tool.pydantic-mypy]
#init_forbid_extra = true
#init_typed = true
#warn_required_dynamic_aliases = true
# Typing is not supported yet.
{%- endif %}

{%- if use_hatch_envs %}
Expand All @@ -276,10 +255,11 @@ installer = "uv"
# This table installs the tools you need to test and build your package
[tool.hatch.envs.build]
description = """Test the installation the package."""
features = [
dependency-groups = [

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This specific envt needed builder=true i'm not sure if it's because it's "Detached" or not?

"build",
]
detached = true
builder = true

# This table installs created the command hatch run install:check which will build and check your package.
[tool.hatch.envs.build.scripts]
Expand All @@ -293,12 +273,12 @@ check = [
{%- if use_test %}
[tool.hatch.envs.test]
description = """Run the test suite."""
features = [
"tests",
dependency-groups = [
"tests",
]

[[tool.hatch.envs.test.matrix]]
python = ["3.10", "3.11", "3.12", "3.13"]
python = ["3.11", "3.12", "3.13"]

[tool.hatch.envs.test.scripts]
run = "pytest {args:--cov={{ package_name }} --cov-report=term-missing --cov-report=xml}"
Expand All @@ -310,7 +290,7 @@ run = "pytest {args:--cov={{ package_name }} --cov-report=term-missing --cov-rep
[tool.hatch.envs.docs]
description = """Build or serve the documentation."""
# Install optional dependency test for docs
features = [
dependency-groups = [
"docs",
]

Expand All @@ -333,7 +313,7 @@ serve = ["sphinx-autobuild docs --watch src/{{ package_name }} {args:-b html doc

[tool.hatch.envs.style]
description = """Check the code and documentation style."""
features = [
dependency-groups = [
"style",
]
detached = true
Expand All @@ -349,7 +329,7 @@ check = ["docstrings", "code"]

[tool.hatch.envs.audit]
description = """Check dependencies for security vulnerabilities."""
features = [
dependency-groups = [
"build",
]

Expand All @@ -361,7 +341,7 @@ check = ["pip-audit"]
#--------------- Typing ---------------#
[tool.hatch.envs.types]
description = """Check the static types of the codebase."""
features = ["types"]
dependency-groups = ["types"]

[tool.hatch.envs.types.scripts]
check = "mypy src/{{ package_name }}"
Expand Down
21 changes: 15 additions & 6 deletions tests/test_template_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,17 @@ def init_git(path: Path):

def run_command(command: str, cwd: Path, **kwargs) -> None:
"""Run a command, showing stdout/stderr on errors."""
# Strip HATCH_ENV_ACTIVE so inner hatch calls don't inherit the outer
# matrix environment name (e.g. test.py3.10), which would cause hatch
# to fail with "Unknown environment" in the generated project.
env = os.environ.copy()
env.pop("HATCH_ENV_ACTIVE", None)
default_kwargs = {
"shell": True,
"stdout": subprocess.PIPE,
"stderr": subprocess.PIPE,
"text": True,
"env": env,
}
kwargs = {**default_kwargs, **kwargs}
try:
Expand Down Expand Up @@ -170,7 +176,10 @@ def test_template_suite(

# Run the local test suite.
run_command("hatch build --clean", project_dir)
run_command(f"hatch run +py={sys.version_info.major}.{sys.version_info.minor} test:run", project_dir)
# The template requires Python >= 3.11; clamp to that minimum so this test
# works even when the outer test suite runs on an older interpreter.
py = max(sys.version_info[:2], (3, 11))
run_command(f"hatch run +py={py[0]}.{py[1]} test:run", project_dir)
run_command("hatch run style:check", project_dir)


Expand Down Expand Up @@ -225,7 +234,7 @@ def test_non_hatch_deps(
documentation: str,
generated: Callable[..., Path],
) -> None:
"""When we aren't using hatch, we should still get the optional dependencies."""
"""When we aren't using hatch, we should still get the dependency groups."""
project = generated(
use_hatch_envs=False,
use_lint=True,
Expand All @@ -242,15 +251,15 @@ def test_non_hatch_deps(
# validate pyproject.toml file if present
validator_api.Validator()(pyproject)

optional_deps = pyproject["project"]["optional-dependencies"]
dep_groups = pyproject["dependency-groups"]
groups = ("dev", "tests", "style", "types", "build")
assert all(group in optional_deps for group in groups)
assert all(group in dep_groups for group in groups)

# we don't want to hardcode all our deps here,
# bc that would be a very fragile test indeed.
# Instead, we just assume their presence and that the validity of the pyproject file
# means that they have been correctly specified.
# except for the docs, where we want to test our switch works :)
if documentation != "no":
assert "docs" in optional_deps
assert any(dep.startswith(documentation) for dep in optional_deps["docs"])
assert "docs" in dep_groups
assert any(dep.startswith(documentation) for dep in dep_groups["docs"])