-
-
Notifications
You must be signed in to change notification settings - Fork 31k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-64376: Use Argument Clinic for datetime.date classmethods #20208
Changes from all commits
ee232ca
78e71d0
d0eac8d
5d9b7de
0497383
13ad7c7
c1a2b1e
e6f7572
11f83fd
188130b
0528066
d6c8759
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2876,13 +2876,18 @@ date_fromtimestamp(PyObject *cls, PyObject *obj) | |
cls); | ||
} | ||
|
||
/* Return new date from current time. | ||
* We say this is equivalent to fromtimestamp(time.time()), and the | ||
* only way to be sure of that is to *call* time.time(). That's not | ||
* generally the same as calling C's time. | ||
*/ | ||
/*[clinic input] | ||
@classmethod | ||
datetime.date.today | ||
|
||
Current date or datetime. | ||
|
||
Same as self.__class__.fromtimestamp(time.time()) | ||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
date_today(PyObject *cls, PyObject *dummy) | ||
datetime_date_today_impl(PyTypeObject *type) | ||
/*[clinic end generated code: output=d5474697df6b251c input=0dff9bfe3e2274b2]*/ | ||
{ | ||
PyObject *time; | ||
PyObject *result; | ||
|
@@ -2897,8 +2902,12 @@ date_today(PyObject *cls, PyObject *dummy) | |
* datetime.fromtimestamp. That's why we need all the accuracy | ||
* time.time() delivers; if someone were gonzo about optimization, | ||
* date.today() could get away with plain C time(). | ||
* Besides, we claim that this method is equivalent to | ||
* fromtimestamp(time.time()), and the only way to be of that is to *call* | ||
* time.time(). That's not generally the same as calling C's time. | ||
*/ | ||
result = _PyObject_CallMethodIdOneArg(cls, &PyId_fromtimestamp, time); | ||
result = _PyObject_CallMethodIdOneArg((PyObject *) type, | ||
&PyId_fromtimestamp, time); | ||
Py_DECREF(time); | ||
return result; | ||
} | ||
|
@@ -2940,34 +2949,50 @@ datetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args) | |
return result; | ||
} | ||
|
||
/* Return new date from proleptic Gregorian ordinal. Raises ValueError if | ||
* the ordinal is out of range. | ||
*/ | ||
|
||
/*[clinic input] | ||
@classmethod | ||
datetime.date.fromordinal | ||
|
||
ordinal: int | ||
/ | ||
|
||
int -> date corresponding to a proleptic Gregorian ordinal. | ||
|
||
Raises ValueError if the ordinal is out of range. | ||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
date_fromordinal(PyObject *cls, PyObject *args) | ||
datetime_date_fromordinal_impl(PyTypeObject *type, int ordinal) | ||
/*[clinic end generated code: output=ea5cc69d86614a6b input=1d7158c082e677fd]*/ | ||
{ | ||
PyObject *result = NULL; | ||
int ordinal; | ||
|
||
if (PyArg_ParseTuple(args, "i:fromordinal", &ordinal)) { | ||
int year; | ||
int month; | ||
int day; | ||
int year; | ||
int month; | ||
int day; | ||
|
||
if (ordinal < 1) | ||
PyErr_SetString(PyExc_ValueError, "ordinal must be " | ||
">= 1"); | ||
else { | ||
ord_to_ymd(ordinal, &year, &month, &day); | ||
result = new_date_subclass_ex(year, month, day, cls); | ||
} | ||
if (ordinal < 1) | ||
PyErr_SetString(PyExc_ValueError, "ordinal must be >= 1"); | ||
else { | ||
ord_to_ymd(ordinal, &year, &month, &day); | ||
result = new_date_subclass_ex(year, month, day, (PyObject *) type); | ||
} | ||
return result; | ||
} | ||
|
||
/* Return the new date from a string as generated by date.isoformat() */ | ||
/*[clinic input] | ||
@classmethod | ||
datetime.date.fromisoformat | ||
|
||
date_string as dtstr: object | ||
/ | ||
|
||
str -> Construct a date from the output of date.isoformat() | ||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
date_fromisoformat(PyObject *cls, PyObject *dtstr) | ||
datetime_date_fromisoformat(PyTypeObject *type, PyObject *dtstr) | ||
/*[clinic end generated code: output=0c55fa0175e3e94b input=6bebe824e582fd1e]*/ | ||
{ | ||
assert(dtstr != NULL); | ||
|
||
|
@@ -2998,33 +3023,32 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) | |
goto invalid_string_error; | ||
} | ||
|
||
return new_date_subclass_ex(year, month, day, cls); | ||
return new_date_subclass_ex(year, month, day, (PyObject *) type); | ||
|
||
invalid_string_error: | ||
PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr); | ||
return NULL; | ||
} | ||
|
||
|
||
static PyObject * | ||
date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) | ||
{ | ||
static char *keywords[] = { | ||
"year", "week", "day", NULL | ||
}; | ||
/*[clinic input] | ||
@classmethod | ||
datetime.date.fromisocalendar | ||
|
||
int year, week, day; | ||
if (PyArg_ParseTupleAndKeywords(args, kw, "iii:fromisocalendar", | ||
keywords, | ||
&year, &week, &day) == 0) { | ||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) { | ||
PyErr_Format(PyExc_ValueError, | ||
"ISO calendar component out of range"); | ||
year: int | ||
week: int | ||
day: int | ||
|
||
} | ||
Comment on lines
-3020
to
-3024
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now I see that before this PR we have code in I think we should find a way to retain this behavior, even if that means not using Argument Clinic for this method right now. |
||
return NULL; | ||
} | ||
int, int, int -> Construct a date from the ISO year, week number and weekday. | ||
|
||
This is the inverse of the date.isocalendar() function. | ||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
datetime_date_fromisocalendar_impl(PyTypeObject *type, int year, int week, | ||
int day) | ||
/*[clinic end generated code: output=7b26e15115d24df6 input=e3daae6e2b75f1be]*/ | ||
{ | ||
// Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5) | ||
if (year < MINYEAR || year > MAXYEAR) { | ||
PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year); | ||
|
@@ -3062,7 +3086,7 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) | |
|
||
ord_to_ymd(day_1 + day_offset, &year, &month, &day); | ||
|
||
return new_date_subclass_ex(year, month, day, cls); | ||
return new_date_subclass_ex(year, month, day, (PyObject *) type); | ||
} | ||
|
||
|
||
|
@@ -3485,25 +3509,10 @@ static PyMethodDef date_methods[] = { | |
|
||
/* Class methods: */ | ||
DATETIME_DATE_FROMTIMESTAMP_METHODDEF | ||
|
||
{"fromordinal", (PyCFunction)date_fromordinal, METH_VARARGS | | ||
METH_CLASS, | ||
PyDoc_STR("int -> date corresponding to a proleptic Gregorian " | ||
"ordinal.")}, | ||
|
||
{"fromisoformat", (PyCFunction)date_fromisoformat, METH_O | | ||
METH_CLASS, | ||
PyDoc_STR("str -> Construct a date from the output of date.isoformat()")}, | ||
|
||
{"fromisocalendar", (PyCFunction)(void(*)(void))date_fromisocalendar, | ||
METH_VARARGS | METH_KEYWORDS | METH_CLASS, | ||
PyDoc_STR("int, int, int -> Construct a date from the ISO year, week " | ||
"number and weekday.\n\n" | ||
"This is the inverse of the date.isocalendar() function")}, | ||
|
||
{"today", (PyCFunction)date_today, METH_NOARGS | METH_CLASS, | ||
PyDoc_STR("Current date or datetime: same as " | ||
"self.__class__.fromtimestamp(time.time()).")}, | ||
DATETIME_DATE_FROMORDINAL_METHODDEF | ||
DATETIME_DATE_FROMISOFORMAT_METHODDEF | ||
DATETIME_DATE_FROMISOCALENDAR_METHODDEF | ||
DATETIME_DATE_TODAY_METHODDEF | ||
|
||
/* Instance methods: */ | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mentioned this in a PR comment:
Re:
datetime.date.fromisocalendar
Note that this now can throw OverflowError instead of ValueError when
using the C version of datetime. There is precedent for this, e.g.,
datetime.date.fromordinal
will throw an OverflowError with the C modulebut ValueError with the Python.
Also, prior to this PR, the C version
fromisocalendar
would throw a ValueError while the Python version throws TypeError for issues with e.g, missing arguments.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thanks, I didn't make the connection! I'll take another look at that.