Skip to content

Commit e4cc7bf

Browse files
Add diagnostic logging and improve venv path handling.
1 parent 08f2340 commit e4cc7bf

File tree

1 file changed

+115
-15
lines changed

1 file changed

+115
-15
lines changed

crates/djls-project/src/lib.rs

Lines changed: 115 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,34 +90,64 @@ struct PythonEnvironment {
9090

9191
impl PythonEnvironment {
9292
fn new(project_path: &Path, venv_path: Option<&str>) -> Option<Self> {
93+
eprintln!(
94+
"[PythonEnvironment::new] Start search. Project: '{}', Explicit venv_path: {:?}",
95+
project_path.display(), venv_path
96+
);
97+
9398
if let Some(path) = venv_path {
99+
eprintln!("[PythonEnvironment::new] Checking explicit venv_path: '{}'", path);
94100
let prefix = PathBuf::from(path);
101+
// Call from_venv_prefix for the explicit path
102+
let explicit_env = Self::from_venv_prefix(&prefix);
95103
// If explicit path is provided and valid, use it.
96104
// If it's invalid, we *don't* fall through according to current logic.
97105
// Let's refine this: if explicit path is given but invalid, maybe we should error or log?
98106
// For now, stick to the current implementation: if from_venv_prefix returns Some, we use it.
99-
if let Some(env) = Self::from_venv_prefix(&prefix) {
107+
if let Some(env) = explicit_env {
108+
eprintln!(
109+
"[PythonEnvironment::new] Found environment via explicit path: '{}'",
110+
path
111+
);
100112
return Some(env);
101113
} else {
102114
// Explicit path provided but invalid. Should we stop here?
103115
// The current code implicitly continues to VIRTUAL_ENV check.
104116
// Let's keep the current behavior for now, but it's worth noting.
105117
eprintln!(
106-
"Warning: Explicit venv_path '{}' provided but seems invalid. Continuing search.",
118+
"[PythonEnvironment::new] Explicit venv_path '{}' is invalid or incomplete. Continuing search...",
107119
path
108120
);
109121
}
122+
} else {
123+
eprintln!("[PythonEnvironment::new] No explicit venv_path provided.");
110124
}
111125

112126
if let Ok(virtual_env) = env::var("VIRTUAL_ENV") {
113127
if !virtual_env.is_empty() {
128+
eprintln!("[PythonEnvironment::new] Checking VIRTUAL_ENV: '{}'", virtual_env);
114129
let prefix = PathBuf::from(virtual_env);
130+
// Call from_venv_prefix for the VIRTUAL_ENV path
115131
if let Some(env) = Self::from_venv_prefix(&prefix) {
132+
eprintln!(
133+
"[PythonEnvironment::new] Found environment via VIRTUAL_ENV: '{}'",
134+
prefix.display()
135+
);
116136
return Some(env);
137+
} else {
138+
eprintln!(
139+
"[PythonEnvironment::new] VIRTUAL_ENV path '{}' is invalid or incomplete. Continuing search...",
140+
prefix.display()
141+
);
117142
}
143+
} else {
144+
eprintln!("[PythonEnvironment::new] VIRTUAL_ENV variable is set but empty.");
118145
}
146+
} else {
147+
eprintln!("[PythonEnvironment::new] VIRTUAL_ENV variable not found.");
119148
}
120149

150+
eprintln!("[PythonEnvironment::new] Checking common venv directories within project: '{}'", project_path.display());
121151
for venv_dir in &[".venv", "venv", "env", ".env"] {
122152
let potential_venv = project_path.join(venv_dir);
123153
if potential_venv.is_dir() {
@@ -126,11 +156,23 @@ impl PythonEnvironment {
126156
}
127157
}
128158
}
129-
130-
Self::from_system_python()
159+
eprintln!("[PythonEnvironment::new] No valid environment found in common project directories.");
160+
161+
eprintln!("[PythonEnvironment::new] Falling back to system Python search...");
162+
let system_env = Self::from_system_python();
163+
if system_env.is_some() {
164+
eprintln!("[PythonEnvironment::new] Found system Python.");
165+
} else {
166+
eprintln!("[PythonEnvironment::new] Could not find system Python via 'which python'.");
167+
}
168+
system_env // Return the result of the system python search
131169
}
132170

133171
fn from_venv_prefix(prefix: &Path) -> Option<Self> {
172+
eprintln!(
173+
"[from_venv_prefix] Checking potential venv prefix: '{}'",
174+
prefix.display()
175+
);
134176
#[cfg(not(windows))]
135177
let python_path = prefix.join("bin").join("python");
136178
#[cfg(not(windows))]
@@ -141,20 +183,38 @@ impl PythonEnvironment {
141183
#[cfg(windows)]
142184
let bin_dir = prefix.join("Scripts");
143185

186+
let prefix_is_dir = prefix.is_dir();
187+
let python_exists = python_path.exists();
188+
189+
eprintln!(
190+
"[from_venv_prefix] Checking prefix directory '{}': Exists = {}",
191+
prefix.display(), prefix_is_dir
192+
);
193+
eprintln!(
194+
"[from_venv_prefix] Checking Python binary '{}': Exists = {}",
195+
python_path.display(), python_exists
196+
);
197+
144198
// Check if the *prefix* and the *binary* exist.
145199
// Checking prefix helps avoid issues if only bin/python exists somehow.
146-
if !prefix.is_dir() || !python_path.exists() {
200+
if !prefix_is_dir || !python_exists {
201+
eprintln!("[from_venv_prefix] Basic requirements not met (prefix dir or python binary missing). Returning None.");
147202
return None;
148203
}
149204

150205
let mut sys_path = Vec::new();
151206
sys_path.push(bin_dir); // Add bin/ or Scripts/
152207

153208
if let Some(site_packages) = Self::find_site_packages(prefix) {
209+
// Check existence inside the if let, as find_site_packages might return a path that doesn't exist
154210
if site_packages.is_dir() {
211+
eprintln!("[from_venv_prefix] Confirmed site-packages directory '{}' exists. Adding to sys_path.", site_packages.display());
155212
sys_path.push(site_packages);
213+
} else {
214+
eprintln!("[from_venv_prefix] Warning: Found site-packages path '{}' but it's not a directory.", site_packages.display());
156215
}
157216
}
217+
eprintln!("[from_venv_prefix] Successfully created environment for prefix '{}'", prefix.display());
158218

159219
Some(Self {
160220
python_path: python_path.clone(),
@@ -324,29 +384,56 @@ mod tests {
324384
fn test_explicit_venv_path_invalid_falls_through_to_virtual_env() {
325385
let project_dir = tempdir().unwrap();
326386
let venv_dir = tempdir().unwrap();
387+
// Keep None here for consistency with original test logic
327388
let venv_prefix = create_mock_venv(venv_dir.path(), None);
389+
let venv_prefix_str = venv_prefix.to_str().expect("Failed to convert venv_prefix path to string");
390+
391+
// --- Add checks immediately after creating the mock venv ---
392+
#[cfg(not(windows))]
393+
{
394+
let expected_bin = venv_prefix.join("bin");
395+
let expected_py = expected_bin.join("python");
396+
let expected_sp = venv_prefix.join("lib").join("python3.9").join("site-packages"); // Matches default in create_mock_venv
397+
assert!(expected_py.exists(), "Mock python binary should exist at '{}'", expected_py.display());
398+
assert!(expected_sp.is_dir(), "Mock site-packages dir should exist at '{}'", expected_sp.display());
399+
}
400+
#[cfg(windows)]
401+
{
402+
let expected_scripts = venv_prefix.join("Scripts");
403+
let expected_py = expected_scripts.join("python.exe");
404+
let expected_sp = venv_prefix.join("Lib").join("site-packages");
405+
assert!(expected_py.exists(), "Mock python binary should exist at '{}'", expected_py.display());
406+
assert!(expected_sp.is_dir(), "Mock site-packages dir should exist at '{}'", expected_sp.display());
407+
}
408+
// --- End added checks ---
328409

329410
// Set VIRTUAL_ENV to the valid path
330-
let _guard = VirtualEnvGuard::set("VIRTUAL_ENV", venv_prefix.to_str().unwrap());
411+
let _guard = VirtualEnvGuard::set("VIRTUAL_ENV", venv_prefix_str);
331412

332413
// Provide an invalid explicit path (points to a non-existent directory)
333414
let invalid_path = project_dir.path().join("non_existent_venv");
334415
let invalid_path_str = invalid_path.to_str().unwrap();
335416
// Ensure the invalid path doesn't accidentally exist
336417
assert!(!invalid_path.exists(), "Invalid path '{}' should not exist before test", invalid_path.display());
337418

338-
// --- Add a small delay before calling the function under test ---
339-
eprintln!("--- Adding small delay before PythonEnvironment::new call ---");
340-
std::thread::sleep(std::time::Duration::from_millis(50)); // 50ms delay
341-
eprintln!("--- Delay finished. Starting PythonEnvironment::new call for the test ---");
342-
// --- End added delay ---
343-
344419
eprintln!("--- Starting PythonEnvironment::new call for the test ---");
345420
// Call the function under test
346421
let env_result = PythonEnvironment::new(project_dir.path(), Some(invalid_path_str));
347422
eprintln!("--- Finished PythonEnvironment::new call for the test ---");
348423

349-
let env = env_result.expect("Should fall through to VIRTUAL_ENV");
424+
// Check the result with more detailed error message if it's None
425+
let env = env_result.unwrap_or_else(|| {
426+
// This path indicates `new` returned None, meaning the VIRTUAL_ENV check likely failed.
427+
panic!(
428+
"PythonEnvironment::new returned None unexpectedly. \
429+
It should have fallen back to VIRTUAL_ENV ('{}'). \
430+
Project: '{}', Invalid Explicit Path: '{}'. \
431+
Check logs above for details on why from_venv_prefix might have failed for the VIRTUAL_ENV path.",
432+
venv_prefix_str,
433+
project_dir.path().display(),
434+
invalid_path_str
435+
);
436+
});
350437

351438
// Should have found the one from VIRTUAL_ENV
352439
assert_eq!(
@@ -362,10 +449,17 @@ mod tests {
362449
env.python_path, expected_python_path,
363450
"Python path should match the one in VIRTUAL_ENV bin dir"
364451
);
452+
let expected_bin_dir = venv_prefix.join("bin");
365453
assert!(
366-
env.sys_path.contains(&venv_prefix.join("bin")),
454+
env.sys_path.contains(&expected_bin_dir),
367455
"Sys path should contain VIRTUAL_ENV bin dir"
368456
);
457+
// Check against the default version used by create_mock_venv when None is passed
458+
let expected_site_packages = venv_prefix.join("lib").join("python3.9").join("site-packages");
459+
assert!(
460+
env.sys_path.contains(&expected_site_packages),
461+
"Sys path should contain VIRTUAL_ENV site-packages dir ('{}')", expected_site_packages.display()
462+
);
369463
}
370464

371465
#[cfg(windows)]
@@ -375,10 +469,16 @@ mod tests {
375469
env.python_path, expected_python_path,
376470
"Python path should match the one in VIRTUAL_ENV Scripts dir"
377471
);
472+
let expected_scripts_dir = venv_prefix.join("Scripts");
378473
assert!(
379-
env.sys_path.contains(&venv_prefix.join("Scripts")),
474+
env.sys_path.contains(&expected_scripts_dir),
380475
"Sys path should contain VIRTUAL_ENV Scripts dir"
381476
);
477+
let expected_site_packages = venv_prefix.join("Lib").join("site-packages");
478+
assert!(
479+
env.sys_path.contains(&expected_site_packages),
480+
"Sys path should contain VIRTUAL_ENV site-packages dir ('{}')", expected_site_packages.display()
481+
);
382482
}
383483
}
384484

0 commit comments

Comments
 (0)