Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit afb73cc

Browse files
Add some more inference (#35)
Fixes #28
1 parent d30ed2e commit afb73cc

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ Unreleased
8282
- Add `--pyanalyze-report`
8383
- Do not add `None` return types to methods marked with `@abstractmethod` and
8484
to methods in stub files
85+
- Improve type inference:
86+
- `"string" % ...` is always `str`
87+
- `b"bytes" % ...` is always `bytes`
88+
- An `and` or `or` operator where left and right sides are of the same type
89+
returns that type
90+
- `is`, `is not`, `in`, and `not in` always return `bool`
8591

8692
21.12.0 (December 21, 2021)
8793

autotyping/autotyping.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,25 @@ def type_of_expression(expr: libcst.BaseExpression) -> Optional[Type[object]]:
560560
expr.operator, libcst.Not
561561
):
562562
return bool
563+
elif isinstance(expr, libcst.BinaryOperation):
564+
left = type_of_expression(expr.left)
565+
if left in (str, bytes) and isinstance(expr.operator, libcst.Modulo):
566+
return left
567+
return None
568+
elif isinstance(expr, libcst.BooleanOperation):
569+
left = type_of_expression(expr.left)
570+
right = type_of_expression(expr.right)
571+
# For AND and OR, if both types are the same, we can infer that type.
572+
if left == right:
573+
return left
574+
else:
575+
return None
576+
elif isinstance(expr, libcst.Comparison):
577+
types = {type(comp.operator) for comp in expr.comparisons}
578+
# Only these are actually guaranteed to return bool
579+
if types <= {libcst.In, libcst.Is, libcst.IsNot, libcst.NotIn}:
580+
return bool
581+
return None
563582
elif (
564583
isinstance(expr, libcst.Call)
565584
and isinstance(expr.func, libcst.Attribute)

tests/test_codemod.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ def return_not(x):
8787
def formatter(x):
8888
return "{}".format(x)
8989
90+
def old_school_formatter(x):
91+
return "%s" % x
92+
93+
def bytes_formatter(x):
94+
return b"%s" % x
95+
96+
def boolean_return(x, y, z):
97+
return x is y or x in z
98+
9099
def baz() -> float:
91100
return "not a float"
92101
@@ -109,6 +118,15 @@ def return_not(x) -> bool:
109118
def formatter(x) -> str:
110119
return "{}".format(x)
111120
121+
def old_school_formatter(x) -> str:
122+
return "%s" % x
123+
124+
def bytes_formatter(x) -> bytes:
125+
return b"%s" % x
126+
127+
def boolean_return(x, y, z) -> bool:
128+
return x is y or x in z
129+
112130
def baz() -> float:
113131
return "not a float"
114132

0 commit comments

Comments
 (0)