@@ -440,53 +440,84 @@ def evaluate_link(self, link):
440
440
return (True , version )
441
441
442
442
443
+ class CandidatePreferences (object ):
444
+
445
+ """
446
+ Encapsulates some of the preferences for filtering and sorting
447
+ InstallationCandidate objects.
448
+ """
449
+
450
+ def __init__ (
451
+ self ,
452
+ prefer_binary = False , # type: bool
453
+ allow_all_prereleases = False , # type: bool
454
+ ):
455
+ # type: (...) -> None
456
+ """
457
+ :param allow_all_prereleases: Whether to allow all pre-releases.
458
+ """
459
+ self .allow_all_prereleases = allow_all_prereleases
460
+ self .prefer_binary = prefer_binary
461
+
462
+
443
463
class CandidateEvaluator (object ):
444
464
445
465
"""
446
466
Responsible for filtering and sorting candidates for installation based
447
467
on what tags are valid.
448
468
"""
449
469
470
+ @classmethod
471
+ def create (
472
+ cls ,
473
+ target_python = None , # type: Optional[TargetPython]
474
+ prefer_binary = False , # type: bool
475
+ allow_all_prereleases = False , # type: bool
476
+ ):
477
+ # type: (...) -> CandidateEvaluator
478
+ """Create a CandidateEvaluator object.
479
+
480
+ :param target_python: The target Python interpreter to use when
481
+ checking compatibility. If None (the default), a TargetPython
482
+ object will be constructed from the running Python.
483
+ """
484
+ if target_python is None :
485
+ target_python = TargetPython ()
486
+
487
+ supported_tags = target_python .get_tags ()
488
+
489
+ return cls (
490
+ supported_tags = supported_tags ,
491
+ prefer_binary = prefer_binary ,
492
+ allow_all_prereleases = allow_all_prereleases ,
493
+ )
494
+
450
495
def __init__ (
451
496
self ,
452
- supported_tags = None , # type: Optional[ List[Pep425Tag] ]
497
+ supported_tags , # type: List[Pep425Tag]
453
498
prefer_binary = False , # type: bool
454
499
allow_all_prereleases = False , # type: bool
455
500
):
456
501
# type: (...) -> None
457
502
"""
458
503
:param supported_tags: The PEP 425 tags supported by the target
459
- Python in order of preference (most preferred first). If None,
460
- then the list will be generated from the running Python.
461
- :param allow_all_prereleases: Whether to allow all pre-releases.
504
+ Python in order of preference (most preferred first).
462
505
"""
463
- if supported_tags is None :
464
- target_python = TargetPython ()
465
- supported_tags = target_python .get_tags ()
466
-
506
+ self ._allow_all_prereleases = allow_all_prereleases
467
507
self ._prefer_binary = prefer_binary
468
508
self ._supported_tags = supported_tags
469
509
470
- self .allow_all_prereleases = allow_all_prereleases
471
-
472
- def make_found_candidates (
510
+ def get_applicable_candidates (
473
511
self ,
474
- candidates , # type: List[InstallationCandidate]
475
- specifier = None , # type: Optional[ specifiers.BaseSpecifier]
512
+ candidates , # type: List[InstallationCandidate]
513
+ specifier , # type: specifiers.BaseSpecifier
476
514
):
477
- # type: (...) -> FoundCandidates
515
+ # type: (...) -> List[InstallationCandidate]
478
516
"""
479
- Create and return a `FoundCandidates` instance.
480
-
481
- :param specifier: An optional object implementing `filter`
482
- (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable
483
- versions.
517
+ Return the applicable candidates from a list of candidates.
484
518
"""
485
- if specifier is None :
486
- specifier = specifiers .SpecifierSet ()
487
-
488
519
# Using None infers from the specifier instead.
489
- allow_prereleases = self .allow_all_prereleases or None
520
+ allow_prereleases = self ._allow_all_prereleases or None
490
521
versions = {
491
522
str (v ) for v in specifier .filter (
492
523
# We turn the version object into a str here because otherwise
@@ -505,6 +536,28 @@ def make_found_candidates(
505
536
applicable_candidates = [
506
537
c for c in candidates if str (c .version ) in versions
507
538
]
539
+ return applicable_candidates
540
+
541
+ def make_found_candidates (
542
+ self ,
543
+ candidates , # type: List[InstallationCandidate]
544
+ specifier = None , # type: Optional[specifiers.BaseSpecifier]
545
+ ):
546
+ # type: (...) -> FoundCandidates
547
+ """
548
+ Create and return a `FoundCandidates` instance.
549
+
550
+ :param specifier: An optional object implementing `filter`
551
+ (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable
552
+ versions.
553
+ """
554
+ if specifier is None :
555
+ specifier = specifiers .SpecifierSet ()
556
+
557
+ applicable_candidates = self .get_applicable_candidates (
558
+ candidates = candidates ,
559
+ specifier = specifier ,
560
+ )
508
561
509
562
return FoundCandidates (
510
563
candidates ,
@@ -649,36 +702,39 @@ class PackageFinder(object):
649
702
650
703
def __init__ (
651
704
self ,
652
- candidate_evaluator , # type: CandidateEvaluator
653
705
search_scope , # type: SearchScope
654
706
session , # type: PipSession
655
707
target_python , # type: TargetPython
656
708
allow_yanked , # type: bool
657
709
format_control = None , # type: Optional[FormatControl]
658
710
trusted_hosts = None , # type: Optional[List[str]]
711
+ candidate_prefs = None , # type: CandidatePreferences
659
712
ignore_requires_python = None , # type: Optional[bool]
660
713
):
661
714
# type: (...) -> None
662
715
"""
663
716
This constructor is primarily meant to be used by the create() class
664
717
method and from tests.
665
718
666
- :param candidate_evaluator: A CandidateEvaluator object.
667
719
:param session: The Session to use to make requests.
668
720
:param format_control: A FormatControl object, used to control
669
721
the selection of source packages / binary packages when consulting
670
722
the index and links.
723
+ :param candidate_prefs: Options to use when creating a
724
+ CandidateEvaluator object.
671
725
"""
672
726
if trusted_hosts is None :
673
727
trusted_hosts = []
728
+ if candidate_prefs is None :
729
+ candidate_prefs = CandidatePreferences ()
674
730
675
731
format_control = format_control or FormatControl (set (), set ())
676
732
677
733
self ._allow_yanked = allow_yanked
734
+ self ._candidate_prefs = candidate_prefs
678
735
self ._ignore_requires_python = ignore_requires_python
679
736
self ._target_python = target_python
680
737
681
- self .candidate_evaluator = candidate_evaluator
682
738
self .search_scope = search_scope
683
739
self .session = session
684
740
self .format_control = format_control
@@ -720,15 +776,13 @@ def create(
720
776
if target_python is None :
721
777
target_python = TargetPython ()
722
778
723
- supported_tags = target_python .get_tags ()
724
- candidate_evaluator = CandidateEvaluator (
725
- supported_tags = supported_tags ,
779
+ candidate_prefs = CandidatePreferences (
726
780
prefer_binary = selection_prefs .prefer_binary ,
727
781
allow_all_prereleases = selection_prefs .allow_all_prereleases ,
728
782
)
729
783
730
784
return cls (
731
- candidate_evaluator = candidate_evaluator ,
785
+ candidate_prefs = candidate_prefs ,
732
786
search_scope = search_scope ,
733
787
session = session ,
734
788
target_python = target_python ,
@@ -751,11 +805,11 @@ def index_urls(self):
751
805
@property
752
806
def allow_all_prereleases (self ):
753
807
# type: () -> bool
754
- return self .candidate_evaluator .allow_all_prereleases
808
+ return self ._candidate_prefs .allow_all_prereleases
755
809
756
810
def set_allow_all_prereleases (self ):
757
811
# type: () -> None
758
- self .candidate_evaluator .allow_all_prereleases = True
812
+ self ._candidate_prefs .allow_all_prereleases = True
759
813
760
814
def add_trusted_host (self , host , source = None ):
761
815
# type: (str, Optional[str]) -> None
@@ -995,6 +1049,17 @@ def find_all_candidates(self, project_name):
995
1049
# This is an intentional priority ordering
996
1050
return file_versions + find_links_versions + page_versions
997
1051
1052
+ def make_candidate_evaluator (self ):
1053
+ # type: (...) -> CandidateEvaluator
1054
+ """Create a CandidateEvaluator object to use.
1055
+ """
1056
+ candidate_prefs = self ._candidate_prefs
1057
+ return CandidateEvaluator .create (
1058
+ target_python = self ._target_python ,
1059
+ prefer_binary = candidate_prefs .prefer_binary ,
1060
+ allow_all_prereleases = candidate_prefs .allow_all_prereleases ,
1061
+ )
1062
+
998
1063
def find_candidates (
999
1064
self ,
1000
1065
project_name , # type: str
@@ -1010,7 +1075,8 @@ def find_candidates(
1010
1075
:return: A `FoundCandidates` instance.
1011
1076
"""
1012
1077
candidates = self .find_all_candidates (project_name )
1013
- return self .candidate_evaluator .make_found_candidates (
1078
+ candidate_evaluator = self .make_candidate_evaluator ()
1079
+ return candidate_evaluator .make_found_candidates (
1014
1080
candidates , specifier = specifier ,
1015
1081
)
1016
1082
0 commit comments