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()
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)
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)
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()
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)
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)
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()
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)
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()
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")
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()
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()
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))
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()
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()
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))
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))
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))