test_header.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests that the file header is properly handled or inferred
  4. during parsing for all of the parsers defined in parsers.py
  5. """
  6. from collections import namedtuple
  7. import numpy as np
  8. import pytest
  9. from pandas.compat import StringIO, u
  10. from pandas.errors import ParserError
  11. from pandas import DataFrame, Index, MultiIndex
  12. import pandas.util.testing as tm
  13. def test_read_with_bad_header(all_parsers):
  14. parser = all_parsers
  15. msg = r"but only \d+ lines in file"
  16. with pytest.raises(ValueError, match=msg):
  17. s = StringIO(",,")
  18. parser.read_csv(s, header=[10])
  19. @pytest.mark.parametrize("header", [True, False])
  20. def test_bool_header_arg(all_parsers, header):
  21. # see gh-6114
  22. parser = all_parsers
  23. data = """\
  24. MyColumn
  25. a
  26. b
  27. a
  28. b"""
  29. msg = "Passing a bool to header is invalid"
  30. with pytest.raises(TypeError, match=msg):
  31. parser.read_csv(StringIO(data), header=header)
  32. def test_no_header_prefix(all_parsers):
  33. parser = all_parsers
  34. data = """1,2,3,4,5
  35. 6,7,8,9,10
  36. 11,12,13,14,15
  37. """
  38. result = parser.read_csv(StringIO(data), prefix="Field", header=None)
  39. expected = DataFrame([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10],
  40. [11, 12, 13, 14, 15]],
  41. columns=["Field0", "Field1", "Field2",
  42. "Field3", "Field4"])
  43. tm.assert_frame_equal(result, expected)
  44. def test_header_with_index_col(all_parsers):
  45. parser = all_parsers
  46. data = """foo,1,2,3
  47. bar,4,5,6
  48. baz,7,8,9
  49. """
  50. names = ["A", "B", "C"]
  51. result = parser.read_csv(StringIO(data), names=names)
  52. expected = DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]],
  53. index=["foo", "bar", "baz"],
  54. columns=["A", "B", "C"])
  55. tm.assert_frame_equal(result, expected)
  56. def test_header_not_first_line(all_parsers):
  57. parser = all_parsers
  58. data = """got,to,ignore,this,line
  59. got,to,ignore,this,line
  60. index,A,B,C,D
  61. foo,2,3,4,5
  62. bar,7,8,9,10
  63. baz,12,13,14,15
  64. """
  65. data2 = """index,A,B,C,D
  66. foo,2,3,4,5
  67. bar,7,8,9,10
  68. baz,12,13,14,15
  69. """
  70. result = parser.read_csv(StringIO(data), header=2, index_col=0)
  71. expected = parser.read_csv(StringIO(data2), header=0, index_col=0)
  72. tm.assert_frame_equal(result, expected)
  73. def test_header_multi_index(all_parsers):
  74. parser = all_parsers
  75. expected = tm.makeCustomDataframe(
  76. 5, 3, r_idx_nlevels=2, c_idx_nlevels=4)
  77. data = """\
  78. C0,,C_l0_g0,C_l0_g1,C_l0_g2
  79. C1,,C_l1_g0,C_l1_g1,C_l1_g2
  80. C2,,C_l2_g0,C_l2_g1,C_l2_g2
  81. C3,,C_l3_g0,C_l3_g1,C_l3_g2
  82. R0,R1,,,
  83. R_l0_g0,R_l1_g0,R0C0,R0C1,R0C2
  84. R_l0_g1,R_l1_g1,R1C0,R1C1,R1C2
  85. R_l0_g2,R_l1_g2,R2C0,R2C1,R2C2
  86. R_l0_g3,R_l1_g3,R3C0,R3C1,R3C2
  87. R_l0_g4,R_l1_g4,R4C0,R4C1,R4C2
  88. """
  89. result = parser.read_csv(StringIO(data), header=[0, 1, 2, 3],
  90. index_col=[0, 1])
  91. tm.assert_frame_equal(result, expected)
  92. @pytest.mark.parametrize("kwargs,msg", [
  93. (dict(index_col=["foo", "bar"]), ("index_col must only contain "
  94. "row numbers when specifying "
  95. "a multi-index header")),
  96. (dict(index_col=[0, 1], names=["foo", "bar"]), ("cannot specify names "
  97. "when specifying a "
  98. "multi-index header")),
  99. (dict(index_col=[0, 1], usecols=["foo", "bar"]), ("cannot specify "
  100. "usecols when "
  101. "specifying a "
  102. "multi-index header")),
  103. ])
  104. def test_header_multi_index_invalid(all_parsers, kwargs, msg):
  105. data = """\
  106. C0,,C_l0_g0,C_l0_g1,C_l0_g2
  107. C1,,C_l1_g0,C_l1_g1,C_l1_g2
  108. C2,,C_l2_g0,C_l2_g1,C_l2_g2
  109. C3,,C_l3_g0,C_l3_g1,C_l3_g2
  110. R0,R1,,,
  111. R_l0_g0,R_l1_g0,R0C0,R0C1,R0C2
  112. R_l0_g1,R_l1_g1,R1C0,R1C1,R1C2
  113. R_l0_g2,R_l1_g2,R2C0,R2C1,R2C2
  114. R_l0_g3,R_l1_g3,R3C0,R3C1,R3C2
  115. R_l0_g4,R_l1_g4,R4C0,R4C1,R4C2
  116. """
  117. parser = all_parsers
  118. with pytest.raises(ValueError, match=msg):
  119. parser.read_csv(StringIO(data), header=[0, 1, 2, 3], **kwargs)
  120. _TestTuple = namedtuple("names", ["first", "second"])
  121. @pytest.mark.parametrize("kwargs", [
  122. dict(header=[0, 1]),
  123. dict(skiprows=3,
  124. names=[("a", "q"), ("a", "r"), ("a", "s"),
  125. ("b", "t"), ("c", "u"), ("c", "v")]),
  126. dict(skiprows=3,
  127. names=[_TestTuple("a", "q"), _TestTuple("a", "r"),
  128. _TestTuple("a", "s"), _TestTuple("b", "t"),
  129. _TestTuple("c", "u"), _TestTuple("c", "v")])
  130. ])
  131. def test_header_multi_index_common_format1(all_parsers, kwargs):
  132. parser = all_parsers
  133. expected = DataFrame([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]],
  134. index=["one", "two"],
  135. columns=MultiIndex.from_tuples(
  136. [("a", "q"), ("a", "r"), ("a", "s"),
  137. ("b", "t"), ("c", "u"), ("c", "v")]))
  138. data = """,a,a,a,b,c,c
  139. ,q,r,s,t,u,v
  140. ,,,,,,
  141. one,1,2,3,4,5,6
  142. two,7,8,9,10,11,12"""
  143. result = parser.read_csv(StringIO(data), index_col=0, **kwargs)
  144. tm.assert_frame_equal(result, expected)
  145. @pytest.mark.parametrize("kwargs", [
  146. dict(header=[0, 1]),
  147. dict(skiprows=2,
  148. names=[("a", "q"), ("a", "r"), ("a", "s"),
  149. ("b", "t"), ("c", "u"), ("c", "v")]),
  150. dict(skiprows=2,
  151. names=[_TestTuple("a", "q"), _TestTuple("a", "r"),
  152. _TestTuple("a", "s"), _TestTuple("b", "t"),
  153. _TestTuple("c", "u"), _TestTuple("c", "v")])
  154. ])
  155. def test_header_multi_index_common_format2(all_parsers, kwargs):
  156. parser = all_parsers
  157. expected = DataFrame([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]],
  158. index=["one", "two"],
  159. columns=MultiIndex.from_tuples(
  160. [("a", "q"), ("a", "r"), ("a", "s"),
  161. ("b", "t"), ("c", "u"), ("c", "v")]))
  162. data = """,a,a,a,b,c,c
  163. ,q,r,s,t,u,v
  164. one,1,2,3,4,5,6
  165. two,7,8,9,10,11,12"""
  166. result = parser.read_csv(StringIO(data), index_col=0, **kwargs)
  167. tm.assert_frame_equal(result, expected)
  168. @pytest.mark.parametrize("kwargs", [
  169. dict(header=[0, 1]),
  170. dict(skiprows=2,
  171. names=[("a", "q"), ("a", "r"), ("a", "s"),
  172. ("b", "t"), ("c", "u"), ("c", "v")]),
  173. dict(skiprows=2,
  174. names=[_TestTuple("a", "q"), _TestTuple("a", "r"),
  175. _TestTuple("a", "s"), _TestTuple("b", "t"),
  176. _TestTuple("c", "u"), _TestTuple("c", "v")])
  177. ])
  178. def test_header_multi_index_common_format3(all_parsers, kwargs):
  179. parser = all_parsers
  180. expected = DataFrame([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]],
  181. index=["one", "two"],
  182. columns=MultiIndex.from_tuples(
  183. [("a", "q"), ("a", "r"), ("a", "s"),
  184. ("b", "t"), ("c", "u"), ("c", "v")]))
  185. expected = expected.reset_index(drop=True)
  186. data = """a,a,a,b,c,c
  187. q,r,s,t,u,v
  188. 1,2,3,4,5,6
  189. 7,8,9,10,11,12"""
  190. result = parser.read_csv(StringIO(data), index_col=None, **kwargs)
  191. tm.assert_frame_equal(result, expected)
  192. def test_header_multi_index_common_format_malformed1(all_parsers):
  193. parser = all_parsers
  194. expected = DataFrame(np.array(
  195. [[2, 3, 4, 5, 6], [8, 9, 10, 11, 12]], dtype="int64"),
  196. index=Index([1, 7]),
  197. columns=MultiIndex(levels=[[u("a"), u("b"), u("c")],
  198. [u("r"), u("s"), u("t"),
  199. u("u"), u("v")]],
  200. codes=[[0, 0, 1, 2, 2], [0, 1, 2, 3, 4]],
  201. names=[u("a"), u("q")]))
  202. data = """a,a,a,b,c,c
  203. q,r,s,t,u,v
  204. 1,2,3,4,5,6
  205. 7,8,9,10,11,12"""
  206. result = parser.read_csv(StringIO(data), header=[0, 1], index_col=0)
  207. tm.assert_frame_equal(expected, result)
  208. def test_header_multi_index_common_format_malformed2(all_parsers):
  209. parser = all_parsers
  210. expected = DataFrame(np.array(
  211. [[2, 3, 4, 5, 6], [8, 9, 10, 11, 12]], dtype="int64"),
  212. index=Index([1, 7]),
  213. columns=MultiIndex(levels=[[u("a"), u("b"), u("c")],
  214. [u("r"), u("s"), u("t"),
  215. u("u"), u("v")]],
  216. codes=[[0, 0, 1, 2, 2], [0, 1, 2, 3, 4]],
  217. names=[None, u("q")]))
  218. data = """,a,a,b,c,c
  219. q,r,s,t,u,v
  220. 1,2,3,4,5,6
  221. 7,8,9,10,11,12"""
  222. result = parser.read_csv(StringIO(data), header=[0, 1], index_col=0)
  223. tm.assert_frame_equal(expected, result)
  224. def test_header_multi_index_common_format_malformed3(all_parsers):
  225. parser = all_parsers
  226. expected = DataFrame(np.array(
  227. [[3, 4, 5, 6], [9, 10, 11, 12]], dtype="int64"),
  228. index=MultiIndex(levels=[[1, 7], [2, 8]],
  229. codes=[[0, 1], [0, 1]]),
  230. columns=MultiIndex(levels=[[u("a"), u("b"), u("c")],
  231. [u("s"), u("t"), u("u"), u("v")]],
  232. codes=[[0, 1, 2, 2], [0, 1, 2, 3]],
  233. names=[None, u("q")]))
  234. data = """,a,a,b,c,c
  235. q,r,s,t,u,v
  236. 1,2,3,4,5,6
  237. 7,8,9,10,11,12"""
  238. result = parser.read_csv(StringIO(data), header=[0, 1], index_col=[0, 1])
  239. tm.assert_frame_equal(expected, result)
  240. @pytest.mark.parametrize("data,header", [
  241. ("1,2,3\n4,5,6", None),
  242. ("foo,bar,baz\n1,2,3\n4,5,6", 0),
  243. ])
  244. def test_header_names_backward_compat(all_parsers, data, header):
  245. # see gh-2539
  246. parser = all_parsers
  247. expected = parser.read_csv(StringIO("1,2,3\n4,5,6"),
  248. names=["a", "b", "c"])
  249. result = parser.read_csv(StringIO(data), names=["a", "b", "c"],
  250. header=header)
  251. tm.assert_frame_equal(result, expected)
  252. @pytest.mark.parametrize("kwargs", [
  253. dict(), dict(index_col=False)
  254. ])
  255. def test_read_only_header_no_rows(all_parsers, kwargs):
  256. # See gh-7773
  257. parser = all_parsers
  258. expected = DataFrame(columns=["a", "b", "c"])
  259. result = parser.read_csv(StringIO("a,b,c"), **kwargs)
  260. tm.assert_frame_equal(result, expected)
  261. @pytest.mark.parametrize("kwargs,names", [
  262. (dict(), [0, 1, 2, 3, 4]),
  263. (dict(prefix="X"), ["X0", "X1", "X2", "X3", "X4"]),
  264. (dict(names=["foo", "bar", "baz", "quux", "panda"]),
  265. ["foo", "bar", "baz", "quux", "panda"])
  266. ])
  267. def test_no_header(all_parsers, kwargs, names):
  268. parser = all_parsers
  269. data = """1,2,3,4,5
  270. 6,7,8,9,10
  271. 11,12,13,14,15
  272. """
  273. expected = DataFrame([[1, 2, 3, 4, 5],
  274. [6, 7, 8, 9, 10],
  275. [11, 12, 13, 14, 15]], columns=names)
  276. result = parser.read_csv(StringIO(data), header=None, **kwargs)
  277. tm.assert_frame_equal(result, expected)
  278. @pytest.mark.parametrize("header", [
  279. ["a", "b"],
  280. "string_header"
  281. ])
  282. def test_non_int_header(all_parsers, header):
  283. # see gh-16338
  284. msg = "header must be integer or list of integers"
  285. data = """1,2\n3,4"""
  286. parser = all_parsers
  287. with pytest.raises(ValueError, match=msg):
  288. parser.read_csv(StringIO(data), header=header)
  289. def test_singleton_header(all_parsers):
  290. # see gh-7757
  291. data = """a,b,c\n0,1,2\n1,2,3"""
  292. parser = all_parsers
  293. expected = DataFrame({"a": [0, 1], "b": [1, 2], "c": [2, 3]})
  294. result = parser.read_csv(StringIO(data), header=[0])
  295. tm.assert_frame_equal(result, expected)
  296. @pytest.mark.parametrize("data,expected", [
  297. ("A,A,A,B\none,one,one,two\n0,40,34,0.1",
  298. DataFrame([[0, 40, 34, 0.1]],
  299. columns=MultiIndex.from_tuples(
  300. [("A", "one"), ("A", "one.1"),
  301. ("A", "one.2"), ("B", "two")]))),
  302. ("A,A,A,B\none,one,one.1,two\n0,40,34,0.1",
  303. DataFrame([[0, 40, 34, 0.1]],
  304. columns=MultiIndex.from_tuples(
  305. [("A", "one"), ("A", "one.1"),
  306. ("A", "one.1.1"), ("B", "two")]))),
  307. ("A,A,A,B,B\none,one,one.1,two,two\n0,40,34,0.1,0.1",
  308. DataFrame([[0, 40, 34, 0.1, 0.1]],
  309. columns=MultiIndex.from_tuples(
  310. [("A", "one"), ("A", "one.1"),
  311. ("A", "one.1.1"), ("B", "two"),
  312. ("B", "two.1")])))
  313. ])
  314. def test_mangles_multi_index(all_parsers, data, expected):
  315. # see gh-18062
  316. parser = all_parsers
  317. result = parser.read_csv(StringIO(data), header=[0, 1])
  318. tm.assert_frame_equal(result, expected)
  319. @pytest.mark.parametrize("index_col", [None, [0]])
  320. @pytest.mark.parametrize("columns", [None,
  321. (["", "Unnamed"]),
  322. (["Unnamed", ""]),
  323. (["Unnamed", "NotUnnamed"])])
  324. def test_multi_index_unnamed(all_parsers, index_col, columns):
  325. # see gh-23687
  326. #
  327. # When specifying a multi-index header, make sure that
  328. # we don't error just because one of the rows in our header
  329. # has ALL column names containing the string "Unnamed". The
  330. # correct condition to check is whether the row contains
  331. # ALL columns that did not have names (and instead were given
  332. # placeholder ones).
  333. parser = all_parsers
  334. header = [0, 1]
  335. if index_col is None:
  336. data = ",".join(columns or ["", ""]) + "\n0,1\n2,3\n4,5\n"
  337. else:
  338. data = (",".join([""] + (columns or ["", ""])) +
  339. "\n,0,1\n0,2,3\n1,4,5\n")
  340. if columns is None:
  341. msg = (r"Passed header=\[0,1\] are too "
  342. r"many rows for this multi_index of columns")
  343. with pytest.raises(ParserError, match=msg):
  344. parser.read_csv(StringIO(data), header=header,
  345. index_col=index_col)
  346. else:
  347. result = parser.read_csv(StringIO(data), header=header,
  348. index_col=index_col)
  349. template = "Unnamed: {i}_level_0"
  350. exp_columns = []
  351. for i, col in enumerate(columns):
  352. if not col: # Unnamed.
  353. col = template.format(i=i if index_col is None else i + 1)
  354. exp_columns.append(col)
  355. columns = MultiIndex.from_tuples(zip(exp_columns, ["0", "1"]))
  356. expected = DataFrame([[2, 3], [4, 5]], columns=columns)
  357. tm.assert_frame_equal(result, expected)