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
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
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)
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)
def _is_parameterized_protocol(t) -> bool: return (isinstance(t, pytd.GenericType) and pytd_utils.MatchesFullName(t.base_type, _PROTOCOL_ALIASES))