PageRenderTime 46ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/rpy/ipython/tests/test_rmagic.py

https://bitbucket.org/breisfeld/rpy2_w32_fix
Python | 279 lines | 239 code | 11 blank | 29 comment | 10 complexity | ba006752ee0a50af1ff3ee46d459b842 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. import unittest
  2. from itertools import product
  3. # Currently numpy is a testing requirement, but rpy2 should work without numpy
  4. try:
  5. import numpy as np
  6. has_numpy = True
  7. except:
  8. has_numpy = False
  9. try:
  10. import pandas as pd
  11. has_pandas = True
  12. except:
  13. has_pandas = False
  14. from IPython.testing.globalipapp import get_ipython
  15. from IPython.utils.py3compat import PY3
  16. if PY3:
  17. from io import StringIO
  18. np_string_type = 'U'
  19. else:
  20. from StringIO import StringIO
  21. np_string_type = 'S'
  22. from rpy2.ipython import rmagic
  23. # from IPython.core.getipython import get_ipython
  24. from rpy2 import rinterface
  25. from rpy2.robjects import r, vectors, globalenv
  26. import rpy2.robjects.packages as rpacks
  27. class TestRmagic(unittest.TestCase):
  28. @classmethod
  29. def setUpClass(cls):
  30. '''Set up an IPython session just once.
  31. It'd be safer to set it up for each test, but for now, I'm mimicking the
  32. IPython team's logic.
  33. '''
  34. cls.ip = get_ipython()
  35. # This is just to get a minimally modified version of the changes
  36. # working
  37. cls.ip.magic('load_ext rpy2.ipython')
  38. def setUp(self):
  39. if hasattr(rmagic.template_converter, 'activate'):
  40. rmagic.template_converter.activate()
  41. def tearDown(self):
  42. # This seems like the safest thing to return to a safe state
  43. self.ip.run_line_magic('Rdevice', 'png')
  44. if hasattr(rmagic.template_converter, 'deactivate'):
  45. rmagic.template_converter.deactivate()
  46. @unittest.skipIf(not has_numpy, 'numpy not installed')
  47. def test_push(self):
  48. self.ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])})
  49. self.ip.run_line_magic('Rpush', 'X Y')
  50. np.testing.assert_almost_equal(np.asarray(r('X')), self.ip.user_ns['X'])
  51. np.testing.assert_almost_equal(np.asarray(r('Y')), self.ip.user_ns['Y'])
  52. @unittest.skipIf(not has_numpy, 'numpy not installed')
  53. def test_push_localscope(self):
  54. """Test that Rpush looks for variables in the local scope first."""
  55. self.ip.run_cell('''
  56. def rmagic_addone(u):
  57. %Rpush u
  58. %R result = u+1
  59. %Rpull result
  60. return result[0]
  61. u = 0
  62. result = rmagic_addone(12344)
  63. ''')
  64. result = self.ip.user_ns['result']
  65. np.testing.assert_equal(result, 12345)
  66. @unittest.skipUnless(has_pandas, 'pandas is not available in python')
  67. @unittest.skipIf(not has_numpy, 'numpy not installed')
  68. def test_push_dataframe(self):
  69. df = pd.DataFrame([{'a': 1, 'b': 'bar'}, {'a': 5, 'b': 'foo', 'c': 20}])
  70. self.ip.push({'df':df})
  71. self.ip.run_line_magic('Rpush', 'df')
  72. # This is converted to factors, which are currently converted back to Python
  73. # as integers, so for now we test its representation in R.
  74. sio = StringIO()
  75. rinterface.set_writeconsole_regular(sio.write)
  76. try:
  77. r('print(df$b[1])')
  78. self.assertIn('[1] bar', sio.getvalue())
  79. finally:
  80. rinterface.set_writeconsole_regular(None)
  81. # Values come packaged in arrays, so we unbox them to test.
  82. self.assertEqual(r('df$a[2]')[0], 5)
  83. missing = r('df$c[1]')[0]
  84. assert np.isnan(missing), missing
  85. @unittest.skipIf(not has_numpy, 'numpy not installed')
  86. def test_pull(self):
  87. r('Z=c(11:20)')
  88. self.ip.run_line_magic('Rpull', 'Z')
  89. np.testing.assert_almost_equal(np.asarray(r('Z')), self.ip.user_ns['Z'])
  90. np.testing.assert_almost_equal(self.ip.user_ns['Z'], np.arange(11,21))
  91. @unittest.skipIf(not has_numpy, 'numpy not installed')
  92. def test_Rconverter(self):
  93. # If we get to dropping numpy requirement, we might use something
  94. # like the following:
  95. # self.assertSequenceEqual(buffer(a).buffer_info(),
  96. # buffer(b).buffer_info())
  97. # numpy recarray (numpy's version of a data frame)
  98. dataf_np= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],
  99. dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|%s1' % np_string_type)])
  100. # store it in the notebook's user namespace
  101. self.ip.user_ns['dataf_np'] = dataf_np
  102. # equivalent to:
  103. # %Rpush dataf_np
  104. # that is send Python object 'dataf_np' into R's globalenv
  105. # as 'dataf_np'. The current conversion rules will make it an
  106. # R data frame.
  107. self.ip.run_line_magic('Rpush', 'dataf_np')
  108. # Now retreive 'dataf_np' from R's globalenv. Twice because
  109. # we want to test whether copies are made
  110. fromr_dataf_np = self.ip.run_line_magic('Rget', 'dataf_np')
  111. fromr_dataf_np_again = self.ip.run_line_magic('Rget', 'dataf_np')
  112. # check whether the data frame retrieved has the same content
  113. # as the original recarray
  114. self.assertEqual(len(dataf_np), len(fromr_dataf_np))
  115. for col_i, col_n in enumerate(('x', 'y')):
  116. #np.testing.assert_array_equal(dataf_np[col_i],
  117. # fromr_dataf_np.ix[col_i].values)
  118. if has_pandas:
  119. self.assertSequenceEqual(tuple(dataf_np[col_i]),
  120. tuple(fromr_dataf_np.ix[col_i+1].values))
  121. else:
  122. # has_numpy then
  123. self.assertSequenceEqual(tuple(dataf_np[col_i]),
  124. tuple(fromr_dataf_np[col_i]))
  125. # pandas2ri is currently making copies
  126. # # modify the data frame retrieved to check whether
  127. # # a copy was made
  128. # fromr_dataf_np['x'].values[0] = 11
  129. # self.assertEqual(11, fromr_dataf_np_again['x'][0])
  130. # fromr_dataf_np['x'].values[0] = 1
  131. # retrieve `dataf_np` from R into `fromr_dataf_np` in the notebook.
  132. self.ip.run_cell_magic('R',
  133. '-o dataf_np',
  134. 'dataf_np')
  135. dataf_np_roundtrip = self.ip.user_ns['dataf_np']
  136. self.assertSequenceEqual(tuple(fromr_dataf_np['x']),
  137. tuple(dataf_np_roundtrip['x']))
  138. self.assertSequenceEqual(tuple(fromr_dataf_np['y']),
  139. tuple(dataf_np_roundtrip['y']))
  140. @unittest.skipIf(not has_numpy, 'numpy not installed')
  141. def test_cell_magic(self):
  142. self.ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
  143. # For now, print statements are commented out because they print
  144. # erroneous ERRORs when running via rpy2.tests
  145. snippet = '''
  146. print(summary(a))
  147. plot(x, y, pch=23, bg='orange', cex=2)
  148. plot(x, x)
  149. print(summary(x))
  150. r = resid(a)
  151. xc = coef(a)
  152. '''
  153. self.ip.run_cell_magic('R', '-i x,y -o r,xc -w 150 -u mm a=lm(y~x)',
  154. snippet)
  155. np.testing.assert_almost_equal(self.ip.user_ns['xc'], [3.2, 0.9])
  156. np.testing.assert_almost_equal(self.ip.user_ns['r'], np.array([-0.2, 0.9, -1. , 0.1, 0.2]))
  157. def test_cell_magic_localconverter(self):
  158. x = (1,2,3)
  159. from rpy2.rinterface import StrSexpVector
  160. def tuple_str(tpl):
  161. res = StrSexpVector(tpl)
  162. return res
  163. from rpy2.robjects.conversion import Converter
  164. my_converter = Converter('my converter')
  165. my_converter.py2ri.register(tuple, tuple_str)
  166. from rpy2.robjects import default_converter
  167. foo = default_converter + my_converter
  168. self.ip.push({'x':x,
  169. 'foo': foo})
  170. snippet = '''
  171. x
  172. '''
  173. self.assertRaises(NotImplementedError,
  174. self.ip.run_cell_magic,
  175. 'R', '-i x', snippet)
  176. self.ip.run_cell_magic('R', '-i x -c foo',
  177. snippet)
  178. self.assertTrue(isinstance(globalenv['x'],
  179. vectors.StrVector))
  180. def test_rmagic_localscope(self):
  181. self.ip.push({'x':0})
  182. self.ip.run_line_magic('R', '-i x -o result result <-x+1')
  183. result = self.ip.user_ns['result']
  184. self.assertEqual(result[0], 1)
  185. self.ip.run_cell('''def rmagic_addone(u):
  186. %R -i u -o result result <- u+1
  187. return result[0]''')
  188. self.ip.run_cell('result = rmagic_addone(1)')
  189. result = self.ip.user_ns['result']
  190. self.assertEqual(result, 2)
  191. self.assertRaises(
  192. NameError,
  193. self.ip.run_line_magic,
  194. "R",
  195. "-i var_not_defined 1+1")
  196. @unittest.skipIf(not has_numpy, 'numpy not installed')
  197. def test_png_plotting_args(self):
  198. '''Exercise the PNG plotting machinery'''
  199. self.ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
  200. cell = '''
  201. plot(x, y, pch=23, bg='orange', cex=2)
  202. '''
  203. png_px_args = [' '.join(('--units=px',w,h,p)) for
  204. w, h, p in product(['--width=400 ',''],
  205. ['--height=400',''],
  206. ['-p=10', ''])]
  207. for line in png_px_args:
  208. self.ip.run_line_magic('Rdevice', 'png')
  209. self.ip.run_cell_magic('R', line, cell)
  210. @unittest.skipUnless(rpacks.isinstalled('Cairo'), 'Cairo not installed')
  211. def test_svg_plotting_args(self):
  212. '''Exercise the plotting machinery
  213. To pass SVG tests, we need Cairo installed in R.'''
  214. self.ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
  215. cell = '''
  216. plot(x, y, pch=23, bg='orange', cex=2)
  217. '''
  218. basic_args = [' '.join((w,h,p)) for w, h, p in product(['--width=6 ',''],
  219. ['--height=6',''],
  220. ['-p=10', ''])]
  221. for line in basic_args:
  222. self.ip.run_line_magic('Rdevice', 'svg')
  223. self.ip.run_cell_magic('R', line, cell)
  224. png_args = ['--units=in --res=1 ' + s for s in basic_args]
  225. for line in png_args:
  226. self.ip.run_line_magic('Rdevice', 'png')
  227. self.ip.run_cell_magic('R', line, cell)
  228. @unittest.skip('Test for X11 skipped.')
  229. def test_plotting_X11(self):
  230. self.ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
  231. cell = '''
  232. plot(x, y, pch=23, bg='orange', cex=2)
  233. '''
  234. self.ip.run_line_magic('Rdevice', 'X11')
  235. self.ip.run_cell_magic('R', '', cell)
  236. if __name__ == '__main__':
  237. unittest.main()