Skip to content

Commit f5719e2

Browse files
Fix sys.implementation
`sys.version_info` and `sys.implementation` are two different versioning schemes. `version_info` refers to the target Python version while `implementation` refers to the implementation version. For RustPython, `version_info` should be 3.14 because it currently targets Python 3.14. This was correct and remains unchanged. `implementation`, however, should be set to RustPython's version. I updated the code to correctly get RustPython's version from the environment. I also ensured values are hard coded at build time which reduces the overall code that needs to be run at runtime as well as removes some unneeded allocations. Closes: RustPython#7770
1 parent e10a27b commit f5719e2

3 files changed

Lines changed: 88 additions & 52 deletions

File tree

‎crates/vm/build.rs‎

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44
)]
55

66
use itertools::Itertools;
7-
use std::{env, io::prelude::*, path::PathBuf, process::Command};
7+
use std::{
8+
env,
9+
io::{self, prelude::*},
10+
path::PathBuf,
11+
process::Command,
12+
time::{SystemTime, UNIX_EPOCH},
13+
};
814

915
fn main() {
1016
let frozen_libs = if cfg!(feature = "freeze-stdlib") {
@@ -27,6 +33,11 @@ fn main() {
2733
println!("cargo:rustc-env=RUSTPYTHON_GIT_BRANCH={}", git_branch());
2834
println!("cargo:rustc-env=RUSTC_VERSION={}", rustc_version());
2935

36+
let release_level = option_env!("RUSTPYTHON_RELEASE_LEVEL").unwrap_or("alpha");
37+
println!("cargo:rustc-env=RUSTPYTHON_RELEASE_LEVEL={release_level}");
38+
let release_serial = option_env!("RUSTPYTHON_RELEASE_SERIAL").unwrap_or("0");
39+
println!("cargo:rustc-env=RUSTPYTHON_RELEASE_SERIAL={release_serial}");
40+
3041
println!(
3142
"cargo:rustc-env=RUSTPYTHON_TARGET_TRIPLE={}",
3243
env::var("TARGET").unwrap()
@@ -44,36 +55,50 @@ fn main() {
4455
}
4556

4657
fn git_hash() -> String {
47-
git(&["rev-parse", "--short", "HEAD"])
58+
git(&["rev-parse", "--short", "HEAD"]).unwrap_or_else(|_| "0000000".into())
4859
}
4960

5061
fn git_timestamp() -> String {
51-
git(&["log", "-1", "--format=%ct"])
62+
git(&["log", "-1", "--format=%ct"]).unwrap_or_else(|_| {
63+
SystemTime::now()
64+
.duration_since(UNIX_EPOCH)
65+
.unwrap_or_default()
66+
.as_secs()
67+
.to_string()
68+
})
5269
}
5370

5471
fn git_tag() -> String {
5572
git(&["describe", "--all", "--always", "--dirty"])
73+
.unwrap_or_else(|_| "heads/unknown-branch".into())
5674
}
5775

5876
fn git_branch() -> String {
59-
git(&["name-rev", "--name-only", "HEAD"])
77+
git(&["name-rev", "--name-only", "HEAD"]).unwrap_or_else(|_| "unknown-branch".into())
6078
}
6179

62-
fn git(args: &[&str]) -> String {
80+
fn git(args: &[&str]) -> io::Result<String> {
6381
command("git", args)
6482
}
6583

6684
fn rustc_version() -> String {
6785
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
68-
command(rustc, &["-V"])
86+
command(rustc, &["-V"]).unwrap_or_else(|_| "rustc [unknown]".into())
6987
}
7088

71-
fn command(cmd: impl AsRef<std::ffi::OsStr>, args: &[&str]) -> String {
72-
match Command::new(cmd).args(args).output() {
73-
Ok(output) => match String::from_utf8(output.stdout) {
74-
Ok(s) => s,
75-
Err(err) => format!("(output error: {err})"),
76-
},
77-
Err(err) => format!("(command error: {err})"),
78-
}
89+
fn command(cmd: impl AsRef<std::ffi::OsStr>, args: &[&str]) -> io::Result<String> {
90+
Command::new(&cmd).args(args).output().and_then(|output| {
91+
// TODO: Switch to exit_ok()? when stable.
92+
if !output.status.success() {
93+
Err(io::Error::other(format!(
94+
"command '{}' exited with status {}",
95+
cmd.as_ref().to_string_lossy(),
96+
output.status
97+
)))?
98+
}
99+
100+
str::from_utf8(&output.stdout)
101+
.map(|s| s.trim().to_owned())
102+
.map_err(io::Error::other)
103+
})
79104
}

‎crates/vm/src/stdlib/sys.rs‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -660,22 +660,22 @@ pub mod sys {
660660
vm.new_tuple((
661661
ascii!("RustPython"),
662662
version::get_git_identifier(),
663-
version::get_git_revision(),
663+
version::GIT_REVISION,
664664
))
665665
}
666666

667667
#[pyattr]
668668
fn implementation(vm: &VirtualMachine) -> PyRef<PyNamespace> {
669669
const NAME: &str = "rustpython";
670670

671-
let cache_tag = format!("{NAME}-{}{}", version::MAJOR, version::MINOR);
671+
let cache_tag = format!("{NAME}-{}.{}", version::MAJOR_IMPL, version::MINOR_IMPL);
672672
let ctx = &vm.ctx;
673673
py_namespace!(vm, {
674674
"name" => ctx.new_str(NAME),
675675
"cache_tag" => ctx.new_str(cache_tag),
676676
"_multiarch" => ctx.new_str(multiarch()),
677-
"version" => version_info(vm),
678-
"hexversion" => ctx.new_int(version::VERSION_HEX),
677+
"version" => PyVersionInfo::from_data(VersionInfoData::IMPLEMENTATION, vm),
678+
"hexversion" => ctx.new_int(version::VERSION_HEX_IMPL),
679679
"supports_isolated_interpreters" => ctx.new_bool(false),
680680
})
681681
}
@@ -1758,6 +1758,14 @@ pub mod sys {
17581758
releaselevel: version::RELEASELEVEL,
17591759
serial: version::SERIAL,
17601760
};
1761+
1762+
pub const IMPLEMENTATION: Self = Self {
1763+
major: version::MAJOR_IMPL,
1764+
minor: version::MINOR_IMPL,
1765+
micro: version::MICRO_IMPL,
1766+
releaselevel: version::RELEASELEVEL_IMPL,
1767+
serial: version::SERIAL_IMPL,
1768+
};
17611769
}
17621770

17631771
#[pystruct_sequence(name = "version_info", data = "VersionInfoData", no_attr)]

‎crates/vm/src/version.rs‎

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,37 @@ pub const MICRO: usize = 0;
1111
pub const RELEASELEVEL: &str = "alpha";
1212
pub const RELEASELEVEL_N: usize = 0xA;
1313
pub const SERIAL: usize = 0;
14-
1514
pub const VERSION_HEX: usize =
1615
(MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL;
1716

17+
pub const GIT_REVISION: &str = env!("RUSTPYTHON_GIT_HASH");
18+
const GIT_TAG: &str = env!("RUSTPYTHON_GIT_TAG");
19+
const GIT_BRANCH: &str = env!("RUSTPYTHON_GIT_BRANCH");
20+
21+
// RustPython version
22+
pub const MAJOR_IMPL: usize = match usize::from_str_radix(env!("CARGO_PKG_VERSION_MAJOR"), 10) {
23+
Ok(v) => v,
24+
Err(_) => panic!("Compile with Cargo to get 'CARGO_PKG_VERSION_MAJOR'"),
25+
};
26+
pub const MINOR_IMPL: usize = match usize::from_str_radix(env!("CARGO_PKG_VERSION_MINOR"), 10) {
27+
Ok(v) => v,
28+
Err(_) => panic!("Compile with Cargo to get 'CARGO_PKG_VERSION_MINOR'"),
29+
};
30+
pub const MICRO_IMPL: usize = match usize::from_str_radix(env!("CARGO_PKG_VERSION_PATCH"), 10) {
31+
Ok(v) => v,
32+
Err(_) => panic!("Compile with Cargo to get 'CARGO_PKG_VERSION_PATCH'"),
33+
};
34+
pub const RELEASELEVEL_IMPL: &str = env!("RUSTPYTHON_RELEASE_LEVEL");
35+
pub const SERIAL_IMPL: usize = match usize::from_str_radix(env!("RUSTPYTHON_RELEASE_SERIAL"), 10) {
36+
Ok(v) => v,
37+
Err(_) => panic!("Compile with Cargo to get 'RUSTPYTHON_RELEASE_SERIAL'"),
38+
};
39+
pub const VERSION_HEX_IMPL: usize = (MAJOR_IMPL << 24)
40+
| (MINOR_IMPL << 16)
41+
| (MICRO_IMPL << 8)
42+
| (RELEASELEVEL_N << 4)
43+
| SERIAL_IMPL;
44+
1845
#[must_use]
1946
pub fn get_version() -> String {
2047
// Windows: include MSC v. for compatibility with ctypes.util.find_library
@@ -57,59 +84,35 @@ const COMPILER: &str = env!("RUSTC_VERSION");
5784
#[must_use]
5885
pub fn get_build_info() -> String {
5986
// See: https://reproducible-builds.org/docs/timestamps/
60-
let git_revision = get_git_revision();
61-
let separator = if git_revision.is_empty() { "" } else { ":" };
62-
87+
let separator = if GIT_REVISION.is_empty() { "" } else { ":" };
6388
let git_identifier = get_git_identifier();
6489

6590
format!(
6691
"{id}{sep}{revision}, {date:.20}, {time:.9}",
6792
id = if git_identifier.is_empty() {
68-
"default".to_owned()
93+
"default"
6994
} else {
7095
git_identifier
7196
},
7297
sep = separator,
73-
revision = git_revision,
98+
revision = GIT_REVISION,
7499
date = get_git_date(),
75100
time = get_git_time(),
76101
)
77102
}
78103

79104
#[must_use]
80-
pub fn get_git_revision() -> String {
81-
option_env!("RUSTPYTHON_GIT_HASH").unwrap_or("").to_owned()
82-
}
83-
84-
#[must_use]
85-
pub fn get_git_tag() -> String {
86-
option_env!("RUSTPYTHON_GIT_TAG").unwrap_or("").to_owned()
87-
}
88-
89-
#[must_use]
90-
pub fn get_git_branch() -> String {
91-
option_env!("RUSTPYTHON_GIT_BRANCH")
92-
.unwrap_or("")
93-
.to_owned()
94-
}
95-
96-
#[must_use]
97-
pub fn get_git_identifier() -> String {
98-
let git_tag = get_git_tag();
99-
let git_branch = get_git_branch();
100-
101-
if git_tag.is_empty() || git_tag == "undefined" {
102-
git_branch
105+
pub const fn get_git_identifier() -> &'static str {
106+
if GIT_TAG.is_empty() || GIT_TAG.eq_ignore_ascii_case("undefined") {
107+
GIT_BRANCH
103108
} else {
104-
git_tag
109+
GIT_TAG
105110
}
106111
}
107112

108113
fn get_git_timestamp_datetime() -> DateTime<Local> {
109-
let timestamp = option_env!("RUSTPYTHON_GIT_TIMESTAMP")
110-
.unwrap_or("")
111-
.to_owned();
112-
let timestamp = timestamp.parse::<u64>().unwrap_or(0);
114+
let timestamp = option_env!("RUSTPYTHON_GIT_TIMESTAMP").unwrap_or_default();
115+
let timestamp = timestamp.parse::<u64>().unwrap_or_default();
113116

114117
let datetime = UNIX_EPOCH + Duration::from_secs(timestamp);
115118

0 commit comments

Comments
 (0)