Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-109798: Normalize _datetime and datetime error messages#127345
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
764eb1b2bf419f4363e9e9da0dfc179423df691251d8973cf5eea62f79543ccd174497498c4ba216d0fec409fec3f454f6a2b8f7a209c3380777aa54d31d33f05ebbaf84010561c95a52ab77b3b1e272a7a35bd4cfd18cb2827514cd3bdc19915dfe1da5a3a610f067410e0ceFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -60,14 +60,14 @@ def _days_in_month(year, month): | ||
| def _days_before_month(year, month): | ||
| "year, month -> number of days in year preceding first day of month." | ||
| assert 1 <= month <= 12, 'month must be in 1..12' | ||
| assert 1 <= month <= 12, f"month must be in 1..12, not {month}" | ||
| return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year)) | ||
| def _ymd2ord(year, month, day): | ||
| "year, month, day -> ordinal, considering 01-Jan-0001 as day 1." | ||
| assert 1 <= month <= 12, 'month must be in 1..12' | ||
| assert 1 <= month <= 12, f"month must be in 1..12, not {month}" | ||
| dim = _days_in_month(year, month) | ||
| assert 1 <= day <= dim, ('day must be in 1..%d' % dim) | ||
| assert 1 <= day <= dim, f"day must be in 1..{dim}, not {day}" | ||
| return (_days_before_year(year) + | ||
| _days_before_month(year, month) + | ||
| day) | ||
| @@ -512,7 +512,7 @@ def _parse_isoformat_time(tstr): | ||
| def _isoweek_to_gregorian(year, week, day): | ||
| # Year is bounded this way because 9999-12-31 is (9999, 52, 5) | ||
| if not MINYEAR <= year <= MAXYEAR: | ||
| raise ValueError(f"Year is out of range: {year}") | ||
| raise ValueError(f"year must be in {MINYEAR}..{MAXYEAR}, not {year}") | ||
| if not 0 < week < 53: | ||
| out_of_range = True | ||
| @@ -545,7 +545,7 @@ def _isoweek_to_gregorian(year, week, day): | ||
| def _check_tzname(name): | ||
| if name is not None and not isinstance(name, str): | ||
| raise TypeError("tzinfo.tzname() must return None or string, " | ||
| "not '%s'" % type(name)) | ||
| f"not {type(name).__name__!r}") | ||
| # name is the offset-producing method, "utcoffset" or "dst". | ||
| # offset is what it returned. | ||
| @@ -558,24 +558,24 @@ def _check_utc_offset(name, offset): | ||
| if offset is None: | ||
| return | ||
| if not isinstance(offset, timedelta): | ||
| raise TypeError("tzinfo.%s() must return None " | ||
| "or timedelta, not '%s'" % (name, type(offset))) | ||
| raise TypeError(f"tzinfo.{name}() must return None " | ||
| f"or timedelta, not {type(offset).__name__!r}") | ||
| if not -timedelta(1) < offset < timedelta(1): | ||
| raise ValueError("%s()=%s, must be strictly between " | ||
| "-timedelta(hours=24) and timedelta(hours=24)" % | ||
| (name, offset)) | ||
| raise ValueError("offset must be a timedelta " | ||
| "strictly between -timedelta(hours=24) and " | ||
| f"timedelta(hours=24), not {offset!r}") | ||
| def _check_date_fields(year, month, day): | ||
| year = _index(year) | ||
| month = _index(month) | ||
| day = _index(day) | ||
| if not MINYEAR <= year <= MAXYEAR: | ||
| raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year) | ||
| raise ValueError(f"year must be in {MINYEAR}..{MAXYEAR}, not {year}") | ||
| if not 1 <= month <= 12: | ||
| raise ValueError('month must be in 1..12', month) | ||
| raise ValueError(f"month must be in 1..12, not {month}") | ||
| dim = _days_in_month(year, month) | ||
| if not 1 <= day <= dim: | ||
| raise ValueError('day must be in 1..%d' % dim, day) | ||
| raise ValueError(f"day must be in 1..{dim}, not {day}") | ||
| return year, month, day | ||
| def _check_time_fields(hour, minute, second, microsecond, fold): | ||
| @@ -584,20 +584,23 @@ def _check_time_fields(hour, minute, second, microsecond, fold): | ||
| second = _index(second) | ||
| microsecond = _index(microsecond) | ||
| if not 0 <= hour <= 23: | ||
| raise ValueError('hour must be in 0..23', hour) | ||
| raise ValueError(f"hour must be in 0..23, not {hour}") | ||
| if not 0 <= minute <= 59: | ||
| raise ValueError('minute must be in 0..59', minute) | ||
| raise ValueError(f"minute must be in 0..59, not {minute}") | ||
| if not 0 <= second <= 59: | ||
| raise ValueError('second must be in 0..59', second) | ||
| raise ValueError(f"second must be in 0..59, not {second}") | ||
| if not 0 <= microsecond <= 999999: | ||
| raise ValueError('microsecond must be in 0..999999', microsecond) | ||
| raise ValueError(f"microsecond must be in 0..999999, not {microsecond}") | ||
| if fold not in (0, 1): | ||
| raise ValueError('fold must be either 0 or 1', fold) | ||
| raise ValueError(f"fold must be either 0 or 1, not {fold}") | ||
| return hour, minute, second, microsecond, fold | ||
| def _check_tzinfo_arg(tz): | ||
| if tz is not None and not isinstance(tz, tzinfo): | ||
| raise TypeError("tzinfo argument must be None or of a tzinfo subclass") | ||
| raise TypeError( | ||
| "tzinfo argument must be None or of a tzinfo subclass, " | ||
| f"not {type(tz).__name__!r}" | ||
| ) | ||
| def _divide_and_round(a, b): | ||
| """divide a by b and round result to the nearest integer | ||
| @@ -2418,7 +2421,7 @@ def __new__(cls, offset, name=_Omitted): | ||
| if not cls._minoffset <= offset <= cls._maxoffset: | ||
| raise ValueError("offset must be a timedelta " | ||
| "strictly between -timedelta(hours=24) and " | ||
| "timedelta(hours=24).") | ||
| f"timedelta(hours=24), not {offset!r}") | ||
Member 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. Probably not going to be a great user experience here because of how bad the >>>print(f"{timedelta(hours=-25)!r}")
datetime.timedelta(days=-2, seconds=82800)Maybe it will be clearer if we do it this way: ifoffset<timedelta(0):
offset_str=f"-{-offset)}"else:
offset_str=str(offset)That will print stuff like Probably a more elaborate timedelta formatter would be better, since we basically always want this in
| ||
| return cls._create(offset, name) | ||
| def __init_subclass__(cls): | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Added additional information into error messages in :mod:`datetime`, and made the messages more consistent between the C and Python implementations. Patch by Semyon Moroz. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -637,17 +637,19 @@ check_date_args(int year, int month, int day) | ||
| { | ||
| if (year < MINYEAR || year > MAXYEAR) { | ||
| PyErr_Format(PyExc_ValueError, "year %i is out of range", year); | ||
| PyErr_Format(PyExc_ValueError, | ||
| "year must be in %d..%d, not %d", MINYEAR, MAXYEAR, year); | ||
| return -1; | ||
| } | ||
| if (month < 1 || month > 12) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "month must be in 1..12"); | ||
| PyErr_Format(PyExc_ValueError, | ||
| "month must be in 1..12, not %d", month); | ||
| return -1; | ||
| } | ||
| if (day < 1 || day > days_in_month(year, month)) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "day is out of range for month"); | ||
| int dim = days_in_month(year, month); | ||
| if (day < 1 || day > dim) { | ||
erlend-aasland marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| PyErr_Format(PyExc_ValueError, | ||
| "day must be in 1..%d, not %d", dim, day); | ||
| return -1; | ||
| } | ||
| return 0; | ||
| @@ -660,28 +662,25 @@ static int | ||
| check_time_args(int h, int m, int s, int us, int fold) | ||
| { | ||
| if (h < 0 || h > 23) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "hour must be in 0..23"); | ||
| PyErr_Format(PyExc_ValueError, "hour must be in 0..23, not %i", h); | ||
| return -1; | ||
| } | ||
| if (m < 0 || m > 59) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "minute must be in 0..59"); | ||
| PyErr_Format(PyExc_ValueError, "minute must be in 0..59, not %i", m); | ||
| return -1; | ||
| } | ||
| if (s < 0 || s > 59) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "second must be in 0..59"); | ||
| PyErr_Format(PyExc_ValueError, "second must be in 0..59, not %i", s); | ||
| return -1; | ||
| } | ||
| if (us < 0 || us > 999999) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "microsecond must be in 0..999999"); | ||
| PyErr_Format(PyExc_ValueError, | ||
| "microsecond must be in 0..999999, not %i", us); | ||
| return -1; | ||
| } | ||
| if (fold != 0 && fold != 1) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "fold must be either 0 or 1"); | ||
| PyErr_Format(PyExc_ValueError, | ||
| "fold must be either 0 or 1, not %i", fold); | ||
| return -1; | ||
| } | ||
| return 0; | ||
| @@ -1435,8 +1434,7 @@ new_timezone(PyObject *offset, PyObject *name) | ||
| GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) { | ||
| PyErr_Format(PyExc_ValueError, "offset must be a timedelta" | ||
| " strictly between -timedelta(hours=24) and" | ||
| " timedelta(hours=24)," | ||
| " not %R.", offset); | ||
erlend-aasland marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| " timedelta(hours=24), not %R", offset); | ||
| return NULL; | ||
| } | ||
| @@ -1505,10 +1503,10 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) | ||
| GET_TD_SECONDS(offset) == 0 && | ||
| GET_TD_MICROSECONDS(offset) < 1) || | ||
| GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) { | ||
| Py_DECREF(offset); | ||
| PyErr_Format(PyExc_ValueError, "offset must be a timedelta" | ||
| " strictly between -timedelta(hours=24) and" | ||
| " timedelta(hours=24)."); | ||
| " timedelta(hours=24), not %R", offset); | ||
| Py_DECREF(offset); | ||
erlend-aasland marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| return NULL; | ||
| } | ||
| } | ||
| @@ -2261,7 +2259,7 @@ get_float_as_integer_ratio(PyObject *floatobj) | ||
| if (!PyTuple_Check(ratio)) { | ||
| PyErr_Format(PyExc_TypeError, | ||
| "unexpected return type from as_integer_ratio(): " | ||
| "expected tuple, got '%.200s'", | ||
| "expected tuple, not '%.200s'", | ||
| Py_TYPE(ratio)->tp_name); | ||
| Py_DECREF(ratio); | ||
| return NULL; | ||
| @@ -3382,7 +3380,8 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) | ||
| 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); | ||
| PyErr_Format(PyExc_ValueError, | ||
| "year must be in %d..%d, not %d", MINYEAR, MAXYEAR, year); | ||
| return NULL; | ||
| } | ||
| @@ -3392,7 +3391,7 @@ date_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw) | ||
| } | ||
| if (rv == -3) { | ||
| PyErr_Format(PyExc_ValueError, "Invalid day: %d (range is [1, 7])", | ||
| PyErr_Format(PyExc_ValueError, "Invalid weekday: %d (range is [1, 7])", | ||
donbarbos marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| day); | ||
| return NULL; | ||
| } | ||
| @@ -4378,8 +4377,7 @@ timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt) | ||
| return NULL; | ||
| } | ||
| if (!HASTZINFO(dt) || dt->tzinfo != (PyObject *)self) { | ||
| PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo " | ||
| "is not self"); | ||
| PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo is not self"); | ||
| return NULL; | ||
| } | ||
| @@ -5352,7 +5350,8 @@ utc_to_seconds(int year, int month, int day, | ||
| /* ymd_to_ord() doesn't support year <= 0 */ | ||
| if (year < MINYEAR || year > MAXYEAR) { | ||
| PyErr_Format(PyExc_ValueError, "year %i is out of range", year); | ||
| PyErr_Format(PyExc_ValueError, | ||
| "year must be in %d..%d, not %d", MINYEAR, MAXYEAR, year); | ||
| return -1; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.