Ejemplo n.º 1
0
def start_server(args: argparse.Namespace) -> None:
    """Start the server from command arguments and wait for it."""
    # Lazy import so this import doesn't slow down other commands.
    from mypy.dmypy_server import daemonize, Server
    if daemonize(Server(args.flags).serve, args.log_file) != 0:
        sys.exit(1)
    wait_for_server()
Ejemplo n.º 2
0
 def maybe_suggest(self, step: int, server: Server, src: str,
                   tmp_dir: str) -> List[str]:
     output: List[str] = []
     targets = self.get_suggest(src, step)
     for flags, target in targets:
         json = '--json' in flags
         callsites = '--callsites' in flags
         no_any = '--no-any' in flags
         no_errors = '--no-errors' in flags
         try_text = '--try-text' in flags
         m = re.match('--flex-any=([0-9.]+)', flags)
         flex_any = float(m.group(1)) if m else None
         m = re.match(r'--use-fixme=(\w+)', flags)
         use_fixme = m.group(1) if m else None
         m = re.match('--max-guesses=([0-9]+)', flags)
         max_guesses = int(m.group(1)) if m else None
         res = cast(
             Dict[str, Any],
             server.cmd_suggest(target.strip(),
                                json=json,
                                no_any=no_any,
                                no_errors=no_errors,
                                try_text=try_text,
                                flex_any=flex_any,
                                use_fixme=use_fixme,
                                callsites=callsites,
                                max_guesses=max_guesses))
         val = res['error'] if 'error' in res else res['out'] + res['err']
         if json:
             # JSON contains already escaped \ on Windows, so requires a bit of care.
             val = val.replace('\\\\', '\\')
             val = val.replace(os.path.realpath(tmp_dir) + os.path.sep, '')
         output.extend(val.strip().split('\n'))
     return normalize_messages(output)
Ejemplo n.º 3
0
def start_server_and_analyze(config, workspace, python_executable=None):
    if settings is None:
        log.error('Settings is None')
        return

    log.info(f'mypy version: {mypy_version}')
    log.info(f'mypyls version: {mypyls_version}')

    options = Options()
    options.check_untyped_defs = True
    options.follow_imports = 'error'
    options.use_fine_grained_cache = True
    options.python_executable = python_executable

    stderr_stream = StringIO()
    config_file = settings.get('configFile')
    if config_file == '':
        # Use empty string rather than null in vscode settings, so that it's shown in settings editor GUI.
        config_file = None
    log.info(f'Trying to read mypy config file from {config_file or "default locations"}')
    with redirect_stderr(stderr_stream):
        if mypy_version >= '0.770':
            def set_strict_flags():
                # The code to set all strict options using the 'strict' flag is in mypy.main.process_options,
                # and we cannot access it from here, so we disable `strict = True` in the config file for now.
                stderr_stream.write(
                    "Setting 'strict' in the configuration file is not supported by mypy-vscode for now. "
                    "The option will be ignored. You may set individual strict flags instead "
                    "(see 'mypy -h' for the list of flags enabled in strict mode).")
            parse_config_file(options, set_strict_flags, config_file)
        else:
            parse_config_file(options, config_file)

    stderr = stderr_stream.getvalue()
    if stderr:
        log.error(f'Error reading mypy config file:\n{stderr}')
        workspace.show_message(f'Error reading mypy config file:\n{stderr}')
    if options.config_file:
        log.info(f'Read mypy config from: {options.config_file}')
    else:
        log.info(f'Mypy configuration not read, using defaults.')
        if config_file:
            workspace.show_message(f'Mypy config file not found:\n{config_file}')

    options.show_column_numbers = True
    if options.follow_imports not in ('error', 'skip'):
        workspace.show_message(f"Cannot use follow_imports='{options.follow_imports}', using 'error' instead.")
        options.follow_imports = 'error'

    if mypy_version > '0.720':
        options.color_output = False
        options.error_summary = False
        options.pretty = False

    log.info(f'python_executable after applying config: {options.python_executable}')
    workspace.mypy_server = Server(options, DEFAULT_STATUS_FILE)

    mypy_check(workspace, config)
Ejemplo n.º 4
0
def start_server(args: argparse.Namespace, allow_sources: bool = False) -> None:
    """Start the server from command arguments and wait for it."""
    # Lazy import so this import doesn't slow down other commands.
    from mypy.dmypy_server import daemonize, Server, process_start_options
    if daemonize(Server(process_start_options(args.flags, allow_sources),
                        timeout=args.timeout).serve,
                 args.log_file) != 0:
        sys.exit(1)
    wait_for_server()
Ejemplo n.º 5
0
 def maybe_suggest(self, step: int, server: Server, src: str) -> List[str]:
     output = []  # type: List[str]
     targets = self.get_suggest(src, step)
     for flag, target in targets:
         json = flag.strip() == '--json'
         callsites = flag.strip() == '--callsites'
         res = cast(Dict[str, Any], server.cmd_suggest(target.strip(), json, callsites))
         val = res['error'] if 'error' in res else res['out'] + res['err']
         output.extend(val.strip().split('\n'))
     return normalize_messages(output)
Ejemplo n.º 6
0
def start_server_and_analyze(config, workspace, python_executable=None):
    if settings is None:
        log.error('Settings is None')
        return

    log.info(f'mypy version: {mypy_version}')
    log.info(f'mypyls version: {mypyls_version}')

    options = Options()
    options.check_untyped_defs = True
    options.follow_imports = 'error'
    options.use_fine_grained_cache = True
    options.python_executable = python_executable

    stderr_stream = StringIO()
    config_file = settings.get('configFile')
    if config_file == '':
        # Use empty string rather than null in vscode settings, so that it's shown in settings editor GUI.
        config_file = None
    log.info(
        f'Trying to read mypy config file from {config_file or "default locations"}'
    )
    with redirect_stderr(stderr_stream):
        parse_config_file(options, config_file)
    stderr = stderr_stream.getvalue()
    if stderr:
        log.error(f'Error reading mypy config file:\n{stderr}')
        workspace.show_message(f'Error reading mypy config file:\n{stderr}')
    if options.config_file:
        log.info(f'Read mypy config from: {options.config_file}')
    else:
        log.info(f'Mypy configuration not read, using defaults.')
        if config_file:
            workspace.show_message(
                f'Mypy config file not found:\n{config_file}')

    options.show_column_numbers = True
    if options.follow_imports not in ('error', 'skip'):
        workspace.show_message(
            f"Cannot use follow_imports='{options.follow_imports}', using 'error' instead."
        )
        options.follow_imports = 'error'

    if mypy_version > '0.720':
        options.color_output = False
        options.error_summary = False

    log.info(
        f'python_executable after applying config: {options.python_executable}'
    )
    workspace.mypy_server = Server(options, DEFAULT_STATUS_FILE)

    mypy_check(workspace, config)
Ejemplo n.º 7
0
def do_daemon(args: argparse.Namespace) -> None:
    """Serve requests in the foreground."""
    # Lazy import so this import doesn't slow down other commands.
    from mypy.dmypy_server import Server, process_start_options
    if args.options_data:
        from mypy.options import Options
        options_dict, timeout, log_file = pickle.loads(base64.b64decode(args.options_data))
        options_obj = Options()
        options = options_obj.apply_changes(options_dict)
        if log_file:
            sys.stdout = sys.stderr = open(log_file, 'a', buffering=1)
            fd = sys.stdout.fileno()
            os.dup2(fd, 2)
            os.dup2(fd, 1)
    else:
        options = process_start_options(args.flags, allow_sources=False)
        timeout = args.timeout
    Server(options, args.status_file, timeout=timeout).serve()
Ejemplo n.º 8
0
 def maybe_suggest(self, step: int, server: Server, src: str) -> List[str]:
     output = []  # type: List[str]
     targets = self.get_suggest(src, step)
     for flags, target in targets:
         json = '--json' in flags
         callsites = '--callsites' in flags
         no_any = '--no-any' in flags
         no_errors = '--no-errors' in flags
         try_text = '--try-text' in flags
         m = re.match('--flex-any=([0-9.]+)', flags)
         flex_any = float(m.group(1)) if m else None
         res = cast(Dict[str, Any],
                    server.cmd_suggest(
                        target.strip(), json=json, no_any=no_any, no_errors=no_errors,
                        try_text=try_text, flex_any=flex_any,
                        callsites=callsites))
         val = res['error'] if 'error' in res else res['out'] + res['err']
         output.extend(val.strip().split('\n'))
     return normalize_messages(output)
Ejemplo n.º 9
0
def do_restart(args: argparse.Namespace) -> None:
    """Restart daemon.

    We first try to stop it politely if it's running.  This also sets
    mypy flags (and has the same issues as start).
    """
    try:
        response = request('stop')
    except SystemExit:
        pass
    else:
        if response:
            sys.exit("Status: %s" % str(response))
        else:
            print("Daemon stopped")
    # Lazy import so this import doesn't slow down other commands.
    from mypy.dmypy_server import daemonize, Server
    if daemonize(Server(args.flags).serve, args.log_file):
        sys.exit(1)
    wait_for_server()
Ejemplo n.º 10
0
def do_start(args: argparse.Namespace) -> None:
    """Start daemon (it must not already be running).

    This is where mypy flags are set.  Setting flags is a bit awkward;
    you have to use e.g.:

      dmypy start -- --strict

    since we don't want to duplicate mypy's huge list of flags.
    """
    try:
        pid, sockname = get_status()
    except SystemExit as err:
        # Lazy import so this import doesn't slow down other commands.
        from mypy.dmypy_server import daemonize, Server
        if daemonize(Server(args.flags).serve, args.log_file):
            sys.exit(1)
        wait_for_server()
    else:
        sys.exit("Daemon is still alive")
Ejemplo n.º 11
0
 def run_check(self, server: Server,
               sources: List[BuildSource]) -> List[str]:
     response = server.check(sources, is_tty=False, terminal_width=-1)
     out = cast(str, response['out'] or response['err'])
     return out.splitlines()
Ejemplo n.º 12
0
def do_daemon(args: argparse.Namespace) -> None:
    """Serve requests in the foreground."""
    # Lazy import so this import doesn't slow down other commands.
    from mypy.dmypy_server import Server
    Server(args.flags).serve()
Ejemplo n.º 13
0
    def run_case(self, testcase: DataDrivenTestCase) -> None:
        if self.should_skip(testcase):
            pytest.skip()
            return

        main_src = '\n'.join(testcase.input)
        main_path = os.path.join(test_temp_dir, 'main')
        with open(main_path, 'w', encoding='utf8') as f:
            f.write(main_src)

        options = self.get_options(main_src, testcase, build_cache=False)
        build_options = self.get_options(main_src, testcase, build_cache=True)
        server = Server(options, DEFAULT_STATUS_FILE)

        num_regular_incremental_steps = self.get_build_steps(main_src)
        step = 1
        sources = self.parse_sources(main_src, step, options)
        if step <= num_regular_incremental_steps:
            messages = self.build(build_options, sources)
        else:
            messages = self.run_check(server, sources)

        a = []
        if messages:
            a.extend(normalize_messages(messages))

        assert testcase.tmpdir
        a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir.name))

        if server.fine_grained_manager:
            if CHECK_CONSISTENCY:
                check_consistency(server.fine_grained_manager)

        steps = testcase.find_steps()
        all_triggered = []

        for operations in steps:
            step += 1
            for op in operations:
                if isinstance(op, UpdateFile):
                    # Modify/create file
                    copy_and_fudge_mtime(op.source_path, op.target_path)
                else:
                    # Delete file
                    os.remove(op.path)
            sources = self.parse_sources(main_src, step, options)

            if step <= num_regular_incremental_steps:
                new_messages = self.build(build_options, sources)
            else:
                new_messages = self.run_check(server, sources)

            updated = []  # type: List[str]
            changed = []  # type: List[str]
            targets = []  # type: List[str]
            if server.fine_grained_manager:
                if CHECK_CONSISTENCY:
                    check_consistency(server.fine_grained_manager)
                all_triggered.append(server.fine_grained_manager.triggered)

                updated = server.fine_grained_manager.updated_modules
                changed = [mod for mod, file in server.fine_grained_manager.changed_modules]
                targets = server.fine_grained_manager.processed_targets

            expected_stale = testcase.expected_stale_modules.get(step - 1)
            if expected_stale is not None:
                assert_module_equivalence(
                    'stale' + str(step - 1),
                    expected_stale, changed)

            expected_rechecked = testcase.expected_rechecked_modules.get(step - 1)
            if expected_rechecked is not None:
                assert_module_equivalence(
                    'rechecked' + str(step - 1),
                    expected_rechecked, updated)

            expected = testcase.expected_fine_grained_targets.get(step)
            if expected:
                assert_target_equivalence(
                    'targets' + str(step),
                    expected, targets)

            new_messages = normalize_messages(new_messages)

            a.append('==')
            a.extend(new_messages)
            assert testcase.tmpdir
            a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir.name))

        # Normalize paths in test output (for Windows).
        a = [line.replace('\\', '/') for line in a]

        assert_string_arrays_equal(
            testcase.output, a,
            'Invalid output ({}, line {})'.format(
                testcase.file, testcase.line))

        if testcase.triggered:
            assert_string_arrays_equal(
                testcase.triggered,
                self.format_triggered(all_triggered),
                'Invalid active triggers ({}, line {})'.format(testcase.file,
                                                               testcase.line))
Ejemplo n.º 14
0
 def run_check(self, server: Server,
               sources: List[BuildSource]) -> List[str]:
     response = server.check(sources)
     out = cast(str, response['out'] or response['err'])
     return out.splitlines()
Ejemplo n.º 15
0
def do_daemon(args: argparse.Namespace) -> None:
    """Serve requests in the foreground."""
    # Lazy import so this import doesn't slow down other commands.
    from mypy.dmypy_server import Server, process_start_options
    Server(process_start_options(args.flags, allow_sources=False),
           timeout=args.timeout).serve()
Ejemplo n.º 16
0
    def run_case(self, testcase: DataDrivenTestCase) -> None:
        if self.should_skip(testcase):
            pytest.skip()
            return

        main_src = '\n'.join(testcase.input)
        main_path = os.path.join(test_temp_dir, 'main')
        with open(main_path, 'w', encoding='utf8') as f:
            f.write(main_src)

        options = self.get_options(main_src, testcase, build_cache=False)
        build_options = self.get_options(main_src, testcase, build_cache=True)
        server = Server(options, DEFAULT_STATUS_FILE)

        num_regular_incremental_steps = self.get_build_steps(main_src)
        step = 1
        sources = self.parse_sources(main_src, step, options)
        if step <= num_regular_incremental_steps:
            messages = self.build(build_options, sources)
        else:
            messages = self.run_check(server, sources)

        a = []
        if messages:
            a.extend(normalize_messages(messages))

        assert testcase.tmpdir
        a.extend(
            self.maybe_suggest(step, server, main_src, testcase.tmpdir.name))

        if server.fine_grained_manager:
            if CHECK_CONSISTENCY:
                check_consistency(server.fine_grained_manager)

        steps = testcase.find_steps()
        all_triggered = []

        for operations in steps:
            step += 1
            output, triggered = self.perform_step(
                operations,
                server,
                options,
                build_options,
                testcase,
                main_src,
                step,
                num_regular_incremental_steps,
            )
            a.append('==')
            a.extend(output)
            all_triggered.extend(triggered)

        # Normalize paths in test output (for Windows).
        a = [line.replace('\\', '/') for line in a]

        assert_string_arrays_equal(
            testcase.output, a,
            'Invalid output ({}, line {})'.format(testcase.file,
                                                  testcase.line))

        if testcase.triggered:
            assert_string_arrays_equal(
                testcase.triggered, self.format_triggered(all_triggered),
                'Invalid active triggers ({}, line {})'.format(
                    testcase.file, testcase.line))
Ejemplo n.º 17
0
 def run_check(self, server: Server, sources: List[BuildSource]) -> List[str]:
     response = server.check(sources)
     out = cast(str, response['out'] or response['err'])
     return out.splitlines()
Ejemplo n.º 18
0
    def run_case(self, testcase: DataDrivenTestCase) -> None:
        if self.should_skip(testcase):
            pytest.skip()
            return

        main_src = '\n'.join(testcase.input)
        main_path = os.path.join(test_temp_dir, 'main')
        with open(main_path, 'w') as f:
            f.write(main_src)

        options = self.get_options(main_src, testcase, build_cache=False)
        for name, _ in testcase.files:
            if 'mypy.ini' in name:
                config = name  # type: Optional[str]
                break
        else:
            config = None
        if config:
            parse_config_file(options, config)
        server = Server(options, alt_lib_path=test_temp_dir)

        step = 1
        sources = self.parse_sources(main_src, step, options)
        if self.use_cache:
            build_options = self.get_options(main_src,
                                             testcase,
                                             build_cache=True)
            if config:
                parse_config_file(build_options, config)
            messages = self.build(build_options, sources)
        else:
            messages = self.run_check(server, sources)

        a = []
        if messages:
            a.extend(normalize_messages(messages))

        if server.fine_grained_manager:
            if CHECK_CONSISTENCY:
                check_consistency(server.fine_grained_manager)

        steps = testcase.find_steps()
        all_triggered = []

        for operations in steps:
            step += 1
            for op in operations:
                if isinstance(op, UpdateFile):
                    # Modify/create file
                    copy_and_fudge_mtime(op.source_path, op.target_path)
                else:
                    # Delete file
                    os.remove(op.path)
            sources = self.parse_sources(main_src, step, options)
            new_messages = self.run_check(server, sources)

            updated = []  # type: List[str]
            changed = []  # type: List[str]
            if server.fine_grained_manager:
                if CHECK_CONSISTENCY:
                    check_consistency(server.fine_grained_manager)
                all_triggered.append(server.fine_grained_manager.triggered)

                updated = server.fine_grained_manager.updated_modules
                changed = [
                    mod for mod, file in
                    server.fine_grained_manager.changed_modules
                ]

            assert_module_equivalence(
                'stale' + str(step - 1),
                testcase.expected_stale_modules.get(step - 1), changed)
            assert_module_equivalence(
                'rechecked' + str(step - 1),
                testcase.expected_rechecked_modules.get(step - 1), updated)

            new_messages = normalize_messages(new_messages)

            a.append('==')
            a.extend(new_messages)

        # Normalize paths in test output (for Windows).
        a = [line.replace('\\', '/') for line in a]

        assert_string_arrays_equal(
            testcase.output, a,
            'Invalid output ({}, line {})'.format(testcase.file,
                                                  testcase.line))

        if testcase.triggered:
            assert_string_arrays_equal(
                testcase.triggered, self.format_triggered(all_triggered),
                'Invalid active triggers ({}, line {})'.format(
                    testcase.file, testcase.line))
Ejemplo n.º 19
0
    def run_case(self, testcase: DataDrivenTestCase) -> None:
        if self.should_skip(testcase):
            pytest.skip()
            return

        main_src = '\n'.join(testcase.input)
        main_path = os.path.join(test_temp_dir, 'main')
        with open(main_path, 'w') as f:
            f.write(main_src)

        server = Server(self.get_options(main_src, testcase,
                                         build_cache=False),
                        alt_lib_path=test_temp_dir)

        step = 1
        sources = self.parse_sources(main_src, step)
        if self.use_cache:
            messages = self.build(
                self.get_options(main_src, testcase, build_cache=True),
                sources)
        else:
            messages = self.run_check(server, sources)

        a = []
        if messages:
            a.extend(normalize_messages(messages))

        if server.fine_grained_manager:
            if CHECK_CONSISTENCY:
                check_consistency(server.fine_grained_manager)

        steps = testcase.find_steps()
        all_triggered = []
        for operations in steps:
            step += 1
            for op in operations:
                if isinstance(op, UpdateFile):
                    # Modify/create file
                    copy_and_fudge_mtime(op.source_path, op.target_path)
                else:
                    # Delete file
                    os.remove(op.path)
            sources = self.parse_sources(main_src, step)
            new_messages = self.run_check(server, sources)

            if server.fine_grained_manager:
                if CHECK_CONSISTENCY:
                    check_consistency(server.fine_grained_manager)
                all_triggered.append(server.fine_grained_manager.triggered)
            new_messages = normalize_messages(new_messages)

            a.append('==')
            a.extend(new_messages)

        # Normalize paths in test output (for Windows).
        a = [line.replace('\\', '/') for line in a]

        assert_string_arrays_equal(
            testcase.output, a,
            'Invalid output ({}, line {})'.format(testcase.file,
                                                  testcase.line))

        if testcase.triggered:
            assert_string_arrays_equal(
                testcase.triggered, self.format_triggered(all_triggered),
                'Invalid active triggers ({}, line {})'.format(
                    testcase.file, testcase.line))