TestIpythonMagic.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # -*- coding: utf-8 -*-
  2. # tag: ipython
  3. """Tests for the Cython magics extension."""
  4. from __future__ import absolute_import
  5. import os
  6. import sys
  7. from contextlib import contextmanager
  8. from Cython.Build import IpythonMagic
  9. from Cython.TestUtils import CythonTest
  10. try:
  11. import IPython.testing.globalipapp
  12. from IPython.utils import py3compat
  13. except ImportError:
  14. # Disable tests and fake helpers for initialisation below.
  15. class _py3compat(object):
  16. def str_to_unicode(self, s):
  17. return s
  18. py3compat = _py3compat()
  19. def skip_if_not_installed(_):
  20. return None
  21. else:
  22. def skip_if_not_installed(c):
  23. return c
  24. try:
  25. # disable IPython history thread before it gets started to avoid having to clean it up
  26. from IPython.core.history import HistoryManager
  27. HistoryManager.enabled = False
  28. except ImportError:
  29. pass
  30. code = py3compat.str_to_unicode("""\
  31. def f(x):
  32. return 2*x
  33. """)
  34. cython3_code = py3compat.str_to_unicode("""\
  35. def f(int x):
  36. return 2 / x
  37. def call(x):
  38. return f(*(x,))
  39. """)
  40. pgo_cython3_code = cython3_code + py3compat.str_to_unicode("""\
  41. def main():
  42. for _ in range(100): call(5)
  43. main()
  44. """)
  45. if sys.platform == 'win32':
  46. # not using IPython's decorators here because they depend on "nose"
  47. try:
  48. from unittest import skip as skip_win32
  49. except ImportError:
  50. # poor dev's silent @unittest.skip()
  51. def skip_win32(dummy):
  52. def _skip_win32(func):
  53. return None
  54. return _skip_win32
  55. else:
  56. def skip_win32(dummy):
  57. def _skip_win32(func):
  58. def wrapper(*args, **kwargs):
  59. func(*args, **kwargs)
  60. return wrapper
  61. return _skip_win32
  62. @skip_if_not_installed
  63. class TestIPythonMagic(CythonTest):
  64. @classmethod
  65. def setUpClass(cls):
  66. CythonTest.setUpClass()
  67. cls._ip = IPython.testing.globalipapp.get_ipython()
  68. def setUp(self):
  69. CythonTest.setUp(self)
  70. self._ip.extension_manager.load_extension('cython')
  71. def test_cython_inline(self):
  72. ip = self._ip
  73. ip.ex('a=10; b=20')
  74. result = ip.run_cell_magic('cython_inline', '', 'return a+b')
  75. self.assertEqual(result, 30)
  76. @skip_win32('Skip on Windows')
  77. def test_cython_pyximport(self):
  78. ip = self._ip
  79. module_name = '_test_cython_pyximport'
  80. ip.run_cell_magic('cython_pyximport', module_name, code)
  81. ip.ex('g = f(10)')
  82. self.assertEqual(ip.user_ns['g'], 20.0)
  83. ip.run_cell_magic('cython_pyximport', module_name, code)
  84. ip.ex('h = f(-10)')
  85. self.assertEqual(ip.user_ns['h'], -20.0)
  86. try:
  87. os.remove(module_name + '.pyx')
  88. except OSError:
  89. pass
  90. def test_cython(self):
  91. ip = self._ip
  92. ip.run_cell_magic('cython', '', code)
  93. ip.ex('g = f(10)')
  94. self.assertEqual(ip.user_ns['g'], 20.0)
  95. def test_cython_name(self):
  96. # The Cython module named 'mymodule' defines the function f.
  97. ip = self._ip
  98. ip.run_cell_magic('cython', '--name=mymodule', code)
  99. # This module can now be imported in the interactive namespace.
  100. ip.ex('import mymodule; g = mymodule.f(10)')
  101. self.assertEqual(ip.user_ns['g'], 20.0)
  102. def test_cython_language_level(self):
  103. # The Cython cell defines the functions f() and call().
  104. ip = self._ip
  105. ip.run_cell_magic('cython', '', cython3_code)
  106. ip.ex('g = f(10); h = call(10)')
  107. if sys.version_info[0] < 3:
  108. self.assertEqual(ip.user_ns['g'], 2 // 10)
  109. self.assertEqual(ip.user_ns['h'], 2 // 10)
  110. else:
  111. self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
  112. self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
  113. def test_cython3(self):
  114. # The Cython cell defines the functions f() and call().
  115. ip = self._ip
  116. ip.run_cell_magic('cython', '-3', cython3_code)
  117. ip.ex('g = f(10); h = call(10)')
  118. self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
  119. self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
  120. def test_cython2(self):
  121. # The Cython cell defines the functions f() and call().
  122. ip = self._ip
  123. ip.run_cell_magic('cython', '-2', cython3_code)
  124. ip.ex('g = f(10); h = call(10)')
  125. self.assertEqual(ip.user_ns['g'], 2 // 10)
  126. self.assertEqual(ip.user_ns['h'], 2 // 10)
  127. @skip_win32('Skip on Windows')
  128. def test_cython3_pgo(self):
  129. # The Cython cell defines the functions f() and call().
  130. ip = self._ip
  131. ip.run_cell_magic('cython', '-3 --pgo', pgo_cython3_code)
  132. ip.ex('g = f(10); h = call(10); main()')
  133. self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
  134. self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
  135. @skip_win32('Skip on Windows')
  136. def test_extlibs(self):
  137. ip = self._ip
  138. code = py3compat.str_to_unicode("""
  139. from libc.math cimport sin
  140. x = sin(0.0)
  141. """)
  142. ip.user_ns['x'] = 1
  143. ip.run_cell_magic('cython', '-l m', code)
  144. self.assertEqual(ip.user_ns['x'], 0)
  145. def test_cython_verbose(self):
  146. ip = self._ip
  147. ip.run_cell_magic('cython', '--verbose', code)
  148. ip.ex('g = f(10)')
  149. self.assertEqual(ip.user_ns['g'], 20.0)
  150. def test_cython_verbose_thresholds(self):
  151. @contextmanager
  152. def mock_distutils():
  153. class MockLog:
  154. DEBUG = 1
  155. INFO = 2
  156. thresholds = [INFO]
  157. def set_threshold(self, val):
  158. self.thresholds.append(val)
  159. return self.thresholds[-2]
  160. new_log = MockLog()
  161. old_log = IpythonMagic.distutils.log
  162. try:
  163. IpythonMagic.distutils.log = new_log
  164. yield new_log
  165. finally:
  166. IpythonMagic.distutils.log = old_log
  167. ip = self._ip
  168. with mock_distutils() as verbose_log:
  169. ip.run_cell_magic('cython', '--verbose', code)
  170. ip.ex('g = f(10)')
  171. self.assertEqual(ip.user_ns['g'], 20.0)
  172. self.assertEquals([verbose_log.INFO, verbose_log.DEBUG, verbose_log.INFO],
  173. verbose_log.thresholds)
  174. with mock_distutils() as normal_log:
  175. ip.run_cell_magic('cython', '', code)
  176. ip.ex('g = f(10)')
  177. self.assertEqual(ip.user_ns['g'], 20.0)
  178. self.assertEquals([normal_log.INFO], normal_log.thresholds)