Diff
1diff --git a/autoswitch_virtualenv.plugin.zsh b/autoswitch_virtualenv.plugin.zsh
2index a6c67d2d2df48303ded6943ddba51d481246e095..d7b13a71d23db25b13abc911066c9a468a3bee46 100644
3--- a/autoswitch_virtualenv.plugin.zsh
4+++ b/autoswitch_virtualenv.plugin.zsh
5@@ -47,6 +47,11 @@ function _autoswitch_message() {
6 }
7
8
9+function _is_valid_virtualenv() {
10+ [[ -d "$1" ]] && [[ -f "$1/bin/activate" ]]
11+}
12+
13+
14 function _get_venv_type() {
15 local venv_dir="$1"
16 local venv_type="${2:-virtualenv}"
17@@ -126,6 +131,9 @@ function _check_path()
18 if [[ -f "${check_dir}/${AUTOSWITCH_FILE}" ]]; then
19 printf "${check_dir}/${AUTOSWITCH_FILE}"
20 return
21+ elif _is_valid_virtualenv "${check_dir}/${AUTOSWITCH_FILE}"; then
22+ printf "${check_dir}/${AUTOSWITCH_FILE}"
23+ return
24 elif [[ -f "${check_dir}/poetry.lock" ]]; then
25 printf "${check_dir}/poetry.lock"
26 elif [[ -f "${check_dir}/Pipfile" ]]; then
27@@ -218,8 +226,7 @@ function check_venv()
28 local switch_to="$(<"$venv_path")"
29 _maybeworkon "$(_virtual_env_dir "$switch_to")" "virtualenv"
30 return
31- # $venv_path actually is itself a virtualenv
32- elif [[ -d "$venv_path" ]] && [[ -f "$venv_path/bin/activate" ]]; then
33+ elif _is_valid_virtualenv "$venv_path"; then
34 _maybeworkon "$venv_path" "virtualenv"
35 return
36 fi
37diff --git a/tests/test_check_path.zunit b/tests/test_check_path.zunit
38index 34e16a5a2a51d4c7d9347c96c97e342a723a21f8..c13f802ed39ae92e7b1d3890585fe48071a19df5 100644
39--- a/tests/test_check_path.zunit
40+++ b/tests/test_check_path.zunit
41@@ -53,3 +53,33 @@
42 assert $state equals 0
43 assert "$output" is_empty
44 }
45+
46+@test '_check_path - finds .venv directory with bin/activate' {
47+ mkdir -p "$TARGET/.venv/bin"
48+ touch "$TARGET/.venv/bin/activate"
49+
50+ run _check_path "$TARGET"
51+
52+ assert $state equals 0
53+ assert "$output" same_as "$TARGET/.venv"
54+}
55+
56+@test '_check_path - ignores .venv directory without bin/activate' {
57+ mkdir -p "$TARGET/.venv"
58+
59+ run _check_path "$TARGET"
60+
61+ assert $state equals 0
62+ assert "$output" is_empty
63+}
64+
65+@test '_check_path - finds local .venv directory instead of parent marker' {
66+ touch "$TARGET/uv.lock"
67+ mkdir -p "$TARGET/subdir/.venv/bin"
68+ touch "$TARGET/subdir/.venv/bin/activate"
69+
70+ run _check_path "$TARGET/subdir"
71+
72+ assert $state equals 0
73+ assert "$output" same_as "$TARGET/subdir/.venv"
74+}
75diff --git a/tests/test_is_valid_virtualenv.zunit b/tests/test_is_valid_virtualenv.zunit
76new file mode 100644
77index 0000000000000000000000000000000000000000..924946c908a91fbe97af7fad1d467ee1d8df1155
78--- /dev/null
79+++ b/tests/test_is_valid_virtualenv.zunit
80@@ -0,0 +1,43 @@
81+#!/usr/bin/env zunit
82+
83+
84+@setup {
85+ export DISABLE_AUTOSWITCH_VENV="1"
86+ load "../autoswitch_virtualenv.plugin.zsh"
87+ TARGET="$(mktemp -d)"
88+}
89+
90+@teardown {
91+ rm -rf "$TARGET"
92+}
93+
94+@test '_is_valid_virtualenv - returns true for valid virtualenv' {
95+ mkdir -p "$TARGET/.venv/bin"
96+ touch "$TARGET/.venv/bin/activate"
97+
98+ run _is_valid_virtualenv "$TARGET/.venv"
99+
100+ assert $state equals 0
101+}
102+
103+@test '_is_valid_virtualenv - returns false for directory without bin/activate' {
104+ mkdir -p "$TARGET/.venv/bin"
105+
106+ run _is_valid_virtualenv "$TARGET/.venv"
107+
108+ assert $state equals 1
109+}
110+
111+@test '_is_valid_virtualenv - returns false for non-existent path' {
112+ run _is_valid_virtualenv "$TARGET/.venv"
113+
114+ assert $state equals 1
115+}
116+
117+@test '_is_valid_virtualenv - returns false for file' {
118+ touch "$TARGET/.venv"
119+
120+ run _is_valid_virtualenv "$TARGET/.venv"
121+
122+ assert $state equals 1
123+}