Poetry PEP 517 Build Backend for building Python packages with lightweight, compliant, self-contained build system
—
Poetry Core provides a comprehensive constraint system for handling version requirements and generic constraints. This includes PEP 440-compliant version constraints, Poetry-specific syntax (caret and tilde), and generic constraint operations.
# Version constraints
from poetry.core.constraints.version import (
Version,
VersionConstraint,
VersionRange,
VersionRangeConstraint,
VersionUnion,
EmptyConstraint,
parse_constraint,
parse_marker_version_constraint,
constraint_regions
)
# Generic constraints
from poetry.core.constraints.generic import (
BaseConstraint,
Constraint,
AnyConstraint,
EmptyConstraint as GenericEmptyConstraint,
MultiConstraint,
UnionConstraint,
parse_constraint as parse_generic_constraint,
parse_extra_constraint
)
``` { .api }
## Version Constraints
Version constraints handle PEP 440 version specifications with additional Poetry syntax support.
### parse_constraint
```python
def parse_constraint(constraints: str) -> VersionConstraint:
"""
Parse string version constraints into constraint objects.
Args:
constraints: Version constraint string supporting various formats:
- PEP 440: ">=1.2.0,<2.0.0", "==1.5.*", "~=1.4.2"
- Poetry caret: "^1.2.0" (compatible release)
- Poetry tilde: "~1.2.0" (reasonably close)
- Wildcards: "1.2.*"
- Multiple: ">=1.0,<2.0,!=1.5"
Returns:
VersionConstraint object (Version, VersionRange, VersionUnion, etc.)
Raises:
ParseConstraintError: If constraint string is malformed
Examples:
>>> constraint = parse_constraint("^1.2.0")
>>> print(constraint) # >=1.2.0,<2.0.0
>>> constraint = parse_constraint("~1.2.3")
>>> print(constraint) # >=1.2.3,<1.3.0
>>> constraint = parse_constraint(">=2.0,<3.0,!=2.5")
>>> isinstance(constraint, VersionUnion)
True
"""
``` { .api }
### parse_marker_version_constraint
```python
def parse_marker_version_constraint(constraint: str) -> VersionConstraint:
"""
Parse version constraints from PEP 508 environment markers.
Args:
constraint: Version constraint from marker context
Returns:
VersionConstraint suitable for marker evaluation
Example:
>>> # From marker: python_version >= "3.8"
>>> constraint = parse_marker_version_constraint("3.8")
>>> print(constraint)
"""
``` { .api }
### constraint_regions
```python
def constraint_regions(constraints: list[VersionConstraint]) -> list[VersionRange]:
"""
Analyze constraint regions for optimization and conflict detection.
Args:
constraints: List of version constraints to analyze
Returns:
List of VersionRange objects representing constraint regions
Note:
Utility function for advanced constraint analysis and optimization.
"""
``` { .api }
## Version Constraint Classes
### Version
```python
class Version(PEP440Version, VersionRangeConstraint):
"""
Concrete version implementation with PEP 440 compliance and constraints.
Combines PEP 440 version parsing with constraint satisfaction logic.
Supports all PEP 440 version formats including pre-releases, dev releases,
and local versions.
"""
@classmethod
def parse(cls, version: str) -> Version:
"""
Parse version string into Version object.
Args:
version: PEP 440 compliant version string
Returns:
Version instance
Example:
>>> v = Version.parse("1.2.3")
>>> v = Version.parse("2.0.0a1") # alpha
>>> v = Version.parse("1.0.0.dev0") # dev
"""
def allows(self, other: Version) -> bool:
"""Check if this version allows another version (equality)."""
def intersect(self, other: VersionConstraint) -> VersionConstraint:
"""Create intersection with another constraint."""
def union(self, other: VersionConstraint) -> VersionConstraint:
"""Create union with another constraint."""
``` { .api }
### VersionRange
```python
class VersionRange(VersionRangeConstraint):
"""
Represents a range of versions with minimum and maximum bounds.
Supports inclusive and exclusive bounds, unbounded ranges,
and complex range operations.
"""
def __init__(
self,
min_version: Version | None = None,
max_version: Version | None = None,
include_min: bool = True,
include_max: bool = False,
) -> None:
"""
Create version range.
Args:
min_version: Minimum version (None for unbounded)
max_version: Maximum version (None for unbounded)
include_min: Whether minimum is inclusive
include_max: Whether maximum is inclusive
Example:
>>> # >=1.0.0,<2.0.0
>>> range1 = VersionRange(
... Version.parse("1.0.0"),
... Version.parse("2.0.0")
... )
>>> # >1.0.0,<=1.5.0
>>> range2 = VersionRange(
... Version.parse("1.0.0"),
... Version.parse("1.5.0"),
... include_min=False,
... include_max=True
... )
"""
@property
def min(self) -> Version | None:
"""Minimum version bound."""
@property
def max(self) -> Version | None:
"""Maximum version bound."""
def allows(self, version: Version) -> bool:
"""Check if version falls within this range."""
def intersect(self, other: VersionConstraint) -> VersionConstraint:
"""Create intersection with another constraint."""
def union(self, other: VersionConstraint) -> VersionConstraint:
"""Create union with another constraint."""
``` { .api }
### VersionUnion
```python
class VersionUnion(VersionConstraint):
"""
Union of multiple version constraints (OR operation).
Represents constraints like ">=1.0,<2.0 || >=3.0,<4.0" where
a version can satisfy any of the constituent constraints.
"""
def __init__(self, *constraints: VersionConstraint) -> None:
"""
Create union of constraints.
Args:
constraints: Version constraints to union
Example:
>>> range1 = VersionRange(Version.parse("1.0.0"), Version.parse("2.0.0"))
>>> range2 = VersionRange(Version.parse("3.0.0"), Version.parse("4.0.0"))
>>> union = VersionUnion(range1, range2)
"""
@property
def constraints(self) -> tuple[VersionConstraint, ...]:
"""Constituent constraints in the union."""
def allows(self, version: Version) -> bool:
"""Check if version satisfies any constraint in union."""
``` { .api }
### EmptyConstraint
```python
class EmptyConstraint(VersionConstraint):
"""
Version constraint representing no valid versions.
Used when constraints are impossible to satisfy or
when explicitly excluding all versions.
"""
def allows(self, version: Version) -> bool:
"""Always returns False - no versions allowed."""
def is_empty(self) -> bool:
"""Always returns True."""
``` { .api }
## Generic Constraints
Generic constraints provide a framework for non-version constraint operations.
### parse_constraint (Generic)
```python
def parse_constraint(constraints: str) -> BaseConstraint:
"""
Parse string constraints into generic constraint objects.
Args:
constraints: Constraint string
Returns:
BaseConstraint implementation
Example:
>>> constraint = parse_constraint("foo")
>>> constraint = parse_constraint("foo,bar") # Multi-constraint
"""
``` { .api }
### parse_extra_constraint
```python
def parse_extra_constraint(constraints: str) -> BaseConstraint:
"""
Parse extra/optional feature constraints.
Args:
constraints: Extra constraint string (e.g., "dev,test")
Returns:
BaseConstraint for extra matching
Example:
>>> extra_constraint = parse_extra_constraint("dev,test")
>>> # Used for conditional dependencies
"""
``` { .api }
## Generic Constraint Classes
### BaseConstraint
```python
class BaseConstraint:
"""
Abstract base class for all constraint types.
Defines the interface that all constraints must implement
for matching, intersection, and union operations.
"""
def allows(self, other: Any) -> bool:
"""Check if constraint allows a value."""
def intersect(self, other: BaseConstraint) -> BaseConstraint:
"""Create intersection with another constraint."""
def union(self, other: BaseConstraint) -> BaseConstraint:
"""Create union with another constraint."""
def is_any(self) -> bool:
"""Check if constraint matches any value."""
def is_empty(self) -> bool:
"""Check if constraint matches no values."""
``` { .api }
### Constraint
```python
class Constraint(BaseConstraint):
"""
Basic constraint implementation for exact matching.
Matches values exactly against a stored constraint value.
"""
def __init__(self, constraint: str) -> None:
"""
Create constraint with exact matching value.
Args:
constraint: Value to match exactly
"""
@property
def constraint(self) -> str:
"""The constraint value."""
``` { .api }
### AnyConstraint
```python
class AnyConstraint(BaseConstraint):
"""
Constraint that matches any value.
Represents the absence of constraints - all values are valid.
"""
def allows(self, other: Any) -> bool:
"""Always returns True - allows any value."""
def is_any(self) -> bool:
"""Always returns True."""
``` { .api }
### EmptyConstraint (Generic)
```python
class EmptyConstraint(BaseConstraint):
"""
Generic constraint matching no values.
Represents impossible or explicitly empty constraints.
"""
def allows(self, other: Any) -> bool:
"""Always returns False - allows no values."""
def is_empty(self) -> bool:
"""Always returns True."""
``` { .api }
### MultiConstraint
```python
class MultiConstraint(BaseConstraint):
"""
Conjunction of multiple constraints (AND operation).
All constituent constraints must be satisfied.
"""
def __init__(self, *constraints: BaseConstraint) -> None:
"""
Create conjunction of constraints.
Args:
constraints: Constraints that must all be satisfied
"""
@property
def constraints(self) -> tuple[BaseConstraint, ...]:
"""Constituent constraints."""
def allows(self, other: Any) -> bool:
"""Check if all constraints allow the value."""
``` { .api }
### UnionConstraint
```python
class UnionConstraint(BaseConstraint):
"""
Disjunction of multiple constraints (OR operation).
Any constituent constraint can be satisfied.
"""
def __init__(self, *constraints: BaseConstraint) -> None:
"""
Create disjunction of constraints.
Args:
constraints: Constraints where any can be satisfied
"""
@property
def constraints(self) -> tuple[BaseConstraint, ...]:
"""Constituent constraints."""
def allows(self, other: Any) -> bool:
"""Check if any constraint allows the value."""
``` { .api }
## Usage Examples
### Basic Version Constraint Parsing
```python
from poetry.core.constraints.version import parse_constraint, Version
def demonstrate_version_constraints():
"""Show various version constraint formats."""
# Poetry caret constraint (compatible release)
caret = parse_constraint("^1.2.0")
print(f"Caret ^1.2.0: {caret}") # >=1.2.0,<2.0.0
# Poetry tilde constraint (reasonably close)
tilde = parse_constraint("~1.2.3")
print(f"Tilde ~1.2.3: {tilde}") # >=1.2.3,<1.3.0
# PEP 440 constraints
pep440 = parse_constraint(">=1.0,<2.0,!=1.5")
print(f"PEP 440: {pep440}")
# Wildcard constraints
wildcard = parse_constraint("1.2.*")
print(f"Wildcard: {wildcard}")
# Test version satisfaction
version = Version.parse("1.2.5")
print(f"Version {version} satisfies caret: {caret.allows(version)}")
print(f"Version {version} satisfies tilde: {tilde.allows(version)}")
demonstrate_version_constraints()
``` { .api }
### Complex Constraint Operations
```python
from poetry.core.constraints.version import parse_constraint, VersionUnion
def constraint_operations():
"""Demonstrate constraint intersection and union."""
# Create individual constraints
constraint1 = parse_constraint(">=1.0.0")
constraint2 = parse_constraint("<3.0.0")
constraint3 = parse_constraint("!=2.0.0")
# Intersection (AND) - must satisfy all
intersection = constraint1.intersect(constraint2).intersect(constraint3)
print(f"Intersection: {intersection}") # >=1.0.0,<3.0.0,!=2.0.0
# Union (OR) - can satisfy any
union = constraint1.union(constraint3)
print(f"Union: {union}")
# Test complex constraint
test_versions = ["0.9.0", "1.5.0", "2.0.0", "2.5.0", "3.5.0"]
print(f"\nTesting intersection ({intersection}):")
for version_str in test_versions:
version = Version.parse(version_str)
satisfies = intersection.allows(version)
print(f" {version}: {'✓' if satisfies else '✗'}")
constraint_operations()
``` { .api }
### Building Custom Constraints
```python
from poetry.core.constraints.version import Version, VersionRange, VersionUnion
def build_custom_constraints():
"""Build constraints programmatically."""
# Create version range manually
min_version = Version.parse("2.0.0")
max_version = Version.parse("3.0.0")
range1 = VersionRange(
min_version=min_version,
max_version=max_version,
include_min=True, # >=2.0.0
include_max=False # <3.0.0
)
# Create another range
range2 = VersionRange(
min_version=Version.parse("4.0.0"),
max_version=Version.parse("5.0.0"),
include_min=True,
include_max=False
)
# Combine ranges with union
combined = VersionUnion(range1, range2)
print(f"Combined constraint: {combined}")
# Allows: >=2.0.0,<3.0.0 || >=4.0.0,<5.0.0
# Test versions against combined constraint
test_versions = ["1.5.0", "2.5.0", "3.5.0", "4.5.0", "5.5.0"]
for version_str in test_versions:
version = Version.parse(version_str)
allowed = combined.allows(version)
print(f"{version}: {'allowed' if allowed else 'rejected'}")
build_custom_constraints()
``` { .api }
### Generic Constraint Usage
```python
from poetry.core.constraints.generic import (
parse_constraint,
MultiConstraint,
UnionConstraint,
AnyConstraint
)
def demonstrate_generic_constraints():
"""Show generic constraint operations."""
# Parse simple constraints
constraint1 = parse_constraint("development")
constraint2 = parse_constraint("testing")
# Create multi-constraint (AND)
both_required = MultiConstraint(constraint1, constraint2)
print(f"Must have both: {both_required}")
# Create union constraint (OR)
either_allowed = UnionConstraint(constraint1, constraint2)
print(f"Can have either: {either_allowed}")
# Any constraint (no restrictions)
any_constraint = AnyConstraint()
print(f"Any allowed: {any_constraint.is_any()}")
# Test constraint matching
print(f"'development' satisfies both_required: {both_required.allows('development')}")
print(f"'testing' satisfies either_allowed: {either_allowed.allows('testing')}")
demonstrate_generic_constraints()
``` { .api }
### Poetry Constraint Syntax
```python
def poetry_syntax_examples():
"""Demonstrate Poetry-specific constraint syntax."""
constraints = {
"^1.2.3": "Caret - compatible release (>=1.2.3,<2.0.0)",
"~1.2.3": "Tilde - reasonably close (>=1.2.3,<1.3.0)",
"^0.2.3": "Caret with 0.x (>=0.2.3,<0.3.0)",
"^0.0.3": "Caret with 0.0.x (>=0.0.3,<0.0.4)",
"~1.2": "Tilde major.minor (>=1.2.0,<1.3.0)",
"1.2.*": "Wildcard (>=1.2.0,<1.3.0)",
">=1.2,<2.0": "Range constraint",
"!=1.5": "Exclusion constraint"
}
print("Poetry Constraint Syntax:")
for syntax, description in constraints.items():
try:
parsed = parse_constraint(syntax)
print(f"{syntax:15} -> {parsed} ({description})")
except Exception as e:
print(f"{syntax:15} -> ERROR: {e}")
poetry_syntax_examples()
``` { .api }
## Error Handling
```python
from poetry.core.exceptions import ParseConstraintError
from poetry.core.constraints.version import parse_constraint
def safe_constraint_parsing(constraint_str: str):
"""Safely parse constraints with error handling."""
try:
constraint = parse_constraint(constraint_str)
return constraint
except ParseConstraintError as e:
print(f"Invalid constraint '{constraint_str}': {e}")
return None
except Exception as e:
print(f"Unexpected error parsing '{constraint_str}': {e}")
return None
# Usage
constraints_to_test = [
"^1.2.0", # Valid
">=1.0,<2.0", # Valid
"invalid", # Invalid
"^", # Invalid
"1.2.3.4.5" # Invalid
]
for constraint_str in constraints_to_test:
result = safe_constraint_parsing(constraint_str)
if result:
print(f"✓ {constraint_str} -> {result}")
else:
print(f"✗ {constraint_str} -> Failed to parse")
``` { .api }Install with Tessl CLI
npx tessl i tessl/pypi-poetry-core