Skip to content

Commit

Permalink
Merge pull request #1542 from google/google_sync
Browse files Browse the repository at this point in the history
Google sync
  • Loading branch information
rchen152 authored Dec 7, 2023
2 parents 8c465c5 + 1dfaf59 commit 3372893
Show file tree
Hide file tree
Showing 12 changed files with 65 additions and 26 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
Version 2023.12.07:

Updates:
* 3.11: support ExceptionGroup.
* Update typeshed pin to commit 0b36e65 from Nov 29.
* Add a flag, --none-is-not-bool, to disable treatment of None as a bool.

Bug fixes:
* Remove extraneous quotes around part of error message.
* Fix pattern matching with `case None` branches.
* Support @override for methods anywhere in the MRO.

Version 2023.11.29:

Updates:
Expand Down
2 changes: 1 addition & 1 deletion pytype/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# pylint: skip-file
__version__ = '2023.11.29'
__version__ = '2023.12.07'
3 changes: 1 addition & 2 deletions pytype/abstract/_classes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Abstract class representations."""

import itertools
import logging
from typing import Any, Dict, List, Optional, Tuple, Union

Expand Down Expand Up @@ -213,7 +212,7 @@ def _override_check(self):

def _get_defining_base_class(self, attr):
"""Gets first base class, if any, that defines the given attribute."""
for base in itertools.chain.from_iterable(b.data for b in self._bases):
for base in self.mro[1:]:
if isinstance(base, class_mixin.Class) and attr in base:
return base
return None
Expand Down
1 change: 1 addition & 0 deletions pytype/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ def add_options(o, arglist):
FEATURE_FLAGS = [
_flag("--bind-decorated-methods", False,
"Bind 'self' in methods with non-transparent decorators."),
_flag("--none-is-not-bool", False, "Don't allow None to match bool."),
_flag("--overriding-renamed-parameter-count-checks", False,
"Enable parameter count checks for overriding methods with "
"renamed arguments."),
Expand Down
22 changes: 12 additions & 10 deletions pytype/matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@

log = logging.getLogger(__name__)


_COMPATIBLE_BUILTINS = [
("builtins." + compatible_builtin, "builtins." + builtin)
for compatible_builtin, builtin in pep484.COMPAT_ITEMS
]

_SubstType = datatypes.AliasingDict[str, cfg.Variable]
_ViewType = datatypes.AccessTrackingDict[cfg.Variable, cfg.Binding]

Expand Down Expand Up @@ -251,6 +245,13 @@ def __init__(self, node, ctx):
self._error_subst = None
self._type_params = _TypeParams()
self._paramspecs = {}

compat_items = pep484.get_compat_items(
none_matches_bool=not ctx.options.none_is_not_bool)
self._compatible_builtins = [
("builtins." + compatible_builtin, "builtins." + builtin)
for compatible_builtin, builtin in compat_items]

self._reset_errors()

def _reset_errors(self):
Expand Down Expand Up @@ -1721,7 +1722,7 @@ def _discard_ambiguous_values(self, values):
def _satisfies_single_type(self, values):
"""Enforce that the variable contains only one concrete type."""
class_names = {v.cls.full_name for v in values}
for compat_name, name in _COMPATIBLE_BUILTINS:
for compat_name, name in self._compatible_builtins:
if {compat_name, name} <= class_names:
class_names.remove(compat_name)
# We require all occurrences to be of the same type, no subtyping allowed.
Expand All @@ -1734,7 +1735,7 @@ def _satisfies_common_superclass(self, values):
for v in values:
object_in_values |= v.cls == self.ctx.convert.object_type
superclasses = {c.full_name for c in v.cls.mro or v.cls.default_mro()}
for compat_name, name in _COMPATIBLE_BUILTINS:
for compat_name, name in self._compatible_builtins:
if compat_name in superclasses:
superclasses.add(name)
if common_classes is None:
Expand Down Expand Up @@ -1789,5 +1790,6 @@ def _match_base_class_flat(self, base_cls, other_type, allow_compat_builtins):
return True
name1 = self._get_full_name(base_cls)
name2 = self._get_full_name(other_type)
return (name1 == name2 or
allow_compat_builtins and (name1, name2) in _COMPATIBLE_BUILTINS)
return (
name1 == name2 or
allow_compat_builtins and (name1, name2) in self._compatible_builtins)
6 changes: 3 additions & 3 deletions pytype/matcher_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class MatcherTestBase(test_base.UnitTest):

def setUp(self):
super().setUp()
options = config.Options.create(python_version=self.python_version)
options = config.Options.create(python_version=self.python_version,
none_is_not_bool=True)
self.ctx = test_utils.make_context(options)
self.matcher = self.ctx.matcher(self.ctx.root_node)

Expand Down Expand Up @@ -143,10 +144,9 @@ def test_class_against_type_union(self):
self.assertMatch(left, right)

def test_none_against_bool(self):
# See pep484.COMPAT_ITEMS.
left = self._convert_type("None", as_instance=True)
right = self._convert_type("bool")
self.assertMatch(left, right)
self.assertNoMatch(left, right)

def test_homogeneous_tuple(self):
left = self._convert_type("Tuple[int, ...]", as_instance=True)
Expand Down
11 changes: 7 additions & 4 deletions pytype/pytd/pep484.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@


# Pairs of a type and a more generalized type.
COMPAT_ITEMS = [
("NoneType", "bool"),
# pep484 allows None as an alias for NoneType in type annotations.
("None", "bool"),
_COMPAT_ITEMS = [
("int", "float"),
("int", "complex"),
("float", "complex"),
Expand All @@ -38,6 +35,12 @@
BUILTIN_TO_TYPING = {v: k for k, v in TYPING_TO_BUILTIN.items()}


def get_compat_items(none_matches_bool=False):
# pep484 allows None as an alias for NoneType in type annotations.
extra = [("NoneType", "bool"), ("None", "bool")] if none_matches_bool else []
return _COMPAT_ITEMS + extra


class ConvertTypingToNative(base_visitor.Visitor):
"""Visitor for converting PEP 484 types to native representation."""

Expand Down
2 changes: 1 addition & 1 deletion pytype/pytd/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ def _FormSetTypeList(self, node):
"""Form list of types within a set type."""
type_list = dict.fromkeys(node.type_list)
if self.in_parameter:
for compat, name in pep484.COMPAT_ITEMS:
for compat, name in pep484.get_compat_items():
# name can replace compat.
if compat in type_list and name in type_list:
del type_list[compat]
Expand Down
2 changes: 1 addition & 1 deletion pytype/pytd/visitors_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ def a(a: float) -> int: ...
def b(a: float) -> int: ...
def c(a: object) -> Union[float, int]: ...
def d(a: float) -> int: ...
def e(a: bool) -> Optional[bool]: ...
def e(a: Optional[bool]) -> Optional[bool]: ...
""")
self.assertMultiLineEqual(expected.strip(),
pytd_utils.Print(self.ToAST(src)).strip())
Expand Down
8 changes: 4 additions & 4 deletions pytype/tests/test_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,11 @@ class Foo:
def bar(self, x: float, default=...) -> str: ...
""")

def test_compat_bool(self):
self.Check("""
def test_nocompat_bool(self):
self.CheckWithErrors("""
def bar(x: bool) -> bool:
return None
bar(None)
return None # bad-return-type
bar(None) # wrong-arg-types
""")

def test_compat_float(self):
Expand Down
1 change: 1 addition & 0 deletions pytype/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def setUp(self):
self.options = config.Options.create(
python_version=self.python_version,
bind_decorated_methods=True,
none_is_not_bool=True,
overriding_renamed_parameter_count_checks=True,
strict_parameter_checks=True,
strict_undefined_checks=True,
Expand Down
21 changes: 21 additions & 0 deletions pytype/tests/test_overriding.py
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,27 @@ class B2: # override-error
pass
""")

def test_grandparent(self):
self.CheckWithErrors("""
from typing_extensions import override
class Base:
def f(self) -> int:
return 0
class Parent(Base):
pass
class Child(Parent):
@override
def f(self) -> int:
return 5
@override
def g(self) -> int: # override-error
return 5
""")

def test_strict_mode(self):
errors = self.CheckWithErrors("""
# pytype: features=require-override-decorator
Expand Down

0 comments on commit 3372893

Please sign in to comment.