refactor: share PyTime conversions with time.sleep (#9362)

Move the existing conversion helper into the production time module and reuse it from sleep, preserving conversion bodies and internal C-API argument binding.

Assisted-by: OpenAI Codex:model version unavailable
This commit is contained in:
youknowdot authored and GitHub committed 2026-10-26 10:07:47 +09:00
1 parent 0dca682e45
commit 1170a337cc
3 files changed
+16 -52

No files matched your search

+1 -3
View File
@@ -1,7 +1,5 @@
pub(crate) use _testinternalcapi::module_def;
mod pytime;
use core::sync::atomic::{AtomicUsize, Ordering};
static RARE_SET_CLASS: AtomicUsize = AtomicUsize::new(0);
@@ -28,7 +26,6 @@ pub(crate) fn note_func_modification() {
#[pymodule]
mod _testinternalcapi {
use super::pytime::Round;
use super::*;
use crate::{
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
@@ -43,6 +40,7 @@ mod _testinternalcapi {
function::{FuncArgs, OptionalArg, PyComparisonValue},
object::{Traverse, TraverseFn},
protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
stdlib::time::pytime::{self, Round},
types::{
AsMapping, AsSequence, Comparable, IterNext, Iterable, PyComparisonOp, PyTypeFlags,
SelfIter,
+5 -39
View File
@@ -5,6 +5,7 @@
// https://docs.python.org/3/library/time.html
pub use decl::time;
pub(crate) mod pytime;
pub(crate) use decl::module_def;
pub(crate) use decl::perf_counter_ns as profiler_time;
@@ -19,7 +20,7 @@ mod decl {
use crate::convert::{ToPyException, ToPyObject};
use crate::{
AsObject, Py, PyObjectRef, PyResult, VirtualMachine,
builtins::{PyFloat, PyStr, PyStrRef, PyTypeRef},
builtins::{PyStr, PyStrRef, PyTypeRef},
class::PyClassDef,
common::wtf8::Wtf8Buf,
function::{Either, FuncArgs, OptionalArg, OptionalOption},
@@ -33,7 +34,6 @@ mod decl {
use core::time::Duration;
#[cfg(not(any(unix, windows)))]
use jiff::{Timestamp, Zoned, civil::DateTime, tz::TimeZone};
use num_traits::ToPrimitive;
#[cfg(target_os = "wasi")]
use rustpython_host_env::time::ClockId;
#[cfg(any(unix, windows))]
@@ -128,43 +128,9 @@ mod decl {
fn sleep(object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
vm.audit("time.sleep", || (object.clone(),))?;
let overflow = || vm.new_overflow_error("timestamp out of range for C PyTime_t");
let nanoseconds = if object.number().is_index() {
let seconds = object.try_index(vm).map_err(|e| {
if e.fast_isinstance(vm.ctx.exceptions.overflow_error) {
overflow()
} else {
e
}
})?;
seconds
.as_bigint()
.to_i64()
.and_then(|seconds| seconds.checked_mul(SEC_TO_NS))
.ok_or_else(overflow)?
} else {
// PyFloat_AsDouble reads float subclasses without calling __float__.
let seconds = match object.downcast_ref::<PyFloat>() {
Some(value) => value.to_f64(),
None => object.try_float(vm)?.to_f64(),
};
if seconds.is_nan() {
return Err(vm.new_value_error("Invalid value NaN (not a number)"));
}
// _PyTime_ROUND_TIMEOUT rounds away from zero.
let nanoseconds = seconds * SEC_TO_NS as f64;
let nanoseconds = if nanoseconds >= 0.0 {
nanoseconds.ceil()
} else {
nanoseconds.floor()
};
let minimum = i64::MIN as f64;
// The signed maximum rounds up to 2**63 as a double.
if !(minimum..-minimum).contains(&nanoseconds) {
return Err(overflow());
}
nanoseconds as i64
};
// _PyTime_ROUND_TIMEOUT rounds away from zero.
let nanoseconds =
super::pytime::from_seconds_object(&object, super::pytime::Round::Up, vm)?;
if nanoseconds < 0 {
return Err(vm.new_value_error("sleep length must be non-negative"));
}
@@ -1,4 +1,4 @@
//! Numeric conversions used by the internal PyTime test helpers.
//! Signed nanosecond timestamps and the rounding used by Python's time APIs.
#![cfg_attr(target_env = "musl", allow(deprecated))]
@@ -7,9 +7,9 @@ use num_traits::ToPrimitive;
use rustpython_host_env::time::SEC_TO_NS;
#[cfg(any(unix, windows))]
pub(super) use rustpython_host_env::time::TimeT;
pub(crate) use rustpython_host_env::time::TimeT;
#[cfg(not(any(unix, windows)))]
pub(super) type TimeT = i64;
pub(crate) type TimeT = i64;
const TIME_T_MIN: i64 = TimeT::MIN as _;
const TIME_T_MAX: i64 = TimeT::MAX as _;
@@ -17,7 +17,7 @@ const PYTIME_OVERFLOW: &str = "timestamp out of range for C PyTime_t";
const TIME_T_OVERFLOW: &str = "timestamp out of range for platform time_t";
#[derive(Clone, Copy)]
pub(super) enum Round {
pub(crate) enum Round {
Floor,
Ceiling,
HalfEven,
@@ -25,7 +25,7 @@ pub(super) enum Round {
}
impl Round {
pub(super) fn from_int(value: i32, vm: &VirtualMachine) -> PyResult<Self> {
pub(crate) fn from_int(value: i32, vm: &VirtualMachine) -> PyResult<Self> {
match value {
0 => Ok(Self::Floor),
1 => Ok(Self::Ceiling),
@@ -45,7 +45,7 @@ impl Round {
}
}
pub(super) fn divide(self, value: i64, divisor: i64) -> i64 {
pub(crate) fn divide(self, value: i64, divisor: i64) -> i64 {
debug_assert!(divisor > 1);
let quotient = value / divisor;
let remainder = value % divisor;
@@ -65,7 +65,7 @@ impl Round {
}
}
pub(super) fn from_seconds(seconds: i32) -> i64 {
pub(crate) fn from_seconds(seconds: i32) -> i64 {
i64::from(seconds) * SEC_TO_NS
}
@@ -95,7 +95,7 @@ fn float_seconds(object: &PyObject, vm: &VirtualMachine) -> PyResult<f64> {
Ok(seconds)
}
pub(super) fn from_seconds_object(
pub(crate) fn from_seconds_object(
object: &PyObject,
round: Round,
vm: &VirtualMachine,
@@ -132,7 +132,7 @@ fn float_to_time_t(seconds: f64, vm: &VirtualMachine) -> PyResult<i64> {
Ok(seconds as i64)
}
pub(super) fn object_to_time_t(
pub(crate) fn object_to_time_t(
object: &PyObject,
round: Round,
vm: &VirtualMachine,
@@ -144,7 +144,7 @@ pub(super) fn object_to_time_t(
}
}
pub(super) fn object_to_denominator(
pub(crate) fn object_to_denominator(
object: &PyObject,
denominator: i64,
round: Round,