Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google sync #1550

Merged
merged 7 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading