Skip to content

Commit bf90e2c

Browse files
ilinumgvanrossum
authored andcommitted
Replace --disallow-any flags with separate boolean flags. (#4178)
This PR also gets rid of `--disallow-any=unannotated` because it is the same thing as `--disallow-untyped-defs`. Fix #4089
1 parent c496504 commit bf90e2c

File tree

13 files changed

+149
-242
lines changed

13 files changed

+149
-242
lines changed

docs/source/command_line.rst

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,35 @@ directory. The four possible values are:
249249
main.py:1: note: Import of 'submodule' ignored
250250
main.py:1: note: (Using --follow-imports=error, module not passed on command line)
251251

252+
Disallow Any Flags
253+
*****************************
254+
The ``--disallow-any`` family of flags disallows various types of ``Any`` in a module.
255+
The following options are available:
256+
257+
- ``--disallow-any-unimported`` disallows usage of types that come from unfollowed imports
258+
(such types become aliases for ``Any``). Unfollowed imports occur either
259+
when the imported module does not exist or when ``--follow-imports=skip``
260+
is set.
261+
262+
- ``--disallow-any-expr`` disallows all expressions in the module that have type ``Any``.
263+
If an expression of type ``Any`` appears anywhere in the module
264+
mypy will output an error unless the expression is immediately
265+
used as an argument to ``cast`` or assigned to a variable with an
266+
explicit type annotation. In addition, declaring a variable of type ``Any``
267+
or casting to type ``Any`` is not allowed. Note that calling functions
268+
that take parameters of type ``Any`` is still allowed.
269+
270+
- ``--disallow-any-decorated`` disallows functions that have ``Any`` in their signature
271+
after decorator transformation.
272+
273+
- ``--disallow-any-explicit`` disallows explicit ``Any`` in type positions such as type
274+
annotations and generic type parameters.
275+
276+
- ``--disallow-any-generics`` disallows usage of generic types that do not specify explicit
277+
type parameters. Moreover, built-in collections (such as ``list`` and
278+
``dict``) become disallowed as you should use their aliases from the typing
279+
module (such as ``List[int]`` and ``Dict[str, str]``).
280+
252281

253282
Additional command line flags
254283
*****************************
@@ -277,42 +306,6 @@ Here are some more useful flags:
277306
re-check your code without ``--strict-optional`` to ensure new type errors
278307
are not introduced.
279308

280-
.. _disallow-any:
281-
282-
- ``--disallow-any`` disallows various types of ``Any`` in a module.
283-
The option takes a comma-separated list of the following values:
284-
``unimported``, ``unannotated``, ``expr``, ``decorated``, ``explicit``,
285-
``generics``.
286-
287-
``unimported`` disallows usage of types that come from unfollowed imports
288-
(such types become aliases for ``Any``). Unfollowed imports occur either
289-
when the imported module does not exist or when ``--follow-imports=skip``
290-
is set.
291-
292-
``unannotated`` disallows function definitions that are not fully
293-
typed (i.e. that are missing an explicit type annotation for any
294-
of the parameters or the return type). ``unannotated`` option is
295-
interchangeable with ``--disallow-untyped-defs``.
296-
297-
``expr`` disallows all expressions in the module that have type ``Any``.
298-
If an expression of type ``Any`` appears anywhere in the module
299-
mypy will output an error unless the expression is immediately
300-
used as an argument to ``cast`` or assigned to a variable with an
301-
explicit type annotation. In addition, declaring a variable of type ``Any``
302-
or casting to type ``Any`` is not allowed. Note that calling functions
303-
that take parameters of type ``Any`` is still allowed.
304-
305-
``decorated`` disallows functions that have ``Any`` in their signature
306-
after decorator transformation.
307-
308-
``explicit`` disallows explicit ``Any`` in type positions such as type
309-
annotations and generic type parameters.
310-
311-
``generics`` disallows usage of generic types that do not specify explicit
312-
type parameters. Moreover, built-in collections (such as ``list`` and
313-
``dict``) become disallowed as you should use their aliases from the typing
314-
module (such as ``List[int]`` and ``Dict[str, str]``).
315-
316309
- ``--disallow-untyped-defs`` reports an error whenever it encounters
317310
a function definition without type annotations.
318311

docs/source/config_file.rst

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,20 @@ overridden by the pattern sections matching the module name.
156156
- ``almost_silent`` (Boolean, deprecated) equivalent to
157157
``follow_imports=skip``.
158158

159-
- ``disallow_any`` (Comma-separated list, default empty) is an option to
160-
disallow various types of ``Any`` in a module. The flag takes a
161-
comma-separated list of the following arguments: ``unimported``,
162-
``unannotated``, ``expr``, ``decorated``, ``explicit``, ``generics``.
163-
For explanations see the discussion for the :ref:`--disallow-any <disallow-any>` option.
159+
- ``disallow_any_unimported`` (Boolean, default false) disallows usage of types that come
160+
from unfollowed imports (such types become aliases for ``Any``).
161+
162+
- ``disallow_any_expr`` (Boolean, default false) disallows all expressions in the module
163+
that have type ``Any``.
164+
165+
- ``disallow_any_decorated`` (Boolean, default false) disallows functions that have ``Any``
166+
in their signature after decorator transformation.
167+
168+
- ``disallow_any_explicit`` (Boolean, default false) disallows explicit ``Any`` in type
169+
positions such as type annotations and generic type parameters.
170+
171+
- ``disallow_any_generics`` (Boolean, default false) disallows usage of generic types that
172+
do not specify explicit type parameters.
164173

165174
- ``disallow_subclassing_any`` (Boolean, default False) disallows
166175
subclassing a value of type ``Any``. See

mypy/checker.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str])
624624
item)
625625

626626
self.check_for_missing_annotations(fdef)
627-
if 'unimported' in self.options.disallow_any:
627+
if self.options.disallow_any_unimported:
628628
if fdef.type and isinstance(fdef.type, CallableType):
629629
ret_type = fdef.type.ret_type
630630
if has_any_from_unimported_type(ret_type):
@@ -1312,7 +1312,7 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
13121312
self.check_assignment(s.lvalues[-1], s.rvalue, s.type is None, s.new_syntax)
13131313

13141314
if (s.type is not None and
1315-
'unimported' in self.options.disallow_any and
1315+
self.options.disallow_any_unimported and
13161316
has_any_from_unimported_type(s.type)):
13171317
if isinstance(s.lvalues[-1], TupleExpr):
13181318
# This is a multiple assignment. Instead of figuring out which type is problematic,
@@ -2524,7 +2524,7 @@ def visit_with_stmt(self, s: WithStmt) -> None:
25242524
self.accept(s.body)
25252525

25262526
def check_untyped_after_decorator(self, typ: Type, func: FuncDef) -> None:
2527-
if 'decorated' not in self.options.disallow_any or self.is_stub:
2527+
if not self.options.disallow_any_decorated or self.is_stub:
25282528
return
25292529

25302530
if mypy.checkexpr.has_any_type(typ):

mypy/checkexpr.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,7 +1786,7 @@ def visit_cast_expr(self, expr: CastExpr) -> Type:
17861786
options = self.chk.options
17871787
if options.warn_redundant_casts and is_same_type(source_type, target_type):
17881788
self.msg.redundant_cast(target_type, expr)
1789-
if 'unimported' in options.disallow_any and has_any_from_unimported_type(target_type):
1789+
if options.disallow_any_unimported and has_any_from_unimported_type(target_type):
17901790
self.msg.unimported_type_becomes_any("Target type of cast", target_type, expr)
17911791
check_for_explicit_any(target_type, self.chk.options, self.chk.is_typeshed_stub, self.msg,
17921792
context=expr)
@@ -2379,7 +2379,7 @@ def accept(self,
23792379
assert typ is not None
23802380
self.chk.store_type(node, typ)
23812381

2382-
if ('expr' in self.chk.options.disallow_any and
2382+
if (self.chk.options.disallow_any_expr and
23832383
not always_allow_any and
23842384
not self.chk.is_stub and
23852385
self.chk.in_checked_function() and
@@ -2558,7 +2558,7 @@ def visit_newtype_expr(self, e: NewTypeExpr) -> Type:
25582558
def visit_namedtuple_expr(self, e: NamedTupleExpr) -> Type:
25592559
tuple_type = e.info.tuple_type
25602560
if tuple_type:
2561-
if ('unimported' in self.chk.options.disallow_any and
2561+
if (self.chk.options.disallow_any_unimported and
25622562
has_any_from_unimported_type(tuple_type)):
25632563
self.msg.unimported_type_becomes_any("NamedTuple type", tuple_type, e)
25642564
check_for_explicit_any(tuple_type, self.chk.options, self.chk.is_typeshed_stub,

mypy/main.py

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -119,24 +119,6 @@ def type_check_only(sources: List[BuildSource], bin_dir: Optional[str],
119119
options=options)
120120

121121

122-
disallow_any_options = ['unimported', 'expr', 'unannotated', 'decorated', 'explicit', 'generics']
123-
124-
125-
def disallow_any_argument_type(raw_options: str) -> List[str]:
126-
if not raw_options:
127-
# empty string disables all options
128-
return []
129-
flag_options = [o.strip() for o in raw_options.split(',')]
130-
for option in flag_options:
131-
if option not in disallow_any_options:
132-
formatted_valid_options = ', '.join(
133-
"'{}'".format(o) for o in disallow_any_options)
134-
message = "Invalid '--disallow-any' option '{}' (valid options are: {}).".format(
135-
option, formatted_valid_options)
136-
raise argparse.ArgumentError(None, message)
137-
return flag_options
138-
139-
140122
FOOTER = """environment variables:
141123
MYPYPATH additional module search path"""
142124

@@ -272,10 +254,18 @@ def add_invertible_flag(flag: str,
272254
help="silently ignore imports of missing modules")
273255
parser.add_argument('--follow-imports', choices=['normal', 'silent', 'skip', 'error'],
274256
default='normal', help="how to treat imports (default normal)")
275-
parser.add_argument('--disallow-any', type=disallow_any_argument_type, default=[],
276-
metavar='{{{}}}'.format(', '.join(disallow_any_options)),
277-
help="disallow various types of Any in a module. Takes a comma-separated "
278-
"list of options (defaults to all options disabled)")
257+
parser.add_argument('--disallow-any-unimported', default=False, action='store_true',
258+
help="disallow Any types resulting from unfollowed imports")
259+
parser.add_argument('--disallow-any-expr', default=False, action='store_true',
260+
help='disallow all expressions that have type Any')
261+
parser.add_argument('--disallow-any-decorated', default=False, action='store_true',
262+
help='disallow functions that have Any in their signature '
263+
'after decorator transformation')
264+
parser.add_argument('--disallow-any-explicit', default=False, action='store_true',
265+
help='disallow explicit Any in type positions')
266+
parser.add_argument('--disallow-any-generics', default=False, action='store_true',
267+
help='disallow usage of generic types that do not specify explicit '
268+
'type parameters')
279269
add_invertible_flag('--disallow-untyped-calls', default=False, strict_flag=True,
280270
help="disallow calling functions without type annotations"
281271
" from functions with type annotations")
@@ -364,6 +354,8 @@ def add_invertible_flag(flag: str,
364354
# --dump-graph will dump the contents of the graph of SCCs and exit.
365355
parser.add_argument('--dump-graph', action='store_true', help=argparse.SUPPRESS)
366356
# deprecated options
357+
parser.add_argument('--disallow-any', dest='special-opts:disallow_any',
358+
help=argparse.SUPPRESS)
367359
add_invertible_flag('--strict-boolean', default=False,
368360
help=argparse.SUPPRESS)
369361
parser.add_argument('-f', '--dirty-stubs', action='store_true',
@@ -438,6 +430,9 @@ def add_invertible_flag(flag: str,
438430
)
439431

440432
# Process deprecated options
433+
if special_opts.disallow_any:
434+
print("--disallow-any option was split up into multiple flags. "
435+
"See http://mypy.readthedocs.io/en/latest/command_line.html#disallow-any-flags")
441436
if options.strict_boolean:
442437
print("Warning: --strict-boolean is deprecated; "
443438
"see https://github.com/python/mypy/issues/3195", file=sys.stderr)
@@ -462,9 +457,6 @@ def add_invertible_flag(flag: str,
462457
print("Warning: --no-fast-parser no longer has any effect. The fast parser "
463458
"is now mypy's default and only parser.")
464459

465-
if 'unannotated' in options.disallow_any:
466-
options.disallow_untyped_defs = True
467-
468460
# Check for invalid argument combinations.
469461
if require_targets:
470462
code_methods = sum(bool(c) for c in [special_opts.modules,
@@ -652,7 +644,6 @@ def get_init_file(dir: str) -> Optional[str]:
652644
'custom_typeshed_dir': str,
653645
'mypy_path': lambda s: [p.strip() for p in re.split('[,:]', s)],
654646
'junit_xml': str,
655-
'disallow_any': disallow_any_argument_type,
656647
# These two are for backwards compatibility
657648
'silent_imports': bool,
658649
'almost_silent': bool,
@@ -770,14 +761,6 @@ def parse_section(prefix: str, template: Options,
770761
except ValueError as err:
771762
print("%s: %s: %s" % (prefix, key, err), file=sys.stderr)
772763
continue
773-
if key == 'disallow_any':
774-
# "disallow_any = " should disable all disallow_any options, including untyped defs,
775-
# given in a more general config.
776-
if not v:
777-
results['disallow_untyped_defs'] = False
778-
# If "unannotated" is explicitly given, turn on disallow_untyped_defs.
779-
elif 'unannotated' in v:
780-
results['disallow_untyped_defs'] = True
781764
if key == 'silent_imports':
782765
print("%s: silent_imports has been replaced by "
783766
"ignore_missing_imports=True; follow_imports=skip" % prefix, file=sys.stderr)

mypy/options.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ class Options:
2020
PER_MODULE_OPTIONS = {
2121
"ignore_missing_imports",
2222
"follow_imports",
23-
"disallow_any",
23+
"disallow_any_generics",
24+
"disallow_any_unimported",
25+
"disallow_any_expr",
26+
"disallow_any_decorated",
27+
"disallow_any_explicit",
2428
"disallow_subclassing_any",
2529
"disallow_untyped_calls",
2630
"disallow_untyped_defs",
@@ -51,7 +55,13 @@ def __init__(self) -> None:
5155
self.report_dirs = {} # type: Dict[str, str]
5256
self.ignore_missing_imports = False
5357
self.follow_imports = 'normal' # normal|silent|skip|error
54-
self.disallow_any = [] # type: List[str]
58+
59+
# disallow_any options
60+
self.disallow_any_generics = False
61+
self.disallow_any_unimported = False
62+
self.disallow_any_expr = False
63+
self.disallow_any_decorated = False
64+
self.disallow_any_explicit = False
5565

5666
# Disallow calling untyped functions from typed ones
5767
self.disallow_untyped_calls = False

mypy/semanal.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ def analyze_base_classes(self, defn: ClassDef) -> None:
10531053
else:
10541054
self.fail('Invalid base class', base_expr)
10551055
info.fallback_to_any = True
1056-
if 'unimported' in self.options.disallow_any and has_any_from_unimported_type(base):
1056+
if self.options.disallow_any_unimported and has_any_from_unimported_type(base):
10571057
if isinstance(base_expr, (NameExpr, MemberExpr)):
10581058
prefix = "Base type {}".format(base_expr.name)
10591059
else:
@@ -2004,7 +2004,7 @@ def process_newtype_declaration(self, s: AssignmentStmt) -> None:
20042004
check_for_explicit_any(old_type, self.options, self.is_typeshed_stub_file, self.msg,
20052005
context=s)
20062006

2007-
if 'unimported' in self.options.disallow_any and has_any_from_unimported_type(old_type):
2007+
if self.options.disallow_any_unimported and has_any_from_unimported_type(old_type):
20082008
self.msg.unimported_type_becomes_any("Argument 2 to NewType(...)", old_type, s)
20092009

20102010
# If so, add it to the symbol table.
@@ -2118,7 +2118,7 @@ def process_typevar_declaration(self, s: AssignmentStmt) -> None:
21182118
return
21192119
variance, upper_bound = res
21202120

2121-
if 'unimported' in self.options.disallow_any:
2121+
if self.options.disallow_any_unimported:
21222122
for idx, constraint in enumerate(values, start=1):
21232123
if has_any_from_unimported_type(constraint):
21242124
prefix = "Constraint {}".format(idx)
@@ -2587,7 +2587,7 @@ def parse_typeddict_args(self, call: CallExpr) -> Tuple[List[str], List[Type], b
25872587
check_for_explicit_any(t, self.options, self.is_typeshed_stub_file, self.msg,
25882588
context=call)
25892589

2590-
if 'unimported' in self.options.disallow_any:
2590+
if self.options.disallow_any_unimported:
25912591
for t in types:
25922592
if has_any_from_unimported_type(t):
25932593
self.msg.unimported_type_becomes_any("Type of a TypedDict key", t, dictexpr)

mypy/semanal_pass3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ def make_type_analyzer(self, indicator: Dict[str, bool]) -> TypeAnalyserPass3:
372372
indicator)
373373

374374
def check_for_omitted_generics(self, typ: Type) -> None:
375-
if 'generics' not in self.options.disallow_any or self.is_typeshed_file:
375+
if not self.options.disallow_any_generics or self.is_typeshed_file:
376376
return
377377

378378
for t in collect_any_types(typ):

mypy/typeanal.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def visit_unbound_type(self, t: UnboundType) -> Type:
213213
elif fullname == 'typing.Tuple':
214214
if len(t.args) == 0 and not t.empty_tuple_index:
215215
# Bare 'Tuple' is same as 'tuple'
216-
if 'generics' in self.options.disallow_any and not self.is_typeshed_stub:
216+
if self.options.disallow_any_generics and not self.is_typeshed_stub:
217217
self.fail(messages.BARE_GENERIC, t)
218218
typ = self.named_type('builtins.tuple', line=t.line, column=t.column)
219219
typ.from_generic_builtin = True
@@ -669,7 +669,7 @@ def visit_instance(self, t: Instance) -> None:
669669
if len(t.args) != len(info.type_vars):
670670
if len(t.args) == 0:
671671
from_builtins = t.type.fullname() in nongen_builtins and not t.from_generic_builtin
672-
if ('generics' in self.options.disallow_any and
672+
if (self.options.disallow_any_generics and
673673
not self.is_typeshed_stub and
674674
from_builtins):
675675
alternative = nongen_builtins[t.type.fullname()]
@@ -930,7 +930,7 @@ def check_for_explicit_any(typ: Optional[Type],
930930
is_typeshed_stub: bool,
931931
msg: MessageBuilder,
932932
context: Context) -> None:
933-
if ('explicit' in options.disallow_any and
933+
if (options.disallow_any_explicit and
934934
not is_typeshed_stub and
935935
typ and
936936
has_explicit_any(typ)):

mypy/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ def TypeOfAny(x: str) -> str:
277277
unannotated = TypeOfAny('unannotated')
278278
# Does this Any come from an explicit type annotation?
279279
explicit = TypeOfAny('explicit')
280-
# Does this come from an unfollowed import? See --disallow-any=unimported option
280+
# Does this come from an unfollowed import? See --disallow-any-unimported option
281281
from_unimported_type = TypeOfAny('from_unimported_type')
282282
# Does this Any type come from omitted generics?
283283
from_omitted_generics = TypeOfAny('from_omitted_generics')

mypy_self_check.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ disallow_subclassing_any = True
44
warn_no_return = True
55
strict_optional = True
66
no_implicit_optional = True
7-
disallow_any = generics, unimported
7+
disallow_any_generics = True
8+
disallow_any_unimported = True
89
warn_redundant_casts = True
910
warn_unused_ignores = True
1011
warn_unused_configs = True

0 commit comments

Comments
 (0)