diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index 56512ee8af39df52283aa88d6885a192732ed020..bcdc7969b4f2b22f5136c733afd477f7d0cf0187 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -28,6 +28,7 @@ use std::env::consts; use terminal::terminal_settings::TerminalSettings; use util::command::new_smol_command; use util::fs::{make_file_executable, remove_matching}; +use util::paths::PathStyle; use util::rel_path::RelPath; use http_client::github_download::{GithubBinaryMetadata, download_server_binary}; @@ -884,7 +885,7 @@ impl PythonContextProvider { variables: &task::TaskVariables, ) -> Option<(VariableName, String)> { let python_module_name = - python_module_name_from_relative_path(variables.get(&VariableName::RelativeFile)?); + python_module_name_from_relative_path(variables.get(&VariableName::RelativeFile)?)?; let unittest_class_name = variables.get(&VariableName::Custom(Cow::Borrowed("_unittest_class_name"))); @@ -941,9 +942,10 @@ impl PythonContextProvider { &self, variables: &task::TaskVariables, ) -> Result<(VariableName, String)> { - let python_module_name = python_module_name_from_relative_path( - variables.get(&VariableName::RelativeFile).unwrap_or(""), - ); + let python_module_name = variables + .get(&VariableName::RelativeFile) + .and_then(|module| python_module_name_from_relative_path(module)) + .unwrap_or_default(); let module_target = (PYTHON_MODULE_NAME_TASK_VARIABLE.clone(), python_module_name); @@ -951,12 +953,15 @@ impl PythonContextProvider { } } -fn python_module_name_from_relative_path(relative_path: &str) -> String { - let path_with_dots = relative_path.replace('/', "."); - path_with_dots - .strip_suffix(".py") - .unwrap_or(&path_with_dots) - .to_string() +fn python_module_name_from_relative_path(relative_path: &str) -> Option { + let rel_path = RelPath::new(relative_path.as_ref(), PathStyle::local()).ok()?; + let path_with_dots = rel_path.display(PathStyle::Posix).replace('/', "."); + Some( + path_with_dots + .strip_suffix(".py") + .map(ToOwned::to_owned) + .unwrap_or(path_with_dots), + ) } fn is_python_env_global(k: &PythonEnvironmentKind) -> bool { @@ -2311,6 +2316,8 @@ mod tests { use settings::SettingsStore; use std::num::NonZeroU32; + use crate::python::python_module_name_from_relative_path; + #[gpui::test] async fn test_python_autoindent(cx: &mut TestAppContext) { cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX); @@ -2439,4 +2446,35 @@ mod tests { buffer }); } + + #[test] + fn test_python_module_name_from_relative_path() { + assert_eq!( + python_module_name_from_relative_path("foo/bar.py"), + Some("foo.bar".to_string()) + ); + assert_eq!( + python_module_name_from_relative_path("foo/bar"), + Some("foo.bar".to_string()) + ); + if cfg!(windows) { + assert_eq!( + python_module_name_from_relative_path("foo\\bar.py"), + Some("foo.bar".to_string()) + ); + assert_eq!( + python_module_name_from_relative_path("foo\\bar"), + Some("foo.bar".to_string()) + ); + } else { + assert_eq!( + python_module_name_from_relative_path("foo\\bar.py"), + Some("foo\\bar".to_string()) + ); + assert_eq!( + python_module_name_from_relative_path("foo\\bar"), + Some("foo\\bar".to_string()) + ); + } + } }