Skip to content

Commit 74b74d5

Browse files
authored
Add __pydantic_private__ (#640)
1 parent 7c6f326 commit 74b74d5

15 files changed

+67
-53
lines changed

pydantic_core/core_schema.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,7 +2912,12 @@ def model_schema(
29122912
from pydantic_core import CoreConfig, SchemaValidator, core_schema
29132913
29142914
class MyModel:
2915-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
2915+
__slots__ = (
2916+
'__dict__',
2917+
'__pydantic_fields_set__',
2918+
'__pydantic_extra__',
2919+
'__pydantic_private__',
2920+
)
29162921
29172922
schema = core_schema.model_schema(
29182923
cls=MyModel,
@@ -3407,7 +3412,12 @@ def json_schema(
34073412
)
34083413
34093414
class MyModel:
3410-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
3415+
__slots__ = (
3416+
'__dict__',
3417+
'__pydantic_fields_set__',
3418+
'__pydantic_extra__',
3419+
'__pydantic_private__',
3420+
)
34113421
field_a: str
34123422
field_b: bool
34133423

src/validators/model.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const ROOT_FIELD: &str = "root";
2020
const DUNDER_DICT: &str = "__dict__";
2121
const DUNDER_FIELDS_SET_KEY: &str = "__pydantic_fields_set__";
2222
const DUNDER_MODEL_EXTRA_KEY: &str = "__pydantic_extra__";
23+
const DUNDER_MODEL_PRIVATE_KEY: &str = "__pydantic_private__";
2324

2425
#[derive(Debug, Clone)]
2526
pub(super) enum Revalidate {
@@ -363,6 +364,7 @@ fn set_model_attrs(instance: &PyAny, model_dict: &PyAny, model_extra: &PyAny, fi
363364
let py = instance.py();
364365
force_setattr(py, instance, intern!(py, DUNDER_DICT), model_dict)?;
365366
force_setattr(py, instance, intern!(py, DUNDER_MODEL_EXTRA_KEY), model_extra)?;
367+
force_setattr(py, instance, intern!(py, DUNDER_MODEL_PRIVATE_KEY), py.None())?;
366368
force_setattr(py, instance, intern!(py, DUNDER_FIELDS_SET_KEY), fields_set)?;
367369
Ok(())
368370
}

tests/benchmarks/complete_schema.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
def schema(*, strict: bool = False) -> dict:
22
class MyModel:
33
# __slots__ is not required, but it avoids __pydantic_fields_set__ falling into __dict__
4-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
4+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
55

66
def append_func(input_value, info):
77
return f'{input_value} Changed'

tests/benchmarks/test_micro_benchmarks.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class PydanticModel(BaseModel):
4141
@pytest.fixture(scope='class')
4242
def core_validator_fs(self):
4343
class CoreModel:
44-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
44+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
4545

4646
return SchemaValidator(
4747
{
@@ -101,7 +101,7 @@ class TestModelLarge:
101101
@pytest.fixture(scope='class')
102102
def core_model_validator(self):
103103
class CoreModel:
104-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
104+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
105105

106106
return SchemaValidator(
107107
{
@@ -193,7 +193,7 @@ def test_small_class_core_dict(benchmark):
193193
def test_small_class_core_model(benchmark):
194194
class MyCoreModel:
195195
# this is not required, but it avoids `__pydantic_fields_set__` being included in `__dict__`
196-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
196+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
197197
# these are here just as decoration
198198
name: str
199199
age: int
@@ -344,7 +344,7 @@ class PydanticBranch(BaseModel):
344344
def test_definition_model_core(definition_model_data, benchmark):
345345
class CoreBranch:
346346
# this is not required, but it avoids `__pydantic_fields_set__` being included in `__dict__`
347-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
347+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
348348

349349
v = SchemaValidator(
350350
{
@@ -678,7 +678,7 @@ def test_many_models_core_dict(benchmark):
678678
@pytest.mark.benchmark(group='List[SimpleMode]')
679679
def test_many_models_core_model(benchmark):
680680
class MyCoreModel:
681-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
681+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
682682

683683
v = SchemaValidator(
684684
{
@@ -745,7 +745,7 @@ class PydanticModel(BaseModel):
745745
@pytest.fixture(scope='class')
746746
def core_validator(self):
747747
class CoreModel:
748-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
748+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
749749

750750
return SchemaValidator(
751751
{
@@ -1234,7 +1234,7 @@ def test_definition_out_of_tree(benchmark):
12341234
@pytest.mark.benchmark(group='model_instance')
12351235
def test_model_instance(benchmark):
12361236
class MyModel:
1237-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
1237+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
12381238

12391239
def __init__(self, **d):
12401240
self.__dict__ = d
@@ -1271,7 +1271,7 @@ def __instancecheck__(self, instance) -> bool:
12711271
return hasattr(instance, '__pydantic_validator__') and super().__instancecheck__(instance)
12721272

12731273
class BaseModel(metaclass=MyMeta):
1274-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
1274+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
12751275
__pydantic_validator__ = True
12761276

12771277
def __init__(self, **d):

tests/benchmarks/test_serialization_micro.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class PydanticModel(BaseModel):
2323
@pytest.fixture(scope='class')
2424
def core_schema(self):
2525
class CoreModel:
26-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
26+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
2727

2828
return {
2929
'type': 'model',
@@ -335,7 +335,7 @@ def test_core_model_json_extra(benchmark, basic_model_serializer_extra):
335335

336336

337337
class FieldsSetModel:
338-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
338+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
339339

340340
def __init__(self, **kwargs):
341341
for key, value in kwargs.items():

tests/serializers/test_any.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def test_exclude_dict(any_serializer):
258258

259259
class FieldsSetModel:
260260
__pydantic_serializer__ = 42
261-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
261+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
262262

263263
def __init__(self, **kwargs):
264264
fields = {}

tests/serializers/test_model.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ def test_exclude_none():
251251

252252

253253
class FieldsSetModel:
254-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
254+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
255255

256256
def __init__(self, **kwargs):
257257
for key, value in kwargs.items():
@@ -756,7 +756,7 @@ def random_n(self) -> int:
756756
def test_extra():
757757
class MyModel:
758758
# this is not required, but it avoids `__pydantic_fields_set__` being included in `__dict__`
759-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
759+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
760760
field_a: str
761761
field_b: int
762762

@@ -813,7 +813,7 @@ class MyModel:
813813
def test_extra_config():
814814
class MyModel:
815815
# this is not required, but it avoids `__pydantic_fields_set__` being included in `__dict__`
816-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
816+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
817817
field_a: str
818818
field_b: int
819819

tests/test_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def test_field_priority_arg():
3434

3535
class MyModel:
3636
# this is not required, but it avoids `__pydantic_fields_set__` being included in `__dict__`
37-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
37+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
3838

3939

4040
def test_on_model_class():

tests/test_misc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_custom_title():
9898
def test_validation_error_multiple():
9999
class MyModel:
100100
# this is not required, but it avoids `__pydantic_fields_set__` being included in `__dict__`
101-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
101+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
102102
field_a: str
103103
field_b: int
104104

tests/test_schema_functions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def make_5():
1717

1818

1919
class MyModel:
20-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
20+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
2121

2222

2323
@dataclasses.dataclass

tests/validators/test_definitions_recursive.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ class Bar:
236236
def test_model_class():
237237
class Branch:
238238
# this is not required, but it avoids `__pydantic_fields_set__` being included in `__dict__`
239-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
239+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
240240
# these are here just as decoration
241241
width: int
242242
branch: Optional['Branch']

tests/validators/test_function.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ def f(input_value):
462462
return input_value
463463

464464
class Model:
465-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
465+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
466466
field_a: str
467467

468468
v = SchemaValidator(
@@ -785,7 +785,7 @@ def f(input_value: Any, info: core_schema.ValidationInfo) -> Any:
785785

786786
def test_non_model_field_wrap_validator_tries_to_access_field_info() -> None:
787787
class Model:
788-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
788+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
789789
x: str
790790

791791
def f(input_value: Any, val: core_schema.ValidatorFunctionWrapHandler, info: core_schema.ValidationInfo) -> Any:
@@ -867,7 +867,7 @@ def test_model_root_function_assignment(mode: str, calls1: Any, calls2: Any):
867867
calls: list[Any] = []
868868

869869
class Model:
870-
__slots__ = '__dict__', '__pydantic_extra__', '__pydantic_fields_set__'
870+
__slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__'
871871
x: str
872872
y: int
873873

0 commit comments

Comments
 (0)