@@ -3,17 +3,17 @@ defmodule Pythonx.Uv do
3
3
4
4
require Logger
5
5
6
- @ uv_version "0.5.21 "
6
+ def default_uv_version ( ) , do: "0.8.5 "
7
7
8
8
@ doc """
9
9
Fetches Python and dependencies based on the given configuration.
10
10
"""
11
11
@ spec fetch ( String . t ( ) , boolean ( ) , keyword ( ) ) :: :ok
12
12
def fetch ( pyproject_toml , priv? , opts \\ [ ] ) do
13
- opts = Keyword . validate! ( opts , force: false )
13
+ opts = Keyword . validate! ( opts , force: false , uv_version: default_uv_version ( ) )
14
14
15
- project_dir = project_dir ( pyproject_toml , priv? )
16
- python_install_dir = python_install_dir ( priv? )
15
+ project_dir = project_dir ( pyproject_toml , priv? , opts [ :uv_version ] )
16
+ python_install_dir = python_install_dir ( priv? , opts [ :uv_version ] )
17
17
18
18
if opts [ :force ] || priv? do
19
19
_ = File . rm_rf ( project_dir )
@@ -30,7 +30,8 @@ defmodule Pythonx.Uv do
30
30
# We always use uv-managed Python, so the paths are predictable.
31
31
if run! ( [ "sync" , "--python-preference" , "only-managed" ] ,
32
32
cd: project_dir ,
33
- env: % { "UV_PYTHON_INSTALL_DIR" => python_install_dir }
33
+ env: % { "UV_PYTHON_INSTALL_DIR" => python_install_dir } ,
34
+ uv_version: opts [ :uv_version ]
34
35
) != 0 do
35
36
_ = File . rm_rf ( project_dir )
36
37
raise "fetching Python and dependencies failed, see standard output for details"
@@ -40,15 +41,15 @@ defmodule Pythonx.Uv do
40
41
:ok
41
42
end
42
43
43
- defp python_install_dir ( priv? ) do
44
+ defp python_install_dir ( priv? , uv_version ) do
44
45
if priv? do
45
46
Path . join ( :code . priv_dir ( :pythonx ) , "uv/python" )
46
47
else
47
- Path . join ( cache_dir ( ) , "python" )
48
+ Path . join ( cache_dir ( uv_version ) , "python" )
48
49
end
49
50
end
50
51
51
- defp project_dir ( pyproject_toml , priv? ) do
52
+ defp project_dir ( pyproject_toml , priv? , uv_version ) do
52
53
if priv? do
53
54
Path . join ( :code . priv_dir ( :pythonx ) , "uv/project" )
54
55
else
@@ -57,7 +58,7 @@ defmodule Pythonx.Uv do
57
58
|> :erlang . md5 ( )
58
59
|> Base . encode32 ( case: :lower , padding: false )
59
60
60
- Path . join ( [ cache_dir ( ) , "projects" , cache_id ] )
61
+ Path . join ( [ cache_dir ( uv_version ) , "projects" , cache_id ] )
61
62
end
62
63
end
63
64
@@ -66,8 +67,9 @@ defmodule Pythonx.Uv do
66
67
fetched by `fetch/3`.
67
68
"""
68
69
@ spec init ( String . t ( ) , boolean ( ) ) :: :ok
69
- def init ( pyproject_toml , priv? ) do
70
- project_dir = project_dir ( pyproject_toml , priv? )
70
+ def init ( pyproject_toml , priv? , opts \\ [ ] ) do
71
+ opts = Keyword . validate! ( opts , uv_version: default_uv_version ( ) )
72
+ project_dir = project_dir ( pyproject_toml , priv? , opts [ :uv_version ] )
71
73
72
74
# Uv stores Python installations in versioned directories in the
73
75
# Python install dir. To find the versioned name for this project,
@@ -91,7 +93,7 @@ defmodule Pythonx.Uv do
91
93
{ :unix , _osname } -> Path . basename ( Path . dirname ( abs_executable_dir ) )
92
94
end
93
95
94
- root_dir = Path . join ( python_install_dir ( priv? ) , versioned_dir_name )
96
+ root_dir = Path . join ( python_install_dir ( priv? , opts [ :uv_version ] ) , versioned_dir_name )
95
97
96
98
case :os . type ( ) do
97
99
{ :win32 , _osname } ->
@@ -158,10 +160,11 @@ defmodule Pythonx.Uv do
158
160
defp make_windows_slashes ( path ) , do: String . replace ( path , "/" , "\\ " )
159
161
160
162
defp run! ( args , opts ) do
161
- path = uv_path ( )
163
+ { uv_version , opts } = Keyword . pop ( opts , :uv_version , default_uv_version ( ) )
164
+ path = uv_path ( uv_version )
162
165
163
166
if not File . exists? ( path ) do
164
- download! ( )
167
+ download! ( uv_version )
165
168
end
166
169
167
170
{ _stream , status } =
@@ -170,31 +173,31 @@ defmodule Pythonx.Uv do
170
173
status
171
174
end
172
175
173
- defp uv_path ( ) do
174
- Path . join ( [ cache_dir ( ) , "bin" , "uv" ] )
176
+ defp uv_path ( uv_version ) do
177
+ Path . join ( [ cache_dir ( uv_version ) , "bin" , "uv" ] )
175
178
end
176
179
177
180
@ version Mix.Project . config ( ) [ :version ]
178
181
179
- defp cache_dir ( ) do
182
+ defp cache_dir ( uv_version ) do
180
183
base_dir =
181
184
if dir = System . get_env ( "PYTHONX_CACHE_DIR" ) do
182
185
Path . expand ( dir )
183
186
else
184
187
:filename . basedir ( :user_cache , "pythonx" )
185
188
end
186
189
187
- Path . join ( [ base_dir , @ version , "uv" , @ uv_version ] )
190
+ Path . join ( [ base_dir , @ version , "uv" , uv_version ] )
188
191
end
189
192
190
- defp download! ( ) do
193
+ defp download! ( uv_version ) do
191
194
{ archive_type , archive_name } = archive_name ( )
192
195
193
- url = "https://github.com/astral-sh/uv/releases/download/#{ @ uv_version } /#{ archive_name } "
196
+ url = "https://github.com/astral-sh/uv/releases/download/#{ uv_version } /#{ archive_name } "
194
197
Logger . debug ( "Downloading uv archive from #{ url } " )
195
198
archive_binary = Pythonx.Utils . fetch_body! ( url )
196
199
197
- path = uv_path ( )
200
+ path = uv_path ( uv_version )
198
201
{ :ok , uv_binary } = extract_executable ( archive_type , archive_binary )
199
202
File . mkdir_p! ( Path . dirname ( path ) )
200
203
File . write! ( path , uv_binary )
0 commit comments