Skip to content

Commit 1f8b10e

Browse files
First documentation pass
Signed-off-by: Jean-Christophe Morin <[email protected]>
1 parent 62da43f commit 1f8b10e

File tree

4 files changed

+317
-185
lines changed

4 files changed

+317
-185
lines changed

docs/source/api.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,5 @@ Python API
4343
rez.system
4444
rez.util
4545
rez.utils
46-
rez.vendor.version
46+
rez.version
4747
rez.wrapper

src/rez/version/__init__.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,46 @@
22
# Copyright Contributors to the Rez Project
33

44

5-
from rez.version._requirement import Requirement, RequirementList, VersionedObject # noqa: F401
6-
from rez.version._util import ParseException, VersionError # noqa: F401
7-
from rez.version._version import ( # noqa: F401
5+
"""
6+
Implements a well defined versioning schema.
7+
8+
There are three class types: :class:`VersionToken`, :class:`Version` and :class:`VersionRange`.
9+
A :class:`Version` is a set of zero or more :class:`VersionToken`\\s, separate by ``.``\\s or ``-``\\s (eg ``1.2-3``).
10+
A :class:`VersionToken` is a string containing alphanumerics, and default implemenations
11+
:class:`NumericToken` and :class:`AlphanumericVersionToken` are supplied. You can implement
12+
your own if you want stricter tokens or different sorting behaviour.
13+
14+
A :class:`VersionRange` is a set of one or more contiguous version ranges. For example,
15+
``3+<5`` contains any version >=3 but less than 5. Version ranges can be used to
16+
define dependency requirements between objects. They can be OR'd together, AND'd
17+
and inverted.
18+
19+
The empty version ``''``, and empty version range ``''``, are also handled. The empty
20+
version is used to denote unversioned objects. The empty version range, also
21+
known as the 'any' range, is used to refer to any version of an object.
22+
"""
23+
24+
from rez.version._requirement import Requirement, RequirementList, VersionedObject
25+
from rez.version._util import ParseException, VersionError
26+
from rez.version._version import (
827
AlphanumericVersionToken,
928
NumericToken,
1029
Version,
1130
VersionRange,
1231
VersionToken,
1332
reverse_sort_key,
1433
)
34+
35+
__all__ = (
36+
"Version",
37+
"VersionRange",
38+
"Requirement",
39+
"RequirementList",
40+
"VersionedObject",
41+
"VersionToken",
42+
"NumericToken",
43+
"AlphanumericVersionToken",
44+
"reverse_sort_key",
45+
"ParseException",
46+
"VersionError",
47+
)

src/rez/version/_requirement.py

Lines changed: 110 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,23 @@
88

99

1010
class VersionedObject(_Common):
11-
"""Definition of a versioned object, eg "foo-1.0".
11+
"""Definition of a versioned object, eg ``foo-1.0``.
1212
13-
"foo" is also a valid object definiton - when there is no version part, we
13+
``foo`` is also a valid object definiton. When there is no version part, we
1414
are defining an unversioned object.
1515
16-
Note that '-', '@' or '#' can be used as the seperator between object name
17-
and version, however this is purely cosmetic - "foo-1" is the same as "foo@1".
16+
.. note::
17+
Note that ``-``, ``@`` or ``#`` can be used as the seperator between object name
18+
and version, however this is purely cosmetic. ``foo-1`` is the same as ``foo@1``.
1819
"""
1920
sep_regex_str = r'[-@#]'
2021
sep_regex = re.compile(sep_regex_str)
2122

2223
def __init__(self, s):
24+
"""
25+
Args:
26+
s (str):
27+
"""
2328
self.name_ = None
2429
self.version_ = None
2530
self.sep_ = '-'
@@ -42,8 +47,8 @@ def construct(cls, name, version=None):
4247
"""Create a VersionedObject directly from an object name and version.
4348
4449
Args:
45-
name: Object name string.
46-
version: Version object.
50+
name (str): Object name string.
51+
version (typing.Optional[Version]): Version object.
4752
"""
4853
other = VersionedObject(None)
4954
other.name_ = name
@@ -52,19 +57,27 @@ def construct(cls, name, version=None):
5257

5358
@property
5459
def name(self):
55-
"""Name of the object."""
60+
"""Name of the object.
61+
62+
Returns:
63+
str:
64+
"""
5665
return self.name_
5766

5867
@property
5968
def version(self):
60-
"""Version of the object."""
69+
"""Version of the object.
70+
71+
Returns:
72+
Version:
73+
"""
6174
return self.version_
6275

6376
def as_exact_requirement(self):
6477
"""Get the versioned object, as an exact requirement string.
6578
6679
Returns:
67-
Equivalent requirement string, eg "maya==2016.1"
80+
str: Equivalent requirement string, eg ``maya==2016.1``
6881
"""
6982
sep_str = ''
7083
ver_str = ''
@@ -91,42 +104,46 @@ def __str__(self):
91104

92105

93106
class Requirement(_Common):
94-
"""Requirement for a versioned object.
95-
96-
Examples of valid requirement strings:
97-
98-
foo-1.0
99-
100-
foo#1.0
101-
foo-1+
102-
foo-1+<4.3
103-
foo<3
104-
foo==1.0.1
105-
106-
Defines a requirement for an object. For example, "foo-5+" means that you
107-
require any version of "foo", version 5 or greater. An unversioned
108-
requirement can also be used ("foo"), this means you require any version of
107+
"""
108+
Defines a requirement for an object. For example, ``foo-5+`` means that you
109+
require any version of ``foo``, version 5 or greater. An unversioned
110+
requirement can also be used (``foo``), this means you require any version of
109111
foo. You can drop the hyphen between object name and version range if the
110-
version range starts with a non-alphanumeric character - eg "foo<2".
112+
version range starts with a non-alphanumeric character - eg ``foo<2``.
111113
112114
There are two different prefixes that can be applied to a requirement:
113115
114-
- "!": The conflict requirement. This means that you require this version
116+
- ``!``: The conflict requirement. This means that you require this version
115117
range of an object NOT to be present. To conflict with all versions of an
116118
object, use "!foo".
117-
118-
- "~": This is known as a "weak reference", and means, "I do not require this
119+
- ``~``: This is known as a "weak reference", and means, "I do not require this
119120
object, but if present, it must be within this range." It is equivalent to
120121
the *conflict of the inverse* of the given version range.
121122
122-
There is one subtle case to be aware of. "~foo" is a requirement that has no
123-
effect - ie, it means "I do not require foo, but if foo is present, it can
123+
There is one subtle case to be aware of. ``~foo`` is a requirement that has no
124+
effect. It means "I do not require foo, but if foo is present, it can
124125
be any version." This statement is still valid, but will produce a
125126
Requirement object with a None range.
127+
128+
Examples of valid requirement strings:
129+
130+
- ``foo-1.0``
131+
132+
- ``foo#1.0``
133+
- ``foo-1+``
134+
- ``foo-1+<4.3``
135+
- ``foo<3``
136+
- ``foo==1.0.1``
126137
"""
127138
sep_regex = re.compile(r'[-@#=<>]')
128139

129140
def __init__(self, s, invalid_bound_error=True):
141+
"""
142+
Args:
143+
s (str): Requirement string
144+
invalid_bound_error (bool): If True, raise :exc:`VersionError` if an
145+
impossible range is given, such as ``3+<2``.
146+
"""
130147
self.name_ = None
131148
self.range_ = None
132149
self.negate_ = False
@@ -170,8 +187,8 @@ def construct(cls, name, range=None):
170187
"""Create a requirement directly from an object name and VersionRange.
171188
172189
Args:
173-
name: Object name string.
174-
range: VersionRange object. If None, an unversioned requirement is
190+
name (str): Object name string.
191+
range (typing.Optional[VersionRange]): If None, an unversioned requirement is
175192
created.
176193
"""
177194
other = Requirement(None)
@@ -181,38 +198,61 @@ def construct(cls, name, range=None):
181198

182199
@property
183200
def name(self):
184-
"""Name of the required object."""
201+
"""Name of the required object.
202+
203+
Returns:
204+
str:
205+
"""
185206
return self.name_
186207

187208
@property
188209
def range(self):
189-
"""VersionRange of the requirement."""
210+
"""Version range of the requirement.
211+
212+
Returns:
213+
VersionRange:
214+
"""
190215
return self.range_
191216

192217
@property
193218
def conflict(self):
194219
"""True if the requirement is a conflict requirement, eg "!foo", "~foo-1".
220+
221+
Returns:
222+
bool:
195223
"""
196224
return self.conflict_
197225

198226
@property
199227
def weak(self):
200228
"""True if the requirement is weak, eg "~foo".
201229
202-
Note that weak requirements are also conflict requirements, but not
203-
necessarily the other way around.
230+
.. note::
231+
Note that weak requirements are also conflict requirements, but not
232+
necessarily the other way around.
233+
234+
Returns:
235+
bool:
204236
"""
205237
return self.negate_
206238

207239
def safe_str(self):
208240
"""Return a string representation that is safe for the current filesystem,
209241
and guarantees that no two different Requirement objects will encode to
210-
the same value."""
242+
the same value.
243+
244+
Returns:
245+
str:
246+
"""
211247
return str(self)
212248

213249
def conflicts_with(self, other):
214-
"""Returns True if this requirement conflicts with another `Requirement`
215-
or `VersionedObject`."""
250+
"""Returns True if this requirement conflicts with another :class:`Requirement`
251+
or :class:`VersionedObject`.
252+
253+
Returns:
254+
bool:
255+
"""
216256
if isinstance(other, Requirement):
217257
if (self.name_ != other.name_) or (self.range is None) \
218258
or (other.range is None):
@@ -233,16 +273,20 @@ def conflicts_with(self, other):
233273
return (other.version_ not in self.range_)
234274

235275
def merged(self, other):
236-
"""Returns the merged result of two requirements.
276+
"""Merge two requirements.
237277
238278
Two requirements can be in conflict and if so, this function returns
239-
None. For example, requests for "foo-4" and "foo-6" are in conflict,
279+
None. For example, requests for ``foo-4`` and ``foo-6`` are in conflict,
240280
since both cannot be satisfied with a single version of foo.
241281
242282
Some example successful requirements merges are:
243-
- "foo-3+" and "!foo-5+" == "foo-3+<5"
244-
- "foo-1" and "foo-1.5" == "foo-1.5"
245-
- "!foo-2" and "!foo-5" == "!foo-2|5"
283+
284+
- ``foo-3+`` and ``!foo-5+`` == ``foo-3+<5``
285+
- ``foo-1`` and ``foo-1.5`` == ``foo-1.5``
286+
- ``!foo-2`` and ``!foo-5`` == ``!foo-2|5``
287+
288+
Returns:
289+
Requirement: the merged result of two requirements.
246290
"""
247291
if self.name_ != other.name_:
248292
return None # cannot merge across object names
@@ -327,10 +371,9 @@ class RequirementList(_Common):
327371
is retained.
328372
"""
329373
def __init__(self, requirements):
330-
"""Create a RequirementList.
331-
374+
"""
332375
Args:
333-
requirements: List of Requirement objects.
376+
requirements (list[Requirement]): List of requirements.
334377
"""
335378
self.requirements_ = []
336379
self.conflict_ = None
@@ -370,6 +413,9 @@ def __init__(self, requirements):
370413
def requirements(self):
371414
"""Returns optimised list of requirements, or None if there are
372415
conflicts.
416+
417+
Returns:
418+
list[Requirement]:
373419
"""
374420
return self.requirements_
375421

@@ -378,28 +424,41 @@ def conflict(self):
378424
"""Get the requirement conflict, if any.
379425
380426
Returns:
381-
None if there is no conflict, otherwise a 2-tuple containing the
382-
conflicting Requirement objects.
427+
typing.Optional[tuple[Requirement]]: None if there is no conflict, otherwise a
428+
2-tuple containing the conflicting requirement objects.
383429
"""
384430
return self.conflict_
385431

386432
@property
387433
def names(self):
388434
"""Set of names of requirements, not including conflict requirements.
435+
436+
Returns:
437+
set[str]:
389438
"""
390439
return self.names_
391440

392441
@property
393442
def conflict_names(self):
394-
"""Set of conflict requirement names."""
443+
"""Set of conflict requirement names.
444+
445+
Returns:
446+
set[str]:
447+
"""
395448
return self.conflict_names_
396449

397450
def __iter__(self):
398451
for requirement in (self.requirements_ or []):
399452
yield requirement
400453

401454
def get(self, name):
402-
"""Returns the Requirement for the given object, or None.
455+
"""Returns the requirement for the given object, or None.
456+
457+
Args:
458+
name (str): requirement to get.
459+
460+
Returns:
461+
Requirement:
403462
"""
404463
return self.requirements_dict.get(name)
405464

0 commit comments

Comments
 (0)