Poetry PEP 517 Build Backend for building Python packages with lightweight, compliant, self-contained build system
—
Poetry Core provides comprehensive support for PEP 440 version specifications and PEP 508 environment markers. This enables precise version handling and conditional dependency specification based on the installation environment.
# PEP 440 version components
from poetry.core.version.pep440 import (
PEP440Version,
Release,
ReleaseTag,
LocalSegmentType
)
# Environment markers
from poetry.core.version.markers import (
BaseMarker,
AnyMarker,
EmptyMarker,
SingleMarker,
MultiMarker,
MarkerUnion,
parse_marker,
intersection,
union
)
# Marker exceptions
from poetry.core.version.markers import (
InvalidMarkerError,
UndefinedComparisonError,
UndefinedEnvironmentNameError
)
``` { .api }
## PEP 440 Version Implementation
### PEP440Version
```python
class PEP440Version:
"""
Core PEP 440 version implementation.
Supports all PEP 440 version formats including:
- Release versions: 1.2.3, 2.0.0
- Pre-releases: 1.0.0a1, 2.0.0b2, 1.5.0rc1
- Post-releases: 1.0.0.post1
- Development releases: 1.0.0.dev0
- Local versions: 1.0.0+local.1
"""
@classmethod
def parse(cls, version: str) -> PEP440Version:
"""
Parse version string into PEP440Version object.
Args:
version: PEP 440 compliant version string
Returns:
PEP440Version instance
Raises:
InvalidVersionError: If version string is not PEP 440 compliant
Examples:
>>> v1 = PEP440Version.parse("1.2.3")
>>> v2 = PEP440Version.parse("2.0.0a1") # Alpha pre-release
>>> v3 = PEP440Version.parse("1.0.0.post1") # Post-release
>>> v4 = PEP440Version.parse("1.0.0.dev0") # Development
>>> v5 = PEP440Version.parse("1.0.0+local") # Local version
"""
@property
def epoch(self) -> int:
"""Version epoch (defaults to 0)."""
@property
def release(self) -> Release:
"""Release version tuple (e.g., (1, 2, 3))."""
@property
def pre(self) -> ReleaseTag | None:
"""Pre-release information (alpha, beta, rc)."""
@property
def post(self) -> int | None:
"""Post-release number."""
@property
def dev(self) -> int | None:
"""Development release number."""
@property
def local(self) -> str | None:
"""Local version identifier."""
@property
def is_prerelease(self) -> bool:
"""Whether version is a pre-release."""
@property
def is_postrelease(self) -> bool:
"""Whether version is a post-release."""
@property
def is_devrelease(self) -> bool:
"""Whether version is a development release."""
def __str__(self) -> str:
"""String representation of version."""
def __eq__(self, other: object) -> bool:
"""Version equality comparison."""
def __lt__(self, other: PEP440Version) -> bool:
"""Version less-than comparison."""
def __le__(self, other: PEP440Version) -> bool:
"""Version less-than-or-equal comparison."""
def __gt__(self, other: PEP440Version) -> bool:
"""Version greater-than comparison."""
def __ge__(self, other: PEP440Version) -> bool:
"""Version greater-than-or-equal comparison."""
``` { .api }
### Release
```python
class Release:
"""
Version release component representing the main version tuple.
Handles version tuples like (1, 2, 3) with proper comparison
and normalization according to PEP 440.
"""
def __init__(self, *parts: int) -> None:
"""
Create release version.
Args:
parts: Version parts (e.g., 1, 2, 3 for "1.2.3")
Example:
>>> release = Release(1, 2, 3)
>>> print(release) # 1.2.3
"""
@property
def parts(self) -> tuple[int, ...]:
"""Version parts tuple."""
def __str__(self) -> str:
"""String representation (e.g., "1.2.3")."""
def __eq__(self, other: object) -> bool:
"""Equality comparison with normalization."""
def __lt__(self, other: Release) -> bool:
"""Less-than comparison."""
``` { .api }
### ReleaseTag
```python
class ReleaseTag:
"""
Pre-release tag information (alpha, beta, release candidate).
Represents pre-release versions like 1.0.0a1, 2.0.0b2, 1.5.0rc1
with proper ordering and normalization.
"""
def __init__(self, tag: str, number: int) -> None:
"""
Create release tag.
Args:
tag: Tag type ("a", "b", "rc" or full forms)
number: Tag number
Example:
>>> alpha = ReleaseTag("a", 1) # alpha 1
>>> beta = ReleaseTag("b", 2) # beta 2
>>> rc = ReleaseTag("rc", 1) # release candidate 1
"""
@property
def tag(self) -> str:
"""Normalized tag type ("a", "b", "rc")."""
@property
def number(self) -> int:
"""Tag number."""
def __str__(self) -> str:
"""String representation (e.g., "a1", "b2", "rc1")."""
def __eq__(self, other: object) -> bool:
"""Equality comparison."""
def __lt__(self, other: ReleaseTag) -> bool:
"""Less-than comparison (a < b < rc)."""
``` { .api }
### LocalSegmentType
```python
LocalSegmentType = Union[int, str]
"""
Type for local version segments.
Local versions can contain integers and strings separated by dots or hyphens,
like "1.0.0+local.1" or "1.0.0+abc.123".
"""
``` { .api }
## Environment Markers
Environment markers provide conditional dependency installation based on the target environment.
### parse_marker
```python
def parse_marker(marker: str) -> BaseMarker:
"""
Parse PEP 508 environment marker string.
Args:
marker: PEP 508 marker expression
Returns:
BaseMarker implementation representing the parsed marker
Raises:
InvalidMarkerError: If marker syntax is invalid
Examples:
>>> marker = parse_marker("python_version >= '3.8'")
>>> marker = parse_marker("sys_platform == 'win32'")
>>> marker = parse_marker("python_version >= '3.8' and sys_platform != 'win32'")
>>> marker = parse_marker("extra == 'dev'")
"""
``` { .api }
### intersection
```python
def intersection(*markers: BaseMarker) -> BaseMarker:
"""
Create intersection (AND) of multiple markers.
Args:
markers: Markers to intersect
Returns:
BaseMarker representing the intersection
Example:
>>> marker1 = parse_marker("python_version >= '3.8'")
>>> marker2 = parse_marker("sys_platform != 'win32'")
>>> combined = intersection(marker1, marker2)
>>> # Equivalent to: python_version >= '3.8' and sys_platform != 'win32'
"""
``` { .api }
### union
```python
def union(*markers: BaseMarker) -> BaseMarker:
"""
Create union (OR) of multiple markers.
Args:
markers: Markers to union
Returns:
BaseMarker representing the union
Example:
>>> marker1 = parse_marker("sys_platform == 'win32'")
>>> marker2 = parse_marker("sys_platform == 'darwin'")
>>> combined = union(marker1, marker2)
>>> # Equivalent to: sys_platform == 'win32' or sys_platform == 'darwin'
"""
``` { .api }
## Marker Classes
### BaseMarker
```python
class BaseMarker:
"""
Abstract base class for all environment markers.
Provides the interface for marker evaluation, intersection,
and union operations.
"""
@abstractmethod
def intersect(self, other: BaseMarker) -> BaseMarker:
"""Create intersection with another marker."""
@abstractmethod
def union(self, other: BaseMarker) -> BaseMarker:
"""Create union with another marker."""
def is_any(self) -> bool:
"""Check if marker matches any environment."""
def is_empty(self) -> bool:
"""Check if marker matches no environment."""
@property
def complexity(self) -> tuple[int, int]:
"""
Marker complexity metrics for optimization.
Returns:
Tuple of (detailed_count, simplified_count)
"""
def evaluate(self, environment: dict[str, Any] | None = None) -> bool:
"""
Evaluate marker against environment.
Args:
environment: Environment variables dict (uses current if None)
Returns:
True if marker matches the environment
"""
``` { .api }
### AnyMarker
```python
class AnyMarker(BaseMarker):
"""
Marker that matches any environment.
Represents the absence of restrictions - all environments are valid.
"""
def is_any(self) -> bool:
"""Always returns True."""
def evaluate(self, environment: dict[str, Any] | None = None) -> bool:
"""Always returns True."""
def intersect(self, other: BaseMarker) -> BaseMarker:
"""Returns the other marker (intersection with 'any')."""
def union(self, other: BaseMarker) -> BaseMarker:
"""Returns self (union with 'any' is 'any')."""
``` { .api }
### EmptyMarker
```python
class EmptyMarker(BaseMarker):
"""
Marker that matches no environment.
Represents impossible conditions or explicit exclusion.
"""
def is_empty(self) -> bool:
"""Always returns True."""
def evaluate(self, environment: dict[str, Any] | None = None) -> bool:
"""Always returns False."""
def intersect(self, other: BaseMarker) -> BaseMarker:
"""Returns self (intersection with 'empty' is 'empty')."""
def union(self, other: BaseMarker) -> BaseMarker:
"""Returns the other marker (union with 'empty')."""
``` { .api }
### SingleMarker
```python
class SingleMarker(BaseMarker):
"""
Single condition marker (e.g., "python_version >= '3.8'").
Represents a single comparison operation between an environment
variable and a value.
"""
def __init__(self, name: str, constraint: BaseConstraint) -> None:
"""
Create single marker.
Args:
name: Environment variable name
constraint: Constraint to apply to the variable
Example:
>>> from poetry.core.constraints.generic import parse_constraint
>>> marker = SingleMarker("python_version", parse_constraint(">= 3.8"))
"""
@property
def name(self) -> str:
"""Environment variable name."""
@property
def constraint(self) -> BaseConstraint:
"""Constraint applied to the variable."""
def evaluate(self, environment: dict[str, Any] | None = None) -> bool:
"""Evaluate constraint against environment variable."""
``` { .api }
### MultiMarker
```python
class MultiMarker(BaseMarker):
"""
Conjunction of multiple markers (AND operation).
All constituent markers must be satisfied.
"""
def __init__(self, *markers: BaseMarker) -> None:
"""
Create conjunction of markers.
Args:
markers: Markers that must all be satisfied
Example:
>>> marker1 = parse_marker("python_version >= '3.8'")
>>> marker2 = parse_marker("sys_platform != 'win32'")
>>> multi = MultiMarker(marker1, marker2)
"""
@property
def markers(self) -> tuple[BaseMarker, ...]:
"""Constituent markers."""
def evaluate(self, environment: dict[str, Any] | None = None) -> bool:
"""Check if all markers are satisfied."""
``` { .api }
### MarkerUnion
```python
class MarkerUnion(BaseMarker):
"""
Disjunction of multiple markers (OR operation).
Any constituent marker can be satisfied.
"""
def __init__(self, *markers: BaseMarker) -> None:
"""
Create disjunction of markers.
Args:
markers: Markers where any can be satisfied
Example:
>>> marker1 = parse_marker("sys_platform == 'win32'")
>>> marker2 = parse_marker("sys_platform == 'darwin'")
>>> union = MarkerUnion(marker1, marker2)
"""
@property
def markers(self) -> tuple[BaseMarker, ...]:
"""Constituent markers."""
def evaluate(self, environment: dict[str, Any] | None = None) -> bool:
"""Check if any marker is satisfied."""
``` { .api }
## Environment Variables
### Supported Environment Variables
```python
# Standard PEP 508 environment variables
ENVIRONMENT_VARIABLES = {
"implementation_name", # Python implementation (cpython, pypy, etc.)
"implementation_version", # Implementation version
"os_name", # Operating system name (posix, nt, java)
"platform_machine", # Machine type (x86_64, i386, etc.)
"platform_python_implementation", # Python implementation
"platform_release", # Platform release
"platform_system", # Platform system (Linux, Windows, Darwin)
"platform_version", # Platform version
"python_full_version", # Full Python version (3.9.1)
"python_version", # Python version (3.9)
"sys_platform", # Platform string (linux, win32, darwin)
"extra", # Extra/feature being installed
}
# Variable aliases for compatibility
ALIASES = {
"os.name": "os_name",
"sys.platform": "sys_platform",
"platform.version": "platform_version",
"platform.machine": "platform_machine",
"platform.python_implementation": "platform_python_implementation",
"python_implementation": "platform_python_implementation",
}
``` { .api }
## Usage Examples
### Version Parsing and Comparison
```python
from poetry.core.version.pep440 import PEP440Version
def version_examples():
"""Demonstrate PEP 440 version parsing and comparison."""
# Parse various version formats
versions = [
"1.0.0", # Release
"2.0.0a1", # Alpha pre-release
"1.5.0b2", # Beta pre-release
"2.1.0rc1", # Release candidate
"1.0.0.post1", # Post-release
"2.0.0.dev0", # Development release
"1.0.0+local.1", # Local version
"1!2.0.0", # Epoch version
]
parsed_versions = []
for version_str in versions:
try:
version = PEP440Version.parse(version_str)
parsed_versions.append(version)
print(f"Version: {version}")
print(f" Release: {version.release}")
print(f" Pre-release: {version.pre}")
print(f" Post-release: {version.post}")
print(f" Dev release: {version.dev}")
print(f" Local: {version.local}")
print(f" Is pre-release: {version.is_prerelease}")
print()
except Exception as e:
print(f"Failed to parse '{version_str}': {e}")
# Version comparison
print("Version Comparison:")
sorted_versions = sorted(parsed_versions)
for version in sorted_versions:
print(f" {version}")
version_examples()
``` { .api }
### Environment Marker Parsing
```python
from poetry.core.version.markers import parse_marker
def marker_examples():
"""Demonstrate environment marker parsing and evaluation."""
markers = [
"python_version >= '3.8'",
"sys_platform == 'win32'",
"python_version >= '3.8' and sys_platform != 'win32'",
"python_version < '3.9' or python_version >= '3.10'",
"implementation_name == 'cpython'",
"platform_machine == 'x86_64'",
"extra == 'dev'",
"os_name == 'posix' and platform_system == 'Linux'",
]
print("Parsing Environment Markers:")
for marker_str in markers:
try:
marker = parse_marker(marker_str)
print(f"✓ {marker_str}")
print(f" Type: {type(marker).__name__}")
print(f" Is any: {marker.is_any()}")
print(f" Is empty: {marker.is_empty()}")
except Exception as e:
print(f"✗ {marker_str}: {e}")
print()
marker_examples()
``` { .api }
### Marker Evaluation
```python
import platform
import sys
from poetry.core.version.markers import parse_marker
def evaluate_markers():
"""Evaluate markers against current environment."""
# Get current environment
current_env = {
"implementation_name": sys.implementation.name,
"implementation_version": ".".join(map(str, sys.implementation.version[:2])),
"os_name": os.name,
"platform_machine": platform.machine(),
"platform_python_implementation": platform.python_implementation(),
"platform_release": platform.release(),
"platform_system": platform.system(),
"platform_version": platform.version(),
"python_full_version": ".".join(map(str, sys.version_info)),
"python_version": ".".join(map(str, sys.version_info[:2])),
"sys_platform": sys.platform,
}
print(f"Current Environment:")
for key, value in current_env.items():
print(f" {key}: {value}")
print()
# Test markers
test_markers = [
"python_version >= '3.8'",
"python_version >= '3.12'",
"sys_platform == 'win32'",
"sys_platform == 'linux'",
"implementation_name == 'cpython'",
"implementation_name == 'pypy'",
]
print("Marker Evaluation:")
for marker_str in test_markers:
try:
marker = parse_marker(marker_str)
result = marker.evaluate(current_env)
status = "✓ MATCH" if result else "✗ NO MATCH"
print(f"{status}: {marker_str}")
except Exception as e:
print(f"ERROR: {marker_str} -> {e}")
evaluate_markers()
``` { .api }
### Complex Marker Operations
```python
from poetry.core.version.markers import parse_marker, intersection, union
def complex_marker_operations():
"""Demonstrate complex marker operations."""
# Create individual markers
py38_plus = parse_marker("python_version >= '3.8'")
not_windows = parse_marker("sys_platform != 'win32'")
linux_only = parse_marker("sys_platform == 'linux'")
macos_only = parse_marker("sys_platform == 'darwin'")
# Intersection (AND)
py38_not_win = intersection(py38_plus, not_windows)
print(f"Python 3.8+ AND not Windows: {py38_not_win}")
# Union (OR)
linux_or_macos = union(linux_only, macos_only)
print(f"Linux OR macOS: {linux_or_macos}")
# Complex combination
complex_marker = intersection(py38_plus, linux_or_macos)
print(f"Python 3.8+ AND (Linux OR macOS): {complex_marker}")
# Test evaluation
test_environments = [
{"python_version": "3.9", "sys_platform": "linux"},
{"python_version": "3.7", "sys_platform": "linux"},
{"python_version": "3.9", "sys_platform": "win32"},
{"python_version": "3.9", "sys_platform": "darwin"},
]
print("\nEvaluation Results:")
for env in test_environments:
result = complex_marker.evaluate(env)
py_ver = env["python_version"]
platform = env["sys_platform"]
status = "✓" if result else "✗"
print(f" {status} Python {py_ver} on {platform}")
complex_marker_operations()
``` { .api }
### Practical Dependency Scenarios
```python
from poetry.core.version.markers import parse_marker
def dependency_scenarios():
"""Show practical dependency marker scenarios."""
scenarios = {
"Windows-specific dependency": "sys_platform == 'win32'",
"Unix-only dependency": "os_name == 'posix'",
"Modern Python requirement": "python_version >= '3.8'",
"Legacy Python support": "python_version < '3.8'",
"CPython optimization": "implementation_name == 'cpython'",
"PyPy compatibility": "implementation_name == 'pypy'",
"Development extra": "extra == 'dev'",
"Testing extra": "extra == 'test'",
"macOS ARM64": "sys_platform == 'darwin' and platform_machine == 'arm64'",
"Linux x86_64": "sys_platform == 'linux' and platform_machine == 'x86_64'",
"Not Windows": "sys_platform != 'win32'",
"Python 3.8-3.11": "python_version >= '3.8' and python_version < '3.12'",
}
print("Common Dependency Marker Scenarios:")
print("=" * 50)
for scenario, marker_str in scenarios.items():
try:
marker = parse_marker(marker_str)
print(f"{scenario}:")
print(f" Marker: {marker_str}")
print(f" Parsed: {marker}")
print(f" Type: {type(marker).__name__}")
print()
except Exception as e:
print(f"❌ {scenario}: {e}")
print()
dependency_scenarios()
``` { .api }
## Error Handling
### Marker Exceptions
```python
from poetry.core.version.markers import (
InvalidMarkerError,
UndefinedComparisonError,
UndefinedEnvironmentNameError,
parse_marker
)
def safe_marker_operations():
"""Demonstrate safe marker parsing and evaluation."""
def safe_parse_marker(marker_str: str):
"""Safely parse marker with error handling."""
try:
return parse_marker(marker_str)
except InvalidMarkerError as e:
print(f"Invalid marker syntax '{marker_str}': {e}")
return None
except Exception as e:
print(f"Unexpected error parsing '{marker_str}': {e}")
return None
def safe_evaluate_marker(marker, environment):
"""Safely evaluate marker with error handling."""
try:
return marker.evaluate(environment)
except UndefinedEnvironmentNameError as e:
print(f"Undefined environment variable: {e}")
return False
except UndefinedComparisonError as e:
print(f"Invalid comparison: {e}")
return False
except Exception as e:
print(f"Evaluation error: {e}")
return False
# Test various marker strings
test_markers = [
"python_version >= '3.8'", # Valid
"python_version >= 3.8", # Invalid (no quotes)
"invalid_var == 'test'", # Valid syntax, undefined var
"python_version >> '3.8'", # Invalid operator
"python_version", # Incomplete
"", # Empty
]
print("Safe Marker Operations:")
for marker_str in test_markers:
print(f"\nTesting: '{marker_str}'")
marker = safe_parse_marker(marker_str)
if marker:
env = {"python_version": "3.9"}
result = safe_evaluate_marker(marker, env)
print(f" ✓ Parsed successfully")
print(f" ✓ Evaluation result: {result}")
else:
print(f" ✗ Failed to parse")
safe_marker_operations()
``` { .api }Install with Tessl CLI
npx tessl i tessl/pypi-poetry-core