Skip to content

Commit

Permalink
Metaclass improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p committed Feb 28, 2021
1 parent 0a7c641 commit 1211992
Showing 1 changed file with 59 additions and 10 deletions.
69 changes: 59 additions & 10 deletions astroid/brain/brain_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""Astroid hooks for typing.py support."""
import sys
import typing
from functools import lru_cache

from astroid import (
MANAGER,
Expand Down Expand Up @@ -96,6 +97,31 @@ def __getitem__(cls, value):
return cls
"""

ABC_METACLASS_TEMPLATE = """
from abc import ABCMeta
ABCMeta
"""


@lru_cache()
def create_typing_metaclass():
#  Needs to mock the __getitem__ class method so that
#  MutableSet[T] is acceptable
func_to_add = extract_node(GET_ITEM_TEMPLATE)

abc_meta = next(extract_node(ABC_METACLASS_TEMPLATE).infer())
typing_meta = nodes.ClassDef(
name="ABCMeta_typing",
lineno=abc_meta.lineno,
col_offset=abc_meta.col_offset,
parent=abc_meta.parent,
)
typing_meta.postinit(
bases=[extract_node(ABC_METACLASS_TEMPLATE)], body=[], decorators=None
)
typing_meta.locals["__getitem__"] = [func_to_add]
return typing_meta


def _looks_like_typing_alias(node: nodes.Call) -> bool:
"""
Expand All @@ -115,23 +141,46 @@ def _looks_like_typing_alias(node: nodes.Call) -> bool:


def infer_typing_alias(
node: nodes.Call, context: context.InferenceContext = None
) -> node_classes.NodeNG:
node: nodes.Call, ctx: context.InferenceContext = None
) -> typing.Optional[node_classes.NodeNG]:
"""
Infers the call to _alias function
:param node: call node
:param context: inference context
"""
if not isinstance(node, nodes.Call):
return
res = next(node.args[0].infer(context=context))
#  Needs to mock the __getitem__ class method so that
#  MutableSet[T] is acceptable
func_to_add = extract_node(GET_ITEM_TEMPLATE)
if res.metaclass():
res.metaclass().locals["__getitem__"] = [func_to_add]
return res
return None
res = next(node.args[0].infer(context=ctx))

if res != astroid.Uninferable and isinstance(res, nodes.ClassDef):
class_def = nodes.ClassDef(
name=res.name,
lineno=res.lineno,
col_offset=res.col_offset,
parent=res.parent,
)
class_def.postinit(
bases=res.bases,
body=res.body,
decorators=res.decorators,
metaclass=create_typing_metaclass(),
)
return class_def

if len(node.args) == 2 and isinstance(node.args[0], nodes.Attribute):
class_def = nodes.ClassDef(
name=node.args[0].attrname,
lineno=node.lineno,
col_offset=node.col_offset,
parent=node.parent,
)
class_def.postinit(
bases=[], body=[], decorators=None, metaclass=create_typing_metaclass()
)
return class_def

return None


MANAGER.register_transform(
Expand Down

0 comments on commit 1211992

Please sign in to comment.