Skip to content

Commit fb694d0

Browse files
committed
add extract_i64
1 parent 4bbdcb1 commit fb694d0

File tree

9 files changed

+32
-22
lines changed

9 files changed

+32
-22
lines changed

src/errors/location.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use serde::ser::SerializeSeq;
88
use serde::{Serialize, Serializer};
99

1010
use crate::lookup_key::{LookupPath, PathItem};
11+
use crate::tools::extract_i64;
1112

1213
/// Used to store individual items of the error location, e.g. a string for key/field names
1314
/// or a number for array indices.
@@ -88,7 +89,7 @@ impl TryFrom<&PyAny> for LocItem {
8889
if let Ok(py_str) = loc_item.downcast::<PyString>() {
8990
let str = py_str.to_str()?.to_string();
9091
Ok(Self::S(str))
91-
} else if let Ok(int) = loc_item.extract::<i64>() {
92+
} else if let Ok(int) = extract_i64(loc_item) {
9293
Ok(Self::I(int))
9394
} else {
9495
Err(PyTypeError::new_err("Item in a location must be a string or int"))

src/errors/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use pyo3::once_cell::GILOnceCell;
77
use pyo3::prelude::*;
88
use pyo3::types::{PyDict, PyList};
99

10-
use crate::tools::{py_err, py_error_type};
10+
use crate::tools::{extract_i64, py_err, py_error_type};
1111
use strum::{Display, EnumMessage, IntoEnumIterator};
1212
use strum_macros::EnumIter;
1313

@@ -729,7 +729,7 @@ impl From<String> for Number {
729729

730730
impl FromPyObject<'_> for Number {
731731
fn extract(obj: &PyAny) -> PyResult<Self> {
732-
if let Ok(int) = obj.extract::<i64>() {
732+
if let Ok(int) = extract_i64(obj) {
733733
Ok(Number::Int(int))
734734
} else if let Ok(float) = obj.extract::<f64>() {
735735
Ok(Number::Float(float))

src/errors/value_exception.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use pyo3::prelude::*;
44
use pyo3::types::{PyDict, PyString};
55

66
use crate::input::Input;
7+
use crate::tools::extract_i64;
78

89
use super::{ErrorType, ValError};
910

@@ -74,7 +75,7 @@ impl PydanticCustomError {
7475
let key: &PyString = key.downcast()?;
7576
if let Ok(py_str) = value.downcast::<PyString>() {
7677
message = message.replace(&format!("{{{}}}", key.to_str()?), py_str.to_str()?);
77-
} else if let Ok(value_int) = value.extract::<i64>() {
78+
} else if let Ok(value_int) = extract_i64(value) {
7879
message = message.replace(&format!("{{{}}}", key.to_str()?), &value_int.to_string());
7980
} else {
8081
// fallback for anything else just in case

src/input/input_python.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use pyo3::types::{PyDictItems, PyDictKeys, PyDictValues};
1111
use pyo3::{ffi, intern, AsPyPointer, PyTypeInfo};
1212

1313
use crate::errors::{ErrorType, InputValue, LocItem, ValError, ValResult};
14-
use crate::tools::safe_repr;
14+
use crate::tools::{extract_i64, safe_repr};
1515
use crate::{ArgsKwargs, PyMultiHostUrl, PyUrl};
1616

1717
use super::datetime::{
@@ -89,7 +89,7 @@ impl<'a> Input<'a> for PyAny {
8989
fn as_loc_item(&self) -> LocItem {
9090
if let Ok(py_str) = self.downcast::<PyString>() {
9191
py_str.to_string_lossy().as_ref().into()
92-
} else if let Ok(key_int) = self.extract::<i64>() {
92+
} else if let Ok(key_int) = extract_i64(self) {
9393
key_int.into()
9494
} else {
9595
safe_repr(self).to_string().into()
@@ -256,7 +256,7 @@ impl<'a> Input<'a> for PyAny {
256256
Ok(bool)
257257
} else if let Some(cow_str) = maybe_as_string(self, ErrorType::BoolParsing)? {
258258
str_as_bool(self, &cow_str)
259-
} else if let Ok(int) = self.extract::<i64>() {
259+
} else if let Ok(int) = extract_i64(self) {
260260
int_as_bool(self, int)
261261
} else if let Ok(float) = self.extract::<f64>() {
262262
match float_as_int(self, float) {
@@ -547,7 +547,7 @@ impl<'a> Input<'a> for PyAny {
547547
bytes_as_time(self, py_bytes.as_bytes())
548548
} else if PyBool::is_exact_type_of(self) {
549549
Err(ValError::new(ErrorType::TimeType, self))
550-
} else if let Ok(int) = self.extract::<i64>() {
550+
} else if let Ok(int) = extract_i64(self) {
551551
int_as_time(self, int, 0)
552552
} else if let Ok(float) = self.extract::<f64>() {
553553
float_as_time(self, float)
@@ -574,7 +574,7 @@ impl<'a> Input<'a> for PyAny {
574574
bytes_as_datetime(self, py_bytes.as_bytes())
575575
} else if PyBool::is_exact_type_of(self) {
576576
Err(ValError::new(ErrorType::DatetimeType, self))
577-
} else if let Ok(int) = self.extract::<i64>() {
577+
} else if let Ok(int) = extract_i64(self) {
578578
int_as_datetime(self, int, 0)
579579
} else if let Ok(float) = self.extract::<f64>() {
580580
float_as_datetime(self, float)
@@ -601,7 +601,7 @@ impl<'a> Input<'a> for PyAny {
601601
bytes_as_timedelta(self, str.as_bytes())
602602
} else if let Ok(py_bytes) = self.downcast::<PyBytes>() {
603603
bytes_as_timedelta(self, py_bytes.as_bytes())
604-
} else if let Ok(int) = self.extract::<i64>() {
604+
} else if let Ok(int) = extract_i64(self) {
605605
Ok(int_as_duration(self, int)?.into())
606606
} else if let Ok(float) = self.extract::<f64>() {
607607
Ok(float_as_duration(self, float)?.into())

src/lookup_key.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use pyo3::types::{PyDict, PyList, PyMapping, PyString};
88
use crate::build_tools::py_schema_err;
99
use crate::errors::{ErrorType, ValLineError};
1010
use crate::input::{Input, JsonInput, JsonObject};
11-
use crate::tools::py_err;
11+
use crate::tools::{extract_i64, py_err};
1212

1313
/// Used got getting items from python dicts, python objects, or JSON objects, in different ways
1414
#[derive(Debug, Clone)]
@@ -409,7 +409,7 @@ impl PathItem {
409409
} else {
410410
Ok(Self::Pos(usize_key))
411411
}
412-
} else if let Ok(int_key) = obj.extract::<i64>() {
412+
} else if let Ok(int_key) = extract_i64(obj) {
413413
if index == 0 {
414414
py_err!(PyTypeError; "The first item in an alias path should be a string")
415415
} else {

src/serializers/infer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::serializers::errors::SERIALIZATION_ERR_MARKER;
1414
use crate::serializers::filter::SchemaFilter;
1515
use crate::serializers::shared::{PydanticSerializer, TypeSerializer};
1616
use crate::serializers::SchemaSerializer;
17-
use crate::tools::{py_err, safe_repr};
17+
use crate::tools::{extract_i64, py_err, safe_repr};
1818
use crate::url::{PyMultiHostUrl, PyUrl};
1919

2020
use super::errors::{py_err_se_err, PydanticSerializationError};
@@ -122,7 +122,7 @@ pub(crate) fn infer_to_python_known(
122122
// `bool` and `None` can't be subclasses, `ObType::Int`, `ObType::Float`, `ObType::Str` refer to exact types
123123
ObType::None | ObType::Bool | ObType::Int | ObType::Float | ObType::Str => value.into_py(py),
124124
// have to do this to make sure subclasses of for example str are upcast to `str`
125-
ObType::IntSubclass => value.extract::<i64>()?.into_py(py),
125+
ObType::IntSubclass => extract_i64(value)?.into_py(py),
126126
ObType::FloatSubclass => value.extract::<f64>()?.into_py(py),
127127
ObType::Decimal => value.to_string().into_py(py),
128128
ObType::StrSubclass => value.extract::<&str>()?.into_py(py),

src/serializers/type_serializers/literal.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use serde::Serialize;
99

1010
use crate::build_tools::py_schema_err;
1111
use crate::definitions::DefinitionsBuilder;
12-
use crate::tools::SchemaDict;
12+
use crate::tools::{extract_i64, SchemaDict};
1313

1414
use super::{
1515
infer_json_key, infer_serialize, infer_to_python, py_err_se_err, BuildSerializer, CombinedSerializer, Extra,
@@ -44,7 +44,7 @@ impl BuildSerializer for LiteralSerializer {
4444
let mut repr_args: Vec<String> = Vec::new();
4545
for item in expected {
4646
repr_args.push(item.repr()?.extract()?);
47-
if let Ok(int) = item.extract::<i64>() {
47+
if let Ok(int) = extract_i64(item) {
4848
expected_int.insert(int);
4949
} else if let Ok(py_str) = item.downcast::<PyString>() {
5050
expected_str.insert(py_str.to_str()?.to_string());
@@ -77,7 +77,7 @@ impl LiteralSerializer {
7777
fn check<'a>(&self, value: &'a PyAny, extra: &Extra) -> PyResult<OutputValue<'a>> {
7878
if extra.check.enabled() {
7979
if !self.expected_int.is_empty() && value.extract::<bool>().is_err() {
80-
if let Ok(int) = value.extract::<i64>() {
80+
if let Ok(int) = extract_i64(value) {
8181
if self.expected_int.contains(&int) {
8282
return Ok(OutputValue::OkInt(int));
8383
}

src/tools.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::borrow::Cow;
22

3-
use pyo3::exceptions::PyKeyError;
3+
use pyo3::exceptions::{PyKeyError, PyTypeError};
44
use pyo3::prelude::*;
5-
use pyo3::types::{PyDict, PyString};
6-
use pyo3::{intern, FromPyObject};
5+
use pyo3::types::{PyDict, PyInt, PyString};
6+
use pyo3::{intern, FromPyObject, PyTypeInfo};
77

88
pub trait SchemaDict<'py> {
99
fn get_as<T>(&'py self, key: &PyString) -> PyResult<Option<T>>
@@ -98,3 +98,11 @@ pub fn safe_repr(v: &PyAny) -> Cow<str> {
9898
"<unprintable object>".into()
9999
}
100100
}
101+
102+
pub fn extract_i64(v: &PyAny) -> PyResult<i64> {
103+
if PyInt::is_type_of(v) {
104+
v.extract()
105+
} else {
106+
py_err!(PyTypeError; "expected int, got {}", safe_repr(v))
107+
}
108+
}

src/validators/union.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::errors::{ErrorType, LocItem, ValError, ValLineError, ValResult};
1515
use crate::input::{GenericMapping, Input};
1616
use crate::lookup_key::LookupKey;
1717
use crate::recursion_guard::RecursionGuard;
18-
use crate::tools::{py_err, SchemaDict};
18+
use crate::tools::{extract_i64, py_err, SchemaDict};
1919

2020
use super::custom_error::CustomError;
2121
use super::{build_validator, BuildValidator, CombinedValidator, Definitions, DefinitionsBuilder, Extra, Validator};
@@ -228,7 +228,7 @@ enum ChoiceKey {
228228

229229
impl ChoiceKey {
230230
fn from_py(raw: &PyAny) -> PyResult<Self> {
231-
if let Ok(py_int) = raw.extract::<i64>() {
231+
if let Ok(py_int) = extract_i64(raw) {
232232
Ok(Self::Int(py_int))
233233
} else if let Ok(py_str) = raw.downcast::<PyString>() {
234234
Ok(Self::Str(py_str.to_str()?.to_string()))

0 commit comments

Comments
 (0)