Back to skills
SKILL.md
1607 Version Build Hook 36209f9b
ASecurityAutomatically write version information to files during build. Covers configuration, templating, target-specific hooks, and runtime version access patterns.
- 9 stars
- 0 votes
- 0 copies
- 0 views
- Added October 11, 2026
Works with
Security analysis
96/100- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add tools-only/X-Skills --skill 1607-version-build-hook_36209f9b --agent claude-codeAre you the author of 1607 Version Build Hook 36209f9b?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-1607-version-build-hook-36209f9b)---
title: Version Build Hook
description: Automatically write version information to files during build. Covers configuration, templating, target-specific hooks, and runtime version access patterns.
---
# Version Build Hook
The version build hook is a powerful feature that automatically writes version information to files during the build process. This ensures packaged code always contains the correct version, regardless of how it's determined (static, dynamic, or from environment variables).
## Overview
The version build hook:
- Runs during package building (wheel, sdist)
- Creates or updates files with version information
- Supports templating for custom formats
- Works with all version sources
- Ensures version availability at runtime
## Basic Configuration
Enable the version build hook in your `pyproject.toml`:
```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
```
This creates `_version.py` during build:
```python
# Automatically generated by Hatch
__version__ = "1.2.3"
```
## Configuration Options
### Global Hook Configuration
```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
template = '__version__ = "{version}"'
pattern = "__version__ = ['\"](?P<version>[^'\"]+)['\"]"
```
### Target-Specific Configuration
Configure per build target:
```toml
# For wheels only
[tool.hatch.build.targets.wheel.hooks.version]
path = "src/my_package/_version.py"
# For source distributions only
[tool.hatch.build.targets.sdist.hooks.version]
path = "src/my_package/_version.py"
```
### Configuration Parameters
| Parameter | Type | Description | Default |
| ---------- | ----------- | ---------------------------------- | --------------------------- |
| `path` | string | File path to write version | Required |
| `template` | string | Template for file content | `__version__ = "{version}"` |
| `pattern` | string/bool | Pattern for updating existing file | `true` (uses default) |
## Template Formatting
### Simple Template
Basic version string:
```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
template = '__version__ = "{version}"'
```
Result:
```python
__version__ = "1.2.3"
```
### Multi-line Template
Include additional metadata:
```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
template = '''
"""Version information."""
__version__ = "{version}"
__version_tuple__ = {version_tuple}
'''
```
Result:
```python
"""Version information."""
__version__ = "1.2.3"
__version_tuple__ = (1, 2, 3)
```
### Available Template Variables
| Variable | Description | Example |
| ----------------- | ------------------- | ----------- |
| `{version}` | Full version string | `"1.2.3"` |
| `{version_tuple}` | Version as tuple | `(1, 2, 3)` |
### Custom Templates
Complex version information:
```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/version_info.py"
template = '''
"""
Automatically generated version information.
Do not edit this file manually.
"""
from typing import Tuple
__version__: str = "{version}"
__version_tuple__: Tuple[int, ...] = {version_tuple}
def get_version() -> str:
"""Get the current version."""
return __version__
def get_version_tuple() -> Tuple[int, ...]:
"""Get version as a tuple of integers."""
return __version_tuple__
'''
```
## Pattern-Based Updates
### Using Default Pattern
The default pattern matches standard Python version declarations:
```toml
[tool.hatch.build.hooks.version]
path = "src/my_package/__init__.py"
pattern = true # Use default pattern
```
Updates existing version in file:
```python
# Before build
__version__ = "0.0.0" # Placeholder
# After build
__version__ = "1.2.3" # Updated
```
### Custom Pattern
Specify custom regex patterns:
```toml
[tool.hatch.build.hooks.version]
path = "setup.cfg"
template = "version = {version}"
pattern = "version = .*"
```
Updates:
```ini
# Before
[metadata]
version = 0.0.0
# After
[metadata]
version = 1.2.3
```
### JSON File Updates
Update version in JSON files:
```toml
[tool.hatch.build.hooks.version]
path = "package.json"
template = ' "version": "{version}",'
pattern = ' "version": "[^"]*",'
```
## Integration Patterns
### With Dynamic Version Sources
Works seamlessly with all version sources:
```toml
[project]
name = "my-package"
dynamic = ["version"]
[tool.hatch.version]
source = "regex"
path = "VERSION"
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
```
Build process:
1. Read version from `VERSION` file
2. Write version to `_version.py`
3. Include both in package
### With Environment Variables
Perfect for CI/CD:
```toml
[tool.hatch.version]
source = "env"
variable = "BUILD_VERSION"
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
```
```bash
BUILD_VERSION=1.2.3 hatch build
# Creates _version.py with version 1.2.3
```
### Multiple Version Files
Create multiple version files:
```toml
# Primary version file
[tool.hatch.build.hooks.version]
path = "src/my_package/_version.py"
# Additional version files via custom hook
[tool.hatch.build.hooks.custom]
path = "hatch_build.py"
```
```python
# hatch_build.py
from pathlib import Path
def initialize(version, build_config):
"""Create additional version files."""
# Create version.txt
version_txt = Path("src/my_package/version.txt")
version_txt.write_text(version)
# Create VERSION file
version_file = Path("VERSION")
version_file.write_text(version)
```
## Runtime Version Access
### Method 1: Import Version File
```python
# src/my_package/__init__.py
try:
from ._version import __version__
except ImportError:
__version__ = "unknown"
```
### Method 2: With Fallback
```python
# src/my_package/__init__.py
try:
from ._version import __version__
except ImportError:
# Development mode - version file not created yet
try:
from importlib import metadata
__version__ = metadata.version("my-package")
except Exception:
__version__ = "0.0.0+dev"
```
### Method 3: Version Module
```python
# src/my_package/version.py (created by hook)
__version__ = "1.2.3"
# src/my_package/__init__.py
from .version import __version__
```
## Build Target Specific Hooks
### Different Files for Different Targets
```toml
# Wheel gets compiled version
[tool.hatch.build.targets.wheel.hooks.version]
path = "src/my_package/_version.py"
template = '__version__ = "{version}"'
# Source distribution gets detailed version
[tool.hatch.build.targets.sdist.hooks.version]
path = "src/my_package/_version_full.py"
template = '''
__version__ = "{version}"
__version_tuple__ = {version_tuple}
__build_date__ = "2024-01-01"
'''
```
### Conditional Hook Activation
```toml
# Only for wheel builds
[tool.hatch.build.targets.wheel]
hooks = ["version"]
# No version hook for sdist
[tool.hatch.build.targets.sdist]
hooks = [] # Explicitly no hooks
```
## Advanced Usage
### Dynamic Path
Use context formatting for paths:
```toml
[tool.hatch.build.hooks.version]
path = "src/{name}/_version.py" # Uses project name
```
### Version File in Multiple Locations
For monorepos or complex projects:
```python
# hatch_build.py
from pathlib import Path
def initialize(version, build_config):
"""Write version to multiple locations."""
locations = [
"packages/core/version.py",
"packages/cli/version.py",
"packages/api/version.py",
]
template = f'__version__ = "{version}"'
for location in locations:
path = Path(location)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(template)
```
### Version with Build Metadata
Include build information:
```python
# hatch_build.py
import os
from datetime import datetime
from pathlib import Path
def initialize(version, build_config):
"""Create version file with build metadata."""
build_info = {
"version": version,
"build_date": datetime.now().isoformat(),
"build_host": os.environ.get("HOSTNAME", "unknown"),
"build_user": os.environ.get("USER", "unknown"),
"ci_build": os.environ.get("CI", "false"),
}
template = f"""
# Automatically generated build information
__version__ = "{build_info['version']}"
__build_date__ = "{build_info['build_date']}"
__build_host__ = "{build_info['build_host']}"
__build_user__ = "{build_info['build_user']}"
__ci_build__ = {build_info['ci_build']}
"""
version_file = Path("src/my_package/_build_info.py")
version_file.write_text(template)
```
## Development Workflow
### Editable Installs
Version files are NOT created during editable installs:
```bash
# Editable install
$ pip install -e .
# No _version.py created
# Regular install
$ pip install .
# _version.py is created
```
Handle this in your code:
```python
try:
from ._version import __version__
except ImportError:
# In development mode
__version__ = "0.0.0+dev"
```
### Git Ignore
Add generated version files to `.gitignore`:
```gitignore
# Generated version files
src/my_package/_version.py
*/_version.py
*/_build_info.py
```
### Pre-commit Hook
Ensure version files aren't committed:
```yaml
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: check-version-file
name: Check version file not committed
entry: sh -c 'test ! -f src/my_package/_version.py'
language: system
files: _version\.py$
pass_filenames: false
```
## Troubleshooting
### File Not Created
Issue: Version file missing after build
Check:
1. Hook is enabled in configuration
2. Path is correct and parent directories exist
3. No errors during build process
```bash
# Debug build
$ hatch build -v
# Look for version hook execution
```
### Template Syntax Error
Issue: Invalid template format
```toml
# Wrong - missing quotes
template = __version__ = {version}
# Correct
template = '__version__ = "{version}"'
```
### Pattern Not Matching
Issue: Existing file not updated
Debug pattern:
```python
import re
pattern = r"__version__ = ['\"](?P<version>[^'\"]+)['\"]"
content = open("src/my_package/__init__.py").read()
match = re.search(pattern, content)
print(f"Match: {match.group('version') if match else 'No match'}")
```
### Version Import Error
Issue: Can't import version at runtime
Solutions:
1. Ensure version file is included in package
2. Check import path is correct
3. Add try/except for development mode
## Best Practices
### 1. Use Dedicated Version Files
Keep version separate from other code:
```toml
# Good
path = "src/my_package/_version.py"
# Less ideal
path = "src/my_package/__init__.py" # Mixed with other code
```
### 2. Include Fallbacks
Always handle missing version files:
```python
try:
from ._version import __version__
except ImportError:
__version__ = "unknown"
```
### 3. Document Generated Files
Add header to templates:
```toml
template = '''
# This file is automatically generated by the build process.
# Do not edit manually.
__version__ = "{version}"
'''
```
### 4. Test Version Access
Add tests for version availability:
```python
def test_version():
"""Test that version is accessible."""
import my_package
assert hasattr(my_package, "__version__")
assert my_package.__version__ != "unknown"
```
## See Also
- [Dynamic Version Sources](./dynamic-version-overview.md)
- [Build Configuration](./build-configuration.md)
- [Custom Build Hooks](./custom-build-hooks.md)
- [Version CLI Commands](./version-cli.md)
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.