From 027ba3b2dad5556645a2b45dc6b9365286c8df83 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Thu, 6 Aug 2020 20:31:15 -0700 Subject: [PATCH 1/5] plugins: delete open plugin Improvements to typeshed types using literals should have rendered this unnecessary. --- mypy/plugins/default.py | 61 ++--------------------------------------- 1 file changed, 2 insertions(+), 59 deletions(-) diff --git a/mypy/plugins/default.py b/mypy/plugins/default.py index dc17450664c8..cb4b7f71a2c8 100644 --- a/mypy/plugins/default.py +++ b/mypy/plugins/default.py @@ -2,10 +2,9 @@ from typing import Callable, Optional, List from mypy import message_registry -from mypy.nodes import Expression, StrExpr, IntExpr, DictExpr, UnaryExpr +from mypy.nodes import StrExpr, IntExpr, DictExpr, UnaryExpr from mypy.plugin import ( - Plugin, FunctionContext, MethodContext, MethodSigContext, AttributeContext, ClassDefContext, - CheckerPluginInterface, + Plugin, FunctionContext, MethodContext, MethodSigContext, AttributeContext, ClassDefContext ) from mypy.plugins.common import try_getting_str_literals from mypy.types import ( @@ -26,8 +25,6 @@ def get_function_hook(self, fullname: str if fullname == 'contextlib.contextmanager': return contextmanager_callback - elif fullname == 'builtins.open' and self.python_version[0] == 3: - return open_callback elif fullname == 'ctypes.Array': return ctypes.array_constructor_callback return None @@ -70,8 +67,6 @@ def get_method_hook(self, fullname: str return ctypes.array_getitem_callback elif fullname == 'ctypes.Array.__iter__': return ctypes.array_iter_callback - elif fullname == 'pathlib.Path.open': - return path_open_callback return None def get_attribute_hook(self, fullname: str @@ -106,58 +101,6 @@ def get_class_decorator_hook(self, fullname: str return None -def open_callback(ctx: FunctionContext) -> Type: - """Infer a better return type for 'open'.""" - return _analyze_open_signature( - arg_types=ctx.arg_types, - args=ctx.args, - mode_arg_index=1, - default_return_type=ctx.default_return_type, - api=ctx.api, - ) - - -def path_open_callback(ctx: MethodContext) -> Type: - """Infer a better return type for 'pathlib.Path.open'.""" - return _analyze_open_signature( - arg_types=ctx.arg_types, - args=ctx.args, - mode_arg_index=0, - default_return_type=ctx.default_return_type, - api=ctx.api, - ) - - -def _analyze_open_signature(arg_types: List[List[Type]], - args: List[List[Expression]], - mode_arg_index: int, - default_return_type: Type, - api: CheckerPluginInterface, - ) -> Type: - """A helper for analyzing any function that has approximately - the same signature as the builtin 'open(...)' function. - - Currently, the only thing the caller can customize is the index - of the 'mode' argument. If the mode argument is omitted or is a - string literal, we refine the return type to either 'TextIO' or - 'BinaryIO' as appropriate. - """ - mode = None - if not arg_types or len(arg_types[mode_arg_index]) != 1: - mode = 'r' - else: - mode_expr = args[mode_arg_index][0] - if isinstance(mode_expr, StrExpr): - mode = mode_expr.value - if mode is not None: - assert isinstance(default_return_type, Instance) # type: ignore - if 'b' in mode: - return api.named_generic_type('typing.BinaryIO', []) - else: - return api.named_generic_type('typing.TextIO', []) - return default_return_type - - def contextmanager_callback(ctx: FunctionContext) -> Type: """Infer a better return type for 'contextlib.contextmanager'.""" # Be defensive, just in case. From 6ac771c73eeea78ed76efec5653d8953e88f0459 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Thu, 6 Aug 2020 21:05:35 -0700 Subject: [PATCH 2/5] update tests --- .../stdlib-samples/3.2/test/test_base64.py | 4 +-- .../3.2/test/test_genericpath.py | 35 ++++++++----------- test-data/unit/pythoneval.test | 14 ++++---- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/test-data/stdlib-samples/3.2/test/test_base64.py b/test-data/stdlib-samples/3.2/test/test_base64.py index 9e4dcf5544ed..c20f2f887e8b 100644 --- a/test-data/stdlib-samples/3.2/test/test_base64.py +++ b/test-data/stdlib-samples/3.2/test/test_base64.py @@ -248,8 +248,8 @@ def test_encode_file(self) -> None: output = self.get_output('-e', support.TESTFN) self.assertEqual(output.rstrip(), b'Yf9iCg==') - with open(support.TESTFN, 'rb') as fp: - output = self.get_output('-e', stdin=fp) + with open(support.TESTFN, 'rb') as fp2: + output = self.get_output('-e', stdin=fp2) self.assertEqual(output.rstrip(), b'Yf9iCg==') def test_decode(self) -> None: diff --git a/test-data/stdlib-samples/3.2/test/test_genericpath.py b/test-data/stdlib-samples/3.2/test/test_genericpath.py index df0e10701d39..8470e5805744 100644 --- a/test-data/stdlib-samples/3.2/test/test_genericpath.py +++ b/test-data/stdlib-samples/3.2/test/test_genericpath.py @@ -114,26 +114,21 @@ def test_getsize(self) -> None: support.unlink(support.TESTFN) def test_time(self) -> None: - f = open(support.TESTFN, "wb") - try: - f.write(b"foo") - f.close() - f = open(support.TESTFN, "ab") - f.write(b"bar") - f.close() - f = open(support.TESTFN, "rb") - d = f.read() - f.close() - self.assertEqual(d, b"foobar") - - self.assertLessEqual( - self.pathmodule.getctime(support.TESTFN), - self.pathmodule.getmtime(support.TESTFN) - ) - finally: - if not f.closed: - f.close() - support.unlink(support.TESTFN) + f1 = open(support.TESTFN, "wb") + f1.write(b"foo") + f1.close() + f2 = open(support.TESTFN, "ab") + f2.write(b"bar") + f2.close() + f3 = open(support.TESTFN, "rb") + d = f3.read() + f3.close() + self.assertEqual(d, b"foobar") + + self.assertLessEqual( + self.pathmodule.getctime(support.TESTFN), + self.pathmodule.getmtime(support.TESTFN) + ) def test_exists(self) -> None: self.assertIs(self.pathmodule.exists(support.TESTFN), False) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index e3eaf8a00ff3..7ffb3c971aa9 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -271,8 +271,8 @@ f.write('x') f.write(b'x') f.foobar() [out] -_program.py:3: error: Argument 1 to "write" of "IO" has incompatible type "bytes"; expected "str" -_program.py:4: error: "TextIO" has no attribute "foobar" +_program.py:3: error: Argument 1 to "write" of "TextIOBase" has incompatible type "bytes"; expected "str" +_program.py:4: error: "TextIOWrapper" has no attribute "foobar" [case testOpenReturnTypeInference] reveal_type(open('x')) @@ -281,9 +281,9 @@ reveal_type(open('x', 'rb')) mode = 'rb' reveal_type(open('x', mode)) [out] -_program.py:1: note: Revealed type is 'typing.TextIO' -_program.py:2: note: Revealed type is 'typing.TextIO' -_program.py:3: note: Revealed type is 'typing.BinaryIO' +_program.py:1: note: Revealed type is 'io.TextIOWrapper' +_program.py:2: note: Revealed type is 'io.TextIOWrapper' +_program.py:3: note: Revealed type is 'io.BufferedReader' _program.py:5: note: Revealed type is 'typing.IO[Any]' [case testOpenReturnTypeInferenceSpecialCases] @@ -292,8 +292,8 @@ reveal_type(open(file='x', mode='rb')) mode = 'rb' reveal_type(open(mode=mode, file='r')) [out] -_testOpenReturnTypeInferenceSpecialCases.py:1: note: Revealed type is 'typing.BinaryIO' -_testOpenReturnTypeInferenceSpecialCases.py:2: note: Revealed type is 'typing.BinaryIO' +_testOpenReturnTypeInferenceSpecialCases.py:1: note: Revealed type is 'io.BufferedReader' +_testOpenReturnTypeInferenceSpecialCases.py:2: note: Revealed type is 'io.BufferedReader' _testOpenReturnTypeInferenceSpecialCases.py:4: note: Revealed type is 'typing.IO[Any]' [case testPathOpenReturnTypeInference] From e7061efe1f4a10fe7c05da20ddf903dcb6995ef4 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Thu, 6 Aug 2020 21:22:13 -0700 Subject: [PATCH 3/5] fix ensuing type errors --- mypy/report.py | 4 ++-- mypyc/build.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mypy/report.py b/mypy/report.py index ae51e1c5fd8d..52ae798d5816 100644 --- a/mypy/report.py +++ b/mypy/report.py @@ -243,10 +243,10 @@ def _write_out_report(self, f.write(separator + '\n') for row_values in rows: r = ("{:>{}}" * len(widths)).format(*itertools.chain(*zip(row_values, widths))) - f.writelines(r + '\n') + f.write(r + '\n') f.write(separator + '\n') footer_str = ("{:>{}}" * len(widths)).format(*itertools.chain(*zip(footer, widths))) - f.writelines(footer_str + '\n') + f.write(footer_str + '\n') def _report_any_exprs(self) -> None: total_any = sum(num_any for num_any, _ in self.counts.values()) diff --git a/mypyc/build.py b/mypyc/build.py index 0a0cf3b03a27..449852947299 100644 --- a/mypyc/build.py +++ b/mypyc/build.py @@ -301,8 +301,8 @@ def write_file(path: str, contents: str) -> None: old_contents = None if old_contents != encoded_contents: os.makedirs(os.path.dirname(path), exist_ok=True) - with open(path, 'wb') as f: - f.write(encoded_contents) + with open(path, 'wb') as g: + g.write(encoded_contents) # Fudge the mtime forward because otherwise when two builds happen close # together (like in a test) setuptools might not realize the source is newer From d2b37c7b5c2875c662e0c3d1541c54e40449cf99 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 21 Aug 2020 21:16:16 -0700 Subject: [PATCH 4/5] update pathlib tests --- test-data/unit/pythoneval.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 7ffb3c971aa9..d1535b1acbc9 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -305,9 +305,9 @@ reveal_type(p.open('rb')) mode = 'rb' reveal_type(p.open(mode)) [out] -_program.py:3: note: Revealed type is 'typing.TextIO' -_program.py:4: note: Revealed type is 'typing.TextIO' -_program.py:5: note: Revealed type is 'typing.BinaryIO' +_program.py:3: note: Revealed type is 'io.TextIOWrapper' +_program.py:4: note: Revealed type is 'io.TextIOWrapper' +_program.py:5: note: Revealed type is 'io.BufferedReader' _program.py:7: note: Revealed type is 'typing.IO[Any]' [case testPathOpenReturnTypeInferenceSpecialCases] From 85026991fec7cf0ca2e2aa78ddb03c793585a3db Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 21 Aug 2020 21:19:16 -0700 Subject: [PATCH 5/5] fix pathlib tests to not use binary mode Since errors shouldn't be used with binary modes. Maybe should just delete? --- test-data/unit/pythoneval.test | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index d1535b1acbc9..9e3dfbe07ed0 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -313,13 +313,13 @@ _program.py:7: note: Revealed type is 'typing.IO[Any]' [case testPathOpenReturnTypeInferenceSpecialCases] from pathlib import Path p = Path("x") -reveal_type(p.open(mode='rb', errors='replace')) -reveal_type(p.open(errors='replace', mode='rb')) -mode = 'rb' +reveal_type(p.open(mode='r', errors='replace')) +reveal_type(p.open(errors='replace', mode='r')) +mode = 'r' reveal_type(p.open(mode=mode, errors='replace')) [out] -_program.py:3: note: Revealed type is 'typing.BinaryIO' -_program.py:4: note: Revealed type is 'typing.BinaryIO' +_program.py:3: note: Revealed type is 'io.TextIOWrapper' +_program.py:4: note: Revealed type is 'io.TextIOWrapper' _program.py:6: note: Revealed type is 'typing.IO[Any]' [case testGenericPatterns]