diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index e5d1a8018bfb6..afae515d733c4 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -16,7 +16,7 @@ flag (or its long form ``--help``):: [--warn-incomplete-stub] [--warn-redundant-casts] [--warn-no-return] [--warn-unused-ignores] [--show-error-context] [--fast-parser] [-i] [--cache-dir DIR] [--strict-optional] - [--strict-optional-whitelist [GLOB [GLOB ...]]] + [--strict-optional-whitelist [GLOB [GLOB ...]]] [--strict] [--junit-xml JUNIT_XML] [--pdb] [--show-traceback] [--stats] [--inferstats] [--custom-typing MODULE] [--custom-typeshed-dir DIR] [--scripts-are-modules] @@ -366,6 +366,14 @@ Here are some more useful flags: also currently ignores functions with an empty body or a body that is just ellipsis (``...``), since these can be valid as abstract methods. +- ``--strict`` mode enables the strictest mypy configuration. It changes + mypy's behaviour regarding new strict flags from opt-in to opt-out. + You can see the list of flags enabled by strict mode in the full ``mypy -h`` + output. + + For all flags enabled by strict, you can opt-out individually using + ``--no-``. + For the remaining flags you can read the full ``mypy -h`` output. .. note:: diff --git a/mypy/main.py b/mypy/main.py index a2c3649a8844d..8fbb774206405 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -126,6 +126,12 @@ def __init__(self, prog: Optional[str]) -> None: super().__init__(prog=prog, max_help_position=28) +# Take a ternary option affected by --strict and set it correctly +def _set_strict_option(options: Options, opt: str, strict: bool) -> None: + if getattr(options, opt) is None: + setattr(options, opt, strict) + + def process_options(args: List[str], require_targets: bool = True ) -> Tuple[List[BuildSource], Options]: @@ -157,11 +163,23 @@ def process_options(args: List[str], parser.add_argument('--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") + parser.add_argument('--no-disallow-untyped-calls', action='store_false', + dest='disallow_untyped_calls', + help=argparse.SUPPRESS) + parser.set_defaults(disallow_untyped_calls=None) parser.add_argument('--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") + parser.add_argument('--no-disallow-untyped-defs', action='store_false', + dest='disallow_untyped_defs', + help=argparse.SUPPRESS) + parser.set_defaults(disallow_untyped_defs=None) parser.add_argument('--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") + parser.add_argument('--no-check-untyped-defs', action='store_false', + dest='check_untyped_defs', + help=argparse.SUPPRESS) + parser.set_defaults(check_untyped_defs=None) parser.add_argument('--disallow-subclassing-any', action='store_true', help="disallow subclassing values of type 'Any' when defining classes") parser.add_argument('--warn-incomplete-stub', action='store_true', @@ -169,10 +187,18 @@ def process_options(args: List[str], " --check-untyped-defs enabled") parser.add_argument('--warn-redundant-casts', action='store_true', help="warn about casting an expression to its inferred type") + parser.add_argument('--no-warn-redundant-casts', action='store_false', + dest='warn_redundant_casts', + help=argparse.SUPPRESS) + parser.set_defaults(warn_redundant_casts=None) parser.add_argument('--warn-no-return', action='store_true', help="warn about functions that end without returning") parser.add_argument('--warn-unused-ignores', action='store_true', help="warn about unneeded '# type: ignore' comments") + parser.add_argument('--no-warn-unused-ignores', action='store_false', + dest='warn_unused_ignores', + help=argparse.SUPPRESS) + parser.set_defaults(warn_unused_ignores=None) parser.add_argument('--show-error-context', action='store_false', dest='hide_error_context', help='Precede errors with "note:" messages explaining context') @@ -186,11 +212,20 @@ def process_options(args: List[str], parser.add_argument('--strict-optional', action='store_true', dest='strict_optional', help="enable experimental strict Optional checks") + parser.add_argument('--no-strict-optional', action='store_false', + dest='strict_optional', + help=argparse.SUPPRESS) + parser.set_defaults(strict_optional=None) parser.add_argument('--strict-optional-whitelist', metavar='GLOB', nargs='*', help="suppress strict Optional errors in all but the provided files " "(experimental -- read documentation before using!). " "Implies --strict-optional. Has the undesirable side-effect of " "suppressing other errors in non-whitelisted files.") + parser.add_argument('--strict', action='store_true', + dest='special-opts:strict', + help=("Strict mode. Enable --strict-optional, --warn-unused-ignores, " + "--warn-redundant-casts, --check-untyped-defs, " + "--disallow-untyped-defs, and --disallow-untyped-calls")) parser.add_argument('--junit-xml', help="write junit.xml to the given file") parser.add_argument('--pdb', action='store_true', help="invoke pdb on fatal error") parser.add_argument('--show-traceback', '--tb', action='store_true', @@ -213,6 +248,7 @@ def process_options(args: List[str], parser.add_argument('--find-occurrences', metavar='CLASS.MEMBER', dest='special-opts:find_occurrences', help="print out all usages of a class member (experimental)") + # hidden options # --shadow-file a.py tmp.py will typecheck tmp.py in place of a.py. # Useful for tools to make transformations to a file to get more @@ -274,7 +310,7 @@ def process_options(args: List[str], if dummy.config_file: config_file = dummy.config_file if not os.path.exists(config_file): - parser.error("Cannot file config file '%s'" % config_file) + parser.error("Cannot find config file '%s'" % config_file) # Parse config file first, so command line can override. options = Options() @@ -321,6 +357,10 @@ def process_options(args: List[str], elif code_methods > 1: parser.error("May only specify one of: module, package, files, or command.") + # Determine if strict options should be enabled or disabled + for strict_opt in options.STRICT_OPTIONS: + _set_strict_option(options, strict_opt, special_opts.strict) + # Set build flags. if options.strict_optional_whitelist is not None: # TODO: Deprecate, then kill this flag diff --git a/mypy/options.py b/mypy/options.py index a9b6a05bb1384..bacca4a101a23 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -29,6 +29,15 @@ class Options: "ignore_errors", } + STRICT_OPTIONS = { + "strict_optional", + "warn_unused_ignores", + "warn_redundant_casts", + "check_untyped_defs", + "disallow_untyped_defs", + "disallow_untyped_calls", + } + OPTIONS_AFFECTING_CACHE = PER_MODULE_OPTIONS | {"strict_optional"} def __init__(self) -> None: @@ -44,13 +53,16 @@ def __init__(self) -> None: self.follow_imports = 'normal' # normal|silent|skip|error # Disallow calling untyped functions from typed ones - self.disallow_untyped_calls = False + # Enabled in strict mode only + self.disallow_untyped_calls = None # type: Optional[bool] # Disallow defining untyped (or incompletely typed) functions - self.disallow_untyped_defs = False + # Enabled in strict mode only + self.disallow_untyped_defs = None # type: Optional[bool] # Type check unannotated functions - self.check_untyped_defs = False + # Enabled in strict mode only + self.check_untyped_defs = None # type: Optional[bool] # Disallow subclassing values of type 'Any' self.disallow_subclassing_any = False @@ -59,19 +71,22 @@ def __init__(self) -> None: self.warn_incomplete_stub = False # Warn about casting an expression to its inferred type - self.warn_redundant_casts = False + # Enabled in strict mode only + self.warn_redundant_casts = None # type: Optional[bool] # Warn about falling off the end of a function returning non-None self.warn_no_return = False # Warn about unused '# type: ignore' comments - self.warn_unused_ignores = False + # Enabled in strict mode only + self.warn_unused_ignores = None # type: Optional[bool] # Files in which to ignore all non-fatal errors self.ignore_errors = False # Apply strict None checking - self.strict_optional = False + # Enabled in strict mode only + self.strict_optional = None # type: Optional[bool] # Hide "note: In function "foo":" messages. self.hide_error_context = True