Regex Version Source
The regex version source is the default version source plugin in Hatchling. It extracts version information from files using regular expressions, providing a simple yet powerful method for managing versions stored as strings in Python files or other text formats.
Basic Configuration
The regex source is used by default when you specify dynamic versioning:
[project]
name = "my-package"
dynamic = ["version"]
[tool.hatch.version]
path = "src/my_package/__about__.py"
# source = "regex" # Optional, as regex is the default
Configuration Options
Required Options
| Option | Type | Description |
|---|---|---|
path |
string | Relative path to the file containing the version |
Optional Options
| Option | Type | Default | Description |
|---|---|---|---|
pattern |
string/bool | true |
Regular expression pattern to match version |
source |
string | "regex" |
Explicitly specify the source type |
Default Pattern
When pattern is not specified or set to true, Hatchling uses a default pattern that matches common Python version declarations:
# Default pattern matches these formats:
__version__ = "1.2.3"
__version__ = '1.2.3'
VERSION = "1.2.3"
VERSION = '1.2.3'
version = "1.2.3"
version = '1.2.3'
__version__: str = "1.2.3" # Type hints supported
VERSION: Final[str] = "1.2.3" # Final annotations supported
The default pattern in regex form:
(?i)(?:__version__|version)\s*(?::\s*(?:str|Final\[str\]))?\s*=\s*['\"]v?(?P<version>[^'\"]+)['\"]
Custom Patterns
Basic Custom Pattern
Specify a custom regex pattern with a named group version:
[tool.hatch.version]
path = "src/my_package/__init__.py"
pattern = "VERSION = ['\"](?P<version>[^'\"]+)['\"]"
Pattern with Version Prefix
Handle version strings with prefixes:
[tool.hatch.version]
path = "setup.cfg"
pattern = "version = v(?P<version>.+)"
Matches:
[metadata]
version = v1.2.3
Multi-line Pattern
Use verbose regex for complex patterns:
[tool.hatch.version]
path = "src/config.py"
pattern = """(?x)
\\#\\s*Version:\\s* # Comment: Version:
(?P<version>\\S+) # Capture non-whitespace as version
"""
Matches:
# Version: 1.2.3
JSON File Pattern
Extract version from JSON files:
[tool.hatch.version]
path = "package.json"
pattern = '"version":\\s*"(?P<version>[^"]+)"'
Matches:
{
"name": "my-package",
"version": "1.2.3"
}
Common Use Cases
Single Version File
The most common pattern - a dedicated version file:
[tool.hatch.version]
path = "src/my_package/_version.py"
# src/my_package/_version.py
__version__ = "1.2.3"
Version in init.py
Store version in the package's __init__.py:
[tool.hatch.version]
path = "src/my_package/__init__.py"
pattern = "__version__ = ['\"](?P<version>[^'\"]+)['\"]"
# src/my_package/__init__.py
"""My package description."""
__version__ = "1.2.3"
__author__ = "Your Name"
Version with Metadata
Include additional version metadata:
[tool.hatch.version]
path = "src/my_package/__about__.py"
pattern = "__version__ = ['\"](?P<version>[^'\"]+)['\"]"
# src/my_package/__about__.py
__version__ = "1.2.3"
__version_info__ = (1, 2, 3)
__version_date__ = "2024-01-01"
Multiple Version Formats
When your file contains multiple version-like strings:
[tool.hatch.version]
path = "src/config.py"
pattern = "^PACKAGE_VERSION = ['\"](?P<version>[^'\"]+)['\"]"
# src/config.py
API_VERSION = "v1" # Not matched
PACKAGE_VERSION = "1.2.3" # Matched
PROTOCOL_VERSION = "2.0" # Not matched
Version Updates
The regex source supports updating versions using the hatch version command:
Simple Update
$ hatch version patch
Old: 1.2.3
New: 1.2.4
The file is updated in place:
# Before
__version__ = "1.2.3"
# After
__version__ = "1.2.4"
Preserving File Structure
The regex source preserves:
- Whitespace and formatting
- Comments
- Other content in the file
- Quote style (single vs double)
# Before update
"""Package metadata."""
__version__ = '1.2.3' # Current version
__author__ = "Name"
# After `hatch version 2.0.0`
"""Package metadata."""
__version__ = '2.0.0' # Current version
__author__ = "Name"
Advanced Patterns
Capturing Version Parts
Use groups to capture version components:
[tool.hatch.version]
path = "version.txt"
pattern = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
Note: Only the version group is used; other groups are for matching only.
Conditional Patterns
Match different version formats:
[tool.hatch.version]
path = "src/version.py"
pattern = "(?:__version__|VERSION)\\s*=\\s*['\"](?P<version>[^'\"]+)['\"]"
Matches both:
__version__ = "1.2.3"
# or
VERSION = "1.2.3"
With Type Annotations
Support modern Python with type hints:
[tool.hatch.version]
path = "src/my_package/__init__.py"
pattern = "__version__:\\s*(?:Final\\[)?str\\]?\\s*=\\s*['\"](?P<version>[^'\"]+)['\"]"
Matches:
__version__: str = "1.2.3"
__version__: Final[str] = "1.2.3"
Working with Different File Types
Python Files
Standard Python version declarations:
# __about__.py
__version__ = "1.2.3"
Configuration Files
INI/TOML style configurations:
[tool.hatch.version]
path = "setup.cfg"
pattern = "version\\s*=\\s*(?P<version>.+)"
Markdown Files
Extract version from documentation:
[tool.hatch.version]
path = "README.md"
pattern = "Version:\\s*(?P<version>\\S+)"
Shell Scripts
Version in shell scripts:
[tool.hatch.version]
path = "scripts/version.sh"
pattern = "VERSION=\"(?P<version>[^\"]+)\""
Error Handling
Pattern Not Matching
When your pattern doesn't match:
$ hatch version
Error: Unable to find version string in 'src/my_package/__about__.py'
Debug with a test script:
import re
from pathlib import Path
pattern = r"__version__ = ['\"](?P<version>[^'\"]+)['\"]"
content = Path("src/my_package/__about__.py").read_text()
if match := re.search(pattern, content):
print(f"Found version: {match.group('version')}")
else:
print("Pattern did not match")
print(f"File content:\n{content}")
Multiple Matches
When pattern matches multiple times:
# File with multiple matches
__version__ = "1.2.3" # First match (used)
old_version = "1.2.2" # Second match (ignored)
The regex source uses the first match found.
File Not Found
[tool.hatch.version]
path = "non/existent/file.py"
Error:
Error: Version source path 'non/existent/file.py' does not exist
Best Practices
1. Maintain Simple Patterns
Keep regex patterns straightforward and readable:
# Good: Simple and clear
pattern = "__version__ = ['\"](?P<version>[^'\"]+)['\"]"
# Avoid: Overly complex
pattern = "(?:(?:__)?(?:version|VERSION)(?:__)?)\\s*(?::|=)\\s*(?:['\"])?(?P<version>[^'\"\\s]+)"
2. Validate Patterns Before Deployment
Test patterns thoroughly before committing to the project:
# test_pattern.py
import re
pattern = r"__version__ = ['\"](?P<version>[^'\"]+)['\"]"
test_content = '__version__ = "1.2.3"'
match = re.search(pattern, test_content)
assert match, "Pattern doesn't match"
assert match.group("version") == "1.2.3"
3. Prefer Dedicated Version Files
Use dedicated version files rather than embedding versions in package code:
# Recommended
path = "src/my_package/_version.py"
# Less ideal
path = "src/my_package/__init__.py" # Mixed with other code
4. Document Custom Pattern Logic
When using non-standard patterns, document the reasoning:
[tool.hatch.version]
path = "version.txt"
# Custom pattern to match our versioning format: "Release: X.Y.Z"
pattern = "Release:\\s*(?P<version>\\S+)"
Performance Considerations
The regex source is fast because it:
- Only reads the specified file (not the entire project)
- Stops searching after first match
- Doesn't execute any code (unlike code source)
- Uses compiled regular expressions
Comparison with Code Source
| Feature | Regex Source | Code Source |
|---|---|---|
| Performance | Fast | Slower (imports Python) |
| Flexibility | Pattern-based | Full Python logic |
| File Types | Any text file | Python files only |
| Dependencies | None | May have imports |
| Complexity | Simple patterns | Arbitrary complexity |
| Default | Yes | No |
Migration Examples
From setuptools
# Old: setup.py
with open("src/my_package/_version.py") as f:
version = re.search(r'__version__ = ["']([^"']+)', f.read()).group(1)
setup(
version=version,
...
)
# New: pyproject.toml
[tool.hatch.version]
path = "src/my_package/_version.py"
From bumpversion
# Old: .bumpversion.cfg
[bumpversion]
current_version = 1.2.3
files = src/my_package/__init__.py
# New: pyproject.toml
[tool.hatch.version]
path = "src/my_package/__init__.py"
Troubleshooting
Issue: Special Characters in Pattern
Problem: Regex special characters not escaped
# Wrong
pattern = "__version__ = "(?P<version>[^"]+)""
# Correct (escape quotes)
pattern = "__version__ = \"(?P<version>[^\"]+)\""
Issue: Windows Path Separators
Problem: Backslashes in Windows paths
# Use forward slashes (works on all platforms)
path = "src/my_package/__about__.py"
# Not: src\my_package\__about__.py
Issue: Unicode in Version Files
The regex source handles Unicode correctly:
# Supported
__version__ = "1.2.3" # ASCII
__версия__ = "1.2.3" # Cyrillic
__版本__ = "1.2.3" # Chinese
See Also
- Code Version Source - For complex version logic
- Environment Version Source - For CI/CD workflows
- Version Build Hook - Write versions during build
- Version CLI Commands - Command-line version management