Skip to content

Commit 3867a0a

Browse files
committed
Add sys._stdlib_dir
1 parent 2da102f commit 3867a0a

File tree

9 files changed

+103
-68
lines changed

9 files changed

+103
-68
lines changed
Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
1-
Received: from xcar [192.168.0.2] by jeeves.wooster.local
2-
(SMTPD32-7.07 EVAL) id AFF92F0214; Sun, 12 May 2002 08:55:37 +0100
3-
Date: Sun, 12 May 2002 08:56:15 +0100
4-
From: Father Time <father.time@xcar.wooster.local>
5-
To: timbo@jeeves.wooster.local
6-
Subject: IMAP file test
7-
Message-ID: <6df65d354b.father.time@rpc.wooster.local>
8-
X-Organization: Home
9-
User-Agent: Messenger-Pro/2.50a (MsgServe/1.50) (RISC-OS/4.02) POPstar/2.03
10-
MIME-Version: 1.0
11-
Content-Type: multipart/mixed; boundary="1618492860--2051301190--113853680"
12-
Status: R
13-
X-UIDL: 319998302
14-
15-
This message is in MIME format which your mailer apparently does not support.
16-
You either require a newer version of your software which supports MIME, or
17-
a separate MIME decoding utility. Alternatively, ask the sender of this
18-
message to resend it in a different format.
19-
20-
--1618492860--2051301190--113853680
21-
Content-Type: text/plain; charset=us-ascii
22-
23-
Simple email with attachment.
24-
25-
26-
--1618492860--2051301190--113853680
27-
Content-Type: application/riscos; name="clock.bmp,69c"; type=BMP;
28-
load=&fff69c4b; exec=&355dd4d1; access=&03
29-
Content-Disposition: attachment; filename="clock.bmp"
30-
Content-Transfer-Encoding: base64
31-
32-
Qk12AgAAAAAAAHYAAAAoAAAAIAAAACAAAAABAAQAAAAAAAAAAADXDQAA1w0AAAAAAAAA
33-
AAAAAAAAAAAAiAAAiAAAAIiIAIgAAACIAIgAiIgAALu7uwCIiIgAERHdACLuIgAz//8A
34-
zAAAAN0R3QDu7iIA////AAAAAAAAAAAAAAAAAAAAAAAAAAi3AAAAAAAAADeAAAAAAAAA
35-
C3ADMzMzMANwAAAAAAAAAAAHMAAAAANwAAAAAAAAAACAMAd3zPfwAwgAAAAAAAAIAwd/
36-
f8x/f3AwgAAAAAAAgDB0x/f3//zPAwgAAAAAAAcHfM9////8z/AwAAAAAAiwd/f3////
37-
////A4AAAAAAcEx/f///////zAMAAAAAiwfM9////3///8zwOAAAAAcHf3////B/////
38-
8DAAAAALB/f3///wd3d3//AwAAAABwTPf//wCQAAD/zAMAAAAAsEx/f///B////8wDAA
39-
AAAHB39////wf/////AwAAAACwf39///8H/////wMAAAAIcHfM9///B////M8DgAAAAA
40-
sHTH///wf///xAMAAAAACHB3f3//8H////cDgAAAAAALB3zH//D//M9wMAAAAAAAgLB0
41-
z39///xHAwgAAAAAAAgLB3d3RHd3cDCAAAAAAAAAgLAHd0R3cAMIAAAAAAAAgAgLcAAA
42-
AAMwgAgAAAAACDAAAAu7t7cwAAgDgAAAAABzcIAAAAAAAAgDMwAAAAAAN7uwgAAAAAgH
43-
MzMAAAAACH97tzAAAAALu3c3gAAAAAAL+7tzDABAu7f7cAAAAAAACA+3MA7EQAv/sIAA
44-
AAAAAAAIAAAAAAAAAIAAAAAA
45-
46-
--1618492860--2051301190--113853680--
1+
Received: from xcar [192.168.0.2] by jeeves.wooster.local
2+
(SMTPD32-7.07 EVAL) id AFF92F0214; Sun, 12 May 2002 08:55:37 +0100
3+
Date: Sun, 12 May 2002 08:56:15 +0100
4+
From: Father Time <father.time@xcar.wooster.local>
5+
To: timbo@jeeves.wooster.local
6+
Subject: IMAP file test
7+
Message-ID: <6df65d354b.father.time@rpc.wooster.local>
8+
X-Organization: Home
9+
User-Agent: Messenger-Pro/2.50a (MsgServe/1.50) (RISC-OS/4.02) POPstar/2.03
10+
MIME-Version: 1.0
11+
Content-Type: multipart/mixed; boundary="1618492860--2051301190--113853680"
12+
Status: R
13+
X-UIDL: 319998302
14+
15+
This message is in MIME format which your mailer apparently does not support.
16+
You either require a newer version of your software which supports MIME, or
17+
a separate MIME decoding utility. Alternatively, ask the sender of this
18+
message to resend it in a different format.
19+
20+
--1618492860--2051301190--113853680
21+
Content-Type: text/plain; charset=us-ascii
22+
23+
Simple email with attachment.
24+
25+
26+
--1618492860--2051301190--113853680
27+
Content-Type: application/riscos; name="clock.bmp,69c"; type=BMP;
28+
load=&fff69c4b; exec=&355dd4d1; access=&03
29+
Content-Disposition: attachment; filename="clock.bmp"
30+
Content-Transfer-Encoding: base64
31+
32+
Qk12AgAAAAAAAHYAAAAoAAAAIAAAACAAAAABAAQAAAAAAAAAAADXDQAA1w0AAAAAAAAA
33+
AAAAAAAAAAAAiAAAiAAAAIiIAIgAAACIAIgAiIgAALu7uwCIiIgAERHdACLuIgAz//8A
34+
zAAAAN0R3QDu7iIA////AAAAAAAAAAAAAAAAAAAAAAAAAAi3AAAAAAAAADeAAAAAAAAA
35+
C3ADMzMzMANwAAAAAAAAAAAHMAAAAANwAAAAAAAAAACAMAd3zPfwAwgAAAAAAAAIAwd/
36+
f8x/f3AwgAAAAAAAgDB0x/f3//zPAwgAAAAAAAcHfM9////8z/AwAAAAAAiwd/f3////
37+
////A4AAAAAAcEx/f///////zAMAAAAAiwfM9////3///8zwOAAAAAcHf3////B/////
38+
8DAAAAALB/f3///wd3d3//AwAAAABwTPf//wCQAAD/zAMAAAAAsEx/f///B////8wDAA
39+
AAAHB39////wf/////AwAAAACwf39///8H/////wMAAAAIcHfM9///B////M8DgAAAAA
40+
sHTH///wf///xAMAAAAACHB3f3//8H////cDgAAAAAALB3zH//D//M9wMAAAAAAAgLB0
41+
z39///xHAwgAAAAAAAgLB3d3RHd3cDCAAAAAAAAAgLAHd0R3cAMIAAAAAAAAgAgLcAAA
42+
AAMwgAgAAAAACDAAAAu7t7cwAAgDgAAAAABzcIAAAAAAAAgDMwAAAAAAN7uwgAAAAAgH
43+
MzMAAAAACH97tzAAAAALu3c3gAAAAAAL+7tzDABAu7f7cAAAAAAACA+3MA7EQAv/sIAA
44+
AAAAAAAIAAAAAAAAAIAAAAAA
45+
46+
--1618492860--2051301190--113853680--
-1 Bytes
Loading

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)