def process_options() -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # Make the help output a little less jarring. help_factory = (lambda prog: argparse.RawDescriptionHelpFormatter( prog=prog, max_help_position=28)) parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, formatter_class=help_factory) def parse_version(v): m = re.match(r'\A(\d)\.(\d+)\Z', v) if m: return int(m.group(1)), int(m.group(2)) else: raise argparse.ArgumentTypeError( "Invalid python version '{}' (expected format: 'x.y')".format( v)) parser.add_argument('-v', '--verbose', action='count', help="more verbose messages") parser.add_argument( '-V', '--version', action='version', # type: ignore # see typeshed#124 version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument('--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('-s', '--silent-imports', action='store_true', help="don't follow imports to .py files") parser.add_argument('--silent', action='store_true', help="deprecated name for --silent-imports") parser.add_argument( '--almost-silent', action='store_true', help="like --silent-imports but reports the imports as errors") parser.add_argument( '--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") parser.add_argument( '--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") parser.add_argument( '--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") parser.add_argument( '--warn-incomplete-stub', action='store_true', help="warn if missing type annotation in typeshed, only relevant with" " --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('--fast-parser', action='store_true', help="enable experimental fast parser") parser.add_argument('-i', '--incremental', action='store_true', help="enable experimental module cache") parser.add_argument('--strict-optional', action='store_true', help="enable experimental strict Optional checks") parser.add_argument('-f', '--dirty-stubs', action='store_true', help="don't warn if typeshed is out of sync") parser.add_argument('--pdb', action='store_true', help="invoke pdb on fatal error") parser.add_argument('--use-python-path', action='store_true', help="an anti-pattern") parser.add_argument('--stats', action='store_true', help="dump stats") parser.add_argument('--inferstats', action='store_true', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', help="use a custom typing module") report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') report_group.add_argument('--html-report', metavar='DIR') report_group.add_argument('--old-html-report', metavar='DIR') report_group.add_argument('--xslt-html-report', metavar='DIR') report_group.add_argument('--xml-report', metavar='DIR') report_group.add_argument('--txt-report', metavar='DIR') report_group.add_argument('--xslt-txt-report', metavar='DIR') report_group.add_argument('--linecount-report', metavar='DIR') code_group = parser.add_argument_group( title='How to specify the code to type check') code_group.add_argument( '-m', '--module', action='append', dest='modules', help="type-check module; can repeat for more modules") # TODO: `mypy -c A -c B` and `mypy -p A -p B` currently silently # ignore A (last option wins). Perhaps -c, -m and -p could just # be command-line flags that modify how we interpret self.files? code_group.add_argument('-c', '--command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', help="type-check all files in a directory") code_group.add_argument('files', nargs='*', help="type-check given files or directories") args = parser.parse_args() # --use-python-path is no longer supported; explain why. if args.use_python_path: parser.error( "Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # --silent is deprecated; warn about this. if args.silent: print("Warning: --silent is deprecated; use --silent-imports", file=sys.stderr) # Check for invalid argument combinations. code_methods = sum( bool(c) for c in [args.modules, args.command, args.package, args.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error( "May only specify one of: module, package, files, or command.") if args.use_python_path and args.python_version and args.python_version[ 0] == 2: parser.error( 'Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') # Set options. options = Options() options.dirty_stubs = args.dirty_stubs options.python_path = args.use_python_path options.pdb = args.pdb options.custom_typing_module = args.custom_typing # Set build flags. if args.python_version is not None: options.pyversion = args.python_version if args.verbose: options.build_flags.extend(args.verbose * [build.VERBOSE]) if args.stats: options.build_flags.append(build.DUMP_TYPE_STATS) if args.inferstats: options.build_flags.append(build.DUMP_INFER_STATS) if args.silent_imports or args.silent: options.build_flags.append(build.SILENT_IMPORTS) if args.almost_silent: options.build_flags.append(build.SILENT_IMPORTS) options.build_flags.append(build.ALMOST_SILENT) if args.disallow_untyped_calls: options.build_flags.append(build.DISALLOW_UNTYPED_CALLS) if args.disallow_untyped_defs: options.build_flags.append(build.DISALLOW_UNTYPED_DEFS) if args.check_untyped_defs: options.build_flags.append(build.CHECK_UNTYPED_DEFS) if args.warn_incomplete_stub: options.build_flags.append(build.WARN_INCOMPLETE_STUB) if args.warn_redundant_casts: options.build_flags.append(build.WARN_REDUNDANT_CASTS) # experimental if args.fast_parser: options.build_flags.append(build.FAST_PARSER) if args.incremental: options.build_flags.append(build.INCREMENTAL) if args.strict_optional: experiments.STRICT_OPTIONAL = True # Set reports. for flag, val in vars(args).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Set target. if args.modules: options.build_flags.append(build.MODULE) targets = [BuildSource(None, m, None) for m in args.modules] return targets, options elif args.package: if os.sep in args.package or os.altsep and os.altsep in args.package: fail("Package name '{}' cannot have a slash in it.".format( args.package)) options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args.package, lib_path) if not targets: fail("Can't find package '{}'".format(args.package)) return targets, options elif args.command: options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args.command)], options else: targets = [] for f in args.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): sub_targets = expand_dir(f) if not sub_targets: fail("There are no .py[i] files in directory '{}'".format( f)) targets.extend(sub_targets) else: targets.append(BuildSource(f, None, None)) return targets, options
def process_options( args: List[str], require_targets: bool = True, server_options: bool = False, ) -> Tuple[List[BuildSource], Options]: """Parse command line arguments.""" parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, fromfile_prefix_chars='@', formatter_class=AugmentedHelpFormatter) strict_flag_names = [] # type: List[str] strict_flag_assignments = [] # type: List[Tuple[str, bool]] def add_invertible_flag(flag: str, *, inverse: Optional[str] = None, default: bool, dest: Optional[str] = None, help: str, strict_flag: bool = False) -> None: if inverse is None: inverse = invert_flag_name(flag) if help is not argparse.SUPPRESS: help += " (inverse: {})".format(inverse) arg = parser.add_argument( flag, # type: ignore # incorrect stub for add_argument action='store_false' if default else 'store_true', dest=dest, help=help) dest = arg.dest arg = parser.add_argument( inverse, # type: ignore # incorrect stub for add_argument action='store_true' if default else 'store_false', dest=dest, help=argparse.SUPPRESS) if strict_flag: assert dest is not None strict_flag_names.append(flag) strict_flag_assignments.append((dest, not default)) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument('-v', '--verbose', action='count', dest='verbosity', help="more verbose messages") parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument( '--platform', action='store', metavar='PLATFORM', help="typecheck special-cased code for the given OS platform " "(defaults to sys.platform).") parser.add_argument('-2', '--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('--ignore-missing-imports', action='store_true', help="silently ignore imports of missing modules") parser.add_argument('--follow-imports', choices=['normal', 'silent', 'skip', 'error'], default='normal', help="how to treat imports (default normal)") parser.add_argument( '--disallow-any-unimported', default=False, action='store_true', help="disallow Any types resulting from unfollowed imports") parser.add_argument('--disallow-any-expr', default=False, action='store_true', help='disallow all expressions that have type Any') parser.add_argument( '--disallow-any-decorated', default=False, action='store_true', help='disallow functions that have Any in their signature ' 'after decorator transformation') parser.add_argument('--disallow-any-explicit', default=False, action='store_true', help='disallow explicit Any in type positions') parser.add_argument( '--disallow-any-generics', default=False, action='store_true', help='disallow usage of generic types that do not specify explicit ' 'type parameters') add_invertible_flag( '--disallow-untyped-calls', default=False, strict_flag=True, help="disallow calling functions without type annotations" " from functions with type annotations") add_invertible_flag( '--disallow-untyped-defs', default=False, strict_flag=True, help="disallow defining functions without type annotations" " or with incomplete type annotations") add_invertible_flag( '--disallow-incomplete-defs', default=False, strict_flag=True, help="disallow defining functions with incomplete type annotations") add_invertible_flag( '--check-untyped-defs', default=False, strict_flag=True, help="type check the interior of functions without type annotations") add_invertible_flag( '--disallow-subclassing-any', default=False, strict_flag=True, help="disallow subclassing values of type 'Any' when defining classes") add_invertible_flag( '--warn-incomplete-stub', default=False, help="warn if missing type annotation in typeshed, only relevant with" " --check-untyped-defs enabled") add_invertible_flag( '--disallow-untyped-decorators', default=False, strict_flag=True, help="disallow decorating typed functions with untyped decorators") add_invertible_flag( '--warn-redundant-casts', default=False, strict_flag=True, help="warn about casting an expression to its inferred type") add_invertible_flag( '--no-warn-no-return', dest='warn_no_return', default=True, help="do not warn about functions that end without returning") add_invertible_flag('--warn-return-any', default=False, strict_flag=True, help="warn about returning values of type Any" " from non-Any typed functions") add_invertible_flag('--warn-unused-ignores', default=False, strict_flag=True, help="warn about unneeded '# type: ignore' comments") add_invertible_flag( '--warn-unused-configs', default=False, strict_flag=True, help="warn about unused '[mypy-<pattern>]' config sections") add_invertible_flag( '--show-error-context', default=False, dest='show_error_context', help='Precede errors with "note:" messages explaining context') add_invertible_flag( '--no-implicit-optional', default=False, strict_flag=True, help="don't assume arguments with default values of None are Optional") parser.add_argument( '-i', '--incremental', action='store_true', help="enable module cache, (inverse: --no-incremental)") parser.add_argument('--no-incremental', action='store_false', dest='incremental', help=argparse.SUPPRESS) parser.add_argument('--quick-and-dirty', action='store_true', help="use cache even if dependencies out of date " "(implies --incremental)") parser.add_argument( '--cache-dir', action='store', metavar='DIR', help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.CACHE_DIR)) parser.add_argument( '--cache-fine-grained', action='store_true', help="include fine-grained dependency information in the cache") parser.add_argument('--skip-version-check', action='store_true', help="allow using cache written by older mypy version") add_invertible_flag('--strict-optional', default=False, strict_flag=True, help="enable experimental strict Optional checks") 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('--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', help="show traceback on fatal error") parser.add_argument('--stats', action='store_true', dest='dump_type_stats', help="dump stats") parser.add_argument('--inferstats', action='store_true', dest='dump_inference_stats', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', dest='custom_typing_module', help="use a custom typing module") parser.add_argument('--custom-typeshed-dir', metavar='DIR', help="use the custom typeshed in DIR") parser.add_argument('--scripts-are-modules', action='store_true', help="Script x becomes module x instead of __main__") parser.add_argument('--config-file', help="Configuration file, must have a [mypy] section " "(defaults to {})".format(defaults.CONFIG_FILE)) add_invertible_flag('--show-column-numbers', default=False, help="Show column numbers in error messages") parser.add_argument( '--find-occurrences', metavar='CLASS.MEMBER', dest='special-opts:find_occurrences', help="print out all usages of a class member (experimental)") strict_help = "Strict mode. Enables the following flags: {}".format( ", ".join(strict_flag_names)) parser.add_argument('--strict', action='store_true', dest='special-opts:strict', help=strict_help) parser.add_argument('--shadow-file', nargs=2, metavar=('SOURCE_FILE', 'SHADOW_FILE'), dest='shadow_file', help='Typecheck SHADOW_FILE in place of SOURCE_FILE.') # hidden options # --debug-cache will disable any cache-related compressions/optimizations, # which will make the cache writing process output pretty-printed JSON (which # is easier to debug). parser.add_argument('--debug-cache', action='store_true', help=argparse.SUPPRESS) # --dump-deps will dump all fine-grained dependencies to stdout parser.add_argument('--dump-deps', action='store_true', help=argparse.SUPPRESS) # --dump-graph will dump the contents of the graph of SCCs and exit. parser.add_argument('--dump-graph', action='store_true', help=argparse.SUPPRESS) # --semantic-analysis-only does exactly that. parser.add_argument('--semantic-analysis-only', action='store_true', help=argparse.SUPPRESS) # --local-partial-types disallows partial types spanning module top level and a function # (implicitly defined in fine-grained incremental mode) parser.add_argument('--local-partial-types', action='store_true', help=argparse.SUPPRESS) # deprecated options parser.add_argument('--disallow-any', dest='special-opts:disallow_any', help=argparse.SUPPRESS) add_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) parser.add_argument('--use-python-path', action='store_true', dest='special-opts:use_python_path', help=argparse.SUPPRESS) parser.add_argument('-s', '--silent-imports', action='store_true', dest='special-opts:silent_imports', help=argparse.SUPPRESS) parser.add_argument('--almost-silent', action='store_true', dest='special-opts:almost_silent', help=argparse.SUPPRESS) parser.add_argument('--fast-parser', action='store_true', dest='special-opts:fast_parser', help=argparse.SUPPRESS) parser.add_argument('--no-fast-parser', action='store_true', dest='special-opts:no_fast_parser', help=argparse.SUPPRESS) if server_options: parser.add_argument('--experimental', action='store_true', dest='fine_grained_incremental', help="enable fine-grained incremental mode") parser.add_argument( '--use-fine-grained-cache', action='store_true', help="use the cache in fine-grained incremental mode") report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') for report_type in sorted(reporter_classes): report_group.add_argument('--%s-report' % report_type.replace('_', '-'), metavar='DIR', dest='special-opts:%s_report' % report_type) code_group = parser.add_argument_group( title='How to specify the code to type check') code_group.add_argument( '-m', '--module', action='append', metavar='MODULE', dest='special-opts:modules', help="type-check module; can repeat for more modules") # TODO: `mypy -p A -p B` currently silently ignores A # (last option wins). Perhaps -c, -m and -p could just be # command-line flags that modify how we interpret self.files? code_group.add_argument('-c', '--command', action='append', metavar='PROGRAM_TEXT', dest='special-opts:command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', metavar='PACKAGE', dest='special-opts:package', help="type-check all files in a directory") code_group.add_argument(metavar='files', nargs='*', dest='special-opts:files', help="type-check given files or directories") # Parse arguments once into a dummy namespace so we can get the # filename for the config file and know if the user requested all strict options. dummy = argparse.Namespace() parser.parse_args(args, dummy) config_file = dummy.config_file if config_file is not None and not os.path.exists(config_file): parser.error("Cannot find config file '%s'" % config_file) # Parse config file first, so command line can override. options = Options() parse_config_file(options, config_file) # Set strict flags before parsing (if strict mode enabled), so other command # line options can override. if getattr(dummy, 'special-opts:strict'): for dest, value in strict_flag_assignments: setattr(options, dest, value) # Parse command line for real, using a split namespace. special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, 'special-opts:')) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error( "Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # Process deprecated options if special_opts.disallow_any: print( "--disallow-any option was split up into multiple flags. " "See http://mypy.readthedocs.io/en/latest/command_line.html#disallow-any-flags" ) 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) if options.follow_imports == 'normal': options.follow_imports = 'errors' elif special_opts.silent_imports: print( "Warning: --silent-imports has been replaced by " "--ignore-missing-imports --follow-imports=skip", file=sys.stderr) options.ignore_missing_imports = True if options.follow_imports == 'normal': options.follow_imports = 'skip' if special_opts.dirty_stubs: print( "Warning: -f/--dirty-stubs is deprecated and no longer necessary. Mypy no longer " "checks the git status of stubs.", file=sys.stderr) if special_opts.fast_parser: print("Warning: --fast-parser is now the default (and only) parser.") if special_opts.no_fast_parser: print( "Warning: --no-fast-parser no longer has any effect. The fast parser " "is now mypy's default and only parser.") # Check for invalid argument combinations. if require_targets: code_methods = sum( bool(c) for c in [ special_opts.modules, special_opts.command, special_opts.package, special_opts.files ]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error( "May only specify one of: module, package, files, or command.") # Set build flags. if options.strict_optional_whitelist is not None: # TODO: Deprecate, then kill this flag options.strict_optional = True if special_opts.find_occurrences: experiments.find_occurrences = special_opts.find_occurrences.split('.') assert experiments.find_occurrences is not None if len(experiments.find_occurrences) < 2: parser.error("Can only find occurrences of class members.") if len(experiments.find_occurrences) != 2: parser.error( "Can only find occurrences of non-nested class members.") # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Let quick_and_dirty imply incremental. if options.quick_and_dirty: options.incremental = True # Set target. if special_opts.modules: options.build_type = BuildType.MODULE targets = [BuildSource(None, m, None) for m in special_opts.modules] return targets, options elif special_opts.package: if os.sep in special_opts.package or os.altsep and os.altsep in special_opts.package: fail("Package name '{}' cannot have a slash in it.".format( special_opts.package)) options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() # TODO: use the same cache as the BuildManager will targets = build.FindModuleCache().find_modules_recursive( special_opts.package, lib_path) if not targets: fail("Can't find package '{}'".format(special_opts.package)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT targets = [BuildSource(None, None, '\n'.join(special_opts.command))] return targets, options else: targets = create_source_list(special_opts.files, options) return targets, options
def process_options() -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # Make the help output a little less jarring. help_factory = lambda prog: argparse.RawDescriptionHelpFormatter(prog=prog, max_help_position=28) parser = argparse.ArgumentParser(prog="mypy", epilog=FOOTER, formatter_class=help_factory) def parse_version(v): m = re.match(r"\A(\d)\.(\d+)\Z", v) if m: return int(m.group(1)), int(m.group(2)) else: raise argparse.ArgumentTypeError("Invalid python version '{}' (expected format: 'x.y')".format(v)) parser.add_argument("-v", "--verbose", action="count", help="more verbose messages") parser.add_argument( "-V", "--version", action="version", version="%(prog)s " + __version__ # type: ignore # see typeshed#124 ) parser.add_argument("--python-version", type=parse_version, metavar="x.y", help="use Python x.y") parser.add_argument( "--py2", dest="python_version", action="store_const", const=defaults.PYTHON2_VERSION, help="use Python 2 mode" ) parser.add_argument("-s", "--silent-imports", action="store_true", help="don't follow imports to .py files") parser.add_argument("--silent", action="store_true", help="deprecated name for --silent-imports") parser.add_argument( "--almost-silent", action="store_true", help="like --silent-imports but reports the imports as errors" ) parser.add_argument( "--disallow-untyped-calls", action="store_true", help="disallow calling functions without type annotations" " from functions with type annotations", ) parser.add_argument( "--disallow-untyped-defs", action="store_true", help="disallow defining functions without type annotations" " or with incomplete type annotations", ) parser.add_argument( "--check-untyped-defs", action="store_true", help="type check the interior of functions without type annotations", ) parser.add_argument( "--warn-incomplete-stub", action="store_true", help="warn if missing type annotation in typeshed, only relevant with" " --check-untyped-defs enabled", ) parser.add_argument("--fast-parser", action="store_true", help="enable experimental fast parser") parser.add_argument("-i", "--incremental", action="store_true", help="enable experimental module cache") parser.add_argument("--strict-optional", action="store_true", help="enable experimental strict Optional checks") parser.add_argument("-f", "--dirty-stubs", action="store_true", help="don't warn if typeshed is out of sync") parser.add_argument("--pdb", action="store_true", help="invoke pdb on fatal error") parser.add_argument("--use-python-path", action="store_true", help="an anti-pattern") parser.add_argument("--stats", action="store_true", help="dump stats") parser.add_argument("--inferstats", action="store_true", help="dump type inference stats") parser.add_argument("--custom-typing", metavar="MODULE", help="use a custom typing module") report_group = parser.add_argument_group( title="report generation", description="Generate a report in the specified format." ) report_group.add_argument("--html-report", metavar="DIR") report_group.add_argument("--old-html-report", metavar="DIR") report_group.add_argument("--xslt-html-report", metavar="DIR") report_group.add_argument("--xml-report", metavar="DIR") report_group.add_argument("--txt-report", metavar="DIR") report_group.add_argument("--xslt-txt-report", metavar="DIR") report_group.add_argument("--linecount-report", metavar="DIR") code_group = parser.add_argument_group(title="How to specify the code to type check") code_group.add_argument( "-m", "--module", action="append", dest="modules", help="type-check module; can repeat for more modules" ) # TODO: `mypy -c A -c B` and `mypy -p A -p B` currently silently # ignore A (last option wins). Perhaps -c, -m and -p could just # be command-line flags that modify how we interpret self.files? code_group.add_argument("-c", "--command", help="type-check program passed in as string") code_group.add_argument("-p", "--package", help="type-check all files in a directory") code_group.add_argument("files", nargs="*", help="type-check given files or directories") args = parser.parse_args() # --use-python-path is no longer supported; explain why. if args.use_python_path: parser.error( "Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # --silent is deprecated; warn about this. if args.silent: print("Warning: --silent is deprecated; use --silent-imports", file=sys.stderr) # Check for invalid argument combinations. code_methods = sum(bool(c) for c in [args.modules, args.command, args.package, args.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error("May only specify one of: module, package, files, or command.") if args.use_python_path and args.python_version and args.python_version[0] == 2: parser.error( "Python version 2 (or --py2) specified, " "but --use-python-path will search in sys.path of Python 3" ) # Set options. options = Options() options.dirty_stubs = args.dirty_stubs options.python_path = args.use_python_path options.pdb = args.pdb options.custom_typing_module = args.custom_typing # Set build flags. if args.python_version is not None: options.pyversion = args.python_version if args.verbose: options.build_flags.extend(args.verbose * [build.VERBOSE]) if args.stats: options.build_flags.append(build.DUMP_TYPE_STATS) if args.inferstats: options.build_flags.append(build.DUMP_INFER_STATS) if args.silent_imports or args.silent: options.build_flags.append(build.SILENT_IMPORTS) if args.almost_silent: options.build_flags.append(build.SILENT_IMPORTS) options.build_flags.append(build.ALMOST_SILENT) if args.disallow_untyped_calls: options.build_flags.append(build.DISALLOW_UNTYPED_CALLS) if args.disallow_untyped_defs: options.build_flags.append(build.DISALLOW_UNTYPED_DEFS) if args.check_untyped_defs: options.build_flags.append(build.CHECK_UNTYPED_DEFS) if args.warn_incomplete_stub: options.build_flags.append(build.WARN_INCOMPLETE_STUB) # experimental if args.fast_parser: options.build_flags.append(build.FAST_PARSER) if args.incremental: options.build_flags.append(build.INCREMENTAL) if args.strict_optional: experiments.STRICT_OPTIONAL = True # Set reports. for flag, val in vars(args).items(): if flag.endswith("_report") and val is not None: report_type = flag[:-7].replace("_", "-") report_dir = val options.report_dirs[report_type] = report_dir # Set target. if args.modules: options.build_flags.append(build.MODULE) targets = [BuildSource(None, m, None) for m in args.modules] return targets, options elif args.package: if os.sep in args.package or os.altsep and os.altsep in args.package: fail("Package name '{}' cannot have a slash in it.".format(args.package)) options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args.package, lib_path) if not targets: fail("Can't find package '{}'".format(args.package)) return targets, options elif args.command: options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args.command)], options else: targets = [] for f in args.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): sub_targets = expand_dir(f) if not sub_targets: fail("There are no .py[i] files in directory '{}'".format(f)) targets.extend(sub_targets) else: targets.append(BuildSource(f, None, None)) return targets, options
def process_options( args: List[str], require_targets: bool = True) -> Tuple[List[BuildSource], Options]: """Parse command line arguments.""" # Make the help output a little less jarring. help_factory = (lambda prog: argparse.RawDescriptionHelpFormatter( prog=prog, max_help_position=28)) parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, fromfile_prefix_chars='@', formatter_class=help_factory) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument('-v', '--verbose', action='count', dest='verbosity', help="more verbose messages") parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument( '--platform', action='store', metavar='PLATFORM', help="typecheck special-cased code for the given OS platform " "(defaults to sys.platform).") parser.add_argument('-2', '--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('-s', '--silent-imports', action='store_true', help="don't follow imports to .py files") parser.add_argument( '--almost-silent', action='store_true', help="like --silent-imports but reports the imports as errors") parser.add_argument( '--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") parser.add_argument( '--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") parser.add_argument( '--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") 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', help="warn if missing type annotation in typeshed, only relevant with" " --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('--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('--hide-error-context', action='store_true', dest='hide_error_context', help="Hide context notes before errors") parser.add_argument('--fast-parser', action='store_true', help="enable experimental fast parser") parser.add_argument('-i', '--incremental', action='store_true', help="enable experimental module cache") parser.add_argument( '--cache-dir', action='store', metavar='DIR', help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.CACHE_DIR)) parser.add_argument('--strict-optional', action='store_true', dest='strict_optional', help="enable experimental strict Optional checks") 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('--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', help="show traceback on fatal error") parser.add_argument('--stats', action='store_true', dest='dump_type_stats', help="dump stats") parser.add_argument('--inferstats', action='store_true', dest='dump_inference_stats', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', dest='custom_typing_module', help="use a custom typing module") parser.add_argument('--custom-typeshed-dir', metavar='DIR', help="use the custom typeshed in DIR") parser.add_argument('--scripts-are-modules', action='store_true', help="Script x becomes module x instead of __main__") parser.add_argument('--config-file', help="Configuration file, must have a [mypy] section " "(defaults to {})".format(defaults.CONFIG_FILE)) parser.add_argument('--show-column-numbers', action='store_true', dest='show_column_numbers', help="Show column numbers in error messages") 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 # information from a mypy run without having to change the file in-place # (e.g. by adding a call to reveal_type). parser.add_argument('--shadow-file', metavar='PATH', nargs=2, dest='shadow_file', help=argparse.SUPPRESS) # --debug-cache will disable any cache-related compressions/optimizations, # which will make the cache writing process output pretty-printed JSON (which # is easier to debug). parser.add_argument('--debug-cache', action='store_true', help=argparse.SUPPRESS) # deprecated options parser.add_argument('--silent', action='store_true', dest='special-opts:silent', help=argparse.SUPPRESS) parser.add_argument('-f', '--dirty-stubs', action='store_true', dest='special-opts:dirty_stubs', help=argparse.SUPPRESS) parser.add_argument('--use-python-path', action='store_true', dest='special-opts:use_python_path', help=argparse.SUPPRESS) report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') for report_type in sorted(reporter_classes): report_group.add_argument('--%s-report' % report_type.replace('_', '-'), metavar='DIR', dest='special-opts:%s_report' % report_type) code_group = parser.add_argument_group( title='How to specify the code to type check') code_group.add_argument( '-m', '--module', action='append', metavar='MODULE', dest='special-opts:modules', help="type-check module; can repeat for more modules") # TODO: `mypy -p A -p B` currently silently ignores ignores A # (last option wins). Perhaps -c, -m and -p could just be # command-line flags that modify how we interpret self.files? code_group.add_argument('-c', '--command', action='append', metavar='PROGRAM_TEXT', dest='special-opts:command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', metavar='PACKAGE', dest='special-opts:package', help="type-check all files in a directory") code_group.add_argument(metavar='files', nargs='*', dest='special-opts:files', help="type-check given files or directories") # Parse arguments once into a dummy namespace so we can get the # filename for the config file. dummy = argparse.Namespace() parser.parse_args(args, dummy) config_file = dummy.config_file or defaults.CONFIG_FILE # Parse config file first, so command line can override. options = Options() if config_file and os.path.exists(config_file): parse_config_file(options, config_file) # Parse command line for real, using a split namespace. special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, 'special-opts:')) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error( "Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # warn about deprecated options if special_opts.silent: print("Warning: --silent is deprecated; use --silent-imports", file=sys.stderr) options.silent_imports = True if special_opts.dirty_stubs: print( "Warning: -f/--dirty-stubs is deprecated and no longer necessary. Mypy no longer " "checks the git status of stubs.", file=sys.stderr) # Check for invalid argument combinations. if require_targets: code_methods = sum( bool(c) for c in [ special_opts.modules, special_opts.command, special_opts.package, special_opts.files ]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error( "May only specify one of: module, package, files, or command.") # Set build flags. if options.strict_optional_whitelist is not None: # TODO: Deprecate, then kill this flag options.strict_optional = True if options.strict_optional: experiments.STRICT_OPTIONAL = True if special_opts.find_occurrences: experiments.find_occurrences = special_opts.find_occurrences.split('.') if len(experiments.find_occurrences) < 2: parser.error("Can only find occurrences of class members.") if len(experiments.find_occurrences) != 2: parser.error( "Can only find occurrences of non-nested class members.") # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Set target. if special_opts.modules: options.build_type = BuildType.MODULE targets = [BuildSource(None, m, None) for m in special_opts.modules] return targets, options elif special_opts.package: if os.sep in special_opts.package or os.altsep and os.altsep in special_opts.package: fail("Package name '{}' cannot have a slash in it.".format( special_opts.package)) options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(special_opts.package, lib_path) if not targets: fail("Can't find package '{}'".format(special_opts.package)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT return [BuildSource(None, None, '\n'.join(special_opts.command))], options else: targets = [] for f in special_opts.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): sub_targets = expand_dir(f) if not sub_targets: fail("There are no .py[i] files in directory '{}'".format( f)) targets.extend(sub_targets) else: mod = os.path.basename( f) if options.scripts_are_modules else None targets.append(BuildSource(f, mod, None)) return targets, options
def process_options(args: List[str], require_targets: bool = True ) -> Tuple[List[BuildSource], Options]: """Parse command line arguments.""" # Make the help output a little less jarring. help_factory = (lambda prog: argparse.RawDescriptionHelpFormatter(prog=prog, max_help_position=28)) # type: Any parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, fromfile_prefix_chars='@', formatter_class=help_factory) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument('-v', '--verbose', action='count', dest='verbosity', help="more verbose messages") parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument('--platform', action='store', metavar='PLATFORM', help="typecheck special-cased code for the given OS platform " "(defaults to sys.platform).") parser.add_argument('-2', '--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('--ignore-missing-imports', action='store_true', help="silently ignore imports of missing modules") parser.add_argument('--follow-imports', choices=['normal', 'silent', 'skip', 'error'], default='normal', help="how to treat imports (default normal)") parser.add_argument('--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") parser.add_argument('--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") parser.add_argument('--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") 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', help="warn if missing type annotation in typeshed, only relevant with" " --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('--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('--show-error-context', action='store_false', dest='hide_error_context', help='Precede errors with "note:" messages explaining context') parser.add_argument('--fast-parser', action='store_true', help="enable fast parser (recommended except on Windows)") parser.add_argument('-i', '--incremental', action='store_true', help="enable experimental module cache") parser.add_argument('--cache-dir', action='store', metavar='DIR', help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.CACHE_DIR)) parser.add_argument('--strict-optional', action='store_true', dest='strict_optional', help="enable experimental strict Optional checks") 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('--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', help="show traceback on fatal error") parser.add_argument('--stats', action='store_true', dest='dump_type_stats', help="dump stats") parser.add_argument('--inferstats', action='store_true', dest='dump_inference_stats', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', dest='custom_typing_module', help="use a custom typing module") parser.add_argument('--custom-typeshed-dir', metavar='DIR', help="use the custom typeshed in DIR") parser.add_argument('--scripts-are-modules', action='store_true', help="Script x becomes module x instead of __main__") parser.add_argument('--config-file', help="Configuration file, must have a [mypy] section " "(defaults to {})".format(defaults.CONFIG_FILE)) parser.add_argument('--show-column-numbers', action='store_true', dest='show_column_numbers', help="Show column numbers in error messages") 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 # information from a mypy run without having to change the file in-place # (e.g. by adding a call to reveal_type). parser.add_argument('--shadow-file', metavar='PATH', nargs=2, dest='shadow_file', help=argparse.SUPPRESS) # --debug-cache will disable any cache-related compressions/optimizations, # which will make the cache writing process output pretty-printed JSON (which # is easier to debug). parser.add_argument('--debug-cache', action='store_true', help=argparse.SUPPRESS) # --dump-graph will dump the contents of the graph of SCCs and exit. parser.add_argument('--dump-graph', action='store_true', help=argparse.SUPPRESS) parser.add_argument('--hide-error-context', action='store_true', dest='hide_error_context', help=argparse.SUPPRESS) # deprecated options parser.add_argument('-f', '--dirty-stubs', action='store_true', dest='special-opts:dirty_stubs', help=argparse.SUPPRESS) parser.add_argument('--use-python-path', action='store_true', dest='special-opts:use_python_path', help=argparse.SUPPRESS) parser.add_argument('-s', '--silent-imports', action='store_true', dest='special-opts:silent_imports', help=argparse.SUPPRESS) parser.add_argument('--almost-silent', action='store_true', dest='special-opts:almost_silent', help=argparse.SUPPRESS) report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') for report_type in sorted(reporter_classes): report_group.add_argument('--%s-report' % report_type.replace('_', '-'), metavar='DIR', dest='special-opts:%s_report' % report_type) code_group = parser.add_argument_group(title='How to specify the code to type check') code_group.add_argument('-m', '--module', action='append', metavar='MODULE', dest='special-opts:modules', help="type-check module; can repeat for more modules") # TODO: `mypy -p A -p B` currently silently ignores ignores A # (last option wins). Perhaps -c, -m and -p could just be # command-line flags that modify how we interpret self.files? code_group.add_argument('-c', '--command', action='append', metavar='PROGRAM_TEXT', dest='special-opts:command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', metavar='PACKAGE', dest='special-opts:package', help="type-check all files in a directory") code_group.add_argument(metavar='files', nargs='*', dest='special-opts:files', help="type-check given files or directories") # Parse arguments once into a dummy namespace so we can get the # filename for the config file. dummy = argparse.Namespace() parser.parse_args(args, dummy) config_file = defaults.CONFIG_FILE 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) # Parse config file first, so command line can override. options = Options() if config_file and os.path.exists(config_file): parse_config_file(options, config_file) # Parse command line for real, using a split namespace. special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, 'special-opts:')) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error("Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # Process deprecated options if special_opts.almost_silent: print("Warning: --almost-silent has been replaced by " "--follow-imports=errors", file=sys.stderr) if options.follow_imports == 'normal': options.follow_imports = 'errors' elif special_opts.silent_imports: print("Warning: --silent-imports has been replaced by " "--ignore-missing-imports --follow-imports=skip", file=sys.stderr) options.ignore_missing_imports = True if options.follow_imports == 'normal': options.follow_imports = 'skip' if special_opts.dirty_stubs: print("Warning: -f/--dirty-stubs is deprecated and no longer necessary. Mypy no longer " "checks the git status of stubs.", file=sys.stderr) # Check for invalid argument combinations. if require_targets: code_methods = sum(bool(c) for c in [special_opts.modules, special_opts.command, special_opts.package, special_opts.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error("May only specify one of: module, package, files, or command.") # Set build flags. if options.strict_optional_whitelist is not None: # TODO: Deprecate, then kill this flag options.strict_optional = True if options.strict_optional: experiments.STRICT_OPTIONAL = True if special_opts.find_occurrences: experiments.find_occurrences = special_opts.find_occurrences.split('.') if len(experiments.find_occurrences) < 2: parser.error("Can only find occurrences of class members.") if len(experiments.find_occurrences) != 2: parser.error("Can only find occurrences of non-nested class members.") # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Set target. if special_opts.modules: options.build_type = BuildType.MODULE targets = [BuildSource(None, m, None) for m in special_opts.modules] return targets, options elif special_opts.package: if os.sep in special_opts.package or os.altsep and os.altsep in special_opts.package: fail("Package name '{}' cannot have a slash in it." .format(special_opts.package)) options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(special_opts.package, lib_path) if not targets: fail("Can't find package '{}'".format(special_opts.package)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT return [BuildSource(None, None, '\n'.join(special_opts.command))], options else: targets = [] for f in special_opts.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): sub_targets = expand_dir(f) if not sub_targets: fail("There are no .py[i] files in directory '{}'" .format(f)) targets.extend(sub_targets) else: mod = os.path.basename(f) if options.scripts_are_modules else None targets.append(BuildSource(f, mod, None)) return targets, options
def process_options(args: List[str], require_targets: bool = True, server_options: bool = False, fscache: Optional[FileSystemCache] = None, ) -> Tuple[List[BuildSource], Options]: """Parse command line arguments. If a FileSystemCache is passed in, and package_root options are given, call fscache.set_package_root() to set the cache's package root. """ parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, fromfile_prefix_chars='@', formatter_class=AugmentedHelpFormatter) strict_flag_names = [] # type: List[str] strict_flag_assignments = [] # type: List[Tuple[str, bool]] def add_invertible_flag(flag: str, *, inverse: Optional[str] = None, default: bool, dest: Optional[str] = None, help: str, strict_flag: bool = False, group: Optional[argparse._ActionsContainer] = None ) -> None: if inverse is None: inverse = invert_flag_name(flag) if group is None: group = parser if help is not argparse.SUPPRESS: help += " (inverse: {})".format(inverse) arg = group.add_argument(flag, action='store_false' if default else 'store_true', dest=dest, help=help) dest = arg.dest arg = group.add_argument(inverse, action='store_true' if default else 'store_false', dest=dest, help=argparse.SUPPRESS) if strict_flag: assert dest is not None strict_flag_names.append(flag) strict_flag_assignments.append((dest, not default)) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument('-v', '--verbose', action='count', dest='verbosity', help="more verbose messages") parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__, help="show program's version number and exit") config_group = parser.add_argument_group( title='config file', description="Use a config file instead of command line arguments.") config_group.add_argument( '--config-file', help="configuration file, must have a [mypy] section " "(defaults to {})".format(', '.join(defaults.CONFIG_FILES))) add_invertible_flag('--warn-unused-configs', default=False, strict_flag=True, help="warn about unused '[mypy-<pattern>]' config sections", group=config_group) imports_group = parser.add_argument_group( title='import discovery', description="Configure how imports are discovered and followed.") imports_group.add_argument( '--ignore-missing-imports', action='store_true', help="silently ignore imports of missing modules") imports_group.add_argument( '--follow-imports', choices=['normal', 'silent', 'skip', 'error'], default='normal', help="how to treat imports (default normal)") imports_group.add_argument( '--python-executable', action='store', metavar='EXECUTABLE', help="Python executable used for finding PEP 561 compliant installed" " packages and stubs", dest='special-opts:python_executable') imports_group.add_argument( '--no-site-packages', action='store_true', dest='special-opts:no_executable', help="do not search for installed PEP 561 compliant packages") platform_group = parser.add_argument_group( title='platform configuration', description="Type check code assuming certain runtime conditions.") platform_group.add_argument( '--python-version', type=parse_version, metavar='x.y', help='type check code assuming it will be running on Python x.y', dest='special-opts:python_version') platform_group.add_argument( '-2', '--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode (same as --python-version 2.7)") platform_group.add_argument( '--platform', action='store', metavar='PLATFORM', help="type check special-cased code for the given OS platform " "(defaults to sys.platform)") platform_group.add_argument( '--always-true', metavar='NAME', action='append', default=[], help="additional variable to be considered True (may be repeated)") platform_group.add_argument( '--always-false', metavar='NAME', action='append', default=[], help="additional variable to be considered False (may be repeated)") disallow_any_group = parser.add_argument_group( title='Any type restrictions', description="Disallow the use of the 'Any' type under certain conditions.") disallow_any_group.add_argument( '--disallow-any-unimported', default=False, action='store_true', help="disallow Any types resulting from unfollowed imports") add_invertible_flag('--disallow-subclassing-any', default=False, strict_flag=True, help="disallow subclassing values of type 'Any' when defining classes", group=disallow_any_group) disallow_any_group.add_argument( '--disallow-any-expr', default=False, action='store_true', help='disallow all expressions that have type Any') disallow_any_group.add_argument( '--disallow-any-decorated', default=False, action='store_true', help='disallow functions that have Any in their signature ' 'after decorator transformation') disallow_any_group.add_argument( '--disallow-any-explicit', default=False, action='store_true', help='disallow explicit Any in type positions') disallow_any_group.add_argument( '--disallow-any-generics', default=False, action='store_true', help='disallow usage of generic types that do not specify explicit ' 'type parameters') untyped_group = parser.add_argument_group( title='untyped definitions and calls', description="Configure how untyped definitions and calls are handled.") add_invertible_flag('--disallow-untyped-calls', default=False, strict_flag=True, help="disallow calling functions without type annotations" " from functions with type annotations", group=untyped_group) add_invertible_flag('--disallow-untyped-defs', default=False, strict_flag=True, help="disallow defining functions without type annotations" " or with incomplete type annotations", group=untyped_group) add_invertible_flag('--disallow-incomplete-defs', default=False, strict_flag=True, help="disallow defining functions with incomplete type annotations", group=untyped_group) add_invertible_flag('--check-untyped-defs', default=False, strict_flag=True, help="type check the interior of functions without type annotations", group=untyped_group) add_invertible_flag('--warn-incomplete-stub', default=False, help="warn if missing type annotation in typeshed, only relevant with" " --check-untyped-defs enabled", group=untyped_group) none_group = parser.add_argument_group( title='None and Optional handling', description="Adjust how values of type 'None' are handled.") add_invertible_flag('--no-implicit-optional', default=False, strict_flag=True, help="don't assume arguments with default values of None are Optional", group=none_group) none_group.add_argument( '--strict-optional', action='store_true', help=argparse.SUPPRESS) none_group.add_argument( '--no-strict-optional', action='store_false', dest='strict_optional', help="disable strict Optional checks (inverse: --strict-optional)") none_group.add_argument( '--strict-optional-whitelist', metavar='GLOB', nargs='*', help="suppress strict Optional errors in all but the provided files; " "implies --strict-optional (may suppress certain other errors " "in non-whitelisted files)") lint_group = parser.add_argument_group( title='warnings', description="Detect code that is sound but redundant or problematic.") add_invertible_flag('--warn-redundant-casts', default=False, strict_flag=True, help="warn about casting an expression to its inferred type", group=lint_group) add_invertible_flag('--no-warn-no-return', dest='warn_no_return', default=True, help="do not warn about functions that end without returning", group=lint_group) add_invertible_flag('--warn-return-any', default=False, strict_flag=True, help="warn about returning values of type Any" " from non-Any typed functions", group=lint_group) add_invertible_flag('--warn-unused-ignores', default=False, strict_flag=True, help="warn about unneeded '# type: ignore' comments", group=lint_group) strictness_group = parser.add_argument_group( title='other strictness checks', description="Other miscellaneous strictness checks.") add_invertible_flag('--disallow-untyped-decorators', default=False, strict_flag=True, help="disallow decorating typed functions with untyped decorators", group=strictness_group) incremental_group = parser.add_argument_group( title='incremental mode', description="Adjust how mypy incrementally type checks and caches modules.") incremental_group.add_argument( '-i', '--incremental', action='store_true', help=argparse.SUPPRESS) incremental_group.add_argument( '--no-incremental', action='store_false', dest='incremental', help="disable module cache (inverse: --incremental)") incremental_group.add_argument( '--cache-dir', action='store', metavar='DIR', help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.CACHE_DIR)) incremental_group.add_argument( '--cache-fine-grained', action='store_true', help="include fine-grained dependency information in the cache for the mypy daemon") incremental_group.add_argument( '--quick-and-dirty', action='store_true', help="use cache even if dependencies out of date (implies --incremental)") incremental_group.add_argument( '--skip-version-check', action='store_true', help="allow using cache written by older mypy version") internals_group = parser.add_argument_group( title='mypy internals', description="Debug and customize mypy internals.") internals_group.add_argument( '--pdb', action='store_true', help="invoke pdb on fatal error") internals_group.add_argument( '--show-traceback', '--tb', action='store_true', help="show traceback on fatal error") internals_group.add_argument( '--custom-typing', metavar='MODULE', dest='custom_typing_module', help="use a custom typing module") internals_group.add_argument( '--custom-typeshed-dir', metavar='DIR', help="use the custom typeshed in DIR") internals_group.add_argument( '--shadow-file', nargs=2, metavar=('SOURCE_FILE', 'SHADOW_FILE'), dest='shadow_file', action='append', help="when encountering SOURCE_FILE, read and type check " "the contents of SHADOW_FILE instead.") error_group = parser.add_argument_group( title='error reporting', description="Adjust the amount of detail shown in error messages.") add_invertible_flag('--show-error-context', default=False, dest='show_error_context', help='precede errors with "note:" messages explaining context', group=error_group) add_invertible_flag('--show-column-numbers', default=False, help="show column numbers in error messages", group=error_group) analysis_group = parser.add_argument_group( title='extra analysis', description="Extract additional information and analysis.") analysis_group.add_argument( '--stats', action='store_true', dest='dump_type_stats', help=argparse.SUPPRESS) analysis_group.add_argument( '--inferstats', action='store_true', dest='dump_inference_stats', help=argparse.SUPPRESS) analysis_group.add_argument( '--find-occurrences', metavar='CLASS.MEMBER', dest='special-opts:find_occurrences', help="print out all usages of a class member (experimental)") strict_help = "strict mode; enables the following flags: {}".format( ", ".join(strict_flag_names)) strictness_group.add_argument( '--strict', action='store_true', dest='special-opts:strict', help=strict_help) report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') for report_type in sorted(reporter_classes): report_group.add_argument('--%s-report' % report_type.replace('_', '-'), metavar='DIR', dest='special-opts:%s_report' % report_type) other_group = parser.add_argument_group( title='miscellaneous', description="Other miscellaneous flags.") other_group.add_argument( '--junit-xml', help="write junit.xml to the given file") other_group.add_argument( '--scripts-are-modules', action='store_true', help="script x becomes module x instead of __main__") if server_options: # TODO: This flag is superfluous; remove after a short transition (2018-03-16) other_group.add_argument( '--experimental', action='store_true', dest='fine_grained_incremental', help="enable fine-grained incremental mode") other_group.add_argument( '--use-fine-grained-cache', action='store_true', help="use the cache in fine-grained incremental mode") # hidden options # --debug-cache will disable any cache-related compressions/optimizations, # which will make the cache writing process output pretty-printed JSON (which # is easier to debug). parser.add_argument('--debug-cache', action='store_true', help=argparse.SUPPRESS) # --dump-deps will dump all fine-grained dependencies to stdout parser.add_argument('--dump-deps', action='store_true', help=argparse.SUPPRESS) # --dump-graph will dump the contents of the graph of SCCs and exit. parser.add_argument('--dump-graph', action='store_true', help=argparse.SUPPRESS) # --semantic-analysis-only does exactly that. parser.add_argument('--semantic-analysis-only', action='store_true', help=argparse.SUPPRESS) # --local-partial-types disallows partial types spanning module top level and a function # (implicitly defined in fine-grained incremental mode) parser.add_argument('--local-partial-types', action='store_true', help=argparse.SUPPRESS) # --bazel changes some behaviors for use with Bazel (https://bazel.build). parser.add_argument('--bazel', action='store_true', help=argparse.SUPPRESS) # --package-root adds a directory below which directories are considered # packages even without __init__.py. May be repeated. parser.add_argument('--package-root', metavar='ROOT', action='append', default=[], help=argparse.SUPPRESS) # --cache-map FILE ... gives a mapping from source files to cache files. # Each triple of arguments is a source file, a cache meta file, and a cache data file. # Modules not mentioned in the file will go through cache_dir. # Must be followed by another flag or by '--' (and then only file args may follow). parser.add_argument('--cache-map', nargs='+', dest='special-opts:cache_map', help=argparse.SUPPRESS) # deprecated options parser.add_argument('--disallow-any', dest='special-opts:disallow_any', help=argparse.SUPPRESS) add_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) parser.add_argument('--use-python-path', action='store_true', dest='special-opts:use_python_path', help=argparse.SUPPRESS) parser.add_argument('-s', '--silent-imports', action='store_true', dest='special-opts:silent_imports', help=argparse.SUPPRESS) parser.add_argument('--almost-silent', action='store_true', dest='special-opts:almost_silent', help=argparse.SUPPRESS) parser.add_argument('--fast-parser', action='store_true', dest='special-opts:fast_parser', help=argparse.SUPPRESS) parser.add_argument('--no-fast-parser', action='store_true', dest='special-opts:no_fast_parser', help=argparse.SUPPRESS) code_group = parser.add_argument_group(title='specifying which code to type check') code_group.add_argument('-m', '--module', action='append', metavar='MODULE', default=[], dest='special-opts:modules', help="type-check module; can repeat for more modules") code_group.add_argument('-p', '--package', action='append', metavar='PACKAGE', default=[], dest='special-opts:packages', help="type-check package recursively; can be repeated") code_group.add_argument('-c', '--command', action='append', metavar='PROGRAM_TEXT', dest='special-opts:command', help="type-check program passed in as string") code_group.add_argument(metavar='files', nargs='*', dest='special-opts:files', help="type-check given files or directories") # Parse arguments once into a dummy namespace so we can get the # filename for the config file and know if the user requested all strict options. dummy = argparse.Namespace() parser.parse_args(args, dummy) config_file = dummy.config_file if config_file is not None and not os.path.exists(config_file): parser.error("Cannot find config file '%s'" % config_file) # Parse config file first, so command line can override. options = Options() parse_config_file(options, config_file) # Set strict flags before parsing (if strict mode enabled), so other command # line options can override. if getattr(dummy, 'special-opts:strict'): for dest, value in strict_flag_assignments: setattr(options, dest, value) # Parse command line for real, using a split namespace. special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, 'special-opts:')) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error("Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # Process deprecated options if special_opts.disallow_any: print("--disallow-any option was split up into multiple flags. " "See http://mypy.readthedocs.io/en/latest/command_line.html#disallow-any-flags") 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) if options.follow_imports == 'normal': options.follow_imports = 'errors' elif special_opts.silent_imports: print("Warning: --silent-imports has been replaced by " "--ignore-missing-imports --follow-imports=skip", file=sys.stderr) options.ignore_missing_imports = True if options.follow_imports == 'normal': options.follow_imports = 'skip' if special_opts.dirty_stubs: print("Warning: -f/--dirty-stubs is deprecated and no longer necessary. Mypy no longer " "checks the git status of stubs.", file=sys.stderr) if special_opts.fast_parser: print("Warning: --fast-parser is now the default (and only) parser.") if special_opts.no_fast_parser: print("Warning: --no-fast-parser no longer has any effect. The fast parser " "is now mypy's default and only parser.") try: infer_python_version_and_executable(options, special_opts) except PythonExecutableInferenceError as e: parser.error(str(e)) if special_opts.no_executable: options.python_executable = None # Check for invalid argument combinations. if require_targets: code_methods = sum(bool(c) for c in [special_opts.modules + special_opts.packages, special_opts.command, special_opts.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error("May only specify one of: module/package, files, or command.") # Check for overlapping `--always-true` and `--always-false` flags. overlap = set(options.always_true) & set(options.always_false) if overlap: parser.error("You can't make a variable always true and always false (%s)" % ', '.join(sorted(overlap))) # Set build flags. if options.strict_optional_whitelist is not None: # TODO: Deprecate, then kill this flag options.strict_optional = True if special_opts.find_occurrences: experiments.find_occurrences = special_opts.find_occurrences.split('.') assert experiments.find_occurrences is not None if len(experiments.find_occurrences) < 2: parser.error("Can only find occurrences of class members.") if len(experiments.find_occurrences) != 2: parser.error("Can only find occurrences of non-nested class members.") # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Process --package-root. if options.package_root: process_package_roots(fscache, parser, options) # Process --cache-map. if special_opts.cache_map: process_cache_map(parser, special_opts, options) # Let quick_and_dirty imply incremental. if options.quick_and_dirty: options.incremental = True # Set target. if special_opts.modules + special_opts.packages: options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() targets = [] # TODO: use the same cache that the BuildManager will cache = build.FindModuleCache(fscache) for p in special_opts.packages: if os.sep in p or os.altsep and os.altsep in p: fail("Package name '{}' cannot have a slash in it.".format(p)) p_targets = cache.find_modules_recursive(p, tuple(lib_path), options.python_executable) if not p_targets: fail("Can't find package '{}'".format(p)) targets.extend(p_targets) for m in special_opts.modules: targets.append(BuildSource(None, m, None)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT targets = [BuildSource(None, None, '\n'.join(special_opts.command))] return targets, options else: try: targets = create_source_list(special_opts.files, options, fscache) except InvalidSourceList as e: fail(str(e)) return targets, options
def process_options(args: List[str], require_targets: bool = True) -> Tuple[List[BuildSource], Options]: """Parse command line arguments.""" # Make the help output a little less jarring. help_factory = lambda prog: argparse.RawDescriptionHelpFormatter(prog=prog, max_help_position=28) parser = argparse.ArgumentParser(prog="mypy", epilog=FOOTER, formatter_class=help_factory) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument("-v", "--verbose", action="count", dest="verbosity", help="more verbose messages") parser.add_argument("-V", "--version", action="version", version="%(prog)s " + __version__) parser.add_argument("--python-version", type=parse_version, metavar="x.y", help="use Python x.y") parser.add_argument( "--platform", action="store", metavar="PLATFORM", help="typecheck special-cased code for the given OS platform " "(defaults to sys.platform).", ) parser.add_argument( "-2", "--py2", dest="python_version", action="store_const", const=defaults.PYTHON2_VERSION, help="use Python 2 mode", ) parser.add_argument("-s", "--silent-imports", action="store_true", help="don't follow imports to .py files") parser.add_argument( "--almost-silent", action="store_true", help="like --silent-imports but reports the imports as errors" ) parser.add_argument( "--disallow-untyped-calls", action="store_true", help="disallow calling functions without type annotations" " from functions with type annotations", ) parser.add_argument( "--disallow-untyped-defs", action="store_true", help="disallow defining functions without type annotations" " or with incomplete type annotations", ) parser.add_argument( "--check-untyped-defs", action="store_true", help="type check the interior of functions without type annotations", ) 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", help="warn if missing type annotation in typeshed, only relevant with" " --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( "--warn-unused-ignores", action="store_true", help="warn about unneeded '# type: ignore' comments" ) parser.add_argument( "--suppress-error-context", action="store_true", dest="suppress_error_context", help="Suppress context notes before errors", ) parser.add_argument("--fast-parser", action="store_true", help="enable experimental fast parser") parser.add_argument("-i", "--incremental", action="store_true", help="enable experimental module cache") parser.add_argument( "--cache-dir", action="store", metavar="DIR", help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.MYPY_CACHE), ) parser.add_argument( "--strict-optional", action="store_true", dest="special-opts:strict_optional", help="enable experimental strict Optional checks", ) 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("--pdb", action="store_true", help="invoke pdb on fatal error") parser.add_argument("--show-traceback", "--tb", action="store_true", help="show traceback on fatal error") parser.add_argument("--stats", action="store_true", dest="dump_type_stats", help="dump stats") parser.add_argument( "--inferstats", action="store_true", dest="dump_inference_stats", help="dump type inference stats" ) parser.add_argument( "--custom-typing", metavar="MODULE", dest="custom_typing_module", help="use a custom typing module" ) # 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 # information from a mypy run without having to change the file in-place # (e.g. by adding a call to reveal_type). parser.add_argument("--shadow-file", metavar="PATH", nargs=2, dest="shadow_file", help=argparse.SUPPRESS) # --debug-cache will disable any cache-related compressions/optimizations, # which will make the cache writing process output pretty-printed JSON (which # is easier to debug). parser.add_argument("--debug-cache", action="store_true", help=argparse.SUPPRESS) # deprecated options parser.add_argument("--silent", action="store_true", dest="special-opts:silent", help=argparse.SUPPRESS) parser.add_argument( "-f", "--dirty-stubs", action="store_true", dest="special-opts:dirty_stubs", help=argparse.SUPPRESS ) parser.add_argument( "--use-python-path", action="store_true", dest="special-opts:use_python_path", help=argparse.SUPPRESS ) report_group = parser.add_argument_group( title="report generation", description="Generate a report in the specified format." ) report_group.add_argument("--html-report", metavar="DIR", dest="special-opts:html_report") report_group.add_argument("--old-html-report", metavar="DIR", dest="special-opts:old_html_report") report_group.add_argument("--xslt-html-report", metavar="DIR", dest="special-opts:xslt_html_report") report_group.add_argument("--xml-report", metavar="DIR", dest="special-opts:xml_report") report_group.add_argument("--txt-report", metavar="DIR", dest="special-opts:txt_report") report_group.add_argument("--xslt-txt-report", metavar="DIR", dest="special-opts:xslt_txt_report") report_group.add_argument("--linecount-report", metavar="DIR", dest="special-opts:linecount_report") report_group.add_argument("--linecoverage-report", metavar="DIR", dest="special-opts:linecoverage_report") code_group = parser.add_argument_group(title="How to specify the code to type check") code_group.add_argument( "-m", "--module", action="append", metavar="MODULE", dest="special-opts:modules", help="type-check module; can repeat for more modules", ) # TODO: `mypy -c A -c B` and `mypy -p A -p B` currently silently # ignore A (last option wins). Perhaps -c, -m and -p could just # be command-line flags that modify how we interpret self.files? code_group.add_argument( "-c", "--command", action="append", metavar="PROGRAM_TEXT", dest="special-opts:command", help="type-check program passed in as string", ) code_group.add_argument( "-p", "--package", metavar="PACKAGE", dest="special-opts:package", help="type-check all files in a directory" ) code_group.add_argument( metavar="files", nargs="*", dest="special-opts:files", help="type-check given files or directories" ) options = Options() special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, "special-opts:")) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error( "Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # warn about deprecated options if special_opts.silent: print("Warning: --silent is deprecated; use --silent-imports", file=sys.stderr) options.silent_imports = True if special_opts.dirty_stubs: print( "Warning: -f/--dirty-stubs is deprecated and no longer necessary. Mypy no longer " "checks the git status of stubs.", file=sys.stderr, ) # Check for invalid argument combinations. if require_targets: code_methods = sum( bool(c) for c in [special_opts.modules, special_opts.command, special_opts.package, special_opts.files] ) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error("May only specify one of: module, package, files, or command.") # Set build flags. if special_opts.strict_optional or options.strict_optional_whitelist is not None: experiments.STRICT_OPTIONAL = True # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith("_report") and val is not None: report_type = flag[:-7].replace("_", "-") report_dir = val options.report_dirs[report_type] = report_dir # Set target. if special_opts.modules: options.build_type = BuildType.MODULE targets = [BuildSource(None, m, None) for m in special_opts.modules] return targets, options elif special_opts.package: if os.sep in special_opts.package or os.altsep and os.altsep in special_opts.package: fail("Package name '{}' cannot have a slash in it.".format(special_opts.package)) options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(special_opts.package, lib_path) if not targets: fail("Can't find package '{}'".format(special_opts.package)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT return [BuildSource(None, None, "\n".join(special_opts.command))], options else: targets = [] for f in special_opts.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): sub_targets = expand_dir(f) if not sub_targets: fail("There are no .py[i] files in directory '{}'".format(f)) targets.extend(sub_targets) else: targets.append(BuildSource(f, None, None)) return targets, options
def process_options(args: List[str]) -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ options = Options() help = False ver = False while args and args[0].startswith('-'): if args[0] == '--verbose': options.build_flags.append(build.VERBOSE) args = args[1:] elif args[0] == '--py2': # Use Python 2 mode. options.pyversion = defaults.PYTHON2_VERSION args = args[1:] elif args[0] == '--python-version': version_components = args[1].split(".")[0:2] if len(version_components) != 2: fail("Invalid python version {} (expected format: 'x.y')".format( repr(args[1]))) if not all(item.isdigit() for item in version_components): fail("Found non-digit in python version: {}".format( args[1])) options.pyversion = (int(version_components[0]), int(version_components[1])) args = args[2:] elif args[0] == '-f' or args[0] == '--dirty-stubs': options.dirty_stubs = True args = args[1:] elif args[0] == '-m' and args[1:]: options.build_flags.append(build.MODULE) return [BuildSource(None, args[1], None)], options elif args[0] == '--package' and args[1:]: options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args[1], lib_path) if not targets: fail("Can't find package '{}'".format(args[1])) return targets, options elif args[0] == '-c' and args[1:]: options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args[1])], options elif args[0] in ('-h', '--help'): help = True args = args[1:] elif args[0] == '--stats': options.build_flags.append(build.DUMP_TYPE_STATS) args = args[1:] elif args[0] == '--inferstats': options.build_flags.append(build.DUMP_INFER_STATS) args = args[1:] elif args[0] == '--custom-typing' and args[1:]: options.custom_typing_module = args[1] args = args[2:] elif is_report(args[0]) and args[1:]: report_type = args[0][2:-7] report_dir = args[1] options.report_dirs[report_type] = report_dir args = args[2:] elif args[0] == '--use-python-path': options.python_path = True args = args[1:] elif args[0] == '--version': ver = True args = args[1:] else: usage('Unknown option: {}'.format(args[0])) if help: usage() if ver: version() if not args: usage('Missing target file or module') if args[1:]: usage('Extra argument: {}'.format(args[1])) if options.python_path and options.pyversion[0] == 2: usage('Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') return [BuildSource(args[0], None, None)], options
def process_options(args: List[str]) -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # Make the help output a little less jarring. help_factory = (lambda prog: argparse.RawDescriptionHelpFormatter( prog=prog, max_help_position=28)) parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, formatter_class=help_factory) def parse_version(v: str) -> Tuple[int, int]: m = re.match(r'\A(\d)\.(\d+)\Z', v) if m: return int(m.group(1)), int(m.group(2)) else: raise argparse.ArgumentTypeError( "Invalid python version '{}' (expected format: 'x.y')".format( v)) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument('-v', '--verbose', action='count', dest='verbosity', help="more verbose messages") parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument('--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('-s', '--silent-imports', action='store_true', help="don't follow imports to .py files") parser.add_argument('--silent', action='store_true', dest='special-opts:silent', help="deprecated name for --silent-imports") parser.add_argument( '--almost-silent', action='store_true', help="like --silent-imports but reports the imports as errors") parser.add_argument( '--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") parser.add_argument( '--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") parser.add_argument( '--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") parser.add_argument( '--warn-incomplete-stub', action='store_true', help="warn if missing type annotation in typeshed, only relevant with" " --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('--warn-unused-ignores', action='store_true', help="warn about unneeded '# type: ignore' comments") parser.add_argument('--fast-parser', action='store_true', help="enable experimental fast parser") parser.add_argument('-i', '--incremental', action='store_true', help="enable experimental module cache") parser.add_argument( '--cache-dir', action='store', metavar='DIR', help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.MYPY_CACHE)) parser.add_argument('--strict-optional', action='store_true', dest='special-opts:strict_optional', help="enable experimental strict Optional checks") parser.add_argument('-f', '--dirty-stubs', action='store_true', help="don't warn if typeshed is out of sync") parser.add_argument('--pdb', action='store_true', help="invoke pdb on fatal error") parser.add_argument('--use-python-path', action='store_true', dest='special-opts:use_python_path', help="an anti-pattern") parser.add_argument('--stats', action='store_true', dest='dump_type_stats', help="dump stats") parser.add_argument('--inferstats', action='store_true', dest='dump_inference_stats', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', dest='custom_typing_module', help="use a custom typing module") report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') report_group.add_argument('--html-report', metavar='DIR', dest='special-opts:html_report') report_group.add_argument('--old-html-report', metavar='DIR', dest='special-opts:old_html_report') report_group.add_argument('--xslt-html-report', metavar='DIR', dest='special-opts:xslt_html_report') report_group.add_argument('--xml-report', metavar='DIR', dest='special-opts:xml_report') report_group.add_argument('--txt-report', metavar='DIR', dest='special-opts:txt_report') report_group.add_argument('--xslt-txt-report', metavar='DIR', dest='special-opts:xslt_txt_report') report_group.add_argument('--linecount-report', metavar='DIR', dest='special-opts:linecount_report') code_group = parser.add_argument_group( title='How to specify the code to type check') code_group.add_argument( '-m', '--module', action='append', metavar='MODULE', dest='special-opts:modules', help="type-check module; can repeat for more modules") # TODO: `mypy -c A -c B` and `mypy -p A -p B` currently silently # ignore A (last option wins). Perhaps -c, -m and -p could just # be command-line flags that modify how we interpret self.files? code_group.add_argument('-c', '--command', metavar='PROGRAM_TEXT', dest='special-opts:command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', metavar='PACKAGE', dest='special-opts:package', help="type-check all files in a directory") code_group.add_argument(metavar='files', nargs='*', dest='special-opts:files', help="type-check given files or directories") options = Options() special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, 'special-opts:')) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error( "Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # --silent is deprecated; warn about this. if special_opts.silent: print("Warning: --silent is deprecated; use --silent-imports", file=sys.stderr) options.silent_imports = True # Check for invalid argument combinations. code_methods = sum( bool(c) for c in [ special_opts.modules, special_opts.command, special_opts.package, special_opts.files ]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error( "May only specify one of: module, package, files, or command.") # Set build flags. if special_opts.strict_optional: experiments.STRICT_OPTIONAL = True # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Set target. if special_opts.modules: options.build_type = BuildType.MODULE targets = [BuildSource(None, m, None) for m in special_opts.modules] return targets, options elif special_opts.package: if os.sep in special_opts.package or os.altsep and os.altsep in special_opts.package: fail("Package name '{}' cannot have a slash in it.".format( special_opts.package)) options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(special_opts.package, lib_path) if not targets: fail("Can't find package '{}'".format(special_opts.package)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT return [BuildSource(None, None, special_opts.command)], options else: targets = [] for f in special_opts.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): sub_targets = expand_dir(f) if not sub_targets: fail("There are no .py[i] files in directory '{}'".format( f)) targets.extend(sub_targets) else: targets.append(BuildSource(f, None, None)) return targets, options
def process_options(args: List[str]) -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # Make the help output a little less jarring. help_factory = (lambda prog: argparse.RawDescriptionHelpFormatter(prog=prog, max_help_position=28)) parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, formatter_class=help_factory) def parse_version(v: str) -> Tuple[int, int]: m = re.match(r'\A(\d)\.(\d+)\Z', v) if m: return int(m.group(1)), int(m.group(2)) else: raise argparse.ArgumentTypeError( "Invalid python version '{}' (expected format: 'x.y')".format(v)) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument('-v', '--verbose', action='count', dest='verbosity', help="more verbose messages") parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument('--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('-s', '--silent-imports', action='store_true', help="don't follow imports to .py files") parser.add_argument('--almost-silent', action='store_true', help="like --silent-imports but reports the imports as errors") parser.add_argument('--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") parser.add_argument('--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") parser.add_argument('--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") parser.add_argument('--warn-incomplete-stub', action='store_true', help="warn if missing type annotation in typeshed, only relevant with" " --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('--warn-unused-ignores', action='store_true', help="warn about unneeded '# type: ignore' comments") parser.add_argument('--suppress-error-context', action='store_true', dest='suppress_error_context', help="Suppress context notes before errors") parser.add_argument('--fast-parser', action='store_true', help="enable experimental fast parser") parser.add_argument('-i', '--incremental', action='store_true', help="enable experimental module cache") parser.add_argument('--cache-dir', action='store', metavar='DIR', help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.MYPY_CACHE)) parser.add_argument('--strict-optional', action='store_true', dest='special-opts:strict_optional', help="enable experimental strict Optional checks") parser.add_argument('--pdb', action='store_true', help="invoke pdb on fatal error") parser.add_argument('--stats', action='store_true', dest='dump_type_stats', help="dump stats") parser.add_argument('--inferstats', action='store_true', dest='dump_inference_stats', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', dest='custom_typing_module', help="use a custom typing module") # deprecated options parser.add_argument('--silent', action='store_true', dest='special-opts:silent', help=argparse.SUPPRESS) parser.add_argument('-f', '--dirty-stubs', action='store_true', dest='special-opts:dirty_stubs', help=argparse.SUPPRESS) parser.add_argument('--use-python-path', action='store_true', dest='special-opts:use_python_path', help=argparse.SUPPRESS) report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') report_group.add_argument('--html-report', metavar='DIR', dest='special-opts:html_report') report_group.add_argument('--old-html-report', metavar='DIR', dest='special-opts:old_html_report') report_group.add_argument('--xslt-html-report', metavar='DIR', dest='special-opts:xslt_html_report') report_group.add_argument('--xml-report', metavar='DIR', dest='special-opts:xml_report') report_group.add_argument('--txt-report', metavar='DIR', dest='special-opts:txt_report') report_group.add_argument('--xslt-txt-report', metavar='DIR', dest='special-opts:xslt_txt_report') report_group.add_argument('--linecount-report', metavar='DIR', dest='special-opts:linecount_report') code_group = parser.add_argument_group(title='How to specify the code to type check') code_group.add_argument('-m', '--module', action='append', metavar='MODULE', dest='special-opts:modules', help="type-check module; can repeat for more modules") # TODO: `mypy -c A -c B` and `mypy -p A -p B` currently silently # ignore A (last option wins). Perhaps -c, -m and -p could just # be command-line flags that modify how we interpret self.files? code_group.add_argument('-c', '--command', metavar='PROGRAM_TEXT', dest='special-opts:command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', metavar='PACKAGE', dest='special-opts:package', help="type-check all files in a directory") code_group.add_argument(metavar='files', nargs='*', dest='special-opts:files', help="type-check given files or directories") options = Options() special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, 'special-opts:')) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error("Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # warn about deprecated options if special_opts.silent: print("Warning: --silent is deprecated; use --silent-imports", file=sys.stderr) options.silent_imports = True if special_opts.dirty_stubs: print("Warning: -f/--dirty-stubs is deprecated and no longer necessary. Mypy no longer " "checks the git status of stubs.", file=sys.stderr) # Check for invalid argument combinations. code_methods = sum(bool(c) for c in [special_opts.modules, special_opts.command, special_opts.package, special_opts.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error("May only specify one of: module, package, files, or command.") # Set build flags. if special_opts.strict_optional: experiments.STRICT_OPTIONAL = True # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Set target. if special_opts.modules: options.build_type = BuildType.MODULE targets = [BuildSource(None, m, None) for m in special_opts.modules] return targets, options elif special_opts.package: if os.sep in special_opts.package or os.altsep and os.altsep in special_opts.package: fail("Package name '{}' cannot have a slash in it." .format(special_opts.package)) options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(special_opts.package, lib_path) if not targets: fail("Can't find package '{}'".format(special_opts.package)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT return [BuildSource(None, None, special_opts.command)], options else: targets = [] for f in special_opts.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): sub_targets = expand_dir(f) if not sub_targets: fail("There are no .py[i] files in directory '{}'" .format(f)) targets.extend(sub_targets) else: targets.append(BuildSource(f, None, None)) return targets, options
def process_options() -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, formatter_class=argparse.RawDescriptionHelpFormatter) def parse_version(v): m = re.match(r'\A(\d)\.(\d+)\Z', v) if m: return int(m.group(1)), int(m.group(2)) else: raise argparse.ArgumentTypeError( "Invalid python version '{}' (expected format: 'x.y')".format(v)) parser.add_argument('-v', '--verbose', action='count', help="more verbose messages") parser.add_argument('-V', '--version', action='version', # type: ignore # see typeshed#124 version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument('--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('-s', '--silent-imports', '--silent', action='store_true', help="don't follow imports to .py files") parser.add_argument('--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") parser.add_argument('--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") parser.add_argument('--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") parser.add_argument('--fast-parser', action='store_true', help="enable experimental fast parser") parser.add_argument('-i', '--incremental', action='store_true', help="enable experimental module cache") parser.add_argument('-f', '--dirty-stubs', action='store_true', help="don't warn if typeshed is out of sync") parser.add_argument('--pdb', action='store_true', help="invoke pdb on fatal error") parser.add_argument('--use-python-path', action='store_true', help="search for modules in sys.path of running Python") parser.add_argument('--stats', action='store_true', help="dump stats") parser.add_argument('--inferstats', action='store_true', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', help="use a custom typing module") report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') report_group.add_argument('--html-report', metavar='DIR') report_group.add_argument('--old-html-report', metavar='DIR') report_group.add_argument('--xslt-html-report', metavar='DIR') report_group.add_argument('--xml-report', metavar='DIR') report_group.add_argument('--txt-report', metavar='DIR') report_group.add_argument('--xslt-txt-report', metavar='DIR') report_group.add_argument('--linecount-report', metavar='DIR') code_group = parser.add_argument_group(title='How to specify the code to type check') code_group.add_argument('-m', '--module', action='append', dest='modules', help="type-check module; can repeat for more modules") code_group.add_argument('-c', '--command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', help="type-check all files in a directory") code_group.add_argument('files', nargs='*', help="type-check given files or directories") args = parser.parse_args() # Check for invalid argument combinations. code_methods = sum(bool(c) for c in [args.modules, args.command, args.package, args.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error("May only specify one of: module, package, files, or command.") if args.use_python_path and args.python_version and args.python_version[0] == 2: parser.error('Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') if args.fast_parser and args.python_version and args.python_version[0] == 2: parser.error('The experimental fast parser is only compatible with Python 3, ' 'but Python 2 specified.') # Set options. options = Options() options.dirty_stubs = args.dirty_stubs options.python_path = args.use_python_path options.pdb = args.pdb options.custom_typing_module = args.custom_typing # Set build flags. if args.python_version is not None: options.pyversion = args.python_version if args.verbose: options.build_flags.extend(args.verbose * [build.VERBOSE]) if args.stats: options.build_flags.append(build.DUMP_TYPE_STATS) if args.inferstats: options.build_flags.append(build.DUMP_INFER_STATS) if args.silent_imports: options.build_flags.append(build.SILENT_IMPORTS) if args.disallow_untyped_calls: options.build_flags.append(build.DISALLOW_UNTYPED_CALLS) if args.disallow_untyped_defs: options.build_flags.append(build.DISALLOW_UNTYPED_DEFS) if args.check_untyped_defs: options.build_flags.append(build.CHECK_UNTYPED_DEFS) # experimental if args.fast_parser: options.build_flags.append(build.FAST_PARSER) if args.incremental: options.build_flags.append(build.INCREMENTAL) # Set reports. for flag, val in vars(args).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Set target. if args.modules: options.build_flags.append(build.MODULE) targets = [BuildSource(None, m, None) for m in args.modules] return targets, options elif args.package: options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args.package, lib_path) if not targets: fail("Can't find package '{}'".format(args.package)) return targets, options elif args.command: options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args.command)], options else: targets = [] for f in args.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): targets.extend(expand_dir(f)) else: targets.append(BuildSource(f, None, None)) return targets, options
def process_options(args: List[str], require_targets: bool = True, server_options: bool = False, ) -> Tuple[List[BuildSource], Options]: """Parse command line arguments.""" parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, fromfile_prefix_chars='@', formatter_class=AugmentedHelpFormatter) strict_flag_names = [] # type: List[str] strict_flag_assignments = [] # type: List[Tuple[str, bool]] def add_invertible_flag(flag: str, *, inverse: Optional[str] = None, default: bool, dest: Optional[str] = None, help: str, strict_flag: bool = False ) -> None: if inverse is None: inverse = invert_flag_name(flag) if help is not argparse.SUPPRESS: help += " (inverse: {})".format(inverse) arg = parser.add_argument(flag, # type: ignore # incorrect stub for add_argument action='store_false' if default else 'store_true', dest=dest, help=help) dest = arg.dest arg = parser.add_argument(inverse, # type: ignore # incorrect stub for add_argument action='store_true' if default else 'store_false', dest=dest, help=argparse.SUPPRESS) if strict_flag: assert dest is not None strict_flag_names.append(flag) strict_flag_assignments.append((dest, not default)) # Unless otherwise specified, arguments will be parsed directly onto an # Options object. Options that require further processing should have # their `dest` prefixed with `special-opts:`, which will cause them to be # parsed into the separate special_opts namespace object. parser.add_argument('-v', '--verbose', action='count', dest='verbosity', help="more verbose messages") parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument('--platform', action='store', metavar='PLATFORM', help="typecheck special-cased code for the given OS platform " "(defaults to sys.platform).") parser.add_argument('-2', '--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('--ignore-missing-imports', action='store_true', help="silently ignore imports of missing modules") parser.add_argument('--follow-imports', choices=['normal', 'silent', 'skip', 'error'], default='normal', help="how to treat imports (default normal)") parser.add_argument('--disallow-any-unimported', default=False, action='store_true', help="disallow Any types resulting from unfollowed imports") parser.add_argument('--disallow-any-expr', default=False, action='store_true', help='disallow all expressions that have type Any') parser.add_argument('--disallow-any-decorated', default=False, action='store_true', help='disallow functions that have Any in their signature ' 'after decorator transformation') parser.add_argument('--disallow-any-explicit', default=False, action='store_true', help='disallow explicit Any in type positions') parser.add_argument('--disallow-any-generics', default=False, action='store_true', help='disallow usage of generic types that do not specify explicit ' 'type parameters') add_invertible_flag('--disallow-untyped-calls', default=False, strict_flag=True, help="disallow calling functions without type annotations" " from functions with type annotations") add_invertible_flag('--disallow-untyped-defs', default=False, strict_flag=True, help="disallow defining functions without type annotations" " or with incomplete type annotations") add_invertible_flag('--disallow-incomplete-defs', default=False, strict_flag=True, help="disallow defining functions with incomplete type annotations") add_invertible_flag('--check-untyped-defs', default=False, strict_flag=True, help="type check the interior of functions without type annotations") add_invertible_flag('--disallow-subclassing-any', default=False, strict_flag=True, help="disallow subclassing values of type 'Any' when defining classes") add_invertible_flag('--warn-incomplete-stub', default=False, help="warn if missing type annotation in typeshed, only relevant with" " --check-untyped-defs enabled") add_invertible_flag('--disallow-untyped-decorators', default=False, strict_flag=True, help="disallow decorating typed functions with untyped decorators") add_invertible_flag('--warn-redundant-casts', default=False, strict_flag=True, help="warn about casting an expression to its inferred type") add_invertible_flag('--no-warn-no-return', dest='warn_no_return', default=True, help="do not warn about functions that end without returning") add_invertible_flag('--warn-return-any', default=False, strict_flag=True, help="warn about returning values of type Any" " from non-Any typed functions") add_invertible_flag('--warn-unused-ignores', default=False, strict_flag=True, help="warn about unneeded '# type: ignore' comments") add_invertible_flag('--warn-unused-configs', default=False, strict_flag=True, help="warn about unused '[mypy-<pattern>]' config sections") add_invertible_flag('--show-error-context', default=False, dest='show_error_context', help='Precede errors with "note:" messages explaining context') add_invertible_flag('--no-implicit-optional', default=False, strict_flag=True, help="don't assume arguments with default values of None are Optional") parser.add_argument('-i', '--incremental', action='store_true', help="enable module cache, (inverse: --no-incremental)") parser.add_argument('--no-incremental', action='store_false', dest='incremental', help=argparse.SUPPRESS) parser.add_argument('--quick-and-dirty', action='store_true', help="use cache even if dependencies out of date " "(implies --incremental)") parser.add_argument('--cache-dir', action='store', metavar='DIR', help="store module cache info in the given folder in incremental mode " "(defaults to '{}')".format(defaults.CACHE_DIR)) parser.add_argument('--cache-fine-grained', action='store_true', help="include fine-grained dependency information in the cache") parser.add_argument('--skip-version-check', action='store_true', help="allow using cache written by older mypy version") add_invertible_flag('--strict-optional', default=False, strict_flag=True, help="enable experimental strict Optional checks") 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('--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', help="show traceback on fatal error") parser.add_argument('--stats', action='store_true', dest='dump_type_stats', help="dump stats") parser.add_argument('--inferstats', action='store_true', dest='dump_inference_stats', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', dest='custom_typing_module', help="use a custom typing module") parser.add_argument('--custom-typeshed-dir', metavar='DIR', help="use the custom typeshed in DIR") parser.add_argument('--scripts-are-modules', action='store_true', help="Script x becomes module x instead of __main__") parser.add_argument('--config-file', help="Configuration file, must have a [mypy] section " "(defaults to {})".format(defaults.CONFIG_FILE)) add_invertible_flag('--show-column-numbers', default=False, help="Show column numbers in error messages") parser.add_argument('--find-occurrences', metavar='CLASS.MEMBER', dest='special-opts:find_occurrences', help="print out all usages of a class member (experimental)") strict_help = "Strict mode. Enables the following flags: {}".format( ", ".join(strict_flag_names)) parser.add_argument('--strict', action='store_true', dest='special-opts:strict', help=strict_help) parser.add_argument('--shadow-file', nargs=2, metavar=('SOURCE_FILE', 'SHADOW_FILE'), dest='shadow_file', help='Typecheck SHADOW_FILE in place of SOURCE_FILE.') # hidden options # --debug-cache will disable any cache-related compressions/optimizations, # which will make the cache writing process output pretty-printed JSON (which # is easier to debug). parser.add_argument('--debug-cache', action='store_true', help=argparse.SUPPRESS) # --dump-deps will dump all fine-grained dependencies to stdout parser.add_argument('--dump-deps', action='store_true', help=argparse.SUPPRESS) # --dump-graph will dump the contents of the graph of SCCs and exit. parser.add_argument('--dump-graph', action='store_true', help=argparse.SUPPRESS) # --semantic-analysis-only does exactly that. parser.add_argument('--semantic-analysis-only', action='store_true', help=argparse.SUPPRESS) # --local-partial-types disallows partial types spanning module top level and a function # (implicitly defined in fine-grained incremental mode) parser.add_argument('--local-partial-types', action='store_true', help=argparse.SUPPRESS) # deprecated options parser.add_argument('--disallow-any', dest='special-opts:disallow_any', help=argparse.SUPPRESS) add_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) parser.add_argument('--use-python-path', action='store_true', dest='special-opts:use_python_path', help=argparse.SUPPRESS) parser.add_argument('-s', '--silent-imports', action='store_true', dest='special-opts:silent_imports', help=argparse.SUPPRESS) parser.add_argument('--almost-silent', action='store_true', dest='special-opts:almost_silent', help=argparse.SUPPRESS) parser.add_argument('--fast-parser', action='store_true', dest='special-opts:fast_parser', help=argparse.SUPPRESS) parser.add_argument('--no-fast-parser', action='store_true', dest='special-opts:no_fast_parser', help=argparse.SUPPRESS) if server_options: # TODO: This flag is superfluous; remove after a short transition (2018-03-16) parser.add_argument('--experimental', action='store_true', dest='fine_grained_incremental', help="enable fine-grained incremental mode") parser.add_argument('--use-fine-grained-cache', action='store_true', help="use the cache in fine-grained incremental mode") report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') for report_type in sorted(reporter_classes): report_group.add_argument('--%s-report' % report_type.replace('_', '-'), metavar='DIR', dest='special-opts:%s_report' % report_type) code_group = parser.add_argument_group(title='How to specify the code to type check') code_group.add_argument('-m', '--module', action='append', metavar='MODULE', default=[], dest='special-opts:modules', help="type-check module; can repeat for more modules") code_group.add_argument('-p', '--package', action='append', metavar='PACKAGE', default=[], dest='special-opts:packages', help="type-check package recursively; can be repeated") code_group.add_argument('-c', '--command', action='append', metavar='PROGRAM_TEXT', dest='special-opts:command', help="type-check program passed in as string") code_group.add_argument(metavar='files', nargs='*', dest='special-opts:files', help="type-check given files or directories") # Parse arguments once into a dummy namespace so we can get the # filename for the config file and know if the user requested all strict options. dummy = argparse.Namespace() parser.parse_args(args, dummy) config_file = dummy.config_file if config_file is not None and not os.path.exists(config_file): parser.error("Cannot find config file '%s'" % config_file) # Parse config file first, so command line can override. options = Options() parse_config_file(options, config_file) # Set strict flags before parsing (if strict mode enabled), so other command # line options can override. if getattr(dummy, 'special-opts:strict'): for dest, value in strict_flag_assignments: setattr(options, dest, value) # Parse command line for real, using a split namespace. special_opts = argparse.Namespace() parser.parse_args(args, SplitNamespace(options, special_opts, 'special-opts:')) # --use-python-path is no longer supported; explain why. if special_opts.use_python_path: parser.error("Sorry, --use-python-path is no longer supported.\n" "If you are trying this because your code depends on a library module,\n" "you should really investigate how to obtain stubs for that module.\n" "See https://github.com/python/mypy/issues/1411 for more discussion." ) # Process deprecated options if special_opts.disallow_any: print("--disallow-any option was split up into multiple flags. " "See http://mypy.readthedocs.io/en/latest/command_line.html#disallow-any-flags") 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) if options.follow_imports == 'normal': options.follow_imports = 'errors' elif special_opts.silent_imports: print("Warning: --silent-imports has been replaced by " "--ignore-missing-imports --follow-imports=skip", file=sys.stderr) options.ignore_missing_imports = True if options.follow_imports == 'normal': options.follow_imports = 'skip' if special_opts.dirty_stubs: print("Warning: -f/--dirty-stubs is deprecated and no longer necessary. Mypy no longer " "checks the git status of stubs.", file=sys.stderr) if special_opts.fast_parser: print("Warning: --fast-parser is now the default (and only) parser.") if special_opts.no_fast_parser: print("Warning: --no-fast-parser no longer has any effect. The fast parser " "is now mypy's default and only parser.") # Check for invalid argument combinations. if require_targets: code_methods = sum(bool(c) for c in [special_opts.modules + special_opts.packages, special_opts.command, special_opts.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error("May only specify one of: module/package, files, or command.") # Set build flags. if options.strict_optional_whitelist is not None: # TODO: Deprecate, then kill this flag options.strict_optional = True if special_opts.find_occurrences: experiments.find_occurrences = special_opts.find_occurrences.split('.') assert experiments.find_occurrences is not None if len(experiments.find_occurrences) < 2: parser.error("Can only find occurrences of class members.") if len(experiments.find_occurrences) != 2: parser.error("Can only find occurrences of non-nested class members.") # Set reports. for flag, val in vars(special_opts).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Let quick_and_dirty imply incremental. if options.quick_and_dirty: options.incremental = True # Set target. if special_opts.modules + special_opts.packages: options.build_type = BuildType.MODULE lib_path = [os.getcwd()] + build.mypy_path() targets = [] # TODO: use the same cache as the BuildManager will cache = build.FindModuleCache() for p in special_opts.packages: if os.sep in p or os.altsep and os.altsep in p: fail("Package name '{}' cannot have a slash in it.".format(p)) p_targets = cache.find_modules_recursive(p, lib_path) if not p_targets: fail("Can't find package '{}'".format(p)) targets.extend(p_targets) for m in special_opts.modules: targets.append(BuildSource(None, m, None)) return targets, options elif special_opts.command: options.build_type = BuildType.PROGRAM_TEXT targets = [BuildSource(None, None, '\n'.join(special_opts.command))] return targets, options else: try: targets = create_source_list(special_opts.files, options) except InvalidSourceList as e: fail(str(e)) return targets, options
def process_options() -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # Make the help output a little less jarring. help_factory = (lambda prog: argparse.RawDescriptionHelpFormatter( prog=prog, max_help_position=28)) parser = argparse.ArgumentParser(prog='mypy', epilog=FOOTER, formatter_class=help_factory) def parse_version(v): m = re.match(r'\A(\d)\.(\d+)\Z', v) if m: return int(m.group(1)), int(m.group(2)) else: raise argparse.ArgumentTypeError( "Invalid python version '{}' (expected format: 'x.y')".format( v)) parser.add_argument('-v', '--verbose', action='count', help="more verbose messages") parser.add_argument( '-V', '--version', action='version', # type: ignore # see typeshed#124 version='%(prog)s ' + __version__) parser.add_argument('--python-version', type=parse_version, metavar='x.y', help='use Python x.y') parser.add_argument('--py2', dest='python_version', action='store_const', const=defaults.PYTHON2_VERSION, help="use Python 2 mode") parser.add_argument('-s', '--silent-imports', action='store_true', help="don't follow imports to .py files") parser.add_argument('--silent', action='store_true', help="deprecated name for --silent-imports") parser.add_argument( '--almost-silent', action='store_true', help="like --silent-imports but reports the imports as errors") parser.add_argument( '--disallow-untyped-calls', action='store_true', help="disallow calling functions without type annotations" " from functions with type annotations") parser.add_argument( '--disallow-untyped-defs', action='store_true', help="disallow defining functions without type annotations" " or with incomplete type annotations") parser.add_argument( '--check-untyped-defs', action='store_true', help="type check the interior of functions without type annotations") parser.add_argument('--fast-parser', action='store_true', help="enable experimental fast parser") parser.add_argument('-i', '--incremental', action='store_true', help="enable experimental module cache") parser.add_argument('-f', '--dirty-stubs', action='store_true', help="don't warn if typeshed is out of sync") parser.add_argument('--pdb', action='store_true', help="invoke pdb on fatal error") parser.add_argument( '--use-python-path', action='store_true', help="search for modules in sys.path of running Python") parser.add_argument('--stats', action='store_true', help="dump stats") parser.add_argument('--inferstats', action='store_true', help="dump type inference stats") parser.add_argument('--custom-typing', metavar='MODULE', help="use a custom typing module") report_group = parser.add_argument_group( title='report generation', description='Generate a report in the specified format.') report_group.add_argument('--html-report', metavar='DIR') report_group.add_argument('--old-html-report', metavar='DIR') report_group.add_argument('--xslt-html-report', metavar='DIR') report_group.add_argument('--xml-report', metavar='DIR') report_group.add_argument('--txt-report', metavar='DIR') report_group.add_argument('--xslt-txt-report', metavar='DIR') report_group.add_argument('--linecount-report', metavar='DIR') code_group = parser.add_argument_group( title='How to specify the code to type check') code_group.add_argument( '-m', '--module', action='append', dest='modules', help="type-check module; can repeat for more modules") code_group.add_argument('-c', '--command', help="type-check program passed in as string") code_group.add_argument('-p', '--package', help="type-check all files in a directory") code_group.add_argument('files', nargs='*', help="type-check given files or directories") args = parser.parse_args() # Check for invalid argument combinations. code_methods = sum( bool(c) for c in [args.modules, args.command, args.package, args.files]) if code_methods == 0: parser.error("Missing target module, package, files, or command.") elif code_methods > 1: parser.error( "May only specify one of: module, package, files, or command.") if args.use_python_path and args.python_version and args.python_version[ 0] == 2: parser.error( 'Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') if args.fast_parser and args.python_version and args.python_version[0] == 2: parser.error( 'The experimental fast parser is only compatible with Python 3, ' 'but Python 2 specified.') # Set options. options = Options() options.dirty_stubs = args.dirty_stubs options.python_path = args.use_python_path options.pdb = args.pdb options.custom_typing_module = args.custom_typing # Set build flags. if args.python_version is not None: options.pyversion = args.python_version if args.verbose: options.build_flags.extend(args.verbose * [build.VERBOSE]) if args.stats: options.build_flags.append(build.DUMP_TYPE_STATS) if args.inferstats: options.build_flags.append(build.DUMP_INFER_STATS) if args.silent_imports or args.silent: options.build_flags.append(build.SILENT_IMPORTS) if args.almost_silent: options.build_flags.append(build.SILENT_IMPORTS) options.build_flags.append(build.ALMOST_SILENT) if args.disallow_untyped_calls: options.build_flags.append(build.DISALLOW_UNTYPED_CALLS) if args.disallow_untyped_defs: options.build_flags.append(build.DISALLOW_UNTYPED_DEFS) if args.check_untyped_defs: options.build_flags.append(build.CHECK_UNTYPED_DEFS) # experimental if args.fast_parser: options.build_flags.append(build.FAST_PARSER) if args.incremental: options.build_flags.append(build.INCREMENTAL) # Set reports. for flag, val in vars(args).items(): if flag.endswith('_report') and val is not None: report_type = flag[:-7].replace('_', '-') report_dir = val options.report_dirs[report_type] = report_dir # Set target. if args.modules: options.build_flags.append(build.MODULE) targets = [BuildSource(None, m, None) for m in args.modules] return targets, options elif args.package: options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args.package, lib_path) if not targets: fail("Can't find package '{}'".format(args.package)) return targets, options elif args.command: options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args.command)], options else: targets = [] for f in args.files: if f.endswith(PY_EXTENSIONS): targets.append(BuildSource(f, crawl_up(f)[1], None)) elif os.path.isdir(f): targets.extend(expand_dir(f)) else: targets.append(BuildSource(f, None, None)) return targets, options
def process_options(args: List[str]) -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # TODO: Rewrite using argparse. options = Options() help = False ver = False while args and args[0].startswith('-'): if args[0] in ('--verbose', '-v'): options.build_flags.append(build.VERBOSE) args = args[1:] elif args[0] == '--py2': # Use Python 2 mode. options.pyversion = defaults.PYTHON2_VERSION args = args[1:] elif args[0] == '--python-version': version_components = args[1].split(".")[0:2] if len(version_components) != 2: fail("Invalid python version {} (expected format: 'x.y')".format( repr(args[1]))) if not all(item.isdigit() for item in version_components): fail("Found non-digit in python version: {}".format( args[1])) options.pyversion = (int(version_components[0]), int(version_components[1])) args = args[2:] elif args[0] == '-f' or args[0] == '--dirty-stubs': options.dirty_stubs = True args = args[1:] elif args[0] == '-m' and args[1:]: if args[2:]: fail("No extra argument should appear after '-m mod'") options.build_flags.append(build.MODULE) return [BuildSource(None, args[1], None)], options elif args[0] == '--package' and args[1:]: if args[2:]: fail("No extra argument should appear after '--package dir'") options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args[1], lib_path) if not targets: fail("Can't find package '{}'".format(args[1])) return targets, options elif args[0] == '-c' and args[1:]: if args[2:]: fail("No extra argument should appear after '-c string'") options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args[1])], options elif args[0] in ('-h', '--help'): help = True args = args[1:] elif args[0] == '--stats': options.build_flags.append(build.DUMP_TYPE_STATS) args = args[1:] elif args[0] == '--inferstats': options.build_flags.append(build.DUMP_INFER_STATS) args = args[1:] elif args[0] == '--custom-typing' and args[1:]: options.custom_typing_module = args[1] args = args[2:] elif is_report(args[0]) and args[1:]: report_type = args[0][2:-7] report_dir = args[1] options.report_dirs[report_type] = report_dir args = args[2:] elif args[0] == '--use-python-path': options.python_path = True args = args[1:] elif args[0] in ('--silent-imports', '--silent', '-s'): options.build_flags.append(build.SILENT_IMPORTS) args = args[1:] elif args[0] == '--pdb': options.pdb = True args = args[1:] elif args[0] == '--implicit-any': options.implicit_any = True args = args[1:] elif args[0] == '--fast-parser': options.build_flags.append(build.FAST_PARSER) args = args[1:] elif args[0] == '--disallow-untyped-calls': options.build_flags.append(build.DISALLOW_UNTYPED_CALLS) args = args[1:] elif args[0] in ('--version', '-V'): ver = True args = args[1:] else: usage('Unknown option: {}'.format(args[0])) if help: usage() if ver: version() if not args: usage('Missing target file or module') if options.python_path and options.pyversion[0] == 2: usage('Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') if build.FAST_PARSER in options.build_flags and options.pyversion[0] == 2: usage('The experimental fast parser is only compatible with Python 3, ' 'but Python 2 specified.') targets = [] for arg in args: if arg.endswith(PY_EXTENSIONS): targets.append(BuildSource(arg, crawl_up(arg)[1], None)) elif os.path.isdir(arg): targets.extend(expand_dir(arg)) else: targets.append(BuildSource(arg, None, None)) return targets, options
def process_options(args: List[str]) -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # TODO: Rewrite using argparse. options = Options() help = False ver = False while args and args[0].startswith('-'): if args[0] in ('--verbose', '-v'): options.build_flags.append(build.VERBOSE) args = args[1:] elif args[0] == '--py2': # Use Python 2 mode. options.pyversion = defaults.PYTHON2_VERSION args = args[1:] elif args[0] == '--python-version': version_components = args[1].split(".")[0:2] if len(version_components) != 2: fail("Invalid python version {} (expected format: 'x.y')". format(repr(args[1]))) if not all(item.isdigit() for item in version_components): fail("Found non-digit in python version: {}".format(args[1])) options.pyversion = (int(version_components[0]), int(version_components[1])) args = args[2:] elif args[0] == '-f' or args[0] == '--dirty-stubs': options.dirty_stubs = True args = args[1:] elif args[0] == '-m' and args[1:]: if args[2:]: fail("No extra argument should appear after '-m mod'") options.build_flags.append(build.MODULE) return [BuildSource(None, args[1], None)], options elif args[0] == '--package' and args[1:]: if args[2:]: fail("No extra argument should appear after '--package dir'") options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args[1], lib_path) if not targets: fail("Can't find package '{}'".format(args[1])) return targets, options elif args[0] == '-c' and args[1:]: if args[2:]: fail("No extra argument should appear after '-c string'") options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args[1])], options elif args[0] in ('-h', '--help'): help = True args = args[1:] elif args[0] == '--stats': options.build_flags.append(build.DUMP_TYPE_STATS) args = args[1:] elif args[0] == '--inferstats': options.build_flags.append(build.DUMP_INFER_STATS) args = args[1:] elif args[0] == '--custom-typing' and args[1:]: options.custom_typing_module = args[1] args = args[2:] elif is_report(args[0]) and args[1:]: report_type = args[0][2:-7] report_dir = args[1] options.report_dirs[report_type] = report_dir args = args[2:] elif args[0] == '--use-python-path': options.python_path = True args = args[1:] elif args[0] in ('--silent-imports', '--silent', '-s'): options.build_flags.append(build.SILENT_IMPORTS) args = args[1:] elif args[0] == '--pdb': options.pdb = True args = args[1:] elif args[0] == '--implicit-any': options.implicit_any = True args = args[1:] elif args[0] == '--fast-parser': options.build_flags.append(build.FAST_PARSER) args = args[1:] elif args[0] == '--disallow-untyped-calls': options.build_flags.append(build.DISALLOW_UNTYPED_CALLS) args = args[1:] elif args[0] in ('--version', '-V'): ver = True args = args[1:] else: usage('Unknown option: {}'.format(args[0])) if help: usage() if ver: version() if not args: usage('Missing target file or module') if options.python_path and options.pyversion[0] == 2: usage('Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') if build.FAST_PARSER in options.build_flags and options.pyversion[0] == 2: usage('The experimental fast parser is only compatible with Python 3, ' 'but Python 2 specified.') targets = [] for arg in args: if arg.endswith(PY_EXTENSIONS): targets.append(BuildSource(arg, crawl_up(arg)[1], None)) elif os.path.isdir(arg): targets.extend(expand_dir(arg)) else: targets.append(BuildSource(arg, None, None)) return targets, options
def process_options(args: List[str]) -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ options = Options() help = False ver = False while args and args[0].startswith('-'): if args[0] == '--verbose': options.build_flags.append(build.VERBOSE) args = args[1:] elif args[0] == '--py2': # Use Python 2 mode. options.pyversion = defaults.PYTHON2_VERSION args = args[1:] elif args[0] == '--python-version': version_components = args[1].split(".")[0:2] if len(version_components) != 2: fail("Invalid python version {} (expected format: 'x.y')". format(repr(args[1]))) if not all(item.isdigit() for item in version_components): fail("Found non-digit in python version: {}".format(args[1])) options.pyversion = (int(version_components[0]), int(version_components[1])) args = args[2:] elif args[0] == '-f' or args[0] == '--dirty-stubs': options.dirty_stubs = True args = args[1:] elif args[0] == '-m' and args[1:]: options.build_flags.append(build.MODULE) return [BuildSource(None, args[1], None)], options elif args[0] == '--package' and args[1:]: options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args[1], lib_path) if not targets: fail("Can't find package '{}'".format(args[1])) return targets, options elif args[0] == '-c' and args[1:]: options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args[1])], options elif args[0] in ('-h', '--help'): help = True args = args[1:] elif args[0] == '--stats': options.build_flags.append(build.DUMP_TYPE_STATS) args = args[1:] elif args[0] == '--inferstats': options.build_flags.append(build.DUMP_INFER_STATS) args = args[1:] elif args[0] == '--custom-typing' and args[1:]: options.custom_typing_module = args[1] args = args[2:] elif is_report(args[0]) and args[1:]: report_type = args[0][2:-7] report_dir = args[1] options.report_dirs[report_type] = report_dir args = args[2:] elif args[0] == '--use-python-path': options.python_path = True args = args[1:] elif args[0] == '--version': ver = True args = args[1:] else: usage('Unknown option: {}'.format(args[0])) if help: usage() if ver: version() if not args: usage('Missing target file or module') if args[1:]: usage('Extra argument: {}'.format(args[1])) if options.python_path and options.pyversion[0] == 2: usage('Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') return [BuildSource(args[0], None, None)], options
def process_options(args: List[str]) -> Tuple[List[BuildSource], Options]: """Process command line arguments. Return (mypy program path (or None), module to run as script (or None), parsed flags) """ # TODO: Rewrite using argparse. options = Options() help = False ver = False while args and args[0].startswith("-"): if args[0] == "--verbose": options.build_flags.append(build.VERBOSE) args = args[1:] elif args[0] == "--py2": # Use Python 2 mode. options.pyversion = defaults.PYTHON2_VERSION args = args[1:] elif args[0] == "--python-version": version_components = args[1].split(".")[0:2] if len(version_components) != 2: fail("Invalid python version {} (expected format: 'x.y')".format(repr(args[1]))) if not all(item.isdigit() for item in version_components): fail("Found non-digit in python version: {}".format(args[1])) options.pyversion = (int(version_components[0]), int(version_components[1])) args = args[2:] elif args[0] == "-f" or args[0] == "--dirty-stubs": options.dirty_stubs = True args = args[1:] elif args[0] == "-m" and args[1:]: options.build_flags.append(build.MODULE) return [BuildSource(None, args[1], None)], options elif args[0] == "--package" and args[1:]: options.build_flags.append(build.MODULE) lib_path = [os.getcwd()] + build.mypy_path() targets = build.find_modules_recursive(args[1], lib_path) if not targets: fail("Can't find package '{}'".format(args[1])) return targets, options elif args[0] == "-c" and args[1:]: options.build_flags.append(build.PROGRAM_TEXT) return [BuildSource(None, None, args[1])], options elif args[0] in ("-h", "--help"): help = True args = args[1:] elif args[0] == "--stats": options.build_flags.append(build.DUMP_TYPE_STATS) args = args[1:] elif args[0] == "--inferstats": options.build_flags.append(build.DUMP_INFER_STATS) args = args[1:] elif args[0] == "--custom-typing" and args[1:]: options.custom_typing_module = args[1] args = args[2:] elif is_report(args[0]) and args[1:]: report_type = args[0][2:-7] report_dir = args[1] options.report_dirs[report_type] = report_dir args = args[2:] elif args[0] == "--use-python-path": options.python_path = True args = args[1:] elif args[0] in ("--silent-imports", "--silent"): options.build_flags.append(build.SILENT_IMPORTS) args = args[1:] elif args[0] == "--pdb": options.pdb = True args = args[1:] elif args[0] == "--version": ver = True args = args[1:] else: usage("Unknown option: {}".format(args[0])) if help: usage() if ver: version() if not args: usage("Missing target file or module") if options.python_path and options.pyversion[0] == 2: usage("Python version 2 (or --py2) specified, " "but --use-python-path will search in sys.path of Python 3") targets = [] for arg in args: if arg.endswith(PY_EXTENSIONS): targets.append(BuildSource(arg, crawl_up(arg)[1], None)) elif os.path.isdir(arg): targets.extend(expand_dir(arg)) else: targets.append(BuildSource(arg, None, None)) return targets, options