Skip to content

Commit

Permalink
Add typeshed bases to explicit type object bases (#635)
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra authored May 27, 2023
1 parent 580c8f2 commit 1ace9f0
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Take into account additional base classes declared in stub
files (fixing some false positives around `typing.IO`) (#635)
- Fix crash on stubs that contain dict or set literals (#634)
- Remove more old special cases and improve robustness of
annotation parsing (#630)
Expand Down
7 changes: 4 additions & 3 deletions pyanalyze/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,16 @@ def _build_type_object(self, typ: Union[type, super, str]) -> TypeObject:
elif isinstance(typ, super):
return TypeObject(typ, self.get_additional_bases(typ))
else:
additional_bases = self.get_additional_bases(typ)
plugin_bases = self.get_additional_bases(typ)
typeshed_bases = self._get_typeshed_bases(typ)
additional_bases = plugin_bases | typeshed_bases
# Is it marked as a protocol in stubs? If so, use the stub definition.
if self.ts_finder.is_protocol(typ):
bases = self._get_typeshed_bases(typ)
return TypeObject(
typ,
additional_bases,
is_protocol=True,
protocol_members=self._get_protocol_members(bases),
protocol_members=self._get_protocol_members(typeshed_bases),
)
# Is it a protocol at runtime?
if is_instance_of_typing_name(typ, "_ProtocolMeta") and safe_getattr(
Expand Down
30 changes: 30 additions & 0 deletions pyanalyze/test_type_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,33 @@ def capybara(t1: Type[int], t2: type):

want_hash([]) # E: incompatible_argument
want_myhash([]) # E: incompatible_argument


class TestIO(TestNameCheckVisitorBase):
@assert_passes()
def test_text(self):
from typing import TextIO
from typing_extensions import assert_type
import io

def want_io(x: TextIO):
x.write("hello")

def capybara():
with open("x") as f:
assert_type(f, io.TextIOWrapper)
want_io(f)

@assert_passes()
def test_binary(self):
from typing import BinaryIO
from typing_extensions import assert_type
import io

def want_io(x: BinaryIO):
x.write(b"hello")

def capybara():
with open("x", "rb") as f:
assert_type(f, io.BufferedReader)
want_io(f)

0 comments on commit 1ace9f0

Please sign in to comment.