Skip to content

Infinite recursion with get_type_hints #667

Closed

Description

@vg0377467

I encountered one condition where calling get_type_hints causes infinite recursion when dealing with forward declaration and cyclic types.

Here's an example:

from typing import Union, List, get_type_hints

ValueList = List['Value']
Value = Union[str, ValueList]

class A:
    a: List[Value]

get_type_hints(A, globals(), locals())

This reaches the recursion limit as of 3.8.0b2.

It seems that the combining _GenericAlias with ForwardRef is what triggers this condition:

  • ForwardRef._evaluate sets __forward_value__ on its first call on a given instance
  • _GenericAlias tries to compare its args post evaluation
    If one of the arguments is a previously evaluated forward reference containing a cycle, then it will infinitely recurse in the hash function when building a frozen set for the comparison.

The above is, of course, a very artificial example, but I can imagine this happening a lot in code with trees or similar structures.
My initial reproduction case was using _eval_type to resolve forward references returned by get_args (side note: it would be nice to have a public function to do that).

Activity

  1. ilevkivskyi commented on Aug 9, 2019

    @ilevkivskyi
    Member

    Thanks for reporting! This looks like something worth fixing soon. Also this tracker is now used for the backport module on PyPI, could you please open an issue on the main https://bugs.python.org tracker?

  2. ilevkivskyi commented on Aug 9, 2019

    @ilevkivskyi
    Member

    (when opening the issue please don't forget to mention it here)

  3. vg0377467 commented on Aug 10, 2019

    @vg0377467
    Author

    I opened an issue on the main tracker:
    https://bugs.python.org/issue37806

  4. rfrowe commented on Mar 2, 2020

    @rfrowe
    Contributor

    Will the patch from python/cpython#15400 be applied here as suggested by @ilevkivskyi? The fix was merged 2019-09-13 however this issue still plagues get_type_hints in python 3.6 and 3.7. It also may not be possible without backporting the fix to cpython 3.6 and 3.7.

  5. gvanrossum commented on Mar 2, 2020

    @gvanrossum
    Member

    Perhaps you can speed it along by opening a PR against this repo containing the patch you link to?

  6. rfrowe commented on Mar 2, 2020

    @rfrowe
    Contributor

    @gvanrossum Thanks for the quick reply. The patch requires modifying __eq__ and __hash__ in ForwardRef. I now realize, as I'm using python 3.7, a patch to _ForwardRef in src/typing.py here won't help me. I'll have to make a backport PR to python/cpython.

    Since I resurrected this thread anyway, I'll go ahead and make a PR here with the patch anyway.

  7. ilevkivskyi commented on Mar 2, 2020

    @ilevkivskyi
    Member

    Backporting this here will not really help with 3.7, as stdlib module takes preference over installed one. Essentially this repo is now mostly about Python 2.

  8. rfrowe commented on Mar 2, 2020

    @rfrowe
    Contributor

    Yeah that's the conclusion I came to. I figured since I brought it up I may as well help people with python <3.5 who may run into this, so I'll make a PR here as well. I went ahead and made python/cpython#18751 to address my issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions