Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py: 34%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

306 statements  

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. 

4from __future__ import absolute_import, division, print_function 

5 

6import abc 

7import functools 

8import itertools 

9import re 

10 

11from ._compat import string_types, with_metaclass 

12from .version import Version, LegacyVersion, parse 

13 

14 

15class InvalidSpecifier(ValueError): 

16 """ 

17 An invalid specifier was found, users should refer to PEP 440. 

18 """ 

19 

20 

21class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): 

22 @abc.abstractmethod 

23 def __str__(self): 

24 """ 

25 Returns the str representation of this Specifier like object. This 

26 should be representative of the Specifier itself. 

27 """ 

28 

29 @abc.abstractmethod 

30 def __hash__(self): 

31 """ 

32 Returns a hash value for this Specifier like object. 

33 """ 

34 

35 @abc.abstractmethod 

36 def __eq__(self, other): 

37 """ 

38 Returns a boolean representing whether or not the two Specifier like 

39 objects are equal. 

40 """ 

41 

42 @abc.abstractmethod 

43 def __ne__(self, other): 

44 """ 

45 Returns a boolean representing whether or not the two Specifier like 

46 objects are not equal. 

47 """ 

48 

49 @abc.abstractproperty 

50 def prereleases(self): 

51 """ 

52 Returns whether or not pre-releases as a whole are allowed by this 

53 specifier. 

54 """ 

55 

56 @prereleases.setter 

57 def prereleases(self, value): 

58 """ 

59 Sets whether or not pre-releases as a whole are allowed by this 

60 specifier. 

61 """ 

62 

63 @abc.abstractmethod 

64 def contains(self, item, prereleases=None): 

65 """ 

66 Determines if the given item is contained within this specifier. 

67 """ 

68 

69 @abc.abstractmethod 

70 def filter(self, iterable, prereleases=None): 

71 """ 

72 Takes an iterable of items and filters them so that only items which 

73 are contained within this specifier are allowed in it. 

74 """ 

75 

76 

77class _IndividualSpecifier(BaseSpecifier): 

78 

79 _operators = {} 

80 

81 def __init__(self, spec="", prereleases=None): 

82 match = self._regex.search(spec) 

83 if not match: 

84 raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) 

85 

86 self._spec = (match.group("operator").strip(), match.group("version").strip()) 

87 

88 # Store whether or not this Specifier should accept prereleases 

89 self._prereleases = prereleases 

90 

91 def __repr__(self): 

92 pre = ( 

93 ", prereleases={0!r}".format(self.prereleases) 

94 if self._prereleases is not None 

95 else "" 

96 ) 

97 

98 return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre) 

99 

100 def __str__(self): 

101 return "{0}{1}".format(*self._spec) 

102 

103 def __hash__(self): 

104 return hash(self._spec) 

105 

106 def __eq__(self, other): 

107 if isinstance(other, string_types): 

108 try: 

109 other = self.__class__(other) 

110 except InvalidSpecifier: 

111 return NotImplemented 

112 elif not isinstance(other, self.__class__): 

113 return NotImplemented 

114 

115 return self._spec == other._spec 

116 

117 def __ne__(self, other): 

118 if isinstance(other, string_types): 

119 try: 

120 other = self.__class__(other) 

121 except InvalidSpecifier: 

122 return NotImplemented 

123 elif not isinstance(other, self.__class__): 

124 return NotImplemented 

125 

126 return self._spec != other._spec 

127 

128 def _get_operator(self, op): 

129 return getattr(self, "_compare_{0}".format(self._operators[op])) 

130 

131 def _coerce_version(self, version): 

132 if not isinstance(version, (LegacyVersion, Version)): 

133 version = parse(version) 

134 return version 

135 

136 @property 

137 def operator(self): 

138 return self._spec[0] 

139 

140 @property 

141 def version(self): 

142 return self._spec[1] 

143 

144 @property 

145 def prereleases(self): 

146 return self._prereleases 

147 

148 @prereleases.setter 

149 def prereleases(self, value): 

150 self._prereleases = value 

151 

152 def __contains__(self, item): 

153 return self.contains(item) 

154 

155 def contains(self, item, prereleases=None): 

156 # Determine if prereleases are to be allowed or not. 

157 if prereleases is None: 

158 prereleases = self.prereleases 

159 

160 # Normalize item to a Version or LegacyVersion, this allows us to have 

161 # a shortcut for ``"2.0" in Specifier(">=2") 

162 item = self._coerce_version(item) 

163 

164 # Determine if we should be supporting prereleases in this specifier 

165 # or not, if we do not support prereleases than we can short circuit 

166 # logic if this version is a prereleases. 

167 if item.is_prerelease and not prereleases: 

168 return False 

169 

170 # Actually do the comparison to determine if this item is contained 

171 # within this Specifier or not. 

172 return self._get_operator(self.operator)(item, self.version) 

173 

174 def filter(self, iterable, prereleases=None): 

175 yielded = False 

176 found_prereleases = [] 

177 

178 kw = {"prereleases": prereleases if prereleases is not None else True} 

179 

180 # Attempt to iterate over all the values in the iterable and if any of 

181 # them match, yield them. 

182 for version in iterable: 

183 parsed_version = self._coerce_version(version) 

184 

185 if self.contains(parsed_version, **kw): 

186 # If our version is a prerelease, and we were not set to allow 

187 # prereleases, then we'll store it for later incase nothing 

188 # else matches this specifier. 

189 if parsed_version.is_prerelease and not ( 

190 prereleases or self.prereleases 

191 ): 

192 found_prereleases.append(version) 

193 # Either this is not a prerelease, or we should have been 

194 # accepting prereleases from the beginning. 

195 else: 

196 yielded = True 

197 yield version 

198 

199 # Now that we've iterated over everything, determine if we've yielded 

200 # any values, and if we have not and we have any prereleases stored up 

201 # then we will go ahead and yield the prereleases. 

202 if not yielded and found_prereleases: 

203 for version in found_prereleases: 

204 yield version 

205 

206 

207class LegacySpecifier(_IndividualSpecifier): 

208 

209 _regex_str = r""" 

210 (?P<operator>(==|!=|<=|>=|<|>)) 

211 \s* 

212 (?P<version> 

213 [^,;\s)]* # Since this is a "legacy" specifier, and the version 

214 # string can be just about anything, we match everything 

215 # except for whitespace, a semi-colon for marker support, 

216 # a closing paren since versions can be enclosed in 

217 # them, and a comma since it's a version separator. 

218 ) 

219 """ 

220 

221 _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) 

222 

223 _operators = { 

224 "==": "equal", 

225 "!=": "not_equal", 

226 "<=": "less_than_equal", 

227 ">=": "greater_than_equal", 

228 "<": "less_than", 

229 ">": "greater_than", 

230 } 

231 

232 def _coerce_version(self, version): 

233 if not isinstance(version, LegacyVersion): 

234 version = LegacyVersion(str(version)) 

235 return version 

236 

237 def _compare_equal(self, prospective, spec): 

238 return prospective == self._coerce_version(spec) 

239 

240 def _compare_not_equal(self, prospective, spec): 

241 return prospective != self._coerce_version(spec) 

242 

243 def _compare_less_than_equal(self, prospective, spec): 

244 return prospective <= self._coerce_version(spec) 

245 

246 def _compare_greater_than_equal(self, prospective, spec): 

247 return prospective >= self._coerce_version(spec) 

248 

249 def _compare_less_than(self, prospective, spec): 

250 return prospective < self._coerce_version(spec) 

251 

252 def _compare_greater_than(self, prospective, spec): 

253 return prospective > self._coerce_version(spec) 

254 

255 

256def _require_version_compare(fn): 

257 @functools.wraps(fn) 

258 def wrapped(self, prospective, spec): 

259 if not isinstance(prospective, Version): 

260 return False 

261 return fn(self, prospective, spec) 

262 

263 return wrapped 

264 

265 

266class Specifier(_IndividualSpecifier): 

267 

268 _regex_str = r""" 

269 (?P<operator>(~=|==|!=|<=|>=|<|>|===)) 

270 (?P<version> 

271 (?: 

272 # The identity operators allow for an escape hatch that will 

273 # do an exact string match of the version you wish to install. 

274 # This will not be parsed by PEP 440 and we cannot determine 

275 # any semantic meaning from it. This operator is discouraged 

276 # but included entirely as an escape hatch. 

277 (?<====) # Only match for the identity operator 

278 \s* 

279 [^\s]* # We just match everything, except for whitespace 

280 # since we are only testing for strict identity. 

281 ) 

282 | 

283 (?: 

284 # The (non)equality operators allow for wild card and local 

285 # versions to be specified so we have to define these two 

286 # operators separately to enable that. 

287 (?<===|!=) # Only match for equals and not equals 

288 

289 \s* 

290 v? 

291 (?:[0-9]+!)? # epoch 

292 [0-9]+(?:\.[0-9]+)* # release 

293 (?: # pre release 

294 [-_\.]? 

295 (a|b|c|rc|alpha|beta|pre|preview) 

296 [-_\.]? 

297 [0-9]* 

298 )? 

299 (?: # post release 

300 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) 

301 )? 

302 

303 # You cannot use a wild card and a dev or local version 

304 # together so group them with a | and make them optional. 

305 (?: 

306 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release 

307 (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local 

308 | 

309 \.\* # Wild card syntax of .* 

310 )? 

311 ) 

312 | 

313 (?: 

314 # The compatible operator requires at least two digits in the 

315 # release segment. 

316 (?<=~=) # Only match for the compatible operator 

317 

318 \s* 

319 v? 

320 (?:[0-9]+!)? # epoch 

321 [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) 

322 (?: # pre release 

323 [-_\.]? 

324 (a|b|c|rc|alpha|beta|pre|preview) 

325 [-_\.]? 

326 [0-9]* 

327 )? 

328 (?: # post release 

329 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) 

330 )? 

331 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release 

332 ) 

333 | 

334 (?: 

335 # All other operators only allow a sub set of what the 

336 # (non)equality operators do. Specifically they do not allow 

337 # local versions to be specified nor do they allow the prefix 

338 # matching wild cards. 

339 (?<!==|!=|~=) # We have special cases for these 

340 # operators so we want to make sure they 

341 # don't match here. 

342 

343 \s* 

344 v? 

345 (?:[0-9]+!)? # epoch 

346 [0-9]+(?:\.[0-9]+)* # release 

347 (?: # pre release 

348 [-_\.]? 

349 (a|b|c|rc|alpha|beta|pre|preview) 

350 [-_\.]? 

351 [0-9]* 

352 )? 

353 (?: # post release 

354 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) 

355 )? 

356 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release 

357 ) 

358 ) 

359 """ 

360 

361 _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) 

362 

363 _operators = { 

364 "~=": "compatible", 

365 "==": "equal", 

366 "!=": "not_equal", 

367 "<=": "less_than_equal", 

368 ">=": "greater_than_equal", 

369 "<": "less_than", 

370 ">": "greater_than", 

371 "===": "arbitrary", 

372 } 

373 

374 @_require_version_compare 

375 def _compare_compatible(self, prospective, spec): 

376 # Compatible releases have an equivalent combination of >= and ==. That 

377 # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to 

378 # implement this in terms of the other specifiers instead of 

379 # implementing it ourselves. The only thing we need to do is construct 

380 # the other specifiers. 

381 

382 # We want everything but the last item in the version, but we want to 

383 # ignore post and dev releases and we want to treat the pre-release as 

384 # it's own separate segment. 

385 prefix = ".".join( 

386 list( 

387 itertools.takewhile( 

388 lambda x: (not x.startswith("post") and not x.startswith("dev")), 

389 _version_split(spec), 

390 ) 

391 )[:-1] 

392 ) 

393 

394 # Add the prefix notation to the end of our string 

395 prefix += ".*" 

396 

397 return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( 

398 prospective, prefix 

399 ) 

400 

401 @_require_version_compare 

402 def _compare_equal(self, prospective, spec): 

403 # We need special logic to handle prefix matching 

404 if spec.endswith(".*"): 

405 # In the case of prefix matching we want to ignore local segment. 

406 prospective = Version(prospective.public) 

407 # Split the spec out by dots, and pretend that there is an implicit 

408 # dot in between a release segment and a pre-release segment. 

409 spec = _version_split(spec[:-2]) # Remove the trailing .* 

410 

411 # Split the prospective version out by dots, and pretend that there 

412 # is an implicit dot in between a release segment and a pre-release 

413 # segment. 

414 prospective = _version_split(str(prospective)) 

415 

416 # Shorten the prospective version to be the same length as the spec 

417 # so that we can determine if the specifier is a prefix of the 

418 # prospective version or not. 

419 prospective = prospective[: len(spec)] 

420 

421 # Pad out our two sides with zeros so that they both equal the same 

422 # length. 

423 spec, prospective = _pad_version(spec, prospective) 

424 else: 

425 # Convert our spec string into a Version 

426 spec = Version(spec) 

427 

428 # If the specifier does not have a local segment, then we want to 

429 # act as if the prospective version also does not have a local 

430 # segment. 

431 if not spec.local: 

432 prospective = Version(prospective.public) 

433 

434 return prospective == spec 

435 

436 @_require_version_compare 

437 def _compare_not_equal(self, prospective, spec): 

438 return not self._compare_equal(prospective, spec) 

439 

440 @_require_version_compare 

441 def _compare_less_than_equal(self, prospective, spec): 

442 return prospective <= Version(spec) 

443 

444 @_require_version_compare 

445 def _compare_greater_than_equal(self, prospective, spec): 

446 return prospective >= Version(spec) 

447 

448 @_require_version_compare 

449 def _compare_less_than(self, prospective, spec): 

450 # Convert our spec to a Version instance, since we'll want to work with 

451 # it as a version. 

452 spec = Version(spec) 

453 

454 # Check to see if the prospective version is less than the spec 

455 # version. If it's not we can short circuit and just return False now 

456 # instead of doing extra unneeded work. 

457 if not prospective < spec: 

458 return False 

459 

460 # This special case is here so that, unless the specifier itself 

461 # includes is a pre-release version, that we do not accept pre-release 

462 # versions for the version mentioned in the specifier (e.g. <3.1 should 

463 # not match 3.1.dev0, but should match 3.0.dev0). 

464 if not spec.is_prerelease and prospective.is_prerelease: 

465 if Version(prospective.base_version) == Version(spec.base_version): 

466 return False 

467 

468 # If we've gotten to here, it means that prospective version is both 

469 # less than the spec version *and* it's not a pre-release of the same 

470 # version in the spec. 

471 return True 

472 

473 @_require_version_compare 

474 def _compare_greater_than(self, prospective, spec): 

475 # Convert our spec to a Version instance, since we'll want to work with 

476 # it as a version. 

477 spec = Version(spec) 

478 

479 # Check to see if the prospective version is greater than the spec 

480 # version. If it's not we can short circuit and just return False now 

481 # instead of doing extra unneeded work. 

482 if not prospective > spec: 

483 return False 

484 

485 # This special case is here so that, unless the specifier itself 

486 # includes is a post-release version, that we do not accept 

487 # post-release versions for the version mentioned in the specifier 

488 # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). 

489 if not spec.is_postrelease and prospective.is_postrelease: 

490 if Version(prospective.base_version) == Version(spec.base_version): 

491 return False 

492 

493 # Ensure that we do not allow a local version of the version mentioned 

494 # in the specifier, which is technically greater than, to match. 

495 if prospective.local is not None: 

496 if Version(prospective.base_version) == Version(spec.base_version): 

497 return False 

498 

499 # If we've gotten to here, it means that prospective version is both 

500 # greater than the spec version *and* it's not a pre-release of the 

501 # same version in the spec. 

502 return True 

503 

504 def _compare_arbitrary(self, prospective, spec): 

505 return str(prospective).lower() == str(spec).lower() 

506 

507 @property 

508 def prereleases(self): 

509 # If there is an explicit prereleases set for this, then we'll just 

510 # blindly use that. 

511 if self._prereleases is not None: 

512 return self._prereleases 

513 

514 # Look at all of our specifiers and determine if they are inclusive 

515 # operators, and if they are if they are including an explicit 

516 # prerelease. 

517 operator, version = self._spec 

518 if operator in ["==", ">=", "<=", "~=", "==="]: 

519 # The == specifier can include a trailing .*, if it does we 

520 # want to remove before parsing. 

521 if operator == "==" and version.endswith(".*"): 

522 version = version[:-2] 

523 

524 # Parse the version, and if it is a pre-release than this 

525 # specifier allows pre-releases. 

526 if parse(version).is_prerelease: 

527 return True 

528 

529 return False 

530 

531 @prereleases.setter 

532 def prereleases(self, value): 

533 self._prereleases = value 

534 

535 

536_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") 

537 

538 

539def _version_split(version): 

540 result = [] 

541 for item in version.split("."): 

542 match = _prefix_regex.search(item) 

543 if match: 

544 result.extend(match.groups()) 

545 else: 

546 result.append(item) 

547 return result 

548 

549 

550def _pad_version(left, right): 

551 left_split, right_split = [], [] 

552 

553 # Get the release segment of our versions 

554 left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) 

555 right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) 

556 

557 # Get the rest of our versions 

558 left_split.append(left[len(left_split[0]) :]) 

559 right_split.append(right[len(right_split[0]) :]) 

560 

561 # Insert our padding 

562 left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) 

563 right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) 

564 

565 return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) 

566 

567 

568class SpecifierSet(BaseSpecifier): 

569 def __init__(self, specifiers="", prereleases=None): 

570 # Split on , to break each indidivual specifier into it's own item, and 

571 # strip each item to remove leading/trailing whitespace. 

572 specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] 

573 

574 # Parsed each individual specifier, attempting first to make it a 

575 # Specifier and falling back to a LegacySpecifier. 

576 parsed = set() 

577 for specifier in specifiers: 

578 try: 

579 parsed.add(Specifier(specifier)) 

580 except InvalidSpecifier: 

581 parsed.add(LegacySpecifier(specifier)) 

582 

583 # Turn our parsed specifiers into a frozen set and save them for later. 

584 self._specs = frozenset(parsed) 

585 

586 # Store our prereleases value so we can use it later to determine if 

587 # we accept prereleases or not. 

588 self._prereleases = prereleases 

589 

590 def __repr__(self): 

591 pre = ( 

592 ", prereleases={0!r}".format(self.prereleases) 

593 if self._prereleases is not None 

594 else "" 

595 ) 

596 

597 return "<SpecifierSet({0!r}{1})>".format(str(self), pre) 

598 

599 def __str__(self): 

600 return ",".join(sorted(str(s) for s in self._specs)) 

601 

602 def __hash__(self): 

603 return hash(self._specs) 

604 

605 def __and__(self, other): 

606 if isinstance(other, string_types): 

607 other = SpecifierSet(other) 

608 elif not isinstance(other, SpecifierSet): 

609 return NotImplemented 

610 

611 specifier = SpecifierSet() 

612 specifier._specs = frozenset(self._specs | other._specs) 

613 

614 if self._prereleases is None and other._prereleases is not None: 

615 specifier._prereleases = other._prereleases 

616 elif self._prereleases is not None and other._prereleases is None: 

617 specifier._prereleases = self._prereleases 

618 elif self._prereleases == other._prereleases: 

619 specifier._prereleases = self._prereleases 

620 else: 

621 raise ValueError( 

622 "Cannot combine SpecifierSets with True and False prerelease " 

623 "overrides." 

624 ) 

625 

626 return specifier 

627 

628 def __eq__(self, other): 

629 if isinstance(other, string_types): 

630 other = SpecifierSet(other) 

631 elif isinstance(other, _IndividualSpecifier): 

632 other = SpecifierSet(str(other)) 

633 elif not isinstance(other, SpecifierSet): 

634 return NotImplemented 

635 

636 return self._specs == other._specs 

637 

638 def __ne__(self, other): 

639 if isinstance(other, string_types): 

640 other = SpecifierSet(other) 

641 elif isinstance(other, _IndividualSpecifier): 

642 other = SpecifierSet(str(other)) 

643 elif not isinstance(other, SpecifierSet): 

644 return NotImplemented 

645 

646 return self._specs != other._specs 

647 

648 def __len__(self): 

649 return len(self._specs) 

650 

651 def __iter__(self): 

652 return iter(self._specs) 

653 

654 @property 

655 def prereleases(self): 

656 # If we have been given an explicit prerelease modifier, then we'll 

657 # pass that through here. 

658 if self._prereleases is not None: 

659 return self._prereleases 

660 

661 # If we don't have any specifiers, and we don't have a forced value, 

662 # then we'll just return None since we don't know if this should have 

663 # pre-releases or not. 

664 if not self._specs: 

665 return None 

666 

667 # Otherwise we'll see if any of the given specifiers accept 

668 # prereleases, if any of them do we'll return True, otherwise False. 

669 return any(s.prereleases for s in self._specs) 

670 

671 @prereleases.setter 

672 def prereleases(self, value): 

673 self._prereleases = value 

674 

675 def __contains__(self, item): 

676 return self.contains(item) 

677 

678 def contains(self, item, prereleases=None): 

679 # Ensure that our item is a Version or LegacyVersion instance. 

680 if not isinstance(item, (LegacyVersion, Version)): 

681 item = parse(item) 

682 

683 # Determine if we're forcing a prerelease or not, if we're not forcing 

684 # one for this particular filter call, then we'll use whatever the 

685 # SpecifierSet thinks for whether or not we should support prereleases. 

686 if prereleases is None: 

687 prereleases = self.prereleases 

688 

689 # We can determine if we're going to allow pre-releases by looking to 

690 # see if any of the underlying items supports them. If none of them do 

691 # and this item is a pre-release then we do not allow it and we can 

692 # short circuit that here. 

693 # Note: This means that 1.0.dev1 would not be contained in something 

694 # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 

695 if not prereleases and item.is_prerelease: 

696 return False 

697 

698 # We simply dispatch to the underlying specs here to make sure that the 

699 # given version is contained within all of them. 

700 # Note: This use of all() here means that an empty set of specifiers 

701 # will always return True, this is an explicit design decision. 

702 return all(s.contains(item, prereleases=prereleases) for s in self._specs) 

703 

704 def filter(self, iterable, prereleases=None): 

705 # Determine if we're forcing a prerelease or not, if we're not forcing 

706 # one for this particular filter call, then we'll use whatever the 

707 # SpecifierSet thinks for whether or not we should support prereleases. 

708 if prereleases is None: 

709 prereleases = self.prereleases 

710 

711 # If we have any specifiers, then we want to wrap our iterable in the 

712 # filter method for each one, this will act as a logical AND amongst 

713 # each specifier. 

714 if self._specs: 

715 for spec in self._specs: 

716 iterable = spec.filter(iterable, prereleases=bool(prereleases)) 

717 return iterable 

718 # If we do not have any specifiers, then we need to have a rough filter 

719 # which will filter out any pre-releases, unless there are no final 

720 # releases, and which will filter out LegacyVersion in general. 

721 else: 

722 filtered = [] 

723 found_prereleases = [] 

724 

725 for item in iterable: 

726 # Ensure that we some kind of Version class for this item. 

727 if not isinstance(item, (LegacyVersion, Version)): 

728 parsed_version = parse(item) 

729 else: 

730 parsed_version = item 

731 

732 # Filter out any item which is parsed as a LegacyVersion 

733 if isinstance(parsed_version, LegacyVersion): 

734 continue 

735 

736 # Store any item which is a pre-release for later unless we've 

737 # already found a final version or we are accepting prereleases 

738 if parsed_version.is_prerelease and not prereleases: 

739 if not filtered: 

740 found_prereleases.append(item) 

741 else: 

742 filtered.append(item) 

743 

744 # If we've found no items except for pre-releases, then we'll go 

745 # ahead and use the pre-releases 

746 if not filtered and found_prereleases and prereleases is None: 

747 return found_prereleases 

748 

749 return filtered