pythonfastapipydantic

Pydantic issue for tuple length


I have the following model in pydantic (Version 2.0.3)

from typing import Tuple
from pydantic import BaseModel

class Model(BaseModel):
    test_field: Tuple[int]

But when I enter

model = Model(test_field=(1,2))

I get as error:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "/Users/tobi/Documents/scraiber/z_legacy/fastapi_test_app/venv/lib/python3.10/site-packages/pydantic/main.py", line 150, in __init__
    __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
pydantic_core._pydantic_core.ValidationError: 1 validation error for Model
test_field
  Tuple should have at most 1 item after validation, not 2 [type=too_long, input_value=(1, 2), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.0.3/v/too_long

Do you know how I can fix that?


Solution

  • Following @Tim Robert's Answer, the linked PR suggests using the Ellipsis ... is the syntax you're after!

    https://github.com/pydantic/pydantic/pull/512/files

    class Model(BaseModel):
        test_field: Tuple[int, ...]
    
    >>> Model(test_field=(1,2))
    Model(test_field=(1, 2))
    

    Additionally, and though I don't think it's really advisable (prefer codegen or reconsider the design), you can generate and expand given an exact count of the fields

    count = 5
    class Model_Five(BaseModel):
        test_field: Tuple[*([int]*count)]
    
    >>> Model_Five(test_field=(1,2,3,4,5))
    Model_Five(test_field=(1, 2, 3, 4, 5))
    >>> Model_Five(test_field=(1,2,3,4))
    [..] omitted
    test_field.4
      Field required [type=missing, input_value=(1, 2, 3, 4), input_type=tuple]
        For further information visit https://docs.pydantic.dev/dev/errors/validation_errors/#missing
    

    Finally, there might be cases where you need a longer form like *(cls for _ in range(count)) (or the even more troublesome for sustainability *(some_class_factory() for _ in range(count))) to expressly avoid having the inner values refer to the same object