Skip to content

Commit 61e08cc

Browse files
authored
Fix the int.__pow__ plugin (#7632)
A recent typeshed change added a modulo argument to int.__pow__ which broke the plugin. Tested manually. I didn't add a test because to be useful it would need to be a cmdline test (so it uses the real typeshed) and this doesn't seem worth adding a slow cmdline test for. Happy to add it if someone disagrees though. Fixes #7621.
1 parent 8f381b8 commit 61e08cc

File tree

5 files changed

+27
-23
lines changed

5 files changed

+27
-23
lines changed

mypy/plugins/default.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,10 @@ def typed_dict_update_signature_callback(ctx: MethodSigContext) -> CallableType:
365365

366366
def int_pow_callback(ctx: MethodContext) -> Type:
367367
"""Infer a more precise return type for int.__pow__."""
368-
if (len(ctx.arg_types) == 1
369-
and len(ctx.arg_types[0]) == 1):
368+
# int.__pow__ has an optional modulo argument,
369+
# so we expect 2 argument positions
370+
if (len(ctx.arg_types) == 2
371+
and len(ctx.arg_types[0]) == 1 and len(ctx.arg_types[1]) == 0):
370372
arg = ctx.args[0][0]
371373
if isinstance(arg, IntExpr):
372374
exponent = arg.value

mypy/test/testcmdline.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ def test_python_cmdline(testcase: DataDrivenTestCase, step: int) -> None:
8989
if obvious_result != result:
9090
out.append('== Return code: {}'.format(result))
9191
expected_out = testcase.output if step == 1 else testcase.output2[step]
92+
# Strip "tmp/" out of the test so that # E: works...
93+
expected_out = [s.replace("tmp" + os.sep, "") for s in expected_out]
9294
assert_string_arrays_equal(expected_out, out,
9395
'Invalid output ({}, line {}){}'.format(
9496
testcase.file, testcase.line,

test-data/unit/check-expressions.test

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,25 +2311,6 @@ class B: ...
23112311

23122312
[builtins fixtures/dict.pyi]
23132313

2314-
-- Type checker default plugin
2315-
-- ---------------------------
2316-
2317-
2318-
[case testIntPow]
2319-
a = 1
2320-
b = a + 2
2321-
reveal_type(a**0) # N: Revealed type is 'builtins.int'
2322-
reveal_type(a**1) # N: Revealed type is 'builtins.int'
2323-
reveal_type(a**2) # N: Revealed type is 'builtins.int'
2324-
reveal_type(a**-0) # N: Revealed type is 'builtins.int'
2325-
reveal_type(a**-1) # N: Revealed type is 'builtins.float'
2326-
reveal_type(a**(-2)) # N: Revealed type is 'builtins.float'
2327-
reveal_type(a**b) # N: Revealed type is 'Any'
2328-
reveal_type(a.__pow__(2)) # N: Revealed type is 'builtins.int'
2329-
reveal_type(a.__pow__(a)) # N: Revealed type is 'Any'
2330-
a.__pow__() # E: Too few arguments for "__pow__" of "int"
2331-
[builtins fixtures/ops.pyi]
2332-
23332314
[case testTypeAnnotationNeededMultipleAssignment]
23342315
x, y = [], [] # E: Need type annotation for 'x' (hint: "x: List[<type>] = ...") \
23352316
# E: Need type annotation for 'y' (hint: "y: List[<type>] = ...")

test-data/unit/cmdline.test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,25 @@ python_version = 3.4
578578
python_version = 3.6
579579
[out]
580580

581+
-- This should be a dumping ground for tests of plugins that are sensitive to
582+
-- typeshed changes.
583+
[case testTypeshedSensitivePlugins]
584+
# cmd: mypy int_pow.py
585+
586+
[file int_pow.py]
587+
a = 1
588+
b = a + 2
589+
reveal_type(a**0) # N: Revealed type is 'builtins.int'
590+
reveal_type(a**1) # N: Revealed type is 'builtins.int'
591+
reveal_type(a**2) # N: Revealed type is 'builtins.int'
592+
reveal_type(a**-0) # N: Revealed type is 'builtins.int'
593+
reveal_type(a**-1) # N: Revealed type is 'builtins.float'
594+
reveal_type(a**(-2)) # N: Revealed type is 'builtins.float'
595+
reveal_type(a**b) # N: Revealed type is 'Any'
596+
reveal_type(a.__pow__(2)) # N: Revealed type is 'builtins.int'
597+
reveal_type(a.__pow__(a)) # N: Revealed type is 'Any'
598+
a.__pow__() # E: Too few arguments for "__pow__" of "int"
599+
581600
[case testDisallowAnyUnimported]
582601
# cmd: mypy main.py
583602
[file mypy.ini]

test-data/unit/fixtures/ops.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import overload, Any, Generic, Sequence, Tuple, TypeVar
1+
from typing import overload, Any, Generic, Sequence, Tuple, TypeVar, Optional
22

33
Tco = TypeVar('Tco', covariant=True)
44

@@ -46,7 +46,7 @@ class int:
4646
def __rtruediv__(self, x: 'int') -> 'int': pass
4747
def __mod__(self, x: 'int') -> 'int': pass
4848
def __floordiv__(self, x: 'int') -> 'int': pass
49-
def __pow__(self, x: 'int') -> Any: pass
49+
def __pow__(self, x: 'int', __modulo: Optional[int] = ...) -> Any: pass
5050
def __pos__(self) -> 'int': pass
5151
def __neg__(self) -> 'int': pass
5252
def __eq__(self, x: object) -> bool: pass

0 commit comments

Comments
 (0)