Skip to content

gh-125618: Make FORWARDREF format succeed more often #132818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

@DavidCEllis
Copy link
Contributor

Looks like this works in the case where the object is defined globally, but this still manages to fail if the object used in the annotation is defined (or even potentially redefined) within the function.

Repro:

from annotationlib import get_annotations, Format

def boom():
    obj = object()
    class RaisesAttributeError:
        attriberr: obj.missing
    get_annotations(RaisesAttributeError, format=Format.FORWARDREF)

boom()

Output:

Traceback (most recent call last):
  File "C:\Users\ducks\Source\cpython\.cache\annotation_examine.py", line 9, in <module>
    boom()
    ~~~~^^
  File "C:\Users\ducks\Source\cpython\.cache\annotation_examine.py", line 7, in boom
    get_annotations(RaisesAttributeError, format=Format.FORWARDREF)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ducks\Source\cpython\Lib\annotationlib.py", line 778, in get_annotations
    ann = _get_and_call_annotate(obj, format)
  File "C:\Users\ducks\Source\cpython\Lib\annotationlib.py", line 902, in _get_and_call_annotate
    ann = call_annotate_function(annotate, format, owner=obj)
  File "C:\Users\ducks\Source\cpython\Lib\annotationlib.py", line 629, in call_annotate_function
    result = func(Format.VALUE_WITH_FAKE_GLOBALS)
  File "C:\Users\ducks\Source\cpython\.cache\annotation_examine.py", line 6, in __annotate__
    attriberr: obj.missing
               ^^^^^^^^^^^
  File "C:\Users\ducks\Source\cpython\Lib\annotationlib.py", line 380, in __getattr__
    return self.__make_new(ast.Attribute(self.__get_ast(), attr))
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ducks\Source\cpython\Lib\annotationlib.py", line 358, in __make_new
    self.__stringifier_dict__.stringifiers.append(stringifier)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'builtin_function_or_method' object has no attribute 'stringifiers'

This came up because this is how I'd written my test case for this (writing the test case was actually as far as I'd gone, because the first test case raised the other issue).

    def test_attributeerror_handled(self):
        class MissingAttrib:
            pass
        
        class RaisesAttributeError:
            attriberr: MissingAttrib.missing

        with self.assertRaises(AttributeError):
            get_annotations(RaisesAttributeError, format=Format.VALUE)

        self.assertEqual(
            get_annotations(RaisesAttributeError, format=Format.FORWARDREF),
            {
                "attriberr": support.EqualToForwardRef(
                    "MissingAttrib.missing", 
                    owner=RaisesAttributeError,
                    is_class=True,
                )
            }
        )

        self.assertEqual(
            get_annotations(RaisesAttributeError, format=Format.STRING),
            {"attriberr": "MissingAttrib.missing"}
        )

@JelleZijlstra
Copy link
Member Author

Thanks! This was a silly bug that also broke test_pydoc, I will add your case as a test case so we catch this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants