test_preprocess_data.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import re
  2. import numpy as np
  3. import pytest
  4. from matplotlib import _preprocess_data
  5. # Notes on testing the plotting functions itself
  6. # * the individual decorated plotting functions are tested in 'test_axes.py'
  7. # * that pyplot functions accept a data kwarg is only tested in
  8. # test_axes.test_pie_linewidth_0
  9. # this gets used in multiple tests, so define it here
  10. @_preprocess_data(replace_names=["x", "y"], label_namer="y")
  11. def plot_func(ax, x, y, ls="x", label=None, w="xyz"):
  12. return ("x: %s, y: %s, ls: %s, w: %s, label: %s" % (
  13. list(x), list(y), ls, w, label))
  14. all_funcs = [plot_func]
  15. all_func_ids = ['plot_func']
  16. def test_compiletime_checks():
  17. """test decorator invocations -> no replacements"""
  18. def func(ax, x, y): pass
  19. def func_args(ax, x, y, *args): pass
  20. def func_kwargs(ax, x, y, **kwargs): pass
  21. def func_no_ax_args(*args, **kwargs): pass
  22. # this is ok
  23. _preprocess_data(replace_names=["x", "y"])(func)
  24. _preprocess_data(replace_names=["x", "y"])(func_kwargs)
  25. # this has "enough" information to do all the replaces
  26. _preprocess_data(replace_names=["x", "y"])(func_args)
  27. # no positional_parameter_names but needed due to replaces
  28. with pytest.raises(AssertionError):
  29. # z is unknown
  30. _preprocess_data(replace_names=["x", "y", "z"])(func_args)
  31. # no replacements at all -> all ok...
  32. _preprocess_data(replace_names=[], label_namer=None)(func)
  33. _preprocess_data(replace_names=[], label_namer=None)(func_args)
  34. _preprocess_data(replace_names=[], label_namer=None)(func_kwargs)
  35. _preprocess_data(replace_names=[], label_namer=None)(func_no_ax_args)
  36. # label namer is unknown
  37. with pytest.raises(AssertionError):
  38. _preprocess_data(label_namer="z")(func)
  39. with pytest.raises(AssertionError):
  40. _preprocess_data(label_namer="z")(func_args)
  41. @pytest.mark.parametrize('func', all_funcs, ids=all_func_ids)
  42. def test_function_call_without_data(func):
  43. """test without data -> no replacements"""
  44. assert (func(None, "x", "y") ==
  45. "x: ['x'], y: ['y'], ls: x, w: xyz, label: None")
  46. assert (func(None, x="x", y="y") ==
  47. "x: ['x'], y: ['y'], ls: x, w: xyz, label: None")
  48. assert (func(None, "x", "y", label="") ==
  49. "x: ['x'], y: ['y'], ls: x, w: xyz, label: ")
  50. assert (func(None, "x", "y", label="text") ==
  51. "x: ['x'], y: ['y'], ls: x, w: xyz, label: text")
  52. assert (func(None, x="x", y="y", label="") ==
  53. "x: ['x'], y: ['y'], ls: x, w: xyz, label: ")
  54. assert (func(None, x="x", y="y", label="text") ==
  55. "x: ['x'], y: ['y'], ls: x, w: xyz, label: text")
  56. @pytest.mark.parametrize('func', all_funcs, ids=all_func_ids)
  57. def test_function_call_with_dict_data(func):
  58. """Test with dict data -> label comes from the value of 'x' parameter."""
  59. data = {"a": [1, 2], "b": [8, 9], "w": "NOT"}
  60. assert (func(None, "a", "b", data=data) ==
  61. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: b")
  62. assert (func(None, x="a", y="b", data=data) ==
  63. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: b")
  64. assert (func(None, "a", "b", label="", data=data) ==
  65. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
  66. assert (func(None, "a", "b", label="text", data=data) ==
  67. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
  68. assert (func(None, x="a", y="b", label="", data=data) ==
  69. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
  70. assert (func(None, x="a", y="b", label="text", data=data) ==
  71. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
  72. @pytest.mark.parametrize('func', all_funcs, ids=all_func_ids)
  73. def test_function_call_with_dict_data_not_in_data(func):
  74. "test for the case that one var is not in data -> half replaces, half kept"
  75. data = {"a": [1, 2], "w": "NOT"}
  76. assert (func(None, "a", "b", data=data) ==
  77. "x: [1, 2], y: ['b'], ls: x, w: xyz, label: b")
  78. assert (func(None, x="a", y="b", data=data) ==
  79. "x: [1, 2], y: ['b'], ls: x, w: xyz, label: b")
  80. assert (func(None, "a", "b", label="", data=data) ==
  81. "x: [1, 2], y: ['b'], ls: x, w: xyz, label: ")
  82. assert (func(None, "a", "b", label="text", data=data) ==
  83. "x: [1, 2], y: ['b'], ls: x, w: xyz, label: text")
  84. assert (func(None, x="a", y="b", label="", data=data) ==
  85. "x: [1, 2], y: ['b'], ls: x, w: xyz, label: ")
  86. assert (func(None, x="a", y="b", label="text", data=data) ==
  87. "x: [1, 2], y: ['b'], ls: x, w: xyz, label: text")
  88. @pytest.mark.parametrize('func', all_funcs, ids=all_func_ids)
  89. def test_function_call_with_pandas_data(func, pd):
  90. """Test with pandas dataframe -> label comes from ``data["col"].name``."""
  91. data = pd.DataFrame({"a": np.array([1, 2], dtype=np.int32),
  92. "b": np.array([8, 9], dtype=np.int32),
  93. "w": ["NOT", "NOT"]})
  94. assert (func(None, "a", "b", data=data) ==
  95. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: b")
  96. assert (func(None, x="a", y="b", data=data) ==
  97. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: b")
  98. assert (func(None, "a", "b", label="", data=data) ==
  99. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
  100. assert (func(None, "a", "b", label="text", data=data) ==
  101. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
  102. assert (func(None, x="a", y="b", label="", data=data) ==
  103. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
  104. assert (func(None, x="a", y="b", label="text", data=data) ==
  105. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
  106. def test_function_call_replace_all():
  107. """Test without a "replace_names" argument, all vars should be replaced"""
  108. data = {"a": [1, 2], "b": [8, 9], "x": "xyz"}
  109. @_preprocess_data(label_namer="y")
  110. def func_replace_all(ax, x, y, ls="x", label=None, w="NOT"):
  111. return "x: %s, y: %s, ls: %s, w: %s, label: %s" % (
  112. list(x), list(y), ls, w, label)
  113. assert (func_replace_all(None, "a", "b", w="x", data=data) ==
  114. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: b")
  115. assert (func_replace_all(None, x="a", y="b", w="x", data=data) ==
  116. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: b")
  117. assert (func_replace_all(None, "a", "b", w="x", label="", data=data) ==
  118. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
  119. assert (
  120. func_replace_all(None, "a", "b", w="x", label="text", data=data) ==
  121. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
  122. assert (
  123. func_replace_all(None, x="a", y="b", w="x", label="", data=data) ==
  124. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
  125. assert (
  126. func_replace_all(None, x="a", y="b", w="x", label="text", data=data) ==
  127. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
  128. def test_no_label_replacements():
  129. """Test with "label_namer=None" -> no label replacement at all"""
  130. @_preprocess_data(replace_names=["x", "y"], label_namer=None)
  131. def func_no_label(ax, x, y, ls="x", label=None, w="xyz"):
  132. return "x: %s, y: %s, ls: %s, w: %s, label: %s" % (
  133. list(x), list(y), ls, w, label)
  134. data = {"a": [1, 2], "b": [8, 9], "w": "NOT"}
  135. assert (func_no_label(None, "a", "b", data=data) ==
  136. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: None")
  137. assert (func_no_label(None, x="a", y="b", data=data) ==
  138. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: None")
  139. assert (func_no_label(None, "a", "b", label="", data=data) ==
  140. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
  141. assert (func_no_label(None, "a", "b", label="text", data=data) ==
  142. "x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
  143. def test_more_args_than_pos_parameter():
  144. @_preprocess_data(replace_names=["x", "y"], label_namer="y")
  145. def func(ax, x, y, z=1):
  146. pass
  147. data = {"a": [1, 2], "b": [8, 9], "w": "NOT"}
  148. with pytest.raises(TypeError):
  149. func(None, "a", "b", "z", "z", data=data)
  150. def test_docstring_addition():
  151. @_preprocess_data()
  152. def funcy(ax, *args, **kwargs):
  153. """Funcy does nothing"""
  154. pass
  155. assert re.search(r".*All positional and all keyword arguments\.",
  156. funcy.__doc__)
  157. assert not re.search(r".*All positional arguments\.",
  158. funcy.__doc__)
  159. assert not re.search(r".*All arguments with the following names: .*",
  160. funcy.__doc__)
  161. @_preprocess_data(replace_names=[])
  162. def funcy(ax, x, y, z, bar=None):
  163. """Funcy does nothing"""
  164. pass
  165. assert not re.search(r".*All positional arguments\.",
  166. funcy.__doc__)
  167. assert not re.search(r".*All positional and all keyword arguments\.",
  168. funcy.__doc__)
  169. assert not re.search(r".*All arguments with the following names: .*",
  170. funcy.__doc__)
  171. @_preprocess_data(replace_names=["bar"])
  172. def funcy(ax, x, y, z, bar=None):
  173. """Funcy does nothing"""
  174. pass
  175. assert not re.search(r".*All positional arguments\.",
  176. funcy.__doc__)
  177. assert re.search(r".*All arguments with the following names: 'bar'\.",
  178. funcy.__doc__)
  179. assert not re.search(r".*All positional and all keyword arguments\.",
  180. funcy.__doc__)
  181. @_preprocess_data(replace_names=["x", "bar"])
  182. def funcy(ax, x, y, z, bar=None):
  183. """Funcy does nothing"""
  184. pass
  185. # lists can print in any order, so test for both x, bar and bar, x.
  186. assert re.search(r".*All arguments with the following names: '.*', '.*'\.",
  187. funcy.__doc__)
  188. assert re.search(r".*'x'.*", funcy.__doc__)
  189. assert re.search(r".*'bar'.*", funcy.__doc__)
  190. assert not re.search(r".*All positional and all keyword arguments\.",
  191. funcy.__doc__)
  192. assert not re.search(r".*All positional arguments\.",
  193. funcy.__doc__)