Spaces:
Build error
Build error
import os | |
import sys | |
import re | |
from unittest import TestCase | |
try: | |
from unittest.mock import patch, Mock | |
except ImportError: # Py2 | |
from mock import patch, Mock | |
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 | |
from .Utils import backup_Options, restore_Options, check_global_options | |
unpatched_exists = os.path.exists | |
def patched_exists(path): | |
# avoid the Cython command raising a file not found error | |
if path in ( | |
'source.pyx', | |
os.path.join('/work/dir', 'source.pyx'), | |
os.path.join('my_working_path', 'source.pyx'), | |
'file.pyx', | |
'file1.pyx', | |
'file2.pyx', | |
'file3.pyx', | |
'foo.pyx', | |
'bar.pyx', | |
): | |
return True | |
return unpatched_exists(path) | |
class CmdLineParserTest(TestCase): | |
def setUp(self): | |
self._options_backup = backup_Options() | |
def tearDown(self): | |
restore_Options(self._options_backup) | |
def check_default_global_options(self, white_list=[]): | |
self.assertEqual(check_global_options(self._options_backup, white_list), "") | |
def check_default_options(self, options, white_list=[]): | |
default_options = Options.CompilationOptions(Options.default_options) | |
no_value = object() | |
for name in default_options.__dict__.keys(): | |
if name not in white_list: | |
self.assertEqual(getattr(options, name, no_value), getattr(default_options, name), msg="error in option " + name) | |
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') | |
self.assertEqual(options.compiler_directives['wraparound'], False) | |
def test_embed_before_positional(self): | |
options, sources = parse_command_line([ | |
'--embed', | |
'source.pyx', | |
]) | |
self.assertEqual(sources, ['source.pyx']) | |
self.assertEqual(Options.embed, 'main') | |
def test_two_embeds(self): | |
options, sources = parse_command_line([ | |
'--embed', '--embed=huhu', | |
'source.pyx', | |
]) | |
self.assertEqual(sources, ['source.pyx']) | |
self.assertEqual(Options.embed, 'huhu') | |
def test_two_embeds2(self): | |
options, sources = parse_command_line([ | |
'--embed=huhu', '--embed', | |
'source.pyx', | |
]) | |
self.assertEqual(sources, ['source.pyx']) | |
self.assertEqual(Options.embed, 'main') | |
def test_no_annotate(self): | |
options, sources = parse_command_line([ | |
'--embed=huhu', 'source.pyx' | |
]) | |
self.assertFalse(Options.annotate) | |
def test_annotate_short(self): | |
options, sources = parse_command_line([ | |
'-a', | |
'source.pyx', | |
]) | |
self.assertEqual(Options.annotate, 'default') | |
def test_annotate_long(self): | |
options, sources = parse_command_line([ | |
'--annotate', | |
'source.pyx', | |
]) | |
self.assertEqual(Options.annotate, 'default') | |
def test_annotate_fullc(self): | |
options, sources = parse_command_line([ | |
'--annotate-fullc', | |
'source.pyx', | |
]) | |
self.assertEqual(Options.annotate, 'fullc') | |
def test_short_w(self): | |
options, sources = parse_command_line([ | |
'-w', 'my_working_path', | |
'source.pyx' | |
]) | |
self.assertEqual(options.working_path, 'my_working_path') | |
self.check_default_global_options() | |
self.check_default_options(options, ['working_path']) | |
def test_short_o(self): | |
options, sources = parse_command_line([ | |
'-o', 'my_output', | |
'source.pyx' | |
]) | |
self.assertEqual(options.output_file, 'my_output') | |
self.check_default_global_options() | |
self.check_default_options(options, ['output_file']) | |
def test_short_z(self): | |
options, sources = parse_command_line([ | |
'-z', 'my_preimport', | |
'source.pyx' | |
]) | |
self.assertEqual(Options.pre_import, 'my_preimport') | |
self.check_default_global_options(['pre_import']) | |
self.check_default_options(options) | |
def test_convert_range(self): | |
options, sources = parse_command_line([ | |
'--convert-range', | |
'source.pyx' | |
]) | |
self.assertEqual(Options.convert_range, True) | |
self.check_default_global_options(['convert_range']) | |
self.check_default_options(options) | |
def test_line_directives(self): | |
options, sources = parse_command_line([ | |
'--line-directives', | |
'source.pyx' | |
]) | |
self.assertEqual(options.emit_linenums, True) | |
self.check_default_global_options() | |
self.check_default_options(options, ['emit_linenums']) | |
def test_no_c_in_traceback(self): | |
options, sources = parse_command_line([ | |
'--no-c-in-traceback', | |
'source.pyx' | |
]) | |
self.assertEqual(options.c_line_in_traceback, False) | |
self.check_default_global_options() | |
self.check_default_options(options, ['c_line_in_traceback']) | |
def test_gdb(self): | |
options, sources = parse_command_line([ | |
'--gdb', | |
'source.pyx' | |
]) | |
self.assertEqual(options.gdb_debug, True) | |
self.assertEqual(options.output_dir, os.curdir) | |
self.check_default_global_options() | |
self.check_default_options(options, ['gdb_debug', 'output_dir']) | |
def test_3str(self): | |
options, sources = parse_command_line([ | |
'--3str', | |
'source.pyx' | |
]) | |
self.assertEqual(options.language_level, '3str') | |
self.check_default_global_options() | |
self.check_default_options(options, ['language_level']) | |
def test_capi_reexport_cincludes(self): | |
options, sources = parse_command_line([ | |
'--capi-reexport-cincludes', | |
'source.pyx' | |
]) | |
self.assertEqual(options.capi_reexport_cincludes, True) | |
self.check_default_global_options() | |
self.check_default_options(options, ['capi_reexport_cincludes']) | |
def test_fast_fail(self): | |
options, sources = parse_command_line([ | |
'--fast-fail', | |
'source.pyx' | |
]) | |
self.assertEqual(Options.fast_fail, True) | |
self.check_default_global_options(['fast_fail']) | |
self.check_default_options(options) | |
def test_cimport_from_pyx(self): | |
options, sources = parse_command_line([ | |
'--cimport-from-pyx', | |
'source.pyx' | |
]) | |
self.assertEqual(Options.cimport_from_pyx, True) | |
self.check_default_global_options(['cimport_from_pyx']) | |
self.check_default_options(options) | |
def test_Werror(self): | |
options, sources = parse_command_line([ | |
'-Werror', | |
'source.pyx' | |
]) | |
self.assertEqual(Options.warning_errors, True) | |
self.check_default_global_options(['warning_errors']) | |
self.check_default_options(options) | |
def test_warning_errors(self): | |
options, sources = parse_command_line([ | |
'--warning-errors', | |
'source.pyx' | |
]) | |
self.assertEqual(Options.warning_errors, True) | |
self.check_default_global_options(['warning_errors']) | |
self.check_default_options(options) | |
def test_Wextra(self): | |
options, sources = parse_command_line([ | |
'-Wextra', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compiler_directives, Options.extra_warnings) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compiler_directives']) | |
def test_warning_extra(self): | |
options, sources = parse_command_line([ | |
'--warning-extra', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compiler_directives, Options.extra_warnings) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compiler_directives']) | |
def test_old_style_globals(self): | |
options, sources = parse_command_line([ | |
'--old-style-globals', | |
'source.pyx' | |
]) | |
self.assertEqual(Options.old_style_globals, True) | |
self.check_default_global_options(['old_style_globals']) | |
self.check_default_options(options) | |
def test_directive_multiple(self): | |
options, source = parse_command_line([ | |
'-X', 'cdivision=True', | |
'-X', 'c_string_type=bytes', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compiler_directives['cdivision'], True) | |
self.assertEqual(options.compiler_directives['c_string_type'], 'bytes') | |
self.check_default_global_options() | |
self.check_default_options(options, ['compiler_directives']) | |
def test_directive_multiple_v2(self): | |
options, source = parse_command_line([ | |
'-X', 'cdivision=True,c_string_type=bytes', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compiler_directives['cdivision'], True) | |
self.assertEqual(options.compiler_directives['c_string_type'], 'bytes') | |
self.check_default_global_options() | |
self.check_default_options(options, ['compiler_directives']) | |
def test_directive_value_yes(self): | |
options, source = parse_command_line([ | |
'-X', 'cdivision=YeS', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compiler_directives['cdivision'], True) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compiler_directives']) | |
def test_directive_value_no(self): | |
options, source = parse_command_line([ | |
'-X', 'cdivision=no', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compiler_directives['cdivision'], False) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compiler_directives']) | |
def test_directive_value_invalid(self): | |
self.assertRaises(ValueError, parse_command_line, [ | |
'-X', 'cdivision=sadfasd', | |
'source.pyx' | |
]) | |
def test_directive_key_invalid(self): | |
self.assertRaises(ValueError, parse_command_line, [ | |
'-X', 'abracadabra', | |
'source.pyx' | |
]) | |
def test_directive_no_value(self): | |
self.assertRaises(ValueError, parse_command_line, [ | |
'-X', 'cdivision', | |
'source.pyx' | |
]) | |
def test_compile_time_env_short(self): | |
options, source = parse_command_line([ | |
'-E', 'MYSIZE=10', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compile_time_env['MYSIZE'], 10) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compile_time_env']) | |
def test_compile_time_env_long(self): | |
options, source = parse_command_line([ | |
'--compile-time-env', 'MYSIZE=10', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compile_time_env['MYSIZE'], 10) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compile_time_env']) | |
def test_compile_time_env_multiple(self): | |
options, source = parse_command_line([ | |
'-E', 'MYSIZE=10', '-E', 'ARRSIZE=11', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compile_time_env['MYSIZE'], 10) | |
self.assertEqual(options.compile_time_env['ARRSIZE'], 11) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compile_time_env']) | |
def test_compile_time_env_multiple_v2(self): | |
options, source = parse_command_line([ | |
'-E', 'MYSIZE=10,ARRSIZE=11', | |
'source.pyx' | |
]) | |
self.assertEqual(options.compile_time_env['MYSIZE'], 10) | |
self.assertEqual(options.compile_time_env['ARRSIZE'], 11) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compile_time_env']) | |
def test_option_first(self): | |
options, sources = parse_command_line(['-V', 'file.pyx']) | |
self.assertEqual(sources, ['file.pyx']) | |
def test_file_inbetween(self): | |
options, sources = parse_command_line(['-V', 'file.pyx', '-a']) | |
self.assertEqual(sources, ['file.pyx']) | |
def test_option_trailing(self): | |
options, sources = parse_command_line(['file.pyx', '-V']) | |
self.assertEqual(sources, ['file.pyx']) | |
def test_multiple_files(self): | |
options, sources = parse_command_line([ | |
'file1.pyx', '-V', | |
'file2.pyx', '-a', | |
'file3.pyx' | |
]) | |
self.assertEqual(sources, ['file1.pyx', 'file2.pyx', 'file3.pyx']) | |
def test_debug_flags(self): | |
options, sources = parse_command_line([ | |
'--debug-disposal-code', '--debug-coercion', | |
'file3.pyx' | |
]) | |
from Cython.Compiler import DebugFlags | |
for name in ['debug_disposal_code', 'debug_temp_alloc', 'debug_coercion']: | |
self.assertEqual(getattr(DebugFlags, name), name in ['debug_disposal_code', 'debug_coercion']) | |
setattr(DebugFlags, name, 0) # restore original value | |
def test_gdb_overwrites_gdb_outdir(self): | |
options, sources = parse_command_line([ | |
'--gdb-outdir=my_dir', '--gdb', | |
'file3.pyx' | |
]) | |
self.assertEqual(options.gdb_debug, True) | |
self.assertEqual(options.output_dir, os.curdir) | |
self.check_default_global_options() | |
self.check_default_options(options, ['gdb_debug', 'output_dir']) | |
def test_gdb_first(self): | |
options, sources = parse_command_line([ | |
'--gdb', '--gdb-outdir=my_dir', | |
'file3.pyx' | |
]) | |
self.assertEqual(options.gdb_debug, True) | |
self.assertEqual(options.output_dir, 'my_dir') | |
self.check_default_global_options() | |
self.check_default_options(options, ['gdb_debug', 'output_dir']) | |
def test_coverage_overwrites_annotation(self): | |
options, sources = parse_command_line([ | |
'--annotate-fullc', '--annotate-coverage=my.xml', | |
'file3.pyx' | |
]) | |
self.assertEqual(Options.annotate, True) | |
self.assertEqual(Options.annotate_coverage_xml, 'my.xml') | |
self.check_default_global_options(['annotate', 'annotate_coverage_xml']) | |
self.check_default_options(options) | |
def test_coverage_first(self): | |
options, sources = parse_command_line([ | |
'--annotate-coverage=my.xml', '--annotate-fullc', | |
'file3.pyx' | |
]) | |
self.assertEqual(Options.annotate, 'fullc') | |
self.assertEqual(Options.annotate_coverage_xml, 'my.xml') | |
self.check_default_global_options(['annotate', 'annotate_coverage_xml']) | |
self.check_default_options(options) | |
def test_annotate_first_fullc_second(self): | |
options, sources = parse_command_line([ | |
'--annotate', '--annotate-fullc', | |
'file3.pyx' | |
]) | |
self.assertEqual(Options.annotate, 'fullc') | |
self.check_default_global_options(['annotate']) | |
self.check_default_options(options) | |
def test_annotate_fullc_first(self): | |
options, sources = parse_command_line([ | |
'--annotate-fullc', '--annotate', | |
'file3.pyx' | |
]) | |
self.assertEqual(Options.annotate, 'default') | |
self.check_default_global_options(['annotate']) | |
self.check_default_options(options) | |
def test_warning_extra_dont_overwrite(self): | |
options, sources = parse_command_line([ | |
'-X', 'cdivision=True', | |
'--warning-extra', | |
'-X', 'c_string_type=bytes', | |
'source.pyx' | |
]) | |
self.assertTrue(len(options.compiler_directives), len(Options.extra_warnings) + 1) | |
self.check_default_global_options() | |
self.check_default_options(options, ['compiler_directives']) | |
def test_module_name(self): | |
options, sources = parse_command_line([ | |
'source.pyx' | |
]) | |
self.assertEqual(options.module_name, None) | |
self.check_default_global_options() | |
self.check_default_options(options) | |
options, sources = parse_command_line([ | |
'--module-name', 'foo.bar', | |
'source.pyx' | |
]) | |
self.assertEqual(options.module_name, 'foo.bar') | |
self.check_default_global_options() | |
self.check_default_options(options, ['module_name']) | |
def test_errors(self): | |
def error(args, regex=None): | |
old_stderr = sys.stderr | |
stderr = sys.stderr = StringIO() | |
try: | |
self.assertRaises(SystemExit, parse_command_line, list(args)) | |
finally: | |
sys.stderr = old_stderr | |
msg = stderr.getvalue() | |
err_msg = 'Message "{}"'.format(msg.strip()) | |
self.assertTrue(msg.startswith('usage: '), | |
'%s does not start with "usage :"' % err_msg) | |
self.assertTrue(': error: ' in msg, | |
'%s does not contain ": error :"' % err_msg) | |
if regex: | |
self.assertTrue(re.search(regex, msg), | |
'%s does not match search "%s"' % | |
(err_msg, regex)) | |
error(['-1'], | |
'unknown option -1') | |
error(['-I'], | |
'argument -I/--include-dir: expected one argument') | |
error(['--version=-a'], | |
"argument -V/--version: ignored explicit argument '-a'") | |
error(['--version=--annotate=true'], | |
"argument -V/--version: ignored explicit argument " | |
"'--annotate=true'") | |
error(['--working'], | |
"argument -w/--working: expected one argument") | |
error(['--verbose=1'], | |
"argument -v/--verbose: ignored explicit argument '1'") | |
error(['--cleanup'], | |
"argument --cleanup: expected one argument") | |
error(['--debug-disposal-code-wrong-name', 'file3.pyx'], | |
"unknown option --debug-disposal-code-wrong-name") | |
error(['--module-name', 'foo.pyx'], | |
"Need at least one source file") | |
error(['--module-name', 'foo.bar'], | |
"Need at least one source file") | |
error(['--module-name', 'foo.bar', 'foo.pyx', 'bar.pyx'], | |
"Only one source file allowed when using --module-name") | |
error(['--module-name', 'foo.bar', '--timestamps', 'foo.pyx'], | |
"Cannot use --module-name with --timestamps") | |