Commit c4c2e3d8 authored by Stefan Behnel's avatar Stefan Behnel

test CmdLine.py and rework long option parsing

parent 2bb096d3
......@@ -64,11 +64,25 @@ def bad_usage():
def parse_command_line(args):
from .Main import CompilationOptions, default_options
pending_arg = []
def pop_arg():
if args:
return args.pop(0)
else:
if not args or pending_arg:
bad_usage()
if '=' in args[0] and args[0].startswith('--'): # allow "--long-option=xyz"
name, value = args.pop(0).split('=', 1)
pending_arg.append(value)
return name
return args.pop(0)
def pop_value(default=None):
if pending_arg:
return pending_arg.pop()
elif default is not None:
return default
elif not args:
bad_usage()
return args.pop(0)
def get_param(option):
tail = option[2:]
......@@ -89,17 +103,15 @@ def parse_command_line(args):
elif option in ("-+", "--cplus"):
options.cplus = 1
elif option == "--embed":
Options.embed = "main"
elif option.startswith("--embed="):
Options.embed = option[8:]
Options.embed = pop_value("main")
elif option.startswith("-I"):
options.include_path.append(get_param(option))
elif option == "--include-dir":
options.include_path.append(pop_arg())
options.include_path.append(pop_value())
elif option in ("-w", "--working"):
options.working_path = pop_arg()
options.working_path = pop_value()
elif option in ("-o", "--output-file"):
options.output_file = pop_arg()
options.output_file = pop_value()
elif option in ("-t", "--timestamps"):
options.timestamps = 1
elif option in ("-f", "--force"):
......@@ -109,16 +121,16 @@ def parse_command_line(args):
elif option in ("-p", "--embed-positions"):
Options.embed_pos_in_docstring = 1
elif option in ("-z", "--pre-import"):
Options.pre_import = pop_arg()
Options.pre_import = pop_value()
elif option == "--cleanup":
Options.generate_cleanup_code = int(pop_arg())
Options.generate_cleanup_code = int(pop_value())
elif option in ("-D", "--no-docstrings"):
Options.docstrings = False
elif option in ("-a", "--annotate"):
Options.annotate = True
elif option == "--annotate-coverage":
Options.annotate = True
Options.annotate_coverage_xml = pop_arg()
Options.annotate_coverage_xml = pop_value()
elif option == "--convert-range":
Options.convert_range = True
elif option == "--line-directives":
......@@ -130,7 +142,7 @@ def parse_command_line(args):
options.output_dir = os.curdir
elif option == "--gdb-outdir":
options.gdb_debug = True
options.output_dir = pop_arg()
options.output_dir = pop_value()
elif option == "--lenient":
Options.error_on_unknown_names = False
Options.error_on_uninitialized = False
......@@ -152,7 +164,7 @@ def parse_command_line(args):
if option.startswith('-X') and option[2:].strip():
x_args = option[2:]
else:
x_args = pop_arg()
x_args = pop_value()
try:
options.compiler_directives = Options.parse_directive_list(
x_args, relaxed_bool=True,
......@@ -176,6 +188,10 @@ def parse_command_line(args):
sys.exit(1)
else:
sources.append(pop_arg())
if pending_arg:
bad_usage()
if options.use_listing_file and len(sources) > 1:
sys.stderr.write(
"cython: Only one source file allowed when using -o\n")
......
import sys
from unittest import TestCase
try:
from StringIO import StringIO
except ImportError:
from io import StringIO # doesn't accept 'str' in Py2
from .. import Options
from ..CmdLine import parse_command_line
class CmdLineParserTest(TestCase):
def setUp(self):
backup = {}
for name, value in vars(Options).items():
backup[name] = value
self._options_backup = backup
def tearDown(self):
no_value = object()
for name, orig_value in self._options_backup.items():
if getattr(Options, name, no_value) != orig_value:
setattr(Options, name, orig_value)
def test_short_options(self):
options, sources = parse_command_line([
'-V', '-l', '-+', '-t', '-v', '-v', '-v', '-p', '-D', '-a', '-3',
])
self.assertFalse(sources)
self.assertTrue(options.show_version)
self.assertTrue(options.use_listing_file)
self.assertTrue(options.cplus)
self.assertTrue(options.timestamps)
self.assertTrue(options.verbose >= 3)
self.assertTrue(Options.embed_pos_in_docstring)
self.assertFalse(Options.docstrings)
self.assertTrue(Options.annotate)
self.assertEqual(options.language_level, 3)
options, sources = parse_command_line([
'-f', '-2', 'source.pyx',
])
self.assertTrue(sources)
self.assertTrue(len(sources) == 1)
self.assertFalse(options.timestamps)
self.assertEqual(options.language_level, 2)
def test_long_options(self):
options, sources = parse_command_line([
'--version', '--create-listing', '--cplus', '--embed', '--timestamps',
'--verbose', '--verbose', '--verbose',
'--embed-positions', '--no-docstrings', '--annotate', '--lenient',
])
self.assertFalse(sources)
self.assertTrue(options.show_version)
self.assertTrue(options.use_listing_file)
self.assertTrue(options.cplus)
self.assertEqual(Options.embed, 'main')
self.assertTrue(options.timestamps)
self.assertTrue(options.verbose >= 3)
self.assertTrue(Options.embed_pos_in_docstring)
self.assertFalse(Options.docstrings)
self.assertTrue(Options.annotate)
self.assertFalse(Options.error_on_unknown_names)
self.assertFalse(Options.error_on_uninitialized)
options, sources = parse_command_line([
'--force', 'source.pyx',
])
self.assertTrue(sources)
self.assertTrue(len(sources) == 1)
self.assertFalse(options.timestamps)
def test_options_with_values(self):
options, sources = parse_command_line([
'--embed=huhu',
'-I/test/include/dir1', '--include-dir=/test/include/dir2',
'--include-dir', '/test/include/dir3',
'--working=/work/dir',
'source.pyx',
'--output-file=/output/dir',
'--pre-import=/pre/import',
'--cleanup=3',
'--annotate-coverage=cov.xml',
'--gdb-outdir=/gdb/outdir',
'--directive=wraparound=false',
])
self.assertEqual(sources, ['source.pyx'])
self.assertEqual(Options.embed, 'huhu')
self.assertEqual(options.include_path, ['/test/include/dir1', '/test/include/dir2', '/test/include/dir3'])
self.assertEqual(options.working_path, '/work/dir')
self.assertEqual(options.output_file, '/output/dir')
self.assertEqual(Options.pre_import, '/pre/import')
self.assertEqual(Options.generate_cleanup_code, 3)
self.assertTrue(Options.annotate)
self.assertEqual(Options.annotate_coverage_xml, 'cov.xml')
self.assertTrue(options.gdb_debug)
self.assertEqual(options.output_dir, '/gdb/outdir')
def test_errors(self):
def error(*args):
old_stderr = sys.stderr
stderr = sys.stderr = StringIO()
try:
self.assertRaises(SystemExit, parse_command_line, list(args))
finally:
sys.stderr = old_stderr
self.assertTrue(stderr.getvalue())
error('-1')
error('-I')
error('--version=-a')
error('--version=--annotate=true')
error('--working')
error('--verbose=1')
error('--verbose=1')
error('--cleanup')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment