def test_get_exclude_file_patterns_from_yapfignore_with_wrong_syntax(self): local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] with open(local_ignore_file, 'w') as f: f.writelines('\n'.join(ignore_patterns)) with self.assertRaises(errors.YapfError): file_resources.GetExcludePatternsForDir(self.test_tmpdir)
def test_get_exclude_file_patterns(self): local_ignore_file = os.path.join(self.test_tmpdir, '.yapfignore') ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: f.writelines('\n'.join(ignore_patterns)) self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), sorted(ignore_patterns))
def test_get_exclude_file_patterns_from_pyproject_no_ignore_section(self): try: import toml except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = [] open(local_ignore_file, 'w').close() self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), sorted(ignore_patterns))
def test_get_exclude_file_patterns_from_pyproject_ignore_section_empty( self): try: import toml except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = [] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), sorted(ignore_patterns))
def test_get_exclude_file_patterns_from_pyproject_with_wrong_syntax(self): try: import toml except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = ['temp/**/*.py', './wrong/syntax/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') f.writelines('\n,'.join([f'"{p}"' for p in ignore_patterns])) f.write(']') with self.assertRaises(errors.YapfError): file_resources.GetExcludePatternsForDir(self.test_tmpdir)
def test_get_exclude_file_patterns_from_pyproject(self): try: import toml except ImportError: return local_ignore_file = os.path.join(self.test_tmpdir, 'pyproject.toml') ignore_patterns = ['temp/**/*.py', 'temp2/*.py'] with open(local_ignore_file, 'w') as f: f.write('[tool.yapfignore]\n') f.write('ignore_patterns=[') f.writelines('\n,'.join([f'"{p}"' for p in ignore_patterns])) f.write(']') self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), sorted(ignore_patterns))
def main(argv): """Main program. Arguments: argv: command-line arguments, such as sys.argv (including the program name in argv[0]). Returns: Zero on successful program termination, non-zero otherwise. With --diff: zero if there were no changes, non-zero otherwise. Raises: YapfError: if none of the supplied files were Python files. """ args = _ParseArguments(argv) if args.version: print('yapf {}'.format(__version__)) return 0 style_config = args.style if args.style_help: print_help(args) return 0 if args.lines and len(args.files) > 1: parser.error('cannot use -l/--lines with more than one file') lines = _GetLines(args.lines) if args.lines is not None else None if not args.files: # No arguments specified. Read code from stdin. if args.in_place or args.diff: parser.error('cannot use --in-place or --diff flags when reading ' 'from stdin') original_source = [] while True: if sys.stdin.closed: break try: # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the # user will need to hit 'Ctrl-D' more than once if they're inputting # the program by hand. 'raw_input' throws an EOFError exception if # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop. original_source.append(py3compat.raw_input()) except EOFError: break except KeyboardInterrupt: return 1 if style_config is None and not args.no_local_style: style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) source = [line.rstrip() for line in original_source] source[0] = py3compat.removeBOM(source[0]) try: reformatted_source, _ = yapf_api.FormatCode( py3compat.unicode('\n'.join(source) + '\n'), filename='<stdin>', style_config=style_config, lines=lines, verify=args.verify) except tokenize.TokenError as e: raise errors.YapfError('%s:%s' % (e.args[1][0], e.args[0])) file_resources.WriteReformattedCode('<stdout>', reformatted_source) return 0 # Get additional exclude patterns from ignorefile exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( os.getcwd()) files = file_resources.GetCommandLineFiles( args.files, args.recursive, (args.exclude or []) + exclude_patterns_from_ignore_file) if not files: raise errors.YapfError( 'Input filenames did not match any python files') changed = FormatFiles(files, lines, style_config=args.style, no_local_style=args.no_local_style, in_place=args.in_place, print_diff=args.diff, verify=args.verify, parallel=args.parallel, quiet=args.quiet, verbose=args.verbose) return 1 if changed and (args.diff or args.quiet) else 0
def test_get_exclude_file_patterns_with_no_config_files(self): ignore_patterns = [] self.assertEqual( sorted(file_resources.GetExcludePatternsForDir(self.test_tmpdir)), sorted(ignore_patterns))
def main(argv): """Main program. Arguments: argv: command-line arguments, such as sys.argv (including the program name in argv[0]). Returns: Zero on successful program termination, non-zero otherwise. With --diff: zero if there were no changes, non-zero otherwise. Raises: YapfError: if none of the supplied files were Python files. """ parser = argparse.ArgumentParser(description='Formatter for Python code.') parser.add_argument( '-v', '--version', action='store_true', help='show version number and exit') diff_inplace_group = parser.add_mutually_exclusive_group() diff_inplace_group.add_argument( '-d', '--diff', action='store_true', help='print the diff for the fixed source') diff_inplace_group.add_argument( '-i', '--in-place', action='store_true', help='make changes to files in place') lines_recursive_group = parser.add_mutually_exclusive_group() lines_recursive_group.add_argument( '-r', '--recursive', action='store_true', help='run recursively over directories') lines_recursive_group.add_argument( '-l', '--lines', metavar='START-END', action='append', default=None, help='range of lines to reformat, one-based') parser.add_argument( '-e', '--exclude', metavar='PATTERN', action='append', default=None, help='patterns for files to exclude from formatting') parser.add_argument( '--style', action='store', help=('specify formatting style: either a style name (for example "pep8" ' 'or "google"), or the name of a file with style settings. The ' 'default is pep8 unless a %s or %s file located in the same ' 'directory as the source or one of its parent directories ' '(for stdin, the current directory is used).' % (style.LOCAL_STYLE, style.SETUP_CONFIG))) parser.add_argument( '--style-help', action='store_true', help=('show style settings and exit; this output can be ' 'saved to .style.yapf to make your settings ' 'permanent')) parser.add_argument( '--no-local-style', action='store_true', help="don't search for local style definition") parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS) parser.add_argument( '-p', '--parallel', action='store_true', help=('Run yapf in parallel when formatting multiple files. Requires ' 'concurrent.futures in Python 2.X')) parser.add_argument( '-vv', '--verbose', action='store_true', help='Print out file names while processing') parser.add_argument( 'files', nargs='*', help='Reads from stdin when no files are specified.') args = parser.parse_args(argv[1:]) if args.version: print('yapf {}'.format(__version__)) return 0 style_config = args.style if args.style_help: if style_config is None and not args.no_local_style: style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) style.SetGlobalStyle(style.CreateStyleFromConfig(style_config)) print('[style]') for option, docstring in sorted(style.Help().items()): for line in docstring.splitlines(): print('#', line and ' ' or '', line, sep='') option_value = style.Get(option) if isinstance(option_value, set) or isinstance(option_value, list): option_value = ', '.join(option_value) print(option.lower(), '=', option_value, sep='') print() return 0 if args.lines and len(args.files) > 1: parser.error('cannot use -l/--lines with more than one file') lines = _GetLines(args.lines) if args.lines is not None else None if not args.files: # No arguments specified. Read code from stdin. if args.in_place or args.diff: parser.error('cannot use --in-place or --diff flags when reading ' 'from stdin') original_source = [] while True: if sys.stdin.closed: break try: # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the # user will need to hit 'Ctrl-D' more than once if they're inputting # the program by hand. 'raw_input' throws an EOFError exception if # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop. original_source.append(py3compat.raw_input()) except EOFError: break except KeyboardInterrupt: return 1 if style_config is None and not args.no_local_style: style_config = file_resources.GetDefaultStyleForDir(os.getcwd()) source = [line.rstrip() for line in original_source] source[0] = py3compat.removeBOM(source[0]) reformatted_source, _ = yapf_api.FormatCode( py3compat.unicode('\n'.join(source) + '\n'), filename='<stdin>', style_config=style_config, lines=lines, verify=args.verify) file_resources.WriteReformattedCode('<stdout>', reformatted_source) return 0 # Get additional exclude patterns from ignorefile exclude_patterns_from_ignore_file = file_resources.GetExcludePatternsForDir( os.getcwd()) files = file_resources.GetCommandLineFiles( args.files, args.recursive, (args.exclude or []) + exclude_patterns_from_ignore_file) if not files: raise errors.YapfError('Input filenames did not match any python files') changed = FormatFiles( files, lines, style_config=args.style, no_local_style=args.no_local_style, in_place=args.in_place, print_diff=args.diff, verify=args.verify, parallel=args.parallel, verbose=args.verbose) return 1 if changed and args.diff else 0
def rpc_lsp_formatter_yapf(self, args: List[Any]) -> Any: buf_path: Optional[str] buf_root_dir: str default_config_path: str fmt_ranges: Optional[List[List[int]]] buf_lines: List[str] buf_path, buf_root_dir, default_config_path, fmt_ranges, buf_lines = args try: from yapf.yapflib.yapf_api import FormatCode from yapf.yapflib import file_resources from yapf.yapflib.errors import YapfError from lib2to3.pgen2.parse import ParseError as ParseError2to3 except ModuleNotFoundError as err: raise pynvim.ErrorResponse('yapf is not installed: {}'.format(err)) # The following code is essentially a reimplementation of # <https://github.com/google/yapf/blob/v0.31.0/yapf/__init__.py#L82-L114>. try: buf_dir = os.path.dirname( buf_path) if buf_path is not None else buf_root_dir config_path = default_config_path if buf_dir is not None: # This thing is actually not possible to pull off just through shelling # out to Yapf because it only has an option to override the config # globally and without any regard for project-local settings. config_path = file_resources.GetDefaultStyleForDir( buf_dir, default_config_path) if buf_root_dir is not None and buf_path is not None: # It should be mentioned that this function doesn't look for files in # parent directories, which is a shame. excluded_patterns = file_resources.GetExcludePatternsForDir( buf_root_dir) if buf_path.startswith(buf_root_dir): buf_path = buf_path[len(buf_root_dir):] if file_resources.IsIgnored(buf_path, excluded_patterns): return None # TODO: comment here about normalization of newlines by yapf and how a # string takes up less space than an array of them when encoded also how # Vim handles BOM buf_text = '\n'.join(buf_lines) + '\n' try: fmt_text, changed = FormatCode( buf_text, filename=buf_path if buf_path is not None else '<unknown>', style_config=config_path, lines=fmt_ranges, verify=False) except ParseError2to3 as err: # lineno, offset = err.context[1] # raise pynvim.ErrorResponse( # 'yapf: syntax error on {}:{}: {}'.format(lineno, offset, err.msg) # ) return None except SyntaxError as err: # raise pynvim.ErrorResponse( # 'yapf: syntax error on {}:{}: {}'.format(err.lineno, err.offset, err.msg) # ) return None if not changed: return None # TODO: write a continuation of that comment here as well fmt_lines = (fmt_text[:-1] if fmt_text.endswith('\n') else fmt_text).split('\n') changed, common_lines_from_start, common_lines_from_end = ( dotfiles.utils.simple_line_diff(buf_lines, fmt_lines)) if not changed: return None if common_lines_from_start > 0: fmt_lines = fmt_lines[common_lines_from_start:] if common_lines_from_end > 0: fmt_lines = fmt_lines[:-common_lines_from_end] return (common_lines_from_start, common_lines_from_end, fmt_lines) except YapfError as err: # <https://github.com/google/yapf/blob/5fda04e1cdf50f548e121173337e07cc5304b752/yapf/__init__.py#L363-L365> # raise pynvim.ErrorResponse('yapf: {}'.format(err)) return None