1
+ import importlib .util
1
2
import json
3
+ import os
2
4
import shlex
5
+ import sys
6
+ from enum import Enum
7
+ from functools import lru_cache
3
8
from importlib .resources import path as resource_path
4
9
from pathlib import Path
5
10
from typing import Any , Dict , Iterable , List , Optional , Sequence , Tuple , TypedDict , cast
6
11
12
+ import typer
7
13
from packaging .utils import NormalizedName
8
14
from packaging .version import Version
9
15
29
35
check_output ,
30
36
get_temp_path_in_dir ,
31
37
log_debug ,
38
+ log_error ,
32
39
log_info ,
33
40
log_warning ,
34
41
normalize_req_line ,
@@ -41,11 +48,53 @@ class PipInspectReport(TypedDict, total=False):
41
48
environment : Dict [str , str ]
42
49
43
50
51
+ class Installer (str , Enum ):
52
+ default = "default"
53
+ envpip = "env-pip"
54
+ uv = "uv"
55
+
56
+
57
+ @lru_cache
58
+ def _has_uv () -> bool :
59
+ return bool (importlib .util .find_spec ("uv" ))
60
+
61
+
62
+ def _env_pip_install_cmd_and_env (python : str ) -> Tuple [List [str ], Dict [str , str ]]:
63
+ return [python , "-m" , "pip" , "install" ], {}
64
+
65
+
66
+ def _uv_install_cmd_and_env (python : str ) -> Tuple [List [str ], Dict [str , str ]]:
67
+ # TODO when https://github.com/astral-sh/uv/issues/1396 is implemented,
68
+ # we will not need to return the VIRTUAL_ENV environment variable.
69
+ return [sys .executable , "-m" , "uv" , "pip" , "install" ], {
70
+ "VIRTUAL_ENV" : str (Path (python ).parent .parent )
71
+ }
72
+
73
+
74
+ def _install_cmd_and_env (
75
+ installer : Installer , python : str
76
+ ) -> Tuple [List [str ], Dict [str , str ]]:
77
+ if installer == Installer .default :
78
+ installer = Installer .envpip
79
+ if installer == Installer .envpip :
80
+ return _env_pip_install_cmd_and_env (python )
81
+ elif installer == Installer .uv :
82
+ if not _has_uv ():
83
+ log_error (
84
+ "The 'uv' installer was requested but it is not available. "
85
+ "Please install pip-deepfreeze with the 'uv' extra to use it."
86
+ )
87
+ raise typer .Exit (1 )
88
+ return _uv_install_cmd_and_env (python )
89
+ raise NotImplementedError (f"Installer { installer } is not implemented." )
90
+
91
+
44
92
def pip_upgrade_project (
45
93
python : str ,
46
94
constraints_filename : Path ,
47
95
project_root : Path ,
48
96
extras : Optional [Sequence [NormalizedName ]] = None ,
97
+ installer : Installer = Installer .envpip ,
49
98
) -> None :
50
99
"""Upgrade a project.
51
100
@@ -117,15 +166,14 @@ def pip_upgrade_project(
117
166
# 4. install project with constraints
118
167
project_name = get_project_name (python , project_root )
119
168
log_info (f"Installing/updating { project_name } " )
120
- cmd = [
121
- python ,
122
- "-m" ,
123
- "pip" ,
124
- "install" ,
125
- "-c" ,
126
- f"{ constraints_without_editables_filename } " ,
127
- * editable_constraints ,
128
- ]
169
+ cmd , env = _install_cmd_and_env (installer , python )
170
+ cmd .extend (
171
+ [
172
+ "-c" ,
173
+ f"{ constraints_without_editables_filename } " ,
174
+ * editable_constraints ,
175
+ ]
176
+ )
129
177
cmd .append ("-e" )
130
178
if extras :
131
179
extras_str = "," .join (extras )
@@ -141,7 +189,7 @@ def pip_upgrade_project(
141
189
log_debug (constraints )
142
190
else :
143
191
log_debug (f"with empty { constraints_without_editables_filename } ." )
144
- check_call (cmd )
192
+ check_call (cmd , os . environ . copy (). update ( env ) )
145
193
146
194
147
195
def _pip_list__env_info_json (python : str ) -> InstalledDistributions :
0 commit comments