Skip to content

Commit d10493e

Browse files
committed
Add hide_input to ValidationError
1 parent 26fa27d commit d10493e

File tree

11 files changed

+199
-21
lines changed

11 files changed

+199
-21
lines changed

pydantic_core/_pydantic_core.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,10 @@ class SchemaError(Exception):
173173
class ValidationError(ValueError):
174174
@staticmethod
175175
def from_exception_data(
176-
title: str, errors: 'list[InitErrorDetails]', error_mode: Literal['python', 'json'] = 'python'
176+
title: str,
177+
errors: 'list[InitErrorDetails]',
178+
error_mode: Literal['python', 'json'] = 'python',
179+
hide_input: bool = False,
177180
) -> ValidationError:
178181
"""
179182
Provisory constructor for a Validation Error.

pydantic_core/core_schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class CoreConfig(TypedDict, total=False):
5151
# the config options are used to customise serialization to JSON
5252
ser_json_timedelta: Literal['iso8601', 'float'] # default: 'iso8601'
5353
ser_json_bytes: Literal['utf8', 'base64'] # default: 'utf8'
54+
hide_input_in_errors: bool
5455

5556

5657
IncExCall: TypeAlias = 'set[int | str] | dict[int | str, IncExCall] | None'

src/build_tools.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl SchemaError {
140140
match error {
141141
ValError::LineErrors(raw_errors) => {
142142
let line_errors = raw_errors.into_iter().map(|e| e.into_py(py)).collect();
143-
let validation_error = ValidationError::new(line_errors, "Schema".to_object(py), ErrorMode::Python);
143+
let validation_error = ValidationError::new(line_errors, "Schema".to_object(py), ErrorMode::Python, false);
144144
let schema_error = SchemaError(SchemaErrorEnum::ValidationError(validation_error));
145145
match Py::new(py, schema_error) {
146146
Ok(err) => PyErr::from_value(err.into_ref(py)),
@@ -177,21 +177,21 @@ impl SchemaError {
177177
fn errors(&self, py: Python) -> PyResult<Py<PyList>> {
178178
match &self.0 {
179179
SchemaErrorEnum::Message(_) => Ok(PyList::empty(py).into_py(py)),
180-
SchemaErrorEnum::ValidationError(error) => error.errors(py, false, true),
180+
SchemaErrorEnum::ValidationError(error) => error.errors(py, false, false),
181181
}
182182
}
183183

184184
fn __str__(&self, py: Python) -> String {
185185
match &self.0 {
186186
SchemaErrorEnum::Message(message) => message.to_owned(),
187-
SchemaErrorEnum::ValidationError(error) => error.display(py, Some("Invalid Schema:")),
187+
SchemaErrorEnum::ValidationError(error) => error.display(py, Some("Invalid Schema:"), false),
188188
}
189189
}
190190

191191
fn __repr__(&self, py: Python) -> String {
192192
match &self.0 {
193193
SchemaErrorEnum::Message(message) => format!("SchemaError({message:?})"),
194-
SchemaErrorEnum::ValidationError(error) => error.display(py, Some("Invalid Schema:")),
194+
SchemaErrorEnum::ValidationError(error) => error.display(py, Some("Invalid Schema:"), false),
195195
}
196196
}
197197
}

src/errors/validation_exception.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,16 @@ pub struct ValidationError {
3131
line_errors: Vec<PyLineError>,
3232
error_mode: ErrorMode,
3333
title: PyObject,
34+
hide_input: bool,
3435
}
3536

3637
impl ValidationError {
37-
pub fn new(line_errors: Vec<PyLineError>, title: PyObject, error_mode: ErrorMode) -> Self {
38+
pub fn new(line_errors: Vec<PyLineError>, title: PyObject, error_mode: ErrorMode, hide_input: bool) -> Self {
3839
Self {
3940
line_errors,
4041
title,
4142
error_mode,
43+
hide_input,
4244
}
4345
}
4446

@@ -48,6 +50,7 @@ impl ValidationError {
4850
error_mode: ErrorMode,
4951
error: ValError,
5052
outer_location: Option<LocItem>,
53+
hide_input: bool,
5154
) -> PyErr {
5255
match error {
5356
ValError::LineErrors(raw_errors) => {
@@ -58,7 +61,7 @@ impl ValidationError {
5861
.collect(),
5962
None => raw_errors.into_iter().map(|e| e.into_py(py)).collect(),
6063
};
61-
let validation_error = Self::new(line_errors, title, error_mode);
64+
let validation_error = Self::new(line_errors, title, error_mode, hide_input);
6265
match Py::new(py, validation_error) {
6366
Ok(err) => PyErr::from_value(err.into_ref(py)),
6467
Err(err) => err,
@@ -69,9 +72,9 @@ impl ValidationError {
6972
}
7073
}
7174

72-
pub fn display(&self, py: Python, prefix_override: Option<&'static str>) -> String {
75+
pub fn display(&self, py: Python, prefix_override: Option<&'static str>, hide_input: bool) -> String {
7376
let url_prefix = get_url_prefix(py, include_url_env(py));
74-
let line_errors = pretty_py_line_errors(py, &self.error_mode, self.line_errors.iter(), url_prefix);
77+
let line_errors = pretty_py_line_errors(py, &self.error_mode, self.line_errors.iter(), url_prefix, hide_input);
7578
if let Some(prefix) = prefix_override {
7679
format!("{prefix}\n{line_errors}")
7780
} else {
@@ -129,13 +132,18 @@ impl ValidationError {
129132
title: PyObject,
130133
line_errors: &PyList,
131134
error_mode: Option<&str>,
135+
hide_input: Option<bool>,
132136
) -> PyResult<Py<Self>> {
133137
Py::new(
134138
py,
135139
Self {
136140
line_errors: line_errors.iter().map(PyLineError::try_from).collect::<PyResult<_>>()?,
137141
title,
138142
error_mode: ErrorMode::try_from(error_mode)?,
143+
hide_input: match hide_input {
144+
Some(t) => t,
145+
None => false,
146+
},
139147
},
140148
)
141149
}
@@ -210,7 +218,7 @@ impl ValidationError {
210218
}
211219

212220
fn __repr__(&self, py: Python) -> String {
213-
self.display(py, None)
221+
self.display(py, None, self.hide_input)
214222
}
215223

216224
fn __str__(&self, py: Python) -> String {
@@ -238,9 +246,10 @@ pub fn pretty_py_line_errors<'a>(
238246
error_mode: &ErrorMode,
239247
line_errors_iter: impl Iterator<Item = &'a PyLineError>,
240248
url_prefix: Option<&str>,
249+
hide_input: bool,
241250
) -> String {
242251
line_errors_iter
243-
.map(|i| i.pretty(py, error_mode, url_prefix))
252+
.map(|i| i.pretty(py, error_mode, url_prefix, hide_input))
244253
.collect::<Result<Vec<_>, _>>()
245254
.unwrap_or_else(|err| vec![format!("[error formatting line errors: {err}]")])
246255
.join("\n")
@@ -349,7 +358,7 @@ impl PyLineError {
349358
Ok(dict.into_py(py))
350359
}
351360

352-
fn pretty(&self, py: Python, error_mode: &ErrorMode, url_prefix: Option<&str>) -> Result<String, fmt::Error> {
361+
fn pretty(&self, py: Python, error_mode: &ErrorMode, url_prefix: Option<&str>, hide_input:bool) -> Result<String, fmt::Error> {
353362
let mut output = String::with_capacity(200);
354363
write!(output, "{}", self.location)?;
355364

@@ -359,12 +368,15 @@ impl PyLineError {
359368
};
360369
write!(output, " {message} [type={}", self.error_type.type_string())?;
361370

362-
let input_value = self.input_value.as_ref(py);
363-
let input_str = safe_repr(input_value);
364-
truncate_input_value!(output, input_str);
371+
println!("{}", hide_input);
372+
if !hide_input {
373+
let input_value = self.input_value.as_ref(py);
374+
let input_str = safe_repr(input_value);
375+
truncate_input_value!(output, input_str);
365376

366-
if let Ok(type_) = input_value.get_type().name() {
367-
write!(output, ", input_type={type_}")?;
377+
if let Ok(type_) = input_value.get_type().name() {
378+
write!(output, ", input_type={type_}")?;
379+
}
368380
}
369381
if let Some(url_prefix) = url_prefix {
370382
match self.error_type {

src/validators/function.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ macro_rules! impl_build {
4646
function_name(function)?,
4747
validator.get_name()
4848
);
49+
let config_hide_input = match config {
50+
Some(c) => c.get_item("hide_input_in_errors"),
51+
None => None,
52+
};
53+
let hide_input = match config_hide_input {
54+
Some(t) => t.is_true().unwrap_or(false),
55+
None => false,
56+
};
4957
Ok(Self {
5058
validator: Box::new(validator),
5159
func: function.into_py(py),
@@ -56,6 +64,7 @@ macro_rules! impl_build {
5664
name,
5765
is_field_validator,
5866
info_arg,
67+
hide_input,
5968
}
6069
.into())
6170
}
@@ -127,6 +136,7 @@ pub struct FunctionBeforeValidator {
127136
name: String,
128137
is_field_validator: bool,
129138
info_arg: bool,
139+
hide_input: bool,
130140
}
131141

132142
impl_build!(FunctionBeforeValidator, "function-before");
@@ -160,6 +170,7 @@ pub struct FunctionAfterValidator {
160170
name: String,
161171
is_field_validator: bool,
162172
info_arg: bool,
173+
hide_input: bool,
163174
}
164175

165176
impl_build!(FunctionAfterValidator, "function-after");
@@ -262,6 +273,7 @@ pub struct FunctionWrapValidator {
262273
name: String,
263274
is_field_validator: bool,
264275
info_arg: bool,
276+
hide_input: bool
265277
}
266278

267279
impl_build!(FunctionWrapValidator, "function-wrap");
@@ -301,6 +313,7 @@ impl Validator for FunctionWrapValidator {
301313
definitions,
302314
extra,
303315
recursion_guard,
316+
self.hide_input,
304317
),
305318
};
306319
self._validate(
@@ -329,6 +342,7 @@ impl Validator for FunctionWrapValidator {
329342
definitions,
330343
extra,
331344
recursion_guard,
345+
self.hide_input,
332346
),
333347
updated_field_name: field_name.to_string(),
334348
updated_field_value: field_value.to_object(py),

src/validators/generator.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub struct GeneratorValidator {
1818
min_length: Option<usize>,
1919
max_length: Option<usize>,
2020
name: String,
21+
hide_input: bool,
2122
}
2223

2324
impl BuildValidator for GeneratorValidator {
@@ -33,11 +34,20 @@ impl BuildValidator for GeneratorValidator {
3334
Some(ref v) => format!("{}[{}]", Self::EXPECTED_TYPE, v.get_name()),
3435
None => format!("{}[any]", Self::EXPECTED_TYPE),
3536
};
37+
let config_hide_input = match config {
38+
Some(c) => c.get_item("hide_input_in_errors"),
39+
None => None,
40+
};
41+
let hide_input = match config_hide_input {
42+
Some(t) => t.is_true().unwrap_or(false),
43+
None => false,
44+
};
3645
Ok(Self {
3746
item_validator,
3847
name,
3948
min_length: schema.get_as(pyo3::intern!(schema.py(), "min_length"))?,
4049
max_length: schema.get_as(pyo3::intern!(schema.py(), "max_length"))?,
50+
hide_input: hide_input,
4151
}
4252
.into())
4353
}
@@ -56,13 +66,14 @@ impl Validator for GeneratorValidator {
5666
let validator = self
5767
.item_validator
5868
.as_ref()
59-
.map(|v| InternalValidator::new(py, "ValidatorIterator", v, definitions, extra, recursion_guard));
69+
.map(|v| InternalValidator::new(py, "ValidatorIterator", v, definitions, extra, recursion_guard, self.hide_input));
6070

6171
let v_iterator = ValidatorIterator {
6272
iterator,
6373
validator,
6474
min_length: self.min_length,
6575
max_length: self.max_length,
76+
hide_input: self.hide_input,
6677
};
6778
Ok(v_iterator.into_py(py))
6879
}
@@ -98,6 +109,7 @@ struct ValidatorIterator {
98109
validator: Option<InternalValidator>,
99110
min_length: Option<usize>,
100111
max_length: Option<usize>,
112+
hide_input: bool,
101113
}
102114

103115
#[pymethods]
@@ -109,6 +121,7 @@ impl ValidatorIterator {
109121
fn __next__(mut slf: PyRefMut<'_, Self>, py: Python) -> PyResult<Option<PyObject>> {
110122
let min_length = slf.min_length;
111123
let max_length = slf.max_length;
124+
let hide_input = slf.hide_input;
112125
let Self {
113126
validator, iterator, ..
114127
} = &mut *slf;
@@ -133,6 +146,7 @@ impl ValidatorIterator {
133146
ErrorMode::Python,
134147
val_error,
135148
None,
149+
hide_input,
136150
));
137151
}
138152
}
@@ -157,6 +171,7 @@ impl ValidatorIterator {
157171
ErrorMode::Python,
158172
val_error,
159173
None,
174+
hide_input,
160175
));
161176
}
162177
}
@@ -203,6 +218,7 @@ pub struct InternalValidator {
203218
self_instance: Option<PyObject>,
204219
recursion_guard: RecursionGuard,
205220
validation_mode: InputType,
221+
hide_input: bool,
206222
}
207223

208224
impl fmt::Debug for InternalValidator {
@@ -219,6 +235,7 @@ impl InternalValidator {
219235
definitions: &[CombinedValidator],
220236
extra: &Extra,
221237
recursion_guard: &RecursionGuard,
238+
hide_input: bool,
222239
) -> Self {
223240
Self {
224241
name: name.to_string(),
@@ -230,6 +247,7 @@ impl InternalValidator {
230247
self_instance: extra.self_instance.map(|d| d.into_py(py)),
231248
recursion_guard: recursion_guard.clone(),
232249
validation_mode: extra.mode,
250+
hide_input: hide_input,
233251
}
234252
}
235253

@@ -261,7 +279,7 @@ impl InternalValidator {
261279
&mut self.recursion_guard,
262280
)
263281
.map_err(|e| {
264-
ValidationError::from_val_error(py, self.name.to_object(py), ErrorMode::Python, e, outer_location)
282+
ValidationError::from_val_error(py, self.name.to_object(py), ErrorMode::Python, e, outer_location, self.hide_input)
265283
})
266284
}
267285

@@ -286,7 +304,7 @@ impl InternalValidator {
286304
self.validator
287305
.validate(py, input, &extra, &self.definitions, &mut self.recursion_guard)
288306
.map_err(|e| {
289-
ValidationError::from_val_error(py, self.name.to_object(py), ErrorMode::Python, e, outer_location)
307+
ValidationError::from_val_error(py, self.name.to_object(py), ErrorMode::Python, e, outer_location, self.hide_input)
290308
})
291309
}
292310
}

src/validators/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub struct SchemaValidator {
6565
schema: PyObject,
6666
#[pyo3(get)]
6767
title: PyObject,
68+
hide_input: bool,
6869
}
6970

7071
#[pymethods]
@@ -90,11 +91,20 @@ impl SchemaValidator {
9091
Some(t) => t.into_py(py),
9192
None => validator.get_name().into_py(py),
9293
};
94+
let config_hide_input = match config {
95+
Some(c) => c.get_item("hide_input_in_errors"),
96+
None => None,
97+
};
98+
let hide_input = match config_hide_input {
99+
Some(t) => t.is_true().unwrap_or(false),
100+
None => false,
101+
};
93102
Ok(Self {
94103
validator,
95104
definitions,
96105
schema: schema.into_py(py),
97106
title,
107+
hide_input: hide_input,
98108
})
99109
}
100110

@@ -227,7 +237,7 @@ impl SchemaValidator {
227237
}
228238

229239
fn prepare_validation_err(&self, py: Python, error: ValError, error_mode: ErrorMode) -> PyErr {
230-
ValidationError::from_val_error(py, self.title.clone_ref(py), error_mode, error, None)
240+
ValidationError::from_val_error(py, self.title.clone_ref(py), error_mode, error, None, self.hide_input)
231241
}
232242
}
233243

@@ -283,6 +293,7 @@ impl<'py> SelfValidator<'py> {
283293
definitions,
284294
schema: py.None(),
285295
title: "Self Schema".into_py(py),
296+
hide_input: false,
286297
})
287298
}
288299
}

0 commit comments

Comments
 (0)