1
- # Vendored from https://github.com/pypa/packaging/blob/main/packaging/_structures.py
2
- # and https://github.com/pypa/packaging/blob/main/packaging/_structures.py
3
- # changeset ae891fd74d6dd4c6063bb04f2faeadaac6fc6313
4
- # 04/30/2021
1
+ # Vendored from https://github.com/pypa/packaging/blob/main/src/packaging/_structures.py
2
+ # and https://github.com/pypa/packaging/blob/main/src/packaging/version.py
3
+ # changeset 24e5350b2ff3c5c7a36676c2af5f2cb39fd1baf8
5
4
6
5
# This file is dual licensed under the terms of the Apache License, Version
7
6
# 2.0, and the BSD License. Licence at LICENSES/PACKAGING_LICENSE
8
7
from __future__ import annotations
9
8
10
- import collections
11
- from collections .abc import (
12
- Callable ,
13
- Iterator ,
14
- )
9
+ from collections .abc import Callable
15
10
import itertools
16
11
import re
17
12
from typing import (
13
+ Any ,
14
+ NamedTuple ,
18
15
SupportsInt ,
19
- Tuple ,
20
16
Union ,
21
17
)
22
- import warnings
23
18
24
- __all__ = ["parse " , "Version " , "LegacyVersion " , "InvalidVersion" , "VERSION_PATTERN " ]
19
+ __all__ = ["VERSION_PATTERN " , "InvalidVersion " , "Version " , "parse " ]
25
20
26
21
27
22
class InfinityType :
@@ -40,9 +35,6 @@ def __le__(self, other: object) -> bool:
40
35
def __eq__ (self , other : object ) -> bool :
41
36
return isinstance (other , type (self ))
42
37
43
- def __ne__ (self , other : object ) -> bool :
44
- return not isinstance (other , type (self ))
45
-
46
38
def __gt__ (self , other : object ) -> bool :
47
39
return True
48
40
@@ -72,9 +64,6 @@ def __le__(self, other: object) -> bool:
72
64
def __eq__ (self , other : object ) -> bool :
73
65
return isinstance (other , type (self ))
74
66
75
- def __ne__ (self , other : object ) -> bool :
76
- return not isinstance (other , type (self ))
77
-
78
67
def __gt__ (self , other : object ) -> bool :
79
68
return False
80
69
@@ -88,45 +77,39 @@ def __neg__(self: object) -> InfinityType:
88
77
NegativeInfinity = NegativeInfinityType ()
89
78
90
79
91
- InfiniteTypes = Union [InfinityType , NegativeInfinityType ]
92
- PrePostDevType = Union [ InfiniteTypes , tuple [ str , int ]]
93
- SubLocalType = Union [InfiniteTypes , int , str ]
94
- LocalType = Union [
80
+ LocalType = tuple [ Union [int , str ], ... ]
81
+
82
+ CmpPrePostDevType = Union [InfinityType , NegativeInfinityType , tuple [ str , int ] ]
83
+ CmpLocalType = Union [
95
84
NegativeInfinityType ,
96
- tuple [
97
- Union [
98
- SubLocalType ,
99
- tuple [SubLocalType , str ],
100
- tuple [NegativeInfinityType , SubLocalType ],
101
- ],
102
- ...,
103
- ],
85
+ tuple [Union [tuple [int , str ], tuple [NegativeInfinityType , Union [int , str ]]], ...],
104
86
]
105
87
CmpKey = tuple [
106
- int , tuple [int , ...], PrePostDevType , PrePostDevType , PrePostDevType , LocalType
107
- ]
108
- LegacyCmpKey = tuple [int , tuple [str , ...]]
109
- VersionComparisonMethod = Callable [
110
- [Union [CmpKey , LegacyCmpKey ], Union [CmpKey , LegacyCmpKey ]], bool
88
+ int ,
89
+ tuple [int , ...],
90
+ CmpPrePostDevType ,
91
+ CmpPrePostDevType ,
92
+ CmpPrePostDevType ,
93
+ CmpLocalType ,
111
94
]
95
+ VersionComparisonMethod = Callable [[CmpKey , CmpKey ], bool ]
112
96
113
- _Version = collections .namedtuple (
114
- "_Version" , ["epoch" , "release" , "dev" , "pre" , "post" , "local" ]
115
- )
116
97
98
+ class _Version (NamedTuple ):
99
+ epoch : int
100
+ release : tuple [int , ...]
101
+ dev : tuple [str , int ] | None
102
+ pre : tuple [str , int ] | None
103
+ post : tuple [str , int ] | None
104
+ local : LocalType | None
117
105
118
- def parse (version : str ) -> LegacyVersion | Version :
119
- """
120
- Parse the given version string and return either a :class:`Version` object
121
- or a :class:`LegacyVersion` object depending on if the given version is
122
- a valid PEP 440 version or a legacy version.
123
- """
124
- try :
125
- return Version (version )
126
- except InvalidVersion :
127
- return LegacyVersion (version )
106
+
107
+ def parse (version : str ) -> Version :
108
+ return Version (version )
128
109
129
110
111
+ # The docstring is from an older version of the packaging library to avoid
112
+ # errors in the docstring validation.
130
113
class InvalidVersion (ValueError ):
131
114
"""
132
115
An invalid version was found, users should refer to PEP 440.
@@ -140,7 +123,7 @@ class InvalidVersion(ValueError):
140
123
141
124
142
125
class _BaseVersion :
143
- _key : CmpKey | LegacyCmpKey
126
+ _key : tuple [ Any , ...]
144
127
145
128
def __hash__ (self ) -> int :
146
129
return hash (self ._key )
@@ -185,132 +168,16 @@ def __ne__(self, other: object) -> bool:
185
168
return self ._key != other ._key
186
169
187
170
188
- class LegacyVersion (_BaseVersion ):
189
- def __init__ (self , version : str ) -> None :
190
- self ._version = str (version )
191
- self ._key = _legacy_cmpkey (self ._version )
192
-
193
- warnings .warn (
194
- "Creating a LegacyVersion has been deprecated and will be "
195
- "removed in the next major release." ,
196
- DeprecationWarning ,
197
- )
198
-
199
- def __str__ (self ) -> str :
200
- return self ._version
201
-
202
- def __repr__ (self ) -> str :
203
- return f"<LegacyVersion('{ self } ')>"
204
-
205
- @property
206
- def public (self ) -> str :
207
- return self ._version
208
-
209
- @property
210
- def base_version (self ) -> str :
211
- return self ._version
212
-
213
- @property
214
- def epoch (self ) -> int :
215
- return - 1
216
-
217
- @property
218
- def release (self ) -> None :
219
- return None
220
-
221
- @property
222
- def pre (self ) -> None :
223
- return None
224
-
225
- @property
226
- def post (self ) -> None :
227
- return None
228
-
229
- @property
230
- def dev (self ) -> None :
231
- return None
232
-
233
- @property
234
- def local (self ) -> None :
235
- return None
236
-
237
- @property
238
- def is_prerelease (self ) -> bool :
239
- return False
240
-
241
- @property
242
- def is_postrelease (self ) -> bool :
243
- return False
244
-
245
- @property
246
- def is_devrelease (self ) -> bool :
247
- return False
248
-
249
-
250
- _legacy_version_component_re = re .compile (r"(\d+ | [a-z]+ | \.| -)" , re .VERBOSE )
251
-
252
- _legacy_version_replacement_map = {
253
- "pre" : "c" ,
254
- "preview" : "c" ,
255
- "-" : "final-" ,
256
- "rc" : "c" ,
257
- "dev" : "@" ,
258
- }
259
-
260
-
261
- def _parse_version_parts (s : str ) -> Iterator [str ]:
262
- for part in _legacy_version_component_re .split (s ):
263
- mapped_part = _legacy_version_replacement_map .get (part , part )
264
-
265
- if not mapped_part or mapped_part == "." :
266
- continue
267
-
268
- if mapped_part [:1 ] in "0123456789" :
269
- # pad for numeric comparison
270
- yield mapped_part .zfill (8 )
271
- else :
272
- yield "*" + mapped_part
273
-
274
- # ensure that alpha/beta/candidate are before final
275
- yield "*final"
276
-
277
-
278
- def _legacy_cmpkey (version : str ) -> LegacyCmpKey :
279
- # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
280
- # greater than or equal to 0. This will effectively put the LegacyVersion,
281
- # which uses the defacto standard originally implemented by setuptools,
282
- # as before all PEP 440 versions.
283
- epoch = - 1
284
-
285
- # This scheme is taken from pkg_resources.parse_version setuptools prior to
286
- # it's adoption of the packaging library.
287
- parts : list [str ] = []
288
- for part in _parse_version_parts (version .lower ()):
289
- if part .startswith ("*" ):
290
- # remove "-" before a prerelease tag
291
- if part < "*final" :
292
- while parts and parts [- 1 ] == "*final-" :
293
- parts .pop ()
294
-
295
- # remove trailing zeros from each series of numeric parts
296
- while parts and parts [- 1 ] == "00000000" :
297
- parts .pop ()
298
-
299
- parts .append (part )
300
-
301
- return epoch , tuple (parts )
302
-
303
-
304
171
# Deliberately not anchored to the start and end of the string, to make it
305
172
# easier for 3rd party code to reuse
306
- VERSION_PATTERN = r"""
173
+ _VERSION_PATTERN = r"""
307
174
v?
308
175
(?:
309
176
(?:(?P<epoch>[0-9]+)!)? # epoch
310
177
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
311
178
(?P<pre> # pre-release
312
179
[-_\.]?
313
- (?P<pre_l>(a|b|c|rc|alpha|beta| pre|preview) )
180
+ (?P<pre_l>alpha|a|beta|b|preview| pre|c|rc )
314
181
[-_\.]?
315
182
(?P<pre_n>[0-9]+)?
316
183
)?
@@ -334,9 +201,12 @@ def _legacy_cmpkey(version: str) -> LegacyCmpKey:
334
201
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
335
202
"""
336
203
204
+ VERSION_PATTERN = _VERSION_PATTERN
205
+
337
206
338
207
class Version (_BaseVersion ):
339
208
_regex = re .compile (r"^\s*" + VERSION_PATTERN + r"\s*$" , re .VERBOSE | re .IGNORECASE )
209
+ _key : CmpKey
340
210
341
211
def __init__ (self , version : str ) -> None :
342
212
# Validate the version and parse it into pieces
@@ -377,11 +247,11 @@ def __str__(self) -> str:
377
247
parts .append (f"{ self .epoch } !" )
378
248
379
249
# Release segment
380
- parts .append ("." .join ([ str (x ) for x in self .release ] ))
250
+ parts .append ("." .join (str (x ) for x in self .release ))
381
251
382
252
# Pre-release
383
253
if self .pre is not None :
384
- parts .append ("" .join ([ str (x ) for x in self .pre ] ))
254
+ parts .append ("" .join (str (x ) for x in self .pre ))
385
255
386
256
# Post-release
387
257
if self .post is not None :
@@ -399,18 +269,15 @@ def __str__(self) -> str:
399
269
400
270
@property
401
271
def epoch (self ) -> int :
402
- _epoch : int = self ._version .epoch
403
- return _epoch
272
+ return self ._version .epoch
404
273
405
274
@property
406
275
def release (self ) -> tuple [int , ...]:
407
- _release : tuple [int , ...] = self ._version .release
408
- return _release
276
+ return self ._version .release
409
277
410
278
@property
411
279
def pre (self ) -> tuple [str , int ] | None :
412
- _pre : tuple [str , int ] | None = self ._version .pre
413
- return _pre
280
+ return self ._version .pre
414
281
415
282
@property
416
283
def post (self ) -> int | None :
@@ -423,7 +290,7 @@ def dev(self) -> int | None:
423
290
@property
424
291
def local (self ) -> str | None :
425
292
if self ._version .local :
426
- return "." .join ([ str (x ) for x in self ._version .local ] )
293
+ return "." .join (str (x ) for x in self ._version .local )
427
294
else :
428
295
return None
429
296
@@ -440,7 +307,7 @@ def base_version(self) -> str:
440
307
parts .append (f"{ self .epoch } !" )
441
308
442
309
# Release segment
443
- parts .append ("." .join ([ str (x ) for x in self .release ] ))
310
+ parts .append ("." .join (str (x ) for x in self .release ))
444
311
445
312
return "" .join (parts )
446
313
@@ -470,7 +337,7 @@ def micro(self) -> int:
470
337
471
338
472
339
def _parse_letter_version (
473
- letter : str , number : str | bytes | SupportsInt
340
+ letter : str | None , number : str | bytes | SupportsInt | None
474
341
) -> tuple [str , int ] | None :
475
342
if letter :
476
343
# We consider there to be an implicit 0 in a pre-release if there is
@@ -507,10 +374,7 @@ def _parse_letter_version(
507
374
_local_version_separators = re .compile (r"[\._-]" )
508
375
509
376
510
- def _parse_local_version (local : str ) -> LocalType | None :
511
- """
512
- Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
513
- """
377
+ def _parse_local_version (local : str | None ) -> LocalType | None :
514
378
if local is not None :
515
379
return tuple (
516
380
part .lower () if not part .isdigit () else int (part )
@@ -525,7 +389,7 @@ def _cmpkey(
525
389
pre : tuple [str , int ] | None ,
526
390
post : tuple [str , int ] | None ,
527
391
dev : tuple [str , int ] | None ,
528
- local : tuple [ SubLocalType ] | None ,
392
+ local : LocalType | None ,
529
393
) -> CmpKey :
530
394
# When we compare a release version, we want to compare it with all of the
531
395
# trailing zeros removed. So we'll use a reverse the list, drop all the now
@@ -541,7 +405,7 @@ def _cmpkey(
541
405
# if there is not a pre or a post segment. If we have one of those then
542
406
# the normal sorting rules will handle this case correctly.
543
407
if pre is None and post is None and dev is not None :
544
- _pre : PrePostDevType = NegativeInfinity
408
+ _pre : CmpPrePostDevType = NegativeInfinity
545
409
# Versions without a pre-release (except as noted above) should sort after
546
410
# those with one.
547
411
elif pre is None :
@@ -551,21 +415,21 @@ def _cmpkey(
551
415
552
416
# Versions without a post segment should sort before those with one.
553
417
if post is None :
554
- _post : PrePostDevType = NegativeInfinity
418
+ _post : CmpPrePostDevType = NegativeInfinity
555
419
556
420
else :
557
421
_post = post
558
422
559
423
# Versions without a development segment should sort after those with one.
560
424
if dev is None :
561
- _dev : PrePostDevType = Infinity
425
+ _dev : CmpPrePostDevType = Infinity
562
426
563
427
else :
564
428
_dev = dev
565
429
566
430
if local is None :
567
431
# Versions without a local segment should sort before those with one.
568
- _local : LocalType = NegativeInfinity
432
+ _local : CmpLocalType = NegativeInfinity
569
433
else :
570
434
# Versions with a local segment need that segment parsed to implement
571
435
# the sorting rules in PEP440.
0 commit comments