예제 #1
0
파일: main.py 프로젝트: tony/mypy
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
예제 #2
0
파일: main.py 프로젝트: jamesemmott/mypy
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
예제 #3
0
파일: main.py 프로젝트: gnprice/mypy
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
예제 #4
0
파일: main.py 프로젝트: lugnitdgp/avskr2.0
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
예제 #5
0
파일: main.py 프로젝트: rra/mypy
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
예제 #6
0
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
예제 #7
0
파일: main.py 프로젝트: JdeH/Transcrypt
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
예제 #8
0
파일: main.py 프로젝트: raph-amiard/mypy
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
예제 #9
0
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
예제 #10
0
파일: main.py 프로젝트: willywu/mypy
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
예제 #11
0
파일: main.py 프로젝트: jayvdb/mypy
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
예제 #12
0
파일: main.py 프로젝트: sixolet/mypy
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
예제 #13
0
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
예제 #14
0
파일: main.py 프로젝트: ivuk/mypy
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
예제 #15
0
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
예제 #16
0
파일: main.py 프로젝트: raph-amiard/mypy
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
예제 #17
0
파일: main.py 프로젝트: the-gigi/mypy
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