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
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ bump = true
[tool.hatch.build.targets.wheel]
# The source location for the package.
packages = ["src/python_package_folder"]
# Force-include the scripts directory (non-Python files)
# Place scripts inside the package directory so importlib.resources can find them
force-include = { "src/python_package_folder/scripts" = "python_package_folder/scripts" }
# Using a build hook to automatically include all files in the scripts directory
# This avoids duplicates while being sustainable for future file additions
[tool.hatch.build.hooks.custom]
path = "src/python_package_folder/_hatch_build.py"


# ---- Settings ----
Expand Down
39 changes: 39 additions & 0 deletions src/python_package_folder/_hatch_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""
Hatch build hook to automatically include all files from the scripts directory.

This hook ensures all non-Python files in the scripts directory are included
in the wheel without creating duplicates, and automatically includes any new
files added to the directory without requiring manual configuration updates.
"""

from pathlib import Path
from typing import Any

from hatchling.builders.hooks.plugin.interface import BuildHookInterface

Check warning on line 12 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Type of "BuildHookInterface" is unknown (reportUnknownVariableType)

Check failure on line 12 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Import "hatchling.builders.hooks.plugin.interface" could not be resolved (reportMissingImports)

Check warning on line 12 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Type of "BuildHookInterface" is unknown (reportUnknownVariableType)

Check failure on line 12 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Import "hatchling.builders.hooks.plugin.interface" could not be resolved (reportMissingImports)

Check warning on line 12 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Type of "BuildHookInterface" is unknown (reportUnknownVariableType)

Check failure on line 12 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Import "hatchling.builders.hooks.plugin.interface" could not be resolved (reportMissingImports)


class CustomBuildHook(BuildHookInterface):

Check warning on line 15 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Base class type is unknown, obscuring type of derived class (reportUntypedBaseClass)

Check warning on line 15 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Base class type is unknown, obscuring type of derived class (reportUntypedBaseClass)

Check warning on line 15 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Base class type is unknown, obscuring type of derived class (reportUntypedBaseClass)
"""Build hook to include all files from the scripts directory."""

def initialize(self, version: str, build_data: dict[str, Any]) -> None:

Check warning on line 18 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

"version" is not accessed (reportUnusedParameter)

Check warning on line 18 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

"version" is not accessed (reportUnusedParameter)

Check warning on line 18 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

"version" is not accessed (reportUnusedParameter)
"""Initialize the build hook and add scripts directory files."""
# Get the source directory for the package
source_dir = Path(self.root) / "src" / "python_package_folder"

Check warning on line 21 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Argument type is unknown   Argument corresponds to parameter "args" in function "__init__" (reportUnknownArgumentType)

Check warning on line 21 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Type of "root" is unknown (reportUnknownMemberType)

Check warning on line 21 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Argument type is unknown   Argument corresponds to parameter "args" in function "__init__" (reportUnknownArgumentType)

Check warning on line 21 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Type of "root" is unknown (reportUnknownMemberType)

Check warning on line 21 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Argument type is unknown   Argument corresponds to parameter "args" in function "__new__" (reportUnknownArgumentType)

Check warning on line 21 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Type of "root" is unknown (reportUnknownMemberType)
scripts_dir = source_dir / "scripts"

# If scripts directory exists, include all files from it
if scripts_dir.exists() and scripts_dir.is_dir():
# Add all files from scripts directory to force-include
# This ensures they're included in the wheel at the correct location
for script_file in scripts_dir.iterdir():
if script_file.is_file():
# Calculate relative paths
source_path = script_file.relative_to(self.root)

Check warning on line 31 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Argument type is unknown   Argument corresponds to parameter "other" in function "relative_to" (reportUnknownArgumentType)

Check warning on line 31 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Type of "root" is unknown (reportUnknownMemberType)

Check warning on line 31 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Argument type is unknown   Argument corresponds to parameter "other" in function "relative_to" (reportUnknownArgumentType)

Check warning on line 31 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Type of "root" is unknown (reportUnknownMemberType)

Check warning on line 31 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Argument type is unknown   Argument corresponds to parameter "other" in function "relative_to" (reportUnknownArgumentType)

Check warning on line 31 in src/python_package_folder/_hatch_build.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Type of "root" is unknown (reportUnknownMemberType)
# Target path inside the wheel package
target_path = f"python_package_folder/scripts/{script_file.name}"

# Add to force-include (hatchling will handle this)
# We need to add it to build_data['force_include']
if "force_include" not in build_data:
build_data["force_include"] = {}
build_data["force_include"][str(source_path)] = target_path
76 changes: 39 additions & 37 deletions src/python_package_folder/python_package_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
try:
from importlib import resources
except ImportError:
import importlib_resources as resources # type: ignore[no-redef]

Check failure on line 20 in src/python_package_folder/python_package_folder.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.13)

Import "importlib_resources" could not be resolved (reportMissingImports)

Check failure on line 20 in src/python_package_folder/python_package_folder.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.12)

Import "importlib_resources" could not be resolved (reportMissingImports)

Check failure on line 20 in src/python_package_folder/python_package_folder.py

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 3.11)

Import "importlib_resources" could not be resolved (reportMissingImports)

from .manager import BuildManager
from .utils import find_project_root, find_source_directory
Expand Down Expand Up @@ -45,48 +45,49 @@
# - For normal installs: direct file path
# - For zip/pex installs: extract to temporary file using as_file()

# First, try project root (development)
dev_script = project_root / "scripts" / "get-next-version.cjs"
if dev_script.exists():
script_path = dev_script
temp_script_context = None
else:
# Try to locate script in installed package using importlib.resources
script_path = None
temp_script_context = None
try:
package = resources.files("python_package_folder")
script_resource = package / "scripts" / "get-next-version.cjs"
if script_resource.is_file():
# Try direct path conversion first (normal file system install)
try:
script_path_candidate = Path(str(script_resource))
if script_path_candidate.exists():
script_path = script_path_candidate
except (TypeError, ValueError):
pass

# If direct path didn't work, try as_file() for zip/pex installs
if script_path is None:
# Track temporary file context for cleanup
temp_script_context = None

try:
# First, try project root (development)
dev_script = project_root / "scripts" / "get-next-version.cjs"
if dev_script.exists():
script_path = dev_script
else:
# Try to locate script in installed package using importlib.resources
script_path = None
try:
package = resources.files("python_package_folder")
script_resource = package / "scripts" / "get-next-version.cjs"
if script_resource.is_file():
# Try direct path conversion first (normal file system install)
try:
temp_script_context = resources.as_file(script_resource)
script_path = temp_script_context.__enter__()
except (TypeError, ValueError, OSError):
script_path_candidate = Path(str(script_resource))
if script_path_candidate.exists():
script_path = script_path_candidate
except (TypeError, ValueError):
pass
except (ImportError, ModuleNotFoundError, TypeError, AttributeError, OSError):
pass

# Fallback: try relative to package directory
if script_path is None:
package_dir = Path(__file__).parent
fallback_script = package_dir / "scripts" / "get-next-version.cjs"
if fallback_script.exists():
script_path = fallback_script
# If direct path didn't work, try as_file() for zip/pex installs
if script_path is None:
try:
temp_script_context = resources.as_file(script_resource)
script_path = temp_script_context.__enter__()
except (TypeError, ValueError, OSError):
pass
except (ImportError, ModuleNotFoundError, TypeError, AttributeError, OSError):
pass

if not script_path:
return None
# Fallback: try relative to package directory
if script_path is None:
package_dir = Path(__file__).parent
fallback_script = package_dir / "scripts" / "get-next-version.cjs"
if fallback_script.exists():
script_path = fallback_script

if not script_path:
return None

try:
# Build command arguments
cmd = ["node", str(script_path), str(project_root)]
if subfolder_path and package_name:
Expand Down Expand Up @@ -142,6 +143,7 @@
return None
finally:
# Clean up temporary file if we extracted from zip/pex
# This must be at function level to ensure cleanup even on early return
if temp_script_context is not None:
try:
temp_script_context.__exit__(None, None, None)
Expand Down
Loading