Skip to content

Commit

Permalink
Merge pull request #1550 from google/google_sync
Browse files Browse the repository at this point in the history
Google sync
  • Loading branch information
rchen152 authored Dec 14, 2023
2 parents c1c440c + da7aa62 commit c9573ba
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 60 deletions.
11 changes: 7 additions & 4 deletions docs/support.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ of pytype.
* [Third-Party Libraries](#third-party-libraries)

<!-- Created by https://github.com/ekalinin/github-markdown-toc -->
<!-- Added by: rechen, at: Tue Nov 28 03:37:40 PM PST 2023 -->
<!-- Added by: rechen, at: Thu Dec 14 10:25:15 AM PST 2023 -->

<!--te-->

Expand Down Expand Up @@ -79,10 +79,10 @@ Feature
[PEP 613 -- Explicit Type Aliases][613] | 3.10 | ✅ |
[PEP 646 -- Variadic Generics][646] | 3.11 | ❌ | [#1525][variadic-generics]
[PEP 647 -- User-Defined Type Guards][647] | 3.10 | ✅ |
[PEP 655 -- Marking individual TypedDict items as required or potentially-missing][655] | 3.11 | ❌ |
[PEP 655 -- Marking individual TypedDict items as required or potentially-missing][655] | 3.11 | ❌ | [#1551][typed-dict-requirements]
[PEP 673 -- Self Type][673] | 3.11 | ✅ |
[PEP 675 -- Arbitrary Literal String Type][675] | 3.11 | ❌ |
[PEP 681 -- Data Class Transforms][681] | 3.11 | 🟡 |
[PEP 675 -- Arbitrary Literal String Type][675] | 3.11 | ❌ | [#1552][literal-string]
[PEP 681 -- Data Class Transforms][681] | 3.11 | 🟡 | [#1553][dataclass-transform]
[PEP 695 -- Type Parameter Syntax][695] | 3.12 | ❌ |
[PEP 698 -- Override Decorator for Static Typing][698] | 3.12 | ✅ |
Custom Recursive Types | 3.6 | ✅ |
Expand Down Expand Up @@ -190,10 +190,12 @@ Tensorflow | 🟡 | Minimal, Google-internal
[698]: https://peps.python.org/pep-0698/
[annotated]: https://github.com/google/pytype/issues/791
[annotation-inheritance]: https://github.com/google/pytype/issues/81
[dataclass-transform]: https://github.com/google/pytype/issues/1553
[ellipsis-issue]: https://github.com/python/typing/issues/276
[experimental-ellipsis-commit]: https://github.com/google/pytype/commit/9f3f21e7a5bcedf6584bb41fd228878498182991
[faq-noniterable-strings]: https://google.github.io/pytype/faq.html#why-doesnt-str-match-against-string-iterables
[generic-aliases]: https://github.com/google/pytype/issues/793
[literal-string]: https://github.com/google/pytype/issues/1552
[packaging]: https://github.com/google/pytype/issues/151
[param-spec]: https://github.com/google/pytype/issues/786
[py27]: https://github.com/google/pytype/issues/545
Expand All @@ -203,4 +205,5 @@ Tensorflow | 🟡 | Minimal, Google-internal
[pytype-typing-faq]: https://google.github.io/pytype/typing_faq.html
[self]: https://github.com/google/pytype/issues/1283
[type-guards]: https://github.com/google/pytype/issues/916
[typed-dict-requirements]: https://github.com/google/pytype/issues/1551
[variadic-generics]: https://github.com/google/pytype/issues/1525
20 changes: 20 additions & 0 deletions pytype/matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,12 @@ def _match_instance_against_type(self, left, other_type, subst, view):
fiddle_overlay.BuildableType)):
return self._match_fiddle_instance(
left.cls, left, other_type, subst, view)
elif (isinstance(other_type, abstract.PyTDClass) and
fiddle_overlay.is_fiddle_buildable_pytd(other_type.pytd_cls) and
isinstance(left, fiddle_overlay.Buildable)):
# Handle a plain `fiddle.Config` imported from a pyi file.
return self._match_fiddle_instance_against_bare_type(
left.cls, left, other_type, subst, view)
elif isinstance(other_type, abstract.Class):
if not self._satisfies_noniterable_str(left.cls, other_type):
self._noniterable_str_error = NonIterableStrError(left.cls, other_type)
Expand Down Expand Up @@ -1294,7 +1300,21 @@ def _match_instance_parameters(self, left, instance, other_type, subst, view):
return None
return subst

def _match_fiddle_instance_against_bare_type(
self, left, instance, other_type, subst, view
):
"""Match a fiddle instance against an unsubscripted buildable pytd type."""
assert isinstance(instance, fiddle_overlay.Buildable)
assert isinstance(other_type, abstract.PyTDClass)
# This is a plain fiddle.Config we have imported from a pyi file and not
# subscripted, so it is still a PyTDClass
if instance.fiddle_type_name == other_type.name:
return subst
else:
return None

def _match_fiddle_instance(self, left, instance, other_type, subst, view):
"""Match a fiddle instance against an buildable type."""
if not isinstance(instance, fiddle_overlay.Buildable):
return None
elif instance.fiddle_type_name != other_type.fiddle_type_name:
Expand Down
16 changes: 3 additions & 13 deletions pytype/overlays/enum_overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import collections
import contextlib
import logging
from typing import Any, Dict, Optional, Union
from typing import Optional, Union

from pytype.abstract import abstract
from pytype.abstract import abstract_utils
Expand Down Expand Up @@ -65,17 +65,7 @@ def __init__(self, ctx):
super().__init__(ctx, "enum", member_map, ctx.loader.import_name("enum"))


class _DelGetAttributeMixin:

_member_map: Dict[str, Any]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if "__getattribute__" in self._member_map:
del self._member_map["__getattribute__"]


class EnumBuilder(_DelGetAttributeMixin, abstract.PyTDClass):
class EnumBuilder(abstract.PyTDClass):
"""Overlays enum.Enum."""

def __init__(self, name, ctx, module):
Expand Down Expand Up @@ -288,7 +278,7 @@ def call(self, node, func, args, alias_map=None):
return node, self.ctx.convert.build_bool(node, this.cls == other.cls)


class EnumMeta(_DelGetAttributeMixin, abstract.PyTDClass):
class EnumMeta(abstract.PyTDClass):
"""Wrapper for enum.EnumMeta.
EnumMeta is essentially a container for the functions that drive a lot of the
Expand Down
2 changes: 1 addition & 1 deletion pytype/pyi/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ def post_process_ast(ast, src, name=None):

if name:
ast = ast.Replace(name=name)
ast = ast.Visit(visitors.AddNamePrefix())
ast = ast.Visit(visitors.ResolveLocalNames())
else:
# If there's no unique name, hash the sourcecode.
ast = ast.Replace(name=hashlib.md5(src.encode("utf-8")).hexdigest())
Expand Down
8 changes: 8 additions & 0 deletions pytype/pytd/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,14 @@ def _DropTypingConstant(self, node):
if self.class_names or node.value:
return False
full_typing_name = f"typing.{node.name}"
# TODO(b/315507078): This is only necessary while these three classes
# are aliases of typing members.
if full_typing_name in (
"typing.ChainMap",
"typing.Counter",
"typing.OrderedDict",
):
return False
if node.type == f"Type[{full_typing_name}]":
self._imports.add(full_typing_name, node.name)
self._imports.decrement_typing_count("Type")
Expand Down
21 changes: 19 additions & 2 deletions pytype/pytd/visitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ def VisitNamedType(self, node):
return node.Replace(name=new_name)


class AddNamePrefix(Visitor):
class ResolveLocalNames(Visitor):
"""Visitor for making names fully qualified.
This will change
Expand All @@ -1252,6 +1252,10 @@ def bar(x: Foo) -> Foo
class baz.Foo:
pass
def bar(x: baz.Foo) -> baz.Foo
References to nested classes will be full resolved, e.g. if C is nested in
B is nested in A, then `x: C` becomes `x: foo.A.B.C`.
References to attributes of Any-typed constants will be resolved to Any.
"""

def __init__(self):
Expand All @@ -1266,6 +1270,12 @@ def _ClassStackString(self):

def EnterTypeDeclUnit(self, node):
self.classes = {cls.name for cls in node.classes}
# TODO(b/293451396): In certain weird cases, a local module named "typing"
# may get mixed up with the stdlib typing module. We end up doing the right
# thing in the end, but in the meantime, "typing" may get mapped to Any.
self.any_constants = {const.name for const in node.constants
if const.type == pytd.AnythingType()
and const.name != "typing"}
self.name = node.name
self.prefix = node.name + "."

Expand All @@ -1287,10 +1297,17 @@ def VisitNamedType(self, node):
# This is an external type; do not prefix it. StripExternalNamePrefix will
# remove it later.
return node
if node.name.split(".")[0] in self.classes:
target = node.name.split(".")[0]
if target in self.classes:
# We need to check just the first part, in case we have a class constant
# like Foo.BAR, or some similarly nested name.
return node.Replace(name=self.prefix + node.name)
if target in self.any_constants:
# If we have a constant in module `foo` that's Any, i.e.
# mod: Any
# x: mod.Thing
# We resolve `mod.Thing` to Any.
return pytd.AnythingType()
if self.cls_stack:
if node.name == self.cls_stack[-1].name:
# We're referencing a class from within itself.
Expand Down
Loading

0 comments on commit c9573ba

Please sign in to comment.