reconnect moved files to git repo
This commit is contained in:
@ -0,0 +1,119 @@
|
||||
import difflib
|
||||
import glob
|
||||
import gzip
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import Cython.Build.Dependencies
|
||||
import Cython.Utils
|
||||
from Cython.TestUtils import CythonTest
|
||||
|
||||
|
||||
class TestCyCache(CythonTest):
|
||||
|
||||
def setUp(self):
|
||||
CythonTest.setUp(self)
|
||||
self.temp_dir = tempfile.mkdtemp(
|
||||
prefix='cycache-test',
|
||||
dir='TEST_TMP' if os.path.isdir('TEST_TMP') else None)
|
||||
self.src_dir = tempfile.mkdtemp(prefix='src', dir=self.temp_dir)
|
||||
self.cache_dir = tempfile.mkdtemp(prefix='cache', dir=self.temp_dir)
|
||||
|
||||
def cache_files(self, file_glob):
|
||||
return glob.glob(os.path.join(self.cache_dir, file_glob))
|
||||
|
||||
def fresh_cythonize(self, *args, **kwargs):
|
||||
Cython.Utils.clear_function_caches()
|
||||
Cython.Build.Dependencies._dep_tree = None # discard method caches
|
||||
Cython.Build.Dependencies.cythonize(*args, **kwargs)
|
||||
|
||||
def test_cycache_switch(self):
|
||||
content1 = 'value = 1\n'
|
||||
content2 = 'value = 2\n'
|
||||
a_pyx = os.path.join(self.src_dir, 'a.pyx')
|
||||
a_c = a_pyx[:-4] + '.c'
|
||||
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write(content1)
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
self.assertEqual(1, len(self.cache_files('a.c*')))
|
||||
with open(a_c) as f:
|
||||
a_contents1 = f.read()
|
||||
os.unlink(a_c)
|
||||
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write(content2)
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
with open(a_c) as f:
|
||||
a_contents2 = f.read()
|
||||
os.unlink(a_c)
|
||||
|
||||
self.assertNotEqual(a_contents1, a_contents2, 'C file not changed!')
|
||||
self.assertEqual(2, len(self.cache_files('a.c*')))
|
||||
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write(content1)
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
self.assertEqual(2, len(self.cache_files('a.c*')))
|
||||
with open(a_c) as f:
|
||||
a_contents = f.read()
|
||||
self.assertEqual(
|
||||
a_contents, a_contents1,
|
||||
msg='\n'.join(list(difflib.unified_diff(
|
||||
a_contents.split('\n'), a_contents1.split('\n')))[:10]))
|
||||
|
||||
def test_cycache_uses_cache(self):
|
||||
a_pyx = os.path.join(self.src_dir, 'a.pyx')
|
||||
a_c = a_pyx[:-4] + '.c'
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write('pass')
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
a_cache = os.path.join(self.cache_dir, os.listdir(self.cache_dir)[0])
|
||||
with gzip.GzipFile(a_cache, 'wb') as gzipfile:
|
||||
gzipfile.write('fake stuff'.encode('ascii'))
|
||||
os.unlink(a_c)
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
with open(a_c) as f:
|
||||
a_contents = f.read()
|
||||
self.assertEqual(a_contents, 'fake stuff',
|
||||
'Unexpected contents: %s...' % a_contents[:100])
|
||||
|
||||
def test_multi_file_output(self):
|
||||
a_pyx = os.path.join(self.src_dir, 'a.pyx')
|
||||
a_c = a_pyx[:-4] + '.c'
|
||||
a_h = a_pyx[:-4] + '.h'
|
||||
a_api_h = a_pyx[:-4] + '_api.h'
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write('cdef public api int foo(int x): return x\n')
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
expected = [a_c, a_h, a_api_h]
|
||||
for output in expected:
|
||||
self.assertTrue(os.path.exists(output), output)
|
||||
os.unlink(output)
|
||||
self.fresh_cythonize(a_pyx, cache=self.cache_dir)
|
||||
for output in expected:
|
||||
self.assertTrue(os.path.exists(output), output)
|
||||
|
||||
def test_options_invalidation(self):
|
||||
hash_pyx = os.path.join(self.src_dir, 'options.pyx')
|
||||
hash_c = hash_pyx[:-len('.pyx')] + '.c'
|
||||
|
||||
with open(hash_pyx, 'w') as f:
|
||||
f.write('pass')
|
||||
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=False)
|
||||
self.assertEqual(1, len(self.cache_files('options.c*')))
|
||||
|
||||
os.unlink(hash_c)
|
||||
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=True)
|
||||
self.assertEqual(2, len(self.cache_files('options.c*')))
|
||||
|
||||
os.unlink(hash_c)
|
||||
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=False, show_version=False)
|
||||
self.assertEqual(2, len(self.cache_files('options.c*')))
|
||||
|
||||
os.unlink(hash_c)
|
||||
self.fresh_cythonize(hash_pyx, cache=self.cache_dir, cplus=False, show_version=True)
|
||||
self.assertEqual(2, len(self.cache_files('options.c*')))
|
||||
@ -0,0 +1,482 @@
|
||||
from Cython.Build.Cythonize import (
|
||||
create_args_parser, parse_args_raw, parse_args,
|
||||
parallel_compiles
|
||||
)
|
||||
|
||||
from Cython.Compiler import Options
|
||||
from Cython.Compiler.Tests.Utils import backup_Options, restore_Options, check_global_options
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
import sys
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO # doesn't accept 'str' in Py2
|
||||
|
||||
|
||||
class TestCythonizeArgsParser(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
TestCase.setUp(self)
|
||||
self.parse_args = lambda x, parser=create_args_parser() : parse_args_raw(parser, x)
|
||||
|
||||
|
||||
def are_default(self, options, skip):
|
||||
# empty containers
|
||||
empty_containers = ['directives', 'compile_time_env', 'options', 'excludes']
|
||||
are_none = ['language_level', 'annotate', 'build', 'build_inplace', 'force', 'quiet', 'lenient', 'keep_going', 'no_docstrings']
|
||||
for opt_name in empty_containers:
|
||||
if len(getattr(options, opt_name))!=0 and (opt_name not in skip):
|
||||
self.assertEqual(opt_name,"", msg="For option "+opt_name)
|
||||
return False
|
||||
for opt_name in are_none:
|
||||
if (getattr(options, opt_name) is not None) and (opt_name not in skip):
|
||||
self.assertEqual(opt_name,"", msg="For option "+opt_name)
|
||||
return False
|
||||
if options.parallel!=parallel_compiles and ('parallel' not in skip):
|
||||
return False
|
||||
return True
|
||||
|
||||
# testing directives:
|
||||
def test_directive_short(self):
|
||||
options, args = self.parse_args(['-X', 'cdivision=True'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['directives']))
|
||||
self.assertEqual(options.directives['cdivision'], True)
|
||||
|
||||
def test_directive_long(self):
|
||||
options, args = self.parse_args(['--directive', 'cdivision=True'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['directives']))
|
||||
self.assertEqual(options.directives['cdivision'], True)
|
||||
|
||||
def test_directive_multiple(self):
|
||||
options, args = self.parse_args(['-X', 'cdivision=True', '-X', 'c_string_type=bytes'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['directives']))
|
||||
self.assertEqual(options.directives['cdivision'], True)
|
||||
self.assertEqual(options.directives['c_string_type'], 'bytes')
|
||||
|
||||
def test_directive_multiple_v2(self):
|
||||
options, args = self.parse_args(['-X', 'cdivision=True,c_string_type=bytes'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['directives']))
|
||||
self.assertEqual(options.directives['cdivision'], True)
|
||||
self.assertEqual(options.directives['c_string_type'], 'bytes')
|
||||
|
||||
def test_directive_value_yes(self):
|
||||
options, args = self.parse_args(['-X', 'cdivision=YeS'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['directives']))
|
||||
self.assertEqual(options.directives['cdivision'], True)
|
||||
|
||||
def test_directive_value_no(self):
|
||||
options, args = self.parse_args(['-X', 'cdivision=no'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['directives']))
|
||||
self.assertEqual(options.directives['cdivision'], False)
|
||||
|
||||
def test_directive_value_invalid(self):
|
||||
with self.assertRaises(ValueError) as context:
|
||||
options, args = self.parse_args(['-X', 'cdivision=sadfasd'])
|
||||
|
||||
def test_directive_key_invalid(self):
|
||||
with self.assertRaises(ValueError) as context:
|
||||
options, args = self.parse_args(['-X', 'abracadabra'])
|
||||
|
||||
def test_directive_no_value(self):
|
||||
with self.assertRaises(ValueError) as context:
|
||||
options, args = self.parse_args(['-X', 'cdivision'])
|
||||
|
||||
def test_directives_types(self):
|
||||
directives = {
|
||||
'auto_pickle': True,
|
||||
'c_string_type': 'bytearray',
|
||||
'c_string_type': 'bytes',
|
||||
'c_string_type': 'str',
|
||||
'c_string_type': 'bytearray',
|
||||
'c_string_type': 'unicode',
|
||||
'c_string_encoding' : 'ascii',
|
||||
'language_level' : 2,
|
||||
'language_level' : 3,
|
||||
'language_level' : '3str',
|
||||
'set_initial_path' : 'my_initial_path',
|
||||
}
|
||||
for key, value in directives.items():
|
||||
cmd = '{key}={value}'.format(key=key, value=str(value))
|
||||
options, args = self.parse_args(['-X', cmd])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['directives']), msg = "Error for option: "+cmd)
|
||||
self.assertEqual(options.directives[key], value, msg = "Error for option: "+cmd)
|
||||
|
||||
def test_directives_wrong(self):
|
||||
directives = {
|
||||
'auto_pickle': 42, # for bool type
|
||||
'auto_pickle': 'NONONO', # for bool type
|
||||
'c_string_type': 'bites',
|
||||
#'c_string_encoding' : 'a',
|
||||
#'language_level' : 4,
|
||||
}
|
||||
for key, value in directives.items():
|
||||
cmd = '{key}={value}'.format(key=key, value=str(value))
|
||||
with self.assertRaises(ValueError, msg = "Error for option: "+cmd) as context:
|
||||
options, args = self.parse_args(['-X', cmd])
|
||||
|
||||
def test_compile_time_env_short(self):
|
||||
options, args = self.parse_args(['-E', 'MYSIZE=10'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['compile_time_env']))
|
||||
self.assertEqual(options.compile_time_env['MYSIZE'], 10)
|
||||
|
||||
def test_compile_time_env_long(self):
|
||||
options, args = self.parse_args(['--compile-time-env', 'MYSIZE=10'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['compile_time_env']))
|
||||
self.assertEqual(options.compile_time_env['MYSIZE'], 10)
|
||||
|
||||
def test_compile_time_env_multiple(self):
|
||||
options, args = self.parse_args(['-E', 'MYSIZE=10', '-E', 'ARRSIZE=11'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['compile_time_env']))
|
||||
self.assertEqual(options.compile_time_env['MYSIZE'], 10)
|
||||
self.assertEqual(options.compile_time_env['ARRSIZE'], 11)
|
||||
|
||||
def test_compile_time_env_multiple_v2(self):
|
||||
options, args = self.parse_args(['-E', 'MYSIZE=10,ARRSIZE=11'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['compile_time_env']))
|
||||
self.assertEqual(options.compile_time_env['MYSIZE'], 10)
|
||||
self.assertEqual(options.compile_time_env['ARRSIZE'], 11)
|
||||
|
||||
#testing options
|
||||
def test_option_short(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=True'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
|
||||
def test_option_long(self):
|
||||
options, args = self.parse_args(['--option', 'docstrings=True'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
|
||||
def test_option_multiple(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=True', '-s', 'buffer_max_dims=8'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
self.assertEqual(options.options['buffer_max_dims'], True) # really?
|
||||
|
||||
def test_option_multiple_v2(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=True,buffer_max_dims=8'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
self.assertEqual(options.options['buffer_max_dims'], True) # really?
|
||||
|
||||
def test_option_value_yes(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=YeS'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
|
||||
def test_option_value_4242(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=4242'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
|
||||
def test_option_value_0(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=0'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], False)
|
||||
|
||||
def test_option_value_emptystr(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings='])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
|
||||
def test_option_value_a_str(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=BB'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
|
||||
def test_option_value_no(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings=nO'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], False)
|
||||
|
||||
def test_option_no_value(self):
|
||||
options, args = self.parse_args(['-s', 'docstrings'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['docstrings'], True)
|
||||
|
||||
def test_option_any_key(self):
|
||||
options, args = self.parse_args(['-s', 'abracadabra'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['options']))
|
||||
self.assertEqual(options.options['abracadabra'], True)
|
||||
|
||||
def test_language_level_2(self):
|
||||
options, args = self.parse_args(['-2'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['language_level']))
|
||||
self.assertEqual(options.language_level, 2)
|
||||
|
||||
def test_language_level_3(self):
|
||||
options, args = self.parse_args(['-3'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['language_level']))
|
||||
self.assertEqual(options.language_level, 3)
|
||||
|
||||
def test_language_level_3str(self):
|
||||
options, args = self.parse_args(['--3str'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['language_level']))
|
||||
self.assertEqual(options.language_level, '3str')
|
||||
|
||||
def test_annotate_short(self):
|
||||
options, args = self.parse_args(['-a'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['annotate']))
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
|
||||
def test_annotate_long(self):
|
||||
options, args = self.parse_args(['--annotate'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['annotate']))
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
|
||||
def test_annotate_fullc(self):
|
||||
options, args = self.parse_args(['--annotate-fullc'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['annotate']))
|
||||
self.assertEqual(options.annotate, 'fullc')
|
||||
|
||||
def test_annotate_and_positional(self):
|
||||
options, args = self.parse_args(['-a', 'foo.pyx'])
|
||||
self.assertEqual(args, ['foo.pyx'])
|
||||
self.assertTrue(self.are_default(options, ['annotate']))
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
|
||||
def test_annotate_and_optional(self):
|
||||
options, args = self.parse_args(['-a', '--3str'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['annotate', 'language_level']))
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
self.assertEqual(options.language_level, '3str')
|
||||
|
||||
def test_exclude_short(self):
|
||||
options, args = self.parse_args(['-x', '*.pyx'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['excludes']))
|
||||
self.assertTrue('*.pyx' in options.excludes)
|
||||
|
||||
def test_exclude_long(self):
|
||||
options, args = self.parse_args(['--exclude', '*.pyx'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['excludes']))
|
||||
self.assertTrue('*.pyx' in options.excludes)
|
||||
|
||||
def test_exclude_multiple(self):
|
||||
options, args = self.parse_args(['--exclude', '*.pyx', '--exclude', '*.py', ])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['excludes']))
|
||||
self.assertEqual(options.excludes, ['*.pyx', '*.py'])
|
||||
|
||||
def test_build_short(self):
|
||||
options, args = self.parse_args(['-b'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['build']))
|
||||
self.assertEqual(options.build, True)
|
||||
|
||||
def test_build_long(self):
|
||||
options, args = self.parse_args(['--build'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['build']))
|
||||
self.assertEqual(options.build, True)
|
||||
|
||||
def test_inplace_short(self):
|
||||
options, args = self.parse_args(['-i'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['build_inplace']))
|
||||
self.assertEqual(options.build_inplace, True)
|
||||
|
||||
def test_inplace_long(self):
|
||||
options, args = self.parse_args(['--inplace'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['build_inplace']))
|
||||
self.assertEqual(options.build_inplace, True)
|
||||
|
||||
def test_parallel_short(self):
|
||||
options, args = self.parse_args(['-j', '42'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['parallel']))
|
||||
self.assertEqual(options.parallel, 42)
|
||||
|
||||
def test_parallel_long(self):
|
||||
options, args = self.parse_args(['--parallel', '42'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['parallel']))
|
||||
self.assertEqual(options.parallel, 42)
|
||||
|
||||
def test_force_short(self):
|
||||
options, args = self.parse_args(['-f'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['force']))
|
||||
self.assertEqual(options.force, True)
|
||||
|
||||
def test_force_long(self):
|
||||
options, args = self.parse_args(['--force'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['force']))
|
||||
self.assertEqual(options.force, True)
|
||||
|
||||
def test_quite_short(self):
|
||||
options, args = self.parse_args(['-q'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['quiet']))
|
||||
self.assertEqual(options.quiet, True)
|
||||
|
||||
def test_quite_long(self):
|
||||
options, args = self.parse_args(['--quiet'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['quiet']))
|
||||
self.assertEqual(options.quiet, True)
|
||||
|
||||
def test_lenient_long(self):
|
||||
options, args = self.parse_args(['--lenient'])
|
||||
self.assertTrue(self.are_default(options, ['lenient']))
|
||||
self.assertFalse(args)
|
||||
self.assertEqual(options.lenient, True)
|
||||
|
||||
def test_keep_going_short(self):
|
||||
options, args = self.parse_args(['-k'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['keep_going']))
|
||||
self.assertEqual(options.keep_going, True)
|
||||
|
||||
def test_keep_going_long(self):
|
||||
options, args = self.parse_args(['--keep-going'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['keep_going']))
|
||||
self.assertEqual(options.keep_going, True)
|
||||
|
||||
def test_no_docstrings_long(self):
|
||||
options, args = self.parse_args(['--no-docstrings'])
|
||||
self.assertFalse(args)
|
||||
self.assertTrue(self.are_default(options, ['no_docstrings']))
|
||||
self.assertEqual(options.no_docstrings, True)
|
||||
|
||||
def test_file_name(self):
|
||||
options, args = self.parse_args(['file1.pyx', 'file2.pyx'])
|
||||
self.assertEqual(len(args), 2)
|
||||
self.assertEqual(args[0], 'file1.pyx')
|
||||
self.assertEqual(args[1], 'file2.pyx')
|
||||
self.assertTrue(self.are_default(options, []))
|
||||
|
||||
def test_option_first(self):
|
||||
options, args = self.parse_args(['-i', 'file.pyx'])
|
||||
self.assertEqual(args, ['file.pyx'])
|
||||
self.assertEqual(options.build_inplace, True)
|
||||
self.assertTrue(self.are_default(options, ['build_inplace']))
|
||||
|
||||
def test_file_inbetween(self):
|
||||
options, args = self.parse_args(['-i', 'file.pyx', '-a'])
|
||||
self.assertEqual(args, ['file.pyx'])
|
||||
self.assertEqual(options.build_inplace, True)
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
self.assertTrue(self.are_default(options, ['build_inplace', 'annotate']))
|
||||
|
||||
def test_option_trailing(self):
|
||||
options, args = self.parse_args(['file.pyx', '-i'])
|
||||
self.assertEqual(args, ['file.pyx'])
|
||||
self.assertEqual(options.build_inplace, True)
|
||||
self.assertTrue(self.are_default(options, ['build_inplace']))
|
||||
|
||||
def test_interspersed_positional(self):
|
||||
options, sources = self.parse_args([
|
||||
'file1.pyx', '-a',
|
||||
'file2.pyx'
|
||||
])
|
||||
self.assertEqual(sources, ['file1.pyx', 'file2.pyx'])
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
self.assertTrue(self.are_default(options, ['annotate']))
|
||||
|
||||
def test_interspersed_positional2(self):
|
||||
options, sources = self.parse_args([
|
||||
'file1.pyx', '-a',
|
||||
'file2.pyx', '-a', 'file3.pyx'
|
||||
])
|
||||
self.assertEqual(sources, ['file1.pyx', 'file2.pyx', 'file3.pyx'])
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
self.assertTrue(self.are_default(options, ['annotate']))
|
||||
|
||||
def test_interspersed_positional3(self):
|
||||
options, sources = self.parse_args([
|
||||
'-f', 'f1', 'f2', '-a',
|
||||
'f3', 'f4', '-a', 'f5'
|
||||
])
|
||||
self.assertEqual(sources, ['f1', 'f2', 'f3', 'f4', 'f5'])
|
||||
self.assertEqual(options.annotate, 'default')
|
||||
self.assertEqual(options.force, True)
|
||||
self.assertTrue(self.are_default(options, ['annotate', 'force']))
|
||||
|
||||
def test_wrong_option(self):
|
||||
old_stderr = sys.stderr
|
||||
stderr = sys.stderr = StringIO()
|
||||
try:
|
||||
self.assertRaises(SystemExit, self.parse_args,
|
||||
['--unknown-option']
|
||||
)
|
||||
finally:
|
||||
sys.stderr = old_stderr
|
||||
self.assertTrue(stderr.getvalue())
|
||||
|
||||
|
||||
class TestParseArgs(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 test_build_set_for_inplace(self):
|
||||
options, args = parse_args(['foo.pyx', '-i'])
|
||||
self.assertEqual(options.build, True)
|
||||
self.check_default_global_options()
|
||||
|
||||
def test_lenient(self):
|
||||
options, sources = parse_args(['foo.pyx', '--lenient'])
|
||||
self.assertEqual(sources, ['foo.pyx'])
|
||||
self.assertEqual(Options.error_on_unknown_names, False)
|
||||
self.assertEqual(Options.error_on_uninitialized, False)
|
||||
self.check_default_global_options(['error_on_unknown_names', 'error_on_uninitialized'])
|
||||
|
||||
def test_annotate(self):
|
||||
options, sources = parse_args(['foo.pyx', '--annotate'])
|
||||
self.assertEqual(sources, ['foo.pyx'])
|
||||
self.assertEqual(Options.annotate, 'default')
|
||||
self.check_default_global_options(['annotate'])
|
||||
|
||||
def test_annotate_fullc(self):
|
||||
options, sources = parse_args(['foo.pyx', '--annotate-fullc'])
|
||||
self.assertEqual(sources, ['foo.pyx'])
|
||||
self.assertEqual(Options.annotate, 'fullc')
|
||||
self.check_default_global_options(['annotate'])
|
||||
|
||||
def test_no_docstrings(self):
|
||||
options, sources = parse_args(['foo.pyx', '--no-docstrings'])
|
||||
self.assertEqual(sources, ['foo.pyx'])
|
||||
self.assertEqual(Options.docstrings, False)
|
||||
self.check_default_global_options(['docstrings'])
|
||||
@ -0,0 +1,142 @@
|
||||
import contextlib
|
||||
import os.path
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from io import open
|
||||
from os.path import join as pjoin
|
||||
|
||||
from ..Dependencies import extended_iglob
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def writable_file(dir_path, filename):
|
||||
with open(pjoin(dir_path, filename), "w", encoding="utf8") as f:
|
||||
yield f
|
||||
|
||||
|
||||
class TestGlobbing(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls._orig_dir = os.getcwd()
|
||||
if sys.version_info[0] < 3:
|
||||
temp_path = cls._tmpdir = tempfile.mkdtemp()
|
||||
else:
|
||||
cls._tmpdir = tempfile.TemporaryDirectory()
|
||||
temp_path = cls._tmpdir.name
|
||||
os.chdir(temp_path)
|
||||
|
||||
for dir1 in "abcd":
|
||||
for dir1x in [dir1, dir1 + 'x']:
|
||||
for dir2 in "xyz":
|
||||
dir_path = pjoin(dir1x, dir2)
|
||||
os.makedirs(dir_path)
|
||||
with writable_file(dir_path, "file2_pyx.pyx") as f:
|
||||
f.write(u'""" PYX """')
|
||||
with writable_file(dir_path, "file2_py.py") as f:
|
||||
f.write(u'""" PY """')
|
||||
|
||||
with writable_file(dir1x, "file1_pyx.pyx") as f:
|
||||
f.write(u'""" PYX """')
|
||||
with writable_file(dir1x, "file1_py.py") as f:
|
||||
f.write(u'""" PY """')
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
os.chdir(cls._orig_dir)
|
||||
if sys.version_info[0] < 3:
|
||||
import shutil
|
||||
shutil.rmtree(cls._tmpdir)
|
||||
else:
|
||||
cls._tmpdir.cleanup()
|
||||
|
||||
def files_equal(self, pattern, expected_files):
|
||||
expected_files = sorted(expected_files)
|
||||
# It's the users's choice whether '/' will appear on Windows.
|
||||
matched_files = sorted(path.replace('/', os.sep) for path in extended_iglob(pattern))
|
||||
self.assertListEqual(matched_files, expected_files) # /
|
||||
|
||||
# Special case for Windows: also support '\' in patterns.
|
||||
if os.sep == '\\' and '/' in pattern:
|
||||
matched_files = sorted(extended_iglob(pattern.replace('/', '\\')))
|
||||
self.assertListEqual(matched_files, expected_files) # \
|
||||
|
||||
def test_extended_iglob_simple(self):
|
||||
ax_files = [pjoin("a", "x", "file2_pyx.pyx"), pjoin("a", "x", "file2_py.py")]
|
||||
self.files_equal("a/x/*", ax_files)
|
||||
self.files_equal("a/x/*.c12", [])
|
||||
self.files_equal("a/x/*.{py,pyx,c12}", ax_files)
|
||||
self.files_equal("a/x/*.{py,pyx}", ax_files)
|
||||
self.files_equal("a/x/*.{pyx}", ax_files[:1])
|
||||
self.files_equal("a/x/*.pyx", ax_files[:1])
|
||||
self.files_equal("a/x/*.{py}", ax_files[1:])
|
||||
self.files_equal("a/x/*.py", ax_files[1:])
|
||||
|
||||
def test_extended_iglob_simple_star(self):
|
||||
for basedir in "ad":
|
||||
files = [
|
||||
pjoin(basedir, dirname, filename)
|
||||
for dirname in "xyz"
|
||||
for filename in ["file2_pyx.pyx", "file2_py.py"]
|
||||
]
|
||||
self.files_equal(basedir + "/*/*", files)
|
||||
self.files_equal(basedir + "/*/*.c12", [])
|
||||
self.files_equal(basedir + "/*/*.{py,pyx,c12}", files)
|
||||
self.files_equal(basedir + "/*/*.{py,pyx}", files)
|
||||
self.files_equal(basedir + "/*/*.{pyx}", files[::2])
|
||||
self.files_equal(basedir + "/*/*.pyx", files[::2])
|
||||
self.files_equal(basedir + "/*/*.{py}", files[1::2])
|
||||
self.files_equal(basedir + "/*/*.py", files[1::2])
|
||||
|
||||
for subdir in "xy*":
|
||||
files = [
|
||||
pjoin(basedir, dirname, filename)
|
||||
for dirname in "xyz"
|
||||
if subdir in ('*', dirname)
|
||||
for filename in ["file2_pyx.pyx", "file2_py.py"]
|
||||
]
|
||||
path = basedir + '/' + subdir + '/'
|
||||
self.files_equal(path + "*", files)
|
||||
self.files_equal(path + "*.{py,pyx}", files)
|
||||
self.files_equal(path + "*.{pyx}", files[::2])
|
||||
self.files_equal(path + "*.pyx", files[::2])
|
||||
self.files_equal(path + "*.{py}", files[1::2])
|
||||
self.files_equal(path + "*.py", files[1::2])
|
||||
|
||||
def test_extended_iglob_double_star(self):
|
||||
basedirs = os.listdir(".")
|
||||
files = [
|
||||
pjoin(basedir, dirname, filename)
|
||||
for basedir in basedirs
|
||||
for dirname in "xyz"
|
||||
for filename in ["file2_pyx.pyx", "file2_py.py"]
|
||||
]
|
||||
all_files = [
|
||||
pjoin(basedir, filename)
|
||||
for basedir in basedirs
|
||||
for filename in ["file1_pyx.pyx", "file1_py.py"]
|
||||
] + files
|
||||
self.files_equal("*/*/*", files)
|
||||
self.files_equal("*/*/**/*", files)
|
||||
self.files_equal("*/**/*.*", all_files)
|
||||
self.files_equal("**/*.*", all_files)
|
||||
self.files_equal("*/**/*.c12", [])
|
||||
self.files_equal("**/*.c12", [])
|
||||
self.files_equal("*/*/*.{py,pyx,c12}", files)
|
||||
self.files_equal("*/*/**/*.{py,pyx,c12}", files)
|
||||
self.files_equal("*/**/*/*.{py,pyx,c12}", files)
|
||||
self.files_equal("**/*/*/*.{py,pyx,c12}", files)
|
||||
self.files_equal("**/*.{py,pyx,c12}", all_files)
|
||||
self.files_equal("*/*/*.{py,pyx}", files)
|
||||
self.files_equal("**/*/*/*.{py,pyx}", files)
|
||||
self.files_equal("*/**/*/*.{py,pyx}", files)
|
||||
self.files_equal("**/*.{py,pyx}", all_files)
|
||||
self.files_equal("*/*/*.{pyx}", files[::2])
|
||||
self.files_equal("**/*.{pyx}", all_files[::2])
|
||||
self.files_equal("*/**/*/*.pyx", files[::2])
|
||||
self.files_equal("*/*/*.pyx", files[::2])
|
||||
self.files_equal("**/*.pyx", all_files[::2])
|
||||
self.files_equal("*/*/*.{py}", files[1::2])
|
||||
self.files_equal("**/*.{py}", all_files[1::2])
|
||||
self.files_equal("*/*/*.py", files[1::2])
|
||||
self.files_equal("**/*.py", all_files[1::2])
|
||||
@ -0,0 +1,112 @@
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from Cython.Shadow import inline
|
||||
from Cython.Build.Inline import safe_type
|
||||
from Cython.TestUtils import CythonTest
|
||||
|
||||
try:
|
||||
import numpy
|
||||
has_numpy = True
|
||||
except:
|
||||
has_numpy = False
|
||||
|
||||
test_kwds = dict(force=True, quiet=True)
|
||||
|
||||
global_value = 100
|
||||
|
||||
class TestInline(CythonTest):
|
||||
def setUp(self):
|
||||
CythonTest.setUp(self)
|
||||
self._call_kwds = dict(test_kwds)
|
||||
if os.path.isdir('TEST_TMP'):
|
||||
lib_dir = os.path.join('TEST_TMP','inline')
|
||||
else:
|
||||
lib_dir = tempfile.mkdtemp(prefix='cython_inline_')
|
||||
self._call_kwds['lib_dir'] = lib_dir
|
||||
|
||||
def test_simple(self):
|
||||
self.assertEqual(inline("return 1+2", **self._call_kwds), 3)
|
||||
|
||||
def test_types(self):
|
||||
self.assertEqual(inline("""
|
||||
cimport cython
|
||||
return cython.typeof(a), cython.typeof(b)
|
||||
""", a=1.0, b=[], **self._call_kwds), ('double', 'list object'))
|
||||
|
||||
def test_locals(self):
|
||||
a = 1
|
||||
b = 2
|
||||
self.assertEqual(inline("return a+b", **self._call_kwds), 3)
|
||||
|
||||
def test_globals(self):
|
||||
self.assertEqual(inline("return global_value + 1", **self._call_kwds), global_value + 1)
|
||||
|
||||
def test_no_return(self):
|
||||
self.assertEqual(inline("""
|
||||
a = 1
|
||||
cdef double b = 2
|
||||
cdef c = []
|
||||
""", **self._call_kwds), dict(a=1, b=2.0, c=[]))
|
||||
|
||||
def test_def_node(self):
|
||||
foo = inline("def foo(x): return x * x", **self._call_kwds)['foo']
|
||||
self.assertEqual(foo(7), 49)
|
||||
|
||||
def test_class_ref(self):
|
||||
class Type(object):
|
||||
pass
|
||||
tp = inline("Type")['Type']
|
||||
self.assertEqual(tp, Type)
|
||||
|
||||
def test_pure(self):
|
||||
import cython as cy
|
||||
b = inline("""
|
||||
b = cy.declare(float, a)
|
||||
c = cy.declare(cy.pointer(cy.float), &b)
|
||||
return b
|
||||
""", a=3, **self._call_kwds)
|
||||
self.assertEqual(type(b), float)
|
||||
|
||||
def test_compiler_directives(self):
|
||||
self.assertEqual(
|
||||
inline('return sum(x)',
|
||||
x=[1, 2, 3],
|
||||
cython_compiler_directives={'boundscheck': False}),
|
||||
6
|
||||
)
|
||||
|
||||
def test_lang_version(self):
|
||||
# GH-3419. Caching for inline code didn't always respect compiler directives.
|
||||
inline_divcode = "def f(int a, int b): return a/b"
|
||||
self.assertEqual(
|
||||
inline(inline_divcode, language_level=2)['f'](5,2),
|
||||
2
|
||||
)
|
||||
self.assertEqual(
|
||||
inline(inline_divcode, language_level=3)['f'](5,2),
|
||||
2.5
|
||||
)
|
||||
self.assertEqual(
|
||||
inline(inline_divcode, language_level=2)['f'](5,2),
|
||||
2
|
||||
)
|
||||
|
||||
def test_repeated_use(self):
|
||||
inline_mulcode = "def f(int a, int b): return a * b"
|
||||
self.assertEqual(inline(inline_mulcode)['f'](5, 2), 10)
|
||||
self.assertEqual(inline(inline_mulcode)['f'](5, 3), 15)
|
||||
self.assertEqual(inline(inline_mulcode)['f'](6, 2), 12)
|
||||
self.assertEqual(inline(inline_mulcode)['f'](5, 2), 10)
|
||||
|
||||
f = inline(inline_mulcode)['f']
|
||||
self.assertEqual(f(5, 2), 10)
|
||||
self.assertEqual(f(5, 3), 15)
|
||||
|
||||
@unittest.skipIf(not has_numpy, "NumPy is not available")
|
||||
def test_numpy(self):
|
||||
import numpy
|
||||
a = numpy.ndarray((10, 20))
|
||||
a[0,0] = 10
|
||||
self.assertEqual(safe_type(a), 'numpy.ndarray[numpy.float64_t, ndim=2]')
|
||||
self.assertEqual(inline("return a[0,0]", a=a, **self._call_kwds), 10.0)
|
||||
@ -0,0 +1,295 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# tag: ipython
|
||||
|
||||
"""Tests for the Cython magics extension."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import io
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from unittest import skipIf
|
||||
|
||||
from Cython.Build import IpythonMagic
|
||||
from Cython.TestUtils import CythonTest
|
||||
from Cython.Compiler.Annotate import AnnotationCCodeWriter
|
||||
|
||||
try:
|
||||
import IPython.testing.globalipapp
|
||||
except ImportError:
|
||||
# Disable tests and fake helpers for initialisation below.
|
||||
def skip_if_not_installed(_):
|
||||
return None
|
||||
else:
|
||||
def skip_if_not_installed(c):
|
||||
return c
|
||||
|
||||
# not using IPython's decorators here because they depend on "nose"
|
||||
skip_win32 = skipIf(sys.platform == 'win32', "Skip on Windows")
|
||||
skip_py27 = skipIf(sys.version_info[:2] == (2,7), "Disabled in Py2.7")
|
||||
|
||||
try:
|
||||
# disable IPython history thread before it gets started to avoid having to clean it up
|
||||
from IPython.core.history import HistoryManager
|
||||
HistoryManager.enabled = False
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
@contextmanager
|
||||
def capture_output():
|
||||
backup = sys.stdout, sys.stderr
|
||||
try:
|
||||
replacement = [
|
||||
io.TextIOWrapper(io.BytesIO(), encoding=sys.stdout.encoding),
|
||||
io.TextIOWrapper(io.BytesIO(), encoding=sys.stderr.encoding),
|
||||
]
|
||||
sys.stdout, sys.stderr = replacement
|
||||
output = []
|
||||
yield output
|
||||
finally:
|
||||
sys.stdout, sys.stderr = backup
|
||||
for wrapper in replacement:
|
||||
wrapper.seek(0) # rewind
|
||||
output.append(wrapper.read())
|
||||
wrapper.close()
|
||||
|
||||
|
||||
code = u"""\
|
||||
def f(x):
|
||||
return 2*x
|
||||
"""
|
||||
|
||||
cython3_code = u"""\
|
||||
def f(int x):
|
||||
return 2 / x
|
||||
|
||||
def call(x):
|
||||
return f(*(x,))
|
||||
"""
|
||||
|
||||
pgo_cython3_code = cython3_code + u"""\
|
||||
def main():
|
||||
for _ in range(100): call(5)
|
||||
main()
|
||||
"""
|
||||
|
||||
compile_error_code = u'''\
|
||||
cdef extern from *:
|
||||
"""
|
||||
xxx a=1;
|
||||
"""
|
||||
int a;
|
||||
def doit():
|
||||
return a
|
||||
'''
|
||||
|
||||
compile_warning_code = u'''\
|
||||
cdef extern from *:
|
||||
"""
|
||||
#pragma message ( "CWarning" )
|
||||
int a = 42;
|
||||
"""
|
||||
int a;
|
||||
def doit():
|
||||
return a
|
||||
'''
|
||||
|
||||
|
||||
@skip_if_not_installed
|
||||
class TestIPythonMagic(CythonTest):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
CythonTest.setUpClass()
|
||||
cls._ip = IPython.testing.globalipapp.get_ipython()
|
||||
|
||||
def setUp(self):
|
||||
CythonTest.setUp(self)
|
||||
self._ip.extension_manager.load_extension('cython')
|
||||
|
||||
def test_cython_inline(self):
|
||||
ip = self._ip
|
||||
ip.ex('a=10; b=20')
|
||||
result = ip.run_cell_magic('cython_inline', '', 'return a+b')
|
||||
self.assertEqual(result, 30)
|
||||
|
||||
@skip_win32
|
||||
def test_cython_pyximport(self):
|
||||
ip = self._ip
|
||||
module_name = '_test_cython_pyximport'
|
||||
ip.run_cell_magic('cython_pyximport', module_name, code)
|
||||
ip.ex('g = f(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 20.0)
|
||||
ip.run_cell_magic('cython_pyximport', module_name, code)
|
||||
ip.ex('h = f(-10)')
|
||||
self.assertEqual(ip.user_ns['h'], -20.0)
|
||||
try:
|
||||
os.remove(module_name + '.pyx')
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def test_cython(self):
|
||||
ip = self._ip
|
||||
ip.run_cell_magic('cython', '', code)
|
||||
ip.ex('g = f(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 20.0)
|
||||
|
||||
def test_cython_name(self):
|
||||
# The Cython module named 'mymodule' defines the function f.
|
||||
ip = self._ip
|
||||
ip.run_cell_magic('cython', '--name=mymodule', code)
|
||||
# This module can now be imported in the interactive namespace.
|
||||
ip.ex('import mymodule; g = mymodule.f(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 20.0)
|
||||
|
||||
def test_cython_language_level(self):
|
||||
# The Cython cell defines the functions f() and call().
|
||||
ip = self._ip
|
||||
ip.run_cell_magic('cython', '', cython3_code)
|
||||
ip.ex('g = f(10); h = call(10)')
|
||||
if sys.version_info[0] < 3:
|
||||
self.assertEqual(ip.user_ns['g'], 2 // 10)
|
||||
self.assertEqual(ip.user_ns['h'], 2 // 10)
|
||||
else:
|
||||
self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
|
||||
self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
|
||||
|
||||
def test_cython3(self):
|
||||
# The Cython cell defines the functions f() and call().
|
||||
ip = self._ip
|
||||
ip.run_cell_magic('cython', '-3', cython3_code)
|
||||
ip.ex('g = f(10); h = call(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
|
||||
self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
|
||||
|
||||
def test_cython2(self):
|
||||
# The Cython cell defines the functions f() and call().
|
||||
ip = self._ip
|
||||
ip.run_cell_magic('cython', '-2', cython3_code)
|
||||
ip.ex('g = f(10); h = call(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 2 // 10)
|
||||
self.assertEqual(ip.user_ns['h'], 2 // 10)
|
||||
|
||||
def test_cython_compile_error_shown(self):
|
||||
ip = self._ip
|
||||
with capture_output() as out:
|
||||
ip.run_cell_magic('cython', '-3', compile_error_code)
|
||||
captured_out, captured_err = out
|
||||
|
||||
# it could be that c-level output is captured by distutil-extension
|
||||
# (and not by us) and is printed to stdout:
|
||||
captured_all = captured_out + "\n" + captured_err
|
||||
self.assertTrue("error" in captured_all, msg="error in " + captured_all)
|
||||
|
||||
def test_cython_link_error_shown(self):
|
||||
ip = self._ip
|
||||
with capture_output() as out:
|
||||
ip.run_cell_magic('cython', '-3 -l=xxxxxxxx', code)
|
||||
captured_out, captured_err = out
|
||||
|
||||
# it could be that c-level output is captured by distutil-extension
|
||||
# (and not by us) and is printed to stdout:
|
||||
captured_all = captured_out + "\n!" + captured_err
|
||||
self.assertTrue("error" in captured_all, msg="error in " + captured_all)
|
||||
|
||||
def test_cython_warning_shown(self):
|
||||
ip = self._ip
|
||||
with capture_output() as out:
|
||||
# force rebuild, otherwise no warning as after the first success
|
||||
# no build step is performed
|
||||
ip.run_cell_magic('cython', '-3 -f', compile_warning_code)
|
||||
captured_out, captured_err = out
|
||||
|
||||
# check that warning was printed to stdout even if build hasn't failed
|
||||
self.assertTrue("CWarning" in captured_out)
|
||||
|
||||
@skip_py27 # Not strictly broken in Py2.7 but currently fails in CI due to C compiler issues.
|
||||
@skip_win32
|
||||
def test_cython3_pgo(self):
|
||||
# The Cython cell defines the functions f() and call().
|
||||
ip = self._ip
|
||||
ip.run_cell_magic('cython', '-3 --pgo', pgo_cython3_code)
|
||||
ip.ex('g = f(10); h = call(10); main()')
|
||||
self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
|
||||
self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
|
||||
|
||||
@skip_win32
|
||||
def test_extlibs(self):
|
||||
ip = self._ip
|
||||
code = u"""
|
||||
from libc.math cimport sin
|
||||
x = sin(0.0)
|
||||
"""
|
||||
ip.user_ns['x'] = 1
|
||||
ip.run_cell_magic('cython', '-l m', code)
|
||||
self.assertEqual(ip.user_ns['x'], 0)
|
||||
|
||||
|
||||
def test_cython_verbose(self):
|
||||
ip = self._ip
|
||||
ip.run_cell_magic('cython', '--verbose', code)
|
||||
ip.ex('g = f(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 20.0)
|
||||
|
||||
def test_cython_verbose_thresholds(self):
|
||||
@contextmanager
|
||||
def mock_distutils():
|
||||
class MockLog:
|
||||
DEBUG = 1
|
||||
INFO = 2
|
||||
thresholds = [INFO]
|
||||
|
||||
def set_threshold(self, val):
|
||||
self.thresholds.append(val)
|
||||
return self.thresholds[-2]
|
||||
|
||||
|
||||
new_log = MockLog()
|
||||
old_log = IpythonMagic.distutils.log
|
||||
try:
|
||||
IpythonMagic.distutils.log = new_log
|
||||
yield new_log
|
||||
finally:
|
||||
IpythonMagic.distutils.log = old_log
|
||||
|
||||
ip = self._ip
|
||||
with mock_distutils() as verbose_log:
|
||||
ip.run_cell_magic('cython', '--verbose', code)
|
||||
ip.ex('g = f(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 20.0)
|
||||
self.assertEqual([verbose_log.INFO, verbose_log.DEBUG, verbose_log.INFO],
|
||||
verbose_log.thresholds)
|
||||
|
||||
with mock_distutils() as normal_log:
|
||||
ip.run_cell_magic('cython', '', code)
|
||||
ip.ex('g = f(10)')
|
||||
self.assertEqual(ip.user_ns['g'], 20.0)
|
||||
self.assertEqual([normal_log.INFO], normal_log.thresholds)
|
||||
|
||||
def test_cython_no_annotate(self):
|
||||
ip = self._ip
|
||||
html = ip.run_cell_magic('cython', '', code)
|
||||
self.assertTrue(html is None)
|
||||
|
||||
def test_cython_annotate(self):
|
||||
ip = self._ip
|
||||
html = ip.run_cell_magic('cython', '--annotate', code)
|
||||
# somewhat brittle way to differentiate between annotated htmls
|
||||
# with/without complete source code:
|
||||
self.assertTrue(AnnotationCCodeWriter.COMPLETE_CODE_TITLE not in html.data)
|
||||
|
||||
def test_cython_annotate_default(self):
|
||||
ip = self._ip
|
||||
html = ip.run_cell_magic('cython', '-a', code)
|
||||
# somewhat brittle way to differentiate between annotated htmls
|
||||
# with/without complete source code:
|
||||
self.assertTrue(AnnotationCCodeWriter.COMPLETE_CODE_TITLE not in html.data)
|
||||
|
||||
def test_cython_annotate_complete_c_code(self):
|
||||
ip = self._ip
|
||||
html = ip.run_cell_magic('cython', '--annotate-fullc', code)
|
||||
# somewhat brittle way to differentiate between annotated htmls
|
||||
# with/without complete source code:
|
||||
self.assertTrue(AnnotationCCodeWriter.COMPLETE_CODE_TITLE in html.data)
|
||||
@ -0,0 +1,212 @@
|
||||
import shutil
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import Cython.Build.Dependencies
|
||||
import Cython.Utils
|
||||
from Cython.TestUtils import CythonTest
|
||||
|
||||
|
||||
def fresh_cythonize(*args, **kwargs):
|
||||
Cython.Utils.clear_function_caches()
|
||||
Cython.Build.Dependencies._dep_tree = None # discard method caches
|
||||
Cython.Build.Dependencies.cythonize(*args, **kwargs)
|
||||
|
||||
class TestRecythonize(CythonTest):
|
||||
|
||||
def setUp(self):
|
||||
CythonTest.setUp(self)
|
||||
self.temp_dir = (
|
||||
tempfile.mkdtemp(
|
||||
prefix='recythonize-test',
|
||||
dir='TEST_TMP' if os.path.isdir('TEST_TMP') else None
|
||||
)
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
CythonTest.tearDown(self)
|
||||
shutil.rmtree(self.temp_dir)
|
||||
|
||||
def test_recythonize_pyx_on_pxd_change(self):
|
||||
|
||||
src_dir = tempfile.mkdtemp(prefix='src', dir=self.temp_dir)
|
||||
|
||||
a_pxd = os.path.join(src_dir, 'a.pxd')
|
||||
a_pyx = os.path.join(src_dir, 'a.pyx')
|
||||
a_c = os.path.join(src_dir, 'a.c')
|
||||
dep_tree = Cython.Build.Dependencies.create_dependency_tree()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef int value\n')
|
||||
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write('value = 1\n')
|
||||
|
||||
|
||||
# The dependencies for "a.pyx" are "a.pxd" and "a.pyx".
|
||||
self.assertEqual({a_pxd, a_pyx}, dep_tree.all_dependencies(a_pyx))
|
||||
|
||||
# Cythonize to create a.c
|
||||
fresh_cythonize(a_pyx)
|
||||
|
||||
# Sleep to address coarse time-stamp precision.
|
||||
time.sleep(1)
|
||||
|
||||
with open(a_c) as f:
|
||||
a_c_contents1 = f.read()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef double value\n')
|
||||
|
||||
fresh_cythonize(a_pyx)
|
||||
|
||||
with open(a_c) as f:
|
||||
a_c_contents2 = f.read()
|
||||
|
||||
self.assertTrue("__pyx_v_1a_value = 1;" in a_c_contents1)
|
||||
self.assertFalse("__pyx_v_1a_value = 1;" in a_c_contents2)
|
||||
self.assertTrue("__pyx_v_1a_value = 1.0;" in a_c_contents2)
|
||||
self.assertFalse("__pyx_v_1a_value = 1.0;" in a_c_contents1)
|
||||
|
||||
|
||||
def test_recythonize_py_on_pxd_change(self):
|
||||
|
||||
src_dir = tempfile.mkdtemp(prefix='src', dir=self.temp_dir)
|
||||
|
||||
a_pxd = os.path.join(src_dir, 'a.pxd')
|
||||
a_py = os.path.join(src_dir, 'a.py')
|
||||
a_c = os.path.join(src_dir, 'a.c')
|
||||
dep_tree = Cython.Build.Dependencies.create_dependency_tree()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef int value\n')
|
||||
|
||||
with open(a_py, 'w') as f:
|
||||
f.write('value = 1\n')
|
||||
|
||||
|
||||
# The dependencies for "a.py" are "a.pxd" and "a.py".
|
||||
self.assertEqual({a_pxd, a_py}, dep_tree.all_dependencies(a_py))
|
||||
|
||||
# Cythonize to create a.c
|
||||
fresh_cythonize(a_py)
|
||||
|
||||
# Sleep to address coarse time-stamp precision.
|
||||
time.sleep(1)
|
||||
|
||||
with open(a_c) as f:
|
||||
a_c_contents1 = f.read()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef double value\n')
|
||||
|
||||
fresh_cythonize(a_py)
|
||||
|
||||
with open(a_c) as f:
|
||||
a_c_contents2 = f.read()
|
||||
|
||||
|
||||
self.assertTrue("__pyx_v_1a_value = 1;" in a_c_contents1)
|
||||
self.assertFalse("__pyx_v_1a_value = 1;" in a_c_contents2)
|
||||
self.assertTrue("__pyx_v_1a_value = 1.0;" in a_c_contents2)
|
||||
self.assertFalse("__pyx_v_1a_value = 1.0;" in a_c_contents1)
|
||||
|
||||
def test_recythonize_pyx_on_dep_pxd_change(self):
|
||||
src_dir = tempfile.mkdtemp(prefix='src', dir=self.temp_dir)
|
||||
|
||||
a_pxd = os.path.join(src_dir, 'a.pxd')
|
||||
a_pyx = os.path.join(src_dir, 'a.pyx')
|
||||
b_pyx = os.path.join(src_dir, 'b.pyx')
|
||||
b_c = os.path.join(src_dir, 'b.c')
|
||||
dep_tree = Cython.Build.Dependencies.create_dependency_tree()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef int value\n')
|
||||
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write('value = 1\n')
|
||||
|
||||
with open(b_pyx, 'w') as f:
|
||||
f.write('cimport a\n' + 'a.value = 2\n')
|
||||
|
||||
|
||||
# The dependencies for "b.pyx" are "a.pxd" and "b.pyx".
|
||||
self.assertEqual({a_pxd, b_pyx}, dep_tree.all_dependencies(b_pyx))
|
||||
|
||||
|
||||
# Cythonize to create b.c
|
||||
fresh_cythonize([a_pyx, b_pyx])
|
||||
|
||||
# Sleep to address coarse time-stamp precision.
|
||||
time.sleep(1)
|
||||
|
||||
with open(b_c) as f:
|
||||
b_c_contents1 = f.read()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef double value\n')
|
||||
|
||||
fresh_cythonize([a_pyx, b_pyx])
|
||||
|
||||
with open(b_c) as f:
|
||||
b_c_contents2 = f.read()
|
||||
|
||||
|
||||
|
||||
self.assertTrue("__pyx_v_1a_value = 2;" in b_c_contents1)
|
||||
self.assertFalse("__pyx_v_1a_value = 2;" in b_c_contents2)
|
||||
self.assertTrue("__pyx_v_1a_value = 2.0;" in b_c_contents2)
|
||||
self.assertFalse("__pyx_v_1a_value = 2.0;" in b_c_contents1)
|
||||
|
||||
|
||||
|
||||
def test_recythonize_py_on_dep_pxd_change(self):
|
||||
|
||||
src_dir = tempfile.mkdtemp(prefix='src', dir=self.temp_dir)
|
||||
|
||||
a_pxd = os.path.join(src_dir, 'a.pxd')
|
||||
a_pyx = os.path.join(src_dir, 'a.pyx')
|
||||
b_pxd = os.path.join(src_dir, 'b.pxd')
|
||||
b_py = os.path.join(src_dir, 'b.py')
|
||||
b_c = os.path.join(src_dir, 'b.c')
|
||||
dep_tree = Cython.Build.Dependencies.create_dependency_tree()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef int value\n')
|
||||
|
||||
with open(a_pyx, 'w') as f:
|
||||
f.write('value = 1\n')
|
||||
|
||||
with open(b_pxd, 'w') as f:
|
||||
f.write('cimport a\n')
|
||||
|
||||
with open(b_py, 'w') as f:
|
||||
f.write('a.value = 2\n')
|
||||
|
||||
|
||||
# The dependencies for b.py are "a.pxd", "b.pxd" and "b.py".
|
||||
self.assertEqual({a_pxd, b_pxd, b_py}, dep_tree.all_dependencies(b_py))
|
||||
|
||||
|
||||
# Cythonize to create b.c
|
||||
fresh_cythonize([a_pyx, b_py])
|
||||
|
||||
# Sleep to address coarse time-stamp precision.
|
||||
time.sleep(1)
|
||||
|
||||
with open(b_c) as f:
|
||||
b_c_contents1 = f.read()
|
||||
|
||||
with open(a_pxd, 'w') as f:
|
||||
f.write('cdef double value\n')
|
||||
|
||||
fresh_cythonize([a_pyx, b_py])
|
||||
|
||||
with open(b_c) as f:
|
||||
b_c_contents2 = f.read()
|
||||
|
||||
self.assertTrue("__pyx_v_1a_value = 2;" in b_c_contents1)
|
||||
self.assertFalse("__pyx_v_1a_value = 2;" in b_c_contents2)
|
||||
self.assertTrue("__pyx_v_1a_value = 2.0;" in b_c_contents2)
|
||||
self.assertFalse("__pyx_v_1a_value = 2.0;" in b_c_contents1)
|
||||
@ -0,0 +1,56 @@
|
||||
from Cython.Build.Dependencies import strip_string_literals
|
||||
|
||||
from Cython.TestUtils import CythonTest
|
||||
|
||||
class TestStripLiterals(CythonTest):
|
||||
|
||||
def t(self, before, expected):
|
||||
actual, literals = strip_string_literals(before, prefix="_L")
|
||||
self.assertEqual(expected, actual)
|
||||
for key, value in literals.items():
|
||||
actual = actual.replace(key, value)
|
||||
self.assertEqual(before, actual)
|
||||
|
||||
def test_empty(self):
|
||||
self.t("", "")
|
||||
|
||||
def test_single_quote(self):
|
||||
self.t("'x'", "'_L1_'")
|
||||
|
||||
def test_double_quote(self):
|
||||
self.t('"x"', '"_L1_"')
|
||||
|
||||
def test_nested_quotes(self):
|
||||
self.t(""" '"' "'" """, """ '_L1_' "_L2_" """)
|
||||
|
||||
def test_triple_quote(self):
|
||||
self.t(" '''a\n''' ", " '''_L1_''' ")
|
||||
|
||||
def test_backslash(self):
|
||||
self.t(r"'a\'b'", "'_L1_'")
|
||||
self.t(r"'a\\'", "'_L1_'")
|
||||
self.t(r"'a\\\'b'", "'_L1_'")
|
||||
|
||||
def test_unicode(self):
|
||||
self.t("u'abc'", "u'_L1_'")
|
||||
|
||||
def test_raw(self):
|
||||
self.t(r"r'abc\\'", "r'_L1_'")
|
||||
|
||||
def test_raw_unicode(self):
|
||||
self.t(r"ru'abc\\'", "ru'_L1_'")
|
||||
|
||||
def test_comment(self):
|
||||
self.t("abc # foo", "abc #_L1_")
|
||||
|
||||
def test_comment_and_quote(self):
|
||||
self.t("abc # 'x'", "abc #_L1_")
|
||||
self.t("'abc#'", "'_L1_'")
|
||||
|
||||
def test_include(self):
|
||||
self.t("include 'a.pxi' # something here",
|
||||
"include '_L1_' #_L2_")
|
||||
|
||||
def test_extern(self):
|
||||
self.t("cdef extern from 'a.h': # comment",
|
||||
"cdef extern from '_L1_': #_L2_")
|
||||
@ -0,0 +1 @@
|
||||
# empty file
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user