Skip to content

Commit feff65d

Browse files
youknowdotcodex
andauthored
Fix datetime constructor and method signature metadata (#9532)
* Expose accurate datetime constructor and method signatures Address the 13 datetime inspect.signature discrepancies in the actual whats_left report against CPython 3.15. Keep constructor pickle handling before normal typed binding, preserving argument destruction and subclass wrapping. Supply truthful defaults and positional parameter names. Independent source review and normal hooks passed; local compilation and runtime verification remain unavailable. Assisted-by: OpenAI Codex:model version not exposed * Report signature mismatches during existing CI scan Use the reviewed one-line diagnostic option from #9530 so this datetime follow-up can verify the actual 13 reported differences on its own CI head. This only enables printing comparison results already computed by the existing whats_left step; imports, builds, scans, and test behavior are unchanged. Assisted-by: OpenAI Codex:model version not exposed --------- Co-authored-by: Codex <codex@openai.com>
1 parent fc10522 commit feff65d

1 file changed

Lines changed: 66 additions & 41 deletions

File tree

‎crates/stdlib/src/_datetime.rs‎

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -564,19 +564,19 @@ mod _datetime {
564564

565565
#[derive(FromArgs)]
566566
pub(super) struct DeltaArgs {
567-
#[pyarg(any, optional)]
567+
#[pyarg(any, optional, py_default = "0")]
568568
days: OptionalArg<PyObjectRef>,
569-
#[pyarg(any, optional)]
569+
#[pyarg(any, optional, py_default = "0")]
570570
seconds: OptionalArg<PyObjectRef>,
571-
#[pyarg(any, optional)]
571+
#[pyarg(any, optional, py_default = "0")]
572572
microseconds: OptionalArg<PyObjectRef>,
573-
#[pyarg(any, optional)]
573+
#[pyarg(any, optional, py_default = "0")]
574574
milliseconds: OptionalArg<PyObjectRef>,
575-
#[pyarg(any, optional)]
575+
#[pyarg(any, optional, py_default = "0")]
576576
minutes: OptionalArg<PyObjectRef>,
577-
#[pyarg(any, optional)]
577+
#[pyarg(any, optional, py_default = "0")]
578578
hours: OptionalArg<PyObjectRef>,
579-
#[pyarg(any, optional)]
579+
#[pyarg(any, optional, py_default = "0")]
580580
weeks: OptionalArg<PyObjectRef>,
581581
}
582582

@@ -1724,7 +1724,7 @@ mod _datetime {
17241724
}
17251725

17261726
#[derive(FromArgs)]
1727-
struct DateArgs {
1727+
pub(super) struct DateArgs {
17281728
#[pyarg(any)]
17291729
year: i32,
17301730
#[pyarg(any)]
@@ -1734,15 +1734,24 @@ mod _datetime {
17341734
}
17351735

17361736
impl Constructor for PyDate {
1737-
type Args = FuncArgs;
1737+
type Args = DateArgs;
17381738

1739-
fn py_new(_cls: &Py<PyType>, args: FuncArgs, vm: &VirtualMachine) -> PyResult<Self> {
1739+
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
17401740
if args.args.len() == 1
17411741
&& let Some(state) = pickle_state(&args.args[0], 4, 2, month_is_sane, "date", vm)?
17421742
{
1743-
return Ok(Self::from_state(&state));
1743+
let payload = Self::from_state(&state);
1744+
drop(args);
1745+
return payload.into_ref_with_type(vm, cls).map(Into::into);
17441746
}
1745-
let DateArgs { year, month, day } = args.bind(vm)?;
1747+
let args = args.bind(vm)?;
1748+
Self::py_new(&cls, args, vm)?
1749+
.into_ref_with_type(vm, cls)
1750+
.map(Into::into)
1751+
}
1752+
1753+
fn py_new(_cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
1754+
let DateArgs { year, month, day } = args;
17461755
check_date_args(year, month, day, vm)?;
17471756
Ok(Self::new(year, month, day))
17481757
}
@@ -1969,8 +1978,8 @@ mod _datetime {
19691978
}
19701979

19711980
#[pyclassmethod]
1972-
fn fromisoformat(cls: PyTypeRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1973-
let dtstr = object;
1981+
fn fromisoformat(cls: PyTypeRef, string: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1982+
let dtstr = string;
19741983
let Some(s) = dtstr.downcast_ref::<PyStr>() else {
19751984
return Err(vm.new_type_error("fromisoformat: argument must be str"));
19761985
};
@@ -2037,8 +2046,8 @@ mod _datetime {
20372046
}
20382047

20392048
#[pymethod]
2040-
fn __format__(zelf: PyObjectRef, spec: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2041-
object_format(&zelf, spec, vm)
2049+
fn __format__(zelf: PyObjectRef, format: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2050+
object_format(&zelf, format, vm)
20422051
}
20432052

20442053
#[pymethod]
@@ -2782,7 +2791,7 @@ mod _datetime {
27822791
}
27832792

27842793
#[derive(FromArgs)]
2785-
struct TimeArgs {
2794+
pub(super) struct TimeArgs {
27862795
#[pyarg(any, default = 0)]
27872796
hour: i32,
27882797
#[pyarg(any, default = 0)]
@@ -2791,7 +2800,7 @@ mod _datetime {
27912800
second: i32,
27922801
#[pyarg(any, default = 0)]
27932802
microsecond: i32,
2794-
#[pyarg(any, optional)]
2803+
#[pyarg(any, optional, py_default = "None")]
27952804
tzinfo: OptionalArg<PyObjectRef>,
27962805
#[pyarg(named, default = 0)]
27972806
fold: i32,
@@ -2813,26 +2822,34 @@ mod _datetime {
28132822
}
28142823

28152824
impl Constructor for PyTime {
2816-
type Args = FuncArgs;
2825+
type Args = TimeArgs;
28172826

2818-
fn py_new(_cls: &Py<PyType>, args: FuncArgs, vm: &VirtualMachine) -> PyResult<Self> {
2827+
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
28192828
if (1..=2).contains(&args.args.len())
28202829
&& let Some(state) =
28212830
pickle_state(&args.args[0], 6, 0, |hour| (hour & 0x7f) < 24, "time", vm)?
28222831
{
28232832
let tzinfo = pickle_tzinfo(args.args.get(1), vm)?;
28242833
let fold = (state[0] & 0x80) != 0;
28252834
let us = i32::from(state[3]) << 16 | i32::from(state[4]) << 8 | i32::from(state[5]);
2826-
return Ok(Self::new(
2835+
let payload = Self::new(
28272836
i32::from(state[0] & 0x7f),
28282837
i32::from(state[1]),
28292838
i32::from(state[2]),
28302839
us,
28312840
tzinfo,
28322841
i32::from(fold),
2833-
));
2842+
);
2843+
drop(args);
2844+
return payload.into_ref_with_type(vm, cls).map(Into::into);
28342845
}
2835-
let a: TimeArgs = args.bind(vm)?;
2846+
let args = args.bind(vm)?;
2847+
Self::py_new(&cls, args, vm)?
2848+
.into_ref_with_type(vm, cls)
2849+
.map(Into::into)
2850+
}
2851+
2852+
fn py_new(_cls: &Py<PyType>, a: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
28362853
let tzinfo = a.tzinfo.into_option().and_then(|tz| tzinfo_arg(tz, vm));
28372854
check_time_args(a.hour, a.minute, a.second, a.microsecond, a.fold, vm)?;
28382855
if let Some(tz) = &tzinfo {
@@ -2867,7 +2884,7 @@ mod _datetime {
28672884

28682885
#[derive(FromArgs)]
28692886
struct TimeIsoformatArgs {
2870-
#[pyarg(any, optional)]
2887+
#[pyarg(any, optional, py_default = "'auto'")]
28712888
timespec: OptionalArg<PyStrRef>,
28722889
}
28732890

@@ -2968,8 +2985,8 @@ mod _datetime {
29682985
}
29692986

29702987
#[pymethod]
2971-
fn __format__(zelf: PyObjectRef, spec: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2972-
object_format(&zelf, spec, vm)
2988+
fn __format__(zelf: PyObjectRef, format: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2989+
object_format(&zelf, format, vm)
29732990
}
29742991

29752992
#[pymethod]
@@ -3018,8 +3035,8 @@ mod _datetime {
30183035
}
30193036

30203037
#[pyclassmethod]
3021-
fn fromisoformat(cls: PyTypeRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
3022-
let tstr = object;
3038+
fn fromisoformat(cls: PyTypeRef, string: PyObjectRef, vm: &VirtualMachine) -> PyResult {
3039+
let tstr = string;
30233040
let Some(s) = tstr.downcast_ref::<PyStr>() else {
30243041
return Err(vm.new_type_error("fromisoformat: argument must be str"));
30253042
};
@@ -3562,7 +3579,7 @@ mod _datetime {
35623579
}
35633580

35643581
#[derive(FromArgs)]
3565-
struct DateTimeArgs {
3582+
pub(super) struct DateTimeArgs {
35663583
#[pyarg(any)]
35673584
year: i32,
35683585
#[pyarg(any)]
@@ -3577,16 +3594,16 @@ mod _datetime {
35773594
second: i32,
35783595
#[pyarg(any, default = 0)]
35793596
microsecond: i32,
3580-
#[pyarg(any, optional)]
3597+
#[pyarg(any, optional, py_default = "None")]
35813598
tzinfo: OptionalArg<PyObjectRef>,
35823599
#[pyarg(named, default = 0)]
35833600
fold: i32,
35843601
}
35853602

35863603
impl Constructor for PyDateTime {
3587-
type Args = FuncArgs;
3604+
type Args = DateTimeArgs;
35883605

3589-
fn py_new(_cls: &Py<PyType>, args: FuncArgs, vm: &VirtualMachine) -> PyResult<Self> {
3606+
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
35903607
if (1..=2).contains(&args.args.len())
35913608
&& let Some(state) = pickle_state(
35923609
&args.args[0],
@@ -3601,7 +3618,7 @@ mod _datetime {
36013618
let fold = (state[2] & 0x80) != 0;
36023619
let date = PyDate::from_state(&[state[0], state[1], state[2] & 0x7f, state[3]]);
36033620
let us = i32::from(state[7]) << 16 | i32::from(state[8]) << 8 | i32::from(state[9]);
3604-
return Ok(Self::new(
3621+
let payload = Self::new(
36053622
date.y(),
36063623
date.m(),
36073624
date.d(),
@@ -3611,9 +3628,17 @@ mod _datetime {
36113628
us,
36123629
tzinfo,
36133630
i32::from(fold),
3614-
));
3631+
);
3632+
drop(args);
3633+
return payload.into_ref_with_type(vm, cls).map(Into::into);
36153634
}
3616-
let a: DateTimeArgs = args.bind(vm)?;
3635+
let args = args.bind(vm)?;
3636+
Self::py_new(&cls, args, vm)?
3637+
.into_ref_with_type(vm, cls)
3638+
.map(Into::into)
3639+
}
3640+
3641+
fn py_new(_cls: &Py<PyType>, a: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
36173642
let tzinfo = a.tzinfo.into_option().and_then(|tz| tzinfo_arg(tz, vm));
36183643
check_date_args(a.year, a.month, a.day, vm)?;
36193644
check_time_args(a.hour, a.minute, a.second, a.microsecond, a.fold, vm)?;
@@ -3644,7 +3669,7 @@ mod _datetime {
36443669
struct FromTimestampArgs {
36453670
#[pyarg(any)]
36463671
timestamp: PyObjectRef,
3647-
#[pyarg(any, optional)]
3672+
#[pyarg(any, optional, py_default = "None")]
36483673
tz: OptionalArg<PyObjectRef>,
36493674
}
36503675

@@ -3660,9 +3685,9 @@ mod _datetime {
36603685

36613686
#[derive(FromArgs)]
36623687
struct DateTimeIsoformatArgs {
3663-
#[pyarg(any, optional)]
3688+
#[pyarg(any, optional, py_default = "'T'")]
36643689
sep: OptionalArg<PyObjectRef>,
3665-
#[pyarg(any, optional)]
3690+
#[pyarg(any, optional, py_default = "'auto'")]
36663691
timespec: OptionalArg<PyStrRef>,
36673692
}
36683693

@@ -3690,7 +3715,7 @@ mod _datetime {
36903715

36913716
#[derive(FromArgs)]
36923717
struct AstimezoneArgs {
3693-
#[pyarg(any, optional)]
3718+
#[pyarg(any, optional, py_default = "None")]
36943719
tz: OptionalArg<PyObjectRef>,
36953720
}
36963721

@@ -3848,8 +3873,8 @@ mod _datetime {
38483873
}
38493874

38503875
#[pyclassmethod]
3851-
fn fromisoformat(cls: PyTypeRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
3852-
let dtstr = object;
3876+
fn fromisoformat(cls: PyTypeRef, string: PyObjectRef, vm: &VirtualMachine) -> PyResult {
3877+
let dtstr = string;
38533878
let Some(s) = dtstr.downcast_ref::<PyStr>() else {
38543879
return Err(vm.new_type_error("fromisoformat: argument must be str"));
38553880
};

0 commit comments

Comments
 (0)