Skip to content
This repository has been archived by the owner on Aug 19, 2023. It is now read-only.

The declaration of ForwardRef in get_class_type_hints doesn't include is_class, which breaks evaluation on Python >=3.9.8 #176

Open
BarakW opened this issue Dec 7, 2021 · 0 comments

Comments

@BarakW
Copy link

BarakW commented Dec 7, 2021

As of python 3.9.8, _type_check will reject a ClassVar type hint if it's not in a class, but the declaration for ForwardRef here:

def get_class_type_hints(klass: Type, localns=None) -> Dict[str, Any]:
    """Return type hints for a class. Adapted from `typing.get_type_hints`, adds support for PEP 585 & PEP 604"""
    hints = {}
    for base in reversed(klass.__mro__):
        base_globals = sys.modules[base.__module__].__dict__
        base_globals['_Union'] = Union
        if sys.version_info < (3, 9):
            base_globals['_List'] = List
            base_globals['_Set'] = Set
            base_globals['_Type'] = Type
            base_globals['_Tuple'] = Tuple
            base_globals['_Dict'] = Dict
        ann = base.__dict__.get('__annotations__', {})
        for name, value in ann.items():
            if value is None:
                value = type(None)
            if isinstance(value, str):
                t = ast.parse(value, '<unknown>', 'eval')
                union_transformer = RewriteUnionTypes()
                t = union_transformer.visit(t)
                builtin_generics_transformer = RewriteBuiltinGenerics()
                if sys.version_info < (3, 9):
                    t = builtin_generics_transformer.visit(t)
                if builtin_generics_transformer.rewritten or union_transformer.rewritten:
                    # Note: ForwardRef raises a TypeError when given anything that isn't a string, so we need
                    # to compile & eval the ast here
                    code = compile(t, '<unknown>', 'eval')
                    hints[name] = eval(code, base_globals, localns)
                    continue
                else:
                    value = ForwardRef(value, is_argument=False)
            value = _eval_type(value, base_globals, localns)
            hints[name] = value
    return hints

Doesn't include a check for if value is a class, which will always cause a failure when the annotation is some variation of the ClassVar generic.

I'm only working on a project using this library and don't know it super closely, would it be enough to always pass in is_class=True?

@BarakW BarakW changed the title The declaration of ForwardRef in get_class_type_hints doesn't include is_class, which breaks evaluation post Python 3.9.8 The declaration of ForwardRef in get_class_type_hints doesn't include is_class, which breaks evaluation on Python >=3.9.8 Dec 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant