Skip to content

Commit

Permalink
Merge pull request #1523 from google/google_sync
Browse files Browse the repository at this point in the history
Google sync
  • Loading branch information
rchen152 authored Oct 31, 2023
2 parents 59e0b01 + e58db28 commit 5474163
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 5 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
Version 2023.10.31:

Updates:
* Happy Halloween!
* typing.Self: support Self in variable annotations.
* 3.11: Implement typing features Never, clear_overloads, get_overloads,
assert_type, reveal_type, and assert_never.
* Add feature flag --bind-decorated-methods to bind 'self' correctly in
decorated methods.

Bug fixes:
* Fix some corner cases in invalidating an enum tracker.
* Use equality check rather than identity check for recursion detection.

Version 2023.10.24:

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.10.24'
__version__ = '2023.10.31'
7 changes: 5 additions & 2 deletions pytype/abstract/_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,12 @@ def has_protocol_base(self):
return True
return False

def get_undecorated_method(self, name, node):
def get_undecorated_method(
self, name: str, node: cfg.CFGNode) -> Optional[cfg.Variable]:
if name not in self._undecorated_methods:
return None
return self.ctx.program.NewVariable(
self._undecorated_methods.get(name, ()), (), node)
self._undecorated_methods[name], (), node)


class PyTDClass(
Expand Down
2 changes: 1 addition & 1 deletion pytype/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def get_attribute(self, node, obj, name, valself=None):
results = []
nodes = []
for b in param_var.bindings:
if b.data is obj:
if b.data == obj:
continue
node2, ret = self.get_attribute(node, b.data, name, valself)
if ret is None:
Expand Down
2 changes: 2 additions & 0 deletions pytype/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ def add_options(o, arglist):


FEATURE_FLAGS = [
_flag("--bind-decorated-methods", False,
"Bind 'self' in methods with non-transparent decorators."),
_flag("--overriding-renamed-parameter-count-checks", False,
"Enable parameter count checks for overriding methods with "
"renamed arguments."),
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 @@ -80,6 +80,7 @@ def setUp(self):
super().setUp()
self.options = config.Options.create(
python_version=self.python_version,
bind_decorated_methods=True,
overriding_renamed_parameter_count_checks=True,
strict_parameter_checks=True,
strict_undefined_checks=True,
Expand Down
11 changes: 11 additions & 0 deletions pytype/tests/test_decorators2.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,17 @@ def f(self, x: T):
pass
""")

def test_self_in_decorated_method(self):
self.Check("""
from typing import Any
def decorate(f) -> Any:
return f
class C:
@decorate
def f(self):
assert_type(self, C)
""")


if __name__ == "__main__":
test_base.main()
19 changes: 19 additions & 0 deletions pytype/tests/test_inplace1.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,25 @@ def test_ixor(self):
self._check_inplace("^", ["x=1", "y=2"], "int")
self._check_inplace("^", ["x={1}", "y={2}"], "set[int]")

def test_setitem_and_iadd(self):
self.Check("""
from typing import Dict, TypeVar
T = TypeVar('T')
class Item:
pass
class ItemDict(Dict[Item, T]):
def __setitem__(self, k: Item, v: T):
if not v.id:
raise ValueError()
super().__setitem__(k, v)
def __iadd__(self, other: 'ItemDict'):
for k, v in other.items():
self[k] += v
return self
def Add(self, value: T):
super().__setitem__(value.id, value)
""")


if __name__ == "__main__":
test_base.main()
9 changes: 8 additions & 1 deletion pytype/tracer_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ def bind(cur_node, m):
# which can happen if the method is decorated, for example - then we look up
# the method before any decorators were applied and use that instead.
undecorated_method = cls.get_undecorated_method(method_name, node)
if undecorated_method.data:
if undecorated_method:
return node, bind(node, undecorated_method)
else:
return node, bound_method
Expand Down Expand Up @@ -477,6 +477,13 @@ def analyze_class(self, node, val):
name = unwrapped.data[0].name if unwrapped else v.name
self.ctx.errorlog.ignored_abstractmethod(
self.ctx.vm.simple_stack(cls.get_first_opcode()), cls.name, name)
is_method_or_nested_class = any(
isinstance(m, (abstract.FUNCTION_TYPES, abstract.InterpreterClass))
for m in methodvar.data)
if (self.ctx.options.bind_decorated_methods and
not is_method_or_nested_class and
(undecorated_method := cls.get_undecorated_method(name, node))):
methodvar = undecorated_method
b = self._bind_method(node, methodvar, instance)
node = self.analyze_method_var(node, name, b, val)
return node
Expand Down

0 comments on commit 5474163

Please sign in to comment.