Skip to content

Commit

Permalink
Defer checking of Final so that it can be used with Annotated.
Browse files Browse the repository at this point in the history
Also tweaks a couple of initializers to let __repr__ work during construction.

Fixes #1110

PiperOrigin-RevId: 424194421
  • Loading branch information
martindemello authored and rchen152 committed Jan 26, 2022
1 parent 2ae395c commit 000d4a3
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 7 deletions.
2 changes: 1 addition & 1 deletion pytype/abstract/_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,8 +581,8 @@ class AnnotationsDict(Dict):
"""__annotations__ dict."""

def __init__(self, annotated_locals, ctx):
super().__init__(ctx)
self.annotated_locals = annotated_locals
super().__init__(ctx)

def get_type(self, node, name):
if name not in self.annotated_locals:
Expand Down
8 changes: 8 additions & 0 deletions pytype/abstract/_interpreter_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ def __init__(self, name, def_opcode, code, f_locals, f_globals, defaults,
self.nonstararg_count += self.code.co_kwonlyargcount
signature = self._build_signature(name, annotations)
super().__init__(signature, ctx)
self._check_annotations(name, annotations)
self._update_signature_scope()
self.last_frame = None # for BuildClass
self._store_call_records = False
Expand All @@ -464,6 +465,13 @@ def record_calls(self):
yield
self._store_call_records = old

def _check_annotations(self, name, annotations):
"""Validate function annotations."""
for ann in annotations.values():
if isinstance(ann, _typing.FinalAnnotation):
self.ctx.errorlog.invalid_final_type(
self.ctx.vm.simple_stack(self.def_opcode))

def _build_signature(self, name, annotations):
"""Build a function.Signature object representing this function."""
vararg_name = None
Expand Down
5 changes: 2 additions & 3 deletions pytype/abstract/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,10 @@ def __init__(self, options, ctx):
self.options = list(options)
self.cls = self._get_class()
self.formal = any(t.formal for t in self.options)
self._printing = False
mixin.NestedAnnotation.init_mixin(self)
mixin.HasSlots.init_mixin(self)
self.set_slot("__getitem__", self.getitem_slot)
self._printing = False

def __repr__(self):
if self._printing: # recursion detected
Expand Down Expand Up @@ -672,5 +672,4 @@ def __repr__(self):
return f"Final[{self.annotation}]"

def instantiate(self, node, container=None):
self.ctx.errorlog.invalid_final_type(self.ctx.vm.frames)
return self.annotation.to_variable(node)
return self.to_variable(node)
13 changes: 10 additions & 3 deletions pytype/tests/test_final.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@ def f(x: Final[int]): # final-error[e]
pass
def g(x: Final): # final-error
pass
def h(x) -> Final[int]:
pass # bad-return-type # final-error
def h(x) -> Final[int]: # final-error
pass # bad-return-type
def i(x) -> Final:
pass # bad-return-type # final-error
pass # bad-return-type # final-error
""")
self.assertErrorSequences(
err, {"e": ["only be used", "assignments", "variable annotations"]})
Expand All @@ -262,6 +262,13 @@ def test_cannot_use_in_type_params(self):
y: Tuple[int, Final[int]] = (1, 2) # invalid-annotation # final-error
""")

def test_can_use_in_annotated(self):
self.CheckWithErrors("""
from typing import Annotated, Final, List
x: Annotated[Final[List[int]], 'valid'] = [10]
y: Annotated[List[Final[int]], 'invalid'] = [10] # invalid-annotation # final-error
""")


class TestFinalDecoratorInPyi(test_base.BaseTest):
"""Test @final in pyi files."""
Expand Down

0 comments on commit 000d4a3

Please sign in to comment.