8000 Fix `ValueError` on year zero by davidhewitt · Pull Request #1583 · pydantic/pydantic-core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix ValueError on year zero #1583

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

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 42 additions & 30 deletions src/input/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,26 @@ pub fn pydate_as_date(py_date: &Bound<'_, PyAny>) -> PyResult<Date> {
})
}

impl<'py> IntoPyObject<'py> for EitherDate<'py> {
type Target = PyDate;
type Output = Bound<'py, PyDate>;
type Error = PyErr;

fn into_pyobject(self, py: Python<'py>) -> PyResult<Self::Output> {
impl<'py> EitherDate<'py> {
pub fn try_into_py(&self, py: Python<'py>, input: &(impl Input<'py> + ?Sized)) -> ValResult<PyObject> {
match self {
Self::Raw(date) => PyDate::new(py, date.year.into(), date.month, date.day),
Self::Py(date) => Ok(date),
Self::Raw(date) => {
if date.year == 0 {
return Err(ValError::new(
ErrorType::DateParsing {
error: Cow::Borrowed("year 0 is out of range"),
context: None,
},
input,
));
};
let py_date = PyDate::new(py, date.year.into(), date.month, date.day)?;
Ok(py_date.into())
}
Self::Py(py_date) => Ok(py_date.clone().into()),
}
}
}

impl EitherDate<'_> {
pub fn as_raw(&self) -> PyResult<Date> {
match self {
Self::Raw(date) => Ok(date.clone()),
Expand Down Expand Up @@ -278,30 +284,36 @@ pub fn pydatetime_as_datetime(py_dt: &Bound<'_, PyAny>) -> PyResult<DateTime> {
})
}

impl<'py> IntoPyObject<'py> for EitherDateTime<'py> {
type Target = PyDateTime;
type Output = Bound<'py, PyDateTime>;
type Error = PyErr;

fn into_pyobject(self, py: Python<'py>) -> PyResult<Self::Output> {
impl<'py> EitherDateTime<'py> {
pub fn try_into_py(&self, py: Python<'py>, input: &(impl Input<'py> + ?Sized)) -> ValResult<PyObject> {
match self {
Self::Raw(dt) => PyDateTime::new(
py,
dt.date.year.into(),
dt.date.month,
dt.date.day,
dt.time.hour,
dt.time.minute,
dt.time.second,
dt.time.microsecond,
time_as_tzinfo(py, &dt.time)?.as_ref(),
),
Self::Py(dt) => Ok(dt),
Self::Raw(dt) => {
if dt.date.year == 0 {
return Err(ValError::new(
ErrorType::DatetimeParsing {
error: Cow::Borrowed("year 0 is out of range"),
context: None,
},
input,
));
};
let py_dt = PyDateTime::new(
py,
dt.date.year.into(),
dt.date.month,
dt.date.day,
dt.time.hour,
dt.time.minute,
dt.time.second,
dt.time.microsecond,
time_as_tzinfo(py, &dt.time)?.as_ref(),
)?;
Ok(py_dt.into())
}
Self::Py(py_dt) => Ok(py_dt.clone().into()),
}
}
}

impl EitherDateTime<'_> {
pub fn as_raw(&self) -> PyResult<DateTime> {
match self {
Self::Raw(dt) => Ok(dt.clone()),
Expand Down
3 changes: 1 addition & 2 deletions src/validators/date.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use pyo3::intern;
use pyo3::prelude::*;
use pyo3::types::{PyDate, PyDict, PyString};
use pyo3::IntoPyObjectExt;
use speedate::{Date, Time};
use strum::EnumMessage;

Expand Down Expand Up @@ -98,7 +97,7 @@ impl Validator for DateValidator {
}
}
}
Ok(date.into_py_any(py)?)
date.try_into_py(py, input)
}

fn get_name(&self) -> &str {
Expand Down
3 changes: 1 addition & 2 deletions src/validators/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use pyo3::intern;
use pyo3::prelude::*;
use pyo3::sync::GILOnceCell;
use pyo3::types::{PyDict, PyString};
use pyo3::IntoPyObjectExt;
use speedate::{DateTime, Time};
use std::cmp::Ordering;
use strum::EnumMessage;
Expand Down Expand Up @@ -131,7 +130,7 @@ impl Validator for DateTimeValidator {
tz_constraint.tz_check(speedate_dt.time.tz_offset, input)?;
}
}
Ok(datetime.into_py_any(py)?)
datetime.try_into_py(py, input)
}

fn get_name(&self) -> &str {
Expand Down
6 changes: 6 additions & 0 deletions tests/validators/test_date.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
),
pytest.param('-', Err('Input should be a valid date or datetime, input is too short'), id='minus'),
pytest.param('+', Err('Input should be a valid date or datetime, input is too short'), id='pus'),
pytest.param('0001-01-01', date(1, 1, 1), id='min-date'),
pytest.param(
'0000-12-31',
Err('Input should be a valid date in the format YYYY-MM-DD, year 0 is out of range [type=date_parsing,'),
id='year-0',
),
],
)
def test_date(input_value, expected):
Expand Down
8 changes: 8 additions & 0 deletions tests/validators/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@
'Input should be a valid datetime or date, day value is outside expected range [type=datetime_from_date_parsing,'
),
),
(
'0001-01-01T00:00:00.000000Z',
datetime(1, 1, 1, tzinfo=timezone.utc),
),
(
'0000-12-31T23:59:59.999999Z',
Err('Input should be a valid datetime, year 0 is out of range [type=datetime_parsing,'),
),
],
)
def test_datetime(input_value, expected):
Expand Down
Loading
0