Constraints expressions are strings representing multiple constraints on a software version. They are defined by this EBNF grammar:
constraints_expression ::= constraint_expression (',' constraint_expression)* constraint_expression ::= operator version_expression operator ::= '==' | '!=' | '>' | '<' | '<=' | '>=' version_expression ::= main | main '-' prerelease main ::= major ('.' minor ('.' patch)?)? major ::= number minor ::= number patch ::= number prerelease ::= string | number build_metadata ::= string number ::= [0-9]+ string ::= [0-9a-zA-Z.-]+
They can be parsed into Constraints objects using the Constraints.parse() class method.
Examples of valid constraint expressions:
>>> from versions import Constraints
>>> c = Constraints.parse('==1.0')
>>> c.constraints
[Constraint.parse('==1.0.0')]
>>> c = Constraints.parse('>=1.0,<2,!=1.5')
>>> c.constraints
[Constraint.parse('!=1.5.0'), Constraint.parse('>=1.0.0'), Constraint.parse('<2.0.0')]
A collection of Constraint objects.
List of Constraint.
Match version with this collection of constraints.
Parameters: | version (version expression or Version) – Version to match against the constraint. |
---|---|
Return type: | True if version satisfies the constraint, False if it doesn’t. |
Parses a constraints_expression and returns a Constraints object.
Constraint objects can be merged using a Constraints object and the + operator:
>>> from versions import Constraints, Constraint
>>> Constraints() + Constraint.parse('<2') + Constraint.parse('!=1.5')
Constraints.parse('<2.0.0,!=1.5.0')
Note
The Constraints object must be on the left side of the + operator. The Constraint object must be on right side.
If the constraint is a constraints expression, it is automatically parsed into a Constraints object.
The previous example can therefore be shortened as:
>>> Constraints() + '<2' + '!=1.5'
Constraints.parse('!=1.5.0,<2.0.0')
Or:
>>> Constraints() + '<2,!=1.5'
Constraints.parse('!=1.5.0,<2.0.0')
Constraints objects work like Constraint objects: they have a Constraints.match() method which returns True when passed a version expression or Version matching all constraints:
>>> Constraints.parse('>=1,<2').match('1.4')
True
>>> '1.4' in Constraints.parse('>=1.2,<2,!=1.4')
False
When merging conflicting constraints, an ExclusiveConstraints exception is raised:
>>> Constraints.parse('<1') + '>1'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "versions/constraints.py", line 96, in __add__
return Constraints(self._merge(constraint))
File "versions/constraints.py", line 89, in _merge
return merge(self.constraints + constraints)
File "versions/constraints.py", line 203, in merge
raise ExclusiveConstraints(g_constraint, [l_constraint])
versions.constraints.ExclusiveConstraints: Constraint >1.0.0 conflicts with constraints <1.0.0
>>> Constraints.parse('<1') + '==1'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "versions/constraints.py", line 96, in __add__
return Constraints(self._merge(constraint))
File "versions/constraints.py", line 89, in _merge
return merge(self.constraints + constraints)
File "versions/constraints.py", line 217, in merge
raise ExclusiveConstraints(eq_constraint, conflict_list)
versions.constraints.ExclusiveConstraints: Constraint ==1.0.0 conflicts with constraints <1.0.0
>>> Constraints.parse('>=1') + '!=1' + '<=1'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "versions/constraints.py", line 96, in __add__
return Constraints(self._merge(constraint))
File "versions/constraints.py", line 89, in _merge
return merge(self.constraints + constraints)
File "versions/constraints.py", line 217, in merge
raise ExclusiveConstraints(eq_constraint, conflict_list)
versions.constraints.ExclusiveConstraints: Constraint ==1.0.0 conflicts with constraints !=1.0.0