Пример #1
0
 def _parameterized_type(self, base_type, parameters):
   """Return a parameterized type."""
   if self._is_literal_base_type(base_type):
     return types.pytd_literal(parameters)
   elif any(isinstance(p, types.Constant) for p in parameters):
     parameters = ", ".join(
         p.repr_str() if isinstance(p, types.Constant) else "_"
         for p in parameters)
     raise ParseError(
         "%s[%s] not supported" % (pytd_utils.Print(base_type), parameters))
   elif pytdgen.is_any(base_type):
     return pytd.AnythingType()
   elif len(parameters) == 2 and parameters[-1] is self.ELLIPSIS and (
       not self._is_callable_base_type(base_type)):
     element_type = parameters[0]
     if element_type is self.ELLIPSIS:
       raise ParseError("[..., ...] not supported")
     return pytd.GenericType(base_type=base_type, parameters=(element_type,))
   else:
     parameters = tuple(pytd.AnythingType() if p is self.ELLIPSIS else p
                        for p in parameters)
     if self._is_tuple_base_type(base_type):
       return pytdgen.heterogeneous_tuple(base_type, parameters)
     elif self._is_callable_base_type(base_type):
       return pytdgen.pytd_callable(base_type, parameters)
     else:
       assert parameters
       return pytd.GenericType(base_type=base_type, parameters=parameters)
Пример #2
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
Пример #3
0
def _split_definitions(defs: List[Any]):
    """Return [constants], [functions] given a mixed list of definitions."""
    constants = []
    functions = []
    aliases = []
    slots = None
    classes = []
    for d in defs:
        if isinstance(d, pytd.Class):
            classes.append(d)
        elif isinstance(d, pytd.Constant):
            if d.name == "__slots__":
                pass  # ignore definitions of __slots__ as a type
            else:
                constants.append(d)
        elif isinstance(d, function.NameAndSig):
            functions.append(d)
        elif isinstance(d, pytd.Alias):
            aliases.append(d)
        elif isinstance(d, types.SlotDecl):
            if slots is not None:
                raise ParseError("Duplicate __slots__ declaration")
            slots = d.slots
        elif isinstance(d, types.Ellipsis):
            pass
        elif isinstance(d, ast3.Expr):
            raise ParseError("Unexpected expression").at(d)
        else:
            msg = "Unexpected definition"
            lineno = None
            if isinstance(d, ast3.AST):
                lineno = getattr(d, "lineno", None)
            raise ParseError(msg, line=lineno)
    return constants, functions, aliases, slots, classes
Пример #4
0
def get_parents(
        bases: List[ast3.AST]) -> Tuple[List[pytd_node.Node], Optional[int]]:
    """Collect base classes and namedtuple index."""

    parents = []
    namedtuple_index = None
    for i, p in enumerate(bases):
        if _is_parameterized_protocol(p):
            # 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
            parents.append(p.base_type)
            parents.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
            parents.append(p)
        elif isinstance(p, pytd.Type):
            parents.append(p)
        else:
            msg = "Unexpected class base:" + p
            raise ParseError(msg)

    return parents, namedtuple_index
Пример #5
0
  def from_function(cls, function: ast3.AST, is_async: bool) -> "NameAndSig":
    """Constructor from an ast.FunctionDef node."""
    name = function.name

    # decorators
    decorators = set(function.decorator_list)
    abstracts = {"abstractmethod", "abc.abstractmethod"}
    coroutines = {"coroutine", "asyncio.coroutine", "coroutines.coroutine"}
    overload = {"overload"}
    ignored = {"type_check_only"}
    is_abstract = bool(decorators & abstracts)
    is_coroutine = bool(decorators & coroutines)
    is_overload = bool(decorators & overload)
    decorators -= abstracts
    decorators -= coroutines
    decorators -= overload
    decorators -= ignored
    # TODO(mdemello): do we need this limitation?
    if len(decorators) > 1:
      raise ParseError("Too many decorators for %s" % name)
    decorator, = decorators if decorators else (None,)

    exceptions = []
    mutators = []
    for i, x in enumerate(function.body):
      if isinstance(x, types.Raise):
        exceptions.append(x.exception)
      elif isinstance(x, Mutator):
        mutators.append(x)
      elif isinstance(x, types.Ellipsis):
        pass
      elif (isinstance(x, ast3.Expr) and
            isinstance(x.value, ast3.Str) and
            i == 0):
        # docstring
        pass
      else:
        msg = textwrap.dedent("""
            Unexpected statement in function body.
            Only `raise` statements and type mutations are valid
        """).lstrip()
        if isinstance(x, ast3.AST):
          raise ParseError(msg).at(x)
        else:
          raise ParseError(msg)

    # exceptions
    sig = _pytd_signature(function, is_async, exceptions=exceptions)

    # mutators
    for mutator in mutators:
      try:
        sig = sig.Visit(mutator)
      except NotImplementedError as e:
        raise ParseError(utils.message(e)) from e
      if not mutator.successful:
        raise ParseError("No parameter named %s" % mutator.name)

    return cls(name, sig, decorator, is_abstract, is_coroutine, is_overload)
Пример #6
0
 def _parameterized_type(self, base_type: Any, parameters):
     """Return a parameterized type."""
     if self._matches_named_type(base_type, _LITERAL_TYPES):
         return pytd_literal(parameters)
     elif self._matches_named_type(base_type, _ANNOTATED_TYPES):
         return pytd_annotated(parameters)
     elif self._matches_named_type(base_type, _FINAL_TYPES):
         typ, = parameters
         return pytd.GenericType(pytd.NamedType("typing.Final"), (typ, ))
     elif self._matches_named_type(base_type, _TYPEGUARD_TYPES):
         # We do not yet support PEP 647, User-Defined Type Guards. To avoid
         # blocking typeshed, convert type guards to plain bools.
         return pytd.NamedType("bool")
     elif any(isinstance(p, types.Pyval) for p in parameters):
         parameters = ", ".join(
             p.repr_str() if isinstance(p, types.Pyval) else "_"
             for p in parameters)
         raise ParseError("%s[%s] not supported" %
                          (pytd_utils.Print(base_type), parameters))
     elif pytdgen.is_any(base_type):
         return pytd.AnythingType()
     elif len(parameters) == 2 and parameters[-1] is self.ELLIPSIS and (
             not self._matches_named_type(base_type, _CALLABLE_TYPES)):
         element_type = parameters[0]
         if element_type is self.ELLIPSIS:
             raise ParseError("[..., ...] not supported")
         return pytd.GenericType(base_type=base_type,
                                 parameters=(element_type, ))
     else:
         processed_parameters = []
         # We do not yet support PEP 612, Parameter Specification Variables.
         # To avoid blocking typeshed from adopting this PEP, we convert new
         # features to approximations that only use supported features.
         for p in parameters:
             if p is self.ELLIPSIS:
                 processed = pytd.AnythingType()
             elif (p in self.param_specs and self._matches_full_name(
                     base_type, "typing.Generic")):
                 # Replacing a ParamSpec with a TypeVar isn't correct, but it'll work
                 # for simple cases in which the filled value is also a ParamSpec.
                 if not any(t.name == p.name for t in self.type_params):
                     self.type_params.append(pytd.TypeParameter(p.name))
                 processed = p
             elif (p in self.param_specs
                   or (isinstance(p, pytd.GenericType)
                       and self._matches_full_name(p, _CONCATENATE_TYPES))):
                 processed = pytd.AnythingType()
             else:
                 processed = p
             processed_parameters.append(processed)
         parameters = tuple(processed_parameters)
         if self._matches_named_type(base_type, _TUPLE_TYPES):
             return pytdgen.heterogeneous_tuple(base_type, parameters)
         elif self._matches_named_type(base_type, _CALLABLE_TYPES):
             return pytdgen.pytd_callable(base_type, parameters)
         else:
             assert parameters
             return pytd.GenericType(base_type=base_type,
                                     parameters=parameters)
Пример #7
0
  def build_type_decl_unit(self, defs) -> pytd.TypeDeclUnit:
    """Return a pytd.TypeDeclUnit for the given defs (plus parser state)."""
    # defs contains both constant and function definitions.
    constants, functions, aliases, slots, classes = _split_definitions(defs)
    assert not slots  # slots aren't allowed on the module level

    # TODO(mdemello): alias/constant handling is broken in some weird manner.
    # assert not aliases # We handle top-level aliases in add_alias_or_constant
    # constants.extend(self.constants)

    if self.module_info.module_name == "builtins":
      constants.extend(types.builtin_keyword_constants())

    generated_classes = sum(self.generated_classes.values(), [])

    classes = generated_classes + classes
    functions = function.merge_method_signatures(functions)

    name_to_class = {c.name: c for c in classes}
    name_to_constant = {c.name: c for c in constants}
    aliases = []
    for a in self.aliases.values():
      t = _maybe_resolve_alias(a, name_to_class, name_to_constant)
      if t is None:
        continue
      elif isinstance(t, pytd.Function):
        functions.append(t)
      elif isinstance(t, pytd.Constant):
        constants.append(t)
      else:
        assert isinstance(t, pytd.Alias)
        aliases.append(t)

    all_names = ([f.name for f in functions] +
                 [c.name for c in constants] +
                 [c.name for c in self.type_params] +
                 [c.name for c in classes] +
                 [c.name for c in aliases])
    duplicates = [name
                  for name, count in collections.Counter(all_names).items()
                  if count >= 2]
    if duplicates:
      raise ParseError(
          "Duplicate top-level identifier(s): " + ", ".join(duplicates))

    properties = [x for x in functions if x.kind == pytd.MethodTypes.PROPERTY]
    if properties:
      prop_names = ", ".join(p.name for p in properties)
      raise ParseError(
          "Module-level functions with property decorators: " + prop_names)

    return pytd.TypeDeclUnit(name=None,
                             constants=tuple(constants),
                             type_params=tuple(self.type_params),
                             functions=tuple(functions),
                             classes=tuple(classes),
                             aliases=tuple(aliases))
Пример #8
0
    def new_type(self,
                 name: Union[str, pytd_node.Node],
                 parameters: Optional[List[pytd.Type]] = None) -> pytd.Type:
        """Return the AST for a type.

    Args:
      name: The name of the type.
      parameters: List of type parameters.

    Returns:
      A pytd type node.

    Raises:
      ParseError: if the wrong number of parameters is supplied for the
        base_type - e.g., 2 parameters to Optional or no parameters to Union.
    """
        base_type = self.resolve_type(name)
        for p in self.param_specs:
            if base_type.name.startswith(f"{p.name}."):
                _, attr = base_type.name.split(".", 1)
                if attr not in ("args", "kwargs"):
                    raise ParseError(
                        f"Unrecognized ParamSpec attribute: {attr}")
                # We do not yet support typing.ParamSpec, so replace references to its
                # args and kwargs attributes with Any.
                return pytd.AnythingType()
        if not isinstance(base_type, pytd.NamedType):
            # We assume that all type parameters have been defined. Since pytype
            # orders type parameters to appear before classes and functions, this
            # assumption is generally safe. AnyStr is special-cased because imported
            # type parameters aren't recognized.
            type_params = self.type_params + [
                pytd.TypeParameter("typing.AnyStr")
            ]
            base_type = base_type.Visit(_InsertTypeParameters(type_params))
            try:
                resolved_type = visitors.MaybeSubstituteParameters(
                    base_type, parameters)
            except ValueError as e:
                raise ParseError(str(e)) from e
            if resolved_type:
                return resolved_type
        if parameters is not None:
            if (len(parameters) > 1 and isinstance(base_type, pytd.NamedType)
                    and base_type.name == "typing.Optional"):
                raise ParseError("Too many options to %s" % base_type.name)
            return self._parameterized_type(base_type, parameters)
        else:
            if (isinstance(base_type, pytd.NamedType)
                    and base_type.name in _TYPING_SETS):
                raise ParseError("Missing options to %s" % base_type.name)
            return base_type
Пример #9
0
def _check_module_functions(functions):
    """Validate top-level module functions."""
    # module.__getattr__ should have a unique signature
    g = [f for f in functions if f.name == "__getattr__"]
    if g and len(g[0].signatures) > 1:
        raise ParseError("Multiple signatures for module __getattr__")

    # module-level functions cannot be properties
    properties = [x for x in functions if x.kind == pytd.MethodKind.PROPERTY]
    if properties:
        prop_names = ", ".join(p.name for p in properties)
        raise ParseError("Module-level functions with property decorators: " +
                         prop_names)
Пример #10
0
 def _parameterized_type(self, base_type, parameters):
     """Return a parameterized type."""
     if self._matches_named_type(base_type, _LITERAL_TYPES):
         return types.pytd_literal(parameters)
     elif self._matches_named_type(base_type, _ANNOTATED_TYPES):
         return types.pytd_annotated(parameters)
     elif self._matches_named_type(base_type, _TYPEGUARD_TYPES):
         # We do not yet support PEP 647, User-Defined Type Guards. To avoid
         # blocking typeshed, convert type guards to plain bools.
         return pytd.NamedType("bool")
     elif any(isinstance(p, types.Constant) for p in parameters):
         parameters = ", ".join(
             p.repr_str() if isinstance(p, types.Constant) else "_"
             for p in parameters)
         raise ParseError("%s[%s] not supported" %
                          (pytd_utils.Print(base_type), parameters))
     elif pytdgen.is_any(base_type):
         return pytd.AnythingType()
     elif len(parameters) == 2 and parameters[-1] is self.ELLIPSIS and (
             not self._matches_named_type(base_type, _CALLABLE_TYPES)):
         element_type = parameters[0]
         if element_type is self.ELLIPSIS:
             raise ParseError("[..., ...] not supported")
         return pytd.GenericType(base_type=base_type,
                                 parameters=(element_type, ))
     else:
         parameters = tuple(pytd.AnythingType() if p is self.ELLIPSIS else p
                            for p in parameters)
         if self._matches_named_type(base_type, _TUPLE_TYPES):
             return pytdgen.heterogeneous_tuple(base_type, parameters)
         elif self._matches_named_type(base_type, _CALLABLE_TYPES):
             callable_parameters = []
             for p in parameters:
                 # We do not yet support PEP 612, Parameter Specification Variables.
                 # To avoid blocking typeshed from adopting this PEP, we convert new
                 # features to Any.
                 if p in self.param_specs or (isinstance(
                         p, pytd.GenericType) and self._matches_full_name(
                             p, _CONCATENATE_TYPES)):
                     callable_parameters.append(pytd.AnythingType())
                 else:
                     callable_parameters.append(p)
             return pytdgen.pytd_callable(base_type,
                                          tuple(callable_parameters))
         else:
             assert parameters
             return pytd.GenericType(base_type=base_type,
                                     parameters=parameters)
Пример #11
0
 def fail(self, name=None):
     if name:
         msg = f"Unsupported condition: '{name}'. "
     else:
         msg = "Unsupported condition. "
     msg += "Supported checks are sys.platform and sys.version_info"
     raise ParseError(msg)
Пример #12
0
 def visit_BoolOp(self, node):
     if isinstance(node.op, ast3.Or):
         return any(node.values)
     elif isinstance(node.op, ast3.And):
         return all(node.values)
     else:
         raise ParseError("Unexpected boolean operator: " + node.op)
Пример #13
0
def pytd_annotated(parameters: List[Any]) -> pytd.Type:
    """Create a pytd.Annotated."""
    if len(parameters) < 2:
        raise ParseError("typing.Annotated takes at least two parameters: "
                         "Annotated[type, annotation, ...].")
    typ, *annotations = parameters
    annotations = tuple(map(_convert_annotated, annotations))
    return pytd.Annotated(typ, annotations)
Пример #14
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
Пример #15
0
 def add_param_spec(self, name, paramspec):
     if name != paramspec.name:
         raise ParseError("ParamSpec name needs to be %r (not %r)" %
                          (paramspec.name, name))
     # ParamSpec should probably be represented with its own pytd class, like
     # TypeVar. This is just a quick, hacky way for us to keep track of which
     # names refer to ParamSpecs so we can replace them with Any in
     # _parameterized_type().
     self.param_specs.append(pytd.NamedType(name))
Пример #16
0
 def EnterParameter(self, node):
     if isinstance(node.mutated_type, pytd.GenericType):
         params = self._GetTypeParameters(node.mutated_type)
         extra = params - self.type_params_in_scope[-1]
         if extra:
             fn = pytd_utils.Print(self.current_function)
             msg = "Type parameter(s) {%s} not in scope in\n\n%s" % (
                 ", ".join(sorted(extra)), fn)
             raise ParseError(msg)
Пример #17
0
 def _parameterized_type(self, base_type, parameters):
     """Return a parameterized type."""
     if self._is_literal_base_type(base_type):
         return types.pytd_literal(parameters)
     elif any(isinstance(p, types.Constant) for p in parameters):
         parameters = ", ".join(
             p.repr_str() if isinstance(p, types.Constant) else "_"
             for p in parameters)
         raise ParseError("%s[%s] not supported" %
                          (pytd_utils.Print(base_type), parameters))
     elif pytdgen.is_any(base_type):
         return pytd.AnythingType()
     elif len(parameters) == 2 and parameters[-1] is self.ELLIPSIS and (
             not self._is_callable_base_type(base_type)):
         element_type = parameters[0]
         if element_type is self.ELLIPSIS:
             raise ParseError("[..., ...] not supported")
         return pytd.GenericType(base_type=base_type,
                                 parameters=(element_type, ))
     else:
         parameters = tuple(pytd.AnythingType() if p is self.ELLIPSIS else p
                            for p in parameters)
         if self._is_tuple_base_type(base_type):
             return pytdgen.heterogeneous_tuple(base_type, parameters)
         elif self._is_callable_base_type(base_type):
             callable_parameters = []
             for p in parameters:
                 # We do not yet support PEP 612, Parameter Specification Variables.
                 # To avoid blocking typeshed from adopting this PEP, we convert new
                 # features to Any.
                 if p in self.param_specs or (isinstance(
                         p, pytd.GenericType) and self._matches_full_name(
                             p, ("typing.Concatenate",
                                 "typing_extensions.Concatenate"))):
                     callable_parameters.append(pytd.AnythingType())
                 else:
                     callable_parameters.append(p)
             return pytdgen.pytd_callable(base_type,
                                          tuple(callable_parameters))
         else:
             assert parameters
             return pytd.GenericType(base_type=base_type,
                                     parameters=parameters)
Пример #18
0
def check_for_duplicate_defs(methods, constants, aliases) -> None:
    """Check a class's list of definitions for duplicates."""
    all_names = (list(set(f.name for f in methods)) +
                 [c.name for c in constants] + [a.name for a in aliases])
    duplicates = [
        name for name, count in collections.Counter(all_names).items()
        if count >= 2
    ]
    if duplicates:
        raise ParseError("Duplicate class-level identifier(s): " +
                         ", ".join(duplicates))
Пример #19
0
def _convert_annotated(x):
    """Convert everything to a string to store it in pytd.Annotated."""
    if isinstance(x, types.Pyval):
        return x.repr_str()
    elif isinstance(x, dict):
        return metadata.to_string(x)
    elif isinstance(x, tuple):
        fn, posargs, kwargs = x
        return metadata.call_to_annotation(fn, posargs=posargs, kwargs=kwargs)
    else:
        raise ParseError(f"Cannot convert metadata {x}")
Пример #20
0
 def _qualify_name_with_special_dir(self, orig_name):
     """Handle the case of '.' and '..' as package names."""
     if "__PACKAGE__." in orig_name:
         # Generated from "from . import foo" - see parser.yy
         prefix, _, name = orig_name.partition("__PACKAGE__.")
         if prefix:
             raise ParseError(f"Cannot resolve import: {orig_name}")
         return f"{self.package_name}.{name}"
     elif "__PARENT__." in orig_name:
         # Generated from "from .. import foo" - see parser.yy
         prefix, _, name = orig_name.partition("__PARENT__.")
         if prefix:
             raise ParseError(f"Cannot resolve import: {orig_name}")
         if not self.parent_name:
             raise ParseError(
                 f"Cannot resolve relative import ..: Package {self.package_name} "
                 "has no parent")
         return f"{self.parent_name}.{name}"
     else:
         return None
Пример #21
0
 def add_type_var(self, name, typevar):
   """Add a type variable, <name> = TypeVar(<name_arg>, <args>)."""
   if name != typevar.name:
     raise ParseError("TypeVar name needs to be %r (not %r)" % (
         typevar.name, name))
   bound = typevar.bound
   if isinstance(bound, str):
     bound = pytd.NamedType(bound)
   constraints = tuple(typevar.constraints) if typevar.constraints else ()
   self.type_params.append(pytd.TypeParameter(
       name=name, constraints=constraints, bound=bound))
Пример #22
0
def pytd_literal(parameters: List[Any]) -> pytd.Type:
    """Create a pytd.Literal."""
    literal_parameters = []
    for p in parameters:
        if pytdgen.is_none(p):
            literal_parameters.append(p)
        elif isinstance(p, pytd.NamedType):
            # TODO(b/173742489): support enums.
            literal_parameters.append(pytd.AnythingType())
        elif isinstance(p, types.Pyval):
            literal_parameters.append(p.to_pytd_literal())
        elif isinstance(p, pytd.Literal):
            literal_parameters.append(p)
        elif isinstance(p, pytd.UnionType):
            for t in p.type_list:
                if isinstance(t, pytd.Literal):
                    literal_parameters.append(t)
                else:
                    raise ParseError(f"Literal[{t}] not supported")
        else:
            raise ParseError(f"Literal[{p}] not supported")
    return pytd_utils.JoinTypes(literal_parameters)
Пример #23
0
def get_metaclass(keywords: List[ast3.keyword]):
    """Scan keywords for a metaclass."""

    for k in keywords:
        keyword, value = k.arg, k.value
        if keyword not in ("metaclass", "total"):
            raise ParseError(f"Unexpected classdef kwarg {keyword!r}")
        # TODO(rechen): We should store the "total" value instead of throwing it
        # away and validate in load_pytd that "total" is passed only to TypedDict
        # subclasses. We can't do the validation here because external types need to
        # be resolved first.
        if keyword == "metaclass":
            return value
    return None
Пример #24
0
 def qualify_name(self, orig_name):
     """Qualify an import name."""
     if not self.package_name:
         return orig_name
     rel_name = self._qualify_name_with_special_dir(orig_name)
     if rel_name:
         return rel_name
     if orig_name.startswith("."):
         name = module_utils.get_absolute_name(self.package_name, orig_name)
         if name is None:
             raise ParseError(
                 f"Cannot resolve relative import {orig_name.rsplit('.', 1)[0]}"
             )
         return name
     return orig_name
Пример #25
0
    def add_alias_or_constant(self, alias_or_constant):
        """Add an alias or constant.

    Args:
      alias_or_constant: the top-level definition to add.

    Raises:
      ParseError: For an invalid __slots__ declaration.
    """
        if isinstance(alias_or_constant, pytd.Constant):
            self.constants.append(alias_or_constant)
        elif isinstance(alias_or_constant, types.SlotDecl):
            raise ParseError("__slots__ only allowed on the class level")
        elif isinstance(alias_or_constant, pytd.Alias):
            name, value = alias_or_constant.name, alias_or_constant.type
            self.type_map[name] = value
            self.aliases[name] = alias_or_constant
        else:
            assert False, "Unknown type of assignment"
Пример #26
0
def get_decorators(decorators: List[str], type_map: Dict[str, pytd_node.Node]):
    """Process a class decorator list."""

    # Drop the @type_check_only decorator from classes
    # TODO(mdemello): Workaround for the bug that typing.foo class decorators
    # don't add the import, since typing.type_check_only is the only one.
    decorators = [x for x in decorators if x != "type_check_only"]

    # Check for some function/method-only decorators
    nonclass = {"property", "classmethod", "staticmethod", "overload"}
    unsupported_decorators = set(decorators) & nonclass
    if unsupported_decorators:
        raise ParseError("Unsupported class decorators: %s" %
                         ", ".join(unsupported_decorators))

    # Convert decorators to named types. These are wrapped as aliases because we
    # otherwise do not allow referencing functions as types.
    return [
        pytd.Alias(d,
                   type_map.get(d) or pytd.NamedType(d)) for d in decorators
    ]
Пример #27
0
    def _eval_comparison(self, ident, op, value) -> bool:
        """Evaluate a comparison and return a bool.

    Args:
      ident: A tuple of a dotted name string and an optional __getitem__ key
        (int or slice).
      op: One of the comparison operator strings in cmp_slots.COMPARES.
      value: Either a string, an integer, or a tuple of integers.

    Returns:
      The boolean result of the comparison.

    Raises:
      ParseError: If the comparison cannot be evaluated.
    """
        name, key = ident
        if name == "sys.version_info":
            if key is None:
                key = slice(None, None, None)
            assert isinstance(key, (int, slice))
            if isinstance(key, int) and not isinstance(value, int):
                raise ParseError(
                    "an element of sys.version_info must be compared to an integer"
                )
            if isinstance(key, slice) and not _is_int_tuple(value):
                raise ParseError(
                    "sys.version_info must be compared to a tuple of integers")
            try:
                actual = self._version[key]
            except IndexError as e:
                raise ParseError(utils.message(e)) from e
            if isinstance(key, slice):
                actual = _three_tuple(actual)
                value = _three_tuple(value)
        elif name == "sys.platform":
            if not isinstance(value, str):
                raise ParseError("sys.platform must be compared to a string")
            valid_cmps = (cmp_slots.EQ, cmp_slots.NE)
            if op not in valid_cmps:
                raise ParseError(
                    "sys.platform must be compared using %s or %s" %
                    valid_cmps)
            actual = self._platform
        else:
            raise ParseError("Unsupported condition: '%s'." % name)
        return cmp_slots.COMPARES[op](actual, value)
Пример #28
0
 def leave(self, node):
     try:
         return super().leave(node)
     except Exception as e:  # pylint: disable=broad-except
         raise ParseError.from_exc(e).at(node, self.filename, self.src_code)
Пример #29
0
 def visit_UnaryOp(self, node):
     if isinstance(node.op, ast3.USub) and isinstance(node.operand, int):
         return -node.operand
     else:
         raise ParseError("Unexpected unary operator: %s" % node.op)
Пример #30
0
 def visit_UnaryOp(self, node):
     if isinstance(node.op, ast3.USub):
         if isinstance(node.operand, types.Pyval):
             return node.operand.negated()
     raise ParseError(f"Unexpected unary operator: {node.op}")