Check if a module file possibly shadows another module of the same name. Compares the module's directory with the original sys.path[0] (derived from sys.argv[0]).
(origin: &str, vm: &VirtualMachine)
| 288 | /// Check if a module file possibly shadows another module of the same name. |
| 289 | /// Compares the module's directory with the original sys.path[0] (derived from sys.argv[0]). |
| 290 | pub(crate) fn is_possibly_shadowing_path(origin: &str, vm: &VirtualMachine) -> bool { |
| 291 | use std::path::Path; |
| 292 | |
| 293 | if vm.state.config.settings.safe_path { |
| 294 | return false; |
| 295 | } |
| 296 | |
| 297 | let origin_path = Path::new(origin); |
| 298 | let parent = match origin_path.parent() { |
| 299 | Some(p) => p, |
| 300 | None => return false, |
| 301 | }; |
| 302 | // For packages (__init__.py), look one directory further up |
| 303 | let root = if origin_path.file_name() == Some("__init__.py".as_ref()) { |
| 304 | parent.parent().unwrap_or(Path::new("")) |
| 305 | } else { |
| 306 | parent |
| 307 | }; |
| 308 | |
| 309 | // Compute original sys.path[0] from sys.argv[0] (the script path). |
| 310 | // See: config->sys_path_0, which is set once |
| 311 | // at initialization and never changes even if sys.path is modified. |
| 312 | let sys_path_0 = (|| -> Option<String> { |
| 313 | let argv = vm.sys_module.get_attr("argv", vm).ok()?; |
| 314 | let argv0 = argv.get_item(&0usize, vm).ok()?; |
| 315 | let argv0_str = argv0.downcast_ref::<PyUtf8Str>()?; |
| 316 | let s = argv0_str.as_str(); |
| 317 | |
| 318 | // For -c and REPL, original sys.path[0] is "" |
| 319 | if s == "-c" || s.is_empty() { |
| 320 | return Some(String::new()); |
| 321 | } |
| 322 | // For scripts, original sys.path[0] is dirname(argv[0]) |
| 323 | Some( |
| 324 | Path::new(s) |
| 325 | .parent() |
| 326 | .and_then(|p| p.to_str()) |
| 327 | .unwrap_or("") |
| 328 | .to_owned(), |
| 329 | ) |
| 330 | })(); |
| 331 | |
| 332 | let sys_path_0 = match sys_path_0 { |
| 333 | Some(p) => p, |
| 334 | None => return false, |
| 335 | }; |
| 336 | |
| 337 | let cmp_path = if sys_path_0.is_empty() { |
| 338 | match std::env::current_dir() { |
| 339 | Ok(d) => d.to_string_lossy().to_string(), |
| 340 | Err(_) => return false, |
| 341 | } |
| 342 | } else { |
| 343 | sys_path_0 |
| 344 | }; |
| 345 | |
| 346 | root.to_str() == Some(cmp_path.as_str()) |
| 347 | } |