Skip to content

Commit 5eab09b

Browse files
committed
Separate __main__ and main() to allow for testing
Also reference example in: https://github.com/ionelmc/cookiecutter-pylibrary
1 parent f266ffb commit 5eab09b

3 files changed

Lines changed: 173 additions & 136 deletions

File tree

sqlparse/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
# Setup namespace
1111
from sqlparse import sql
12+
from sqlparse import cli
1213
from sqlparse import engine
1314
from sqlparse import tokens
1415
from sqlparse import filters
@@ -17,7 +18,7 @@
1718
from sqlparse.compat import text_type
1819

1920
__version__ = '0.2.0.dev0'
20-
__all__ = ['engine', 'filters', 'formatter', 'sql', 'tokens']
21+
__all__ = ['engine', 'filters', 'formatter', 'sql', 'tokens', 'cli']
2122

2223

2324
def parse(sql, encoding=None):

sqlparse/__main__.py

Lines changed: 8 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -6,144 +6,17 @@
66
# This module is part of python-sqlparse and is released under
77
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
88

9-
import argparse
10-
import sys
11-
12-
import sqlparse
13-
from sqlparse.compat import PY2
14-
from sqlparse.exceptions import SQLParseError
15-
16-
_CASE_CHOICES = ['upper', 'lower', 'capitalize']
17-
18-
# TODO: Add CLI Tests
19-
# TODO: Simplify formatter by using argparse `type` arguments
20-
parser = argparse.ArgumentParser(
21-
prog='sqlformat',
22-
description='Format FILE according to OPTIONS. Use "-" as FILE '
23-
'to read from stdin.',
24-
usage='%(prog)s [OPTIONS] FILE, ...',
25-
)
26-
27-
parser.add_argument('filename')
28-
29-
parser.add_argument(
30-
'-o', '--outfile',
31-
dest='outfile',
32-
metavar='FILE',
33-
help='write output to FILE (defaults to stdout)')
34-
35-
parser.add_argument(
36-
'--version',
37-
action='version',
38-
version=sqlparse.__version__)
39-
40-
group = parser.add_argument_group('Formatting Options')
41-
42-
group.add_argument(
43-
'-k', '--keywords',
44-
metavar='CHOICE',
45-
dest='keyword_case',
46-
choices=_CASE_CHOICES,
47-
help='change case of keywords, CHOICE is one of {0}'.format(
48-
', '.join('"{0}"'.format(x) for x in _CASE_CHOICES)))
49-
50-
group.add_argument(
51-
'-i', '--identifiers',
52-
metavar='CHOICE',
53-
dest='identifier_case',
54-
choices=_CASE_CHOICES,
55-
help='change case of identifiers, CHOICE is one of {0}'.format(
56-
', '.join('"{0}"'.format(x) for x in _CASE_CHOICES)))
57-
58-
group.add_argument(
59-
'-l', '--language',
60-
metavar='LANG',
61-
dest='output_format',
62-
choices=['python', 'php'],
63-
help='output a snippet in programming language LANG, '
64-
'choices are "python", "php"')
65-
66-
group.add_argument(
67-
'--strip-comments',
68-
dest='strip_comments',
69-
action='store_true',
70-
default=False,
71-
help='remove comments')
9+
"""Entrypoint module for `python -m sqlparse`.
7210
73-
group.add_argument(
74-
'-r', '--reindent',
75-
dest='reindent',
76-
action='store_true',
77-
default=False,
78-
help='reindent statements')
11+
Why does this file exist, and why __main__? For more info, read:
12+
- https://www.python.org/dev/peps/pep-0338/
13+
- https://docs.python.org/2/using/cmdline.html#cmdoption-m
14+
- https://docs.python.org/3/using/cmdline.html#cmdoption-m
15+
"""
7916

80-
group.add_argument(
81-
'--indent_width',
82-
dest='indent_width',
83-
default=2,
84-
type=int,
85-
help='indentation width (defaults to 2 spaces)')
86-
87-
group.add_argument(
88-
'-a', '--reindent_aligned',
89-
action='store_true',
90-
default=False,
91-
help='reindent statements to aligned format')
92-
93-
group.add_argument(
94-
'-s', '--use_space_around_operators',
95-
action='store_true',
96-
default=False,
97-
help='place spaces around mathematical operators')
98-
99-
group.add_argument(
100-
'--wrap_after',
101-
dest='wrap_after',
102-
default=0,
103-
type=int,
104-
help='Column after which lists should be wrapped')
105-
106-
107-
def _error(msg):
108-
"""Print msg and optionally exit with return code exit_."""
109-
sys.stderr.write('[ERROR] %s\n' % msg)
110-
111-
112-
def main(args=None):
113-
args = parser.parse_args(args)
114-
115-
if args.filename == '-': # read from stdin
116-
data = sys.stdin.read()
117-
else:
118-
try:
119-
data = ''.join(open(args.filename).readlines())
120-
except IOError as e:
121-
_error('Failed to read %s: %s' % (args.filename, e))
122-
return 1
123-
124-
if args.outfile:
125-
try:
126-
stream = open(args.outfile, 'w')
127-
except IOError as e:
128-
_error('Failed to open %s: %s' % (args.outfile, e))
129-
return 1
130-
else:
131-
stream = sys.stdout
132-
133-
formatter_opts = vars(args)
134-
try:
135-
formatter_opts = sqlparse.formatter.validate_options(formatter_opts)
136-
except SQLParseError as e:
137-
_error('Invalid options: %s' % e)
138-
return 1
139-
140-
s = sqlparse.format(data, **formatter_opts)
141-
if PY2:
142-
s = s.encode('utf-8', 'replace')
143-
stream.write(s)
144-
stream.flush()
145-
return 0
17+
import sys
14618

19+
from sqlparse.cli import main
14720

14821
if __name__ == '__main__':
14922
sys.exit(main())

sqlparse/cli.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (C) 2016 Andi Albrecht, [email protected]
5+
#
6+
# This module is part of python-sqlparse and is released under
7+
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
8+
9+
"""Module that contains the command line app.
10+
11+
Why does this file exist, and why not put this in __main__?
12+
You might be tempted to import things from __main__ later, but that will
13+
cause problems: the code will get executed twice:
14+
- When you run `python -m sqlparse` python will execute
15+
``__main__.py`` as a script. That means there won't be any
16+
``sqlparse.__main__`` in ``sys.modules``.
17+
- When you import __main__ it will get executed again (as a module) because
18+
there's no ``sqlparse.__main__`` in ``sys.modules``.
19+
Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration
20+
"""
21+
22+
import argparse
23+
import sys
24+
25+
import sqlparse
26+
from sqlparse.compat import PY2
27+
from sqlparse.exceptions import SQLParseError
28+
29+
30+
# TODO: Add CLI Tests
31+
# TODO: Simplify formatter by using argparse `type` arguments
32+
def create_parser():
33+
_CASE_CHOICES = ['upper', 'lower', 'capitalize']
34+
35+
parser = argparse.ArgumentParser(
36+
prog='sqlformat',
37+
description='Format FILE according to OPTIONS. Use "-" as FILE '
38+
'to read from stdin.',
39+
usage='%(prog)s [OPTIONS] FILE, ...',
40+
)
41+
42+
parser.add_argument('filename')
43+
44+
parser.add_argument(
45+
'-o', '--outfile',
46+
dest='outfile',
47+
metavar='FILE',
48+
help='write output to FILE (defaults to stdout)')
49+
50+
parser.add_argument(
51+
'--version',
52+
action='version',
53+
version=sqlparse.__version__)
54+
55+
group = parser.add_argument_group('Formatting Options')
56+
57+
group.add_argument(
58+
'-k', '--keywords',
59+
metavar='CHOICE',
60+
dest='keyword_case',
61+
choices=_CASE_CHOICES,
62+
help='change case of keywords, CHOICE is one of {0}'.format(
63+
', '.join('"{0}"'.format(x) for x in _CASE_CHOICES)))
64+
65+
group.add_argument(
66+
'-i', '--identifiers',
67+
metavar='CHOICE',
68+
dest='identifier_case',
69+
choices=_CASE_CHOICES,
70+
help='change case of identifiers, CHOICE is one of {0}'.format(
71+
', '.join('"{0}"'.format(x) for x in _CASE_CHOICES)))
72+
73+
group.add_argument(
74+
'-l', '--language',
75+
metavar='LANG',
76+
dest='output_format',
77+
choices=['python', 'php'],
78+
help='output a snippet in programming language LANG, '
79+
'choices are "python", "php"')
80+
81+
group.add_argument(
82+
'--strip-comments',
83+
dest='strip_comments',
84+
action='store_true',
85+
default=False,
86+
help='remove comments')
87+
88+
group.add_argument(
89+
'-r', '--reindent',
90+
dest='reindent',
91+
action='store_true',
92+
default=False,
93+
help='reindent statements')
94+
95+
group.add_argument(
96+
'--indent_width',
97+
dest='indent_width',
98+
default=2,
99+
type=int,
100+
help='indentation width (defaults to 2 spaces)')
101+
102+
group.add_argument(
103+
'-a', '--reindent_aligned',
104+
action='store_true',
105+
default=False,
106+
help='reindent statements to aligned format')
107+
108+
group.add_argument(
109+
'-s', '--use_space_around_operators',
110+
action='store_true',
111+
default=False,
112+
help='place spaces around mathematical operators')
113+
114+
group.add_argument(
115+
'--wrap_after',
116+
dest='wrap_after',
117+
default=0,
118+
type=int,
119+
help='Column after which lists should be wrapped')
120+
121+
return parser
122+
123+
124+
def _error(msg):
125+
"""Print msg and optionally exit with return code exit_."""
126+
sys.stderr.write('[ERROR] %s\n' % msg)
127+
128+
129+
def main(args=None):
130+
parser = create_parser()
131+
args = parser.parse_args(args)
132+
133+
if args.filename == '-': # read from stdin
134+
data = sys.stdin.read()
135+
else:
136+
try:
137+
data = ''.join(open(args.filename).readlines())
138+
except IOError as e:
139+
_error('Failed to read %s: %s' % (args.filename, e))
140+
return 1
141+
142+
if args.outfile:
143+
try:
144+
stream = open(args.outfile, 'w')
145+
except IOError as e:
146+
_error('Failed to open %s: %s' % (args.outfile, e))
147+
return 1
148+
else:
149+
stream = sys.stdout
150+
151+
formatter_opts = vars(args)
152+
try:
153+
formatter_opts = sqlparse.formatter.validate_options(formatter_opts)
154+
except SQLParseError as e:
155+
_error('Invalid options: %s' % e)
156+
return 1
157+
158+
s = sqlparse.format(data, **formatter_opts)
159+
if PY2:
160+
s = s.encode('utf-8', 'replace')
161+
stream.write(s)
162+
stream.flush()
163+
return 0

0 commit comments

Comments
 (0)