Skip to content

Commit b76906a

Browse files
authored
Add sys._stdlib_dir (#6798)
1 parent 7d2f284 commit b76906a

File tree

7 files changed

+57
-22
lines changed

7 files changed

+57
-22
lines changed

Lib/test/test_importlib/resources/test_files.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class OpenDiskTests(FilesTests, unittest.TestCase):
5252
def setUp(self):
5353
self.data = data01
5454

55-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
55+
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON, line ending issue")
5656
def test_read_bytes(self):
5757
super().test_read_bytes()
5858

@@ -67,10 +67,11 @@ def setUp(self):
6767

6868
self.data = namespacedata01
6969

70-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
70+
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON, line ending issue")
7171
def test_read_bytes(self):
7272
super().test_read_bytes()
7373

74+
7475
class SiteDir:
7576
def setUp(self):
7677
self.fixtures = contextlib.ExitStack()

Lib/test/test_sys.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1310,7 +1310,6 @@ def test_module_names(self):
13101310
for name in sys.stdlib_module_names:
13111311
self.assertIsInstance(name, str)
13121312

1313-
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'sys' has no attribute '_stdlib_dir'
13141313
def test_stdlib_dir(self):
13151314
os = import_helper.import_fresh_module('os')
13161315
marker = getattr(os, '__file__', None)

crates/pylib/build.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,25 @@ fn main() {
1111
process_python_libs("./Lib/**/*");
1212
}
1313

14-
if cfg!(windows)
15-
&& let Ok(real_path) = std::fs::read_to_string("Lib")
16-
{
17-
let canonicalized_path = std::fs::canonicalize(real_path)
18-
.expect("failed to resolve RUSTPYTHONPATH during build time");
19-
// Strip the extended path prefix (\\?\) that canonicalize adds on Windows
20-
let path_str = canonicalized_path.to_str().unwrap();
21-
let path_str = path_str.strip_prefix(r"\\?\").unwrap_or(path_str);
22-
println!("cargo:rustc-env=win_lib_path={path_str}");
14+
if cfg!(windows) {
15+
// On Windows, the Lib entry can be either:
16+
// 1. A text file containing the relative path (git without symlink support)
17+
// 2. A proper symlink (git with symlink support)
18+
// We handle both cases to resolve to the actual Lib directory.
19+
let lib_path = if let Ok(real_path) = std::fs::read_to_string("Lib") {
20+
// Case 1: Text file containing relative path
21+
std::path::PathBuf::from(real_path.trim())
22+
} else {
23+
// Case 2: Symlink or directory - canonicalize directly
24+
std::path::PathBuf::from("Lib")
25+
};
26+
27+
if let Ok(canonicalized_path) = std::fs::canonicalize(&lib_path) {
28+
// Strip the extended path prefix (\\?\) that canonicalize adds on Windows
29+
let path_str = canonicalized_path.to_str().unwrap();
30+
let path_str = path_str.strip_prefix(r"\\?\").unwrap_or(path_str);
31+
println!("cargo:rustc-env=win_lib_path={path_str}");
32+
}
2333
}
2434
}
2535

crates/vm/src/getpath.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ pub fn init_path_config(settings: &Settings) -> Paths {
174174
paths.module_search_paths =
175175
build_module_search_paths(settings, &paths.prefix, &paths.exec_prefix);
176176

177+
// Step 9: Calculate stdlib_dir
178+
paths.stdlib_dir = calculate_stdlib_dir(&paths.prefix);
179+
177180
paths
178181
}
179182

@@ -301,6 +304,22 @@ fn calculate_base_executable(executable: Option<&PathBuf>, home_dir: &Option<Pat
301304
.unwrap_or_default()
302305
}
303306

307+
/// Calculate stdlib_dir (sys._stdlib_dir)
308+
/// Returns None if the stdlib directory doesn't exist
309+
fn calculate_stdlib_dir(prefix: &str) -> Option<String> {
310+
#[cfg(not(windows))]
311+
let stdlib_dir = PathBuf::from(prefix).join(platform::stdlib_subdir());
312+
313+
#[cfg(windows)]
314+
let stdlib_dir = PathBuf::from(prefix).join(platform::STDLIB_SUBDIR);
315+
316+
if stdlib_dir.is_dir() {
317+
Some(stdlib_dir.to_string_lossy().into_owned())
318+
} else {
319+
None
320+
}
321+
}
322+
304323
/// Build the complete module_search_paths (sys.path)
305324
fn build_module_search_paths(settings: &Settings, prefix: &str, exec_prefix: &str) -> Vec<String> {
306325
let mut paths = Vec::new();

crates/vm/src/stdlib/sys.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ mod sys {
148148
fn platlibdir(_vm: &VirtualMachine) -> &'static str {
149149
option_env!("RUSTPYTHON_PLATLIBDIR").unwrap_or("lib")
150150
}
151+
#[pyattr]
152+
fn _stdlib_dir(vm: &VirtualMachine) -> PyObjectRef {
153+
vm.state.config.paths.stdlib_dir.clone().to_pyobject(vm)
154+
}
151155

152156
// alphabetical order with segments of pyattr and others
153157

crates/vm/src/vm/setting.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub struct Paths {
1616
pub exec_prefix: String,
1717
/// sys.base_exec_prefix
1818
pub base_exec_prefix: String,
19+
/// sys._stdlib_dir
20+
pub stdlib_dir: Option<String>,
1921
/// Computed module_search_paths (complete sys.path)
2022
pub module_search_paths: Vec<String>,
2123
}

src/interpreter.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,13 @@ pub fn init_stdlib(vm: &mut VirtualMachine) {
113113
/// Setup frozen standard library (compiled into the binary)
114114
#[cfg(all(feature = "stdlib", feature = "freeze-stdlib"))]
115115
fn setup_frozen_stdlib(vm: &mut VirtualMachine) {
116+
use rustpython_vm::common::rc::PyRc;
117+
116118
vm.add_frozen(rustpython_pylib::FROZEN_STDLIB);
117119

118-
// FIXME: Remove this hack once sys._stdlib_dir is properly implemented
119-
// or _frozen_importlib doesn't depend on it anymore.
120-
assert!(vm.sys_module.get_attr("_stdlib_dir", vm).is_err());
121-
vm.sys_module
122-
.set_attr(
123-
"_stdlib_dir",
124-
vm.new_pyobj(rustpython_pylib::LIB_PATH.to_owned()),
125-
vm,
126-
)
127-
.unwrap();
120+
// Set stdlib_dir to the frozen stdlib path
121+
let state = PyRc::get_mut(&mut vm.state).unwrap();
122+
state.config.paths.stdlib_dir = Some(rustpython_pylib::LIB_PATH.to_owned());
128123
}
129124

130125
/// Setup dynamic standard library loading from filesystem
@@ -135,6 +130,11 @@ fn setup_dynamic_stdlib(vm: &mut VirtualMachine) {
135130
let state = PyRc::get_mut(&mut vm.state).unwrap();
136131
let paths = collect_stdlib_paths();
137132

133+
// Set stdlib_dir to the first stdlib path if available
134+
if let Some(first_path) = paths.first() {
135+
state.config.paths.stdlib_dir = Some(first_path.clone());
136+
}
137+
138138
// Insert at the beginning so stdlib comes before user paths
139139
for path in paths.into_iter().rev() {
140140
state.config.paths.module_search_paths.insert(0, path);

0 commit comments

Comments
 (0)