mirror of https://github.com/python/cpython
gh-117534: Add checking for input parameter in iso_to_ymd (#117543)
Moves the validation for invalid years in the C implementation of the `datetime` module into a common location between `fromisoformat` and `fromisocalendar`, which improves the error message and fixes a failed assertion when parsing invalid ISO 8601 years using one of the "ISO weeks" formats. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
This commit is contained in:
parent
a25c02eaf0
commit
d5f1139c79
|
@ -1927,6 +1927,10 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
|
||||||
'2009-02-29', # Invalid leap day
|
'2009-02-29', # Invalid leap day
|
||||||
'2019-W53-1', # No week 53 in 2019
|
'2019-W53-1', # No week 53 in 2019
|
||||||
'2020-W54-1', # No week 54
|
'2020-W54-1', # No week 54
|
||||||
|
'0000-W25-1', # Invalid year
|
||||||
|
'10000-W25-1', # Invalid year
|
||||||
|
'2020-W25-0', # Invalid day-of-week
|
||||||
|
'2020-W25-8', # Invalid day-of-week
|
||||||
'2009\ud80002\ud80028', # Separators are surrogate codepoints
|
'2009\ud80002\ud80028', # Separators are surrogate codepoints
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -496,6 +496,7 @@ David Edelsohn
|
||||||
John Edmonds
|
John Edmonds
|
||||||
Benjamin Edwards
|
Benjamin Edwards
|
||||||
Grant Edwards
|
Grant Edwards
|
||||||
|
Vlad Efanov
|
||||||
Zvi Effron
|
Zvi Effron
|
||||||
John Ehresman
|
John Ehresman
|
||||||
Tal Einat
|
Tal Einat
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve validation logic in the C implementation of :meth:`datetime.fromisoformat`
|
||||||
|
to better handle invalid years. Patch by Vlad Efanov.
|
|
@ -416,6 +416,10 @@ iso_week1_monday(int year)
|
||||||
static int
|
static int
|
||||||
iso_to_ymd(const int iso_year, const int iso_week, const int iso_day,
|
iso_to_ymd(const int iso_year, const int iso_week, const int iso_day,
|
||||||
int *year, int *month, int *day) {
|
int *year, int *month, int *day) {
|
||||||
|
// Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5)
|
||||||
|
if (iso_year < MINYEAR || iso_year > MAXYEAR) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
if (iso_week <= 0 || iso_week >= 53) {
|
if (iso_week <= 0 || iso_week >= 53) {
|
||||||
int out_of_range = 1;
|
int out_of_range = 1;
|
||||||
if (iso_week == 53) {
|
if (iso_week == 53) {
|
||||||
|
@ -762,7 +766,7 @@ parse_isoformat_date(const char *dtstr, const size_t len, int *year, int *month,
|
||||||
* -2: Inconsistent date separator usage
|
* -2: Inconsistent date separator usage
|
||||||
* -3: Failed to parse ISO week.
|
* -3: Failed to parse ISO week.
|
||||||
* -4: Failed to parse ISO day.
|
* -4: Failed to parse ISO day.
|
||||||
* -5, -6: Failure in iso_to_ymd
|
* -5, -6, -7: Failure in iso_to_ymd
|
||||||
*/
|
*/
|
||||||
const char *p = dtstr;
|
const char *p = dtstr;
|
||||||
p = parse_digits(p, year, 4);
|
p = parse_digits(p, year, 4);
|
||||||
|
@ -3142,15 +3146,13 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int month;
|
int month;
|
||||||
int rv = iso_to_ymd(year, week, day, &year, &month, &day);
|
int rv = iso_to_ymd(year, week, day, &year, &month, &day);
|
||||||
|
|
||||||
|
if (rv == -4) {
|
||||||
|
PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (rv == -2) {
|
if (rv == -2) {
|
||||||
PyErr_Format(PyExc_ValueError, "Invalid week: %d", week);
|
PyErr_Format(PyExc_ValueError, "Invalid week: %d", week);
|
||||||
|
|
Loading…
Reference in New Issue