nab-python 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. nab_python/__init__.py +1 -0
  2. nab_python/_build/__init__.py +1 -0
  3. nab_python/_build/env.py +364 -0
  4. nab_python/_build/errors.py +17 -0
  5. nab_python/_build/runner.py +254 -0
  6. nab_python/_lockfile/__init__.py +1 -0
  7. nab_python/_lockfile/builder.py +339 -0
  8. nab_python/_lockfile/disjointness.py +207 -0
  9. nab_python/_lockfile/pylock.py +323 -0
  10. nab_python/_lockfile/requirements.py +121 -0
  11. nab_python/_packaging_provider.py +98 -0
  12. nab_python/_provider/__init__.py +1 -0
  13. nab_python/_provider/build_remote.py +95 -0
  14. nab_python/_provider/extras.py +231 -0
  15. nab_python/_provider/listing.py +442 -0
  16. nab_python/_provider/lookahead.py +156 -0
  17. nab_python/_provider/metadata_resolver.py +450 -0
  18. nab_python/_provider/priority.py +174 -0
  19. nab_python/_provider/sources.py +215 -0
  20. nab_python/_testing/__init__.py +1 -0
  21. nab_python/_testing/coordinator_fake.py +240 -0
  22. nab_python/_vcs_admission.py +209 -0
  23. nab_python/_vendor/__init__.py +6 -0
  24. nab_python/_vendor/packaging/LICENSE +3 -0
  25. nab_python/_vendor/packaging/LICENSE.APACHE +177 -0
  26. nab_python/_vendor/packaging/LICENSE.BSD +23 -0
  27. nab_python/_vendor/packaging/PROVENANCE.md +73 -0
  28. nab_python/_vendor/packaging/__init__.py +15 -0
  29. nab_python/_vendor/packaging/_elffile.py +108 -0
  30. nab_python/_vendor/packaging/_manylinux.py +265 -0
  31. nab_python/_vendor/packaging/_musllinux.py +88 -0
  32. nab_python/_vendor/packaging/_parser.py +394 -0
  33. nab_python/_vendor/packaging/_structures.py +33 -0
  34. nab_python/_vendor/packaging/_tokenizer.py +196 -0
  35. nab_python/_vendor/packaging/dependency_groups.py +302 -0
  36. nab_python/_vendor/packaging/direct_url.py +325 -0
  37. nab_python/_vendor/packaging/errors.py +94 -0
  38. nab_python/_vendor/packaging/licenses/__init__.py +186 -0
  39. nab_python/_vendor/packaging/licenses/_spdx.py +799 -0
  40. nab_python/_vendor/packaging/markers.py +506 -0
  41. nab_python/_vendor/packaging/metadata.py +964 -0
  42. nab_python/_vendor/packaging/py.typed +0 -0
  43. nab_python/_vendor/packaging/pylock.py +910 -0
  44. nab_python/_vendor/packaging/ranges.py +1803 -0
  45. nab_python/_vendor/packaging/requirements.py +132 -0
  46. nab_python/_vendor/packaging/specifiers.py +1141 -0
  47. nab_python/_vendor/packaging/tags.py +929 -0
  48. nab_python/_vendor/packaging/utils.py +296 -0
  49. nab_python/_vendor/packaging/version.py +1230 -0
  50. nab_python/build_backend.py +184 -0
  51. nab_python/config.py +805 -0
  52. nab_python/download.py +170 -0
  53. nab_python/fetch.py +827 -0
  54. nab_python/lockfile.py +238 -0
  55. nab_python/metadata.py +145 -0
  56. nab_python/provider.py +1235 -0
  57. nab_python/py.typed +0 -0
  58. nab_python/requirements_file.py +180 -0
  59. nab_python/resolve.py +497 -0
  60. nab_python/universal/__init__.py +1 -0
  61. nab_python/universal/matrix.py +235 -0
  62. nab_python/universal/provider.py +214 -0
  63. nab_python/universal/reresolve.py +310 -0
  64. nab_python/universal/resolve.py +508 -0
  65. nab_python/universal/validate.py +439 -0
  66. nab_python/universal/wheel_selection.py +327 -0
  67. nab_python/workspace.py +214 -0
  68. nab_python-0.0.1.dist-info/METADATA +49 -0
  69. nab_python-0.0.1.dist-info/RECORD +71 -0
  70. nab_python-0.0.1.dist-info/WHEEL +4 -0
  71. nab_python-0.0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1141 @@
1
+ # This file is dual licensed under the terms of the Apache License, Version
2
+ # 2.0, and the BSD License. See the LICENSE file in the root of this repository
3
+ # for complete details.
4
+ """
5
+ .. testsetup::
6
+
7
+ from packaging.ranges import VersionRange
8
+ from packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier
9
+ from packaging.version import Version
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import abc
15
+ import re
16
+ import sys
17
+ import typing
18
+ from typing import (
19
+ TYPE_CHECKING,
20
+ Any,
21
+ Callable,
22
+ Final,
23
+ TypeVar,
24
+ Union,
25
+ )
26
+
27
+ from .ranges import VersionRange
28
+ from .utils import canonicalize_version
29
+ from .version import InvalidVersion, Version
30
+
31
+ if sys.version_info >= (3, 10):
32
+ from typing import TypeGuard # pragma: no cover
33
+ elif TYPE_CHECKING:
34
+ from typing_extensions import TypeGuard
35
+
36
+ if TYPE_CHECKING:
37
+ from collections.abc import Iterable, Iterator
38
+
39
+
40
+ __all__ = [
41
+ "BaseSpecifier",
42
+ "InvalidSpecifier",
43
+ "Specifier",
44
+ "SpecifierSet",
45
+ ]
46
+
47
+
48
+ def __dir__() -> list[str]:
49
+ return __all__
50
+
51
+
52
+ def _validate_spec(spec: object, /) -> TypeGuard[tuple[str, str]]:
53
+ return (
54
+ isinstance(spec, tuple)
55
+ and len(spec) == 2
56
+ and isinstance(spec[0], str)
57
+ and isinstance(spec[1], str)
58
+ )
59
+
60
+
61
+ def _validate_pre(pre: object, /) -> TypeGuard[bool | None]:
62
+ return pre is None or isinstance(pre, bool)
63
+
64
+
65
+ T = TypeVar("T")
66
+ UnparsedVersion = Union[Version, str]
67
+ UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion)
68
+
69
+
70
+ def _coerce_version(version: UnparsedVersion) -> Version | None:
71
+ if not isinstance(version, Version):
72
+ try:
73
+ version = Version(version)
74
+ except InvalidVersion:
75
+ return None
76
+ return version
77
+
78
+
79
+ class InvalidSpecifier(ValueError):
80
+ """
81
+ Raised when attempting to create a :class:`Specifier` with a specifier
82
+ string that is invalid.
83
+
84
+ >>> Specifier("lolwat")
85
+ Traceback (most recent call last):
86
+ ...
87
+ packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat'
88
+ """
89
+
90
+
91
+ class BaseSpecifier(metaclass=abc.ABCMeta):
92
+ __slots__ = ()
93
+ __match_args__ = ("_str",)
94
+
95
+ @property
96
+ def _str(self) -> str:
97
+ """Internal property for match_args"""
98
+ return str(self)
99
+
100
+ @abc.abstractmethod
101
+ def __str__(self) -> str:
102
+ """
103
+ Returns the str representation of this Specifier-like object. This
104
+ should be representative of the Specifier itself.
105
+ """
106
+
107
+ @abc.abstractmethod
108
+ def __hash__(self) -> int:
109
+ """
110
+ Returns a hash value for this Specifier-like object.
111
+ """
112
+
113
+ @abc.abstractmethod
114
+ def __eq__(self, other: object) -> bool:
115
+ """
116
+ Returns a boolean representing whether or not the two Specifier-like
117
+ objects are equal.
118
+
119
+ :param other: The other object to check against.
120
+ """
121
+
122
+ @property
123
+ @abc.abstractmethod
124
+ def prereleases(self) -> bool | None:
125
+ """Whether or not pre-releases as a whole are allowed.
126
+
127
+ This can be set to either ``True`` or ``False`` to explicitly enable or disable
128
+ prereleases or it can be set to ``None`` (the default) to use default semantics.
129
+ """
130
+
131
+ @prereleases.setter # noqa: B027
132
+ def prereleases(self, value: bool) -> None:
133
+ """Setter for :attr:`prereleases`.
134
+
135
+ :param value: The value to set.
136
+ """
137
+
138
+ @abc.abstractmethod
139
+ def contains(self, item: str, prereleases: bool | None = None) -> bool:
140
+ """
141
+ Determines if the given item is contained within this specifier.
142
+ """
143
+
144
+ @typing.overload
145
+ def filter(
146
+ self,
147
+ iterable: Iterable[UnparsedVersionVar],
148
+ prereleases: bool | None = None,
149
+ key: None = ...,
150
+ ) -> Iterator[UnparsedVersionVar]: ...
151
+
152
+ @typing.overload
153
+ def filter(
154
+ self,
155
+ iterable: Iterable[T],
156
+ prereleases: bool | None = None,
157
+ key: Callable[[T], UnparsedVersion] = ...,
158
+ ) -> Iterator[T]: ...
159
+
160
+ @abc.abstractmethod
161
+ def filter(
162
+ self,
163
+ iterable: Iterable[Any],
164
+ prereleases: bool | None = None,
165
+ key: Callable[[Any], UnparsedVersion] | None = None,
166
+ ) -> Iterator[Any]:
167
+ """
168
+ Takes an iterable of items and filters them so that only items which
169
+ are contained within this specifier are allowed in it.
170
+ """
171
+
172
+
173
+ class Specifier(BaseSpecifier):
174
+ """This class abstracts handling of version specifiers.
175
+
176
+ .. tip::
177
+
178
+ It is generally not required to instantiate this manually. You should instead
179
+ prefer to work with :class:`SpecifierSet` instead, which can parse
180
+ comma-separated version specifiers (which is what package metadata contains).
181
+
182
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
183
+ format so the same pickle can be loaded in future packaging releases.
184
+
185
+ .. versionchanged:: 26.2
186
+
187
+ Added a stable pickle format. Pickles created with packaging 26.2+ can
188
+ be unpickled with future releases. Backward compatibility with pickles
189
+ from packaging < 26.2 is supported but may be removed in a future
190
+ release.
191
+ """
192
+
193
+ __slots__ = (
194
+ "_prereleases",
195
+ "_range_cache",
196
+ "_spec",
197
+ "_spec_version",
198
+ )
199
+
200
+ _specifier_regex_str = r"""
201
+ (?:
202
+ (?:
203
+ # The identity operators allow for an escape hatch that will
204
+ # do an exact string match of the version you wish to install.
205
+ # This will not be parsed by PEP 440 and we cannot determine
206
+ # any semantic meaning from it. This operator is discouraged
207
+ # but included entirely as an escape hatch.
208
+ === # Only match for the identity operator
209
+ \s*
210
+ [^\s;)]* # The arbitrary version can be just about anything,
211
+ # we match everything except for whitespace, a
212
+ # semi-colon for marker support, and a closing paren
213
+ # since versions can be enclosed in them.
214
+ )
215
+ |
216
+ (?:
217
+ # The (non)equality operators allow for wild card and local
218
+ # versions to be specified so we have to define these two
219
+ # operators separately to enable that.
220
+ (?:==|!=) # Only match for equals and not equals
221
+
222
+ \s*
223
+ v?
224
+ (?:[0-9]+!)? # epoch
225
+ [0-9]+(?:\.[0-9]+)* # release
226
+
227
+ # You cannot use a wild card and a pre-release, post-release, a dev or
228
+ # local version together so group them with a | and make them optional.
229
+ (?:
230
+ \.\* # Wild card syntax of .*
231
+ |
232
+ (?a: # pre release
233
+ [-_\.]?
234
+ (alpha|beta|preview|pre|a|b|c|rc)
235
+ [-_\.]?
236
+ [0-9]*
237
+ )?
238
+ (?a: # post release
239
+ (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
240
+ )?
241
+ (?a:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
242
+ (?a:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
243
+ )?
244
+ )
245
+ |
246
+ (?:
247
+ # The compatible operator requires at least two digits in the
248
+ # release segment.
249
+ (?:~=) # Only match for the compatible operator
250
+
251
+ \s*
252
+ v?
253
+ (?:[0-9]+!)? # epoch
254
+ [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
255
+ (?: # pre release
256
+ [-_\.]?
257
+ (alpha|beta|preview|pre|a|b|c|rc)
258
+ [-_\.]?
259
+ [0-9]*
260
+ )?
261
+ (?: # post release
262
+ (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
263
+ )?
264
+ (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
265
+ )
266
+ |
267
+ (?:
268
+ # All other operators only allow a sub set of what the
269
+ # (non)equality operators do. Specifically they do not allow
270
+ # local versions to be specified nor do they allow the prefix
271
+ # matching wild cards.
272
+ (?:<=|>=|<|>)
273
+
274
+ \s*
275
+ v?
276
+ (?:[0-9]+!)? # epoch
277
+ [0-9]+(?:\.[0-9]+)* # release
278
+ (?a: # pre release
279
+ [-_\.]?
280
+ (alpha|beta|preview|pre|a|b|c|rc)
281
+ [-_\.]?
282
+ [0-9]*
283
+ )?
284
+ (?a: # post release
285
+ (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
286
+ )?
287
+ (?a:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
288
+ )
289
+ )
290
+ """
291
+
292
+ _regex = re.compile(
293
+ r"\s*" + _specifier_regex_str + r"\s*", re.VERBOSE | re.IGNORECASE
294
+ )
295
+
296
+ # Legacy unused attribute, kept for backward compatibility
297
+ _operators: Final = {
298
+ "~=": "compatible",
299
+ "==": "equal",
300
+ "!=": "not_equal",
301
+ "<=": "less_than_equal",
302
+ ">=": "greater_than_equal",
303
+ "<": "less_than",
304
+ ">": "greater_than",
305
+ "===": "arbitrary",
306
+ }
307
+
308
+ def __init__(self, spec: str = "", prereleases: bool | None = None) -> None:
309
+ """Initialize a Specifier instance.
310
+
311
+ :param spec:
312
+ The string representation of a specifier which will be parsed and
313
+ normalized before use.
314
+ :param prereleases:
315
+ This tells the specifier if it should accept prerelease versions if
316
+ applicable or not. The default of ``None`` will autodetect it from the
317
+ given specifiers.
318
+ :raises InvalidSpecifier:
319
+ If the given specifier is invalid (i.e. bad syntax).
320
+ """
321
+ if not self._regex.fullmatch(spec):
322
+ raise InvalidSpecifier(f"Invalid specifier: {spec!r}")
323
+
324
+ spec = spec.strip()
325
+ if spec.startswith("==="):
326
+ operator, version = spec[:3], spec[3:].strip()
327
+ elif spec.startswith(("~=", "==", "!=", "<=", ">=")):
328
+ operator, version = spec[:2], spec[2:].strip()
329
+ else:
330
+ operator, version = spec[:1], spec[1:].strip()
331
+
332
+ self._spec: tuple[str, str] = (operator, version)
333
+
334
+ # Store whether or not this Specifier should accept prereleases
335
+ self._prereleases = prereleases
336
+
337
+ # Specifier version cache
338
+ self._spec_version: tuple[str, Version] | None = None
339
+
340
+ # VersionRange cache (populated by VersionRange.from_specifier)
341
+ self._range_cache: VersionRange | None = None
342
+
343
+ def _get_spec_version(self, version: str) -> Version | None:
344
+ """One element cache, as only one spec Version is needed per Specifier."""
345
+ if self._spec_version is not None and self._spec_version[0] == version:
346
+ return self._spec_version[1]
347
+
348
+ version_specifier = _coerce_version(version)
349
+ if version_specifier is None:
350
+ return None
351
+
352
+ self._spec_version = (version, version_specifier)
353
+ return version_specifier
354
+
355
+ def _require_spec_version(self, version: str) -> Version:
356
+ """Get spec version, asserting it's valid (not for === operator).
357
+
358
+ This method should only be called for operators where version
359
+ strings are guaranteed to be valid PEP 440 versions (not ===).
360
+ """
361
+ spec_version = self._get_spec_version(version)
362
+ assert spec_version is not None
363
+ return spec_version
364
+
365
+ @property
366
+ def _range(self) -> VersionRange:
367
+ """The :class:`VersionRange` accepted by this specifier.
368
+
369
+ Computed lazily; cached on the instance.
370
+ """
371
+ return VersionRange.from_specifier(self)
372
+
373
+ @property
374
+ def prereleases(self) -> bool | None:
375
+ # If there is an explicit prereleases set for this, then we'll just
376
+ # blindly use that.
377
+ if self._prereleases is not None:
378
+ return self._prereleases
379
+
380
+ # Only the "!=" operator does not imply prereleases when
381
+ # the version in the specifier is a prerelease.
382
+ operator, version_str = self._spec
383
+ if operator == "!=":
384
+ return False
385
+
386
+ # The == specifier with trailing .* cannot include prereleases
387
+ # e.g. "==1.0a1.*" is not valid.
388
+ if operator == "==" and version_str.endswith(".*"):
389
+ return False
390
+
391
+ # "===" can have arbitrary string versions, so we cannot parse
392
+ # those, we take prereleases as unknown (None) for those.
393
+ version = self._get_spec_version(version_str)
394
+ if version is None:
395
+ return None
396
+
397
+ # For all other operators, use the check if spec Version
398
+ # object implies pre-releases.
399
+ return version.is_prerelease
400
+
401
+ @prereleases.setter
402
+ def prereleases(self, value: bool | None) -> None:
403
+ self._prereleases = value
404
+
405
+ def __getstate__(self) -> tuple[tuple[str, str], bool | None]:
406
+ # Return state as a 2-item tuple for compactness:
407
+ # ((operator, version), prereleases)
408
+ # Cache members are excluded and will be recomputed on demand.
409
+ return (self._spec, self._prereleases)
410
+
411
+ def __setstate__(self, state: object) -> None:
412
+ # Always discard cached values - they will be recomputed on demand.
413
+ self._spec_version = None
414
+ self._range_cache = None
415
+
416
+ if isinstance(state, tuple):
417
+ if len(state) == 2:
418
+ # New format (26.2+): ((operator, version), prereleases)
419
+ spec, prereleases = state
420
+ if _validate_spec(spec) and _validate_pre(prereleases):
421
+ self._spec = spec
422
+ self._prereleases = prereleases
423
+ return
424
+ if len(state) == 2 and isinstance(state[1], dict):
425
+ # Format (packaging 26.0-26.1): (None, {slot: value}).
426
+ _, slot_dict = state
427
+ spec = slot_dict.get("_spec")
428
+ prereleases = slot_dict.get("_prereleases", "invalid")
429
+ if _validate_spec(spec) and _validate_pre(prereleases):
430
+ self._spec = spec
431
+ self._prereleases = prereleases
432
+ return
433
+ if isinstance(state, dict):
434
+ # Old format (packaging <= 25.x, no __slots__): state is a plain dict.
435
+ spec = state.get("_spec")
436
+ prereleases = state.get("_prereleases", "invalid")
437
+ if _validate_spec(spec) and _validate_pre(prereleases):
438
+ self._spec = spec
439
+ self._prereleases = prereleases
440
+ return
441
+
442
+ raise TypeError(f"Cannot restore Specifier from {state!r}")
443
+
444
+ @property
445
+ def operator(self) -> str:
446
+ """The operator of this specifier.
447
+
448
+ >>> Specifier("==1.2.3").operator
449
+ '=='
450
+ """
451
+ return self._spec[0]
452
+
453
+ @property
454
+ def version(self) -> str:
455
+ """The version of this specifier.
456
+
457
+ >>> Specifier("==1.2.3").version
458
+ '1.2.3'
459
+ """
460
+ return self._spec[1]
461
+
462
+ def __repr__(self) -> str:
463
+ """A representation of the Specifier that shows all internal state.
464
+
465
+ >>> Specifier('>=1.0.0')
466
+ <Specifier('>=1.0.0')>
467
+ >>> Specifier('>=1.0.0', prereleases=False)
468
+ <Specifier('>=1.0.0', prereleases=False)>
469
+ >>> Specifier('>=1.0.0', prereleases=True)
470
+ <Specifier('>=1.0.0', prereleases=True)>
471
+ """
472
+ pre = (
473
+ f", prereleases={self.prereleases!r}"
474
+ if self._prereleases is not None
475
+ else ""
476
+ )
477
+
478
+ return f"<{self.__class__.__name__}({str(self)!r}{pre})>"
479
+
480
+ def __str__(self) -> str:
481
+ """A string representation of the Specifier that can be round-tripped.
482
+
483
+ >>> str(Specifier('>=1.0.0'))
484
+ '>=1.0.0'
485
+ >>> str(Specifier('>=1.0.0', prereleases=False))
486
+ '>=1.0.0'
487
+ """
488
+ return "{}{}".format(*self._spec)
489
+
490
+ @property
491
+ def _canonical_spec(self) -> tuple[str, str]:
492
+ operator, version = self._spec
493
+ if operator == "===" or version.endswith(".*"):
494
+ return operator, version
495
+
496
+ spec_version = self._require_spec_version(version)
497
+
498
+ canonical_version = canonicalize_version(
499
+ spec_version, strip_trailing_zero=(operator != "~=")
500
+ )
501
+
502
+ return operator, canonical_version
503
+
504
+ def __hash__(self) -> int:
505
+ return hash(self._canonical_spec)
506
+
507
+ def __eq__(self, other: object) -> bool:
508
+ """Whether or not the two Specifier-like objects are equal.
509
+
510
+ :param other: The other object to check against.
511
+
512
+ The value of :attr:`prereleases` is ignored.
513
+
514
+ >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0")
515
+ True
516
+ >>> (Specifier("==1.2.3", prereleases=False) ==
517
+ ... Specifier("==1.2.3", prereleases=True))
518
+ True
519
+ >>> Specifier("==1.2.3") == "==1.2.3"
520
+ True
521
+ >>> Specifier("==1.2.3") == Specifier("==1.2.4")
522
+ False
523
+ >>> Specifier("==1.2.3") == Specifier("~=1.2.3")
524
+ False
525
+ """
526
+ if isinstance(other, str):
527
+ try:
528
+ other = self.__class__(str(other))
529
+ except InvalidSpecifier:
530
+ return NotImplemented
531
+ elif not isinstance(other, self.__class__):
532
+ return NotImplemented
533
+
534
+ return self._canonical_spec == other._canonical_spec
535
+
536
+ def __contains__(self, item: str | Version) -> bool:
537
+ """Return whether or not the item is contained in this specifier.
538
+
539
+ :param item: The item to check for.
540
+
541
+ This is used for the ``in`` operator and behaves the same as
542
+ :meth:`contains` with no ``prereleases`` argument passed.
543
+
544
+ >>> "1.2.3" in Specifier(">=1.2.3")
545
+ True
546
+ >>> Version("1.2.3") in Specifier(">=1.2.3")
547
+ True
548
+ >>> "1.0.0" in Specifier(">=1.2.3")
549
+ False
550
+ >>> "1.3.0a1" in Specifier(">=1.2.3")
551
+ True
552
+ >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True)
553
+ True
554
+ """
555
+ return self.contains(item)
556
+
557
+ def contains(self, item: UnparsedVersion, prereleases: bool | None = None) -> bool:
558
+ """Return whether or not the item is contained in this specifier.
559
+
560
+ :param item:
561
+ The item to check for, which can be a version string or a
562
+ :class:`Version` instance.
563
+ :param prereleases:
564
+ Whether or not to match prereleases with this Specifier. If set to
565
+ ``None`` (the default), it will follow the recommendation from
566
+ :pep:`440` and match prereleases, as there are no other versions.
567
+
568
+ >>> Specifier(">=1.2.3").contains("1.2.3")
569
+ True
570
+ >>> Specifier(">=1.2.3").contains(Version("1.2.3"))
571
+ True
572
+ >>> Specifier(">=1.2.3").contains("1.0.0")
573
+ False
574
+ >>> Specifier(">=1.2.3").contains("1.3.0a1")
575
+ True
576
+ >>> Specifier(">=1.2.3", prereleases=False).contains("1.3.0a1")
577
+ False
578
+ >>> Specifier(">=1.2.3").contains("1.3.0a1")
579
+ True
580
+ """
581
+
582
+ return bool(list(self.filter([item], prereleases=prereleases)))
583
+
584
+ def to_range(self) -> VersionRange:
585
+ """The :class:`VersionRange` accepted by this specifier.
586
+
587
+ For ``===`` the returned range matches the literal string
588
+ case-insensitively; no PEP 440 :class:`Version` other than the
589
+ literal itself is contained.
590
+
591
+ >>> isinstance(Specifier(">=1.0").to_range(), VersionRange)
592
+ True
593
+ >>> "wat" in Specifier("===wat").to_range()
594
+ True
595
+ """
596
+ return VersionRange.from_specifier(self)
597
+
598
+ @typing.overload
599
+ def filter(
600
+ self,
601
+ iterable: Iterable[UnparsedVersionVar],
602
+ prereleases: bool | None = None,
603
+ key: None = ...,
604
+ ) -> Iterator[UnparsedVersionVar]: ...
605
+
606
+ @typing.overload
607
+ def filter(
608
+ self,
609
+ iterable: Iterable[T],
610
+ prereleases: bool | None = None,
611
+ key: Callable[[T], UnparsedVersion] = ...,
612
+ ) -> Iterator[T]: ...
613
+
614
+ def filter(
615
+ self,
616
+ iterable: Iterable[Any],
617
+ prereleases: bool | None = None,
618
+ key: Callable[[Any], UnparsedVersion] | None = None,
619
+ ) -> Iterator[Any]:
620
+ """Filter items in the given iterable, that match the specifier.
621
+
622
+ :param iterable:
623
+ An iterable that can contain version strings and :class:`Version` instances.
624
+ The items in the iterable will be filtered according to the specifier.
625
+ :param prereleases:
626
+ Whether or not to allow prereleases in the returned iterator. If set to
627
+ ``None`` (the default), it will follow the recommendation from :pep:`440`
628
+ and match prereleases if there are no other versions.
629
+ :param key:
630
+ A callable that takes a single argument (an item from the iterable) and
631
+ returns a version string or :class:`Version` instance to be used for
632
+ filtering.
633
+
634
+ >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
635
+ ['1.3']
636
+ >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")]))
637
+ ['1.2.3', '1.3', <Version('1.4')>]
638
+ >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"]))
639
+ ['1.5a1']
640
+ >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
641
+ ['1.3', '1.5a1']
642
+ >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
643
+ ['1.3', '1.5a1']
644
+ >>> list(Specifier(">=1.2.3").filter(
645
+ ... [{"ver": "1.2"}, {"ver": "1.3"}],
646
+ ... key=lambda x: x["ver"]))
647
+ [{'ver': '1.3'}]
648
+ """
649
+ # Inlined ``_resolve_prereleases`` for hot-path performance.
650
+ if prereleases is None:
651
+ if self._prereleases is not None:
652
+ prereleases = self._prereleases
653
+ elif self.prereleases:
654
+ prereleases = True
655
+ version_range = self._range_cache
656
+ if version_range is None:
657
+ version_range = VersionRange.from_specifier(self)
658
+ return version_range.filter(iterable, key, prereleases)
659
+
660
+ def _resolve_prereleases(self, prereleases: bool | None) -> bool | None:
661
+ """Resolve ``prereleases`` for :meth:`filter` / :meth:`contains`.
662
+
663
+ Explicit caller argument wins; otherwise the constructor value
664
+ ``self._prereleases``; otherwise auto-detected ``self.prereleases``
665
+ only when True (an auto-detected False does not propagate, so
666
+ non-pre specifiers keep PEP 440 default behaviour).
667
+ """
668
+ if prereleases is not None:
669
+ return prereleases
670
+ if self._prereleases is not None:
671
+ return self._prereleases
672
+ if self.prereleases:
673
+ return True
674
+ return None
675
+
676
+
677
+ class SpecifierSet(BaseSpecifier):
678
+ """This class abstracts handling of a set of version specifiers.
679
+
680
+ It can be passed a single specifier (``>=3.0``), a comma-separated list of
681
+ specifiers (``>=3.0,!=3.1``), or no specifier at all.
682
+
683
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
684
+ format so the same pickle can be loaded in future packaging
685
+ releases.
686
+
687
+ .. versionchanged:: 26.2
688
+
689
+ Added a stable pickle format. Pickles created with
690
+ packaging 26.2+ can be unpickled with future releases.
691
+ Backward compatibility with pickles from
692
+ packaging < 26.2 is supported but may be removed in a future
693
+ release.
694
+ """
695
+
696
+ __slots__ = (
697
+ "_canonicalized",
698
+ "_is_unsatisfiable",
699
+ "_prereleases",
700
+ "_range_cache",
701
+ "_specs",
702
+ )
703
+
704
+ def __init__(
705
+ self,
706
+ specifiers: str | Iterable[Specifier] = "",
707
+ prereleases: bool | None = None,
708
+ ) -> None:
709
+ """Initialize a SpecifierSet instance.
710
+
711
+ :param specifiers:
712
+ The string representation of a specifier or a comma-separated list of
713
+ specifiers which will be parsed and normalized before use.
714
+ May also be an iterable of ``Specifier`` instances, which will be used
715
+ as is.
716
+ :param prereleases:
717
+ This tells the SpecifierSet if it should accept prerelease versions if
718
+ applicable or not. The default of ``None`` will autodetect it from the
719
+ given specifiers.
720
+
721
+ :raises InvalidSpecifier:
722
+ If the given ``specifiers`` are not parseable than this exception will be
723
+ raised.
724
+ """
725
+
726
+ if isinstance(specifiers, str):
727
+ split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
728
+ self._specs: tuple[Specifier, ...] = tuple(map(Specifier, split_specifiers))
729
+ else:
730
+ self._specs = tuple(specifiers)
731
+
732
+ self._canonicalized = len(self._specs) <= 1
733
+ self._is_unsatisfiable: bool | None = None
734
+ self._range_cache: VersionRange | None = None
735
+ self._prereleases = prereleases
736
+
737
+ def _canonical_specs(self) -> tuple[Specifier, ...]:
738
+ """Deduplicate, sort, and cache specs for order-sensitive operations."""
739
+ if not self._canonicalized:
740
+ self._specs = tuple(dict.fromkeys(sorted(self._specs, key=str)))
741
+ self._canonicalized = True
742
+ self._is_unsatisfiable = None
743
+ self._range_cache = None
744
+ return self._specs
745
+
746
+ @property
747
+ def prereleases(self) -> bool | None:
748
+ # If we have been given an explicit prerelease modifier, then we'll
749
+ # pass that through here.
750
+ if self._prereleases is not None:
751
+ return self._prereleases
752
+
753
+ # If we don't have any specifiers, and we don't have a forced value,
754
+ # then we'll just return None since we don't know if this should have
755
+ # pre-releases or not.
756
+ if not self._specs:
757
+ return None
758
+
759
+ # Otherwise we'll see if any of the given specifiers accept
760
+ # prereleases, if any of them do we'll return True, otherwise False.
761
+ if any(s.prereleases for s in self._specs):
762
+ return True
763
+
764
+ return None
765
+
766
+ @prereleases.setter
767
+ def prereleases(self, value: bool | None) -> None:
768
+ self._prereleases = value
769
+ self._is_unsatisfiable = None
770
+ self._range_cache = None
771
+
772
+ def __getstate__(self) -> tuple[tuple[Specifier, ...], bool | None]:
773
+ # Return state as a 2-item tuple for compactness:
774
+ # (specs, prereleases)
775
+ # Cache members are excluded and will be recomputed on demand.
776
+ return (self._specs, self._prereleases)
777
+
778
+ def __setstate__(self, state: object) -> None:
779
+ # Always discard cached values - they will be recomputed on demand.
780
+ self._is_unsatisfiable = None
781
+ self._range_cache = None
782
+
783
+ if isinstance(state, tuple):
784
+ if len(state) == 2:
785
+ # New format (26.2+): (specs, prereleases)
786
+ specs, prereleases = state
787
+ if (
788
+ isinstance(specs, tuple)
789
+ and all(isinstance(s, Specifier) for s in specs)
790
+ and _validate_pre(prereleases)
791
+ ):
792
+ self._specs = specs
793
+ self._prereleases = prereleases
794
+ self._canonicalized = len(specs) <= 1
795
+ return
796
+ if len(state) == 2 and isinstance(state[1], dict):
797
+ # Format (packaging 26.0-26.1): (None, {slot: value}).
798
+ _, slot_dict = state
799
+ specs = slot_dict.get("_specs", ())
800
+ prereleases = slot_dict.get("_prereleases")
801
+ # Convert frozenset to tuple (26.0 stored as frozenset)
802
+ if isinstance(specs, frozenset):
803
+ specs = tuple(sorted(specs, key=str))
804
+ if (
805
+ isinstance(specs, tuple)
806
+ and all(isinstance(s, Specifier) for s in specs)
807
+ and _validate_pre(prereleases)
808
+ ):
809
+ self._specs = specs
810
+ self._prereleases = prereleases
811
+ self._canonicalized = len(self._specs) <= 1
812
+ return
813
+ if isinstance(state, dict):
814
+ # Old format (packaging <= 25.x, no __slots__): state is a plain dict.
815
+ specs = state.get("_specs", ())
816
+ prereleases = state.get("_prereleases")
817
+ # Convert frozenset to tuple (26.0 stored as frozenset)
818
+ if isinstance(specs, frozenset):
819
+ specs = tuple(sorted(specs, key=str))
820
+ if (
821
+ isinstance(specs, tuple)
822
+ and all(isinstance(s, Specifier) for s in specs)
823
+ and _validate_pre(prereleases)
824
+ ):
825
+ self._specs = specs
826
+ self._prereleases = prereleases
827
+ self._canonicalized = len(self._specs) <= 1
828
+ return
829
+
830
+ raise TypeError(f"Cannot restore SpecifierSet from {state!r}")
831
+
832
+ def __repr__(self) -> str:
833
+ """A representation of the specifier set that shows all internal state.
834
+
835
+ Note that the ordering of the individual specifiers within the set may not
836
+ match the input string.
837
+
838
+ >>> SpecifierSet('>=1.0.0,!=2.0.0')
839
+ <SpecifierSet('!=2.0.0,>=1.0.0')>
840
+ >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False)
841
+ <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=False)>
842
+ >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True)
843
+ <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=True)>
844
+ """
845
+ pre = (
846
+ f", prereleases={self.prereleases!r}"
847
+ if self._prereleases is not None
848
+ else ""
849
+ )
850
+
851
+ return f"<{self.__class__.__name__}({str(self)!r}{pre})>"
852
+
853
+ def __str__(self) -> str:
854
+ """A string representation of the specifier set that can be round-tripped.
855
+
856
+ Note that the ordering of the individual specifiers within the set may not
857
+ match the input string.
858
+
859
+ >>> str(SpecifierSet(">=1.0.0,!=1.0.1"))
860
+ '!=1.0.1,>=1.0.0'
861
+ >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False))
862
+ '!=1.0.1,>=1.0.0'
863
+ """
864
+ return ",".join(str(s) for s in self._canonical_specs())
865
+
866
+ def __hash__(self) -> int:
867
+ return hash(self._canonical_specs())
868
+
869
+ def __and__(self, other: SpecifierSet | str) -> SpecifierSet:
870
+ """Return a SpecifierSet which is a combination of the two sets.
871
+
872
+ :param other: The other object to combine with.
873
+
874
+ >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1'
875
+ <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
876
+ >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1')
877
+ <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
878
+ """
879
+ if isinstance(other, str):
880
+ other = SpecifierSet(other)
881
+ elif not isinstance(other, SpecifierSet):
882
+ return NotImplemented
883
+
884
+ specifier = SpecifierSet()
885
+ specifier._specs = self._specs + other._specs
886
+ specifier._canonicalized = len(specifier._specs) <= 1
887
+
888
+ if self._prereleases is None or self._prereleases == other._prereleases:
889
+ specifier._prereleases = other._prereleases
890
+ elif other._prereleases is None:
891
+ specifier._prereleases = self._prereleases
892
+ else:
893
+ raise ValueError(
894
+ "Cannot combine SpecifierSets with True and False prerelease overrides."
895
+ )
896
+
897
+ return specifier
898
+
899
+ def __eq__(self, other: object) -> bool:
900
+ """Whether or not the two SpecifierSet-like objects are equal.
901
+
902
+ :param other: The other object to check against.
903
+
904
+ The value of :attr:`prereleases` is ignored.
905
+
906
+ >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1")
907
+ True
908
+ >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) ==
909
+ ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True))
910
+ True
911
+ >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1"
912
+ True
913
+ >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0")
914
+ False
915
+ >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2")
916
+ False
917
+ """
918
+ if isinstance(other, (str, Specifier)):
919
+ other = SpecifierSet(str(other))
920
+ elif not isinstance(other, SpecifierSet):
921
+ return NotImplemented
922
+
923
+ return self._canonical_specs() == other._canonical_specs()
924
+
925
+ def __len__(self) -> int:
926
+ """Returns the number of specifiers in this specifier set."""
927
+ return len(self._specs)
928
+
929
+ def __iter__(self) -> Iterator[Specifier]:
930
+ """
931
+ Returns an iterator over all the underlying :class:`Specifier` instances
932
+ in this specifier set.
933
+
934
+ >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str)
935
+ [<Specifier('!=1.0.1')>, <Specifier('>=1.0.0')>]
936
+ """
937
+ return iter(self._specs)
938
+
939
+ @property
940
+ def _range(self) -> VersionRange:
941
+ """The intersection of every specifier's :class:`VersionRange`.
942
+
943
+ Computed lazily; cached on the instance.
944
+ """
945
+ return VersionRange.from_specifier_set(self)
946
+
947
+ def is_unsatisfiable(self) -> bool:
948
+ """Check whether this specifier set can never be satisfied.
949
+
950
+ Returns True if no version can satisfy all specifiers simultaneously.
951
+
952
+ >>> SpecifierSet(">=2.0,<1.0").is_unsatisfiable()
953
+ True
954
+ >>> SpecifierSet(">=1.0,<2.0").is_unsatisfiable()
955
+ False
956
+ >>> SpecifierSet("").is_unsatisfiable()
957
+ False
958
+ >>> SpecifierSet("==1.0,!=1.0").is_unsatisfiable()
959
+ True
960
+ """
961
+ cached = self._is_unsatisfiable
962
+ if cached is not None:
963
+ return cached
964
+
965
+ if not self._specs:
966
+ self._is_unsatisfiable = False
967
+ return False
968
+
969
+ # An empty combined range covers contradicting bounds and
970
+ # disagreeing === literals; only-pre-release matches still
971
+ # count as unsatisfiable when prereleases=False.
972
+ range_ = self._range
973
+ if range_.is_empty:
974
+ self._is_unsatisfiable = True
975
+ return True
976
+ if self.prereleases is not False:
977
+ self._is_unsatisfiable = False
978
+ return False
979
+ result = range_.is_prerelease_only
980
+ self._is_unsatisfiable = result
981
+ return result
982
+
983
+ def to_range(self) -> VersionRange:
984
+ """The :class:`VersionRange` accepted by this specifier set.
985
+
986
+ The intersection of every specifier in the set. An empty
987
+ :class:`SpecifierSet` yields the unbounded range; an
988
+ unsatisfiable set yields an empty :class:`VersionRange`. Sets
989
+ containing ``===`` produce a range whose only matching items
990
+ are the literal strings (case-insensitive) that satisfy every
991
+ rangelike specifier in the set as well.
992
+
993
+ >>> isinstance(SpecifierSet(">=1.0,<2.0").to_range(), VersionRange)
994
+ True
995
+ >>> SpecifierSet(">=1.0,<2.0").to_range().is_empty
996
+ False
997
+ >>> SpecifierSet(">=2.0,<1.0").to_range().is_empty
998
+ True
999
+ >>> "wat" in SpecifierSet("===wat").to_range()
1000
+ True
1001
+ """
1002
+ return VersionRange.from_specifier_set(self)
1003
+
1004
+ def __contains__(self, item: UnparsedVersion) -> bool:
1005
+ """Return whether or not the item is contained in this specifier.
1006
+
1007
+ :param item: The item to check for.
1008
+
1009
+ This is used for the ``in`` operator and behaves the same as
1010
+ :meth:`contains` with no ``prereleases`` argument passed.
1011
+
1012
+ >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1")
1013
+ True
1014
+ >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1")
1015
+ True
1016
+ >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1")
1017
+ False
1018
+ >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1")
1019
+ True
1020
+ >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)
1021
+ True
1022
+ """
1023
+ return self.contains(item)
1024
+
1025
+ def contains(
1026
+ self,
1027
+ item: UnparsedVersion,
1028
+ prereleases: bool | None = None,
1029
+ installed: bool | None = None,
1030
+ ) -> bool:
1031
+ """Return whether or not the item is contained in this SpecifierSet.
1032
+
1033
+ :param item:
1034
+ The item to check for, which can be a version string or a
1035
+ :class:`Version` instance.
1036
+ :param prereleases:
1037
+ Whether or not to match prereleases with this SpecifierSet. If set to
1038
+ ``None`` (the default), it will follow the recommendation from :pep:`440`
1039
+ and match prereleases, as there are no other versions.
1040
+ :param installed:
1041
+ Whether or not the item is installed. If set to ``True``, it will
1042
+ accept prerelease versions even if the specifier does not allow them.
1043
+
1044
+ >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3")
1045
+ True
1046
+ >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3"))
1047
+ True
1048
+ >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1")
1049
+ False
1050
+ >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1")
1051
+ True
1052
+ >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False).contains("1.3.0a1")
1053
+ False
1054
+ >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True)
1055
+ True
1056
+ """
1057
+ if installed:
1058
+ version = _coerce_version(item)
1059
+ if version is not None and version.is_prerelease:
1060
+ prereleases = True
1061
+ return bool(list(self.filter([item], prereleases=prereleases)))
1062
+
1063
+ def _resolve_prereleases(self, prereleases: bool | None) -> bool | None:
1064
+ """Resolve ``prereleases`` for :meth:`filter` / :meth:`contains`.
1065
+
1066
+ Explicit caller argument wins; otherwise ``self.prereleases``.
1067
+ """
1068
+ if prereleases is not None:
1069
+ return prereleases
1070
+ return self.prereleases
1071
+
1072
+ @typing.overload
1073
+ def filter(
1074
+ self,
1075
+ iterable: Iterable[UnparsedVersionVar],
1076
+ prereleases: bool | None = None,
1077
+ key: None = ...,
1078
+ ) -> Iterator[UnparsedVersionVar]: ...
1079
+
1080
+ @typing.overload
1081
+ def filter(
1082
+ self,
1083
+ iterable: Iterable[T],
1084
+ prereleases: bool | None = None,
1085
+ key: Callable[[T], UnparsedVersion] = ...,
1086
+ ) -> Iterator[T]: ...
1087
+
1088
+ def filter(
1089
+ self,
1090
+ iterable: Iterable[Any],
1091
+ prereleases: bool | None = None,
1092
+ key: Callable[[Any], UnparsedVersion] | None = None,
1093
+ ) -> Iterator[Any]:
1094
+ """Filter items in the given iterable, that match the specifiers in this set.
1095
+
1096
+ :param iterable:
1097
+ An iterable that can contain version strings and :class:`Version` instances.
1098
+ The items in the iterable will be filtered according to the specifier.
1099
+ :param prereleases:
1100
+ Whether or not to allow prereleases in the returned iterator. If set to
1101
+ ``None`` (the default), it will follow the recommendation from :pep:`440`
1102
+ and match prereleases if there are no other versions.
1103
+ :param key:
1104
+ A callable that takes a single argument (an item from the iterable) and
1105
+ returns a version string or :class:`Version` instance to be used for
1106
+ filtering.
1107
+
1108
+ >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
1109
+ ['1.3']
1110
+ >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")]))
1111
+ ['1.3', <Version('1.4')>]
1112
+ >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"]))
1113
+ ['1.5a1']
1114
+ >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
1115
+ ['1.3', '1.5a1']
1116
+ >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
1117
+ ['1.3', '1.5a1']
1118
+ >>> list(SpecifierSet(">=1.2.3").filter(
1119
+ ... [{"ver": "1.2"}, {"ver": "1.3"}],
1120
+ ... key=lambda x: x["ver"]))
1121
+ [{'ver': '1.3'}]
1122
+
1123
+ An "empty" SpecifierSet will filter items based on the presence of prerelease
1124
+ versions in the set.
1125
+
1126
+ >>> list(SpecifierSet("").filter(["1.3", "1.5a1"]))
1127
+ ['1.3']
1128
+ >>> list(SpecifierSet("").filter(["1.5a1"]))
1129
+ ['1.5a1']
1130
+ >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"]))
1131
+ ['1.3', '1.5a1']
1132
+ >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True))
1133
+ ['1.3', '1.5a1']
1134
+ """
1135
+ # Inlined ``_resolve_prereleases`` for hot-path performance.
1136
+ if prereleases is None and self.prereleases is not None:
1137
+ prereleases = self.prereleases
1138
+ version_range = self._range_cache
1139
+ if version_range is None:
1140
+ version_range = VersionRange.from_specifier_set(self)
1141
+ return version_range.filter(iterable, key, prereleases)