CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-poetry-core

Poetry PEP 517 Build Backend for building Python packages with lightweight, compliant, self-contained build system

Pending
Overview
Eval results
Files

version-system.mddocs/

PEP 440 Version and Environment Markers

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.

Core Imports

# 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

docs

build-backend.md

builders.md

configuration.md

constraints.md

factory-core.md

index.md

json-validation.md

packages.md

utilities.md

vcs-support.md

version-system.md

tile.json