test_format.py 124 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541
  1. """
  2. Test output formatting for Series/DataFrame, including to_string & reprs
  3. """
  4. from contextlib import nullcontext
  5. from datetime import (
  6. datetime,
  7. time,
  8. timedelta,
  9. )
  10. from io import StringIO
  11. import itertools
  12. import locale
  13. from operator import methodcaller
  14. from pathlib import Path
  15. import re
  16. from shutil import get_terminal_size
  17. import sys
  18. import textwrap
  19. import dateutil
  20. import numpy as np
  21. import pytest
  22. import pytz
  23. from pandas.compat import (
  24. IS64,
  25. is_platform_windows,
  26. )
  27. import pandas as pd
  28. from pandas import (
  29. DataFrame,
  30. Index,
  31. MultiIndex,
  32. NaT,
  33. Series,
  34. Timestamp,
  35. date_range,
  36. get_option,
  37. option_context,
  38. read_csv,
  39. reset_option,
  40. set_option,
  41. )
  42. import pandas._testing as tm
  43. from pandas.io.formats import printing
  44. import pandas.io.formats.format as fmt
  45. use_32bit_repr = is_platform_windows() or not IS64
  46. def get_local_am_pm():
  47. """Return the AM and PM strings returned by strftime in current locale."""
  48. am_local = time(1).strftime("%p")
  49. pm_local = time(13).strftime("%p")
  50. return am_local, pm_local
  51. @pytest.fixture(params=["string", "pathlike", "buffer"])
  52. def filepath_or_buffer_id(request):
  53. """
  54. A fixture yielding test ids for filepath_or_buffer testing.
  55. """
  56. return request.param
  57. @pytest.fixture
  58. def filepath_or_buffer(filepath_or_buffer_id, tmp_path):
  59. """
  60. A fixture yielding a string representing a filepath, a path-like object
  61. and a StringIO buffer. Also checks that buffer is not closed.
  62. """
  63. if filepath_or_buffer_id == "buffer":
  64. buf = StringIO()
  65. yield buf
  66. assert not buf.closed
  67. else:
  68. assert isinstance(tmp_path, Path)
  69. if filepath_or_buffer_id == "pathlike":
  70. yield tmp_path / "foo"
  71. else:
  72. yield str(tmp_path / "foo")
  73. @pytest.fixture
  74. def assert_filepath_or_buffer_equals(
  75. filepath_or_buffer, filepath_or_buffer_id, encoding
  76. ):
  77. """
  78. Assertion helper for checking filepath_or_buffer.
  79. """
  80. def _assert_filepath_or_buffer_equals(expected):
  81. if filepath_or_buffer_id == "string":
  82. with open(filepath_or_buffer, encoding=encoding) as f:
  83. result = f.read()
  84. elif filepath_or_buffer_id == "pathlike":
  85. result = filepath_or_buffer.read_text(encoding=encoding)
  86. elif filepath_or_buffer_id == "buffer":
  87. result = filepath_or_buffer.getvalue()
  88. assert result == expected
  89. return _assert_filepath_or_buffer_equals
  90. def has_info_repr(df):
  91. r = repr(df)
  92. c1 = r.split("\n")[0].startswith("<class")
  93. c2 = r.split("\n")[0].startswith(r"&lt;class") # _repr_html_
  94. return c1 or c2
  95. def has_non_verbose_info_repr(df):
  96. has_info = has_info_repr(df)
  97. r = repr(df)
  98. # 1. <class>
  99. # 2. Index
  100. # 3. Columns
  101. # 4. dtype
  102. # 5. memory usage
  103. # 6. trailing newline
  104. nv = len(r.split("\n")) == 6
  105. return has_info and nv
  106. def has_horizontally_truncated_repr(df):
  107. try: # Check header row
  108. fst_line = np.array(repr(df).splitlines()[0].split())
  109. cand_col = np.where(fst_line == "...")[0][0]
  110. except IndexError:
  111. return False
  112. # Make sure each row has this ... in the same place
  113. r = repr(df)
  114. for ix, _ in enumerate(r.splitlines()):
  115. if not r.split()[cand_col] == "...":
  116. return False
  117. return True
  118. def has_vertically_truncated_repr(df):
  119. r = repr(df)
  120. only_dot_row = False
  121. for row in r.splitlines():
  122. if re.match(r"^[\.\ ]+$", row):
  123. only_dot_row = True
  124. return only_dot_row
  125. def has_truncated_repr(df):
  126. return has_horizontally_truncated_repr(df) or has_vertically_truncated_repr(df)
  127. def has_doubly_truncated_repr(df):
  128. return has_horizontally_truncated_repr(df) and has_vertically_truncated_repr(df)
  129. def has_expanded_repr(df):
  130. r = repr(df)
  131. for line in r.split("\n"):
  132. if line.endswith("\\"):
  133. return True
  134. return False
  135. class TestDataFrameFormatting:
  136. def test_eng_float_formatter(self, float_frame):
  137. df = float_frame
  138. df.loc[5] = 0
  139. fmt.set_eng_float_format()
  140. repr(df)
  141. fmt.set_eng_float_format(use_eng_prefix=True)
  142. repr(df)
  143. fmt.set_eng_float_format(accuracy=0)
  144. repr(df)
  145. tm.reset_display_options()
  146. @pytest.mark.parametrize(
  147. "row, columns, show_counts, result",
  148. [
  149. [20, 20, None, True],
  150. [20, 20, True, True],
  151. [20, 20, False, False],
  152. [5, 5, None, False],
  153. [5, 5, True, False],
  154. [5, 5, False, False],
  155. ],
  156. )
  157. def test_show_counts(self, row, columns, show_counts, result):
  158. # Explicit cast to float to avoid implicit cast when setting nan
  159. df = DataFrame(1, columns=range(10), index=range(10)).astype({1: "float"})
  160. df.iloc[1, 1] = np.nan
  161. with option_context(
  162. "display.max_info_rows", row, "display.max_info_columns", columns
  163. ):
  164. with StringIO() as buf:
  165. df.info(buf=buf, show_counts=show_counts)
  166. assert ("non-null" in buf.getvalue()) is result
  167. def test_repr_truncation(self):
  168. max_len = 20
  169. with option_context("display.max_colwidth", max_len):
  170. df = DataFrame(
  171. {
  172. "A": np.random.randn(10),
  173. "B": [
  174. tm.rands(np.random.randint(max_len - 1, max_len + 1))
  175. for i in range(10)
  176. ],
  177. }
  178. )
  179. r = repr(df)
  180. r = r[r.find("\n") + 1 :]
  181. adj = fmt.get_adjustment()
  182. for line, value in zip(r.split("\n"), df["B"]):
  183. if adj.len(value) + 1 > max_len:
  184. assert "..." in line
  185. else:
  186. assert "..." not in line
  187. with option_context("display.max_colwidth", 999999):
  188. assert "..." not in repr(df)
  189. with option_context("display.max_colwidth", max_len + 2):
  190. assert "..." not in repr(df)
  191. def test_max_colwidth_negative_int_raises(self):
  192. # Deprecation enforced from:
  193. # https://github.com/pandas-dev/pandas/issues/31532
  194. width = get_option("display.max_colwidth")
  195. with pytest.raises(
  196. ValueError, match="Value must be a nonnegative integer or None"
  197. ):
  198. set_option("display.max_colwidth", -1)
  199. set_option("display.max_colwidth", width)
  200. def test_repr_chop_threshold(self):
  201. df = DataFrame([[0.1, 0.5], [0.5, -0.1]])
  202. reset_option("display.chop_threshold") # default None
  203. assert repr(df) == " 0 1\n0 0.1 0.5\n1 0.5 -0.1"
  204. with option_context("display.chop_threshold", 0.2):
  205. assert repr(df) == " 0 1\n0 0.0 0.5\n1 0.5 0.0"
  206. with option_context("display.chop_threshold", 0.6):
  207. assert repr(df) == " 0 1\n0 0.0 0.0\n1 0.0 0.0"
  208. with option_context("display.chop_threshold", None):
  209. assert repr(df) == " 0 1\n0 0.1 0.5\n1 0.5 -0.1"
  210. def test_repr_chop_threshold_column_below(self):
  211. # GH 6839: validation case
  212. df = DataFrame([[10, 20, 30, 40], [8e-10, -1e-11, 2e-9, -2e-11]]).T
  213. with option_context("display.chop_threshold", 0):
  214. assert repr(df) == (
  215. " 0 1\n"
  216. "0 10.0 8.000000e-10\n"
  217. "1 20.0 -1.000000e-11\n"
  218. "2 30.0 2.000000e-09\n"
  219. "3 40.0 -2.000000e-11"
  220. )
  221. with option_context("display.chop_threshold", 1e-8):
  222. assert repr(df) == (
  223. " 0 1\n"
  224. "0 10.0 0.000000e+00\n"
  225. "1 20.0 0.000000e+00\n"
  226. "2 30.0 0.000000e+00\n"
  227. "3 40.0 0.000000e+00"
  228. )
  229. with option_context("display.chop_threshold", 5e-11):
  230. assert repr(df) == (
  231. " 0 1\n"
  232. "0 10.0 8.000000e-10\n"
  233. "1 20.0 0.000000e+00\n"
  234. "2 30.0 2.000000e-09\n"
  235. "3 40.0 0.000000e+00"
  236. )
  237. def test_repr_obeys_max_seq_limit(self):
  238. with option_context("display.max_seq_items", 2000):
  239. assert len(printing.pprint_thing(list(range(1000)))) > 1000
  240. with option_context("display.max_seq_items", 5):
  241. assert len(printing.pprint_thing(list(range(1000)))) < 100
  242. with option_context("display.max_seq_items", 1):
  243. assert len(printing.pprint_thing(list(range(1000)))) < 9
  244. def test_repr_set(self):
  245. assert printing.pprint_thing({1}) == "{1}"
  246. def test_repr_is_valid_construction_code(self):
  247. # for the case of Index, where the repr is traditional rather than
  248. # stylized
  249. idx = Index(["a", "b"])
  250. res = eval("pd." + repr(idx))
  251. tm.assert_series_equal(Series(res), Series(idx))
  252. def test_repr_should_return_str(self):
  253. # https://docs.python.org/3/reference/datamodel.html#object.__repr__
  254. # "...The return value must be a string object."
  255. # (str on py2.x, str (unicode) on py3)
  256. data = [8, 5, 3, 5]
  257. index1 = ["\u03c3", "\u03c4", "\u03c5", "\u03c6"]
  258. cols = ["\u03c8"]
  259. df = DataFrame(data, columns=cols, index=index1)
  260. assert type(df.__repr__()) == str # both py2 / 3
  261. def test_repr_no_backslash(self):
  262. with option_context("mode.sim_interactive", True):
  263. df = DataFrame(np.random.randn(10, 4))
  264. assert "\\" not in repr(df)
  265. def test_expand_frame_repr(self):
  266. df_small = DataFrame("hello", index=[0], columns=[0])
  267. df_wide = DataFrame("hello", index=[0], columns=range(10))
  268. df_tall = DataFrame("hello", index=range(30), columns=range(5))
  269. with option_context("mode.sim_interactive", True):
  270. with option_context(
  271. "display.max_columns",
  272. 10,
  273. "display.width",
  274. 20,
  275. "display.max_rows",
  276. 20,
  277. "display.show_dimensions",
  278. True,
  279. ):
  280. with option_context("display.expand_frame_repr", True):
  281. assert not has_truncated_repr(df_small)
  282. assert not has_expanded_repr(df_small)
  283. assert not has_truncated_repr(df_wide)
  284. assert has_expanded_repr(df_wide)
  285. assert has_vertically_truncated_repr(df_tall)
  286. assert has_expanded_repr(df_tall)
  287. with option_context("display.expand_frame_repr", False):
  288. assert not has_truncated_repr(df_small)
  289. assert not has_expanded_repr(df_small)
  290. assert not has_horizontally_truncated_repr(df_wide)
  291. assert not has_expanded_repr(df_wide)
  292. assert has_vertically_truncated_repr(df_tall)
  293. assert not has_expanded_repr(df_tall)
  294. def test_repr_non_interactive(self):
  295. # in non interactive mode, there can be no dependency on the
  296. # result of terminal auto size detection
  297. df = DataFrame("hello", index=range(1000), columns=range(5))
  298. with option_context(
  299. "mode.sim_interactive", False, "display.width", 0, "display.max_rows", 5000
  300. ):
  301. assert not has_truncated_repr(df)
  302. assert not has_expanded_repr(df)
  303. def test_repr_truncates_terminal_size(self, monkeypatch):
  304. # see gh-21180
  305. terminal_size = (118, 96)
  306. monkeypatch.setattr(
  307. "pandas.io.formats.format.get_terminal_size", lambda: terminal_size
  308. )
  309. index = range(5)
  310. columns = MultiIndex.from_tuples(
  311. [
  312. ("This is a long title with > 37 chars.", "cat"),
  313. ("This is a loooooonger title with > 43 chars.", "dog"),
  314. ]
  315. )
  316. df = DataFrame(1, index=index, columns=columns)
  317. result = repr(df)
  318. h1, h2 = result.split("\n")[:2]
  319. assert "long" in h1
  320. assert "loooooonger" in h1
  321. assert "cat" in h2
  322. assert "dog" in h2
  323. # regular columns
  324. df2 = DataFrame({"A" * 41: [1, 2], "B" * 41: [1, 2]})
  325. result = repr(df2)
  326. assert df2.columns[0] in result.split("\n")[0]
  327. def test_repr_truncates_terminal_size_full(self, monkeypatch):
  328. # GH 22984 ensure entire window is filled
  329. terminal_size = (80, 24)
  330. df = DataFrame(np.random.rand(1, 7))
  331. monkeypatch.setattr(
  332. "pandas.io.formats.format.get_terminal_size", lambda: terminal_size
  333. )
  334. assert "..." not in str(df)
  335. def test_repr_truncation_column_size(self):
  336. # dataframe with last column very wide -> check it is not used to
  337. # determine size of truncation (...) column
  338. df = DataFrame(
  339. {
  340. "a": [108480, 30830],
  341. "b": [12345, 12345],
  342. "c": [12345, 12345],
  343. "d": [12345, 12345],
  344. "e": ["a" * 50] * 2,
  345. }
  346. )
  347. assert "..." in str(df)
  348. assert " ... " not in str(df)
  349. def test_repr_max_columns_max_rows(self):
  350. term_width, term_height = get_terminal_size()
  351. if term_width < 10 or term_height < 10:
  352. pytest.skip(f"terminal size too small, {term_width} x {term_height}")
  353. def mkframe(n):
  354. index = [f"{i:05d}" for i in range(n)]
  355. return DataFrame(0, index, index)
  356. df6 = mkframe(6)
  357. df10 = mkframe(10)
  358. with option_context("mode.sim_interactive", True):
  359. with option_context("display.width", term_width * 2):
  360. with option_context("display.max_rows", 5, "display.max_columns", 5):
  361. assert not has_expanded_repr(mkframe(4))
  362. assert not has_expanded_repr(mkframe(5))
  363. assert not has_expanded_repr(df6)
  364. assert has_doubly_truncated_repr(df6)
  365. with option_context("display.max_rows", 20, "display.max_columns", 10):
  366. # Out off max_columns boundary, but no extending
  367. # since not exceeding width
  368. assert not has_expanded_repr(df6)
  369. assert not has_truncated_repr(df6)
  370. with option_context("display.max_rows", 9, "display.max_columns", 10):
  371. # out vertical bounds can not result in expanded repr
  372. assert not has_expanded_repr(df10)
  373. assert has_vertically_truncated_repr(df10)
  374. # width=None in terminal, auto detection
  375. with option_context(
  376. "display.max_columns",
  377. 100,
  378. "display.max_rows",
  379. term_width * 20,
  380. "display.width",
  381. None,
  382. ):
  383. df = mkframe((term_width // 7) - 2)
  384. assert not has_expanded_repr(df)
  385. df = mkframe((term_width // 7) + 2)
  386. printing.pprint_thing(df._repr_fits_horizontal_())
  387. assert has_expanded_repr(df)
  388. def test_repr_min_rows(self):
  389. df = DataFrame({"a": range(20)})
  390. # default setting no truncation even if above min_rows
  391. assert ".." not in repr(df)
  392. assert ".." not in df._repr_html_()
  393. df = DataFrame({"a": range(61)})
  394. # default of max_rows 60 triggers truncation if above
  395. assert ".." in repr(df)
  396. assert ".." in df._repr_html_()
  397. with option_context("display.max_rows", 10, "display.min_rows", 4):
  398. # truncated after first two rows
  399. assert ".." in repr(df)
  400. assert "2 " not in repr(df)
  401. assert "..." in df._repr_html_()
  402. assert "<td>2</td>" not in df._repr_html_()
  403. with option_context("display.max_rows", 12, "display.min_rows", None):
  404. # when set to None, follow value of max_rows
  405. assert "5 5" in repr(df)
  406. assert "<td>5</td>" in df._repr_html_()
  407. with option_context("display.max_rows", 10, "display.min_rows", 12):
  408. # when set value higher as max_rows, use the minimum
  409. assert "5 5" not in repr(df)
  410. assert "<td>5</td>" not in df._repr_html_()
  411. with option_context("display.max_rows", None, "display.min_rows", 12):
  412. # max_rows of None -> never truncate
  413. assert ".." not in repr(df)
  414. assert ".." not in df._repr_html_()
  415. def test_str_max_colwidth(self):
  416. # GH 7856
  417. df = DataFrame(
  418. [
  419. {
  420. "a": "foo",
  421. "b": "bar",
  422. "c": "uncomfortably long line with lots of stuff",
  423. "d": 1,
  424. },
  425. {"a": "foo", "b": "bar", "c": "stuff", "d": 1},
  426. ]
  427. )
  428. df.set_index(["a", "b", "c"])
  429. assert str(df) == (
  430. " a b c d\n"
  431. "0 foo bar uncomfortably long line with lots of stuff 1\n"
  432. "1 foo bar stuff 1"
  433. )
  434. with option_context("max_colwidth", 20):
  435. assert str(df) == (
  436. " a b c d\n"
  437. "0 foo bar uncomfortably lo... 1\n"
  438. "1 foo bar stuff 1"
  439. )
  440. def test_auto_detect(self):
  441. term_width, term_height = get_terminal_size()
  442. fac = 1.05 # Arbitrary large factor to exceed term width
  443. cols = range(int(term_width * fac))
  444. index = range(10)
  445. df = DataFrame(index=index, columns=cols)
  446. with option_context("mode.sim_interactive", True):
  447. with option_context("display.max_rows", None):
  448. with option_context("display.max_columns", None):
  449. # Wrap around with None
  450. assert has_expanded_repr(df)
  451. with option_context("display.max_rows", 0):
  452. with option_context("display.max_columns", 0):
  453. # Truncate with auto detection.
  454. assert has_horizontally_truncated_repr(df)
  455. index = range(int(term_height * fac))
  456. df = DataFrame(index=index, columns=cols)
  457. with option_context("display.max_rows", 0):
  458. with option_context("display.max_columns", None):
  459. # Wrap around with None
  460. assert has_expanded_repr(df)
  461. # Truncate vertically
  462. assert has_vertically_truncated_repr(df)
  463. with option_context("display.max_rows", None):
  464. with option_context("display.max_columns", 0):
  465. assert has_horizontally_truncated_repr(df)
  466. def test_to_string_repr_unicode(self):
  467. buf = StringIO()
  468. unicode_values = ["\u03c3"] * 10
  469. unicode_values = np.array(unicode_values, dtype=object)
  470. df = DataFrame({"unicode": unicode_values})
  471. df.to_string(col_space=10, buf=buf)
  472. # it works!
  473. repr(df)
  474. idx = Index(["abc", "\u03c3a", "aegdvg"])
  475. ser = Series(np.random.randn(len(idx)), idx)
  476. rs = repr(ser).split("\n")
  477. line_len = len(rs[0])
  478. for line in rs[1:]:
  479. try:
  480. line = line.decode(get_option("display.encoding"))
  481. except AttributeError:
  482. pass
  483. if not line.startswith("dtype:"):
  484. assert len(line) == line_len
  485. # it works even if sys.stdin in None
  486. _stdin = sys.stdin
  487. try:
  488. sys.stdin = None
  489. repr(df)
  490. finally:
  491. sys.stdin = _stdin
  492. def test_east_asian_unicode_false(self):
  493. # not aligned properly because of east asian width
  494. # mid col
  495. df = DataFrame(
  496. {"a": ["あ", "いいい", "う", "ええええええ"], "b": [1, 222, 33333, 4]},
  497. index=["a", "bb", "c", "ddd"],
  498. )
  499. expected = (
  500. " a b\na あ 1\n"
  501. "bb いいい 222\nc う 33333\n"
  502. "ddd ええええええ 4"
  503. )
  504. assert repr(df) == expected
  505. # last col
  506. df = DataFrame(
  507. {"a": [1, 222, 33333, 4], "b": ["あ", "いいい", "う", "ええええええ"]},
  508. index=["a", "bb", "c", "ddd"],
  509. )
  510. expected = (
  511. " a b\na 1 あ\n"
  512. "bb 222 いいい\nc 33333 う\n"
  513. "ddd 4 ええええええ"
  514. )
  515. assert repr(df) == expected
  516. # all col
  517. df = DataFrame(
  518. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  519. index=["a", "bb", "c", "ddd"],
  520. )
  521. expected = (
  522. " a b\na あああああ あ\n"
  523. "bb い いいい\nc う う\n"
  524. "ddd えええ ええええええ"
  525. )
  526. assert repr(df) == expected
  527. # column name
  528. df = DataFrame(
  529. {"b": ["あ", "いいい", "う", "ええええええ"], "あああああ": [1, 222, 33333, 4]},
  530. index=["a", "bb", "c", "ddd"],
  531. )
  532. expected = (
  533. " b あああああ\na あ 1\n"
  534. "bb いいい 222\nc う 33333\n"
  535. "ddd ええええええ 4"
  536. )
  537. assert repr(df) == expected
  538. # index
  539. df = DataFrame(
  540. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  541. index=["あああ", "いいいいいい", "うう", "え"],
  542. )
  543. expected = (
  544. " a b\nあああ あああああ あ\n"
  545. "いいいいいい い いいい\nうう う う\n"
  546. "え えええ ええええええ"
  547. )
  548. assert repr(df) == expected
  549. # index name
  550. df = DataFrame(
  551. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  552. index=Index(["あ", "い", "うう", "え"], name="おおおお"),
  553. )
  554. expected = (
  555. " a b\n"
  556. "おおおお \n"
  557. "あ あああああ あ\n"
  558. "い い いいい\n"
  559. "うう う う\n"
  560. "え えええ ええええええ"
  561. )
  562. assert repr(df) == expected
  563. # all
  564. df = DataFrame(
  565. {"あああ": ["あああ", "い", "う", "えええええ"], "いいいいい": ["あ", "いいい", "う", "ええ"]},
  566. index=Index(["あ", "いいい", "うう", "え"], name="お"),
  567. )
  568. expected = (
  569. " あああ いいいいい\n"
  570. "お \n"
  571. "あ あああ あ\n"
  572. "いいい い いいい\n"
  573. "うう う う\n"
  574. "え えええええ ええ"
  575. )
  576. assert repr(df) == expected
  577. # MultiIndex
  578. idx = MultiIndex.from_tuples(
  579. [("あ", "いい"), ("う", "え"), ("おおお", "かかかか"), ("き", "くく")]
  580. )
  581. df = DataFrame(
  582. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  583. index=idx,
  584. )
  585. expected = (
  586. " a b\n"
  587. "あ いい あああああ あ\n"
  588. "う え い いいい\n"
  589. "おおお かかかか う う\n"
  590. "き くく えええ ええええええ"
  591. )
  592. assert repr(df) == expected
  593. # truncate
  594. with option_context("display.max_rows", 3, "display.max_columns", 3):
  595. df = DataFrame(
  596. {
  597. "a": ["あああああ", "い", "う", "えええ"],
  598. "b": ["あ", "いいい", "う", "ええええええ"],
  599. "c": ["お", "か", "ききき", "くくくくくく"],
  600. "ああああ": ["さ", "し", "す", "せ"],
  601. },
  602. columns=["a", "b", "c", "ああああ"],
  603. )
  604. expected = (
  605. " a ... ああああ\n0 あああああ ... さ\n"
  606. ".. ... ... ...\n3 えええ ... せ\n"
  607. "\n[4 rows x 4 columns]"
  608. )
  609. assert repr(df) == expected
  610. df.index = ["あああ", "いいいい", "う", "aaa"]
  611. expected = (
  612. " a ... ああああ\nあああ あああああ ... さ\n"
  613. ".. ... ... ...\naaa えええ ... せ\n"
  614. "\n[4 rows x 4 columns]"
  615. )
  616. assert repr(df) == expected
  617. def test_east_asian_unicode_true(self):
  618. # Enable Unicode option -----------------------------------------
  619. with option_context("display.unicode.east_asian_width", True):
  620. # mid col
  621. df = DataFrame(
  622. {"a": ["あ", "いいい", "う", "ええええええ"], "b": [1, 222, 33333, 4]},
  623. index=["a", "bb", "c", "ddd"],
  624. )
  625. expected = (
  626. " a b\na あ 1\n"
  627. "bb いいい 222\nc う 33333\n"
  628. "ddd ええええええ 4"
  629. )
  630. assert repr(df) == expected
  631. # last col
  632. df = DataFrame(
  633. {"a": [1, 222, 33333, 4], "b": ["あ", "いいい", "う", "ええええええ"]},
  634. index=["a", "bb", "c", "ddd"],
  635. )
  636. expected = (
  637. " a b\na 1 あ\n"
  638. "bb 222 いいい\nc 33333 う\n"
  639. "ddd 4 ええええええ"
  640. )
  641. assert repr(df) == expected
  642. # all col
  643. df = DataFrame(
  644. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  645. index=["a", "bb", "c", "ddd"],
  646. )
  647. expected = (
  648. " a b\n"
  649. "a あああああ あ\n"
  650. "bb い いいい\n"
  651. "c う う\n"
  652. "ddd えええ ええええええ"
  653. )
  654. assert repr(df) == expected
  655. # column name
  656. df = DataFrame(
  657. {"b": ["あ", "いいい", "う", "ええええええ"], "あああああ": [1, 222, 33333, 4]},
  658. index=["a", "bb", "c", "ddd"],
  659. )
  660. expected = (
  661. " b あああああ\n"
  662. "a あ 1\n"
  663. "bb いいい 222\n"
  664. "c う 33333\n"
  665. "ddd ええええええ 4"
  666. )
  667. assert repr(df) == expected
  668. # index
  669. df = DataFrame(
  670. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  671. index=["あああ", "いいいいいい", "うう", "え"],
  672. )
  673. expected = (
  674. " a b\n"
  675. "あああ あああああ あ\n"
  676. "いいいいいい い いいい\n"
  677. "うう う う\n"
  678. "え えええ ええええええ"
  679. )
  680. assert repr(df) == expected
  681. # index name
  682. df = DataFrame(
  683. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  684. index=Index(["あ", "い", "うう", "え"], name="おおおお"),
  685. )
  686. expected = (
  687. " a b\n"
  688. "おおおお \n"
  689. "あ あああああ あ\n"
  690. "い い いいい\n"
  691. "うう う う\n"
  692. "え えええ ええええええ"
  693. )
  694. assert repr(df) == expected
  695. # all
  696. df = DataFrame(
  697. {"あああ": ["あああ", "い", "う", "えええええ"], "いいいいい": ["あ", "いいい", "う", "ええ"]},
  698. index=Index(["あ", "いいい", "うう", "え"], name="お"),
  699. )
  700. expected = (
  701. " あああ いいいいい\n"
  702. "お \n"
  703. "あ あああ あ\n"
  704. "いいい い いいい\n"
  705. "うう う う\n"
  706. "え えええええ ええ"
  707. )
  708. assert repr(df) == expected
  709. # MultiIndex
  710. idx = MultiIndex.from_tuples(
  711. [("あ", "いい"), ("う", "え"), ("おおお", "かかかか"), ("き", "くく")]
  712. )
  713. df = DataFrame(
  714. {"a": ["あああああ", "い", "う", "えええ"], "b": ["あ", "いいい", "う", "ええええええ"]},
  715. index=idx,
  716. )
  717. expected = (
  718. " a b\n"
  719. "あ いい あああああ あ\n"
  720. "う え い いいい\n"
  721. "おおお かかかか う う\n"
  722. "き くく えええ ええええええ"
  723. )
  724. assert repr(df) == expected
  725. # truncate
  726. with option_context("display.max_rows", 3, "display.max_columns", 3):
  727. df = DataFrame(
  728. {
  729. "a": ["あああああ", "い", "う", "えええ"],
  730. "b": ["あ", "いいい", "う", "ええええええ"],
  731. "c": ["お", "か", "ききき", "くくくくくく"],
  732. "ああああ": ["さ", "し", "す", "せ"],
  733. },
  734. columns=["a", "b", "c", "ああああ"],
  735. )
  736. expected = (
  737. " a ... ああああ\n"
  738. "0 あああああ ... さ\n"
  739. ".. ... ... ...\n"
  740. "3 えええ ... せ\n"
  741. "\n[4 rows x 4 columns]"
  742. )
  743. assert repr(df) == expected
  744. df.index = ["あああ", "いいいい", "う", "aaa"]
  745. expected = (
  746. " a ... ああああ\n"
  747. "あああ あああああ ... さ\n"
  748. "... ... ... ...\n"
  749. "aaa えええ ... せ\n"
  750. "\n[4 rows x 4 columns]"
  751. )
  752. assert repr(df) == expected
  753. # ambiguous unicode
  754. df = DataFrame(
  755. {"b": ["あ", "いいい", "¡¡", "ええええええ"], "あああああ": [1, 222, 33333, 4]},
  756. index=["a", "bb", "c", "¡¡¡"],
  757. )
  758. expected = (
  759. " b あああああ\n"
  760. "a あ 1\n"
  761. "bb いいい 222\n"
  762. "c ¡¡ 33333\n"
  763. "¡¡¡ ええええええ 4"
  764. )
  765. assert repr(df) == expected
  766. def test_to_string_buffer_all_unicode(self):
  767. buf = StringIO()
  768. empty = DataFrame({"c/\u03c3": Series(dtype=object)})
  769. nonempty = DataFrame({"c/\u03c3": Series([1, 2, 3])})
  770. print(empty, file=buf)
  771. print(nonempty, file=buf)
  772. # this should work
  773. buf.getvalue()
  774. def test_to_string_with_col_space(self):
  775. df = DataFrame(np.random.random(size=(1, 3)))
  776. c10 = len(df.to_string(col_space=10).split("\n")[1])
  777. c20 = len(df.to_string(col_space=20).split("\n")[1])
  778. c30 = len(df.to_string(col_space=30).split("\n")[1])
  779. assert c10 < c20 < c30
  780. # GH 8230
  781. # col_space wasn't being applied with header=False
  782. with_header = df.to_string(col_space=20)
  783. with_header_row1 = with_header.splitlines()[1]
  784. no_header = df.to_string(col_space=20, header=False)
  785. assert len(with_header_row1) == len(no_header)
  786. def test_to_string_with_column_specific_col_space_raises(self):
  787. df = DataFrame(np.random.random(size=(3, 3)), columns=["a", "b", "c"])
  788. msg = (
  789. "Col_space length\\(\\d+\\) should match "
  790. "DataFrame number of columns\\(\\d+\\)"
  791. )
  792. with pytest.raises(ValueError, match=msg):
  793. df.to_string(col_space=[30, 40])
  794. with pytest.raises(ValueError, match=msg):
  795. df.to_string(col_space=[30, 40, 50, 60])
  796. msg = "unknown column"
  797. with pytest.raises(ValueError, match=msg):
  798. df.to_string(col_space={"a": "foo", "b": 23, "d": 34})
  799. def test_to_string_with_column_specific_col_space(self):
  800. df = DataFrame(np.random.random(size=(3, 3)), columns=["a", "b", "c"])
  801. result = df.to_string(col_space={"a": 10, "b": 11, "c": 12})
  802. # 3 separating space + each col_space for (id, a, b, c)
  803. assert len(result.split("\n")[1]) == (3 + 1 + 10 + 11 + 12)
  804. result = df.to_string(col_space=[10, 11, 12])
  805. assert len(result.split("\n")[1]) == (3 + 1 + 10 + 11 + 12)
  806. @pytest.mark.parametrize(
  807. "index",
  808. [
  809. tm.makeStringIndex,
  810. tm.makeIntIndex,
  811. tm.makeDateIndex,
  812. tm.makePeriodIndex,
  813. ],
  814. )
  815. @pytest.mark.parametrize("h", [10, 20])
  816. @pytest.mark.parametrize("w", [10, 20])
  817. def test_to_string_truncate_indices(self, index, h, w):
  818. with option_context("display.expand_frame_repr", False):
  819. df = DataFrame(index=index(h), columns=tm.makeStringIndex(w))
  820. with option_context("display.max_rows", 15):
  821. if h == 20:
  822. assert has_vertically_truncated_repr(df)
  823. else:
  824. assert not has_vertically_truncated_repr(df)
  825. with option_context("display.max_columns", 15):
  826. if w == 20:
  827. assert has_horizontally_truncated_repr(df)
  828. else:
  829. assert not has_horizontally_truncated_repr(df)
  830. with option_context("display.max_rows", 15, "display.max_columns", 15):
  831. if h == 20 and w == 20:
  832. assert has_doubly_truncated_repr(df)
  833. else:
  834. assert not has_doubly_truncated_repr(df)
  835. def test_to_string_truncate_multilevel(self):
  836. arrays = [
  837. ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"],
  838. ["one", "two", "one", "two", "one", "two", "one", "two"],
  839. ]
  840. df = DataFrame(index=arrays, columns=arrays)
  841. with option_context("display.max_rows", 7, "display.max_columns", 7):
  842. assert has_doubly_truncated_repr(df)
  843. def test_truncate_with_different_dtypes(self):
  844. # 11594, 12045
  845. # when truncated the dtypes of the splits can differ
  846. # 11594
  847. s = Series(
  848. [datetime(2012, 1, 1)] * 10
  849. + [datetime(1012, 1, 2)]
  850. + [datetime(2012, 1, 3)] * 10
  851. )
  852. with option_context("display.max_rows", 8):
  853. result = str(s)
  854. assert "object" in result
  855. # 12045
  856. df = DataFrame({"text": ["some words"] + [None] * 9})
  857. with option_context("display.max_rows", 8, "display.max_columns", 3):
  858. result = str(df)
  859. assert "None" in result
  860. assert "NaN" not in result
  861. def test_truncate_with_different_dtypes_multiindex(self):
  862. # GH#13000
  863. df = DataFrame({"Vals": range(100)})
  864. frame = pd.concat([df], keys=["Sweep"], names=["Sweep", "Index"])
  865. result = repr(frame)
  866. result2 = repr(frame.iloc[:5])
  867. assert result.startswith(result2)
  868. def test_datetimelike_frame(self):
  869. # GH 12211
  870. df = DataFrame({"date": [Timestamp("20130101").tz_localize("UTC")] + [NaT] * 5})
  871. with option_context("display.max_rows", 5):
  872. result = str(df)
  873. assert "2013-01-01 00:00:00+00:00" in result
  874. assert "NaT" in result
  875. assert "..." in result
  876. assert "[6 rows x 1 columns]" in result
  877. dts = [Timestamp("2011-01-01", tz="US/Eastern")] * 5 + [NaT] * 5
  878. df = DataFrame({"dt": dts, "x": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]})
  879. with option_context("display.max_rows", 5):
  880. expected = (
  881. " dt x\n"
  882. "0 2011-01-01 00:00:00-05:00 1\n"
  883. "1 2011-01-01 00:00:00-05:00 2\n"
  884. ".. ... ..\n"
  885. "8 NaT 9\n"
  886. "9 NaT 10\n\n"
  887. "[10 rows x 2 columns]"
  888. )
  889. assert repr(df) == expected
  890. dts = [NaT] * 5 + [Timestamp("2011-01-01", tz="US/Eastern")] * 5
  891. df = DataFrame({"dt": dts, "x": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]})
  892. with option_context("display.max_rows", 5):
  893. expected = (
  894. " dt x\n"
  895. "0 NaT 1\n"
  896. "1 NaT 2\n"
  897. ".. ... ..\n"
  898. "8 2011-01-01 00:00:00-05:00 9\n"
  899. "9 2011-01-01 00:00:00-05:00 10\n\n"
  900. "[10 rows x 2 columns]"
  901. )
  902. assert repr(df) == expected
  903. dts = [Timestamp("2011-01-01", tz="Asia/Tokyo")] * 5 + [
  904. Timestamp("2011-01-01", tz="US/Eastern")
  905. ] * 5
  906. df = DataFrame({"dt": dts, "x": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]})
  907. with option_context("display.max_rows", 5):
  908. expected = (
  909. " dt x\n"
  910. "0 2011-01-01 00:00:00+09:00 1\n"
  911. "1 2011-01-01 00:00:00+09:00 2\n"
  912. ".. ... ..\n"
  913. "8 2011-01-01 00:00:00-05:00 9\n"
  914. "9 2011-01-01 00:00:00-05:00 10\n\n"
  915. "[10 rows x 2 columns]"
  916. )
  917. assert repr(df) == expected
  918. @pytest.mark.parametrize(
  919. "start_date",
  920. [
  921. "2017-01-01 23:59:59.999999999",
  922. "2017-01-01 23:59:59.99999999",
  923. "2017-01-01 23:59:59.9999999",
  924. "2017-01-01 23:59:59.999999",
  925. "2017-01-01 23:59:59.99999",
  926. "2017-01-01 23:59:59.9999",
  927. ],
  928. )
  929. def test_datetimeindex_highprecision(self, start_date):
  930. # GH19030
  931. # Check that high-precision time values for the end of day are
  932. # included in repr for DatetimeIndex
  933. df = DataFrame({"A": date_range(start=start_date, freq="D", periods=5)})
  934. result = str(df)
  935. assert start_date in result
  936. dti = date_range(start=start_date, freq="D", periods=5)
  937. df = DataFrame({"A": range(5)}, index=dti)
  938. result = str(df.index)
  939. assert start_date in result
  940. def test_nonunicode_nonascii_alignment(self):
  941. df = DataFrame([["aa\xc3\xa4\xc3\xa4", 1], ["bbbb", 2]])
  942. rep_str = df.to_string()
  943. lines = rep_str.split("\n")
  944. assert len(lines[1]) == len(lines[2])
  945. def test_unicode_problem_decoding_as_ascii(self):
  946. dm = DataFrame({"c/\u03c3": Series({"test": np.nan})})
  947. str(dm.to_string())
  948. def test_string_repr_encoding(self, datapath):
  949. filepath = datapath("io", "parser", "data", "unicode_series.csv")
  950. df = read_csv(filepath, header=None, encoding="latin1")
  951. repr(df)
  952. repr(df[1])
  953. def test_repr_corner(self):
  954. # representing infs poses no problems
  955. df = DataFrame({"foo": [-np.inf, np.inf]})
  956. repr(df)
  957. def test_frame_info_encoding(self):
  958. index = ["'Til There Was You (1997)", "ldum klaka (Cold Fever) (1994)"]
  959. fmt.set_option("display.max_rows", 1)
  960. df = DataFrame(columns=["a", "b", "c"], index=index)
  961. repr(df)
  962. repr(df.T)
  963. fmt.set_option("display.max_rows", 200)
  964. def test_wide_repr(self):
  965. with option_context(
  966. "mode.sim_interactive",
  967. True,
  968. "display.show_dimensions",
  969. True,
  970. "display.max_columns",
  971. 20,
  972. ):
  973. max_cols = get_option("display.max_columns")
  974. df = DataFrame(tm.rands_array(25, size=(10, max_cols - 1)))
  975. with option_context("display.expand_frame_repr", False):
  976. rep_str = repr(df)
  977. assert f"10 rows x {max_cols - 1} columns" in rep_str
  978. with option_context("display.expand_frame_repr", True):
  979. wide_repr = repr(df)
  980. assert rep_str != wide_repr
  981. with option_context("display.width", 120):
  982. wider_repr = repr(df)
  983. assert len(wider_repr) < len(wide_repr)
  984. def test_wide_repr_wide_columns(self):
  985. with option_context("mode.sim_interactive", True, "display.max_columns", 20):
  986. df = DataFrame(
  987. np.random.randn(5, 3), columns=["a" * 90, "b" * 90, "c" * 90]
  988. )
  989. rep_str = repr(df)
  990. assert len(rep_str.splitlines()) == 20
  991. def test_wide_repr_named(self):
  992. with option_context("mode.sim_interactive", True, "display.max_columns", 20):
  993. max_cols = get_option("display.max_columns")
  994. df = DataFrame(tm.rands_array(25, size=(10, max_cols - 1)))
  995. df.index.name = "DataFrame Index"
  996. with option_context("display.expand_frame_repr", False):
  997. rep_str = repr(df)
  998. with option_context("display.expand_frame_repr", True):
  999. wide_repr = repr(df)
  1000. assert rep_str != wide_repr
  1001. with option_context("display.width", 150):
  1002. wider_repr = repr(df)
  1003. assert len(wider_repr) < len(wide_repr)
  1004. for line in wide_repr.splitlines()[1::13]:
  1005. assert "DataFrame Index" in line
  1006. def test_wide_repr_multiindex(self):
  1007. with option_context("mode.sim_interactive", True, "display.max_columns", 20):
  1008. midx = MultiIndex.from_arrays(tm.rands_array(5, size=(2, 10)))
  1009. max_cols = get_option("display.max_columns")
  1010. df = DataFrame(tm.rands_array(25, size=(10, max_cols - 1)), index=midx)
  1011. df.index.names = ["Level 0", "Level 1"]
  1012. with option_context("display.expand_frame_repr", False):
  1013. rep_str = repr(df)
  1014. with option_context("display.expand_frame_repr", True):
  1015. wide_repr = repr(df)
  1016. assert rep_str != wide_repr
  1017. with option_context("display.width", 150):
  1018. wider_repr = repr(df)
  1019. assert len(wider_repr) < len(wide_repr)
  1020. for line in wide_repr.splitlines()[1::13]:
  1021. assert "Level 0 Level 1" in line
  1022. def test_wide_repr_multiindex_cols(self):
  1023. with option_context("mode.sim_interactive", True, "display.max_columns", 20):
  1024. max_cols = get_option("display.max_columns")
  1025. midx = MultiIndex.from_arrays(tm.rands_array(5, size=(2, 10)))
  1026. mcols = MultiIndex.from_arrays(tm.rands_array(3, size=(2, max_cols - 1)))
  1027. df = DataFrame(
  1028. tm.rands_array(25, (10, max_cols - 1)), index=midx, columns=mcols
  1029. )
  1030. df.index.names = ["Level 0", "Level 1"]
  1031. with option_context("display.expand_frame_repr", False):
  1032. rep_str = repr(df)
  1033. with option_context("display.expand_frame_repr", True):
  1034. wide_repr = repr(df)
  1035. assert rep_str != wide_repr
  1036. with option_context("display.width", 150, "display.max_columns", 20):
  1037. wider_repr = repr(df)
  1038. assert len(wider_repr) < len(wide_repr)
  1039. def test_wide_repr_unicode(self):
  1040. with option_context("mode.sim_interactive", True, "display.max_columns", 20):
  1041. max_cols = 20
  1042. df = DataFrame(tm.rands_array(25, size=(10, max_cols - 1)))
  1043. with option_context("display.expand_frame_repr", False):
  1044. rep_str = repr(df)
  1045. with option_context("display.expand_frame_repr", True):
  1046. wide_repr = repr(df)
  1047. assert rep_str != wide_repr
  1048. with option_context("display.width", 150):
  1049. wider_repr = repr(df)
  1050. assert len(wider_repr) < len(wide_repr)
  1051. def test_wide_repr_wide_long_columns(self):
  1052. with option_context("mode.sim_interactive", True):
  1053. df = DataFrame({"a": ["a" * 30, "b" * 30], "b": ["c" * 70, "d" * 80]})
  1054. result = repr(df)
  1055. assert "ccccc" in result
  1056. assert "ddddd" in result
  1057. def test_long_series(self):
  1058. n = 1000
  1059. s = Series(
  1060. np.random.randint(-50, 50, n),
  1061. index=[f"s{x:04d}" for x in range(n)],
  1062. dtype="int64",
  1063. )
  1064. str_rep = str(s)
  1065. nmatches = len(re.findall("dtype", str_rep))
  1066. assert nmatches == 1
  1067. def test_index_with_nan(self):
  1068. # GH 2850
  1069. df = DataFrame(
  1070. {
  1071. "id1": {0: "1a3", 1: "9h4"},
  1072. "id2": {0: np.nan, 1: "d67"},
  1073. "id3": {0: "78d", 1: "79d"},
  1074. "value": {0: 123, 1: 64},
  1075. }
  1076. )
  1077. # multi-index
  1078. y = df.set_index(["id1", "id2", "id3"])
  1079. result = y.to_string()
  1080. expected = (
  1081. " value\nid1 id2 id3 \n"
  1082. "1a3 NaN 78d 123\n9h4 d67 79d 64"
  1083. )
  1084. assert result == expected
  1085. # index
  1086. y = df.set_index("id2")
  1087. result = y.to_string()
  1088. expected = (
  1089. " id1 id3 value\nid2 \n"
  1090. "NaN 1a3 78d 123\nd67 9h4 79d 64"
  1091. )
  1092. assert result == expected
  1093. # with append (this failed in 0.12)
  1094. y = df.set_index(["id1", "id2"]).set_index("id3", append=True)
  1095. result = y.to_string()
  1096. expected = (
  1097. " value\nid1 id2 id3 \n"
  1098. "1a3 NaN 78d 123\n9h4 d67 79d 64"
  1099. )
  1100. assert result == expected
  1101. # all-nan in mi
  1102. df2 = df.copy()
  1103. df2.loc[:, "id2"] = np.nan
  1104. y = df2.set_index("id2")
  1105. result = y.to_string()
  1106. expected = (
  1107. " id1 id3 value\nid2 \n"
  1108. "NaN 1a3 78d 123\nNaN 9h4 79d 64"
  1109. )
  1110. assert result == expected
  1111. # partial nan in mi
  1112. df2 = df.copy()
  1113. df2.loc[:, "id2"] = np.nan
  1114. y = df2.set_index(["id2", "id3"])
  1115. result = y.to_string()
  1116. expected = (
  1117. " id1 value\nid2 id3 \n"
  1118. "NaN 78d 1a3 123\n 79d 9h4 64"
  1119. )
  1120. assert result == expected
  1121. df = DataFrame(
  1122. {
  1123. "id1": {0: np.nan, 1: "9h4"},
  1124. "id2": {0: np.nan, 1: "d67"},
  1125. "id3": {0: np.nan, 1: "79d"},
  1126. "value": {0: 123, 1: 64},
  1127. }
  1128. )
  1129. y = df.set_index(["id1", "id2", "id3"])
  1130. result = y.to_string()
  1131. expected = (
  1132. " value\nid1 id2 id3 \n"
  1133. "NaN NaN NaN 123\n9h4 d67 79d 64"
  1134. )
  1135. assert result == expected
  1136. def test_to_string(self):
  1137. # big mixed
  1138. biggie = DataFrame(
  1139. {"A": np.random.randn(200), "B": tm.makeStringIndex(200)},
  1140. )
  1141. biggie.loc[:20, "A"] = np.nan
  1142. biggie.loc[:20, "B"] = np.nan
  1143. s = biggie.to_string()
  1144. buf = StringIO()
  1145. retval = biggie.to_string(buf=buf)
  1146. assert retval is None
  1147. assert buf.getvalue() == s
  1148. assert isinstance(s, str)
  1149. # print in right order
  1150. result = biggie.to_string(
  1151. columns=["B", "A"], col_space=17, float_format="%.5f".__mod__
  1152. )
  1153. lines = result.split("\n")
  1154. header = lines[0].strip().split()
  1155. joined = "\n".join([re.sub(r"\s+", " ", x).strip() for x in lines[1:]])
  1156. recons = read_csv(StringIO(joined), names=header, header=None, sep=" ")
  1157. tm.assert_series_equal(recons["B"], biggie["B"])
  1158. assert recons["A"].count() == biggie["A"].count()
  1159. assert (np.abs(recons["A"].dropna() - biggie["A"].dropna()) < 0.1).all()
  1160. # expected = ['B', 'A']
  1161. # assert header == expected
  1162. result = biggie.to_string(columns=["A"], col_space=17)
  1163. header = result.split("\n")[0].strip().split()
  1164. expected = ["A"]
  1165. assert header == expected
  1166. biggie.to_string(columns=["B", "A"], formatters={"A": lambda x: f"{x:.1f}"})
  1167. biggie.to_string(columns=["B", "A"], float_format=str)
  1168. biggie.to_string(columns=["B", "A"], col_space=12, float_format=str)
  1169. frame = DataFrame(index=np.arange(200))
  1170. frame.to_string()
  1171. def test_to_string_no_header(self):
  1172. df = DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
  1173. df_s = df.to_string(header=False)
  1174. expected = "0 1 4\n1 2 5\n2 3 6"
  1175. assert df_s == expected
  1176. def test_to_string_specified_header(self):
  1177. df = DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
  1178. df_s = df.to_string(header=["X", "Y"])
  1179. expected = " X Y\n0 1 4\n1 2 5\n2 3 6"
  1180. assert df_s == expected
  1181. msg = "Writing 2 cols but got 1 aliases"
  1182. with pytest.raises(ValueError, match=msg):
  1183. df.to_string(header=["X"])
  1184. def test_to_string_no_index(self):
  1185. # GH 16839, GH 13032
  1186. df = DataFrame({"x": [11, 22], "y": [33, -44], "z": ["AAA", " "]})
  1187. df_s = df.to_string(index=False)
  1188. # Leading space is expected for positive numbers.
  1189. expected = " x y z\n11 33 AAA\n22 -44 "
  1190. assert df_s == expected
  1191. df_s = df[["y", "x", "z"]].to_string(index=False)
  1192. expected = " y x z\n 33 11 AAA\n-44 22 "
  1193. assert df_s == expected
  1194. def test_to_string_line_width_no_index(self):
  1195. # GH 13998, GH 22505
  1196. df = DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
  1197. df_s = df.to_string(line_width=1, index=False)
  1198. expected = " x \\\n 1 \n 2 \n 3 \n\n y \n 4 \n 5 \n 6 "
  1199. assert df_s == expected
  1200. df = DataFrame({"x": [11, 22, 33], "y": [4, 5, 6]})
  1201. df_s = df.to_string(line_width=1, index=False)
  1202. expected = " x \\\n11 \n22 \n33 \n\n y \n 4 \n 5 \n 6 "
  1203. assert df_s == expected
  1204. df = DataFrame({"x": [11, 22, -33], "y": [4, 5, -6]})
  1205. df_s = df.to_string(line_width=1, index=False)
  1206. expected = " x \\\n 11 \n 22 \n-33 \n\n y \n 4 \n 5 \n-6 "
  1207. assert df_s == expected
  1208. def test_to_string_line_width_no_header(self):
  1209. # GH 53054
  1210. df = DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
  1211. df_s = df.to_string(line_width=1, header=False)
  1212. expected = "0 1 \\\n1 2 \n2 3 \n\n0 4 \n1 5 \n2 6 "
  1213. assert df_s == expected
  1214. df = DataFrame({"x": [11, 22, 33], "y": [4, 5, 6]})
  1215. df_s = df.to_string(line_width=1, header=False)
  1216. expected = "0 11 \\\n1 22 \n2 33 \n\n0 4 \n1 5 \n2 6 "
  1217. assert df_s == expected
  1218. df = DataFrame({"x": [11, 22, -33], "y": [4, 5, -6]})
  1219. df_s = df.to_string(line_width=1, header=False)
  1220. expected = "0 11 \\\n1 22 \n2 -33 \n\n0 4 \n1 5 \n2 -6 "
  1221. assert df_s == expected
  1222. def test_to_string_line_width_no_index_no_header(self):
  1223. # GH 53054
  1224. df = DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
  1225. df_s = df.to_string(line_width=1, index=False, header=False)
  1226. expected = "1 \\\n2 \n3 \n\n4 \n5 \n6 "
  1227. assert df_s == expected
  1228. df = DataFrame({"x": [11, 22, 33], "y": [4, 5, 6]})
  1229. df_s = df.to_string(line_width=1, index=False, header=False)
  1230. expected = "11 \\\n22 \n33 \n\n4 \n5 \n6 "
  1231. assert df_s == expected
  1232. df = DataFrame({"x": [11, 22, -33], "y": [4, 5, -6]})
  1233. df_s = df.to_string(line_width=1, index=False, header=False)
  1234. expected = " 11 \\\n 22 \n-33 \n\n 4 \n 5 \n-6 "
  1235. assert df_s == expected
  1236. def test_to_string_line_width_with_both_index_and_header(self):
  1237. # GH 53054
  1238. df = DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
  1239. df_s = df.to_string(line_width=1)
  1240. expected = (
  1241. " x \\\n0 1 \n1 2 \n2 3 \n\n y \n0 4 \n1 5 \n2 6 "
  1242. )
  1243. assert df_s == expected
  1244. df = DataFrame({"x": [11, 22, 33], "y": [4, 5, 6]})
  1245. df_s = df.to_string(line_width=1)
  1246. expected = (
  1247. " x \\\n0 11 \n1 22 \n2 33 \n\n y \n0 4 \n1 5 \n2 6 "
  1248. )
  1249. assert df_s == expected
  1250. df = DataFrame({"x": [11, 22, -33], "y": [4, 5, -6]})
  1251. df_s = df.to_string(line_width=1)
  1252. expected = (
  1253. " x \\\n0 11 \n1 22 \n2 -33 \n\n y \n0 4 \n1 5 \n2 -6 "
  1254. )
  1255. assert df_s == expected
  1256. def test_to_string_float_formatting(self):
  1257. tm.reset_display_options()
  1258. fmt.set_option(
  1259. "display.precision",
  1260. 5,
  1261. "display.notebook_repr_html",
  1262. False,
  1263. )
  1264. df = DataFrame(
  1265. {"x": [0, 0.25, 3456.000, 12e45, 1.64e6, 1.7e8, 1.253456, np.pi, -1e6]}
  1266. )
  1267. df_s = df.to_string()
  1268. if _three_digit_exp():
  1269. expected = (
  1270. " x\n0 0.00000e+000\n1 2.50000e-001\n"
  1271. "2 3.45600e+003\n3 1.20000e+046\n4 1.64000e+006\n"
  1272. "5 1.70000e+008\n6 1.25346e+000\n7 3.14159e+000\n"
  1273. "8 -1.00000e+006"
  1274. )
  1275. else:
  1276. expected = (
  1277. " x\n0 0.00000e+00\n1 2.50000e-01\n"
  1278. "2 3.45600e+03\n3 1.20000e+46\n4 1.64000e+06\n"
  1279. "5 1.70000e+08\n6 1.25346e+00\n7 3.14159e+00\n"
  1280. "8 -1.00000e+06"
  1281. )
  1282. assert df_s == expected
  1283. df = DataFrame({"x": [3234, 0.253]})
  1284. df_s = df.to_string()
  1285. expected = " x\n0 3234.000\n1 0.253"
  1286. assert df_s == expected
  1287. tm.reset_display_options()
  1288. assert get_option("display.precision") == 6
  1289. df = DataFrame({"x": [1e9, 0.2512]})
  1290. df_s = df.to_string()
  1291. if _three_digit_exp():
  1292. expected = " x\n0 1.000000e+009\n1 2.512000e-001"
  1293. else:
  1294. expected = " x\n0 1.000000e+09\n1 2.512000e-01"
  1295. assert df_s == expected
  1296. def test_to_string_float_format_no_fixed_width(self):
  1297. # GH 21625
  1298. df = DataFrame({"x": [0.19999]})
  1299. expected = " x\n0 0.200"
  1300. assert df.to_string(float_format="%.3f") == expected
  1301. # GH 22270
  1302. df = DataFrame({"x": [100.0]})
  1303. expected = " x\n0 100"
  1304. assert df.to_string(float_format="%.0f") == expected
  1305. def test_to_string_small_float_values(self):
  1306. df = DataFrame({"a": [1.5, 1e-17, -5.5e-7]})
  1307. result = df.to_string()
  1308. # sadness per above
  1309. if _three_digit_exp():
  1310. expected = (
  1311. " a\n"
  1312. "0 1.500000e+000\n"
  1313. "1 1.000000e-017\n"
  1314. "2 -5.500000e-007"
  1315. )
  1316. else:
  1317. expected = (
  1318. " a\n"
  1319. "0 1.500000e+00\n"
  1320. "1 1.000000e-17\n"
  1321. "2 -5.500000e-07"
  1322. )
  1323. assert result == expected
  1324. # but not all exactly zero
  1325. df = df * 0
  1326. result = df.to_string()
  1327. expected = " 0\n0 0\n1 0\n2 -0"
  1328. def test_to_string_float_index(self):
  1329. index = Index([1.5, 2, 3, 4, 5])
  1330. df = DataFrame(np.arange(5), index=index)
  1331. result = df.to_string()
  1332. expected = " 0\n1.5 0\n2.0 1\n3.0 2\n4.0 3\n5.0 4"
  1333. assert result == expected
  1334. def test_to_string_complex_float_formatting(self):
  1335. # GH #25514, 25745
  1336. with option_context("display.precision", 5):
  1337. df = DataFrame(
  1338. {
  1339. "x": [
  1340. (0.4467846931321966 + 0.0715185102060818j),
  1341. (0.2739442392974528 + 0.23515228785438969j),
  1342. (0.26974928742135185 + 0.3250604054898979j),
  1343. (-1j),
  1344. ]
  1345. }
  1346. )
  1347. result = df.to_string()
  1348. expected = (
  1349. " x\n0 0.44678+0.07152j\n"
  1350. "1 0.27394+0.23515j\n"
  1351. "2 0.26975+0.32506j\n"
  1352. "3 -0.00000-1.00000j"
  1353. )
  1354. assert result == expected
  1355. def test_to_string_ascii_error(self):
  1356. data = [
  1357. (
  1358. "0 ",
  1359. " .gitignore ",
  1360. " 5 ",
  1361. " \xe2\x80\xa2\xe2\x80\xa2\xe2\x80\xa2\xe2\x80\xa2\xe2\x80\xa2",
  1362. )
  1363. ]
  1364. df = DataFrame(data)
  1365. # it works!
  1366. repr(df)
  1367. def test_to_string_int_formatting(self):
  1368. df = DataFrame({"x": [-15, 20, 25, -35]})
  1369. assert issubclass(df["x"].dtype.type, np.integer)
  1370. output = df.to_string()
  1371. expected = " x\n0 -15\n1 20\n2 25\n3 -35"
  1372. assert output == expected
  1373. def test_to_string_index_formatter(self):
  1374. df = DataFrame([range(5), range(5, 10), range(10, 15)])
  1375. rs = df.to_string(formatters={"__index__": lambda x: "abc"[x]})
  1376. xp = """\
  1377. 0 1 2 3 4
  1378. a 0 1 2 3 4
  1379. b 5 6 7 8 9
  1380. c 10 11 12 13 14\
  1381. """
  1382. assert rs == xp
  1383. def test_to_string_left_justify_cols(self):
  1384. tm.reset_display_options()
  1385. df = DataFrame({"x": [3234, 0.253]})
  1386. df_s = df.to_string(justify="left")
  1387. expected = " x \n0 3234.000\n1 0.253"
  1388. assert df_s == expected
  1389. def test_to_string_format_na(self):
  1390. tm.reset_display_options()
  1391. df = DataFrame(
  1392. {
  1393. "A": [np.nan, -1, -2.1234, 3, 4],
  1394. "B": [np.nan, "foo", "foooo", "fooooo", "bar"],
  1395. }
  1396. )
  1397. result = df.to_string()
  1398. expected = (
  1399. " A B\n"
  1400. "0 NaN NaN\n"
  1401. "1 -1.0000 foo\n"
  1402. "2 -2.1234 foooo\n"
  1403. "3 3.0000 fooooo\n"
  1404. "4 4.0000 bar"
  1405. )
  1406. assert result == expected
  1407. df = DataFrame(
  1408. {
  1409. "A": [np.nan, -1.0, -2.0, 3.0, 4.0],
  1410. "B": [np.nan, "foo", "foooo", "fooooo", "bar"],
  1411. }
  1412. )
  1413. result = df.to_string()
  1414. expected = (
  1415. " A B\n"
  1416. "0 NaN NaN\n"
  1417. "1 -1.0 foo\n"
  1418. "2 -2.0 foooo\n"
  1419. "3 3.0 fooooo\n"
  1420. "4 4.0 bar"
  1421. )
  1422. assert result == expected
  1423. def test_to_string_format_inf(self):
  1424. # Issue #24861
  1425. tm.reset_display_options()
  1426. df = DataFrame(
  1427. {
  1428. "A": [-np.inf, np.inf, -1, -2.1234, 3, 4],
  1429. "B": [-np.inf, np.inf, "foo", "foooo", "fooooo", "bar"],
  1430. }
  1431. )
  1432. result = df.to_string()
  1433. expected = (
  1434. " A B\n"
  1435. "0 -inf -inf\n"
  1436. "1 inf inf\n"
  1437. "2 -1.0000 foo\n"
  1438. "3 -2.1234 foooo\n"
  1439. "4 3.0000 fooooo\n"
  1440. "5 4.0000 bar"
  1441. )
  1442. assert result == expected
  1443. df = DataFrame(
  1444. {
  1445. "A": [-np.inf, np.inf, -1.0, -2.0, 3.0, 4.0],
  1446. "B": [-np.inf, np.inf, "foo", "foooo", "fooooo", "bar"],
  1447. }
  1448. )
  1449. result = df.to_string()
  1450. expected = (
  1451. " A B\n"
  1452. "0 -inf -inf\n"
  1453. "1 inf inf\n"
  1454. "2 -1.0 foo\n"
  1455. "3 -2.0 foooo\n"
  1456. "4 3.0 fooooo\n"
  1457. "5 4.0 bar"
  1458. )
  1459. assert result == expected
  1460. def test_to_string_decimal(self):
  1461. # Issue #23614
  1462. df = DataFrame({"A": [6.0, 3.1, 2.2]})
  1463. expected = " A\n0 6,0\n1 3,1\n2 2,2"
  1464. assert df.to_string(decimal=",") == expected
  1465. def test_to_string_line_width(self):
  1466. df = DataFrame(123, index=range(10, 15), columns=range(30))
  1467. s = df.to_string(line_width=80)
  1468. assert max(len(line) for line in s.split("\n")) == 80
  1469. def test_to_string_header_false(self):
  1470. # GH 49230
  1471. df = DataFrame([1, 2])
  1472. df.index.name = "a"
  1473. s = df.to_string(header=False)
  1474. expected = "a \n0 1\n1 2"
  1475. assert s == expected
  1476. df = DataFrame([[1, 2], [3, 4]])
  1477. df.index.name = "a"
  1478. s = df.to_string(header=False)
  1479. expected = "a \n0 1 2\n1 3 4"
  1480. assert s == expected
  1481. def test_show_dimensions(self):
  1482. df = DataFrame(123, index=range(10, 15), columns=range(30))
  1483. with option_context(
  1484. "display.max_rows",
  1485. 10,
  1486. "display.max_columns",
  1487. 40,
  1488. "display.width",
  1489. 500,
  1490. "display.expand_frame_repr",
  1491. "info",
  1492. "display.show_dimensions",
  1493. True,
  1494. ):
  1495. assert "5 rows" in str(df)
  1496. assert "5 rows" in df._repr_html_()
  1497. with option_context(
  1498. "display.max_rows",
  1499. 10,
  1500. "display.max_columns",
  1501. 40,
  1502. "display.width",
  1503. 500,
  1504. "display.expand_frame_repr",
  1505. "info",
  1506. "display.show_dimensions",
  1507. False,
  1508. ):
  1509. assert "5 rows" not in str(df)
  1510. assert "5 rows" not in df._repr_html_()
  1511. with option_context(
  1512. "display.max_rows",
  1513. 2,
  1514. "display.max_columns",
  1515. 2,
  1516. "display.width",
  1517. 500,
  1518. "display.expand_frame_repr",
  1519. "info",
  1520. "display.show_dimensions",
  1521. "truncate",
  1522. ):
  1523. assert "5 rows" in str(df)
  1524. assert "5 rows" in df._repr_html_()
  1525. with option_context(
  1526. "display.max_rows",
  1527. 10,
  1528. "display.max_columns",
  1529. 40,
  1530. "display.width",
  1531. 500,
  1532. "display.expand_frame_repr",
  1533. "info",
  1534. "display.show_dimensions",
  1535. "truncate",
  1536. ):
  1537. assert "5 rows" not in str(df)
  1538. assert "5 rows" not in df._repr_html_()
  1539. def test_repr_html(self, float_frame):
  1540. df = float_frame
  1541. df._repr_html_()
  1542. fmt.set_option("display.max_rows", 1, "display.max_columns", 1)
  1543. df._repr_html_()
  1544. fmt.set_option("display.notebook_repr_html", False)
  1545. df._repr_html_()
  1546. tm.reset_display_options()
  1547. df = DataFrame([[1, 2], [3, 4]])
  1548. fmt.set_option("display.show_dimensions", True)
  1549. assert "2 rows" in df._repr_html_()
  1550. fmt.set_option("display.show_dimensions", False)
  1551. assert "2 rows" not in df._repr_html_()
  1552. tm.reset_display_options()
  1553. def test_repr_html_mathjax(self):
  1554. df = DataFrame([[1, 2], [3, 4]])
  1555. assert "tex2jax_ignore" not in df._repr_html_()
  1556. with option_context("display.html.use_mathjax", False):
  1557. assert "tex2jax_ignore" in df._repr_html_()
  1558. def test_repr_html_wide(self):
  1559. max_cols = 20
  1560. df = DataFrame(tm.rands_array(25, size=(10, max_cols - 1)))
  1561. with option_context("display.max_rows", 60, "display.max_columns", 20):
  1562. assert "..." not in df._repr_html_()
  1563. wide_df = DataFrame(tm.rands_array(25, size=(10, max_cols + 1)))
  1564. with option_context("display.max_rows", 60, "display.max_columns", 20):
  1565. assert "..." in wide_df._repr_html_()
  1566. def test_repr_html_wide_multiindex_cols(self):
  1567. max_cols = 20
  1568. mcols = MultiIndex.from_product(
  1569. [np.arange(max_cols // 2), ["foo", "bar"]], names=["first", "second"]
  1570. )
  1571. df = DataFrame(tm.rands_array(25, size=(10, len(mcols))), columns=mcols)
  1572. reg_repr = df._repr_html_()
  1573. assert "..." not in reg_repr
  1574. mcols = MultiIndex.from_product(
  1575. (np.arange(1 + (max_cols // 2)), ["foo", "bar"]), names=["first", "second"]
  1576. )
  1577. df = DataFrame(tm.rands_array(25, size=(10, len(mcols))), columns=mcols)
  1578. with option_context("display.max_rows", 60, "display.max_columns", 20):
  1579. assert "..." in df._repr_html_()
  1580. def test_repr_html_long(self):
  1581. with option_context("display.max_rows", 60):
  1582. max_rows = get_option("display.max_rows")
  1583. h = max_rows - 1
  1584. df = DataFrame({"A": np.arange(1, 1 + h), "B": np.arange(41, 41 + h)})
  1585. reg_repr = df._repr_html_()
  1586. assert ".." not in reg_repr
  1587. assert str(41 + max_rows // 2) in reg_repr
  1588. h = max_rows + 1
  1589. df = DataFrame({"A": np.arange(1, 1 + h), "B": np.arange(41, 41 + h)})
  1590. long_repr = df._repr_html_()
  1591. assert ".." in long_repr
  1592. assert str(41 + max_rows // 2) not in long_repr
  1593. assert f"{h} rows " in long_repr
  1594. assert "2 columns" in long_repr
  1595. def test_repr_html_float(self):
  1596. with option_context("display.max_rows", 60):
  1597. max_rows = get_option("display.max_rows")
  1598. h = max_rows - 1
  1599. df = DataFrame(
  1600. {
  1601. "idx": np.linspace(-10, 10, h),
  1602. "A": np.arange(1, 1 + h),
  1603. "B": np.arange(41, 41 + h),
  1604. }
  1605. ).set_index("idx")
  1606. reg_repr = df._repr_html_()
  1607. assert ".." not in reg_repr
  1608. assert f"<td>{40 + h}</td>" in reg_repr
  1609. h = max_rows + 1
  1610. df = DataFrame(
  1611. {
  1612. "idx": np.linspace(-10, 10, h),
  1613. "A": np.arange(1, 1 + h),
  1614. "B": np.arange(41, 41 + h),
  1615. }
  1616. ).set_index("idx")
  1617. long_repr = df._repr_html_()
  1618. assert ".." in long_repr
  1619. assert "<td>31</td>" not in long_repr
  1620. assert f"{h} rows " in long_repr
  1621. assert "2 columns" in long_repr
  1622. def test_repr_html_long_multiindex(self):
  1623. max_rows = 60
  1624. max_L1 = max_rows // 2
  1625. tuples = list(itertools.product(np.arange(max_L1), ["foo", "bar"]))
  1626. idx = MultiIndex.from_tuples(tuples, names=["first", "second"])
  1627. df = DataFrame(np.random.randn(max_L1 * 2, 2), index=idx, columns=["A", "B"])
  1628. with option_context("display.max_rows", 60, "display.max_columns", 20):
  1629. reg_repr = df._repr_html_()
  1630. assert "..." not in reg_repr
  1631. tuples = list(itertools.product(np.arange(max_L1 + 1), ["foo", "bar"]))
  1632. idx = MultiIndex.from_tuples(tuples, names=["first", "second"])
  1633. df = DataFrame(
  1634. np.random.randn((max_L1 + 1) * 2, 2), index=idx, columns=["A", "B"]
  1635. )
  1636. long_repr = df._repr_html_()
  1637. assert "..." in long_repr
  1638. def test_repr_html_long_and_wide(self):
  1639. max_cols = 20
  1640. max_rows = 60
  1641. h, w = max_rows - 1, max_cols - 1
  1642. df = DataFrame({k: np.arange(1, 1 + h) for k in np.arange(w)})
  1643. with option_context("display.max_rows", 60, "display.max_columns", 20):
  1644. assert "..." not in df._repr_html_()
  1645. h, w = max_rows + 1, max_cols + 1
  1646. df = DataFrame({k: np.arange(1, 1 + h) for k in np.arange(w)})
  1647. with option_context("display.max_rows", 60, "display.max_columns", 20):
  1648. assert "..." in df._repr_html_()
  1649. def test_info_repr(self):
  1650. # GH#21746 For tests inside a terminal (i.e. not CI) we need to detect
  1651. # the terminal size to ensure that we try to print something "too big"
  1652. term_width, term_height = get_terminal_size()
  1653. max_rows = 60
  1654. max_cols = 20 + (max(term_width, 80) - 80) // 4
  1655. # Long
  1656. h, w = max_rows + 1, max_cols - 1
  1657. df = DataFrame({k: np.arange(1, 1 + h) for k in np.arange(w)})
  1658. assert has_vertically_truncated_repr(df)
  1659. with option_context("display.large_repr", "info"):
  1660. assert has_info_repr(df)
  1661. # Wide
  1662. h, w = max_rows - 1, max_cols + 1
  1663. df = DataFrame({k: np.arange(1, 1 + h) for k in np.arange(w)})
  1664. assert has_horizontally_truncated_repr(df)
  1665. with option_context(
  1666. "display.large_repr", "info", "display.max_columns", max_cols
  1667. ):
  1668. assert has_info_repr(df)
  1669. def test_info_repr_max_cols(self):
  1670. # GH #6939
  1671. df = DataFrame(np.random.randn(10, 5))
  1672. with option_context(
  1673. "display.large_repr",
  1674. "info",
  1675. "display.max_columns",
  1676. 1,
  1677. "display.max_info_columns",
  1678. 4,
  1679. ):
  1680. assert has_non_verbose_info_repr(df)
  1681. with option_context(
  1682. "display.large_repr",
  1683. "info",
  1684. "display.max_columns",
  1685. 1,
  1686. "display.max_info_columns",
  1687. 5,
  1688. ):
  1689. assert not has_non_verbose_info_repr(df)
  1690. # test verbose overrides
  1691. # fmt.set_option('display.max_info_columns', 4) # exceeded
  1692. def test_info_repr_html(self):
  1693. max_rows = 60
  1694. max_cols = 20
  1695. # Long
  1696. h, w = max_rows + 1, max_cols - 1
  1697. df = DataFrame({k: np.arange(1, 1 + h) for k in np.arange(w)})
  1698. assert r"&lt;class" not in df._repr_html_()
  1699. with option_context("display.large_repr", "info"):
  1700. assert r"&lt;class" in df._repr_html_()
  1701. # Wide
  1702. h, w = max_rows - 1, max_cols + 1
  1703. df = DataFrame({k: np.arange(1, 1 + h) for k in np.arange(w)})
  1704. assert "<class" not in df._repr_html_()
  1705. with option_context(
  1706. "display.large_repr", "info", "display.max_columns", max_cols
  1707. ):
  1708. assert "&lt;class" in df._repr_html_()
  1709. def test_fake_qtconsole_repr_html(self, float_frame):
  1710. df = float_frame
  1711. def get_ipython():
  1712. return {"config": {"KernelApp": {"parent_appname": "ipython-qtconsole"}}}
  1713. repstr = df._repr_html_()
  1714. assert repstr is not None
  1715. fmt.set_option("display.max_rows", 5, "display.max_columns", 2)
  1716. repstr = df._repr_html_()
  1717. assert "class" in repstr # info fallback
  1718. tm.reset_display_options()
  1719. def test_pprint_pathological_object(self):
  1720. """
  1721. If the test fails, it at least won't hang.
  1722. """
  1723. class A:
  1724. def __getitem__(self, key):
  1725. return 3 # obviously simplified
  1726. df = DataFrame([A()])
  1727. repr(df) # just don't die
  1728. def test_float_trim_zeros(self):
  1729. vals = [
  1730. 2.08430917305e10,
  1731. 3.52205017305e10,
  1732. 2.30674817305e10,
  1733. 2.03954217305e10,
  1734. 5.59897817305e10,
  1735. ]
  1736. skip = True
  1737. for line in repr(DataFrame({"A": vals})).split("\n")[:-2]:
  1738. if line.startswith("dtype:"):
  1739. continue
  1740. if _three_digit_exp():
  1741. assert ("+010" in line) or skip
  1742. else:
  1743. assert ("+10" in line) or skip
  1744. skip = False
  1745. @pytest.mark.parametrize(
  1746. "data, expected",
  1747. [
  1748. (["3.50"], "0 3.50\ndtype: object"),
  1749. ([1.20, "1.00"], "0 1.2\n1 1.00\ndtype: object"),
  1750. ([np.nan], "0 NaN\ndtype: float64"),
  1751. ([None], "0 None\ndtype: object"),
  1752. (["3.50", np.nan], "0 3.50\n1 NaN\ndtype: object"),
  1753. ([3.50, np.nan], "0 3.5\n1 NaN\ndtype: float64"),
  1754. ([3.50, np.nan, "3.50"], "0 3.5\n1 NaN\n2 3.50\ndtype: object"),
  1755. ([3.50, None, "3.50"], "0 3.5\n1 None\n2 3.50\ndtype: object"),
  1756. ],
  1757. )
  1758. def test_repr_str_float_truncation(self, data, expected):
  1759. # GH#38708
  1760. series = Series(data)
  1761. result = repr(series)
  1762. assert result == expected
  1763. @pytest.mark.parametrize(
  1764. "float_format,expected",
  1765. [
  1766. ("{:,.0f}".format, "0 1,000\n1 test\ndtype: object"),
  1767. ("{:.4f}".format, "0 1000.0000\n1 test\ndtype: object"),
  1768. ],
  1769. )
  1770. def test_repr_float_format_in_object_col(self, float_format, expected):
  1771. # GH#40024
  1772. df = Series([1000.0, "test"])
  1773. with option_context("display.float_format", float_format):
  1774. result = repr(df)
  1775. assert result == expected
  1776. def test_dict_entries(self):
  1777. df = DataFrame({"A": [{"a": 1, "b": 2}]})
  1778. val = df.to_string()
  1779. assert "'a': 1" in val
  1780. assert "'b': 2" in val
  1781. def test_categorical_columns(self):
  1782. # GH35439
  1783. data = [[4, 2], [3, 2], [4, 3]]
  1784. cols = ["aaaaaaaaa", "b"]
  1785. df = DataFrame(data, columns=cols)
  1786. df_cat_cols = DataFrame(data, columns=pd.CategoricalIndex(cols))
  1787. assert df.to_string() == df_cat_cols.to_string()
  1788. def test_period(self):
  1789. # GH 12615
  1790. df = DataFrame(
  1791. {
  1792. "A": pd.period_range("2013-01", periods=4, freq="M"),
  1793. "B": [
  1794. pd.Period("2011-01", freq="M"),
  1795. pd.Period("2011-02-01", freq="D"),
  1796. pd.Period("2011-03-01 09:00", freq="H"),
  1797. pd.Period("2011-04", freq="M"),
  1798. ],
  1799. "C": list("abcd"),
  1800. }
  1801. )
  1802. exp = (
  1803. " A B C\n"
  1804. "0 2013-01 2011-01 a\n"
  1805. "1 2013-02 2011-02-01 b\n"
  1806. "2 2013-03 2011-03-01 09:00 c\n"
  1807. "3 2013-04 2011-04 d"
  1808. )
  1809. assert str(df) == exp
  1810. @pytest.mark.parametrize(
  1811. "length, max_rows, min_rows, expected",
  1812. [
  1813. (10, 10, 10, 10),
  1814. (10, 10, None, 10),
  1815. (10, 8, None, 8),
  1816. (20, 30, 10, 30), # max_rows > len(frame), hence max_rows
  1817. (50, 30, 10, 10), # max_rows < len(frame), hence min_rows
  1818. (100, 60, 10, 10), # same
  1819. (60, 60, 10, 60), # edge case
  1820. (61, 60, 10, 10), # edge case
  1821. ],
  1822. )
  1823. def test_max_rows_fitted(self, length, min_rows, max_rows, expected):
  1824. """Check that display logic is correct.
  1825. GH #37359
  1826. See description here:
  1827. https://pandas.pydata.org/docs/dev/user_guide/options.html#frequently-used-options
  1828. """
  1829. formatter = fmt.DataFrameFormatter(
  1830. DataFrame(np.random.rand(length, 3)),
  1831. max_rows=max_rows,
  1832. min_rows=min_rows,
  1833. )
  1834. result = formatter.max_rows_fitted
  1835. assert result == expected
  1836. def test_no_extra_space(self):
  1837. # GH 52690: Check that no extra space is given
  1838. col1 = "TEST"
  1839. col2 = "PANDAS"
  1840. col3 = "to_string"
  1841. expected = f"{col1:<6s} {col2:<7s} {col3:<10s}"
  1842. df = DataFrame([{"col1": "TEST", "col2": "PANDAS", "col3": "to_string"}])
  1843. d = {"col1": "{:<6s}".format, "col2": "{:<7s}".format, "col3": "{:<10s}".format}
  1844. result = df.to_string(index=False, header=False, formatters=d)
  1845. assert result == expected
  1846. def gen_series_formatting():
  1847. s1 = Series(["a"] * 100)
  1848. s2 = Series(["ab"] * 100)
  1849. s3 = Series(["a", "ab", "abc", "abcd", "abcde", "abcdef"])
  1850. s4 = s3[::-1]
  1851. test_sers = {"onel": s1, "twol": s2, "asc": s3, "desc": s4}
  1852. return test_sers
  1853. class TestSeriesFormatting:
  1854. def test_repr_unicode(self):
  1855. s = Series(["\u03c3"] * 10)
  1856. repr(s)
  1857. a = Series(["\u05d0"] * 1000)
  1858. a.name = "title1"
  1859. repr(a)
  1860. def test_to_string(self):
  1861. ts = tm.makeTimeSeries()
  1862. buf = StringIO()
  1863. s = ts.to_string()
  1864. retval = ts.to_string(buf=buf)
  1865. assert retval is None
  1866. assert buf.getvalue().strip() == s
  1867. # pass float_format
  1868. format = "%.4f".__mod__
  1869. result = ts.to_string(float_format=format)
  1870. result = [x.split()[1] for x in result.split("\n")[:-1]]
  1871. expected = [format(x) for x in ts]
  1872. assert result == expected
  1873. # empty string
  1874. result = ts[:0].to_string()
  1875. assert result == "Series([], Freq: B)"
  1876. result = ts[:0].to_string(length=0)
  1877. assert result == "Series([], Freq: B)"
  1878. # name and length
  1879. cp = ts.copy()
  1880. cp.name = "foo"
  1881. result = cp.to_string(length=True, name=True, dtype=True)
  1882. last_line = result.split("\n")[-1].strip()
  1883. assert last_line == (f"Freq: B, Name: foo, Length: {len(cp)}, dtype: float64")
  1884. def test_freq_name_separation(self):
  1885. s = Series(
  1886. np.random.randn(10), index=date_range("1/1/2000", periods=10), name=0
  1887. )
  1888. result = repr(s)
  1889. assert "Freq: D, Name: 0" in result
  1890. def test_to_string_mixed(self):
  1891. s = Series(["foo", np.nan, -1.23, 4.56])
  1892. result = s.to_string()
  1893. expected = "0 foo\n" + "1 NaN\n" + "2 -1.23\n" + "3 4.56"
  1894. assert result == expected
  1895. # but don't count NAs as floats
  1896. s = Series(["foo", np.nan, "bar", "baz"])
  1897. result = s.to_string()
  1898. expected = "0 foo\n" + "1 NaN\n" + "2 bar\n" + "3 baz"
  1899. assert result == expected
  1900. s = Series(["foo", 5, "bar", "baz"])
  1901. result = s.to_string()
  1902. expected = "0 foo\n" + "1 5\n" + "2 bar\n" + "3 baz"
  1903. assert result == expected
  1904. def test_to_string_float_na_spacing(self):
  1905. s = Series([0.0, 1.5678, 2.0, -3.0, 4.0])
  1906. s[::2] = np.nan
  1907. result = s.to_string()
  1908. expected = (
  1909. "0 NaN\n"
  1910. + "1 1.5678\n"
  1911. + "2 NaN\n"
  1912. + "3 -3.0000\n"
  1913. + "4 NaN"
  1914. )
  1915. assert result == expected
  1916. def test_to_string_without_index(self):
  1917. # GH 11729 Test index=False option
  1918. s = Series([1, 2, 3, 4])
  1919. result = s.to_string(index=False)
  1920. expected = "1\n" + "2\n" + "3\n" + "4"
  1921. assert result == expected
  1922. def test_unicode_name_in_footer(self):
  1923. s = Series([1, 2], name="\u05e2\u05d1\u05e8\u05d9\u05ea")
  1924. sf = fmt.SeriesFormatter(s, name="\u05e2\u05d1\u05e8\u05d9\u05ea")
  1925. sf._get_footer() # should not raise exception
  1926. def test_east_asian_unicode_series(self):
  1927. # not aligned properly because of east asian width
  1928. # unicode index
  1929. s = Series(["a", "bb", "CCC", "D"], index=["あ", "いい", "ううう", "ええええ"])
  1930. expected = "あ a\nいい bb\nううう CCC\nええええ D\ndtype: object"
  1931. assert repr(s) == expected
  1932. # unicode values
  1933. s = Series(["あ", "いい", "ううう", "ええええ"], index=["a", "bb", "c", "ddd"])
  1934. expected = "a あ\nbb いい\nc ううう\nddd ええええ\ndtype: object"
  1935. assert repr(s) == expected
  1936. # both
  1937. s = Series(["あ", "いい", "ううう", "ええええ"], index=["ああ", "いいいい", "う", "えええ"])
  1938. expected = (
  1939. "ああ あ\nいいいい いい\nう ううう\nえええ ええええ\ndtype: object"
  1940. )
  1941. assert repr(s) == expected
  1942. # unicode footer
  1943. s = Series(
  1944. ["あ", "いい", "ううう", "ええええ"], index=["ああ", "いいいい", "う", "えええ"], name="おおおおおおお"
  1945. )
  1946. expected = (
  1947. "ああ あ\nいいいい いい\nう ううう\n"
  1948. "えええ ええええ\nName: おおおおおおお, dtype: object"
  1949. )
  1950. assert repr(s) == expected
  1951. # MultiIndex
  1952. idx = MultiIndex.from_tuples(
  1953. [("あ", "いい"), ("う", "え"), ("おおお", "かかかか"), ("き", "くく")]
  1954. )
  1955. s = Series([1, 22, 3333, 44444], index=idx)
  1956. expected = (
  1957. "あ いい 1\n"
  1958. "う え 22\n"
  1959. "おおお かかかか 3333\n"
  1960. "き くく 44444\ndtype: int64"
  1961. )
  1962. assert repr(s) == expected
  1963. # object dtype, shorter than unicode repr
  1964. s = Series([1, 22, 3333, 44444], index=[1, "AB", np.nan, "あああ"])
  1965. expected = (
  1966. "1 1\nAB 22\nNaN 3333\nあああ 44444\ndtype: int64"
  1967. )
  1968. assert repr(s) == expected
  1969. # object dtype, longer than unicode repr
  1970. s = Series(
  1971. [1, 22, 3333, 44444], index=[1, "AB", Timestamp("2011-01-01"), "あああ"]
  1972. )
  1973. expected = (
  1974. "1 1\n"
  1975. "AB 22\n"
  1976. "2011-01-01 00:00:00 3333\n"
  1977. "あああ 44444\ndtype: int64"
  1978. )
  1979. assert repr(s) == expected
  1980. # truncate
  1981. with option_context("display.max_rows", 3):
  1982. s = Series(["あ", "いい", "ううう", "ええええ"], name="おおおおおおお")
  1983. expected = (
  1984. "0 あ\n ... \n"
  1985. "3 ええええ\n"
  1986. "Name: おおおおおおお, Length: 4, dtype: object"
  1987. )
  1988. assert repr(s) == expected
  1989. s.index = ["ああ", "いいいい", "う", "えええ"]
  1990. expected = (
  1991. "ああ あ\n ... \n"
  1992. "えええ ええええ\n"
  1993. "Name: おおおおおおお, Length: 4, dtype: object"
  1994. )
  1995. assert repr(s) == expected
  1996. # Enable Unicode option -----------------------------------------
  1997. with option_context("display.unicode.east_asian_width", True):
  1998. # unicode index
  1999. s = Series(["a", "bb", "CCC", "D"], index=["あ", "いい", "ううう", "ええええ"])
  2000. expected = (
  2001. "あ a\nいい bb\nううう CCC\n"
  2002. "ええええ D\ndtype: object"
  2003. )
  2004. assert repr(s) == expected
  2005. # unicode values
  2006. s = Series(["あ", "いい", "ううう", "ええええ"], index=["a", "bb", "c", "ddd"])
  2007. expected = (
  2008. "a あ\nbb いい\nc ううう\n"
  2009. "ddd ええええ\ndtype: object"
  2010. )
  2011. assert repr(s) == expected
  2012. # both
  2013. s = Series(["あ", "いい", "ううう", "ええええ"], index=["ああ", "いいいい", "う", "えええ"])
  2014. expected = (
  2015. "ああ あ\n"
  2016. "いいいい いい\n"
  2017. "う ううう\n"
  2018. "えええ ええええ\ndtype: object"
  2019. )
  2020. assert repr(s) == expected
  2021. # unicode footer
  2022. s = Series(
  2023. ["あ", "いい", "ううう", "ええええ"],
  2024. index=["ああ", "いいいい", "う", "えええ"],
  2025. name="おおおおおおお",
  2026. )
  2027. expected = (
  2028. "ああ あ\n"
  2029. "いいいい いい\n"
  2030. "う ううう\n"
  2031. "えええ ええええ\n"
  2032. "Name: おおおおおおお, dtype: object"
  2033. )
  2034. assert repr(s) == expected
  2035. # MultiIndex
  2036. idx = MultiIndex.from_tuples(
  2037. [("あ", "いい"), ("う", "え"), ("おおお", "かかかか"), ("き", "くく")]
  2038. )
  2039. s = Series([1, 22, 3333, 44444], index=idx)
  2040. expected = (
  2041. "あ いい 1\n"
  2042. "う え 22\n"
  2043. "おおお かかかか 3333\n"
  2044. "き くく 44444\n"
  2045. "dtype: int64"
  2046. )
  2047. assert repr(s) == expected
  2048. # object dtype, shorter than unicode repr
  2049. s = Series([1, 22, 3333, 44444], index=[1, "AB", np.nan, "あああ"])
  2050. expected = (
  2051. "1 1\nAB 22\nNaN 3333\n"
  2052. "あああ 44444\ndtype: int64"
  2053. )
  2054. assert repr(s) == expected
  2055. # object dtype, longer than unicode repr
  2056. s = Series(
  2057. [1, 22, 3333, 44444],
  2058. index=[1, "AB", Timestamp("2011-01-01"), "あああ"],
  2059. )
  2060. expected = (
  2061. "1 1\n"
  2062. "AB 22\n"
  2063. "2011-01-01 00:00:00 3333\n"
  2064. "あああ 44444\ndtype: int64"
  2065. )
  2066. assert repr(s) == expected
  2067. # truncate
  2068. with option_context("display.max_rows", 3):
  2069. s = Series(["あ", "いい", "ううう", "ええええ"], name="おおおおおおお")
  2070. expected = (
  2071. "0 あ\n ... \n"
  2072. "3 ええええ\n"
  2073. "Name: おおおおおおお, Length: 4, dtype: object"
  2074. )
  2075. assert repr(s) == expected
  2076. s.index = ["ああ", "いいいい", "う", "えええ"]
  2077. expected = (
  2078. "ああ あ\n"
  2079. " ... \n"
  2080. "えええ ええええ\n"
  2081. "Name: おおおおおおお, Length: 4, dtype: object"
  2082. )
  2083. assert repr(s) == expected
  2084. # ambiguous unicode
  2085. s = Series(
  2086. ["¡¡", "い¡¡", "ううう", "ええええ"], index=["ああ", "¡¡¡¡いい", "¡¡", "えええ"]
  2087. )
  2088. expected = (
  2089. "ああ ¡¡\n"
  2090. "¡¡¡¡いい い¡¡\n"
  2091. "¡¡ ううう\n"
  2092. "えええ ええええ\ndtype: object"
  2093. )
  2094. assert repr(s) == expected
  2095. def test_float_trim_zeros(self):
  2096. vals = [
  2097. 2.08430917305e10,
  2098. 3.52205017305e10,
  2099. 2.30674817305e10,
  2100. 2.03954217305e10,
  2101. 5.59897817305e10,
  2102. ]
  2103. for line in repr(Series(vals)).split("\n"):
  2104. if line.startswith("dtype:"):
  2105. continue
  2106. if _three_digit_exp():
  2107. assert "+010" in line
  2108. else:
  2109. assert "+10" in line
  2110. def test_datetimeindex(self):
  2111. index = date_range("20130102", periods=6)
  2112. s = Series(1, index=index)
  2113. result = s.to_string()
  2114. assert "2013-01-02" in result
  2115. # nat in index
  2116. s2 = Series(2, index=[Timestamp("20130111"), NaT])
  2117. s = pd.concat([s2, s])
  2118. result = s.to_string()
  2119. assert "NaT" in result
  2120. # nat in summary
  2121. result = str(s2.index)
  2122. assert "NaT" in result
  2123. @pytest.mark.parametrize(
  2124. "start_date",
  2125. [
  2126. "2017-01-01 23:59:59.999999999",
  2127. "2017-01-01 23:59:59.99999999",
  2128. "2017-01-01 23:59:59.9999999",
  2129. "2017-01-01 23:59:59.999999",
  2130. "2017-01-01 23:59:59.99999",
  2131. "2017-01-01 23:59:59.9999",
  2132. ],
  2133. )
  2134. def test_datetimeindex_highprecision(self, start_date):
  2135. # GH19030
  2136. # Check that high-precision time values for the end of day are
  2137. # included in repr for DatetimeIndex
  2138. s1 = Series(date_range(start=start_date, freq="D", periods=5))
  2139. result = str(s1)
  2140. assert start_date in result
  2141. dti = date_range(start=start_date, freq="D", periods=5)
  2142. s2 = Series(3, index=dti)
  2143. result = str(s2.index)
  2144. assert start_date in result
  2145. def test_timedelta64(self):
  2146. Series(np.array([1100, 20], dtype="timedelta64[ns]")).to_string()
  2147. s = Series(date_range("2012-1-1", periods=3, freq="D"))
  2148. # GH2146
  2149. # adding NaTs
  2150. y = s - s.shift(1)
  2151. result = y.to_string()
  2152. assert "1 days" in result
  2153. assert "00:00:00" not in result
  2154. assert "NaT" in result
  2155. # with frac seconds
  2156. o = Series([datetime(2012, 1, 1, microsecond=150)] * 3)
  2157. y = s - o
  2158. result = y.to_string()
  2159. assert "-1 days +23:59:59.999850" in result
  2160. # rounding?
  2161. o = Series([datetime(2012, 1, 1, 1)] * 3)
  2162. y = s - o
  2163. result = y.to_string()
  2164. assert "-1 days +23:00:00" in result
  2165. assert "1 days 23:00:00" in result
  2166. o = Series([datetime(2012, 1, 1, 1, 1)] * 3)
  2167. y = s - o
  2168. result = y.to_string()
  2169. assert "-1 days +22:59:00" in result
  2170. assert "1 days 22:59:00" in result
  2171. o = Series([datetime(2012, 1, 1, 1, 1, microsecond=150)] * 3)
  2172. y = s - o
  2173. result = y.to_string()
  2174. assert "-1 days +22:58:59.999850" in result
  2175. assert "0 days 22:58:59.999850" in result
  2176. # neg time
  2177. td = timedelta(minutes=5, seconds=3)
  2178. s2 = Series(date_range("2012-1-1", periods=3, freq="D")) + td
  2179. y = s - s2
  2180. result = y.to_string()
  2181. assert "-1 days +23:54:57" in result
  2182. td = timedelta(microseconds=550)
  2183. s2 = Series(date_range("2012-1-1", periods=3, freq="D")) + td
  2184. y = s - td
  2185. result = y.to_string()
  2186. assert "2012-01-01 23:59:59.999450" in result
  2187. # no boxing of the actual elements
  2188. td = Series(pd.timedelta_range("1 days", periods=3))
  2189. result = td.to_string()
  2190. assert result == "0 1 days\n1 2 days\n2 3 days"
  2191. def test_mixed_datetime64(self):
  2192. df = DataFrame({"A": [1, 2], "B": ["2012-01-01", "2012-01-02"]})
  2193. df["B"] = pd.to_datetime(df.B)
  2194. result = repr(df.loc[0])
  2195. assert "2012-01-01" in result
  2196. def test_period(self):
  2197. # GH 12615
  2198. index = pd.period_range("2013-01", periods=6, freq="M")
  2199. s = Series(np.arange(6, dtype="int64"), index=index)
  2200. exp = (
  2201. "2013-01 0\n"
  2202. "2013-02 1\n"
  2203. "2013-03 2\n"
  2204. "2013-04 3\n"
  2205. "2013-05 4\n"
  2206. "2013-06 5\n"
  2207. "Freq: M, dtype: int64"
  2208. )
  2209. assert str(s) == exp
  2210. s = Series(index)
  2211. exp = (
  2212. "0 2013-01\n"
  2213. "1 2013-02\n"
  2214. "2 2013-03\n"
  2215. "3 2013-04\n"
  2216. "4 2013-05\n"
  2217. "5 2013-06\n"
  2218. "dtype: period[M]"
  2219. )
  2220. assert str(s) == exp
  2221. # periods with mixed freq
  2222. s = Series(
  2223. [
  2224. pd.Period("2011-01", freq="M"),
  2225. pd.Period("2011-02-01", freq="D"),
  2226. pd.Period("2011-03-01 09:00", freq="H"),
  2227. ]
  2228. )
  2229. exp = (
  2230. "0 2011-01\n1 2011-02-01\n"
  2231. "2 2011-03-01 09:00\ndtype: object"
  2232. )
  2233. assert str(s) == exp
  2234. def test_max_multi_index_display(self):
  2235. # GH 7101
  2236. # doc example (indexing.rst)
  2237. # multi-index
  2238. arrays = [
  2239. ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"],
  2240. ["one", "two", "one", "two", "one", "two", "one", "two"],
  2241. ]
  2242. tuples = list(zip(*arrays))
  2243. index = MultiIndex.from_tuples(tuples, names=["first", "second"])
  2244. s = Series(np.random.randn(8), index=index)
  2245. with option_context("display.max_rows", 10):
  2246. assert len(str(s).split("\n")) == 10
  2247. with option_context("display.max_rows", 3):
  2248. assert len(str(s).split("\n")) == 5
  2249. with option_context("display.max_rows", 2):
  2250. assert len(str(s).split("\n")) == 5
  2251. with option_context("display.max_rows", 1):
  2252. assert len(str(s).split("\n")) == 4
  2253. with option_context("display.max_rows", 0):
  2254. assert len(str(s).split("\n")) == 10
  2255. # index
  2256. s = Series(np.random.randn(8), None)
  2257. with option_context("display.max_rows", 10):
  2258. assert len(str(s).split("\n")) == 9
  2259. with option_context("display.max_rows", 3):
  2260. assert len(str(s).split("\n")) == 4
  2261. with option_context("display.max_rows", 2):
  2262. assert len(str(s).split("\n")) == 4
  2263. with option_context("display.max_rows", 1):
  2264. assert len(str(s).split("\n")) == 3
  2265. with option_context("display.max_rows", 0):
  2266. assert len(str(s).split("\n")) == 9
  2267. # Make sure #8532 is fixed
  2268. def test_consistent_format(self):
  2269. s = Series([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9999, 1, 1] * 10)
  2270. with option_context("display.max_rows", 10, "display.show_dimensions", False):
  2271. res = repr(s)
  2272. exp = (
  2273. "0 1.0000\n1 1.0000\n2 1.0000\n3 "
  2274. "1.0000\n4 1.0000\n ... \n125 "
  2275. "1.0000\n126 1.0000\n127 0.9999\n128 "
  2276. "1.0000\n129 1.0000\ndtype: float64"
  2277. )
  2278. assert res == exp
  2279. def chck_ncols(self, s):
  2280. with option_context("display.max_rows", 10):
  2281. res = repr(s)
  2282. lines = res.split("\n")
  2283. lines = [
  2284. line for line in repr(s).split("\n") if not re.match(r"[^\.]*\.+", line)
  2285. ][:-1]
  2286. ncolsizes = len({len(line.strip()) for line in lines})
  2287. assert ncolsizes == 1
  2288. def test_format_explicit(self):
  2289. test_sers = gen_series_formatting()
  2290. with option_context("display.max_rows", 4, "display.show_dimensions", False):
  2291. res = repr(test_sers["onel"])
  2292. exp = "0 a\n1 a\n ..\n98 a\n99 a\ndtype: object"
  2293. assert exp == res
  2294. res = repr(test_sers["twol"])
  2295. exp = "0 ab\n1 ab\n ..\n98 ab\n99 ab\ndtype: object"
  2296. assert exp == res
  2297. res = repr(test_sers["asc"])
  2298. exp = (
  2299. "0 a\n1 ab\n ... \n4 abcde\n5 "
  2300. "abcdef\ndtype: object"
  2301. )
  2302. assert exp == res
  2303. res = repr(test_sers["desc"])
  2304. exp = (
  2305. "5 abcdef\n4 abcde\n ... \n1 ab\n0 "
  2306. "a\ndtype: object"
  2307. )
  2308. assert exp == res
  2309. def test_ncols(self):
  2310. test_sers = gen_series_formatting()
  2311. for s in test_sers.values():
  2312. self.chck_ncols(s)
  2313. def test_max_rows_eq_one(self):
  2314. s = Series(range(10), dtype="int64")
  2315. with option_context("display.max_rows", 1):
  2316. strrepr = repr(s).split("\n")
  2317. exp1 = ["0", "0"]
  2318. res1 = strrepr[0].split()
  2319. assert exp1 == res1
  2320. exp2 = [".."]
  2321. res2 = strrepr[1].split()
  2322. assert exp2 == res2
  2323. def test_truncate_ndots(self):
  2324. def getndots(s):
  2325. return len(re.match(r"[^\.]*(\.*)", s).groups()[0])
  2326. s = Series([0, 2, 3, 6])
  2327. with option_context("display.max_rows", 2):
  2328. strrepr = repr(s).replace("\n", "")
  2329. assert getndots(strrepr) == 2
  2330. s = Series([0, 100, 200, 400])
  2331. with option_context("display.max_rows", 2):
  2332. strrepr = repr(s).replace("\n", "")
  2333. assert getndots(strrepr) == 3
  2334. def test_show_dimensions(self):
  2335. # gh-7117
  2336. s = Series(range(5))
  2337. assert "Length" not in repr(s)
  2338. with option_context("display.max_rows", 4):
  2339. assert "Length" in repr(s)
  2340. with option_context("display.show_dimensions", True):
  2341. assert "Length" in repr(s)
  2342. with option_context("display.max_rows", 4, "display.show_dimensions", False):
  2343. assert "Length" not in repr(s)
  2344. def test_repr_min_rows(self):
  2345. s = Series(range(20))
  2346. # default setting no truncation even if above min_rows
  2347. assert ".." not in repr(s)
  2348. s = Series(range(61))
  2349. # default of max_rows 60 triggers truncation if above
  2350. assert ".." in repr(s)
  2351. with option_context("display.max_rows", 10, "display.min_rows", 4):
  2352. # truncated after first two rows
  2353. assert ".." in repr(s)
  2354. assert "2 " not in repr(s)
  2355. with option_context("display.max_rows", 12, "display.min_rows", None):
  2356. # when set to None, follow value of max_rows
  2357. assert "5 5" in repr(s)
  2358. with option_context("display.max_rows", 10, "display.min_rows", 12):
  2359. # when set value higher as max_rows, use the minimum
  2360. assert "5 5" not in repr(s)
  2361. with option_context("display.max_rows", None, "display.min_rows", 12):
  2362. # max_rows of None -> never truncate
  2363. assert ".." not in repr(s)
  2364. def test_to_string_name(self):
  2365. s = Series(range(100), dtype="int64")
  2366. s.name = "myser"
  2367. res = s.to_string(max_rows=2, name=True)
  2368. exp = "0 0\n ..\n99 99\nName: myser"
  2369. assert res == exp
  2370. res = s.to_string(max_rows=2, name=False)
  2371. exp = "0 0\n ..\n99 99"
  2372. assert res == exp
  2373. def test_to_string_dtype(self):
  2374. s = Series(range(100), dtype="int64")
  2375. res = s.to_string(max_rows=2, dtype=True)
  2376. exp = "0 0\n ..\n99 99\ndtype: int64"
  2377. assert res == exp
  2378. res = s.to_string(max_rows=2, dtype=False)
  2379. exp = "0 0\n ..\n99 99"
  2380. assert res == exp
  2381. def test_to_string_length(self):
  2382. s = Series(range(100), dtype="int64")
  2383. res = s.to_string(max_rows=2, length=True)
  2384. exp = "0 0\n ..\n99 99\nLength: 100"
  2385. assert res == exp
  2386. def test_to_string_na_rep(self):
  2387. s = Series(index=range(100), dtype=np.float64)
  2388. res = s.to_string(na_rep="foo", max_rows=2)
  2389. exp = "0 foo\n ..\n99 foo"
  2390. assert res == exp
  2391. def test_to_string_float_format(self):
  2392. s = Series(range(10), dtype="float64")
  2393. res = s.to_string(float_format=lambda x: f"{x:2.1f}", max_rows=2)
  2394. exp = "0 0.0\n ..\n9 9.0"
  2395. assert res == exp
  2396. def test_to_string_header(self):
  2397. s = Series(range(10), dtype="int64")
  2398. s.index.name = "foo"
  2399. res = s.to_string(header=True, max_rows=2)
  2400. exp = "foo\n0 0\n ..\n9 9"
  2401. assert res == exp
  2402. res = s.to_string(header=False, max_rows=2)
  2403. exp = "0 0\n ..\n9 9"
  2404. assert res == exp
  2405. def test_to_string_multindex_header(self):
  2406. # GH 16718
  2407. df = DataFrame({"a": [0], "b": [1], "c": [2], "d": [3]}).set_index(["a", "b"])
  2408. res = df.to_string(header=["r1", "r2"])
  2409. exp = " r1 r2\na b \n0 1 2 3"
  2410. assert res == exp
  2411. def test_to_string_empty_col(self):
  2412. # GH 13653
  2413. s = Series(["", "Hello", "World", "", "", "Mooooo", "", ""])
  2414. res = s.to_string(index=False)
  2415. exp = " \n Hello\n World\n \n \nMooooo\n \n "
  2416. assert re.match(exp, res)
  2417. class TestGenericArrayFormatter:
  2418. def test_1d_array(self):
  2419. # GenericArrayFormatter is used on types for which there isn't a dedicated
  2420. # formatter. np.bool_ is one of those types.
  2421. obj = fmt.GenericArrayFormatter(np.array([True, False]))
  2422. res = obj.get_result()
  2423. assert len(res) == 2
  2424. # Results should be right-justified.
  2425. assert res[0] == " True"
  2426. assert res[1] == " False"
  2427. def test_2d_array(self):
  2428. obj = fmt.GenericArrayFormatter(np.array([[True, False], [False, True]]))
  2429. res = obj.get_result()
  2430. assert len(res) == 2
  2431. assert res[0] == " [True, False]"
  2432. assert res[1] == " [False, True]"
  2433. def test_3d_array(self):
  2434. obj = fmt.GenericArrayFormatter(
  2435. np.array([[[True, True], [False, False]], [[False, True], [True, False]]])
  2436. )
  2437. res = obj.get_result()
  2438. assert len(res) == 2
  2439. assert res[0] == " [[True, True], [False, False]]"
  2440. assert res[1] == " [[False, True], [True, False]]"
  2441. def test_2d_extension_type(self):
  2442. # GH 33770
  2443. # Define a stub extension type with just enough code to run Series.__repr__()
  2444. class DtypeStub(pd.api.extensions.ExtensionDtype):
  2445. @property
  2446. def type(self):
  2447. return np.ndarray
  2448. @property
  2449. def name(self):
  2450. return "DtypeStub"
  2451. class ExtTypeStub(pd.api.extensions.ExtensionArray):
  2452. def __len__(self) -> int:
  2453. return 2
  2454. def __getitem__(self, ix):
  2455. return [ix == 1, ix == 0]
  2456. @property
  2457. def dtype(self):
  2458. return DtypeStub()
  2459. series = Series(ExtTypeStub(), copy=False)
  2460. res = repr(series) # This line crashed before #33770 was fixed.
  2461. expected = "0 [False True]\n" + "1 [ True False]\n" + "dtype: DtypeStub"
  2462. assert res == expected
  2463. def _three_digit_exp():
  2464. return f"{1.7e8:.4g}" == "1.7e+008"
  2465. class TestFloatArrayFormatter:
  2466. def test_misc(self):
  2467. obj = fmt.FloatArrayFormatter(np.array([], dtype=np.float64))
  2468. result = obj.get_result()
  2469. assert len(result) == 0
  2470. def test_format(self):
  2471. obj = fmt.FloatArrayFormatter(np.array([12, 0], dtype=np.float64))
  2472. result = obj.get_result()
  2473. assert result[0] == " 12.0"
  2474. assert result[1] == " 0.0"
  2475. def test_output_display_precision_trailing_zeroes(self):
  2476. # Issue #20359: trimming zeros while there is no decimal point
  2477. # Happens when display precision is set to zero
  2478. with option_context("display.precision", 0):
  2479. s = Series([840.0, 4200.0])
  2480. expected_output = "0 840\n1 4200\ndtype: float64"
  2481. assert str(s) == expected_output
  2482. @pytest.mark.parametrize(
  2483. "value,expected",
  2484. [
  2485. ([9.4444], " 0\n0 9"),
  2486. ([0.49], " 0\n0 5e-01"),
  2487. ([10.9999], " 0\n0 11"),
  2488. ([9.5444, 9.6], " 0\n0 10\n1 10"),
  2489. ([0.46, 0.78, -9.9999], " 0\n0 5e-01\n1 8e-01\n2 -1e+01"),
  2490. ],
  2491. )
  2492. def test_set_option_precision(self, value, expected):
  2493. # Issue #30122
  2494. # Precision was incorrectly shown
  2495. with option_context("display.precision", 0):
  2496. df_value = DataFrame(value)
  2497. assert str(df_value) == expected
  2498. def test_output_significant_digits(self):
  2499. # Issue #9764
  2500. # In case default display precision changes:
  2501. with option_context("display.precision", 6):
  2502. # DataFrame example from issue #9764
  2503. d = DataFrame(
  2504. {
  2505. "col1": [
  2506. 9.999e-8,
  2507. 1e-7,
  2508. 1.0001e-7,
  2509. 2e-7,
  2510. 4.999e-7,
  2511. 5e-7,
  2512. 5.0001e-7,
  2513. 6e-7,
  2514. 9.999e-7,
  2515. 1e-6,
  2516. 1.0001e-6,
  2517. 2e-6,
  2518. 4.999e-6,
  2519. 5e-6,
  2520. 5.0001e-6,
  2521. 6e-6,
  2522. ]
  2523. }
  2524. )
  2525. expected_output = {
  2526. (0, 6): " col1\n"
  2527. "0 9.999000e-08\n"
  2528. "1 1.000000e-07\n"
  2529. "2 1.000100e-07\n"
  2530. "3 2.000000e-07\n"
  2531. "4 4.999000e-07\n"
  2532. "5 5.000000e-07",
  2533. (1, 6): " col1\n"
  2534. "1 1.000000e-07\n"
  2535. "2 1.000100e-07\n"
  2536. "3 2.000000e-07\n"
  2537. "4 4.999000e-07\n"
  2538. "5 5.000000e-07",
  2539. (1, 8): " col1\n"
  2540. "1 1.000000e-07\n"
  2541. "2 1.000100e-07\n"
  2542. "3 2.000000e-07\n"
  2543. "4 4.999000e-07\n"
  2544. "5 5.000000e-07\n"
  2545. "6 5.000100e-07\n"
  2546. "7 6.000000e-07",
  2547. (8, 16): " col1\n"
  2548. "8 9.999000e-07\n"
  2549. "9 1.000000e-06\n"
  2550. "10 1.000100e-06\n"
  2551. "11 2.000000e-06\n"
  2552. "12 4.999000e-06\n"
  2553. "13 5.000000e-06\n"
  2554. "14 5.000100e-06\n"
  2555. "15 6.000000e-06",
  2556. (9, 16): " col1\n"
  2557. "9 0.000001\n"
  2558. "10 0.000001\n"
  2559. "11 0.000002\n"
  2560. "12 0.000005\n"
  2561. "13 0.000005\n"
  2562. "14 0.000005\n"
  2563. "15 0.000006",
  2564. }
  2565. for (start, stop), v in expected_output.items():
  2566. assert str(d[start:stop]) == v
  2567. def test_too_long(self):
  2568. # GH 10451
  2569. with option_context("display.precision", 4):
  2570. # need both a number > 1e6 and something that normally formats to
  2571. # having length > display.precision + 6
  2572. df = DataFrame({"x": [12345.6789]})
  2573. assert str(df) == " x\n0 12345.6789"
  2574. df = DataFrame({"x": [2e6]})
  2575. assert str(df) == " x\n0 2000000.0"
  2576. df = DataFrame({"x": [12345.6789, 2e6]})
  2577. assert str(df) == " x\n0 1.2346e+04\n1 2.0000e+06"
  2578. class TestRepr_timedelta64:
  2579. def test_none(self):
  2580. delta_1d = pd.to_timedelta(1, unit="D")
  2581. delta_0d = pd.to_timedelta(0, unit="D")
  2582. delta_1s = pd.to_timedelta(1, unit="s")
  2583. delta_500ms = pd.to_timedelta(500, unit="ms")
  2584. drepr = lambda x: x._repr_base()
  2585. assert drepr(delta_1d) == "1 days"
  2586. assert drepr(-delta_1d) == "-1 days"
  2587. assert drepr(delta_0d) == "0 days"
  2588. assert drepr(delta_1s) == "0 days 00:00:01"
  2589. assert drepr(delta_500ms) == "0 days 00:00:00.500000"
  2590. assert drepr(delta_1d + delta_1s) == "1 days 00:00:01"
  2591. assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01"
  2592. assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000"
  2593. assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000"
  2594. def test_sub_day(self):
  2595. delta_1d = pd.to_timedelta(1, unit="D")
  2596. delta_0d = pd.to_timedelta(0, unit="D")
  2597. delta_1s = pd.to_timedelta(1, unit="s")
  2598. delta_500ms = pd.to_timedelta(500, unit="ms")
  2599. drepr = lambda x: x._repr_base(format="sub_day")
  2600. assert drepr(delta_1d) == "1 days"
  2601. assert drepr(-delta_1d) == "-1 days"
  2602. assert drepr(delta_0d) == "00:00:00"
  2603. assert drepr(delta_1s) == "00:00:01"
  2604. assert drepr(delta_500ms) == "00:00:00.500000"
  2605. assert drepr(delta_1d + delta_1s) == "1 days 00:00:01"
  2606. assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01"
  2607. assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000"
  2608. assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000"
  2609. def test_long(self):
  2610. delta_1d = pd.to_timedelta(1, unit="D")
  2611. delta_0d = pd.to_timedelta(0, unit="D")
  2612. delta_1s = pd.to_timedelta(1, unit="s")
  2613. delta_500ms = pd.to_timedelta(500, unit="ms")
  2614. drepr = lambda x: x._repr_base(format="long")
  2615. assert drepr(delta_1d) == "1 days 00:00:00"
  2616. assert drepr(-delta_1d) == "-1 days +00:00:00"
  2617. assert drepr(delta_0d) == "0 days 00:00:00"
  2618. assert drepr(delta_1s) == "0 days 00:00:01"
  2619. assert drepr(delta_500ms) == "0 days 00:00:00.500000"
  2620. assert drepr(delta_1d + delta_1s) == "1 days 00:00:01"
  2621. assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01"
  2622. assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000"
  2623. assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000"
  2624. def test_all(self):
  2625. delta_1d = pd.to_timedelta(1, unit="D")
  2626. delta_0d = pd.to_timedelta(0, unit="D")
  2627. delta_1ns = pd.to_timedelta(1, unit="ns")
  2628. drepr = lambda x: x._repr_base(format="all")
  2629. assert drepr(delta_1d) == "1 days 00:00:00.000000000"
  2630. assert drepr(-delta_1d) == "-1 days +00:00:00.000000000"
  2631. assert drepr(delta_0d) == "0 days 00:00:00.000000000"
  2632. assert drepr(delta_1ns) == "0 days 00:00:00.000000001"
  2633. assert drepr(-delta_1d + delta_1ns) == "-1 days +00:00:00.000000001"
  2634. class TestTimedelta64Formatter:
  2635. def test_days(self):
  2636. x = pd.to_timedelta(list(range(5)) + [NaT], unit="D")
  2637. result = fmt.Timedelta64Formatter(x, box=True).get_result()
  2638. assert result[0].strip() == "'0 days'"
  2639. assert result[1].strip() == "'1 days'"
  2640. result = fmt.Timedelta64Formatter(x[1:2], box=True).get_result()
  2641. assert result[0].strip() == "'1 days'"
  2642. result = fmt.Timedelta64Formatter(x, box=False).get_result()
  2643. assert result[0].strip() == "0 days"
  2644. assert result[1].strip() == "1 days"
  2645. result = fmt.Timedelta64Formatter(x[1:2], box=False).get_result()
  2646. assert result[0].strip() == "1 days"
  2647. def test_days_neg(self):
  2648. x = pd.to_timedelta(list(range(5)) + [NaT], unit="D")
  2649. result = fmt.Timedelta64Formatter(-x, box=True).get_result()
  2650. assert result[0].strip() == "'0 days'"
  2651. assert result[1].strip() == "'-1 days'"
  2652. def test_subdays(self):
  2653. y = pd.to_timedelta(list(range(5)) + [NaT], unit="s")
  2654. result = fmt.Timedelta64Formatter(y, box=True).get_result()
  2655. assert result[0].strip() == "'0 days 00:00:00'"
  2656. assert result[1].strip() == "'0 days 00:00:01'"
  2657. def test_subdays_neg(self):
  2658. y = pd.to_timedelta(list(range(5)) + [NaT], unit="s")
  2659. result = fmt.Timedelta64Formatter(-y, box=True).get_result()
  2660. assert result[0].strip() == "'0 days 00:00:00'"
  2661. assert result[1].strip() == "'-1 days +23:59:59'"
  2662. def test_zero(self):
  2663. x = pd.to_timedelta(list(range(1)) + [NaT], unit="D")
  2664. result = fmt.Timedelta64Formatter(x, box=True).get_result()
  2665. assert result[0].strip() == "'0 days'"
  2666. x = pd.to_timedelta(list(range(1)), unit="D")
  2667. result = fmt.Timedelta64Formatter(x, box=True).get_result()
  2668. assert result[0].strip() == "'0 days'"
  2669. class TestDatetime64Formatter:
  2670. def test_mixed(self):
  2671. x = Series([datetime(2013, 1, 1), datetime(2013, 1, 1, 12), NaT])
  2672. result = fmt.Datetime64Formatter(x).get_result()
  2673. assert result[0].strip() == "2013-01-01 00:00:00"
  2674. assert result[1].strip() == "2013-01-01 12:00:00"
  2675. def test_dates(self):
  2676. x = Series([datetime(2013, 1, 1), datetime(2013, 1, 2), NaT])
  2677. result = fmt.Datetime64Formatter(x).get_result()
  2678. assert result[0].strip() == "2013-01-01"
  2679. assert result[1].strip() == "2013-01-02"
  2680. def test_date_nanos(self):
  2681. x = Series([Timestamp(200)])
  2682. result = fmt.Datetime64Formatter(x).get_result()
  2683. assert result[0].strip() == "1970-01-01 00:00:00.000000200"
  2684. def test_dates_display(self):
  2685. # 10170
  2686. # make sure that we are consistently display date formatting
  2687. x = Series(date_range("20130101 09:00:00", periods=5, freq="D"))
  2688. x.iloc[1] = np.nan
  2689. result = fmt.Datetime64Formatter(x).get_result()
  2690. assert result[0].strip() == "2013-01-01 09:00:00"
  2691. assert result[1].strip() == "NaT"
  2692. assert result[4].strip() == "2013-01-05 09:00:00"
  2693. x = Series(date_range("20130101 09:00:00", periods=5, freq="s"))
  2694. x.iloc[1] = np.nan
  2695. result = fmt.Datetime64Formatter(x).get_result()
  2696. assert result[0].strip() == "2013-01-01 09:00:00"
  2697. assert result[1].strip() == "NaT"
  2698. assert result[4].strip() == "2013-01-01 09:00:04"
  2699. x = Series(date_range("20130101 09:00:00", periods=5, freq="ms"))
  2700. x.iloc[1] = np.nan
  2701. result = fmt.Datetime64Formatter(x).get_result()
  2702. assert result[0].strip() == "2013-01-01 09:00:00.000"
  2703. assert result[1].strip() == "NaT"
  2704. assert result[4].strip() == "2013-01-01 09:00:00.004"
  2705. x = Series(date_range("20130101 09:00:00", periods=5, freq="us"))
  2706. x.iloc[1] = np.nan
  2707. result = fmt.Datetime64Formatter(x).get_result()
  2708. assert result[0].strip() == "2013-01-01 09:00:00.000000"
  2709. assert result[1].strip() == "NaT"
  2710. assert result[4].strip() == "2013-01-01 09:00:00.000004"
  2711. x = Series(date_range("20130101 09:00:00", periods=5, freq="N"))
  2712. x.iloc[1] = np.nan
  2713. result = fmt.Datetime64Formatter(x).get_result()
  2714. assert result[0].strip() == "2013-01-01 09:00:00.000000000"
  2715. assert result[1].strip() == "NaT"
  2716. assert result[4].strip() == "2013-01-01 09:00:00.000000004"
  2717. def test_datetime64formatter_yearmonth(self):
  2718. x = Series([datetime(2016, 1, 1), datetime(2016, 2, 2)])
  2719. def format_func(x):
  2720. return x.strftime("%Y-%m")
  2721. formatter = fmt.Datetime64Formatter(x, formatter=format_func)
  2722. result = formatter.get_result()
  2723. assert result == ["2016-01", "2016-02"]
  2724. def test_datetime64formatter_hoursecond(self):
  2725. x = Series(
  2726. pd.to_datetime(["10:10:10.100", "12:12:12.120"], format="%H:%M:%S.%f")
  2727. )
  2728. def format_func(x):
  2729. return x.strftime("%H:%M")
  2730. formatter = fmt.Datetime64Formatter(x, formatter=format_func)
  2731. result = formatter.get_result()
  2732. assert result == ["10:10", "12:12"]
  2733. class TestNaTFormatting:
  2734. def test_repr(self):
  2735. assert repr(NaT) == "NaT"
  2736. def test_str(self):
  2737. assert str(NaT) == "NaT"
  2738. class TestPeriodIndexFormat:
  2739. def test_period_format_and_strftime_default(self):
  2740. per = pd.PeriodIndex([datetime(2003, 1, 1, 12), None], freq="H")
  2741. # Default formatting
  2742. formatted = per.format()
  2743. assert formatted[0] == "2003-01-01 12:00" # default: minutes not shown
  2744. assert formatted[1] == "NaT"
  2745. # format is equivalent to strftime(None)...
  2746. assert formatted[0] == per.strftime(None)[0]
  2747. assert per.strftime(None)[1] is np.nan # ...except for NaTs
  2748. # Same test with nanoseconds freq
  2749. per = pd.period_range("2003-01-01 12:01:01.123456789", periods=2, freq="n")
  2750. formatted = per.format()
  2751. assert (formatted == per.strftime(None)).all()
  2752. assert formatted[0] == "2003-01-01 12:01:01.123456789"
  2753. assert formatted[1] == "2003-01-01 12:01:01.123456790"
  2754. def test_period_custom(self):
  2755. # GH#46252 custom formatting directives %l (ms) and %u (us)
  2756. # 3 digits
  2757. per = pd.period_range("2003-01-01 12:01:01.123", periods=2, freq="l")
  2758. formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
  2759. assert formatted[0] == "03 12:01:01 (ms=123 us=123000 ns=123000000)"
  2760. assert formatted[1] == "03 12:01:01 (ms=124 us=124000 ns=124000000)"
  2761. # 6 digits
  2762. per = pd.period_range("2003-01-01 12:01:01.123456", periods=2, freq="u")
  2763. formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
  2764. assert formatted[0] == "03 12:01:01 (ms=123 us=123456 ns=123456000)"
  2765. assert formatted[1] == "03 12:01:01 (ms=123 us=123457 ns=123457000)"
  2766. # 9 digits
  2767. per = pd.period_range("2003-01-01 12:01:01.123456789", periods=2, freq="n")
  2768. formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
  2769. assert formatted[0] == "03 12:01:01 (ms=123 us=123456 ns=123456789)"
  2770. assert formatted[1] == "03 12:01:01 (ms=123 us=123456 ns=123456790)"
  2771. def test_period_tz(self):
  2772. # Formatting periods created from a datetime with timezone.
  2773. # This timestamp is in 2013 in Europe/Paris but is 2012 in UTC
  2774. dt = pd.to_datetime(["2013-01-01 00:00:00+01:00"], utc=True)
  2775. # Converting to a period looses the timezone information
  2776. # Since tz is currently set as utc, we'll see 2012
  2777. with tm.assert_produces_warning(UserWarning, match="will drop timezone"):
  2778. per = dt.to_period(freq="H")
  2779. assert per.format()[0] == "2012-12-31 23:00"
  2780. # If tz is currently set as paris before conversion, we'll see 2013
  2781. dt = dt.tz_convert("Europe/Paris")
  2782. with tm.assert_produces_warning(UserWarning, match="will drop timezone"):
  2783. per = dt.to_period(freq="H")
  2784. assert per.format()[0] == "2013-01-01 00:00"
  2785. @pytest.mark.parametrize(
  2786. "locale_str",
  2787. [
  2788. pytest.param(None, id=str(locale.getlocale())),
  2789. "it_IT.utf8",
  2790. "it_IT", # Note: encoding will be 'ISO8859-1'
  2791. "zh_CN.utf8",
  2792. "zh_CN", # Note: encoding will be 'gb2312'
  2793. ],
  2794. )
  2795. def test_period_non_ascii_fmt(self, locale_str):
  2796. # GH#46468 non-ascii char in input format string leads to wrong output
  2797. # Skip if locale cannot be set
  2798. if locale_str is not None and not tm.can_set_locale(locale_str, locale.LC_ALL):
  2799. pytest.skip(f"Skipping as locale '{locale_str}' cannot be set on host.")
  2800. # Change locale temporarily for this test.
  2801. with tm.set_locale(locale_str, locale.LC_ALL) if locale_str else nullcontext():
  2802. # Scalar
  2803. per = pd.Period("2018-03-11 13:00", freq="H")
  2804. assert per.strftime("%y é") == "18 é"
  2805. # Index
  2806. per = pd.period_range("2003-01-01 01:00:00", periods=2, freq="12h")
  2807. formatted = per.format(date_format="%y é")
  2808. assert formatted[0] == "03 é"
  2809. assert formatted[1] == "03 é"
  2810. @pytest.mark.parametrize(
  2811. "locale_str",
  2812. [
  2813. pytest.param(None, id=str(locale.getlocale())),
  2814. "it_IT.utf8",
  2815. "it_IT", # Note: encoding will be 'ISO8859-1'
  2816. "zh_CN.utf8",
  2817. "zh_CN", # Note: encoding will be 'gb2312'
  2818. ],
  2819. )
  2820. def test_period_custom_locale_directive(self, locale_str):
  2821. # GH#46319 locale-specific directive leads to non-utf8 c strftime char* result
  2822. # Skip if locale cannot be set
  2823. if locale_str is not None and not tm.can_set_locale(locale_str, locale.LC_ALL):
  2824. pytest.skip(f"Skipping as locale '{locale_str}' cannot be set on host.")
  2825. # Change locale temporarily for this test.
  2826. with tm.set_locale(locale_str, locale.LC_ALL) if locale_str else nullcontext():
  2827. # Get locale-specific reference
  2828. am_local, pm_local = get_local_am_pm()
  2829. # Scalar
  2830. per = pd.Period("2018-03-11 13:00", freq="H")
  2831. assert per.strftime("%p") == pm_local
  2832. # Index
  2833. per = pd.period_range("2003-01-01 01:00:00", periods=2, freq="12h")
  2834. formatted = per.format(date_format="%y %I:%M:%S%p")
  2835. assert formatted[0] == f"03 01:00:00{am_local}"
  2836. assert formatted[1] == f"03 01:00:00{pm_local}"
  2837. class TestDatetimeIndexFormat:
  2838. def test_datetime(self):
  2839. formatted = pd.to_datetime([datetime(2003, 1, 1, 12), NaT]).format()
  2840. assert formatted[0] == "2003-01-01 12:00:00"
  2841. assert formatted[1] == "NaT"
  2842. def test_date(self):
  2843. formatted = pd.to_datetime([datetime(2003, 1, 1), NaT]).format()
  2844. assert formatted[0] == "2003-01-01"
  2845. assert formatted[1] == "NaT"
  2846. def test_date_tz(self):
  2847. formatted = pd.to_datetime([datetime(2013, 1, 1)], utc=True).format()
  2848. assert formatted[0] == "2013-01-01 00:00:00+00:00"
  2849. formatted = pd.to_datetime([datetime(2013, 1, 1), NaT], utc=True).format()
  2850. assert formatted[0] == "2013-01-01 00:00:00+00:00"
  2851. def test_date_explicit_date_format(self):
  2852. formatted = pd.to_datetime([datetime(2003, 2, 1), NaT]).format(
  2853. date_format="%m-%d-%Y", na_rep="UT"
  2854. )
  2855. assert formatted[0] == "02-01-2003"
  2856. assert formatted[1] == "UT"
  2857. class TestDatetimeIndexUnicode:
  2858. def test_dates(self):
  2859. text = str(pd.to_datetime([datetime(2013, 1, 1), datetime(2014, 1, 1)]))
  2860. assert "['2013-01-01'," in text
  2861. assert ", '2014-01-01']" in text
  2862. def test_mixed(self):
  2863. text = str(
  2864. pd.to_datetime(
  2865. [datetime(2013, 1, 1), datetime(2014, 1, 1, 12), datetime(2014, 1, 1)]
  2866. )
  2867. )
  2868. assert "'2013-01-01 00:00:00'," in text
  2869. assert "'2014-01-01 00:00:00']" in text
  2870. class TestStringRepTimestamp:
  2871. def test_no_tz(self):
  2872. dt_date = datetime(2013, 1, 2)
  2873. assert str(dt_date) == str(Timestamp(dt_date))
  2874. dt_datetime = datetime(2013, 1, 2, 12, 1, 3)
  2875. assert str(dt_datetime) == str(Timestamp(dt_datetime))
  2876. dt_datetime_us = datetime(2013, 1, 2, 12, 1, 3, 45)
  2877. assert str(dt_datetime_us) == str(Timestamp(dt_datetime_us))
  2878. ts_nanos_only = Timestamp(200)
  2879. assert str(ts_nanos_only) == "1970-01-01 00:00:00.000000200"
  2880. ts_nanos_micros = Timestamp(1200)
  2881. assert str(ts_nanos_micros) == "1970-01-01 00:00:00.000001200"
  2882. def test_tz_pytz(self):
  2883. dt_date = datetime(2013, 1, 2, tzinfo=pytz.utc)
  2884. assert str(dt_date) == str(Timestamp(dt_date))
  2885. dt_datetime = datetime(2013, 1, 2, 12, 1, 3, tzinfo=pytz.utc)
  2886. assert str(dt_datetime) == str(Timestamp(dt_datetime))
  2887. dt_datetime_us = datetime(2013, 1, 2, 12, 1, 3, 45, tzinfo=pytz.utc)
  2888. assert str(dt_datetime_us) == str(Timestamp(dt_datetime_us))
  2889. def test_tz_dateutil(self):
  2890. utc = dateutil.tz.tzutc()
  2891. dt_date = datetime(2013, 1, 2, tzinfo=utc)
  2892. assert str(dt_date) == str(Timestamp(dt_date))
  2893. dt_datetime = datetime(2013, 1, 2, 12, 1, 3, tzinfo=utc)
  2894. assert str(dt_datetime) == str(Timestamp(dt_datetime))
  2895. dt_datetime_us = datetime(2013, 1, 2, 12, 1, 3, 45, tzinfo=utc)
  2896. assert str(dt_datetime_us) == str(Timestamp(dt_datetime_us))
  2897. def test_nat_representations(self):
  2898. for f in (str, repr, methodcaller("isoformat")):
  2899. assert f(NaT) == "NaT"
  2900. @pytest.mark.parametrize(
  2901. "percentiles, expected",
  2902. [
  2903. (
  2904. [0.01999, 0.02001, 0.5, 0.666666, 0.9999],
  2905. ["1.999%", "2.001%", "50%", "66.667%", "99.99%"],
  2906. ),
  2907. (
  2908. [0, 0.5, 0.02001, 0.5, 0.666666, 0.9999],
  2909. ["0%", "50%", "2.0%", "50%", "66.67%", "99.99%"],
  2910. ),
  2911. ([0.281, 0.29, 0.57, 0.58], ["28.1%", "29%", "57%", "58%"]),
  2912. ([0.28, 0.29, 0.57, 0.58], ["28%", "29%", "57%", "58%"]),
  2913. ],
  2914. )
  2915. def test_format_percentiles(percentiles, expected):
  2916. result = fmt.format_percentiles(percentiles)
  2917. assert result == expected
  2918. @pytest.mark.parametrize(
  2919. "percentiles",
  2920. [([0.1, np.nan, 0.5]), ([-0.001, 0.1, 0.5]), ([2, 0.1, 0.5]), ([0.1, 0.5, "a"])],
  2921. )
  2922. def test_error_format_percentiles(percentiles):
  2923. msg = r"percentiles should all be in the interval \[0,1\]"
  2924. with pytest.raises(ValueError, match=msg):
  2925. fmt.format_percentiles(percentiles)
  2926. def test_format_percentiles_integer_idx():
  2927. # Issue #26660
  2928. result = fmt.format_percentiles(np.linspace(0, 1, 10 + 1))
  2929. expected = [
  2930. "0%",
  2931. "10%",
  2932. "20%",
  2933. "30%",
  2934. "40%",
  2935. "50%",
  2936. "60%",
  2937. "70%",
  2938. "80%",
  2939. "90%",
  2940. "100%",
  2941. ]
  2942. assert result == expected
  2943. def test_repr_html_ipython_config(ip):
  2944. code = textwrap.dedent(
  2945. """\
  2946. from pandas import DataFrame
  2947. df = DataFrame({"A": [1, 2]})
  2948. df._repr_html_()
  2949. cfg = get_ipython().config
  2950. cfg['IPKernelApp']['parent_appname']
  2951. df._repr_html_()
  2952. """
  2953. )
  2954. result = ip.run_cell(code)
  2955. assert not result.error_in_exec
  2956. @pytest.mark.parametrize("method", ["to_string", "to_html", "to_latex"])
  2957. @pytest.mark.parametrize(
  2958. "encoding, data",
  2959. [(None, "abc"), ("utf-8", "abc"), ("gbk", "造成输出中文显示乱码"), ("foo", "abc")],
  2960. )
  2961. def test_filepath_or_buffer_arg(
  2962. method,
  2963. filepath_or_buffer,
  2964. assert_filepath_or_buffer_equals,
  2965. encoding,
  2966. data,
  2967. filepath_or_buffer_id,
  2968. ):
  2969. df = DataFrame([data])
  2970. if method in ["to_latex"]: # uses styler implementation
  2971. pytest.importorskip("jinja2")
  2972. if filepath_or_buffer_id not in ["string", "pathlike"] and encoding is not None:
  2973. with pytest.raises(
  2974. ValueError, match="buf is not a file name and encoding is specified."
  2975. ):
  2976. getattr(df, method)(buf=filepath_or_buffer, encoding=encoding)
  2977. elif encoding == "foo":
  2978. with pytest.raises(LookupError, match="unknown encoding"):
  2979. getattr(df, method)(buf=filepath_or_buffer, encoding=encoding)
  2980. else:
  2981. expected = getattr(df, method)()
  2982. getattr(df, method)(buf=filepath_or_buffer, encoding=encoding)
  2983. assert_filepath_or_buffer_equals(expected)
  2984. @pytest.mark.parametrize("method", ["to_string", "to_html", "to_latex"])
  2985. def test_filepath_or_buffer_bad_arg_raises(float_frame, method):
  2986. if method in ["to_latex"]: # uses styler implementation
  2987. pytest.importorskip("jinja2")
  2988. msg = "buf is not a file name and it has no write method"
  2989. with pytest.raises(TypeError, match=msg):
  2990. getattr(float_frame, method)(buf=object())