Skip to content

Commit

Permalink
jiter (#974)
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Nov 6, 2023
1 parent 9d07a8c commit 1f18da2
Show file tree
Hide file tree
Showing 30 changed files with 385 additions and 489 deletions.
85 changes: 85 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Expand Up @@ -43,6 +43,8 @@ base64 = "0.21.5"
num-bigint = "0.4.4"
python3-dll-a = "0.2.7"
uuid = "1.5.0"
jiter = {version = "0.0.4", features = ["python"]}
#jiter = {path = "../jiter", features = ["python"]}

[lib]
name = "_pydantic_core"
Expand Down
2 changes: 2 additions & 0 deletions python/pydantic_core/__init__.py
Expand Up @@ -22,6 +22,7 @@
Url,
ValidationError,
__version__,
from_json,
to_json,
to_jsonable_python,
validate_core_schema,
Expand Down Expand Up @@ -63,6 +64,7 @@
'PydanticSerializationUnexpectedValue',
'TzInfo',
'to_json',
'from_json',
'to_jsonable_python',
'validate_core_schema',
]
Expand Down
18 changes: 18 additions & 0 deletions python/pydantic_core/_pydantic_core.pyi
Expand Up @@ -41,6 +41,7 @@ __all__ = [
'PydanticUndefinedType',
'Some',
'to_json',
'from_json',
'to_jsonable_python',
'list_all_errors',
'TzInfo',
Expand Down Expand Up @@ -384,6 +385,23 @@ def to_json(
JSON bytes.
"""

def from_json(data: str | bytes | bytearray, *, allow_inf_nan: bool = True) -> Any:
"""
Deserialize JSON data to a Python object.
This is effectively a faster version of [`json.loads()`][json.loads].
Arguments:
data: The JSON data to deserialize.
allow_inf_nan: Whether to allow `Infinity`, `-Infinity` and `NaN` values as `json.loads()` does by default.
Raises:
ValueError: If deserialization fails.
Returns:
The deserialized Python object.
"""

def to_jsonable_python(
value: Any,
*,
Expand Down
6 changes: 4 additions & 2 deletions src/errors/line_error.rs
Expand Up @@ -2,7 +2,9 @@ use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use pyo3::PyDowncastError;

use crate::input::{Input, JsonInput};
use jiter::JsonValue;

use crate::input::Input;

use super::location::{LocItem, Location};
use super::types::ErrorType;
Expand Down Expand Up @@ -147,7 +149,7 @@ impl<'a> ValLineError<'a> {
#[derive(Clone)]
pub enum InputValue<'a> {
PyAny(&'a PyAny),
JsonInput(JsonInput),
JsonInput(JsonValue),
String(&'a str),
}

Expand Down
28 changes: 9 additions & 19 deletions src/errors/location.rs
Expand Up @@ -3,12 +3,11 @@ use pyo3::once_cell::GILOnceCell;
use std::fmt;

use pyo3::prelude::*;
use pyo3::types::{PyList, PyString, PyTuple};
use pyo3::types::{PyList, PyTuple};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};

use crate::lookup_key::{LookupPath, PathItem};
use crate::tools::extract_i64;

/// Used to store individual items of the error location, e.g. a string for key/field names
/// or a number for array indices.
Expand All @@ -35,6 +34,12 @@ impl fmt::Display for LocItem {
}
}

// TODO rename to ToLocItem
pub trait AsLocItem {
// TODO rename to to_loc_item
fn as_loc_item(&self) -> LocItem;
}

impl From<String> for LocItem {
fn from(s: String) -> Self {
Self::S(s)
Expand Down Expand Up @@ -82,21 +87,6 @@ impl ToPyObject for LocItem {
}
}

impl TryFrom<&PyAny> for LocItem {
type Error = PyErr;

fn try_from(loc_item: &PyAny) -> PyResult<Self> {
if let Ok(py_str) = loc_item.downcast::<PyString>() {
let str = py_str.to_str()?.to_string();
Ok(Self::S(str))
} else if let Ok(int) = extract_i64(loc_item) {
Ok(Self::I(int))
} else {
Err(PyTypeError::new_err("Item in a location must be a string or int"))
}
}
}

impl Serialize for LocItem {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down Expand Up @@ -211,9 +201,9 @@ impl TryFrom<Option<&PyAny>> for Location {
fn try_from(location: Option<&PyAny>) -> PyResult<Self> {
if let Some(location) = location {
let mut loc_vec: Vec<LocItem> = if let Ok(tuple) = location.downcast::<PyTuple>() {
tuple.iter().map(LocItem::try_from).collect::<PyResult<_>>()?
tuple.iter().map(AsLocItem::as_loc_item).collect()
} else if let Ok(list) = location.downcast::<PyList>() {
list.iter().map(LocItem::try_from).collect::<PyResult<_>>()?
list.iter().map(AsLocItem::as_loc_item).collect()
} else {
return Err(PyTypeError::new_err(
"Location must be a list or tuple of strings and ints",
Expand Down
2 changes: 1 addition & 1 deletion src/errors/mod.rs
Expand Up @@ -7,7 +7,7 @@ mod validation_exception;
mod value_exception;

pub use self::line_error::{InputValue, ValError, ValLineError, ValResult};
pub use self::location::LocItem;
pub use self::location::{AsLocItem, LocItem};
pub use self::types::{list_all_errors, ErrorType, ErrorTypeDefaults, Number};
pub use self::validation_exception::ValidationError;
pub use self::value_exception::{PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticUseDefault};
Expand Down
12 changes: 6 additions & 6 deletions src/input/input_abstract.rs
Expand Up @@ -4,13 +4,15 @@ use pyo3::exceptions::PyValueError;
use pyo3::types::{PyDict, PyType};
use pyo3::{intern, prelude::*};

use crate::errors::{InputValue, LocItem, ValResult};
use jiter::JsonValue;

use crate::errors::{AsLocItem, InputValue, ValResult};
use crate::tools::py_err;
use crate::{PyMultiHostUrl, PyUrl};

use super::datetime::{EitherDate, EitherDateTime, EitherTime, EitherTimedelta};
use super::return_enums::{EitherBytes, EitherInt, EitherString};
use super::{EitherFloat, GenericArguments, GenericIterable, GenericIterator, GenericMapping, JsonInput};
use super::{EitherFloat, GenericArguments, GenericIterable, GenericIterator, GenericMapping};

#[derive(Debug, Clone, Copy)]
pub enum InputType {
Expand Down Expand Up @@ -46,9 +48,7 @@ impl TryFrom<&str> for InputType {
/// the convention is to either implement:
/// * `strict_*` & `lax_*` if they have different behavior
/// * or, `validate_*` and `strict_*` to just call `validate_*` if the behavior for strict and lax is the same
pub trait Input<'a>: fmt::Debug + ToPyObject {
fn as_loc_item(&self) -> LocItem;

pub trait Input<'a>: fmt::Debug + ToPyObject + AsLocItem {
fn as_error_value(&'a self) -> InputValue<'a>;

fn identity(&self) -> Option<usize> {
Expand Down Expand Up @@ -89,7 +89,7 @@ pub trait Input<'a>: fmt::Debug + ToPyObject {

fn validate_dataclass_args(&'a self, dataclass_name: &str) -> ValResult<'a, GenericArguments<'a>>;

fn parse_json(&'a self) -> ValResult<'a, JsonInput>;
fn parse_json(&'a self) -> ValResult<'a, JsonValue>;

fn validate_str(&'a self, strict: bool, coerce_numbers_to_str: bool) -> ValResult<EitherString<'a>> {
if strict {
Expand Down

0 comments on commit 1f18da2

Please sign in to comment.