Skip to content

Commit 1669f5d

Browse files
committed
Fix ensure_venv to always install deps, even if venv exists
Previously, if a venv already existed, ensure_venv would just activate it without checking/installing dependencies. Now it always runs pip/uv install, which is fast when deps are already present (they get skipped) but ensures new dependencies are installed. Added test: test_ensure_venv_installs_new_deps
1 parent c45d9e5 commit 1669f5d

2 files changed

Lines changed: 44 additions & 13 deletions

File tree

src/py.erl

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -763,24 +763,24 @@ ensure_venv(Path, RequirementsFile, Opts) ->
763763
PathStr = to_string(Path),
764764
ReqFileStr = to_string(RequirementsFile),
765765
Force = proplists:get_bool(force, Opts),
766-
case venv_exists(PathStr) of
766+
%% Create venv if needed
767+
VenvReady = case venv_exists(PathStr) of
767768
true when not Force ->
768-
%% Venv exists, just activate
769-
activate_venv(PathStr);
769+
ok;
770770
_ ->
771-
%% Create venv
772-
case create_venv(PathStr, Opts) of
771+
create_venv(PathStr, Opts)
772+
end,
773+
case VenvReady of
774+
ok ->
775+
%% Always install/update dependencies (pip/uv skip existing)
776+
case install_deps(PathStr, ReqFileStr, Opts) of
773777
ok ->
774-
%% Install dependencies
775-
case install_deps(PathStr, ReqFileStr, Opts) of
776-
ok ->
777-
activate_venv(PathStr);
778-
{error, _} = Err ->
779-
Err
780-
end;
778+
activate_venv(PathStr);
781779
{error, _} = Err ->
782780
Err
783-
end
781+
end;
782+
{error, _} = Err ->
783+
Err
784784
end.
785785

786786
%% @private Check if venv exists by looking for pyvenv.cfg

test/py_venv_SUITE.erl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
test_ensure_venv_creates_venv/1,
3333
test_ensure_venv_activates_existing/1,
3434
test_ensure_venv_with_requirements/1,
35+
test_ensure_venv_installs_new_deps/1,
3536
test_ensure_venv_force_recreate/1,
3637
test_activate_venv/1,
3738
test_deactivate_venv/1,
@@ -46,6 +47,7 @@ groups() ->
4647
test_ensure_venv_creates_venv,
4748
test_ensure_venv_activates_existing,
4849
test_ensure_venv_with_requirements,
50+
test_ensure_venv_installs_new_deps,
4951
test_ensure_venv_force_recreate,
5052
test_activate_venv,
5153
test_deactivate_venv,
@@ -161,6 +163,35 @@ test_ensure_venv_with_requirements(Config) ->
161163
true = is_binary(Version),
162164
ok.
163165

166+
test_ensure_venv_installs_new_deps(Config) ->
167+
TempDir = ?config(temp_dir, Config),
168+
VenvPath = filename:join(TempDir, "venv"),
169+
ReqFile = filename:join(TempDir, "requirements.txt"),
170+
171+
%% Create requirements with only six
172+
ok = file:write_file(ReqFile, <<"six\n">>),
173+
174+
%% Create venv with six
175+
ok = py:ensure_venv(VenvPath, ReqFile, [{installer, pip}]),
176+
177+
%% Verify six is installed
178+
{ok, _} = py:eval(<<"__import__('six').__version__">>),
179+
180+
%% Verify toml is NOT installed yet (uncommon package)
181+
{error, _} = py:eval(<<"__import__('toml').__version__">>),
182+
183+
%% Now update requirements to add toml
184+
ok = file:write_file(ReqFile, <<"six\ntoml\n">>),
185+
186+
%% Deactivate and re-ensure - should install new deps without recreating venv
187+
ok = py:deactivate_venv(),
188+
ok = py:ensure_venv(VenvPath, ReqFile, [{installer, pip}]),
189+
190+
%% Verify both packages are now installed
191+
{ok, _} = py:eval(<<"__import__('six').__version__">>),
192+
{ok, _} = py:eval(<<"__import__('toml').__version__">>),
193+
ok.
194+
164195
test_ensure_venv_force_recreate(Config) ->
165196
TempDir = ?config(temp_dir, Config),
166197
VenvPath = filename:join(TempDir, "venv"),

0 commit comments

Comments
 (0)