Skip to content

Multiple RecursionErrors with self-referencing models #524

@khaeru

Description

@khaeru
  • OS: Ubuntu 19.04
  • Python version: 3.7.3 (default, Apr 3 2019, 05:39:12) [GCC 8.3.0]
  • Pydantic version: 0.25

The following code works:

from typing import Optional
from pydantic import BaseModel


class Foo(BaseModel):
    id: str
    parent: Optional['Foo'] = None
    child: Optional['Foo'] = None

    # 1:
    # class Config:
    #     validate_assignment = True

    def __contains__(self, other):
        return other is self or other in self.child


Foo.update_forward_refs()


items = []
for i in range(10):
    items.append(Foo(id='Object {}'.format(i)))

    if i > 0:
        # 2:
        # print(items[-1], items[-2])
        items[-1].parent = items[-2]
        items[-2].child = items[-1]

print(items[1] in items[0])

print(items[-1] in items[0])

However, RecursionError can be triggered in two trivial ways:

Uncommenting the lines at # 1: which set validate_assignment = True:

  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 473, in _iter
    yield k, self._get_value(v, by_alias=by_alias, skip_defaults=skip_defaults)
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 443, in _get_value
    return v.dict(by_alias=by_alias, skip_defaults=skip_defaults)
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 284, in dict
    return {get_key(k): v for k, v in self._iter(by_alias=by_alias, skip_defaults=skip_defaults)}
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 284, in <dictcomp>
    return {get_key(k): v for k, v in self._iter(by_alias=by_alias, skip_defaults=skip_defaults)}
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 473, in _iter
    yield k, self._get_value(v, by_alias=by_alias, skip_defaults=skip_defaults)
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 442, in _get_value
    if isinstance(v, BaseModel):
  File "/usr/lib/python3.7/abc.py", line 139, in __instancecheck__
    return _abc_instancecheck(cls, instance)
RecursionError: maximum recursion depth exceeded in comparison

Uncommenting the line at # 2: with the print(...) call:

  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/utils.py", line 144, in truncate
    v = repr(v)
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 502, in __repr__
    return f'<{self}>'
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 513, in __str__
    return self.to_string()
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 509, in to_string
    divider.join('{}={}'.format(k, truncate(v)) for k, v in self.__values__.items()),
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/main.py", line 509, in <genexpr>
    divider.join('{}={}'.format(k, truncate(v)) for k, v in self.__values__.items()),
  File "/home/khaeru/.local/lib/python3.7/site-packages/pydantic/utils.py", line 144, in truncate
    v = repr(v)
RecursionError: maximum recursion depth exceeded

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug V1Bug related to Pydantic V1.Xtopic-json schemaRelated to JSON Schema

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions