1 # -*- coding: utf-8 ; test-case-name: bridgedb.test.test_parse_versions ; -*-
3 # This file is part of BridgeDB, a Tor bridge distribution system.
5 # :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 <isis@torproject.org>
6 # please also see AUTHORS file
7 # :copyright: (c) 2014-2017 Isis Lovecruft
8 # (c) 2007-2017, The Tor Project, Inc.
9 # (c) 2007-2017, all entities within the AUTHORS file
10 # :license: see included LICENSE for information
12 """Parsers for Tor version number strings.
14 .. py:module:: bridgedb.parse.versions
15 :synopsis: Parsers for Tor version number strings.
17 bridgedb.parse.versions
18 =======================
21 Version - Holds, parses, and does comparison operations for package
30 from twisted
import version
as _txversion
32 # The twisted.python.util.Version class was moved in Twisted==14.0.0 to
33 # twisted.python.versions.Version:
34 if _txversion
.major
>= 14:
35 from twisted
.python
.versions
import Version
as _Version
37 from twisted
.python
.util
import Version
as _Version
40 class InvalidVersionStringFormat(ValueError):
41 """Raised when a version string is not in a parseable format."""
44 class Version(_Version
):
45 """Holds, parses, and does comparison operations for version numbers.
47 :attr str package: The package name, if available.
48 :attr int major: The major version number.
49 :attr int minor: The minor version number.
50 :attr int micro: The micro version number.
51 :attr str prerelease: The **prerelease** specifier isn't always present,
52 though when it is, it's usually separated from the main
53 ``major.minor.micro`` part of the version string with a ``-``, ``+``,
54 or ``#`` character. Sometimes the **prerelease** is another number,
55 although often it can be a word specifying the release state,
56 i.e. ``+alpha``, ``-rc2``, etc.
59 def __init__(self
, version
, package
=None):
60 """Create a version object.
62 Comparisons may be computed between instances of :class:`Version`s.
64 >>> from bridgedb.parse.versions import Version
65 >>> v1 = Version("0.2.3.25", package="tor")
70 >>> v2 = Version("0.2.5.1-alpha", package="tor")
72 Version(package=tor, major=0, minor=2, micro=5, prerelease=1-alpha)
78 :param str version: A Tor version string specifier, i.e. one taken
79 from either the ``client-versions`` or ``server-versions`` lines
80 within a Tor ``cached-consensus`` file.
81 :param str package: The package or program which we are creating a
84 if version
.find('.') == -1:
85 raise InvalidVersionStringFormat(
86 "Invalid delimiters in version string: %r" % version
)
88 package
= package
if package
is not None else str()
89 major
, minor
, micro
= [int() for _
in range(3)]
91 components
= version
.split('.')
92 if len(components
) > 0:
94 prerelease
= str(components
.pop())
95 micro
= int(components
.pop())
96 minor
= int(components
.pop())
97 major
= int(components
.pop())
100 super(Version
, self
).__init
__(package
, major
, minor
, micro
, prerelease
)
103 """Get the base version number (with prerelease).
106 :returns: A version number, without the package/program name, and with
107 the prefix (if available). For example: '0.2.5.1-alpha'.
109 pre
= self
.getPrefixedPrerelease()
110 return '%s.%s.%s%s' % (self
.major
, self
.minor
, self
.micro
, pre
)
112 def getPrefixedPrerelease(self
, separator
='.'):
113 """Get the prerelease string, prefixed by the separator ``prefix``.
115 :param string separator: The separator to use between the rest of the
116 version string and the :attr:`prerelease` string.
118 :returns: The separator plus the ``prefix``, i.e. '.1-alpha'.
121 if self
.prerelease
is not None:
122 pre
= separator
+ self
.prerelease
126 prerelease
= self
.getPrefixedPrerelease('')
127 return '%s(package=%s, major=%s, minor=%s, micro=%s, prerelease=%s)' \
128 % (str(self
.__class
__.__name
__),
136 def parseVersionsList(versions_list
):
137 """Turn the given version strings into stem objects.
139 :param list versions_list: A list of tuples. Each tuple contains a minimum
140 and maximum version number as strings.
142 :returns: A list of tuples. Each tuple contains a minimum and maximum
143 version number as :class:`stem.version.Version` objects.
146 for v1
, v2
in versions_list
:
147 # We're dealing with an already-parsed version list.
148 if isinstance(v1
, stem
.version
.Version
):
151 parsed
.append(tuple([stem
.version
.Version(v1
),
152 stem
.version
.Version(v2
)]))
154 logging
.error("Couldn't parse BLACKLISTED_TOR_VERSIONS; "
155 "probably because of badly formatted "
156 "configuration file. Ignoring config option.")