Pydantic: A Union[Dict[str, str], List[Any]] field parses dict, when it should parse List[str] for 2-character inputs

Created on 20 Jan 2021  路  1Comment  路  Source: samuelcolvin/pydantic

Checks

  • [x] I added a descriptive title to this issue
  • [x] I have searched (google, github) for similar issues and couldn't find anything
  • [x] I have read and followed the docs and still think this is a bug

Versions

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

             pydantic version: 1.7.3
            pydantic compiled: True
                 install path: /home/moose/.pyenv/versions/3.9.1/lib/python3.9/site-packages/pydantic
               python version: 3.9.1 (default, Jan 16 2021, 13:41:30)  [GCC 9.3.0]
                     platform: Linux-5.4.0-62-generic-x86_64-with-glibc2.31
     optional deps. installed: ['typing-extensions']

Bug

When I pass a List[str] with the string being 2 characters long (e.g. ["ab"]) to a field which is annotated with Union[Dict[str, str], List[Any]], I get a dictionary {"a": "b"} instead of ["ab"].

Example:

from typing import Union, List, Any, Dict

from pydantic import BaseModel


class Foo(BaseModel):
    values: Union[Dict[str, str], List[Any]]

class Foo2(BaseModel):
    values: Union[List[Any], Dict[str, str]]


print(Foo.parse_obj({"values": ["L1"]}))
print(Foo.parse_obj({"values": ["L11"]}))
print(Foo2.parse_obj({"values": ["L1"]}))

Results in:

values={'L': '1'}  # Unexpected - why do I get a dict?
values=['L11']  # expected value, but surprising after seeing output (1)
values=['L1']  # expected value, but surprising after seeing output (1)
bug

Most helpful comment

Hello @MartinThoma
Yes it's a very common issue on _pydantic_ as it tries to coerce the value with types inside the Union in order (so the first one will take precedence over the second one if possible).
So here it first tries to coerce ["L1"] with Dict[str, str], which works because dict(["11"]) == {'1': '1'}.
I'm working on a way to prevent this in https://github.com/samuelcolvin/pydantic/pull/2092. The whole behaviour will change in v2.
Please have a look at linked issues to this PR if you want more information

>All comments

Hello @MartinThoma
Yes it's a very common issue on _pydantic_ as it tries to coerce the value with types inside the Union in order (so the first one will take precedence over the second one if possible).
So here it first tries to coerce ["L1"] with Dict[str, str], which works because dict(["11"]) == {'1': '1'}.
I'm working on a way to prevent this in https://github.com/samuelcolvin/pydantic/pull/2092. The whole behaviour will change in v2.
Please have a look at linked issues to this PR if you want more information

Was this page helpful?
0 / 5 - 0 ratings

Related issues

demospace picture demospace  路  26Comments

jasonkuhrt picture jasonkuhrt  路  21Comments

dand-oss picture dand-oss  路  19Comments

sm-Fifteen picture sm-Fifteen  路  45Comments

samuelcolvin picture samuelcolvin  路  30Comments