8000 Better callable: `Callable[[Arg('x', int), VarArg(str)], int]` now a thing you can do by sixolet · Pull Request #2607 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Better callable: Callable[[Arg('x', int), VarArg(str)], int] now a thing you can do #2607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
May 2, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
249d70f
Implement Callable[[Arg('name', Type)], ret] syntax
sixolet Nov 11, 2016
7ecdcc1
General cleanup
sixolet Dec 24, 2016
066bd5e
Change tests back to match old behavior
sixolet Dec 24, 2016
213944b
lots of lint
sixolet Dec 24, 2016
0e19070
Oh god I am tired of writing parsers
sixolet Dec 25, 2016
3f2f617
Tighten fastparse a little
sixolet Dec 25, 2016
0b69630
make all tests pass now
sixolet Dec 25, 2016
f4ccf92
go back to master version of typeshed I guess
sixolet Dec 25, 2016
967bb5a
Meged master, but tests fail again now.
sixolet Apr 12, 2017
bb5134e
Tests all pass again after merge
sixolet Apr 18, 2017
d4a83e1
Merged master again
sixolet Apr 18, 2017
54a5da9
Big refactor. Wait until semanal to get arg kinds, switch order again…
sixolet Apr 20, 2017
e79c527
Change back to TypeList
sixolet Apr 20, 2017
52ffe5c
Cleanups. Preparing to split into two diffs maybe?
sixolet Apr 20, 2017
06416f7
update typeshed to master version
sixolet Apr 20, 2017
398fbad
more cleanups
sixolet Apr 20, 2017
2c9ce02
should not have changed these test files
sixolet Apr 20, 2017
51c6f56
Semanal needs to be a SyntheticTypeVisitor
sixolet Apr 20, 2017
5e679a3
Annot
sixolet Apr 20, 2017
0926fe9
Oops
sixolet Apr 20, 2017
288a8be
Add testing for exprtotype Arg constructors in wierd places
sixolet Apr 20, 2017
6e67ab2
Remove some ill-modified modifications to tests
sixolet Apr 20, 2017
97a859b
Merge master, no longer depend on other PR
sixolet Apr 20, 2017
1c7d4c6
Jukka comments
sixolet Apr 21, 2017
f153850
Synthetic types don't serialize
sixolet Apr 21, 2017
be954f5
Remove unused instance var
sixolet Apr 21, 2017
07ae917
Merge master
sixolet Apr 22, 2017
1b97362
Revert "Remove unused instance var"
sixolet Apr 22, 2017
552f49e
Accessing TypeList types directly is not required
sixolet Apr 22, 2017
f2e3663
Undo changes to this file they were not required
sixolet Apr 22, 2017
27e2a9d
lint
sixolet Apr 22, 2017
793a663
Merge master again
sixolet Apr 22, 2017
3d212b3
Merge master
sixolet May 1, 2017
0780149
Disallow CallableArgument in exprtotype outside a TypeList
sixolet May 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge master
  • Loading branch information
sixolet committed Apr 22, 2017
commit 07ae91727d4289cbde5ece4b44a1fc47301bed71
3 changes: 3 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ environment:


install:
- "git config core.symlinks true"
- "git reset --hard"
- "%PYTHON%\\python.exe -m pip install -r test-requirements.txt"
- "git submodule update --init typeshed"
- "cd typeshed && git reset --hard && cd .."
- "%PYTHON%\\python.exe setup.py -q install"

build: off
Expand Down
1 change: 0 additions & 1 deletion docs/source/cheat_sheet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ When you're puzzled or when things are complicated
# type: (*str, **str) -> str
request = make_request(*args, **kwargs)
return self.do_api_query(request)


# Use `ignore` to suppress type-checking on a given line, when your
# code confuses mypy or runs into an outright bug in mypy.
Expand Down
6 changes: 6 additions & 0 deletions docs/source/cheat_sheet_py3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ When you're puzzled or when things are complicated
# dynamic to write a type for.
x = mystery_function() # type: Any

# This is how to deal with varargs.
# This makes each positional arg and each keyword arg a 'str'.
def call(self, *args: str, **kwargs: str) -> str:
request = make_request(*args, **kwargs)
return self.do_api_query(request)

# Use `ignore` to suppress type-checking on a given line, when your
# code confuses mypy or runs into an outright bug in mypy.
# Good practice is to comment every `ignore` with a bug link
Expand Down
7 changes: 1 addition & 6 deletions docs/source/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ flag (or its long form ``--help``)::
[--inferstats] [--custom-typing MODULE]
[--custom-typeshed-dir DIR] [--scripts-are-modules]
[--config-file CONFIG_FILE] [--show-column-numbers]
[--find-occurrences CLASS.MEMBER] [--strict-boolean]
[--find-occurrences CLASS.MEMBER]
[--cobertura-xml-report DIR] [--html-report DIR]
[--linecount-report DIR] [--linecoverage-report DIR]
[--memory-xml-report DIR] [--old-html-report DIR]
Expand Down Expand Up @@ -366,11 +366,6 @@ Here are some more useful flags:
- ``--warn-return-any`` causes mypy to generate a warning when returning a value
with type ``Any`` from a function declared with a non- ``Any`` return type.

- ``--strict-boolean`` will make using non-boolean expressions in conditions
an error. This means ``if x`` and ``while x`` are disallowed when ``x`` has any
type other than ``bool``. Instead use explicit checks like ``if x > 0`` or
``while x is not None``.

- ``--strict`` mode enables all optional error checking flags. You can see the
list of flags enabled by strict mode in the full ``mypy -h`` output.

Expand Down
3 changes: 3 additions & 0 deletions docs/source/revision_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Revision history

List of major changes to this document:

- April 2017
* Remove option ``strict_boolean``.

- March 2017
* Publish ``mypy`` version 0.500 on PyPI.

Expand Down
65 changes: 52 additions & 13 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2675,6 +2675,21 @@ def or_conditional_maps(m1: TypeMap, m2: TypeMap) -> TypeMap:
return result


def convert_to_typetype(type_map: TypeMap) -> TypeMap:
converted_type_map = {} # type: TypeMap
if type_map is None:
return None
for expr, typ in type_map.items():
if isinstance(typ, UnionType):
converted_type_map[expr] = UnionType([TypeType(t) for t in typ.items])
elif isinstance(typ, Instance):
converted_type_map[expr] = TypeType(typ)
else:
# unknown type; error was likely reported earlier
return {}
return converted_type_map


def find_isinstance_check(node: Expression,
type_map: Dict[Expression, Type],
) -> Tuple[TypeMap, TypeMap]:
Expand All @@ -2700,8 +2715,32 @@ def find_isinstance_check(node: Expression,
expr = node.args[0]
if expr.literal == LITERAL_TYPE:
vartype = type_map[expr]
types = get_isinstance_type(node.args[1], type_map)
return conditional_type_map(expr, vartype, types)
type = get_isinstance_type(node.args[1], type_map)
return conditional_type_map(expr, vartype, type)
elif refers_to_fullname(node.callee, 'builtins.issubclass'):
expr = node.args[0]
if expr.literal == LITERAL_TYPE:
vartype = type_map[expr]
type = get_isinstance_type(node.args[1], type_map)
if isinstance(vartype, UnionType):
union_list = []
for t in vartype.items:
if isinstance(t, TypeType):
union_list.append(t.item)
else:
# this is an error that should be reported earlier
# if we reach here, we refuse to do any type inference
return {}, {}
vartype = UnionType(union_list)
elif isinstance(vartype, TypeType):
vartype = vartype.item
else:
# any other object whose type we don't know precisely
# for example, Any or Instance of type type
return {}, {} # unknown type
yes_map, no_map = conditional_type_map(expr, vartype, type)
yes_map, no_map = map(convert_to_typetype, (yes_map, no_map))
return yes_map, no_map
elif refers_to_fullname(node.callee, 'builtins.callable'):
expr = node.args[0]
if expr.literal == LITERAL_TYPE:
Expand Down Expand Up @@ -2793,18 +2832,18 @@ def flatten_types(t: Type) -> List[Type]:
def get_isinstance_type(expr: Expression, type_map: Dict[Expression, Type]) -> List[TypeRange]:
all_types = flatten_types(type_map[expr])
types = [] # type: List[TypeRange]
for type in all_types:
if isinstance(type, FunctionLike) and type.is_type_obj():
for typ in all_types:
if isinstance(typ, FunctionLike) and typ.is_type_obj():
# Type variables may be present -- erase them, which is the best
# we can do (outside disallowing them here).
type = erase_typevars(type.items()[0].ret_type)
types.append(TypeRange(type, is_upper_bound=False))
elif isinstance(type, TypeType):
typ = erase_typevars(typ.items()[0].ret_type)
types.append(TypeRange(typ, is_upper_bound=False))
elif isinstance(typ, TypeType):
# Type[A] means "any type that is a subtype of A" rather than "precisely type A"
# we indicate this by setting is_upper_bound flag
types.append(TypeRange(type.item, is_upper_bound=True))
elif isinstance(type, Instance) and type.type.fullname() == 'builtins.type':
object_type = Instance(type.type.mro[-1], [])
types.append(TypeRange(typ.item, is_upper_bound=True))
elif isinstance(typ, Instance) and typ.type.fullname() == 'builtins.type':
object_type = Instance(typ.type.mro[-1], [])
types.append(TypeRange(object_type, is_upper_bound=True))
else: # we didn't see an actual type, but rather a variable whose value is unknown to us
return None
Expand Down Expand Up @@ -2955,17 +2994,17 @@ def is_more_precise_signature(t: CallableType, s: CallableType) -> bool:
return is_more_precise(t.ret_type, s.ret_type)


def infer_operator_assignment_method(type: Type, operator: str) -> Tuple[bool, str]:
def infer_operator_assignment_method(typ: Type, operator: str) -> Tuple[bool, str]:
"""Determine if operator assignment on given value type is in-place, and the method name.

For example, if operator is '+', return (True, '__iadd__') or (False, '__add__')
depending on which method is supported by the type.
"""
method = nodes.op_methods[operator]
if isinstance(type, Instance):
if isinstance(typ, Instance):
if operator in nodes.ops_with_inplace_method:
inplace_method = '__i' + method[2:]
if type.type.has_readable_member(inplace_method):
if typ.type.has_readable_member(inplace_method):
return True, inplace_method
return False, method

Expand Down
5 changes: 2 additions & 3 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
DictionaryComprehension, ComplexExpr, EllipsisExpr, StarExpr, AwaitExpr, YieldExpr,
YieldFromExpr, TypedDictExpr, PromoteExpr, NewTypeExpr, NamedTupleExpr, TypeVarExpr,
TypeAliasExpr, BackquoteExpr, EnumCallExpr,
ARG_POS, ARG_NAMED, ARG_STAR, ARG_STAR2, MODULE_REF,
UNBOUND_TVAR, BOUND_TVAR, LITERAL_TYPE
ARG_POS, ARG_NAMED, ARG_STAR, ARG_STAR2, MODULE_REF, TVAR, LITERAL_TYPE,
)
from mypy import nodes
import mypy.checker
Expand Down Expand Up @@ -1623,7 +1622,7 @@ def replace_tvars_any(self, tp: Type) -> Type:
sym = self.chk.lookup_qualified(arg.name)
except KeyError:
pass
if sym and (sym.kind == UNBOUND_TVAR or sym.kind == BOUND_TVAR):
if sym and (sym.kind == TVAR):
new_args[i] = AnyType()
else:
new_args[i] = self.replace_tvars_any(arg)
Expand Down
3 changes: 3 additions & 0 deletions mypy/fixup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
)
from mypy.visitor import NodeVisitor

from mypy.semanal import rev_module_rename_map


def fixup_module_pass_one(tree: MypyFile, modules: Dict[str, MypyFile],
quick_and_dirty: bool) -> None:
Expand Down Expand Up @@ -241,6 +243,7 @@ def lookup_qualified(modules: Dict[str, MypyFile], name: str,

def lookup_qualified_stnode(modules: Dict[str, MypyFile], name: str,
quick_and_dirty: bool) -> Optional[SymbolTableNode]:
name = rev_module_rename_map.get(name, name)
head = name
rest = []
while True:
Expand Down
7 changes: 5 additions & 2 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,6 @@ def add_invertible_flag(flag: str,
parser.add_argument('--find-occurrences', metavar='CLASS.MEMBER',
dest='special-opts:find_occurrences',
help="print out all usages of a class member (experimental)")
add_invertible_flag('--strict-boolean', default=False, strict_flag=True,
help='enable strict boolean checks in conditions')
strict_help = "Strict mode. Enables the following flags: {}".format(
", ".join(strict_flag_names))
parser.add_argument('--strict', action='store_true', dest='special-opts:strict',
Expand All @@ -292,6 +290,8 @@ def add_invertible_flag(flag: str,
# --dump-graph will dump the contents of the graph of SCCs and exit.
parser.add_argument('--dump-graph', action='store_true', help=argparse.SUPPRESS)
# deprecated options
a FEE1 dd_invertible_flag('--strict-boolean', default=False,
help=argparse.SUPPRESS)
parser.add_argument('-f', '--dirty-stubs', action='store_true',
dest='special-opts:dirty_stubs',
help=argparse.SUPPRESS)
Expand Down Expand Up @@ -364,6 +364,9 @@ def add_invertible_flag(flag: str,
)

# Process deprecated options
if options.strict_boolean:
print("Warning: --strict-boolean is deprecated; "
"see https://github.com/python/mypy/issues/3195", file=sys.stderr)
if special_opts.almost_silent:
print("Warning: --almost-silent has been replaced by "
"--follow-imports=errors", file=sys.stderr)
Expand Down
22 changes: 6 additions & 16 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ def get_column(self) -> int: pass
GDEF = 1 # type: int
MDEF = 2 # type: int
MODULE_REF = 3 # type: int
# Type variable declared using TypeVar(...) has kind UNBOUND_TVAR. It's not
# valid as a type. A type variable is valid as a type (kind BOUND_TVAR) within
# Type variable declared using TypeVar(...) has kind TVAR. It's not
# valid as a type unless bound in a TypeVarScope. That happens within:
# (1) a generic class that uses the type variable as a type argument or
# (2) a generic function that refers to the type variable in its signature.
UNBOUND_TVAR = 4 # type: int
BOUND_TVAR = 5 # type: int
TVAR = 4 # type: int

TYPE_ALIAS = 6 # type: int
# Placeholder for a name imported via 'from ... import'. Second phase of
# semantic will replace this the actual imported reference. This is
Expand All @@ -65,8 +65,7 @@ def get_column(self) -> int: pass
GDEF: 'Gdef',
MDEF: 'Mdef',
MODULE_REF: 'ModuleRef',
UNBOUND_TVAR: 'UnboundTvar',
BOUND_TVAR: 'Tvar',
TVAR: 'Tvar',
TYPE_ALIAS: 'TypeAlias',
UNBOUND_IMPORTED: 'UnboundImported',
}
Expand Down Expand Up @@ -2211,17 +2210,14 @@ class SymbolTableNode:
# - LDEF: local definition (of any kind)
# - GDEF: global (module-level) definition
# - MDEF: class member definition
# - UNBOUND_TVAR: TypeVar(...) definition, not bound
# - TVAR: type variable in a bound scope (generic function / generic clas)
# - TVAR: TypeVar(...) definition
# - MODULE_REF: reference to a module
# - TYPE_ALIAS: type alias
# - UNBOUND_IMPORTED: temporary kind for imported names
kind = None # type: int
# AST node of definition (FuncDef/Var/TypeInfo/Decorator/TypeVarExpr,
# or None for a bound type variable).
node = None # type: Optional[SymbolNode]
# Type variable definition (for bound type variables only)
tvar_def = None # type: Optional[mypy.types.TypeVarDef]
# Module id (e.g. "foo.bar") or None
mod_id = ''
# If this not None, override the type of the 'node' attribute.
Expand All @@ -2237,13 +2233,11 @@ class SymbolTableNode:

def __init__(self, kind: int, node: Optional[SymbolNode], mod_id: str = None,
typ: 'mypy.types.Type' = None,
tvar_def: 'mypy.types.TypeVarDef' = None,
module_public: bool = True, normalized: bool = False) -> None:
self.kind = kind
self.node = node
self.type_override = typ
self.mod_id = mod_id
self.tvar_def = tvar_def
self.module_public = module_public
self.normalized = normalized

Expand Down Expand Up @@ -2287,8 +2281,6 @@ def serialize(self, prefix: str, name: str) -> JsonDict:
data = {'.class': 'SymbolTableNode',
'kind': node_kinds[self.kind],
} # type: JsonDict
if self.tvar_def:
data['tvar_def'] = self.tvar_def.serialize()
if not self.module_public:
data['module_public'] = False
if self.kind == MODULE_REF:
Expand Down Expand Up @@ -2323,8 +2315,6 @@ def deserialize(cls, data: JsonDict) -> 'SymbolTableNode':
if 'type_override' in data:
typ = mypy.types.deserialize_type(data['type_override'])
stnode = SymbolTableNode(kind, node, typ=typ)
if 'tvar_def' in data:
stnode.tvar_def = mypy.types.TypeVarDef.deserialize(data['tvar_def'])
if 'module_public' in data:
stnode.module_public = data['module_public']
return stnode
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.
0