Skip to content

Commit c445bc4

Browse files
committed
Update validation.rs for Python 3.13
1 parent 92382eb commit c445bc4

File tree

1 file changed

+110
-54
lines changed

1 file changed

+110
-54
lines changed

src/validation.rs

+110-54
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,6 @@ const GLOBAL_EXTENSIONS: &[&str] = &[
648648
"_weakref",
649649
"array",
650650
"atexit",
651-
"audioop",
652651
"binascii",
653652
"builtins",
654653
"cmath",
@@ -675,13 +674,17 @@ const GLOBAL_EXTENSIONS: &[&str] = &[
675674
// _testsinglephase added in 3.12.
676675
// _sha256 and _sha512 merged into _sha2 in 3.12.
677676
// _xxinterpchannels added in 3.12.
677+
// audioop removed in 3.13
678+
// _crypt removed in 3.13
679+
// spwd removed in Python 3.13
678680

679681
// We didn't build ctypes_test until 3.9.
680682
// We didn't build some test extensions until 3.9.
681683

682684
const GLOBAL_EXTENSIONS_PYTHON_3_8: &[&str] = &["_sha256", "_sha512", "parser"];
683685

684686
const GLOBAL_EXTENSIONS_PYTHON_3_9: &[&str] = &[
687+
"audioop",
685688
"_peg_parser",
686689
"_sha256",
687690
"_sha512",
@@ -692,6 +695,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_9: &[&str] = &[
692695
];
693696

694697
const GLOBAL_EXTENSIONS_PYTHON_3_10: &[&str] = &[
698+
"audioop",
695699
"_sha256",
696700
"_sha512",
697701
"_uuid",
@@ -700,6 +704,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_10: &[&str] = &[
700704
];
701705

702706
const GLOBAL_EXTENSIONS_PYTHON_3_11: &[&str] = &[
707+
"audioop",
703708
"_sha256",
704709
"_sha512",
705710
"_tokenize",
@@ -710,6 +715,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_11: &[&str] = &[
710715
];
711716

712717
const GLOBAL_EXTENSIONS_PYTHON_3_12: &[&str] = &[
718+
"audioop",
713719
"_sha2",
714720
"_tokenize",
715721
"_typing",
@@ -722,14 +728,19 @@ const GLOBAL_EXTENSIONS_PYTHON_3_13: &[&str] = &[
722728
"_sha2",
723729
"_tokenize",
724730
"_typing",
725-
"_xxinterpchannels",
726-
"_xxsubinterpreters",
731+
"_interpchannels",
732+
"_subinterpreters",
727733
"_zoneinfo",
734+
"_interpreters",
735+
"_suggestions",
736+
"_sysconfig",
737+
"_testexternalinspection",
728738
];
729739

730740
const GLOBAL_EXTENSIONS_MACOS: &[&str] = &["_scproxy"];
731741

732-
const GLOBAL_EXTENSIONS_POSIX: &[&str] = &[
742+
// TODO(zanieb): Consider replicating this explicitly for each Python version.
743+
const GLOBAL_EXTENSIONS_POSIX_PRE_313: &[&str] = &[
733744
"_crypt",
734745
"_ctypes_test",
735746
"_curses",
@@ -748,7 +759,26 @@ const GLOBAL_EXTENSIONS_POSIX: &[&str] = &[
748759
"termios",
749760
];
750761

751-
const GLOBAL_EXTENSIONS_LINUX: &[&str] = &["spwd"];
762+
const GLOBAL_EXTENSIONS_POSIX_POST_313: &[&str] = &[
763+
"_ctypes_test",
764+
"_curses",
765+
"_curses_panel",
766+
"_dbm",
767+
"_posixshmem",
768+
"_posixsubprocess",
769+
"_testinternalcapi",
770+
"fcntl",
771+
"grp",
772+
"posix",
773+
"pwd",
774+
"readline",
775+
"resource",
776+
"syslog",
777+
"termios",
778+
];
779+
780+
const GLOBAL_EXTENSIONS_LINUX_PRE_313: &[&str] = &["spwd"];
781+
const GLOBAL_EXTENSIONS_LINUX_POST_313: &[&str] = &[];
752782

753783
const GLOBAL_EXTENSIONS_WINDOWS: &[&str] = &[
754784
"_msi",
@@ -1004,20 +1034,18 @@ fn validate_elf<'data, Elf: FileHeader<Endian = Endianness>>(
10041034
if let Some(version) = version_version {
10051035
let parts: Vec<&str> = version.splitn(2, '_').collect();
10061036

1007-
if parts.len() == 2 {
1008-
if parts[0] == "GLIBC" {
1009-
let v = version_compare::Version::from(parts[1])
1010-
.expect("unable to parse version");
1037+
if parts.len() == 2 && parts[0] == "GLIBC" {
1038+
let v = version_compare::Version::from(parts[1])
1039+
.expect("unable to parse version");
10111040

1012-
if &v > wanted_glibc_max_version {
1013-
context.errors.push(format!(
1014-
"{} references too new glibc symbol {:?} ({} > {})",
1015-
path.display(),
1016-
name,
1017-
v,
1018-
wanted_glibc_max_version,
1019-
));
1020-
}
1041+
if &v > wanted_glibc_max_version {
1042+
context.errors.push(format!(
1043+
"{} references too new glibc symbol {:?} ({} > {})",
1044+
path.display(),
1045+
name,
1046+
v,
1047+
wanted_glibc_max_version,
1048+
));
10211049
}
10221050
}
10231051
}
@@ -1045,12 +1073,8 @@ fn validate_elf<'data, Elf: FileHeader<Endian = Endianness>>(
10451073
if let Some(filename) = path.file_name() {
10461074
let filename = filename.to_string_lossy();
10471075

1048-
if filename.starts_with("libpython") && filename.ends_with(".so.1.0") {
1049-
if matches!(symbol.st_bind(), STB_GLOBAL | STB_WEAK)
1050-
&& symbol.st_visibility() == STV_DEFAULT
1051-
{
1052-
context.libpython_exported_symbols.insert(name.to_string());
1053-
}
1076+
if filename.starts_with("libpython") && filename.ends_with(".so.1.0") && matches!(symbol.st_bind(), STB_GLOBAL | STB_WEAK) && symbol.st_visibility() == STV_DEFAULT {
1077+
context.libpython_exported_symbols.insert(name.to_string());
10541078
}
10551079
}
10561080
}
@@ -1144,7 +1168,7 @@ fn validate_macho<Mach: MachHeader<Endian = Endianness>>(
11441168
target_version = Some(parse_version_nibbles(v.version.get(endian)));
11451169
}
11461170
LoadCommandVariant::Dylib(command) => {
1147-
let raw_string = load_command.string(endian, command.dylib.name.clone())?;
1171+
let raw_string = load_command.string(endian, command.dylib.name)?;
11481172
let lib = String::from_utf8(raw_string.to_vec())?;
11491173

11501174
dylib_names.push(lib.clone());
@@ -1355,9 +1379,9 @@ fn validate_possible_object_file(
13551379
json,
13561380
triple,
13571381
python_major_minor,
1358-
path.as_ref(),
1382+
path,
13591383
header,
1360-
&data,
1384+
data,
13611385
)?;
13621386
}
13631387
FileKind::Elf64 => {
@@ -1368,9 +1392,9 @@ fn validate_possible_object_file(
13681392
json,
13691393
triple,
13701394
python_major_minor,
1371-
path.as_ref(),
1395+
path,
13721396
header,
1373-
&data,
1397+
data,
13741398
)?;
13751399
}
13761400
FileKind::MachO32 => {
@@ -1386,9 +1410,9 @@ fn validate_possible_object_file(
13861410
json.apple_sdk_version
13871411
.as_ref()
13881412
.expect("apple_sdk_version should be set"),
1389-
path.as_ref(),
1413+
path,
13901414
header,
1391-
&data,
1415+
data,
13921416
)?;
13931417
}
13941418
FileKind::MachO64 => {
@@ -1404,9 +1428,9 @@ fn validate_possible_object_file(
14041428
json.apple_sdk_version
14051429
.as_ref()
14061430
.expect("apple_sdk_version should be set"),
1407-
path.as_ref(),
1431+
path,
14081432
header,
1409-
&data,
1433+
data,
14101434
)?;
14111435
}
14121436
FileKind::MachOFat32 | FileKind::MachOFat64 => {
@@ -1418,11 +1442,11 @@ fn validate_possible_object_file(
14181442
}
14191443
FileKind::Pe32 => {
14201444
let file = PeFile32::parse(data)?;
1421-
validate_pe(&mut context, path.as_ref(), &file)?;
1445+
validate_pe(&mut context, path, &file)?;
14221446
}
14231447
FileKind::Pe64 => {
14241448
let file = PeFile64::parse(data)?;
1425-
validate_pe(&mut context, path.as_ref(), &file)?;
1449+
validate_pe(&mut context, path, &file)?;
14261450
}
14271451
_ => {}
14281452
}
@@ -1450,7 +1474,7 @@ fn validate_extension_modules(
14501474
return Ok(errors);
14511475
}
14521476

1453-
let mut wanted = BTreeSet::from_iter(GLOBAL_EXTENSIONS.iter().map(|x| *x));
1477+
let mut wanted = BTreeSet::from_iter(GLOBAL_EXTENSIONS.iter().copied());
14541478

14551479
match python_major_minor {
14561480
"3.8" => {
@@ -1477,7 +1501,17 @@ fn validate_extension_modules(
14771501
}
14781502

14791503
if is_macos {
1480-
wanted.extend(GLOBAL_EXTENSIONS_POSIX);
1504+
match python_major_minor {
1505+
"3.8" | "3.9" | "3.10" | "3.11" | "3.12" => {
1506+
wanted.extend(GLOBAL_EXTENSIONS_POSIX_PRE_313);
1507+
}
1508+
"3.13" => {
1509+
wanted.extend(GLOBAL_EXTENSIONS_POSIX_POST_313);
1510+
}
1511+
_ => {
1512+
panic!("unhandled Python version: {}", python_major_minor);
1513+
}
1514+
}
14811515
wanted.extend(GLOBAL_EXTENSIONS_MACOS);
14821516
}
14831517

@@ -1492,15 +1526,42 @@ fn validate_extension_modules(
14921526
}
14931527

14941528
if is_linux {
1495-
wanted.extend(GLOBAL_EXTENSIONS_POSIX);
1496-
wanted.extend(GLOBAL_EXTENSIONS_LINUX);
1529+
match python_major_minor {
1530+
"3.8" | "3.9" | "3.10" | "3.11" | "3.12" => {
1531+
wanted.extend(GLOBAL_EXTENSIONS_POSIX_PRE_313);
1532+
}
1533+
"3.13" => {
1534+
wanted.extend(GLOBAL_EXTENSIONS_POSIX_POST_313);
1535+
}
1536+
_ => {
1537+
panic!("unhandled Python version: {}", python_major_minor);
1538+
}
1539+
}
1540+
match python_major_minor {
1541+
"3.8" | "3.9" | "3.10" | "3.11" | "3.12" => {
1542+
wanted.extend(GLOBAL_EXTENSIONS_LINUX_PRE_313);
1543+
}
1544+
"3.13" => {
1545+
wanted.extend(GLOBAL_EXTENSIONS_LINUX_POST_313);
1546+
}
1547+
_ => {
1548+
panic!("unhandled Python version: {}", python_major_minor);
1549+
}
1550+
}
14971551

1498-
if !is_linux_musl {
1552+
// Removed in Python 3.13
1553+
if !is_linux_musl && matches!(python_major_minor, "3.8" | "3.9" | "3.10" | "3.11" | "3.12")
1554+
{
14991555
wanted.insert("ossaudiodev");
15001556
}
15011557
}
15021558

1503-
if (is_linux || is_macos) && matches!(python_major_minor, "3.9" | "3.10" | "3.11" | "3.12" | "3.13") {
1559+
if (is_linux || is_macos)
1560+
&& matches!(
1561+
python_major_minor,
1562+
"3.9" | "3.10" | "3.11" | "3.12" | "3.13"
1563+
)
1564+
{
15041565
wanted.extend([
15051566
"_testbuffer",
15061567
"_testimportmultiple",
@@ -1604,8 +1665,7 @@ fn validate_json(json: &PythonJsonMain, triple: &str, is_debug: bool) -> Result<
16041665
triple,
16051666
json.crt_features.contains(&"static".to_string()),
16061667
&have_extensions,
1607-
)?
1608-
.into_iter(),
1668+
)?,
16091669
);
16101670

16111671
Ok(errors)
@@ -1659,7 +1719,7 @@ fn validate_distribution(
16591719

16601720
let is_static = triple.contains("unknown-linux-musl");
16611721

1662-
let mut tf = crate::open_distribution_archive(&dist_path)?;
1722+
let mut tf = crate::open_distribution_archive(dist_path)?;
16631723

16641724
// First entry in archive should be python/PYTHON.json.
16651725
let mut entries = tf.entries()?;
@@ -1725,7 +1785,7 @@ fn validate_distribution(
17251785
context.merge(validate_possible_object_file(
17261786
json.as_ref().unwrap(),
17271787
python_major_minor,
1728-
&triple,
1788+
triple,
17291789
&path,
17301790
&data,
17311791
)?);
@@ -1750,9 +1810,9 @@ fn validate_distribution(
17501810
context.merge(validate_possible_object_file(
17511811
json.as_ref().unwrap(),
17521812
python_major_minor,
1753-
&triple,
1813+
triple,
17541814
&member_path,
1755-
&member_data,
1815+
member_data,
17561816
)?);
17571817
}
17581818
}
@@ -1938,11 +1998,7 @@ fn validate_distribution(
19381998
} else if triple.contains("-windows-") {
19391999
false
19402000
// Presence of a shared library extension implies no export.
1941-
} else if ext.shared_lib.is_some() {
1942-
false
1943-
} else {
1944-
true
1945-
};
2001+
} else { ext.shared_lib.is_none() };
19462002

19472003
if exported != wanted {
19482004
context.errors.push(format!(
@@ -2020,7 +2076,7 @@ fn verify_distribution_behavior(dist_path: &Path) -> Result<Vec<String>> {
20202076
tf.unpack(temp_dir.path())?;
20212077

20222078
let python_json_path = temp_dir.path().join("python").join("PYTHON.json");
2023-
let python_json_data = std::fs::read(&python_json_path)?;
2079+
let python_json_data = std::fs::read(python_json_path)?;
20242080
let python_json = parse_python_json(&python_json_data)?;
20252081

20262082
let python_exe = temp_dir.path().join("python").join(python_json.python_exe);
@@ -2029,7 +2085,7 @@ fn verify_distribution_behavior(dist_path: &Path) -> Result<Vec<String>> {
20292085
std::fs::write(&test_file, PYTHON_VERIFICATIONS.as_bytes())?;
20302086

20312087
eprintln!(" running interpreter tests (output should follow)");
2032-
let output = duct::cmd(&python_exe, &[test_file.display().to_string()])
2088+
let output = duct::cmd(python_exe, [test_file.display().to_string()])
20332089
.stdout_to_stderr()
20342090
.unchecked()
20352091
.env("TARGET_TRIPLE", &python_json.target_triple)

0 commit comments

Comments
 (0)