Skip to content

Commit affaa73

Browse files
committed
Merge pull request #1 from pypa/pep440
[WIP] PEP 440 Implementation
2 parents 9b6f703 + 44aec39 commit affaa73

13 files changed

+2312
-3
lines changed

.coveragerc

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[run]
2-
branch = True
2+
branch = True
3+
omit = packaging/_compat.py

docs/index.rst

+14
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,26 @@ Core utilities for Python packages
66

77
Installation
88
------------
9+
910
You can install packaging with ``pip``:
1011

1112
.. code-block:: console
1213
1314
$ pip install packaging
1415
16+
17+
API
18+
---
19+
20+
.. toctree::
21+
:maxdepth: 1
22+
23+
version
24+
25+
26+
Project
27+
-------
28+
1529
.. toctree::
1630
:maxdepth: 2
1731

docs/version.rst

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
Version Handling
2+
================
3+
4+
.. currentmodule:: packaging.version
5+
6+
A core requirement of dealing with packages is the ability to work with
7+
versions. `PEP 440`_ defines the standard version scheme for Python packages
8+
which has been implemented by this module.
9+
10+
Usage
11+
-----
12+
13+
.. doctest::
14+
15+
>>> from packaging.version import Version, Specifier
16+
>>> v1 = Version("1.0a5")
17+
>>> v2 = Version("1.0")
18+
>>> v1
19+
<Version('1.0a5')>
20+
>>> v2
21+
<Version('1.0')>
22+
>>> v1 < v2
23+
True
24+
>>> v1.is_prerelease
25+
True
26+
>>> v2.is_prerelease
27+
False
28+
>>> Version("french toast")
29+
Traceback (most recent call last):
30+
...
31+
InvalidVersion: Invalid version: 'french toast'
32+
>>> spec1 = Specifier("~=1.0")
33+
>>> spec1
34+
<Specifier('~=1.0')>
35+
>>> spec2 = Specifier(">=1.0")
36+
>>> spec2
37+
<Specifier('>=1.0')>
38+
>>> # We can combine specifiers
39+
>>> combined_spec = spec1 & spec2
40+
>>> combined_spec
41+
<Specifier('>=1.0,~=1.0')>
42+
>>> # We can also implicitly combine a string specifier
43+
>>> combined_spec &= "!=1.1"
44+
>>> combined_spec
45+
<Specifier('!=1.1,>=1.0,~=1.0')>
46+
>>> # We can check a version object to see if it falls within a specifier
47+
>>> v1 in combined_spec
48+
False
49+
>>> v2 in combined_spec
50+
True
51+
>>> # We can even do the same with a string based version
52+
>>> "1.4" in combined_spec
53+
True
54+
55+
56+
Reference
57+
---------
58+
59+
.. class:: Version(version)
60+
61+
This class abstracts handling of a project's versions. It implements the
62+
scheme defined in `PEP 440`_. A :class:`Version` instance is comparison
63+
aware and can be compared and sorted using the standard Python interfaces.
64+
65+
:param str version: The string representation of a version which will be
66+
parsed and normalized before use.
67+
:raises InvalidVersion: If the ``version`` does not conform to PEP 440 in
68+
any way then this exception will be raised.
69+
70+
.. attribute:: public
71+
72+
A string representing the public version portion of this ``Version()``.
73+
74+
.. attribute:: local
75+
76+
A string representing the local version portion of this ``Version()``
77+
if it has one, or ``None`` otherwise.
78+
79+
.. attribute:: is_prerelease
80+
81+
A boolean value indicating whether this :class:`Version` instance
82+
represents a prerelease or a final release.
83+
84+
85+
.. class:: LegacyVersion(version)
86+
87+
This class abstracts handling of a project's versions if they are not
88+
compatible with the scheme defined in `PEP 440`_. It implements a similar
89+
interface to that of :class:`Version` however it is considered unorderable
90+
and many of the comparison types are not implemented.
91+
92+
:param str version: The string representation of a version which will be
93+
used as is.
94+
95+
.. attribute:: public
96+
97+
A string representing the public version portion of this
98+
:class:`LegacyVersion`. This will always be the entire version string.
99+
100+
.. attribute:: local
101+
102+
This will always be ``None`` since without `PEP 440`_ we do not have
103+
the concept of a local version. It exists primarily to allow a
104+
:class:`LegacyVersion` to be used as a stand in for a :class:`Version`.
105+
106+
.. attribute:: is_prerelease
107+
108+
A boolean value indicating whether this :class:`LegacyVersion`
109+
represents a prerelease or a final release. Since without `PEP 440`_
110+
there is no concept of pre or final releases this will always be
111+
`False` and exists for compatibility with :class:`Version`.
112+
113+
114+
.. class:: Specifier(specifier)
115+
116+
This class abstracts handling of specifying the dependencies of a project.
117+
It implements the scheme defined in `PEP 440`_. You can test membership
118+
of a particular version within a set of specifiers in a :class:`Specifier`
119+
instance by using the standard ``in`` operator (e.g.
120+
``Version("2.0") in Specifier("==2.0")``). You may also combine Specifier
121+
instances using the ``&`` operator (``Specifier(">2") & Specifier(">3")``).
122+
123+
Both the membership test and the combination supports using raw strings
124+
in place of already instantiated objects.
125+
126+
:param str specifier: The string representation of a specifier which will
127+
be parsed and normalized before use.
128+
:raises InvalidSpecifier: If the ``specifier`` does not conform to PEP 440
129+
in any way then this exception will be raised.
130+
131+
132+
.. class:: InvalidVersion
133+
134+
Raised when attempting to create a :class:`Version` with a version string
135+
that does not conform to `PEP 440`_.
136+
137+
138+
.. class:: InvalidSpecifier
139+
140+
Raised when attempting to create a :class:`Specifier` with a specifier
141+
string that does not conform to `PEP 440`_.
142+
143+
144+
.. _`PEP 440`: https://www.python.org/dev/peps/pep-0440/

packaging/_compat.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright 2014 Donald Stufft
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from __future__ import absolute_import, division, print_function
15+
16+
import sys
17+
18+
19+
PY2 = sys.version_info[0] == 2
20+
PY3 = sys.version_info[0] == 3
21+
22+
# flake8: noqa
23+
24+
if PY3:
25+
string_types = str,
26+
else:
27+
string_types = basestring,

packaging/_structures.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright 2014 Donald Stufft
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from __future__ import absolute_import, division, print_function
15+
16+
17+
class Infinity(object):
18+
19+
def __repr__(self):
20+
return "Infinity"
21+
22+
def __hash__(self):
23+
return hash(repr(self))
24+
25+
def __lt__(self, other):
26+
return False
27+
28+
def __le__(self, other):
29+
return False
30+
31+
def __eq__(self, other):
32+
return isinstance(other, self.__class__)
33+
34+
def __ne__(self, other):
35+
return not isinstance(other, self.__class__)
36+
37+
def __gt__(self, other):
38+
return True
39+
40+
def __ge__(self, other):
41+
return True
42+
43+
def __neg__(self):
44+
return NegativeInfinity
45+
46+
Infinity = Infinity()
47+
48+
49+
class NegativeInfinity(object):
50+
51+
def __repr__(self):
52+
return "-Infinity"
53+
54+
def __hash__(self):
55+
return hash(repr(self))
56+
57+
def __lt__(self, other):
58+
return True
59+
60+
def __le__(self, other):
61+
return True
62+
63+
def __eq__(self, other):
64+
return isinstance(other, self.__class__)
65+
66+
def __ne__(self, other):
67+
return not isinstance(other, self.__class__)
68+
69+
def __gt__(self, other):
70+
return False
71+
72+
def __ge__(self, other):
73+
return False
74+
75+
def __neg__(self):
76+
return Infinity
77+
78+
NegativeInfinity = NegativeInfinity()

0 commit comments

Comments
 (0)