Buckets:
| # Copyright (C) 2009-2020 the sqlparse authors and contributors | |
| # <see AUTHORS file> | |
| # | |
| # This module is part of python-sqlparse and is released under | |
| # the BSD License: https://opensource.org/licenses/BSD-3-Clause | |
| """Module that contains the command line app. | |
| Why does this file exist, and why not put this in __main__? | |
| You might be tempted to import things from __main__ later, but that will | |
| cause problems: the code will get executed twice: | |
| - When you run `python -m sqlparse` python will execute | |
| ``__main__.py`` as a script. That means there won't be any | |
| ``sqlparse.__main__`` in ``sys.modules``. | |
| - When you import __main__ it will get executed again (as a module) because | |
| there's no ``sqlparse.__main__`` in ``sys.modules``. | |
| Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration | |
| """ | |
| import argparse | |
| import sys | |
| from io import TextIOWrapper | |
| import sqlparse | |
| from sqlparse.exceptions import SQLParseError | |
| # TODO: Add CLI Tests | |
| # TODO: Simplify formatter by using argparse `type` arguments | |
| def create_parser(): | |
| _CASE_CHOICES = ['upper', 'lower', 'capitalize'] | |
| parser = argparse.ArgumentParser( | |
| prog='sqlformat', | |
| description='Format FILE according to OPTIONS. Use "-" as FILE ' | |
| 'to read from stdin.', | |
| usage='%(prog)s [OPTIONS] FILE [FILE ...]', | |
| ) | |
| parser.add_argument( | |
| 'filename', | |
| nargs='+', | |
| help='file(s) to format (use "-" for stdin)') | |
| parser.add_argument( | |
| '-o', '--outfile', | |
| dest='outfile', | |
| metavar='FILE', | |
| help='write output to FILE (defaults to stdout)') | |
| parser.add_argument( | |
| '--in-place', | |
| dest='inplace', | |
| action='store_true', | |
| default=False, | |
| help='format files in-place (overwrite existing files)') | |
| parser.add_argument( | |
| '--version', | |
| action='version', | |
| version=sqlparse.__version__) | |
| group = parser.add_argument_group('Formatting Options') | |
| group.add_argument( | |
| '-k', '--keywords', | |
| metavar='CHOICE', | |
| dest='keyword_case', | |
| choices=_CASE_CHOICES, | |
| help='change case of keywords, CHOICE is one of {}'.format( | |
| ', '.join(f'"{x}"' for x in _CASE_CHOICES))) | |
| group.add_argument( | |
| '-i', '--identifiers', | |
| metavar='CHOICE', | |
| dest='identifier_case', | |
| choices=_CASE_CHOICES, | |
| help='change case of identifiers, CHOICE is one of {}'.format( | |
| ', '.join(f'"{x}"' for x in _CASE_CHOICES))) | |
| group.add_argument( | |
| '-l', '--language', | |
| metavar='LANG', | |
| dest='output_format', | |
| choices=['python', 'php'], | |
| help='output a snippet in programming language LANG, ' | |
| 'choices are "python", "php"') | |
| group.add_argument( | |
| '--strip-comments', | |
| dest='strip_comments', | |
| action='store_true', | |
| default=False, | |
| help='remove comments') | |
| group.add_argument( | |
| '-r', '--reindent', | |
| dest='reindent', | |
| action='store_true', | |
| default=False, | |
| help='reindent statements') | |
| group.add_argument( | |
| '--indent_width', | |
| dest='indent_width', | |
| default=2, | |
| type=int, | |
| help='indentation width (defaults to 2 spaces)') | |
| group.add_argument( | |
| '--indent_after_first', | |
| dest='indent_after_first', | |
| action='store_true', | |
| default=False, | |
| help='indent after first line of statement (e.g. SELECT)') | |
| group.add_argument( | |
| '--indent_columns', | |
| dest='indent_columns', | |
| action='store_true', | |
| default=False, | |
| help='indent all columns by indent_width instead of keyword length') | |
| group.add_argument( | |
| '-a', '--reindent_aligned', | |
| action='store_true', | |
| default=False, | |
| help='reindent statements to aligned format') | |
| group.add_argument( | |
| '-s', '--use_space_around_operators', | |
| action='store_true', | |
| default=False, | |
| help='place spaces around mathematical operators') | |
| group.add_argument( | |
| '--wrap_after', | |
| dest='wrap_after', | |
| default=0, | |
| type=int, | |
| help='Column after which lists should be wrapped') | |
| group.add_argument( | |
| '--comma_first', | |
| dest='comma_first', | |
| default=False, | |
| type=bool, | |
| help='Insert linebreak before comma (default False)') | |
| group.add_argument( | |
| '--compact', | |
| dest='compact', | |
| default=False, | |
| type=bool, | |
| help='Try to produce more compact output (default False)') | |
| group.add_argument( | |
| '--encoding', | |
| dest='encoding', | |
| default='utf-8', | |
| help='Specify the input encoding (default utf-8)') | |
| return parser | |
| def _error(msg): | |
| """Print msg and optionally exit with return code exit_.""" | |
| sys.stderr.write(f'[ERROR] {msg}\n') | |
| return 1 | |
| def _process_file(filename, args): | |
| """Process a single file with the given formatting options. | |
| Returns 0 on success, 1 on error. | |
| """ | |
| # Check for incompatible option combinations first | |
| if filename == '-' and args.inplace: | |
| return _error('Cannot use --in-place with stdin') | |
| # Read input | |
| if filename == '-': # read from stdin | |
| wrapper = TextIOWrapper(sys.stdin.buffer, encoding=args.encoding) | |
| try: | |
| data = wrapper.read() | |
| finally: | |
| wrapper.detach() | |
| else: | |
| try: | |
| with open(filename, encoding=args.encoding) as f: | |
| data = ''.join(f.readlines()) | |
| except OSError as e: | |
| return _error(f'Failed to read {filename}: {e}') | |
| # Determine output destination | |
| close_stream = False | |
| if args.inplace: | |
| try: | |
| stream = open(filename, 'w', encoding=args.encoding) | |
| close_stream = True | |
| except OSError as e: | |
| return _error(f'Failed to open {filename}: {e}') | |
| elif args.outfile: | |
| try: | |
| stream = open(args.outfile, 'w', encoding=args.encoding) | |
| close_stream = True | |
| except OSError as e: | |
| return _error(f'Failed to open {args.outfile}: {e}') | |
| else: | |
| stream = sys.stdout | |
| # Format the SQL | |
| formatter_opts = vars(args) | |
| try: | |
| formatter_opts = sqlparse.formatter.validate_options(formatter_opts) | |
| except SQLParseError as e: | |
| return _error(f'Invalid options: {e}') | |
| s = sqlparse.format(data, **formatter_opts) | |
| stream.write(s) | |
| stream.flush() | |
| if close_stream: | |
| stream.close() | |
| return 0 | |
| def main(args=None): | |
| parser = create_parser() | |
| args = parser.parse_args(args) | |
| # Validate argument combinations | |
| if len(args.filename) > 1: | |
| if args.outfile: | |
| return _error('Cannot use -o/--outfile with multiple files') | |
| if not args.inplace: | |
| return _error('Multiple files require --in-place flag') | |
| # Process all files | |
| exit_code = 0 | |
| for filename in args.filename: | |
| result = _process_file(filename, args) | |
| if result != 0: | |
| exit_code = result | |
| # Continue processing remaining files even if one fails | |
| return exit_code | |
Xet Storage Details
- Size:
- 7.19 kB
- Xet hash:
- 62250278e1c46609e8e9d6b24606bdefb60de855be10eeb50c6260fbae0d6505
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.