mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
fix: support empty tuple type (#2319)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Support empty tuple type
|
||||
+10
-8
@@ -452,18 +452,20 @@ class ModelField(Representation):
|
||||
|
||||
if issubclass(origin, Tuple): # type: ignore
|
||||
# origin == Tuple without item type
|
||||
if not get_args(self.type_):
|
||||
args = get_args(self.type_)
|
||||
if not args: # plain tuple
|
||||
self.type_ = Any
|
||||
self.shape = SHAPE_TUPLE_ELLIPSIS
|
||||
elif len(args) == 2 and args[1] is Ellipsis: # e.g. Tuple[int, ...]
|
||||
self.type_ = args[0]
|
||||
self.shape = SHAPE_TUPLE_ELLIPSIS
|
||||
elif args == ((),): # Tuple[()] means empty tuple
|
||||
self.shape = SHAPE_TUPLE
|
||||
self.type_ = Any
|
||||
self.sub_fields = []
|
||||
else:
|
||||
self.shape = SHAPE_TUPLE
|
||||
self.sub_fields = []
|
||||
for i, t in enumerate(get_args(self.type_)):
|
||||
if t is Ellipsis:
|
||||
self.type_ = get_args(self.type_)[0]
|
||||
self.shape = SHAPE_TUPLE_ELLIPSIS
|
||||
return
|
||||
self.sub_fields.append(self._create_sub_type(t, f'{self.name}_{i}'))
|
||||
self.sub_fields = [self._create_sub_type(t, f'{self.name}_{i}') for i, t in enumerate(args)]
|
||||
return
|
||||
|
||||
if issubclass(origin, List):
|
||||
|
||||
@@ -194,26 +194,38 @@ def test_tuple():
|
||||
|
||||
def test_tuple_more():
|
||||
class Model(BaseModel):
|
||||
empty_tuple: Tuple[()]
|
||||
simple_tuple: tuple = None
|
||||
tuple_of_different_types: Tuple[int, float, str, bool] = None
|
||||
|
||||
m = Model(simple_tuple=[1, 2, 3, 4], tuple_of_different_types=[4, 3, 2, 1])
|
||||
assert m.dict() == {'simple_tuple': (1, 2, 3, 4), 'tuple_of_different_types': (4, 3.0, '2', True)}
|
||||
m = Model(empty_tuple=[], simple_tuple=[1, 2, 3, 4], tuple_of_different_types=[4, 3, 2, 1])
|
||||
assert m.dict() == {
|
||||
'empty_tuple': (),
|
||||
'simple_tuple': (1, 2, 3, 4),
|
||||
'tuple_of_different_types': (4, 3.0, '2', True),
|
||||
}
|
||||
|
||||
|
||||
def test_tuple_length_error():
|
||||
class Model(BaseModel):
|
||||
v: Tuple[int, float, bool]
|
||||
w: Tuple[()]
|
||||
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
Model(v=[1, 2])
|
||||
Model(v=[1, 2], w=[1])
|
||||
assert exc_info.value.errors() == [
|
||||
{
|
||||
'loc': ('v',),
|
||||
'msg': 'wrong tuple length 2, expected 3',
|
||||
'type': 'value_error.tuple.length',
|
||||
'ctx': {'actual_length': 2, 'expected_length': 3},
|
||||
}
|
||||
},
|
||||
{
|
||||
'loc': ('w',),
|
||||
'msg': 'wrong tuple length 1, expected 0',
|
||||
'type': 'value_error.tuple.length',
|
||||
'ctx': {'actual_length': 1, 'expected_length': 0},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user