Skip to content

Commit

Permalink
Fix crash on stubs that contain dict or set literals (#634)
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra authored May 26, 2023
1 parent bd7f520 commit 580c8f2
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- Fix crash on stubs that contain dict or set literals (#634)
- Remove more old special cases and improve robustness of
annotation parsing (#630)
- Remove dependency on `typing_inspect` (#629)
Expand Down
21 changes: 21 additions & 0 deletions pyanalyze/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
show errors.
"""
from _ast import Dict
import ast
import builtins
import contextlib
Expand Down Expand Up @@ -76,6 +77,8 @@
)
from .value import (
_HashableValue,
DictIncompleteValue,
KVPair,
annotate_value,
AnnotatedValue,
AnySource,
Expand Down Expand Up @@ -916,6 +919,24 @@ def visit_List(self, node: ast.List) -> Value:
elts = [(False, self.visit(elt)) for elt in node.elts]
return SequenceValue(list, elts)

def visit_Set(self, node: ast.Set) -> Value:
elts = [(False, self.visit(elt)) for elt in node.elts]
return SequenceValue(set, elts)

def visit_Dict(self, node: Dict) -> Any:
keys = [self.visit(key) if key is not None else None for key in node.keys]
values = [self.visit(value) for value in node.values]
kvpairs = []
for key, value in zip(keys, values):
if key is None:
# Just skip ** unpacking in stubs for now.
kvpairs.append(
KVPair(AnyValue(AnySource.inference), AnyValue(AnySource.inference))
)
else:
kvpairs.append(KVPair(key, value))
return DictIncompleteValue(dict, kvpairs)

def visit_Index(self, node: ast.Index) -> Value:
# class is unused in 3.9
return self.visit(node.value) # static analysis: ignore[undefined_attribute]
Expand Down
10 changes: 10 additions & 0 deletions pyanalyze/stubs/_pyanalyze_tests-stubs/defaults.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from typing import TypeVar

T = TypeVar("T")
U = TypeVar("U")
V = TypeVar("V")
W = TypeVar("W")

def many_defaults(
a: T = {"a": 1}, b: U = [1, ()], c: V = (1, 2), d: W = {1, 2}
) -> tuple[T, U, V, W]: ...
24 changes: 24 additions & 0 deletions pyanalyze/test_typeshed.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from .value import (
AnySource,
AnyValue,
SequenceValue,
assert_is_value,
CallableValue,
DictIncompleteValue,
Expand Down Expand Up @@ -373,6 +374,29 @@ def capybara():

assert_type(x, Literal[3])

@assert_passes()
def test_stub_defaults(self):
def capybara():
from _pyanalyze_tests.defaults import many_defaults

a, b, c, d = many_defaults()
assert_is_value(
a, DictIncompleteValue(dict, [KVPair(KnownValue("a"), KnownValue(1))])
)
assert_is_value(
b,
SequenceValue(
list, [(False, KnownValue(1)), (False, SequenceValue(tuple, []))]
),
)
assert_is_value(
c,
SequenceValue(tuple, [(False, KnownValue(1)), (False, KnownValue(2))]),
)
assert_is_value(
d, SequenceValue(set, [(False, KnownValue(1)), (False, KnownValue(2))])
)


class TestConstructors(TestNameCheckVisitorBase):
@assert_passes()
Expand Down

0 comments on commit 580c8f2

Please sign in to comment.