18
18
from argparse import ArgumentParser
19
19
from collections .abc import Callable , Generator , Iterable , Mapping , Sequence
20
20
21
- from virtualenv .app_data . base import AppData
21
+ from .app_data import AppData
22
22
LOGGER = logging .getLogger (__name__ )
23
23
24
24
@@ -27,8 +27,8 @@ class Builtin(Discover):
27
27
app_data : AppData
28
28
try_first_with : Sequence [str ]
29
29
30
- def __init__ (self , options ) -> None :
31
- super ().__init__ (options )
30
+ def __init__ (self , options , cache = None ) -> None :
31
+ super ().__init__ (options , cache )
32
32
self .python_spec = options .python or [sys .executable ]
33
33
if self ._env .get ("VIRTUALENV_PYTHON" ):
34
34
self .python_spec = self .python_spec [1 :] + self .python_spec [:1 ] # Rotate the list
@@ -60,7 +60,7 @@ def add_parser_arguments(cls, parser: ArgumentParser) -> None:
60
60
61
61
def run (self ) -> PythonInfo | None :
62
62
for python_spec in self .python_spec :
63
- result = get_interpreter (python_spec , self .try_first_with , self .app_data , self ._env )
63
+ result = get_interpreter (python_spec , self .try_first_with , self .app_data , self .cache , self . _env )
64
64
if result is not None :
65
65
return result
66
66
return None
@@ -71,13 +71,17 @@ def __repr__(self) -> str:
71
71
72
72
73
73
def get_interpreter (
74
- key , try_first_with : Iterable [str ], app_data : AppData | None = None , env : Mapping [str , str ] | None = None
74
+ key ,
75
+ try_first_with : Iterable [str ],
76
+ app_data : AppData | None = None ,
77
+ cache = None ,
78
+ env : Mapping [str , str ] | None = None ,
75
79
) -> PythonInfo | None :
76
80
spec = PythonSpec .from_string_spec (key )
77
81
LOGGER .info ("find interpreter for spec %r" , spec )
78
82
proposed_paths = set ()
79
83
env = os .environ if env is None else env
80
- for interpreter , impl_must_match in propose_interpreters (spec , try_first_with , app_data , env ):
84
+ for interpreter , impl_must_match in propose_interpreters (spec , try_first_with , app_data , cache , env ):
81
85
key = interpreter .system_executable , impl_must_match
82
86
if key in proposed_paths :
83
87
continue
@@ -93,6 +97,7 @@ def propose_interpreters( # noqa: C901, PLR0912, PLR0915
93
97
spec : PythonSpec ,
94
98
try_first_with : Iterable [str ],
95
99
app_data : AppData | None = None ,
100
+ cache = None ,
96
101
env : Mapping [str , str ] | None = None ,
97
102
) -> Generator [tuple [PythonInfo , bool ], None , None ]:
98
103
# 0. if it's a path and exists, and is absolute path, this is the only option we consider
@@ -108,7 +113,7 @@ def propose_interpreters( # noqa: C901, PLR0912, PLR0915
108
113
exe_id = fs_path_id (exe_raw )
109
114
if exe_id not in tested_exes :
110
115
tested_exes .add (exe_id )
111
- yield PythonInfo .from_exe (exe_raw , app_data , env = env ), True
116
+ yield PythonInfo .from_exe (exe_raw , app_data , cache , env = env ), True
112
117
return
113
118
114
119
# 1. try with first
@@ -124,7 +129,7 @@ def propose_interpreters( # noqa: C901, PLR0912, PLR0915
124
129
if exe_id in tested_exes :
125
130
continue
126
131
tested_exes .add (exe_id )
127
- yield PythonInfo .from_exe (exe_raw , app_data , env = env ), True
132
+ yield PythonInfo .from_exe (exe_raw , app_data , cache , env = env ), True
128
133
129
134
# 1. if it's a path and exists
130
135
if spec .path is not None :
@@ -137,12 +142,12 @@ def propose_interpreters( # noqa: C901, PLR0912, PLR0915
137
142
exe_id = fs_path_id (exe_raw )
138
143
if exe_id not in tested_exes :
139
144
tested_exes .add (exe_id )
140
- yield PythonInfo .from_exe (exe_raw , app_data , env = env ), True
145
+ yield PythonInfo .from_exe (exe_raw , app_data , cache , env = env ), True
141
146
if spec .is_abs :
142
147
return
143
148
else :
144
149
# 2. otherwise try with the current
145
- current_python = PythonInfo .current_system (app_data )
150
+ current_python = PythonInfo .current_system (app_data , cache )
146
151
exe_raw = str (current_python .executable )
147
152
exe_id = fs_path_id (exe_raw )
148
153
if exe_id not in tested_exes :
@@ -153,7 +158,7 @@ def propose_interpreters( # noqa: C901, PLR0912, PLR0915
153
158
if IS_WIN :
154
159
from .windows import propose_interpreters # noqa: PLC0415
155
160
156
- for interpreter in propose_interpreters (spec , app_data , env ):
161
+ for interpreter in propose_interpreters (spec , app_data , cache , env ):
157
162
exe_raw = str (interpreter .executable )
158
163
exe_id = fs_path_id (exe_raw )
159
164
if exe_id in tested_exes :
@@ -171,7 +176,7 @@ def propose_interpreters( # noqa: C901, PLR0912, PLR0915
171
176
if exe_id in tested_exes :
172
177
continue
173
178
tested_exes .add (exe_id )
174
- interpreter = PathPythonInfo .from_exe (exe_raw , app_data , raise_on_error = False , env = env )
179
+ interpreter = PathPythonInfo .from_exe (exe_raw , app_data , cache , raise_on_error = False , env = env )
175
180
if interpreter is not None :
176
181
yield interpreter , impl_must_match
177
182
@@ -184,7 +189,7 @@ def propose_interpreters( # noqa: C901, PLR0912, PLR0915
184
189
uv_python_path = user_data_path ("uv" ) / "python"
185
190
186
191
for exe_path in uv_python_path .glob ("*/bin/python" ):
187
- interpreter = PathPythonInfo .from_exe (str (exe_path ), app_data , raise_on_error = False , env = env )
192
+ interpreter = PathPythonInfo .from_exe (str (exe_path ), app_data , cache , raise_on_error = False , env = env )
188
193
if interpreter is not None :
189
194
yield interpreter , True
190
195
0 commit comments