44from __future__ import absolute_import
55
66import functools
7+ import hashlib
78import os
89import sys
910from textwrap import dedent
@@ -42,6 +43,22 @@ def overridden(cls):
4243 break
4344 return cast ("Optional[PipVersionValue]" , getattr (cls , "_overridden" ))
4445
46+ @staticmethod
47+ def _to_requirement (
48+ project_name , # type: str
49+ project_version , # type: Union[str, Version]
50+ ):
51+ # type: (...) -> Requirement
52+
53+ if not project_version :
54+ return Requirement .parse (project_name )
55+
56+ return Requirement .parse (
57+ "{project_name}=={project_version}" .format (
58+ project_name = project_name , project_version = project_version
59+ )
60+ )
61+
4562 def __init__ (
4663 self ,
4764 version , # type: str
@@ -54,34 +71,34 @@ def __init__(
5471 hidden = False , # type: bool
5572 ):
5673 # type: (...) -> None
57- super (PipVersionValue , self ).__init__ (name or version )
58-
59- def to_requirement (
60- project_name , # type: str
61- project_version , # type: str
62- ):
63- # type: (...) -> Requirement
64- return Requirement .parse (
65- "{project_name}=={project_version}" .format (
66- project_name = project_name , project_version = project_version
67- )
68- )
74+ super (PipVersionValue , self ).__init__ (name or version , enum_type = PipVersionValue )
6975
7076 self .version = Version (version )
71- self .requirement = (
72- Requirement .parse (requirement ) if requirement else to_requirement ("pip" , version )
73- )
77+ self ._requirement = requirement
7478 self .setuptools_version = setuptools_version
7579 self .setuptools_requirement = (
7680 Requirement .parse (setuptools_requirement )
7781 if setuptools_requirement
78- else to_requirement ("setuptools" , setuptools_version )
82+ else self . _to_requirement ("setuptools" , setuptools_version )
7983 )
8084 self .wheel_version = wheel_version
81- self .wheel_requirement = to_requirement ("wheel" , wheel_version )
85+ self .wheel_requirement = self . _to_requirement ("wheel" , wheel_version )
8286 self .requires_python = SpecifierSet (requires_python ) if requires_python else None
8387 self .hidden = hidden
8488
89+ def cache_dir_name (self ):
90+ # type: () -> str
91+ return self .value
92+
93+ @property
94+ def requirement (self ):
95+ # type: () -> Requirement
96+ return (
97+ Requirement .parse (self ._requirement )
98+ if self ._requirement
99+ else self ._to_requirement ("pip" , self .version )
100+ )
101+
85102 @property
86103 def requirements (self ):
87104 # type: () -> Iterable[Requirement]
@@ -124,9 +141,9 @@ def __get__(self, obj, objtype=None):
124141class LatestCompatiblePipVersion (object ):
125142 def __get__ (self , obj , objtype = None ):
126143 # type: (...) -> PipVersionValue
127- if not hasattr (self , "_latest " ):
128- self ._latest = PipVersion .latest_compatible ()
129- return self ._latest
144+ if not hasattr (self , "_latest_compatible " ):
145+ self ._latest_compatible = PipVersion .latest_compatible ()
146+ return self ._latest_compatible
130147
131148
132149class DefaultPipVersion (object ):
@@ -171,6 +188,39 @@ def __get__(self, obj, objtype=None):
171188 return self ._default
172189
173190
191+ class Adhoc (PipVersionValue ):
192+ def __init__ (self ):
193+ super (Adhoc , self ).__init__ (
194+ name = "adhoc" ,
195+ version = "99" ,
196+ setuptools_version = "" ,
197+ wheel_version = "" ,
198+ requires_python = "" ,
199+ hidden = True ,
200+ )
201+ self ._adhoc_requirement = None # type: Optional[Requirement]
202+
203+ def cache_dir_name (self ):
204+ # type: () -> str
205+ return "adhoc-{fingerprint}" .format (
206+ fingerprint = hashlib .sha1 (str (self .requirement ).encode ("utf-8" )).hexdigest ()
207+ )
208+
209+ @property
210+ def requirement (self ):
211+ # type: () -> Requirement
212+
213+ if self ._adhoc_requirement is None :
214+ requirement = os .environ .get ("_PEX_PIP_ADHOC_REQUIREMENT" )
215+ if not requirement :
216+ raise ValueError (
217+ "You must set a value for the _PEX_PIP_ADHOC_REQUIREMENT environment variable "
218+ "to use an adhoc Pip version."
219+ )
220+ self ._adhoc_requirement = Requirement .parse (requirement )
221+ return self ._adhoc_requirement
222+
223+
174224class PipVersion (Enum ["PipVersionValue" ]):
175225 @classmethod
176226 def values (cls ):
@@ -376,6 +426,8 @@ def latest_compatible(cls, target=None):
376426 requires_python = ">=3.9,<3.16" ,
377427 )
378428
429+ ADHOC = Adhoc ()
430+
379431 VENDORED = v20_3_4_patched
380432 LATEST = LatestPipVersion ()
381433 LATEST_COMPATIBLE = LatestCompatiblePipVersion ()
0 commit comments