@@ -877,13 +877,8 @@ def create_venv(
877
877
io .write_line (
878
878
"Creating virtualenv <c1>{}</> in {}" .format (name , str (venv_path ))
879
879
)
880
-
881
- self .build_venv (
882
- venv ,
883
- executable = executable ,
884
- flags = self ._poetry .config .get ("virtualenvs.options" ),
885
- )
886
880
else :
881
+ create_venv = False
887
882
if force :
888
883
if not env .is_sane ():
889
884
io .write_line (
@@ -895,14 +890,23 @@ def create_venv(
895
890
"Recreating virtualenv <c1>{}</> in {}" .format (name , str (venv ))
896
891
)
897
892
self .remove_venv (venv )
898
- self .build_venv (
899
- venv ,
900
- executable = executable ,
901
- flags = self ._poetry .config .get ("virtualenvs.options" ),
902
- )
893
+ create_venv = True
903
894
elif io .is_very_verbose ():
904
895
io .write_line (f"Virtualenv <c1>{ name } </> already exists." )
905
896
897
+ if create_venv :
898
+ self .build_venv (
899
+ venv ,
900
+ executable = executable ,
901
+ flags = self ._poetry .config .get ("virtualenvs.options" ),
902
+ # TODO: in a future version switch remove pip/setuptools/wheel
903
+ # poetry does not need them these exists today to not break developer
904
+ # environment assumptions
905
+ with_pip = True ,
906
+ with_setuptools = True ,
907
+ with_wheel = True ,
908
+ )
909
+
906
910
# venv detection:
907
911
# stdlib venv may symlink sys.executable, so we can't use realpath.
908
912
# but others can symlink *to* the venv Python,
@@ -927,12 +931,29 @@ def build_venv(
927
931
path : Union [Path , str ],
928
932
executable : Optional [Union [str , Path ]] = None ,
929
933
flags : Dict [str , bool ] = None ,
930
- with_pip : bool = False ,
934
+ with_pip : Optional [ bool ] = None ,
931
935
with_wheel : Optional [bool ] = None ,
932
936
with_setuptools : Optional [bool ] = None ,
933
937
) -> virtualenv .run .session .Session :
934
938
flags = flags or {}
935
939
940
+ flags ["no-pip" ] = (
941
+ not with_pip if with_pip is not None else flags .pop ("no-pip" , True )
942
+ )
943
+
944
+ flags ["no-setuptools" ] = (
945
+ not with_setuptools
946
+ if with_setuptools is not None
947
+ else flags .pop ("no-setuptools" , True )
948
+ )
949
+
950
+ # we want wheels to be enabled when pip is required and it has not been explicitly disabled
951
+ flags ["no-wheel" ] = (
952
+ not with_wheel
953
+ if with_wheel is not None
954
+ else flags .pop ("no-wheel" , flags ["no-pip" ])
955
+ )
956
+
936
957
if isinstance (executable , Path ):
937
958
executable = executable .resolve ().as_posix ()
938
959
@@ -943,20 +964,6 @@ def build_venv(
943
964
executable or sys .executable ,
944
965
]
945
966
946
- if not with_pip :
947
- args .append ("--no-pip" )
948
- else :
949
- if with_wheel is None :
950
- # we want wheels to be enabled when pip is required and it has
951
- # not been explicitly disabled
952
- with_wheel = True
953
-
954
- if with_wheel is None or not with_wheel :
955
- args .append ("--no-wheel" )
956
-
957
- if with_setuptools is None or not with_setuptools :
958
- args .append ("--no-setuptools" )
959
-
960
967
for flag , value in flags .items ():
961
968
if value is True :
962
969
args .append (f"--{ flag } " )
@@ -1039,6 +1046,8 @@ def __init__(self, path: Path, base: Optional[Path] = None) -> None:
1039
1046
self ._platlib = None
1040
1047
self ._script_dirs = None
1041
1048
1049
+ self ._embedded_pip_path = None
1050
+
1042
1051
@property
1043
1052
def path (self ) -> Path :
1044
1053
return self ._path
@@ -1074,6 +1083,12 @@ def get_embedded_wheel(self, distribution):
1074
1083
distribution , "{}.{}" .format (self .version_info [0 ], self .version_info [1 ])
1075
1084
).path
1076
1085
1086
+ @property
1087
+ def pip_embedded (self ) -> str :
1088
+ if self ._embedded_pip_path is None :
1089
+ self ._embedded_pip_path = str (self .get_embedded_wheel ("pip" ) / "pip" )
1090
+ return self ._embedded_pip_path
1091
+
1077
1092
@property
1078
1093
def pip (self ) -> str :
1079
1094
"""
@@ -1082,7 +1097,7 @@ def pip(self) -> str:
1082
1097
# we do not use as_posix() here due to issues with windows pathlib2 implementation
1083
1098
path = self ._bin ("pip" )
1084
1099
if not Path (path ).exists ():
1085
- return str (self .get_embedded_wheel ( "pip" ) / "pip" )
1100
+ return str (self .pip_embedded )
1086
1101
return path
1087
1102
1088
1103
@property
@@ -1187,7 +1202,7 @@ def get_python_implementation(self) -> str:
1187
1202
def get_marker_env (self ) -> Dict [str , Any ]:
1188
1203
raise NotImplementedError ()
1189
1204
1190
- def get_pip_command (self ) -> List [str ]:
1205
+ def get_pip_command (self , embedded : bool = False ) -> List [str ]:
1191
1206
raise NotImplementedError ()
1192
1207
1193
1208
def get_supported_tags (self ) -> List [Tag ]:
@@ -1208,16 +1223,20 @@ def is_sane(self) -> bool:
1208
1223
"""
1209
1224
return True
1210
1225
1211
- def run (self , bin : str , * args : str , ** kwargs : Any ) -> Union [str , int ]:
1226
+ def get_command_from_bin (self , bin : str ) -> List [str ]:
1212
1227
if bin == "pip" :
1213
- return self .run_pip (* args , ** kwargs )
1228
+ # when pip is required we need to ensure that we fallback to
1229
+ # embedded pip when pip is not available in the environment
1230
+ return self .get_pip_command ()
1231
+
1232
+ return [self ._bin (bin )]
1214
1233
1215
- bin = self . _bin ( bin )
1216
- cmd = [ bin ] + list (args )
1234
+ def run ( self , bin : str , * args : str , ** kwargs : Any ) -> Union [ str , int ]:
1235
+ cmd = self . get_command_from_bin ( bin ) + list (args )
1217
1236
return self ._run (cmd , ** kwargs )
1218
1237
1219
1238
def run_pip (self , * args : str , ** kwargs : Any ) -> Union [int , str ]:
1220
- pip = self .get_pip_command ()
1239
+ pip = self .get_pip_command (embedded = True )
1221
1240
cmd = pip + list (args )
1222
1241
return self ._run (cmd , ** kwargs )
1223
1242
@@ -1260,17 +1279,13 @@ def _run(self, cmd: List[str], **kwargs: Any) -> Union[int, str]:
1260
1279
return decode (output )
1261
1280
1262
1281
def execute (self , bin : str , * args : str , ** kwargs : Any ) -> Optional [int ]:
1263
- if bin == "pip" :
1264
- return self .run_pip (* args , ** kwargs )
1265
-
1266
- bin = self ._bin (bin )
1282
+ command = self .get_command_from_bin (bin ) + list (args )
1267
1283
env = kwargs .pop ("env" , {k : v for k , v in os .environ .items ()})
1268
1284
1269
1285
if not self ._is_windows :
1270
- args = [bin ] + list (args )
1271
- return os .execvpe (bin , args , env = env )
1286
+ return os .execvpe (command [0 ], command , env = env )
1272
1287
else :
1273
- exe = subprocess .Popen ([bin ] + list ( args ) , env = env , ** kwargs )
1288
+ exe = subprocess .Popen ([command [ 0 ]] + command [ 1 :] , env = env , ** kwargs )
1274
1289
exe .communicate ()
1275
1290
return exe .returncode
1276
1291
@@ -1338,10 +1353,10 @@ def get_version_info(self) -> Tuple[int]:
1338
1353
def get_python_implementation (self ) -> str :
1339
1354
return platform .python_implementation ()
1340
1355
1341
- def get_pip_command (self ) -> List [str ]:
1356
+ def get_pip_command (self , embedded : bool = False ) -> List [str ]:
1342
1357
# If we're not in a venv, assume the interpreter we're running on
1343
1358
# has a pip and use that
1344
- return [sys .executable , self .pip ]
1359
+ return [sys .executable , self .pip_embedded if embedded else self . pip ]
1345
1360
1346
1361
def get_paths (self ) -> Dict [str , str ]:
1347
1362
# We can't use sysconfig.get_paths() because
@@ -1445,10 +1460,10 @@ def get_version_info(self) -> Tuple[int]:
1445
1460
def get_python_implementation (self ) -> str :
1446
1461
return self .marker_env ["platform_python_implementation" ]
1447
1462
1448
- def get_pip_command (self ) -> List [str ]:
1463
+ def get_pip_command (self , embedded : bool = False ) -> List [str ]:
1449
1464
# We're in a virtualenv that is known to be sane,
1450
1465
# so assume that we have a functional pip
1451
- return [self ._bin ("python" ), self .pip ]
1466
+ return [self ._bin ("python" ), self .pip_embedded if embedded else self . pip ]
1452
1467
1453
1468
def get_supported_tags (self ) -> List [Tag ]:
1454
1469
file_path = Path (packaging .tags .__file__ )
@@ -1560,8 +1575,8 @@ def __init__(
1560
1575
self ._execute = execute
1561
1576
self .executed = []
1562
1577
1563
- def get_pip_command (self ) -> List [str ]:
1564
- return [self ._bin ("python" ), self .pip ]
1578
+ def get_pip_command (self , embedded : bool = False ) -> List [str ]:
1579
+ return [self ._bin ("python" ), self .pip_embedded if embedded else self . pip ]
1565
1580
1566
1581
def _run (self , cmd : List [str ], ** kwargs : Any ) -> int :
1567
1582
self .executed .append (cmd )
0 commit comments