Skip to content

Commit 36d54a1

Browse files
fix Callable/Annotated (#381)
1 parent dd2f244 commit 36d54a1

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

docs/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Fix compatibility between `Callable` and `Annotated`
6+
(#381)
57
- Fix inference for nested `async def` functions (#380)
68
- Fix usage of type variables in function parameters
79
with defaults (#378)

pyanalyze/test_annotations.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,3 +1592,35 @@ def capybara(unannotated):
15921592
assert_is_value(
15931593
refined(), GenericValue(list, [AnyValue(AnySource.generic_argument)])
15941594
)
1595+
1596+
1597+
class TestCallable(TestNameCheckVisitorBase):
1598+
@assert_passes()
1599+
def test_compatibility(self):
1600+
from typing import Callable, TypeVar
1601+
1602+
T = TypeVar("T")
1603+
1604+
def want_callable(c: Callable[[int], T]) -> T:
1605+
return c(1)
1606+
1607+
def string_func(s: str) -> str:
1608+
return s
1609+
1610+
def capybara(unannotated, other):
1611+
assert_is_value(want_callable(lambda _: 3), KnownValue(3))
1612+
assert_is_value(
1613+
want_callable(unannotated), AnyValue(AnySource.generic_argument)
1614+
)
1615+
# generates an AnnotatedValue(MultiValuedValue(...))
1616+
assert_is_value(
1617+
want_callable(unannotated or other),
1618+
AnyValue(AnySource.generic_argument),
1619+
)
1620+
1621+
assert_is_value(
1622+
want_callable(string_func), # E: incompatible_argument
1623+
AnyValue(AnySource.error),
1624+
)
1625+
want_callable(1) # E: incompatible_argument
1626+
want_callable(int(unannotated)) # E: incompatible_argument

pyanalyze/value.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ def get_asynq_value(self) -> Value:
11861186
return CallableValue(sig, self.typ)
11871187

11881188
def can_assign(self, other: Value, ctx: CanAssignContext) -> CanAssign:
1189-
if not isinstance(other, (MultiValuedValue, AnyValue)):
1189+
if not isinstance(other, (MultiValuedValue, AnyValue, AnnotatedValue)):
11901190
signature = ctx.signature_from_value(other)
11911191
if signature is None:
11921192
return CanAssignError(f"{other} is not a callable type")

0 commit comments

Comments
 (0)