Ejemplo n.º 1
0
def get_bases(
        bases: List[pytd.Type]) -> Tuple[List[pytd_node.Node], Optional[int]]:
    """Collect base classes and namedtuple index."""

    bases_out = []
    namedtuple_index = None
    for i, p in enumerate(bases):
        if p.name and pytd_utils.MatchesFullName(p, _PROTOCOL_ALIASES):
            bases_out.append(pytd.NamedType("typing.Protocol"))
            if isinstance(p, pytd.GenericType):
                # From PEP 544: "`Protocol[T, S, ...]` is allowed as a shorthand for
                # `Protocol, Generic[T, S, ...]`."
                # https://www.python.org/dev/peps/pep-0544/#generic-protocols
                bases_out.append(
                    p.Replace(base_type=pytd.NamedType("typing.Generic")))
        elif isinstance(p, pytd.NamedType) and p.name == "typing.NamedTuple":
            if namedtuple_index is not None:
                raise ParseError(
                    "cannot inherit from bare NamedTuple more than once")
            namedtuple_index = i
            bases_out.append(p)
        elif isinstance(p, pytd.Type):
            bases_out.append(p)
        else:
            msg = f"Unexpected class base: {p}"
            raise ParseError(msg)

    return bases_out, namedtuple_index
Ejemplo n.º 2
0
def get_metaclass(keywords: List[ast3.AST], parents: List[pytd_node.Node]):
    """Scan keywords for a metaclass."""

    for k in keywords:
        keyword, value = k.arg, k.value
        if keyword not in ("metaclass", "total"):
            raise ParseError("Unexpected classdef kwarg %r" % keyword)
        elif keyword == "total" and not any(
                isinstance(parent, pytd.NamedType)
                and pytd_utils.MatchesFullName(parent, _TYPED_DICT_ALIASES)
                for parent in parents):
            raise ParseError(
                "'total' allowed as classdef kwarg only for TypedDict subclasses"
            )
        if keyword == "metaclass":
            return value
    return None
Ejemplo n.º 3
0
 def visit_AnnAssign(self, node):
   self.convert_node_annotations(node)
   name = node.target.id
   typ = node.annotation
   val = self.convert_node(node.value)
   msg = f"Default value for {name}: {typ.name} can only be '...', got {val}"
   if typ.name and pytd_utils.MatchesFullName(typ, _FINAL_IDS):
     if isinstance(node.value, types.Pyval):
       # to_pytd_literal raises an exception if the value is a float, but
       # checking upfront allows us to generate a nicer error message.
       if isinstance(node.value.value, float):
         msg = (f"Default value for {name}: Final can only be '...' or a "
                f"legal Literal parameter, got {val}")
       else:
         typ = node.value.to_pytd_literal()
         val = pytd.AnythingType()
     elif isinstance(val, pytd.NamedType):
       typ = pytd.Literal(val)
       val = pytd.AnythingType()
   if val and not types.is_any(val):
     raise ParseError(msg)
   return pytd.Constant(name, typ, val)
Ejemplo n.º 4
0
 def _matches_full_name(self, t, full_name):
     """Whether t.name matches full_name in format {module}.{member}."""
     return pytd_utils.MatchesFullName(t, full_name,
                                       self.module_info.module_name,
                                       self.aliases)
Ejemplo n.º 5
0
def _is_parameterized_protocol(t) -> bool:
    return (isinstance(t, pytd.GenericType)
            and pytd_utils.MatchesFullName(t.base_type, _PROTOCOL_ALIASES))