Skip to content

Commit 11a1317

Browse files
committed
temp refactor for model fields to experiment with perf
1 parent 8bc4350 commit 11a1317

File tree

2 files changed

+60
-17
lines changed

2 files changed

+60
-17
lines changed

src/lookup_key.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,3 +601,47 @@ pub fn get_lookup_key(
601601
None => Ok(LookupKey::from_string(py, field_name)),
602602
}
603603
}
604+
605+
#[derive(Debug)]
606+
#[allow(clippy::struct_field_names)]
607+
pub struct LookupKeyCollection {
608+
by_name: LookupKey,
609+
by_alias: Option<LookupKey>,
610+
by_alias_then_name: Option<LookupKey>,
611+
}
612+
613+
impl LookupKeyCollection {
614+
pub fn new(py: Python, validation_alias: Option<Bound<'_, PyAny>>, field_name: &str) -> PyResult<Self> {
615+
let by_name = LookupKey::from_string(py, field_name);
616+
617+
if let Some(va) = validation_alias {
618+
let by_alias = Some(LookupKey::from_py(py, &va, None)?);
619+
let by_alias_then_name = Some(LookupKey::from_py(py, &va, Some(field_name))?);
620+
Ok(Self {
621+
by_name,
622+
by_alias,
623+
by_alias_then_name,
624+
})
625+
} else {
626+
Ok(Self {
627+
by_name,
628+
by_alias: None,
629+
by_alias_then_name: None,
630+
})
631+
}
632+
}
633+
634+
pub fn select(&self, validate_by_alias: bool, validate_by_name: bool) -> PyResult<&LookupKey> {
635+
let lookup_key_selection = match (validate_by_alias, validate_by_name) {
636+
(true, true) => self.by_alias_then_name.as_ref().unwrap_or(&self.by_name),
637+
(true, false) => self.by_alias.as_ref().unwrap_or(&self.by_name),
638+
(false, true) => &self.by_name,
639+
(false, false) => {
640+
// Note: we shouldn't hit this branch much, as this is enforced in `pydantic` with a `PydanticUserError`
641+
// at config creation time / validation function call time.
642+
return py_schema_err!("`validate_by_name` and `validate_by_alias` cannot both be set to `False`.");
643+
}
644+
};
645+
Ok(lookup_key_selection)
646+
}
647+
}

src/validators/model_fields.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ use crate::errors::LocItem;
1212
use crate::errors::{ErrorType, ErrorTypeDefaults, ValError, ValLineError, ValResult};
1313
use crate::input::ConsumeIterator;
1414
use crate::input::{BorrowInput, Input, ValidatedDict, ValidationMatch};
15-
use crate::lookup_key::get_lookup_key;
15+
use crate::lookup_key::LookupKeyCollection;
1616
use crate::tools::SchemaDict;
1717

1818
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, ValidationState, Validator};
1919

2020
#[derive(Debug)]
2121
struct Field {
2222
name: String,
23-
alias: Option<Py<PyAny>>,
23+
lookup_key_collection: LookupKeyCollection,
2424
name_py: Py<PyString>,
2525
validator: CombinedValidator,
2626
frozen: bool,
@@ -52,9 +52,11 @@ impl BuildValidator for ModelFieldsValidator {
5252
let py = schema.py();
5353

5454
let strict = is_strict(schema, config)?;
55-
let extra_behavior = ExtraBehavior::from_schema_or_config(py, schema, config, ExtraBehavior::Ignore)?;
55+
5656
let from_attributes = schema_or_config_same(schema, config, intern!(py, "from_attributes"))?.unwrap_or(false);
5757

58+
let extra_behavior = ExtraBehavior::from_schema_or_config(py, schema, config, ExtraBehavior::Ignore)?;
59+
5860
let extras_validator = match (schema.get_item(intern!(py, "extras_schema"))?, &extra_behavior) {
5961
(Some(v), ExtraBehavior::Allow) => Some(Box::new(build_validator(&v, config, definitions)?)),
6062
(Some(_), _) => return py_schema_err!("extras_schema can only be used if extra_behavior=allow"),
@@ -79,11 +81,12 @@ impl BuildValidator for ModelFieldsValidator {
7981
Err(err) => return py_schema_err!("Field \"{}\":\n {}", field_name, err),
8082
};
8183

84+
let validation_alias = field_info.get_item(intern!(py, "validation_alias"))?;
85+
let lookup_key_collection = LookupKeyCollection::new(py, validation_alias, field_name)?;
86+
8287
fields.push(Field {
8388
name: field_name.to_string(),
84-
alias: field_info
85-
.get_item(intern!(py, "validation_alias"))?
86-
.map(std::convert::Into::into),
89+
lookup_key_collection,
8790
name_py: field_name_py.into(),
8891
validator,
8992
frozen: field_info.get_as::<bool>(intern!(py, "frozen"))?.unwrap_or(false),
@@ -157,7 +160,7 @@ impl Validator for ModelFieldsValidator {
157160

158161
// we only care about which keys have been used if we're iterating over the object for extra after
159162
// the first pass
160-
let mut used_keys: Option<AHashSet<String>> =
163+
let mut used_keys: Option<AHashSet<&str>> =
161164
if self.extra_behavior == ExtraBehavior::Ignore || dict.is_py_get_attr() {
162165
None
163166
} else {
@@ -168,14 +171,10 @@ impl Validator for ModelFieldsValidator {
168171
let state = &mut state.rebind_extra(|extra| extra.data = Some(model_dict.clone()));
169172

170173
for field in &self.fields {
171-
let lookup_key = get_lookup_key(
172-
py,
173-
field.alias.as_ref(),
174-
validate_by_name,
175-
validate_by_alias,
176-
&field.name,
177-
)?;
178-
let op_key_value = match dict.get_item(&lookup_key) {
174+
let lookup_key = field
175+
.lookup_key_collection
176+
.select(validate_by_alias, validate_by_name)?;
177+
let op_key_value = match dict.get_item(lookup_key) {
179178
Ok(v) => v,
180179
Err(ValError::LineErrors(line_errors)) => {
181180
for err in line_errors {
@@ -189,7 +188,7 @@ impl Validator for ModelFieldsValidator {
189188
if let Some(ref mut used_keys) = used_keys {
190189
// key is "used" whether or not validation passes, since we want to skip this key in
191190
// extra logic either way
192-
used_keys.insert(lookup_path.first_key().to_string());
191+
used_keys.insert(lookup_path.first_key());
193192
}
194193
match field.validator.validate(py, value.borrow_input(), state) {
195194
Ok(value) => {
@@ -240,7 +239,7 @@ impl Validator for ModelFieldsValidator {
240239
if let Some(used_keys) = used_keys {
241240
struct ValidateToModelExtra<'a, 's, 'py> {
242241
py: Python<'py>,
243-
used_keys: AHashSet<String>,
242+
used_keys: AHashSet<&'a str>,
244243
errors: &'a mut Vec<ValLineError>,
245244
fields_set_vec: &'a mut Vec<Py<PyString>>,
246245
extra_behavior: ExtraBehavior,

0 commit comments

Comments
 (0)