From 4ff00b7f63e13752ddadc67b028a340b017022f1 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 20 Jan 2022 11:35:38 -0800 Subject: [PATCH 01/26] CI: Troubleshoot --- pandas/tests/io/excel/__init__.py | 35 - pandas/tests/io/excel/conftest.py | 65 - pandas/tests/io/excel/test_odf.py | 38 - pandas/tests/io/excel/test_odswriter.py | 58 - pandas/tests/io/excel/test_openpyxl.py | 377 - pandas/tests/io/excel/test_readers.py | 1579 --- pandas/tests/io/excel/test_style.py | 167 - pandas/tests/io/excel/test_writers.py | 1335 --- pandas/tests/io/excel/test_xlrd.py | 109 - pandas/tests/io/excel/test_xlsxwriter.py | 84 - pandas/tests/io/excel/test_xlwt.py | 127 - pandas/tests/io/formats/__init__.py | 0 .../data/html/datetime64_hourformatter.html | 18 - .../data/html/datetime64_monthformatter.html | 18 - .../io/formats/data/html/escape_disabled.html | 21 - .../tests/io/formats/data/html/escaped.html | 21 - .../data/html/gh12031_expected_output.html | 22 - .../data/html/gh13828_expected_output.html | 21 - .../data/html/gh14882_expected_output_1.html | 274 - .../data/html/gh14882_expected_output_2.html | 258 - .../data/html/gh14998_expected_output.html | 12 - .../data/html/gh15019_expected_output.html | 30 - .../data/html/gh21625_expected_output.html | 14 - .../data/html/gh22270_expected_output.html | 14 - .../data/html/gh22579_expected_output.html | 76 - .../data/html/gh22783_expected_output.html | 27 - .../html/gh22783_named_columns_index.html | 30 - .../data/html/gh40024_expected_output.html | 18 - .../data/html/gh6131_expected_output.html | 46 - .../data/html/gh8452_expected_output.html | 28 - .../html_repr_max_rows_10_min_rows_12.html | 70 - .../html_repr_max_rows_10_min_rows_4.html | 46 - .../html_repr_max_rows_12_min_rows_None.html | 78 - .../html_repr_max_rows_None_min_rows_12.html | 269 - ...l_repr_min_rows_default_no_truncation.html | 105 - .../html_repr_min_rows_default_truncated.html | 70 - .../tests/io/formats/data/html/index_1.html | 30 - .../tests/io/formats/data/html/index_2.html | 26 - .../tests/io/formats/data/html/index_3.html | 36 - .../tests/io/formats/data/html/index_4.html | 33 - .../tests/io/formats/data/html/index_5.html | 40 - .../io/formats/data/html/index_formatter.html | 31 - ...index_named_multi_columns_named_multi.html | 34 - ...ex_named_multi_columns_named_standard.html | 29 - .../html/index_named_multi_columns_none.html | 23 - ...dex_named_multi_columns_unnamed_multi.html | 34 - ..._named_multi_columns_unnamed_standard.html | 29 - ...ex_named_standard_columns_named_multi.html | 30 - ...named_standard_columns_named_standard.html | 26 - .../index_named_standard_columns_none.html | 21 - ..._named_standard_columns_unnamed_multi.html | 30 - ...med_standard_columns_unnamed_standard.html | 26 - .../html/index_none_columns_named_multi.html | 25 - .../index_none_columns_named_standard.html | 21 - .../data/html/index_none_columns_none.html | 12 - .../index_none_columns_unnamed_multi.html | 21 - .../index_none_columns_unnamed_standard.html | 18 - ...dex_unnamed_multi_columns_named_multi.html | 28 - ..._unnamed_multi_columns_named_standard.html | 23 - .../index_unnamed_multi_columns_none.html | 15 - ...x_unnamed_multi_columns_unnamed_multi.html | 28 - ...nnamed_multi_columns_unnamed_standard.html | 23 - ..._unnamed_standard_columns_named_multi.html | 25 - ...named_standard_columns_named_standard.html | 21 - .../index_unnamed_standard_columns_none.html | 14 - ...nnamed_standard_columns_unnamed_multi.html | 25 - ...med_standard_columns_unnamed_standard.html | 21 - .../tests/io/formats/data/html/justify.html | 30 - .../io/formats/data/html/multiindex_1.html | 32 - .../io/formats/data/html/multiindex_2.html | 34 - .../data/html/multiindex_sparsify_1.html | 40 - .../data/html/multiindex_sparsify_2.html | 46 - ...tiindex_sparsify_false_multi_sparse_1.html | 42 - ...tiindex_sparsify_false_multi_sparse_2.html | 48 - .../formats/data/html/render_links_false.html | 24 - .../formats/data/html/render_links_true.html | 24 - ...index_named_multi_columns_named_multi.html | 88 - ...ex_named_multi_columns_named_standard.html | 72 - ...unc_df_index_named_multi_columns_none.html | 62 - ...dex_named_multi_columns_unnamed_multi.html | 88 - ..._named_multi_columns_unnamed_standard.html | 72 - ...ex_named_standard_columns_named_multi.html | 74 - ...named_standard_columns_named_standard.html | 62 - ..._df_index_named_standard_columns_none.html | 54 - ..._named_standard_columns_unnamed_multi.html | 74 - ...med_standard_columns_unnamed_standard.html | 62 - ...unc_df_index_none_columns_named_multi.html | 66 - ..._df_index_none_columns_named_standard.html | 54 - .../trunc_df_index_none_columns_none.html | 39 - ...c_df_index_none_columns_unnamed_multi.html | 58 - ...f_index_none_columns_unnamed_standard.html | 48 - ...dex_unnamed_multi_columns_named_multi.html | 78 - ..._unnamed_multi_columns_named_standard.html | 62 - ...c_df_index_unnamed_multi_columns_none.html | 50 - ...x_unnamed_multi_columns_unnamed_multi.html | 78 - ...nnamed_multi_columns_unnamed_standard.html | 62 - ..._unnamed_standard_columns_named_multi.html | 66 - ...named_standard_columns_named_standard.html | 54 - ...f_index_unnamed_standard_columns_none.html | 44 - ...nnamed_standard_columns_unnamed_multi.html | 66 - ...med_standard_columns_unnamed_standard.html | 54 - .../tests/io/formats/data/html/truncate.html | 86 - .../formats/data/html/truncate_formatter.html | 36 - .../data/html/truncate_multi_index.html | 101 - .../html/truncate_multi_index_sparse_off.html | 105 - .../tests/io/formats/data/html/unicode_1.html | 50 - .../tests/io/formats/data/html/unicode_2.html | 14 - .../data/html/various_dtypes_formatted.html | 36 - .../io/formats/data/html/with_classes.html | 9 - pandas/tests/io/formats/style/__init__.py | 0 pandas/tests/io/formats/style/test_bar.py | 307 - .../tests/io/formats/style/test_deprecated.py | 165 - pandas/tests/io/formats/style/test_format.py | 436 - .../tests/io/formats/style/test_highlight.py | 216 - pandas/tests/io/formats/style/test_html.py | 806 -- .../tests/io/formats/style/test_matplotlib.py | 286 - .../tests/io/formats/style/test_non_unique.py | 140 - pandas/tests/io/formats/style/test_style.py | 1556 --- .../tests/io/formats/style/test_to_latex.py | 992 -- .../tests/io/formats/style/test_to_string.py | 42 - pandas/tests/io/formats/style/test_tooltip.py | 85 - pandas/tests/io/formats/test_console.py | 72 - pandas/tests/io/formats/test_css.py | 229 - .../tests/io/formats/test_eng_formatting.py | 234 - pandas/tests/io/formats/test_format.py | 3349 ------ pandas/tests/io/formats/test_info.py | 492 - pandas/tests/io/formats/test_printing.py | 200 - pandas/tests/io/formats/test_series_info.py | 179 - pandas/tests/io/formats/test_to_csv.py | 719 -- pandas/tests/io/formats/test_to_excel.py | 333 - pandas/tests/io/formats/test_to_html.py | 890 -- pandas/tests/io/formats/test_to_latex.py | 1530 --- pandas/tests/io/formats/test_to_markdown.py | 101 - pandas/tests/io/formats/test_to_string.py | 340 - pandas/tests/io/json/__init__.py | 0 pandas/tests/io/json/conftest.py | 9 - pandas/tests/io/json/data/line_delimited.json | 3 - .../tests/io/json/data/tsframe_iso_v012.json | 1 - pandas/tests/io/json/data/tsframe_v012.json | 1 - .../tests/io/json/data/tsframe_v012.json.zip | Bin 436 -> 0 bytes pandas/tests/io/json/test_compression.py | 127 - .../tests/io/json/test_deprecated_kwargs.py | 31 - .../tests/io/json/test_json_table_schema.py | 813 -- .../json/test_json_table_schema_ext_dtype.py | 268 - pandas/tests/io/json/test_normalize.py | 893 -- pandas/tests/io/json/test_pandas.py | 1860 ---- pandas/tests/io/json/test_readlines.py | 298 - pandas/tests/io/json/test_ujson.py | 1244 --- pandas/tests/io/parser/__init__.py | 0 pandas/tests/io/parser/common/__init__.py | 0 .../tests/io/parser/common/test_chunksize.py | 278 - .../io/parser/common/test_common_basic.py | 931 -- .../tests/io/parser/common/test_data_list.py | 87 - pandas/tests/io/parser/common/test_decimal.py | 62 - .../io/parser/common/test_file_buffer_url.py | 422 - pandas/tests/io/parser/common/test_float.py | 65 - pandas/tests/io/parser/common/test_index.py | 299 - pandas/tests/io/parser/common/test_inf.py | 68 - pandas/tests/io/parser/common/test_ints.py | 215 - .../tests/io/parser/common/test_iterator.py | 109 - .../io/parser/common/test_read_errors.py | 280 - pandas/tests/io/parser/common/test_verbose.py | 55 - pandas/tests/io/parser/conftest.py | 280 - pandas/tests/io/parser/data/items.jsonl | 2 - pandas/tests/io/parser/data/salaries.csv | 47 - pandas/tests/io/parser/data/salaries.csv.bz2 | Bin 283 -> 0 bytes pandas/tests/io/parser/data/salaries.csv.gz | Bin 302 -> 0 bytes pandas/tests/io/parser/data/salaries.csv.xz | Bin 336 -> 0 bytes pandas/tests/io/parser/data/salaries.csv.zip | Bin 445 -> 0 bytes pandas/tests/io/parser/data/salaries.csv.zst | Bin 281 -> 0 bytes .../tests/io/parser/data/sauron.SHIFT_JIS.csv | 14 - pandas/tests/io/parser/data/sub_char.csv | 2 - pandas/tests/io/parser/data/tar_csv.tar | Bin 10240 -> 0 bytes pandas/tests/io/parser/data/tar_csv.tar.gz | Bin 117 -> 0 bytes pandas/tests/io/parser/data/test2.csv | 6 - pandas/tests/io/parser/data/test_mmap.csv | 4 - .../tests/io/parser/data/unicode_series.csv | 18 - pandas/tests/io/parser/data/utf16_ex.txt | Bin 11406 -> 0 bytes .../tests/io/parser/data/utf16_ex_small.zip | Bin 285 -> 0 bytes .../tests/io/parser/data/utf32_ex_small.zip | Bin 251 -> 0 bytes pandas/tests/io/parser/data/utf8_ex_small.zip | Bin 201 -> 0 bytes pandas/tests/io/parser/dtypes/__init__.py | 0 .../io/parser/dtypes/test_categorical.py | 310 - .../io/parser/dtypes/test_dtypes_basic.py | 336 - pandas/tests/io/parser/dtypes/test_empty.py | 182 - pandas/tests/io/parser/test_c_parser_only.py | 684 -- pandas/tests/io/parser/test_comment.py | 168 - pandas/tests/io/parser/test_compression.py | 176 - pandas/tests/io/parser/test_converters.py | 191 - pandas/tests/io/parser/test_dialect.py | 146 - pandas/tests/io/parser/test_encoding.py | 315 - pandas/tests/io/parser/test_header.py | 668 -- pandas/tests/io/parser/test_index_col.py | 354 - pandas/tests/io/parser/test_mangle_dupes.py | 168 - pandas/tests/io/parser/test_multi_thread.py | 154 - pandas/tests/io/parser/test_na_values.py | 656 -- pandas/tests/io/parser/test_network.py | 303 - pandas/tests/io/parser/test_parse_dates.py | 1987 ---- .../io/parser/test_python_parser_only.py | 460 - pandas/tests/io/parser/test_quoting.py | 161 - pandas/tests/io/parser/test_read_fwf.py | 922 -- pandas/tests/io/parser/test_skiprows.py | 277 - pandas/tests/io/parser/test_textreader.py | 350 - pandas/tests/io/parser/test_unsupported.py | 183 - pandas/tests/io/parser/usecols/__init__.py | 0 .../io/parser/usecols/test_parse_dates.py | 155 - .../tests/io/parser/usecols/test_strings.py | 97 - .../io/parser/usecols/test_usecols_basic.py | 418 - pandas/tests/io/pytables/__init__.py | 15 - pandas/tests/io/pytables/common.py | 84 - pandas/tests/io/pytables/conftest.py | 17 - pandas/tests/io/pytables/test_append.py | 941 -- pandas/tests/io/pytables/test_categorical.py | 222 - pandas/tests/io/pytables/test_compat.py | 77 - pandas/tests/io/pytables/test_complex.py | 203 - pandas/tests/io/pytables/test_errors.py | 239 - .../tests/io/pytables/test_file_handling.py | 447 - pandas/tests/io/pytables/test_keys.py | 80 - pandas/tests/io/pytables/test_put.py | 369 - .../io/pytables/test_pytables_missing.py | 14 - pandas/tests/io/pytables/test_read.py | 345 - .../io/pytables/test_retain_attributes.py | 117 - pandas/tests/io/pytables/test_round_trip.py | 564 - pandas/tests/io/pytables/test_select.py | 976 -- pandas/tests/io/pytables/test_store.py | 1022 -- pandas/tests/io/pytables/test_subclass.py | 50 - pandas/tests/io/pytables/test_time_series.py | 66 - pandas/tests/io/pytables/test_timezones.py | 370 - pandas/tests/io/sas/__init__.py | 0 pandas/tests/io/sas/data/DEMO_G.csv | 9757 ----------------- pandas/tests/io/sas/data/DEMO_G.xpt | Bin 3753760 -> 0 bytes pandas/tests/io/sas/data/DEMO_PUF.cpt | Bin 694 -> 0 bytes pandas/tests/io/sas/data/DRXFCD_G.csv | 7619 ------------- pandas/tests/io/sas/data/DRXFCD_G.xpt | Bin 2195200 -> 0 bytes pandas/tests/io/sas/data/SSHSV1_A.csv | 1427 --- pandas/tests/io/sas/data/SSHSV1_A.xpt | Bin 23920 -> 0 bytes pandas/tests/io/sas/data/airline.csv | 33 - pandas/tests/io/sas/data/airline.sas7bdat | Bin 5120 -> 0 bytes pandas/tests/io/sas/data/cars.sas7bdat | Bin 13312 -> 0 bytes pandas/tests/io/sas/data/corrupt.sas7bdat | Bin 292 -> 0 bytes pandas/tests/io/sas/data/dates_null.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/datetime.csv | 5 - pandas/tests/io/sas/data/datetime.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/load_log.sas7bdat | Bin 589824 -> 0 bytes pandas/tests/io/sas/data/many_columns.csv | 4 - .../tests/io/sas/data/many_columns.sas7bdat | Bin 81920 -> 0 bytes .../tests/io/sas/data/max_sas_date.sas7bdat | Bin 393216 -> 0 bytes pandas/tests/io/sas/data/paxraw_d_short.csv | 101 - pandas/tests/io/sas/data/paxraw_d_short.xpt | Bin 6960 -> 0 bytes pandas/tests/io/sas/data/productsales.csv | 1441 --- .../tests/io/sas/data/productsales.sas7bdat | Bin 148480 -> 0 bytes pandas/tests/io/sas/data/test1.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/test10.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/test11.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test12.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test13.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/test14.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test15.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test16.sas7bdat | Bin 73728 -> 0 bytes pandas/tests/io/sas/data/test2.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test3.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test4.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/test5.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test6.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test7.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/test8.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test9.sas7bdat | Bin 196608 -> 0 bytes pandas/tests/io/sas/data/test_12659.csv | 37 - pandas/tests/io/sas/data/test_12659.sas7bdat | Bin 131072 -> 0 bytes pandas/tests/io/sas/data/test_sas7bdat_1.csv | 11 - pandas/tests/io/sas/data/test_sas7bdat_2.csv | 11 - .../tests/io/sas/data/zero_variables.sas7bdat | Bin 149504 -> 0 bytes pandas/tests/io/sas/test_sas.py | 26 - pandas/tests/io/sas/test_sas7bdat.py | 343 - pandas/tests/io/sas/test_xport.py | 168 - pandas/tests/io/test_clipboard.py | 313 - pandas/tests/io/test_common.py | 602 - pandas/tests/io/test_compression.py | 257 - pandas/tests/io/test_date_converters.py | 43 - pandas/tests/io/test_feather.py | 199 - pandas/tests/io/test_fsspec.py | 329 - pandas/tests/io/test_gcs.py | 194 - pandas/tests/io/test_html.py | 1284 --- pandas/tests/io/test_orc.py | 226 - pandas/tests/io/test_parquet.py | 1119 -- pandas/tests/io/test_pickle.py | 630 -- pandas/tests/io/test_s3.py | 48 - pandas/tests/io/test_spss.py | 76 - pandas/tests/io/test_sql.py | 2938 ----- pandas/tests/io/test_stata.py | 2208 ---- pandas/tests/io/test_user_agent.py | 366 - pandas/tests/io/xml/__init__.py | 0 pandas/tests/io/xml/test_to_xml.py | 1344 --- pandas/tests/io/xml/test_xml.py | 1125 -- 294 files changed, 81516 deletions(-) delete mode 100644 pandas/tests/io/excel/__init__.py delete mode 100644 pandas/tests/io/excel/conftest.py delete mode 100644 pandas/tests/io/excel/test_odf.py delete mode 100644 pandas/tests/io/excel/test_odswriter.py delete mode 100644 pandas/tests/io/excel/test_openpyxl.py delete mode 100644 pandas/tests/io/excel/test_readers.py delete mode 100644 pandas/tests/io/excel/test_style.py delete mode 100644 pandas/tests/io/excel/test_writers.py delete mode 100644 pandas/tests/io/excel/test_xlrd.py delete mode 100644 pandas/tests/io/excel/test_xlsxwriter.py delete mode 100644 pandas/tests/io/excel/test_xlwt.py delete mode 100644 pandas/tests/io/formats/__init__.py delete mode 100644 pandas/tests/io/formats/data/html/datetime64_hourformatter.html delete mode 100644 pandas/tests/io/formats/data/html/datetime64_monthformatter.html delete mode 100644 pandas/tests/io/formats/data/html/escape_disabled.html delete mode 100644 pandas/tests/io/formats/data/html/escaped.html delete mode 100644 pandas/tests/io/formats/data/html/gh12031_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh13828_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh14882_expected_output_1.html delete mode 100644 pandas/tests/io/formats/data/html/gh14882_expected_output_2.html delete mode 100644 pandas/tests/io/formats/data/html/gh14998_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh15019_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh21625_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh22270_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh22579_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh22783_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh22783_named_columns_index.html delete mode 100644 pandas/tests/io/formats/data/html/gh40024_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh6131_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/gh8452_expected_output.html delete mode 100644 pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_12.html delete mode 100644 pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_4.html delete mode 100644 pandas/tests/io/formats/data/html/html_repr_max_rows_12_min_rows_None.html delete mode 100644 pandas/tests/io/formats/data/html/html_repr_max_rows_None_min_rows_12.html delete mode 100644 pandas/tests/io/formats/data/html/html_repr_min_rows_default_no_truncation.html delete mode 100644 pandas/tests/io/formats/data/html/html_repr_min_rows_default_truncated.html delete mode 100644 pandas/tests/io/formats/data/html/index_1.html delete mode 100644 pandas/tests/io/formats/data/html/index_2.html delete mode 100644 pandas/tests/io/formats/data/html/index_3.html delete mode 100644 pandas/tests/io/formats/data/html/index_4.html delete mode 100644 pandas/tests/io/formats/data/html/index_5.html delete mode 100644 pandas/tests/io/formats/data/html/index_formatter.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_multi_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_multi_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_multi_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_standard_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_standard_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_standard_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_none_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_none_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_none_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/index_none_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_none_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_multi_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_standard_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/justify.html delete mode 100644 pandas/tests/io/formats/data/html/multiindex_1.html delete mode 100644 pandas/tests/io/formats/data/html/multiindex_2.html delete mode 100644 pandas/tests/io/formats/data/html/multiindex_sparsify_1.html delete mode 100644 pandas/tests/io/formats/data/html/multiindex_sparsify_2.html delete mode 100644 pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_1.html delete mode 100644 pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_2.html delete mode 100644 pandas/tests/io/formats/data/html/render_links_false.html delete mode 100644 pandas/tests/io/formats/data/html/render_links_true.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_none_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_standard.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_none.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_multi.html delete mode 100644 pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_standard.html delete mode 100644 pandas/tests/io/formats/data/html/truncate.html delete mode 100644 pandas/tests/io/formats/data/html/truncate_formatter.html delete mode 100644 pandas/tests/io/formats/data/html/truncate_multi_index.html delete mode 100644 pandas/tests/io/formats/data/html/truncate_multi_index_sparse_off.html delete mode 100644 pandas/tests/io/formats/data/html/unicode_1.html delete mode 100644 pandas/tests/io/formats/data/html/unicode_2.html delete mode 100644 pandas/tests/io/formats/data/html/various_dtypes_formatted.html delete mode 100644 pandas/tests/io/formats/data/html/with_classes.html delete mode 100644 pandas/tests/io/formats/style/__init__.py delete mode 100644 pandas/tests/io/formats/style/test_bar.py delete mode 100644 pandas/tests/io/formats/style/test_deprecated.py delete mode 100644 pandas/tests/io/formats/style/test_format.py delete mode 100644 pandas/tests/io/formats/style/test_highlight.py delete mode 100644 pandas/tests/io/formats/style/test_html.py delete mode 100644 pandas/tests/io/formats/style/test_matplotlib.py delete mode 100644 pandas/tests/io/formats/style/test_non_unique.py delete mode 100644 pandas/tests/io/formats/style/test_style.py delete mode 100644 pandas/tests/io/formats/style/test_to_latex.py delete mode 100644 pandas/tests/io/formats/style/test_to_string.py delete mode 100644 pandas/tests/io/formats/style/test_tooltip.py delete mode 100644 pandas/tests/io/formats/test_console.py delete mode 100644 pandas/tests/io/formats/test_css.py delete mode 100644 pandas/tests/io/formats/test_eng_formatting.py delete mode 100644 pandas/tests/io/formats/test_format.py delete mode 100644 pandas/tests/io/formats/test_info.py delete mode 100644 pandas/tests/io/formats/test_printing.py delete mode 100644 pandas/tests/io/formats/test_series_info.py delete mode 100644 pandas/tests/io/formats/test_to_csv.py delete mode 100644 pandas/tests/io/formats/test_to_excel.py delete mode 100644 pandas/tests/io/formats/test_to_html.py delete mode 100644 pandas/tests/io/formats/test_to_latex.py delete mode 100644 pandas/tests/io/formats/test_to_markdown.py delete mode 100644 pandas/tests/io/formats/test_to_string.py delete mode 100644 pandas/tests/io/json/__init__.py delete mode 100644 pandas/tests/io/json/conftest.py delete mode 100644 pandas/tests/io/json/data/line_delimited.json delete mode 100644 pandas/tests/io/json/data/tsframe_iso_v012.json delete mode 100644 pandas/tests/io/json/data/tsframe_v012.json delete mode 100644 pandas/tests/io/json/data/tsframe_v012.json.zip delete mode 100644 pandas/tests/io/json/test_compression.py delete mode 100644 pandas/tests/io/json/test_deprecated_kwargs.py delete mode 100644 pandas/tests/io/json/test_json_table_schema.py delete mode 100644 pandas/tests/io/json/test_json_table_schema_ext_dtype.py delete mode 100644 pandas/tests/io/json/test_normalize.py delete mode 100644 pandas/tests/io/json/test_pandas.py delete mode 100644 pandas/tests/io/json/test_readlines.py delete mode 100644 pandas/tests/io/json/test_ujson.py delete mode 100644 pandas/tests/io/parser/__init__.py delete mode 100644 pandas/tests/io/parser/common/__init__.py delete mode 100644 pandas/tests/io/parser/common/test_chunksize.py delete mode 100644 pandas/tests/io/parser/common/test_common_basic.py delete mode 100644 pandas/tests/io/parser/common/test_data_list.py delete mode 100644 pandas/tests/io/parser/common/test_decimal.py delete mode 100644 pandas/tests/io/parser/common/test_file_buffer_url.py delete mode 100644 pandas/tests/io/parser/common/test_float.py delete mode 100644 pandas/tests/io/parser/common/test_index.py delete mode 100644 pandas/tests/io/parser/common/test_inf.py delete mode 100644 pandas/tests/io/parser/common/test_ints.py delete mode 100644 pandas/tests/io/parser/common/test_iterator.py delete mode 100644 pandas/tests/io/parser/common/test_read_errors.py delete mode 100644 pandas/tests/io/parser/common/test_verbose.py delete mode 100644 pandas/tests/io/parser/conftest.py delete mode 100644 pandas/tests/io/parser/data/items.jsonl delete mode 100644 pandas/tests/io/parser/data/salaries.csv delete mode 100644 pandas/tests/io/parser/data/salaries.csv.bz2 delete mode 100644 pandas/tests/io/parser/data/salaries.csv.gz delete mode 100644 pandas/tests/io/parser/data/salaries.csv.xz delete mode 100644 pandas/tests/io/parser/data/salaries.csv.zip delete mode 100644 pandas/tests/io/parser/data/salaries.csv.zst delete mode 100644 pandas/tests/io/parser/data/sauron.SHIFT_JIS.csv delete mode 100644 pandas/tests/io/parser/data/sub_char.csv delete mode 100644 pandas/tests/io/parser/data/tar_csv.tar delete mode 100644 pandas/tests/io/parser/data/tar_csv.tar.gz delete mode 100644 pandas/tests/io/parser/data/test2.csv delete mode 100644 pandas/tests/io/parser/data/test_mmap.csv delete mode 100644 pandas/tests/io/parser/data/unicode_series.csv delete mode 100644 pandas/tests/io/parser/data/utf16_ex.txt delete mode 100644 pandas/tests/io/parser/data/utf16_ex_small.zip delete mode 100644 pandas/tests/io/parser/data/utf32_ex_small.zip delete mode 100644 pandas/tests/io/parser/data/utf8_ex_small.zip delete mode 100644 pandas/tests/io/parser/dtypes/__init__.py delete mode 100644 pandas/tests/io/parser/dtypes/test_categorical.py delete mode 100644 pandas/tests/io/parser/dtypes/test_dtypes_basic.py delete mode 100644 pandas/tests/io/parser/dtypes/test_empty.py delete mode 100644 pandas/tests/io/parser/test_c_parser_only.py delete mode 100644 pandas/tests/io/parser/test_comment.py delete mode 100644 pandas/tests/io/parser/test_compression.py delete mode 100644 pandas/tests/io/parser/test_converters.py delete mode 100644 pandas/tests/io/parser/test_dialect.py delete mode 100644 pandas/tests/io/parser/test_encoding.py delete mode 100644 pandas/tests/io/parser/test_header.py delete mode 100644 pandas/tests/io/parser/test_index_col.py delete mode 100644 pandas/tests/io/parser/test_mangle_dupes.py delete mode 100644 pandas/tests/io/parser/test_multi_thread.py delete mode 100644 pandas/tests/io/parser/test_na_values.py delete mode 100644 pandas/tests/io/parser/test_network.py delete mode 100644 pandas/tests/io/parser/test_parse_dates.py delete mode 100644 pandas/tests/io/parser/test_python_parser_only.py delete mode 100644 pandas/tests/io/parser/test_quoting.py delete mode 100644 pandas/tests/io/parser/test_read_fwf.py delete mode 100644 pandas/tests/io/parser/test_skiprows.py delete mode 100644 pandas/tests/io/parser/test_textreader.py delete mode 100644 pandas/tests/io/parser/test_unsupported.py delete mode 100644 pandas/tests/io/parser/usecols/__init__.py delete mode 100644 pandas/tests/io/parser/usecols/test_parse_dates.py delete mode 100644 pandas/tests/io/parser/usecols/test_strings.py delete mode 100644 pandas/tests/io/parser/usecols/test_usecols_basic.py delete mode 100644 pandas/tests/io/pytables/__init__.py delete mode 100644 pandas/tests/io/pytables/common.py delete mode 100644 pandas/tests/io/pytables/conftest.py delete mode 100644 pandas/tests/io/pytables/test_append.py delete mode 100644 pandas/tests/io/pytables/test_categorical.py delete mode 100644 pandas/tests/io/pytables/test_compat.py delete mode 100644 pandas/tests/io/pytables/test_complex.py delete mode 100644 pandas/tests/io/pytables/test_errors.py delete mode 100644 pandas/tests/io/pytables/test_file_handling.py delete mode 100644 pandas/tests/io/pytables/test_keys.py delete mode 100644 pandas/tests/io/pytables/test_put.py delete mode 100644 pandas/tests/io/pytables/test_pytables_missing.py delete mode 100644 pandas/tests/io/pytables/test_read.py delete mode 100644 pandas/tests/io/pytables/test_retain_attributes.py delete mode 100644 pandas/tests/io/pytables/test_round_trip.py delete mode 100644 pandas/tests/io/pytables/test_select.py delete mode 100644 pandas/tests/io/pytables/test_store.py delete mode 100644 pandas/tests/io/pytables/test_subclass.py delete mode 100644 pandas/tests/io/pytables/test_time_series.py delete mode 100644 pandas/tests/io/pytables/test_timezones.py delete mode 100644 pandas/tests/io/sas/__init__.py delete mode 100644 pandas/tests/io/sas/data/DEMO_G.csv delete mode 100644 pandas/tests/io/sas/data/DEMO_G.xpt delete mode 100644 pandas/tests/io/sas/data/DEMO_PUF.cpt delete mode 100644 pandas/tests/io/sas/data/DRXFCD_G.csv delete mode 100644 pandas/tests/io/sas/data/DRXFCD_G.xpt delete mode 100644 pandas/tests/io/sas/data/SSHSV1_A.csv delete mode 100644 pandas/tests/io/sas/data/SSHSV1_A.xpt delete mode 100644 pandas/tests/io/sas/data/airline.csv delete mode 100644 pandas/tests/io/sas/data/airline.sas7bdat delete mode 100644 pandas/tests/io/sas/data/cars.sas7bdat delete mode 100644 pandas/tests/io/sas/data/corrupt.sas7bdat delete mode 100644 pandas/tests/io/sas/data/dates_null.sas7bdat delete mode 100644 pandas/tests/io/sas/data/datetime.csv delete mode 100644 pandas/tests/io/sas/data/datetime.sas7bdat delete mode 100644 pandas/tests/io/sas/data/load_log.sas7bdat delete mode 100644 pandas/tests/io/sas/data/many_columns.csv delete mode 100644 pandas/tests/io/sas/data/many_columns.sas7bdat delete mode 100644 pandas/tests/io/sas/data/max_sas_date.sas7bdat delete mode 100644 pandas/tests/io/sas/data/paxraw_d_short.csv delete mode 100644 pandas/tests/io/sas/data/paxraw_d_short.xpt delete mode 100644 pandas/tests/io/sas/data/productsales.csv delete mode 100644 pandas/tests/io/sas/data/productsales.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test1.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test10.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test11.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test12.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test13.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test14.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test15.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test16.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test2.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test3.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test4.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test5.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test6.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test7.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test8.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test9.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test_12659.csv delete mode 100644 pandas/tests/io/sas/data/test_12659.sas7bdat delete mode 100644 pandas/tests/io/sas/data/test_sas7bdat_1.csv delete mode 100644 pandas/tests/io/sas/data/test_sas7bdat_2.csv delete mode 100644 pandas/tests/io/sas/data/zero_variables.sas7bdat delete mode 100644 pandas/tests/io/sas/test_sas.py delete mode 100644 pandas/tests/io/sas/test_sas7bdat.py delete mode 100644 pandas/tests/io/sas/test_xport.py delete mode 100644 pandas/tests/io/test_clipboard.py delete mode 100644 pandas/tests/io/test_common.py delete mode 100644 pandas/tests/io/test_compression.py delete mode 100644 pandas/tests/io/test_date_converters.py delete mode 100644 pandas/tests/io/test_feather.py delete mode 100644 pandas/tests/io/test_fsspec.py delete mode 100644 pandas/tests/io/test_gcs.py delete mode 100644 pandas/tests/io/test_html.py delete mode 100644 pandas/tests/io/test_orc.py delete mode 100644 pandas/tests/io/test_parquet.py delete mode 100644 pandas/tests/io/test_pickle.py delete mode 100644 pandas/tests/io/test_s3.py delete mode 100644 pandas/tests/io/test_spss.py delete mode 100644 pandas/tests/io/test_sql.py delete mode 100644 pandas/tests/io/test_stata.py delete mode 100644 pandas/tests/io/test_user_agent.py delete mode 100644 pandas/tests/io/xml/__init__.py delete mode 100644 pandas/tests/io/xml/test_to_xml.py delete mode 100644 pandas/tests/io/xml/test_xml.py diff --git a/pandas/tests/io/excel/__init__.py b/pandas/tests/io/excel/__init__.py deleted file mode 100644 index c4343497ded48..0000000000000 --- a/pandas/tests/io/excel/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -import pytest - -from pandas.compat._optional import ( - get_version, - import_optional_dependency, -) - -from pandas.util.version import Version - -pytestmark = [ - pytest.mark.filterwarnings( - # Looks like tree.getiterator is deprecated in favor of tree.iter - "ignore:This method will be removed in future versions:" - "PendingDeprecationWarning" - ), - pytest.mark.filterwarnings( - "ignore:This method will be removed in future versions:DeprecationWarning" - ), - # GH 26552 - pytest.mark.filterwarnings( - "ignore:As the xlwt package is no longer maintained:FutureWarning" - ), - # GH 38571 - pytest.mark.filterwarnings( - "ignore:.*In xlrd >= 2.0, only the xls format is supported:FutureWarning" - ), -] - - -if import_optional_dependency("xlrd", errors="ignore") is None: - xlrd_version = None -else: - import xlrd - - xlrd_version = Version(get_version(xlrd)) diff --git a/pandas/tests/io/excel/conftest.py b/pandas/tests/io/excel/conftest.py deleted file mode 100644 index 0455e0d61ad97..0000000000000 --- a/pandas/tests/io/excel/conftest.py +++ /dev/null @@ -1,65 +0,0 @@ -import pytest - -import pandas.util._test_decorators as td - -import pandas._testing as tm - -from pandas.io.parsers import read_csv - - -@pytest.fixture -def frame(float_frame): - """ - Returns the first ten items in fixture "float_frame". - """ - return float_frame[:10] - - -@pytest.fixture -def tsframe(): - return tm.makeTimeDataFrame()[:5] - - -@pytest.fixture(params=[True, False]) -def merge_cells(request): - return request.param - - -@pytest.fixture -def df_ref(datapath): - """ - Obtain the reference data from read_csv with the Python engine. - """ - filepath = datapath("io", "data", "csv", "test1.csv") - df_ref = read_csv(filepath, index_col=0, parse_dates=True, engine="python") - return df_ref - - -@pytest.fixture(params=[".xls", ".xlsx", ".xlsm", ".ods", ".xlsb"]) -def read_ext(request): - """ - Valid extensions for reading Excel files. - """ - return request.param - - -@pytest.fixture(autouse=True) -def check_for_file_leaks(): - """ - Fixture to run around every test to ensure that we are not leaking files. - - See also - -------- - _test_decorators.check_file_leaks - """ - # GH#30162 - psutil = td.safe_import("psutil") - if not psutil: - yield - - else: - proc = psutil.Process() - flist = proc.open_files() - yield - flist2 = proc.open_files() - assert flist == flist2 diff --git a/pandas/tests/io/excel/test_odf.py b/pandas/tests/io/excel/test_odf.py deleted file mode 100644 index ddc3c42710a61..0000000000000 --- a/pandas/tests/io/excel/test_odf.py +++ /dev/null @@ -1,38 +0,0 @@ -import functools - -import numpy as np -import pytest - -import pandas as pd -import pandas._testing as tm - -pytest.importorskip("odf") - - -@pytest.fixture(autouse=True) -def cd_and_set_engine(monkeypatch, datapath): - func = functools.partial(pd.read_excel, engine="odf") - monkeypatch.setattr(pd, "read_excel", func) - monkeypatch.chdir(datapath("io", "data", "excel")) - - -def test_read_invalid_types_raises(): - # the invalid_value_type.ods required manually editing - # of the included content.xml file - with pytest.raises(ValueError, match="Unrecognized type awesome_new_type"): - pd.read_excel("invalid_value_type.ods") - - -def test_read_writer_table(): - # Also test reading tables from an text OpenDocument file - # (.odt) - index = pd.Index(["Row 1", "Row 2", "Row 3"], name="Header") - expected = pd.DataFrame( - [[1, np.nan, 7], [2, np.nan, 8], [3, np.nan, 9]], - index=index, - columns=["Column 1", "Unnamed: 2", "Column 3"], - ) - - result = pd.read_excel("writertable.odt", sheet_name="Table1", index_col=0) - - tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/io/excel/test_odswriter.py b/pandas/tests/io/excel/test_odswriter.py deleted file mode 100644 index 0e6d1dac55506..0000000000000 --- a/pandas/tests/io/excel/test_odswriter.py +++ /dev/null @@ -1,58 +0,0 @@ -import re - -import pytest - -import pandas._testing as tm - -from pandas.io.excel import ExcelWriter - -odf = pytest.importorskip("odf") - -pytestmark = pytest.mark.parametrize("ext", [".ods"]) - - -def test_write_append_mode_raises(ext): - msg = "Append mode is not supported with odf!" - - with tm.ensure_clean(ext) as f: - with pytest.raises(ValueError, match=msg): - ExcelWriter(f, engine="odf", mode="a") - - -def test_kwargs(ext): - # GH 42286 - # GH 43445 - # test for error: OpenDocumentSpreadsheet does not accept any arguments - kwargs = {"kwarg": 1} - with tm.ensure_clean(ext) as f: - msg = re.escape("Use of **kwargs is deprecated") - error = re.escape( - "OpenDocumentSpreadsheet() got an unexpected keyword argument 'kwarg'" - ) - with pytest.raises( - TypeError, - match=error, - ): - with tm.assert_produces_warning(FutureWarning, match=msg): - with ExcelWriter(f, engine="odf", **kwargs) as _: - pass - - -@pytest.mark.parametrize("engine_kwargs", [None, {"kwarg": 1}]) -def test_engine_kwargs(ext, engine_kwargs): - # GH 42286 - # GH 43445 - # test for error: OpenDocumentSpreadsheet does not accept any arguments - with tm.ensure_clean(ext) as f: - if engine_kwargs is not None: - error = re.escape( - "OpenDocumentSpreadsheet() got an unexpected keyword argument 'kwarg'" - ) - with pytest.raises( - TypeError, - match=error, - ): - ExcelWriter(f, engine="odf", engine_kwargs=engine_kwargs) - else: - with ExcelWriter(f, engine="odf", engine_kwargs=engine_kwargs) as _: - pass diff --git a/pandas/tests/io/excel/test_openpyxl.py b/pandas/tests/io/excel/test_openpyxl.py deleted file mode 100644 index e0d4a0c12ecdf..0000000000000 --- a/pandas/tests/io/excel/test_openpyxl.py +++ /dev/null @@ -1,377 +0,0 @@ -from pathlib import Path -import re - -import numpy as np -import pytest - -import pandas as pd -from pandas import DataFrame -import pandas._testing as tm - -from pandas.io.excel import ( - ExcelWriter, - _OpenpyxlWriter, -) - -openpyxl = pytest.importorskip("openpyxl") - -pytestmark = pytest.mark.parametrize("ext", [".xlsx"]) - - -def test_to_excel_styleconverter(ext): - from openpyxl import styles - - hstyle = { - "font": {"color": "00FF0000", "bold": True}, - "borders": {"top": "thin", "right": "thin", "bottom": "thin", "left": "thin"}, - "alignment": {"horizontal": "center", "vertical": "top"}, - "fill": {"patternType": "solid", "fgColor": {"rgb": "006666FF", "tint": 0.3}}, - "number_format": {"format_code": "0.00"}, - "protection": {"locked": True, "hidden": False}, - } - - font_color = styles.Color("00FF0000") - font = styles.Font(bold=True, color=font_color) - side = styles.Side(style=styles.borders.BORDER_THIN) - border = styles.Border(top=side, right=side, bottom=side, left=side) - alignment = styles.Alignment(horizontal="center", vertical="top") - fill_color = styles.Color(rgb="006666FF", tint=0.3) - fill = styles.PatternFill(patternType="solid", fgColor=fill_color) - - number_format = "0.00" - - protection = styles.Protection(locked=True, hidden=False) - - kw = _OpenpyxlWriter._convert_to_style_kwargs(hstyle) - assert kw["font"] == font - assert kw["border"] == border - assert kw["alignment"] == alignment - assert kw["fill"] == fill - assert kw["number_format"] == number_format - assert kw["protection"] == protection - - -def test_write_cells_merge_styled(ext): - from pandas.io.formats.excel import ExcelCell - - sheet_name = "merge_styled" - - sty_b1 = {"font": {"color": "00FF0000"}} - sty_a2 = {"font": {"color": "0000FF00"}} - - initial_cells = [ - ExcelCell(col=1, row=0, val=42, style=sty_b1), - ExcelCell(col=0, row=1, val=99, style=sty_a2), - ] - - sty_merged = {"font": {"color": "000000FF", "bold": True}} - sty_kwargs = _OpenpyxlWriter._convert_to_style_kwargs(sty_merged) - openpyxl_sty_merged = sty_kwargs["font"] - merge_cells = [ - ExcelCell( - col=0, row=0, val="pandas", mergestart=1, mergeend=1, style=sty_merged - ) - ] - - with tm.ensure_clean(ext) as path: - with _OpenpyxlWriter(path) as writer: - writer.write_cells(initial_cells, sheet_name=sheet_name) - writer.write_cells(merge_cells, sheet_name=sheet_name) - - wks = writer.sheets[sheet_name] - xcell_b1 = wks["B1"] - xcell_a2 = wks["A2"] - assert xcell_b1.font == openpyxl_sty_merged - assert xcell_a2.font == openpyxl_sty_merged - - -@pytest.mark.parametrize("iso_dates", [True, False]) -def test_kwargs(ext, iso_dates): - # GH 42286 GH 43445 - kwargs = {"iso_dates": iso_dates} - with tm.ensure_clean(ext) as f: - msg = re.escape("Use of **kwargs is deprecated") - with tm.assert_produces_warning(FutureWarning, match=msg): - with ExcelWriter(f, engine="openpyxl", **kwargs) as writer: - assert writer.book.iso_dates == iso_dates - # ExcelWriter won't allow us to close without writing something - DataFrame().to_excel(writer) - - -@pytest.mark.parametrize("iso_dates", [True, False]) -def test_engine_kwargs_write(ext, iso_dates): - # GH 42286 GH 43445 - engine_kwargs = {"iso_dates": iso_dates} - with tm.ensure_clean(ext) as f: - with ExcelWriter(f, engine="openpyxl", engine_kwargs=engine_kwargs) as writer: - assert writer.book.iso_dates == iso_dates - # ExcelWriter won't allow us to close without writing something - DataFrame().to_excel(writer) - - -def test_engine_kwargs_append_invalid(ext): - # GH 43445 - # test whether an invalid engine kwargs actually raises - with tm.ensure_clean(ext) as f: - DataFrame(["hello", "world"]).to_excel(f) - with pytest.raises( - TypeError, - match=re.escape( - "load_workbook() got an unexpected keyword argument 'apple_banana'" - ), - ): - with ExcelWriter( - f, engine="openpyxl", mode="a", engine_kwargs={"apple_banana": "fruit"} - ) as writer: - # ExcelWriter needs us to write something to close properly - DataFrame(["good"]).to_excel(writer, sheet_name="Sheet2") - - -@pytest.mark.parametrize("data_only, expected", [(True, 0), (False, "=1+1")]) -def test_engine_kwargs_append_data_only(ext, data_only, expected): - # GH 43445 - # tests whether the data_only engine_kwarg actually works well for - # openpyxl's load_workbook - with tm.ensure_clean(ext) as f: - DataFrame(["=1+1"]).to_excel(f) - with ExcelWriter( - f, engine="openpyxl", mode="a", engine_kwargs={"data_only": data_only} - ) as writer: - assert writer.sheets["Sheet1"]["B2"].value == expected - # ExcelWriter needs us to writer something to close properly? - DataFrame().to_excel(writer, sheet_name="Sheet2") - - -@pytest.mark.parametrize( - "mode,expected", [("w", ["baz"]), ("a", ["foo", "bar", "baz"])] -) -def test_write_append_mode(ext, mode, expected): - df = DataFrame([1], columns=["baz"]) - - with tm.ensure_clean(ext) as f: - wb = openpyxl.Workbook() - wb.worksheets[0].title = "foo" - wb.worksheets[0]["A1"].value = "foo" - wb.create_sheet("bar") - wb.worksheets[1]["A1"].value = "bar" - wb.save(f) - - with ExcelWriter(f, engine="openpyxl", mode=mode) as writer: - df.to_excel(writer, sheet_name="baz", index=False) - - wb2 = openpyxl.load_workbook(f) - result = [sheet.title for sheet in wb2.worksheets] - assert result == expected - - for index, cell_value in enumerate(expected): - assert wb2.worksheets[index]["A1"].value == cell_value - - -@pytest.mark.parametrize( - "if_sheet_exists,num_sheets,expected", - [ - ("new", 2, ["apple", "banana"]), - ("replace", 1, ["pear"]), - ("overlay", 1, ["pear", "banana"]), - ], -) -def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected): - # GH 40230 - df1 = DataFrame({"fruit": ["apple", "banana"]}) - df2 = DataFrame({"fruit": ["pear"]}) - - with tm.ensure_clean(ext) as f: - df1.to_excel(f, engine="openpyxl", sheet_name="foo", index=False) - with ExcelWriter( - f, engine="openpyxl", mode="a", if_sheet_exists=if_sheet_exists - ) as writer: - df2.to_excel(writer, sheet_name="foo", index=False) - - wb = openpyxl.load_workbook(f) - assert len(wb.sheetnames) == num_sheets - assert wb.sheetnames[0] == "foo" - result = pd.read_excel(wb, "foo", engine="openpyxl") - assert list(result["fruit"]) == expected - if len(wb.sheetnames) == 2: - result = pd.read_excel(wb, wb.sheetnames[1], engine="openpyxl") - tm.assert_frame_equal(result, df2) - wb.close() - - -@pytest.mark.parametrize( - "startrow, startcol, greeting, goodbye", - [ - (0, 0, ["poop", "world"], ["goodbye", "people"]), - (0, 1, ["hello", "world"], ["poop", "people"]), - (1, 0, ["hello", "poop"], ["goodbye", "people"]), - (1, 1, ["hello", "world"], ["goodbye", "poop"]), - ], -) -def test_append_overlay_startrow_startcol(ext, startrow, startcol, greeting, goodbye): - df1 = DataFrame({"greeting": ["hello", "world"], "goodbye": ["goodbye", "people"]}) - df2 = DataFrame(["poop"]) - - with tm.ensure_clean(ext) as f: - df1.to_excel(f, engine="openpyxl", sheet_name="poo", index=False) - with ExcelWriter( - f, engine="openpyxl", mode="a", if_sheet_exists="overlay" - ) as writer: - # use startrow+1 because we don't have a header - df2.to_excel( - writer, - index=False, - header=False, - startrow=startrow + 1, - startcol=startcol, - sheet_name="poo", - ) - - result = pd.read_excel(f, sheet_name="poo", engine="openpyxl") - expected = DataFrame({"greeting": greeting, "goodbye": goodbye}) - tm.assert_frame_equal(result, expected) - - -@pytest.mark.parametrize( - "if_sheet_exists,msg", - [ - ( - "invalid", - "'invalid' is not valid for if_sheet_exists. Valid options " - "are 'error', 'new', 'replace' and 'overlay'.", - ), - ( - "error", - "Sheet 'foo' already exists and if_sheet_exists is set to 'error'.", - ), - ( - None, - "Sheet 'foo' already exists and if_sheet_exists is set to 'error'.", - ), - ], -) -def test_if_sheet_exists_raises(ext, if_sheet_exists, msg): - # GH 40230 - df = DataFrame({"fruit": ["pear"]}) - with tm.ensure_clean(ext) as f: - with pytest.raises(ValueError, match=re.escape(msg)): - df.to_excel(f, "foo", engine="openpyxl") - with ExcelWriter( - f, engine="openpyxl", mode="a", if_sheet_exists=if_sheet_exists - ) as writer: - df.to_excel(writer, sheet_name="foo") - - -def test_to_excel_with_openpyxl_engine(ext): - # GH 29854 - with tm.ensure_clean(ext) as filename: - - df1 = DataFrame({"A": np.linspace(1, 10, 10)}) - df2 = DataFrame({"B": np.linspace(1, 20, 10)}) - df = pd.concat([df1, df2], axis=1) - styled = df.style.applymap( - lambda val: "color: %s" % ("red" if val < 0 else "black") - ).highlight_max() - - styled.to_excel(filename, engine="openpyxl") - - -@pytest.mark.parametrize("read_only", [True, False]) -def test_read_workbook(datapath, ext, read_only): - # GH 39528 - filename = datapath("io", "data", "excel", "test1" + ext) - wb = openpyxl.load_workbook(filename, read_only=read_only) - result = pd.read_excel(wb, engine="openpyxl") - wb.close() - expected = pd.read_excel(filename) - tm.assert_frame_equal(result, expected) - - -@pytest.mark.parametrize( - "header, expected_data", - [ - ( - 0, - { - "Title": [np.nan, "A", 1, 2, 3], - "Unnamed: 1": [np.nan, "B", 4, 5, 6], - "Unnamed: 2": [np.nan, "C", 7, 8, 9], - }, - ), - (2, {"A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]}), - ], -) -@pytest.mark.parametrize( - "filename", ["dimension_missing", "dimension_small", "dimension_large"] -) -# When read_only is None, use read_excel instead of a workbook -@pytest.mark.parametrize("read_only", [True, False, None]) -def test_read_with_bad_dimension( - datapath, ext, header, expected_data, filename, read_only, request -): - # GH 38956, 39001 - no/incorrect dimension information - path = datapath("io", "data", "excel", f"{filename}{ext}") - if read_only is None: - result = pd.read_excel(path, header=header) - else: - wb = openpyxl.load_workbook(path, read_only=read_only) - result = pd.read_excel(wb, engine="openpyxl", header=header) - wb.close() - expected = DataFrame(expected_data) - tm.assert_frame_equal(result, expected) - - -def test_append_mode_file(ext): - # GH 39576 - df = DataFrame() - - with tm.ensure_clean(ext) as f: - df.to_excel(f, engine="openpyxl") - - with ExcelWriter( - f, mode="a", engine="openpyxl", if_sheet_exists="new" - ) as writer: - df.to_excel(writer) - - # make sure that zip files are not concatenated by making sure that - # "docProps/app.xml" only occurs twice in the file - data = Path(f).read_bytes() - first = data.find(b"docProps/app.xml") - second = data.find(b"docProps/app.xml", first + 1) - third = data.find(b"docProps/app.xml", second + 1) - assert second != -1 and third == -1 - - -# When read_only is None, use read_excel instead of a workbook -@pytest.mark.parametrize("read_only", [True, False, None]) -def test_read_with_empty_trailing_rows(datapath, ext, read_only, request): - # GH 39181 - path = datapath("io", "data", "excel", f"empty_trailing_rows{ext}") - if read_only is None: - result = pd.read_excel(path) - else: - wb = openpyxl.load_workbook(path, read_only=read_only) - result = pd.read_excel(wb, engine="openpyxl") - wb.close() - expected = DataFrame( - { - "Title": [np.nan, "A", 1, 2, 3], - "Unnamed: 1": [np.nan, "B", 4, 5, 6], - "Unnamed: 2": [np.nan, "C", 7, 8, 9], - } - ) - tm.assert_frame_equal(result, expected) - - -# When read_only is None, use read_excel instead of a workbook -@pytest.mark.parametrize("read_only", [True, False, None]) -def test_read_empty_with_blank_row(datapath, ext, read_only): - # GH 39547 - empty excel file with a row that has no data - path = datapath("io", "data", "excel", f"empty_with_blank_row{ext}") - if read_only is None: - result = pd.read_excel(path) - else: - wb = openpyxl.load_workbook(path, read_only=read_only) - result = pd.read_excel(wb, engine="openpyxl") - wb.close() - expected = DataFrame() - tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/io/excel/test_readers.py b/pandas/tests/io/excel/test_readers.py deleted file mode 100644 index 589c98721f139..0000000000000 --- a/pandas/tests/io/excel/test_readers.py +++ /dev/null @@ -1,1579 +0,0 @@ -from datetime import ( - datetime, - time, -) -from functools import partial -import os -from pathlib import Path -from urllib.error import URLError -from zipfile import BadZipFile - -import numpy as np -import pytest - -import pandas.util._test_decorators as td - -import pandas as pd -from pandas import ( - DataFrame, - Index, - MultiIndex, - Series, -) -import pandas._testing as tm -from pandas.tests.io.excel import xlrd_version -from pandas.util.version import Version - -read_ext_params = [".xls", ".xlsx", ".xlsm", ".xlsb", ".ods"] -engine_params = [ - # Add any engines to test here - # When defusedxml is installed it triggers deprecation warnings for - # xlrd and openpyxl, so catch those here - pytest.param( - "xlrd", - marks=[ - td.skip_if_no("xlrd"), - ], - ), - pytest.param( - "openpyxl", - marks=[ - td.skip_if_no("openpyxl"), - pytest.mark.filterwarnings("ignore:.*html argument"), - ], - ), - pytest.param( - None, - marks=[ - td.skip_if_no("xlrd"), - ], - ), - pytest.param("pyxlsb", marks=td.skip_if_no("pyxlsb")), - pytest.param("odf", marks=td.skip_if_no("odf")), -] - - -def _is_valid_engine_ext_pair(engine, read_ext: str) -> bool: - """ - Filter out invalid (engine, ext) pairs instead of skipping, as that - produces 500+ pytest.skips. - """ - engine = engine.values[0] - if engine == "openpyxl" and read_ext == ".xls": - return False - if engine == "odf" and read_ext != ".ods": - return False - if read_ext == ".ods" and engine != "odf": - return False - if engine == "pyxlsb" and read_ext != ".xlsb": - return False - if read_ext == ".xlsb" and engine != "pyxlsb": - return False - if ( - engine == "xlrd" - and xlrd_version is not None - and xlrd_version >= Version("2") - and read_ext != ".xls" - ): - return False - return True - - -def _transfer_marks(engine, read_ext): - """ - engine gives us a pytest.param object with some marks, read_ext is just - a string. We need to generate a new pytest.param inheriting the marks. - """ - values = engine.values + (read_ext,) - new_param = pytest.param(values, marks=engine.marks) - return new_param - - -@pytest.fixture( - params=[ - _transfer_marks(eng, ext) - for eng in engine_params - for ext in read_ext_params - if _is_valid_engine_ext_pair(eng, ext) - ], -) -def engine_and_read_ext(request): - """ - Fixture for Excel reader engine and read_ext, only including valid pairs. - """ - return request.param - - -@pytest.fixture -def engine(engine_and_read_ext): - engine, read_ext = engine_and_read_ext - return engine - - -@pytest.fixture -def read_ext(engine_and_read_ext): - engine, read_ext = engine_and_read_ext - return read_ext - - -class TestReaders: - @pytest.fixture(autouse=True) - def cd_and_set_engine(self, engine, datapath, monkeypatch): - """ - Change directory and set engine for read_excel calls. - """ - func = partial(pd.read_excel, engine=engine) - monkeypatch.chdir(datapath("io", "data", "excel")) - monkeypatch.setattr(pd, "read_excel", func) - - def test_engine_used(self, read_ext, engine, monkeypatch): - # GH 38884 - def parser(self, *args, **kwargs): - return self.engine - - monkeypatch.setattr(pd.ExcelFile, "parse", parser) - - expected_defaults = { - "xlsx": "openpyxl", - "xlsm": "openpyxl", - "xlsb": "pyxlsb", - "xls": "xlrd", - "ods": "odf", - } - - with open("test1" + read_ext, "rb") as f: - result = pd.read_excel(f) - - if engine is not None: - expected = engine - else: - expected = expected_defaults[read_ext[1:]] - assert result == expected - - def test_usecols_int(self, read_ext, df_ref): - df_ref = df_ref.reindex(columns=["A", "B", "C"]) - - # usecols as int - msg = "Passing an integer for `usecols`" - with pytest.raises(ValueError, match=msg): - pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, usecols=3 - ) - - # usecols as int - with pytest.raises(ValueError, match=msg): - pd.read_excel( - "test1" + read_ext, - sheet_name="Sheet2", - skiprows=[1], - index_col=0, - usecols=3, - ) - - def test_usecols_list(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - df_ref = df_ref.reindex(columns=["B", "C"]) - df1 = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, usecols=[0, 2, 3] - ) - df2 = pd.read_excel( - "test1" + read_ext, - sheet_name="Sheet2", - skiprows=[1], - index_col=0, - usecols=[0, 2, 3], - ) - - # TODO add index to xls file) - tm.assert_frame_equal(df1, df_ref, check_names=False) - tm.assert_frame_equal(df2, df_ref, check_names=False) - - def test_usecols_str(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - df1 = df_ref.reindex(columns=["A", "B", "C"]) - df2 = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, usecols="A:D" - ) - df3 = pd.read_excel( - "test1" + read_ext, - sheet_name="Sheet2", - skiprows=[1], - index_col=0, - usecols="A:D", - ) - - # TODO add index to xls, read xls ignores index name ? - tm.assert_frame_equal(df2, df1, check_names=False) - tm.assert_frame_equal(df3, df1, check_names=False) - - df1 = df_ref.reindex(columns=["B", "C"]) - df2 = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, usecols="A,C,D" - ) - df3 = pd.read_excel( - "test1" + read_ext, - sheet_name="Sheet2", - skiprows=[1], - index_col=0, - usecols="A,C,D", - ) - # TODO add index to xls file - tm.assert_frame_equal(df2, df1, check_names=False) - tm.assert_frame_equal(df3, df1, check_names=False) - - df1 = df_ref.reindex(columns=["B", "C"]) - df2 = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, usecols="A,C:D" - ) - df3 = pd.read_excel( - "test1" + read_ext, - sheet_name="Sheet2", - skiprows=[1], - index_col=0, - usecols="A,C:D", - ) - tm.assert_frame_equal(df2, df1, check_names=False) - tm.assert_frame_equal(df3, df1, check_names=False) - - @pytest.mark.parametrize( - "usecols", [[0, 1, 3], [0, 3, 1], [1, 0, 3], [1, 3, 0], [3, 0, 1], [3, 1, 0]] - ) - def test_usecols_diff_positional_int_columns_order( - self, request, read_ext, usecols, df_ref - ): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - expected = df_ref[["A", "C"]] - result = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, usecols=usecols - ) - tm.assert_frame_equal(result, expected, check_names=False) - - @pytest.mark.parametrize("usecols", [["B", "D"], ["D", "B"]]) - def test_usecols_diff_positional_str_columns_order(self, read_ext, usecols, df_ref): - expected = df_ref[["B", "D"]] - expected.index = range(len(expected)) - - result = pd.read_excel("test1" + read_ext, sheet_name="Sheet1", usecols=usecols) - tm.assert_frame_equal(result, expected, check_names=False) - - def test_read_excel_without_slicing(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - expected = df_ref - result = pd.read_excel("test1" + read_ext, sheet_name="Sheet1", index_col=0) - tm.assert_frame_equal(result, expected, check_names=False) - - def test_usecols_excel_range_str(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - expected = df_ref[["C", "D"]] - result = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, usecols="A,D:E" - ) - tm.assert_frame_equal(result, expected, check_names=False) - - def test_usecols_excel_range_str_invalid(self, read_ext): - msg = "Invalid column name: E1" - - with pytest.raises(ValueError, match=msg): - pd.read_excel("test1" + read_ext, sheet_name="Sheet1", usecols="D:E1") - - def test_index_col_label_error(self, read_ext): - msg = "list indices must be integers.*, not str" - - with pytest.raises(TypeError, match=msg): - pd.read_excel( - "test1" + read_ext, - sheet_name="Sheet1", - index_col=["A"], - usecols=["A", "C"], - ) - - def test_index_col_empty(self, read_ext): - # see gh-9208 - result = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet3", index_col=["A", "B", "C"] - ) - expected = DataFrame( - columns=["D", "E", "F"], - index=MultiIndex(levels=[[]] * 3, codes=[[]] * 3, names=["A", "B", "C"]), - ) - tm.assert_frame_equal(result, expected) - - @pytest.mark.parametrize("index_col", [None, 2]) - def test_index_col_with_unnamed(self, read_ext, index_col): - # see gh-18792 - result = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet4", index_col=index_col - ) - expected = DataFrame( - [["i1", "a", "x"], ["i2", "b", "y"]], columns=["Unnamed: 0", "col1", "col2"] - ) - if index_col: - expected = expected.set_index(expected.columns[index_col]) - - tm.assert_frame_equal(result, expected) - - def test_usecols_pass_non_existent_column(self, read_ext): - msg = ( - "Usecols do not match columns, " - "columns expected but not found: " + r"\['E'\]" - ) - - with pytest.raises(ValueError, match=msg): - pd.read_excel("test1" + read_ext, usecols=["E"]) - - def test_usecols_wrong_type(self, read_ext): - msg = ( - "'usecols' must either be list-like of " - "all strings, all unicode, all integers or a callable." - ) - - with pytest.raises(ValueError, match=msg): - pd.read_excel("test1" + read_ext, usecols=["E1", 0]) - - def test_excel_stop_iterator(self, read_ext): - - parsed = pd.read_excel("test2" + read_ext, sheet_name="Sheet1") - expected = DataFrame([["aaaa", "bbbbb"]], columns=["Test", "Test1"]) - tm.assert_frame_equal(parsed, expected) - - def test_excel_cell_error_na(self, request, read_ext): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - parsed = pd.read_excel("test3" + read_ext, sheet_name="Sheet1") - expected = DataFrame([[np.nan]], columns=["Test"]) - tm.assert_frame_equal(parsed, expected) - - def test_excel_table(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - df1 = pd.read_excel("test1" + read_ext, sheet_name="Sheet1", index_col=0) - df2 = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet2", skiprows=[1], index_col=0 - ) - # TODO add index to file - tm.assert_frame_equal(df1, df_ref, check_names=False) - tm.assert_frame_equal(df2, df_ref, check_names=False) - - df3 = pd.read_excel( - "test1" + read_ext, sheet_name="Sheet1", index_col=0, skipfooter=1 - ) - tm.assert_frame_equal(df3, df1.iloc[:-1]) - - def test_reader_special_dtypes(self, request, read_ext): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - expected = DataFrame.from_dict( - { - "IntCol": [1, 2, -3, 4, 0], - "FloatCol": [1.25, 2.25, 1.83, 1.92, 0.0000000005], - "BoolCol": [True, False, True, True, False], - "StrCol": [1, 2, 3, 4, 5], - # GH5394 - this is why convert_float isn't vectorized - "Str2Col": ["a", 3, "c", "d", "e"], - "DateCol": [ - datetime(2013, 10, 30), - datetime(2013, 10, 31), - datetime(1905, 1, 1), - datetime(2013, 12, 14), - datetime(2015, 3, 14), - ], - }, - ) - basename = "test_types" - - # should read in correctly and infer types - actual = pd.read_excel(basename + read_ext, sheet_name="Sheet1") - tm.assert_frame_equal(actual, expected) - - # if not coercing number, then int comes in as float - float_expected = expected.copy() - float_expected["IntCol"] = float_expected["IntCol"].astype(float) - float_expected.loc[float_expected.index[1], "Str2Col"] = 3.0 - with tm.assert_produces_warning( - FutureWarning, - match="convert_float is deprecated", - raise_on_extra_warnings=False, - ): - # raise_on_extra_warnings because xlrd raises a PendingDeprecationWarning - # on database job Linux_py37_IO (ci/deps/actions-37-db.yaml) - # See GH#41176 - actual = pd.read_excel( - basename + read_ext, sheet_name="Sheet1", convert_float=False - ) - tm.assert_frame_equal(actual, float_expected) - - # check setting Index (assuming xls and xlsx are the same here) - for icol, name in enumerate(expected.columns): - actual = pd.read_excel( - basename + read_ext, sheet_name="Sheet1", index_col=icol - ) - exp = expected.set_index(name) - tm.assert_frame_equal(actual, exp) - - # convert_float and converters should be different but both accepted - expected["StrCol"] = expected["StrCol"].apply(str) - actual = pd.read_excel( - basename + read_ext, sheet_name="Sheet1", converters={"StrCol": str} - ) - tm.assert_frame_equal(actual, expected) - - no_convert_float = float_expected.copy() - no_convert_float["StrCol"] = no_convert_float["StrCol"].apply(str) - with tm.assert_produces_warning( - FutureWarning, - match="convert_float is deprecated", - raise_on_extra_warnings=False, - ): - # raise_on_extra_warnings because xlrd raises a PendingDeprecationWarning - # on database job Linux_py37_IO (ci/deps/actions-37-db.yaml) - # See GH#41176 - actual = pd.read_excel( - basename + read_ext, - sheet_name="Sheet1", - convert_float=False, - converters={"StrCol": str}, - ) - tm.assert_frame_equal(actual, no_convert_float) - - # GH8212 - support for converters and missing values - def test_reader_converters(self, read_ext): - - basename = "test_converters" - - expected = DataFrame.from_dict( - { - "IntCol": [1, 2, -3, -1000, 0], - "FloatCol": [12.5, np.nan, 18.3, 19.2, 0.000000005], - "BoolCol": ["Found", "Found", "Found", "Not found", "Found"], - "StrCol": ["1", np.nan, "3", "4", "5"], - } - ) - - converters = { - "IntCol": lambda x: int(x) if x != "" else -1000, - "FloatCol": lambda x: 10 * x if x else np.nan, - 2: lambda x: "Found" if x != "" else "Not found", - 3: lambda x: str(x) if x else "", - } - - # should read in correctly and set types of single cells (not array - # dtypes) - actual = pd.read_excel( - basename + read_ext, sheet_name="Sheet1", converters=converters - ) - tm.assert_frame_equal(actual, expected) - - def test_reader_dtype(self, read_ext): - # GH 8212 - basename = "testdtype" - actual = pd.read_excel(basename + read_ext) - - expected = DataFrame( - { - "a": [1, 2, 3, 4], - "b": [2.5, 3.5, 4.5, 5.5], - "c": [1, 2, 3, 4], - "d": [1.0, 2.0, np.nan, 4.0], - } - ).reindex(columns=["a", "b", "c", "d"]) - - tm.assert_frame_equal(actual, expected) - - actual = pd.read_excel( - basename + read_ext, dtype={"a": "float64", "b": "float32", "c": str} - ) - - expected["a"] = expected["a"].astype("float64") - expected["b"] = expected["b"].astype("float32") - expected["c"] = ["001", "002", "003", "004"] - tm.assert_frame_equal(actual, expected) - - msg = "Unable to convert column d to type int64" - with pytest.raises(ValueError, match=msg): - pd.read_excel(basename + read_ext, dtype={"d": "int64"}) - - @pytest.mark.parametrize( - "dtype,expected", - [ - ( - None, - DataFrame( - { - "a": [1, 2, 3, 4], - "b": [2.5, 3.5, 4.5, 5.5], - "c": [1, 2, 3, 4], - "d": [1.0, 2.0, np.nan, 4.0], - } - ), - ), - ( - {"a": "float64", "b": "float32", "c": str, "d": str}, - DataFrame( - { - "a": Series([1, 2, 3, 4], dtype="float64"), - "b": Series([2.5, 3.5, 4.5, 5.5], dtype="float32"), - "c": ["001", "002", "003", "004"], - "d": ["1", "2", np.nan, "4"], - } - ), - ), - ], - ) - def test_reader_dtype_str(self, read_ext, dtype, expected): - # see gh-20377 - basename = "testdtype" - - actual = pd.read_excel(basename + read_ext, dtype=dtype) - tm.assert_frame_equal(actual, expected) - - @pytest.mark.parametrize("dtypes, exp_value", [({}, "1"), ({"a.1": "int64"}, 1)]) - def test_dtype_mangle_dup_cols(self, read_ext, dtypes, exp_value): - # GH#35211 - basename = "df_mangle_dup_col_dtypes" - dtype_dict = {"a": str, **dtypes} - dtype_dict_copy = dtype_dict.copy() - # GH#42462 - result = pd.read_excel(basename + read_ext, dtype=dtype_dict) - expected = DataFrame({"a": ["1"], "a.1": [exp_value]}) - assert dtype_dict == dtype_dict_copy, "dtype dict changed" - tm.assert_frame_equal(result, expected) - - def test_reader_spaces(self, read_ext): - # see gh-32207 - basename = "test_spaces" - - actual = pd.read_excel(basename + read_ext) - expected = DataFrame( - { - "testcol": [ - "this is great", - "4 spaces", - "1 trailing ", - " 1 leading", - "2 spaces multiple times", - ] - } - ) - tm.assert_frame_equal(actual, expected) - - # gh-36122, gh-35802 - @pytest.mark.parametrize( - "basename,expected", - [ - ("gh-35802", DataFrame({"COLUMN": ["Test (1)"]})), - ("gh-36122", DataFrame(columns=["got 2nd sa"])), - ], - ) - def test_read_excel_ods_nested_xml(self, engine, read_ext, basename, expected): - # see gh-35802 - if engine != "odf": - pytest.skip(f"Skipped for engine: {engine}") - - actual = pd.read_excel(basename + read_ext) - tm.assert_frame_equal(actual, expected) - - def test_reading_all_sheets(self, read_ext): - # Test reading all sheet names by setting sheet_name to None, - # Ensure a dict is returned. - # See PR #9450 - basename = "test_multisheet" - dfs = pd.read_excel(basename + read_ext, sheet_name=None) - # ensure this is not alphabetical to test order preservation - expected_keys = ["Charlie", "Alpha", "Beta"] - tm.assert_contains_all(expected_keys, dfs.keys()) - # Issue 9930 - # Ensure sheet order is preserved - assert expected_keys == list(dfs.keys()) - - def test_reading_multiple_specific_sheets(self, read_ext): - # Test reading specific sheet names by specifying a mixed list - # of integers and strings, and confirm that duplicated sheet - # references (positions/names) are removed properly. - # Ensure a dict is returned - # See PR #9450 - basename = "test_multisheet" - # Explicitly request duplicates. Only the set should be returned. - expected_keys = [2, "Charlie", "Charlie"] - dfs = pd.read_excel(basename + read_ext, sheet_name=expected_keys) - expected_keys = list(set(expected_keys)) - tm.assert_contains_all(expected_keys, dfs.keys()) - assert len(expected_keys) == len(dfs.keys()) - - def test_reading_all_sheets_with_blank(self, read_ext): - # Test reading all sheet names by setting sheet_name to None, - # In the case where some sheets are blank. - # Issue #11711 - basename = "blank_with_header" - dfs = pd.read_excel(basename + read_ext, sheet_name=None) - expected_keys = ["Sheet1", "Sheet2", "Sheet3"] - tm.assert_contains_all(expected_keys, dfs.keys()) - - # GH6403 - def test_read_excel_blank(self, read_ext): - actual = pd.read_excel("blank" + read_ext, sheet_name="Sheet1") - tm.assert_frame_equal(actual, DataFrame()) - - def test_read_excel_blank_with_header(self, read_ext): - expected = DataFrame(columns=["col_1", "col_2"]) - actual = pd.read_excel("blank_with_header" + read_ext, sheet_name="Sheet1") - tm.assert_frame_equal(actual, expected) - - def test_date_conversion_overflow(self, request, engine, read_ext): - # GH 10001 : pandas.ExcelFile ignore parse_dates=False - if engine == "pyxlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - expected = DataFrame( - [ - [pd.Timestamp("2016-03-12"), "Marc Johnson"], - [pd.Timestamp("2016-03-16"), "Jack Black"], - [1e20, "Timothy Brown"], - ], - columns=["DateColWithBigInt", "StringCol"], - ) - - if engine == "openpyxl": - request.node.add_marker( - pytest.mark.xfail(reason="Maybe not supported by openpyxl") - ) - - if engine is None and read_ext in (".xlsx", ".xlsm"): - # GH 35029 - request.node.add_marker( - pytest.mark.xfail(reason="Defaults to openpyxl, maybe not supported") - ) - - result = pd.read_excel("testdateoverflow" + read_ext) - tm.assert_frame_equal(result, expected) - - def test_sheet_name(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - filename = "test1" - sheet_name = "Sheet1" - - df1 = pd.read_excel( - filename + read_ext, sheet_name=sheet_name, index_col=0 - ) # doc - df2 = pd.read_excel(filename + read_ext, index_col=0, sheet_name=sheet_name) - - tm.assert_frame_equal(df1, df_ref, check_names=False) - tm.assert_frame_equal(df2, df_ref, check_names=False) - - def test_excel_read_buffer(self, read_ext): - - pth = "test1" + read_ext - expected = pd.read_excel(pth, sheet_name="Sheet1", index_col=0) - with open(pth, "rb") as f: - actual = pd.read_excel(f, sheet_name="Sheet1", index_col=0) - tm.assert_frame_equal(expected, actual) - - def test_bad_engine_raises(self, read_ext): - bad_engine = "foo" - with pytest.raises(ValueError, match="Unknown engine: foo"): - pd.read_excel("", engine=bad_engine) - - @pytest.mark.parametrize( - "sheet_name", - [3, [0, 3], [3, 0], "Sheet4", ["Sheet1", "Sheet4"], ["Sheet4", "Sheet1"]], - ) - def test_bad_sheetname_raises(self, read_ext, sheet_name): - # GH 39250 - msg = "Worksheet index 3 is invalid|Worksheet named 'Sheet4' not found" - with pytest.raises(ValueError, match=msg): - pd.read_excel("blank" + read_ext, sheet_name=sheet_name) - - def test_missing_file_raises(self, read_ext): - bad_file = f"foo{read_ext}" - # CI tests with other languages, translates to "No such file or directory" - match = r"(No such file or directory|没有那个文件或目录|File o directory non esistente)" - with pytest.raises(FileNotFoundError, match=match): - pd.read_excel(bad_file) - - def test_corrupt_bytes_raises(self, read_ext, engine): - bad_stream = b"foo" - if engine is None: - error = ValueError - msg = ( - "Excel file format cannot be determined, you must " - "specify an engine manually." - ) - elif engine == "xlrd": - from xlrd import XLRDError - - error = XLRDError - msg = ( - "Unsupported format, or corrupt file: Expected BOF " - "record; found b'foo'" - ) - else: - error = BadZipFile - msg = "File is not a zip file" - with pytest.raises(error, match=msg): - pd.read_excel(bad_stream) - - @tm.network - def test_read_from_http_url(self, read_ext): - url = ( - "https://raw.githubusercontent.com/pandas-dev/pandas/main/" - "pandas/tests/io/data/excel/test1" + read_ext - ) - url_table = pd.read_excel(url) - local_table = pd.read_excel("test1" + read_ext) - tm.assert_frame_equal(url_table, local_table) - - @td.skip_if_not_us_locale - def test_read_from_s3_url(self, read_ext, s3_resource, s3so): - # Bucket "pandas-test" created in tests/io/conftest.py - with open("test1" + read_ext, "rb") as f: - s3_resource.Bucket("pandas-test").put_object(Key="test1" + read_ext, Body=f) - - url = "s3://pandas-test/test1" + read_ext - - url_table = pd.read_excel(url, storage_options=s3so) - local_table = pd.read_excel("test1" + read_ext) - tm.assert_frame_equal(url_table, local_table) - - def test_read_from_s3_object(self, read_ext, s3_resource, s3so): - # GH 38788 - # Bucket "pandas-test" created in tests/io/conftest.py - with open("test1" + read_ext, "rb") as f: - s3_resource.Bucket("pandas-test").put_object(Key="test1" + read_ext, Body=f) - - import s3fs - - s3 = s3fs.S3FileSystem(**s3so) - - with s3.open("s3://pandas-test/test1" + read_ext) as f: - url_table = pd.read_excel(f) - - local_table = pd.read_excel("test1" + read_ext) - tm.assert_frame_equal(url_table, local_table) - - @pytest.mark.slow - def test_read_from_file_url(self, read_ext, datapath): - - # FILE - localtable = os.path.join(datapath("io", "data", "excel"), "test1" + read_ext) - local_table = pd.read_excel(localtable) - - try: - url_table = pd.read_excel("file://localhost/" + localtable) - except URLError: - # fails on some systems - import platform - - platform_info = " ".join(platform.uname()).strip() - pytest.skip(f"failing on {platform_info}") - - tm.assert_frame_equal(url_table, local_table) - - def test_read_from_pathlib_path(self, read_ext): - - # GH12655 - from pathlib import Path - - str_path = "test1" + read_ext - expected = pd.read_excel(str_path, sheet_name="Sheet1", index_col=0) - - path_obj = Path("test1" + read_ext) - actual = pd.read_excel(path_obj, sheet_name="Sheet1", index_col=0) - - tm.assert_frame_equal(expected, actual) - - @td.skip_if_no("py.path") - @td.check_file_leaks - def test_read_from_py_localpath(self, read_ext): - - # GH12655 - from py.path import local as LocalPath - - str_path = os.path.join("test1" + read_ext) - expected = pd.read_excel(str_path, sheet_name="Sheet1", index_col=0) - - path_obj = LocalPath().join("test1" + read_ext) - actual = pd.read_excel(path_obj, sheet_name="Sheet1", index_col=0) - - tm.assert_frame_equal(expected, actual) - - @td.check_file_leaks - def test_close_from_py_localpath(self, read_ext): - - # GH31467 - str_path = os.path.join("test1" + read_ext) - with open(str_path, "rb") as f: - x = pd.read_excel(f, sheet_name="Sheet1", index_col=0) - del x - # should not throw an exception because the passed file was closed - f.read() - - def test_reader_seconds(self, request, engine, read_ext): - if engine == "pyxlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - # Test reading times with and without milliseconds. GH5945. - expected = DataFrame.from_dict( - { - "Time": [ - time(1, 2, 3), - time(2, 45, 56, 100000), - time(4, 29, 49, 200000), - time(6, 13, 42, 300000), - time(7, 57, 35, 400000), - time(9, 41, 28, 500000), - time(11, 25, 21, 600000), - time(13, 9, 14, 700000), - time(14, 53, 7, 800000), - time(16, 37, 0, 900000), - time(18, 20, 54), - ] - } - ) - - actual = pd.read_excel("times_1900" + read_ext, sheet_name="Sheet1") - tm.assert_frame_equal(actual, expected) - - actual = pd.read_excel("times_1904" + read_ext, sheet_name="Sheet1") - tm.assert_frame_equal(actual, expected) - - def test_read_excel_multiindex(self, request, read_ext): - # see gh-4679 - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - mi = MultiIndex.from_product([["foo", "bar"], ["a", "b"]]) - mi_file = "testmultiindex" + read_ext - - # "mi_column" sheet - expected = DataFrame( - [ - [1, 2.5, pd.Timestamp("2015-01-01"), True], - [2, 3.5, pd.Timestamp("2015-01-02"), False], - [3, 4.5, pd.Timestamp("2015-01-03"), False], - [4, 5.5, pd.Timestamp("2015-01-04"), True], - ], - columns=mi, - ) - - actual = pd.read_excel( - mi_file, sheet_name="mi_column", header=[0, 1], index_col=0 - ) - tm.assert_frame_equal(actual, expected) - - # "mi_index" sheet - expected.index = mi - expected.columns = ["a", "b", "c", "d"] - - actual = pd.read_excel(mi_file, sheet_name="mi_index", index_col=[0, 1]) - tm.assert_frame_equal(actual, expected, check_names=False) - - # "both" sheet - expected.columns = mi - - actual = pd.read_excel( - mi_file, sheet_name="both", index_col=[0, 1], header=[0, 1] - ) - tm.assert_frame_equal(actual, expected, check_names=False) - - # "mi_index_name" sheet - expected.columns = ["a", "b", "c", "d"] - expected.index = mi.set_names(["ilvl1", "ilvl2"]) - - actual = pd.read_excel(mi_file, sheet_name="mi_index_name", index_col=[0, 1]) - tm.assert_frame_equal(actual, expected) - - # "mi_column_name" sheet - expected.index = list(range(4)) - expected.columns = mi.set_names(["c1", "c2"]) - actual = pd.read_excel( - mi_file, sheet_name="mi_column_name", header=[0, 1], index_col=0 - ) - tm.assert_frame_equal(actual, expected) - - # see gh-11317 - # "name_with_int" sheet - expected.columns = mi.set_levels([1, 2], level=1).set_names(["c1", "c2"]) - - actual = pd.read_excel( - mi_file, sheet_name="name_with_int", index_col=0, header=[0, 1] - ) - tm.assert_frame_equal(actual, expected) - - # "both_name" sheet - expected.columns = mi.set_names(["c1", "c2"]) - expected.index = mi.set_names(["ilvl1", "ilvl2"]) - - actual = pd.read_excel( - mi_file, sheet_name="both_name", index_col=[0, 1], header=[0, 1] - ) - tm.assert_frame_equal(actual, expected) - - # "both_skiprows" sheet - actual = pd.read_excel( - mi_file, - sheet_name="both_name_skiprows", - index_col=[0, 1], - header=[0, 1], - skiprows=2, - ) - tm.assert_frame_equal(actual, expected) - - @pytest.mark.parametrize( - "sheet_name,idx_lvl2", - [ - ("both_name_blank_after_mi_name", [np.nan, "b", "a", "b"]), - ("both_name_multiple_blanks", [np.nan] * 4), - ], - ) - def test_read_excel_multiindex_blank_after_name( - self, request, read_ext, sheet_name, idx_lvl2 - ): - # GH34673 - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb (GH4679" - ) - ) - - mi_file = "testmultiindex" + read_ext - mi = MultiIndex.from_product([["foo", "bar"], ["a", "b"]], names=["c1", "c2"]) - expected = DataFrame( - [ - [1, 2.5, pd.Timestamp("2015-01-01"), True], - [2, 3.5, pd.Timestamp("2015-01-02"), False], - [3, 4.5, pd.Timestamp("2015-01-03"), False], - [4, 5.5, pd.Timestamp("2015-01-04"), True], - ], - columns=mi, - index=MultiIndex.from_arrays( - (["foo", "foo", "bar", "bar"], idx_lvl2), - names=["ilvl1", "ilvl2"], - ), - ) - result = pd.read_excel( - mi_file, - sheet_name=sheet_name, - index_col=[0, 1], - header=[0, 1], - ) - tm.assert_frame_equal(result, expected) - - def test_read_excel_multiindex_header_only(self, read_ext): - # see gh-11733. - # - # Don't try to parse a header name if there isn't one. - mi_file = "testmultiindex" + read_ext - result = pd.read_excel(mi_file, sheet_name="index_col_none", header=[0, 1]) - - exp_columns = MultiIndex.from_product([("A", "B"), ("key", "val")]) - expected = DataFrame([[1, 2, 3, 4]] * 2, columns=exp_columns) - tm.assert_frame_equal(result, expected) - - def test_excel_old_index_format(self, read_ext): - # see gh-4679 - filename = "test_index_name_pre17" + read_ext - - # We detect headers to determine if index names exist, so - # that "index" name in the "names" version of the data will - # now be interpreted as rows that include null data. - data = np.array( - [ - [None, None, None, None, None], - ["R0C0", "R0C1", "R0C2", "R0C3", "R0C4"], - ["R1C0", "R1C1", "R1C2", "R1C3", "R1C4"], - ["R2C0", "R2C1", "R2C2", "R2C3", "R2C4"], - ["R3C0", "R3C1", "R3C2", "R3C3", "R3C4"], - ["R4C0", "R4C1", "R4C2", "R4C3", "R4C4"], - ] - ) - columns = ["C_l0_g0", "C_l0_g1", "C_l0_g2", "C_l0_g3", "C_l0_g4"] - mi = MultiIndex( - levels=[ - ["R0", "R_l0_g0", "R_l0_g1", "R_l0_g2", "R_l0_g3", "R_l0_g4"], - ["R1", "R_l1_g0", "R_l1_g1", "R_l1_g2", "R_l1_g3", "R_l1_g4"], - ], - codes=[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], - names=[None, None], - ) - si = Index( - ["R0", "R_l0_g0", "R_l0_g1", "R_l0_g2", "R_l0_g3", "R_l0_g4"], name=None - ) - - expected = DataFrame(data, index=si, columns=columns) - - actual = pd.read_excel(filename, sheet_name="single_names", index_col=0) - tm.assert_frame_equal(actual, expected) - - expected.index = mi - - actual = pd.read_excel(filename, sheet_name="multi_names", index_col=[0, 1]) - tm.assert_frame_equal(actual, expected) - - # The analogous versions of the "names" version data - # where there are explicitly no names for the indices. - data = np.array( - [ - ["R0C0", "R0C1", "R0C2", "R0C3", "R0C4"], - ["R1C0", "R1C1", "R1C2", "R1C3", "R1C4"], - ["R2C0", "R2C1", "R2C2", "R2C3", "R2C4"], - ["R3C0", "R3C1", "R3C2", "R3C3", "R3C4"], - ["R4C0", "R4C1", "R4C2", "R4C3", "R4C4"], - ] - ) - columns = ["C_l0_g0", "C_l0_g1", "C_l0_g2", "C_l0_g3", "C_l0_g4"] - mi = MultiIndex( - levels=[ - ["R_l0_g0", "R_l0_g1", "R_l0_g2", "R_l0_g3", "R_l0_g4"], - ["R_l1_g0", "R_l1_g1", "R_l1_g2", "R_l1_g3", "R_l1_g4"], - ], - codes=[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], - names=[None, None], - ) - si = Index(["R_l0_g0", "R_l0_g1", "R_l0_g2", "R_l0_g3", "R_l0_g4"], name=None) - - expected = DataFrame(data, index=si, columns=columns) - - actual = pd.read_excel(filename, sheet_name="single_no_names", index_col=0) - tm.assert_frame_equal(actual, expected) - - expected.index = mi - - actual = pd.read_excel(filename, sheet_name="multi_no_names", index_col=[0, 1]) - tm.assert_frame_equal(actual, expected, check_names=False) - - def test_read_excel_bool_header_arg(self, read_ext): - # GH 6114 - msg = "Passing a bool to header is invalid" - for arg in [True, False]: - with pytest.raises(TypeError, match=msg): - pd.read_excel("test1" + read_ext, header=arg) - - def test_read_excel_skiprows(self, request, read_ext): - # GH 4903 - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - actual = pd.read_excel( - "testskiprows" + read_ext, sheet_name="skiprows_list", skiprows=[0, 2] - ) - expected = DataFrame( - [ - [1, 2.5, pd.Timestamp("2015-01-01"), True], - [2, 3.5, pd.Timestamp("2015-01-02"), False], - [3, 4.5, pd.Timestamp("2015-01-03"), False], - [4, 5.5, pd.Timestamp("2015-01-04"), True], - ], - columns=["a", "b", "c", "d"], - ) - tm.assert_frame_equal(actual, expected) - - actual = pd.read_excel( - "testskiprows" + read_ext, - sheet_name="skiprows_list", - skiprows=np.array([0, 2]), - ) - tm.assert_frame_equal(actual, expected) - - # GH36435 - actual = pd.read_excel( - "testskiprows" + read_ext, - sheet_name="skiprows_list", - skiprows=lambda x: x in [0, 2], - ) - tm.assert_frame_equal(actual, expected) - - actual = pd.read_excel( - "testskiprows" + read_ext, - sheet_name="skiprows_list", - skiprows=3, - names=["a", "b", "c", "d"], - ) - expected = DataFrame( - [ - # [1, 2.5, pd.Timestamp("2015-01-01"), True], - [2, 3.5, pd.Timestamp("2015-01-02"), False], - [3, 4.5, pd.Timestamp("2015-01-03"), False], - [4, 5.5, pd.Timestamp("2015-01-04"), True], - ], - columns=["a", "b", "c", "d"], - ) - tm.assert_frame_equal(actual, expected) - - def test_read_excel_nrows(self, read_ext): - # GH 16645 - num_rows_to_pull = 5 - actual = pd.read_excel("test1" + read_ext, nrows=num_rows_to_pull) - expected = pd.read_excel("test1" + read_ext) - expected = expected[:num_rows_to_pull] - tm.assert_frame_equal(actual, expected) - - def test_read_excel_nrows_greater_than_nrows_in_file(self, read_ext): - # GH 16645 - expected = pd.read_excel("test1" + read_ext) - num_records_in_file = len(expected) - num_rows_to_pull = num_records_in_file + 10 - actual = pd.read_excel("test1" + read_ext, nrows=num_rows_to_pull) - tm.assert_frame_equal(actual, expected) - - def test_read_excel_nrows_non_integer_parameter(self, read_ext): - # GH 16645 - msg = "'nrows' must be an integer >=0" - with pytest.raises(ValueError, match=msg): - pd.read_excel("test1" + read_ext, nrows="5") - - def test_read_excel_squeeze(self, read_ext): - # GH 12157 - f = "test_squeeze" + read_ext - - with tm.assert_produces_warning( - FutureWarning, - match="The squeeze argument has been deprecated " - "and will be removed in a future version. " - 'Append .squeeze\\("columns"\\) to the call to squeeze.\n\n', - ): - actual = pd.read_excel( - f, sheet_name="two_columns", index_col=0, squeeze=True - ) - expected = Series([2, 3, 4], [4, 5, 6], name="b") - expected.index.name = "a" - tm.assert_series_equal(actual, expected) - - actual = pd.read_excel(f, sheet_name="two_columns", squeeze=True) - expected = DataFrame({"a": [4, 5, 6], "b": [2, 3, 4]}) - tm.assert_frame_equal(actual, expected) - - actual = pd.read_excel(f, sheet_name="one_column", squeeze=True) - expected = Series([1, 2, 3], name="a") - tm.assert_series_equal(actual, expected) - - def test_deprecated_kwargs(self, read_ext): - with tm.assert_produces_warning(FutureWarning, raise_on_extra_warnings=False): - pd.read_excel("test1" + read_ext, "Sheet1", 0) - - pd.read_excel("test1" + read_ext) - - def test_no_header_with_list_index_col(self, read_ext): - # GH 31783 - file_name = "testmultiindex" + read_ext - data = [("B", "B"), ("key", "val"), (3, 4), (3, 4)] - idx = MultiIndex.from_tuples( - [("A", "A"), ("key", "val"), (1, 2), (1, 2)], names=(0, 1) - ) - expected = DataFrame(data, index=idx, columns=(2, 3)) - result = pd.read_excel( - file_name, sheet_name="index_col_none", index_col=[0, 1], header=None - ) - tm.assert_frame_equal(expected, result) - - def test_one_col_noskip_blank_line(self, read_ext): - # GH 39808 - file_name = "one_col_blank_line" + read_ext - data = [0.5, np.nan, 1, 2] - expected = DataFrame(data, columns=["numbers"]) - result = pd.read_excel(file_name) - tm.assert_frame_equal(result, expected) - - def test_multiheader_two_blank_lines(self, read_ext): - # GH 40442 - file_name = "testmultiindex" + read_ext - columns = MultiIndex.from_tuples([("a", "A"), ("b", "B")]) - data = [[np.nan, np.nan], [np.nan, np.nan], [1, 3], [2, 4]] - expected = DataFrame(data, columns=columns) - result = pd.read_excel( - file_name, sheet_name="mi_column_empty_rows", header=[0, 1] - ) - tm.assert_frame_equal(result, expected) - - def test_trailing_blanks(self, read_ext): - """ - Sheets can contain blank cells with no data. Some of our readers - were including those cells, creating many empty rows and columns - """ - file_name = "trailing_blanks" + read_ext - result = pd.read_excel(file_name) - assert result.shape == (3, 3) - - def test_ignore_chartsheets_by_str(self, request, engine, read_ext): - # GH 41448 - if engine == "odf": - pytest.skip("chartsheets do not exist in the ODF format") - if engine == "pyxlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="pyxlsb can't distinguish chartsheets from worksheets" - ) - ) - with pytest.raises(ValueError, match="Worksheet named 'Chart1' not found"): - pd.read_excel("chartsheet" + read_ext, sheet_name="Chart1") - - def test_ignore_chartsheets_by_int(self, request, engine, read_ext): - # GH 41448 - if engine == "odf": - pytest.skip("chartsheets do not exist in the ODF format") - if engine == "pyxlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="pyxlsb can't distinguish chartsheets from worksheets" - ) - ) - with pytest.raises( - ValueError, match="Worksheet index 1 is invalid, 1 worksheets found" - ): - pd.read_excel("chartsheet" + read_ext, sheet_name=1) - - def test_euro_decimal_format(self, request, read_ext): - # copied from read_csv - result = pd.read_excel("test_decimal" + read_ext, decimal=",", skiprows=1) - expected = DataFrame( - [ - [1, 1521.1541, 187101.9543, "ABC", "poi", 4.738797819], - [2, 121.12, 14897.76, "DEF", "uyt", 0.377320872], - [3, 878.158, 108013.434, "GHI", "rez", 2.735694704], - ], - columns=["Id", "Number1", "Number2", "Text1", "Text2", "Number3"], - ) - tm.assert_frame_equal(result, expected) - - -class TestExcelFileRead: - @pytest.fixture(autouse=True) - def cd_and_set_engine(self, engine, datapath, monkeypatch): - """ - Change directory and set engine for ExcelFile objects. - """ - func = partial(pd.ExcelFile, engine=engine) - monkeypatch.chdir(datapath("io", "data", "excel")) - monkeypatch.setattr(pd, "ExcelFile", func) - - def test_engine_used(self, read_ext, engine, monkeypatch): - expected_defaults = { - "xlsx": "openpyxl", - "xlsm": "openpyxl", - "xlsb": "pyxlsb", - "xls": "xlrd", - "ods": "odf", - } - - with pd.ExcelFile("test1" + read_ext) as excel: - result = excel.engine - - if engine is not None: - expected = engine - else: - expected = expected_defaults[read_ext[1:]] - assert result == expected - - def test_excel_passes_na(self, read_ext): - with pd.ExcelFile("test4" + read_ext) as excel: - parsed = pd.read_excel( - excel, sheet_name="Sheet1", keep_default_na=False, na_values=["apple"] - ) - expected = DataFrame( - [["NA"], [1], ["NA"], [np.nan], ["rabbit"]], columns=["Test"] - ) - tm.assert_frame_equal(parsed, expected) - - with pd.ExcelFile("test4" + read_ext) as excel: - parsed = pd.read_excel( - excel, sheet_name="Sheet1", keep_default_na=True, na_values=["apple"] - ) - expected = DataFrame( - [[np.nan], [1], [np.nan], [np.nan], ["rabbit"]], columns=["Test"] - ) - tm.assert_frame_equal(parsed, expected) - - # 13967 - with pd.ExcelFile("test5" + read_ext) as excel: - parsed = pd.read_excel( - excel, sheet_name="Sheet1", keep_default_na=False, na_values=["apple"] - ) - expected = DataFrame( - [["1.#QNAN"], [1], ["nan"], [np.nan], ["rabbit"]], columns=["Test"] - ) - tm.assert_frame_equal(parsed, expected) - - with pd.ExcelFile("test5" + read_ext) as excel: - parsed = pd.read_excel( - excel, sheet_name="Sheet1", keep_default_na=True, na_values=["apple"] - ) - expected = DataFrame( - [[np.nan], [1], [np.nan], [np.nan], ["rabbit"]], columns=["Test"] - ) - tm.assert_frame_equal(parsed, expected) - - @pytest.mark.parametrize("na_filter", [None, True, False]) - def test_excel_passes_na_filter(self, read_ext, na_filter): - # gh-25453 - kwargs = {} - - if na_filter is not None: - kwargs["na_filter"] = na_filter - - with pd.ExcelFile("test5" + read_ext) as excel: - parsed = pd.read_excel( - excel, - sheet_name="Sheet1", - keep_default_na=True, - na_values=["apple"], - **kwargs, - ) - - if na_filter is False: - expected = [["1.#QNAN"], [1], ["nan"], ["apple"], ["rabbit"]] - else: - expected = [[np.nan], [1], [np.nan], [np.nan], ["rabbit"]] - - expected = DataFrame(expected, columns=["Test"]) - tm.assert_frame_equal(parsed, expected) - - def test_excel_table_sheet_by_index(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - with pd.ExcelFile("test1" + read_ext) as excel: - df1 = pd.read_excel(excel, sheet_name=0, index_col=0) - df2 = pd.read_excel(excel, sheet_name=1, skiprows=[1], index_col=0) - tm.assert_frame_equal(df1, df_ref, check_names=False) - tm.assert_frame_equal(df2, df_ref, check_names=False) - - with pd.ExcelFile("test1" + read_ext) as excel: - df1 = excel.parse(0, index_col=0) - df2 = excel.parse(1, skiprows=[1], index_col=0) - tm.assert_frame_equal(df1, df_ref, check_names=False) - tm.assert_frame_equal(df2, df_ref, check_names=False) - - with pd.ExcelFile("test1" + read_ext) as excel: - df3 = pd.read_excel(excel, sheet_name=0, index_col=0, skipfooter=1) - tm.assert_frame_equal(df3, df1.iloc[:-1]) - - with pd.ExcelFile("test1" + read_ext) as excel: - df3 = excel.parse(0, index_col=0, skipfooter=1) - - tm.assert_frame_equal(df3, df1.iloc[:-1]) - - def test_sheet_name(self, request, read_ext, df_ref): - if read_ext == ".xlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - filename = "test1" - sheet_name = "Sheet1" - - with pd.ExcelFile(filename + read_ext) as excel: - df1_parse = excel.parse(sheet_name=sheet_name, index_col=0) # doc - - with pd.ExcelFile(filename + read_ext) as excel: - df2_parse = excel.parse(index_col=0, sheet_name=sheet_name) - - tm.assert_frame_equal(df1_parse, df_ref, check_names=False) - tm.assert_frame_equal(df2_parse, df_ref, check_names=False) - - @pytest.mark.parametrize( - "sheet_name", - [3, [0, 3], [3, 0], "Sheet4", ["Sheet1", "Sheet4"], ["Sheet4", "Sheet1"]], - ) - def test_bad_sheetname_raises(self, read_ext, sheet_name): - # GH 39250 - msg = "Worksheet index 3 is invalid|Worksheet named 'Sheet4' not found" - with pytest.raises(ValueError, match=msg): - with pd.ExcelFile("blank" + read_ext) as excel: - excel.parse(sheet_name=sheet_name) - - def test_excel_read_buffer(self, engine, read_ext): - pth = "test1" + read_ext - expected = pd.read_excel(pth, sheet_name="Sheet1", index_col=0, engine=engine) - - with open(pth, "rb") as f: - with pd.ExcelFile(f) as xls: - actual = pd.read_excel(xls, sheet_name="Sheet1", index_col=0) - - tm.assert_frame_equal(expected, actual) - - def test_reader_closes_file(self, engine, read_ext): - with open("test1" + read_ext, "rb") as f: - with pd.ExcelFile(f) as xlsx: - # parses okay - pd.read_excel(xlsx, sheet_name="Sheet1", index_col=0, engine=engine) - - assert f.closed - - def test_conflicting_excel_engines(self, read_ext): - # GH 26566 - msg = "Engine should not be specified when passing an ExcelFile" - - with pd.ExcelFile("test1" + read_ext) as xl: - with pytest.raises(ValueError, match=msg): - pd.read_excel(xl, engine="foo") - - def test_excel_read_binary(self, engine, read_ext): - # GH 15914 - expected = pd.read_excel("test1" + read_ext, engine=engine) - - with open("test1" + read_ext, "rb") as f: - data = f.read() - - actual = pd.read_excel(data, engine=engine) - tm.assert_frame_equal(expected, actual) - - def test_excel_read_binary_via_read_excel(self, read_ext, engine): - # GH 38424 - with open("test1" + read_ext, "rb") as f: - result = pd.read_excel(f) - expected = pd.read_excel("test1" + read_ext, engine=engine) - tm.assert_frame_equal(result, expected) - - @pytest.mark.skipif( - xlrd_version is not None and xlrd_version >= Version("2"), - reason="xlrd no longer supports xlsx", - ) - def test_excel_high_surrogate(self): - # GH 23809 - expected = DataFrame(["\udc88"], columns=["Column1"]) - - # should not produce a segmentation violation - actual = pd.read_excel("high_surrogate.xlsx", engine="xlrd") - tm.assert_frame_equal(expected, actual) - - @pytest.mark.parametrize("filename", ["df_empty.xlsx", "df_equals.xlsx"]) - def test_header_with_index_col(self, filename): - # GH 33476 - idx = Index(["Z"], name="I2") - cols = MultiIndex.from_tuples([("A", "B"), ("A", "B.1")], names=["I11", "I12"]) - expected = DataFrame([[1, 3]], index=idx, columns=cols, dtype="int64") - result = pd.read_excel( - filename, sheet_name="Sheet1", index_col=0, header=[0, 1] - ) - tm.assert_frame_equal(expected, result) - - def test_read_datetime_multiindex(self, request, engine, read_ext): - # GH 34748 - if engine == "pyxlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="Sheets containing datetimes not supported by pyxlsb" - ) - ) - - f = "test_datetime_mi" + read_ext - with pd.ExcelFile(f) as excel: - actual = pd.read_excel(excel, header=[0, 1], index_col=0, engine=engine) - expected_column_index = MultiIndex.from_tuples( - [(pd.to_datetime("02/29/2020"), pd.to_datetime("03/01/2020"))], - names=[ - pd.to_datetime("02/29/2020").to_pydatetime(), - pd.to_datetime("03/01/2020").to_pydatetime(), - ], - ) - expected = DataFrame([], columns=expected_column_index) - - tm.assert_frame_equal(expected, actual) - - def test_engine_invalid_option(self, read_ext): - # read_ext includes the '.' hence the weird formatting - with pytest.raises(ValueError, match="Value must be one of *"): - with pd.option_context(f"io.excel{read_ext}.reader", "abc"): - pass - - def test_ignore_chartsheets(self, request, engine, read_ext): - # GH 41448 - if engine == "odf": - pytest.skip("chartsheets do not exist in the ODF format") - if engine == "pyxlsb": - request.node.add_marker( - pytest.mark.xfail( - reason="pyxlsb can't distinguish chartsheets from worksheets" - ) - ) - with pd.ExcelFile("chartsheet" + read_ext) as excel: - assert excel.sheet_names == ["Sheet1"] - - def test_corrupt_files_closed(self, engine, read_ext): - # GH41778 - errors = (BadZipFile,) - if engine is None: - pytest.skip() - elif engine == "xlrd": - import xlrd - - errors = (BadZipFile, xlrd.biffh.XLRDError) - - with tm.ensure_clean(f"corrupt{read_ext}") as file: - Path(file).write_text("corrupt") - with tm.assert_produces_warning(False): - try: - pd.ExcelFile(file, engine=engine) - except errors: - pass diff --git a/pandas/tests/io/excel/test_style.py b/pandas/tests/io/excel/test_style.py deleted file mode 100644 index 8a142aebd719d..0000000000000 --- a/pandas/tests/io/excel/test_style.py +++ /dev/null @@ -1,167 +0,0 @@ -import numpy as np -import pytest - -from pandas import DataFrame -import pandas._testing as tm - -from pandas.io.excel import ExcelWriter -from pandas.io.formats.excel import ExcelFormatter - -pytest.importorskip("jinja2") -# jinja2 is currently required for Styler.__init__(). Technically Styler.to_excel -# could compute styles and render to excel without jinja2, since there is no -# 'template' file, but this needs the import error to delayed until render time. - - -def assert_equal_cell_styles(cell1, cell2): - # TODO: should find a better way to check equality - assert cell1.alignment.__dict__ == cell2.alignment.__dict__ - assert cell1.border.__dict__ == cell2.border.__dict__ - assert cell1.fill.__dict__ == cell2.fill.__dict__ - assert cell1.font.__dict__ == cell2.font.__dict__ - assert cell1.number_format == cell2.number_format - assert cell1.protection.__dict__ == cell2.protection.__dict__ - - -@pytest.mark.parametrize( - "engine", - ["xlsxwriter", "openpyxl"], -) -def test_styler_to_excel_unstyled(engine): - # compare DataFrame.to_excel and Styler.to_excel when no styles applied - pytest.importorskip(engine) - df = DataFrame(np.random.randn(2, 2)) - with tm.ensure_clean(".xlsx") as path: - with ExcelWriter(path, engine=engine) as writer: - df.to_excel(writer, sheet_name="dataframe") - df.style.to_excel(writer, sheet_name="unstyled") - - openpyxl = pytest.importorskip("openpyxl") # test loading only with openpyxl - wb = openpyxl.load_workbook(path) - - for col1, col2 in zip(wb["dataframe"].columns, wb["unstyled"].columns): - assert len(col1) == len(col2) - for cell1, cell2 in zip(col1, col2): - assert cell1.value == cell2.value - assert_equal_cell_styles(cell1, cell2) - - -shared_style_params = [ - ( - "background-color: #111222", - ["fill", "fgColor", "rgb"], - {"xlsxwriter": "FF111222", "openpyxl": "00111222"}, - ), - ( - "color: #111222", - ["font", "color", "value"], - {"xlsxwriter": "FF111222", "openpyxl": "00111222"}, - ), - ("font-family: Arial;", ["font", "name"], "arial"), - ("font-weight: bold;", ["font", "b"], True), - ("font-style: italic;", ["font", "i"], True), - ("text-decoration: underline;", ["font", "u"], "single"), - ("number-format: $??,???.00;", ["number_format"], "$??,???.00"), - ("text-align: left;", ["alignment", "horizontal"], "left"), - ( - "vertical-align: bottom;", - ["alignment", "vertical"], - {"xlsxwriter": None, "openpyxl": "bottom"}, # xlsxwriter Fails - ), -] - - -@pytest.mark.parametrize( - "engine", - ["xlsxwriter", "openpyxl"], -) -@pytest.mark.parametrize("css, attrs, expected", shared_style_params) -def test_styler_to_excel_basic(engine, css, attrs, expected): - pytest.importorskip(engine) - df = DataFrame(np.random.randn(1, 1)) - styler = df.style.applymap(lambda x: css) - - with tm.ensure_clean(".xlsx") as path: - with ExcelWriter(path, engine=engine) as writer: - df.to_excel(writer, sheet_name="dataframe") - styler.to_excel(writer, sheet_name="styled") - - openpyxl = pytest.importorskip("openpyxl") # test loading only with openpyxl - wb = openpyxl.load_workbook(path) - - # test unstyled data cell does not have expected styles - # test styled cell has expected styles - u_cell, s_cell = wb["dataframe"].cell(2, 2), wb["styled"].cell(2, 2) - for attr in attrs: - u_cell, s_cell = getattr(u_cell, attr), getattr(s_cell, attr) - - if isinstance(expected, dict): - assert u_cell is None or u_cell != expected[engine] - assert s_cell == expected[engine] - else: - assert u_cell is None or u_cell != expected - assert s_cell == expected - - -@pytest.mark.parametrize( - "engine", - ["xlsxwriter", "openpyxl"], -) -@pytest.mark.parametrize("css, attrs, expected", shared_style_params) -def test_styler_to_excel_basic_indexes(engine, css, attrs, expected): - pytest.importorskip(engine) - df = DataFrame(np.random.randn(1, 1)) - - styler = df.style - styler.applymap_index(lambda x: css, axis=0) - styler.applymap_index(lambda x: css, axis=1) - - null_styler = df.style - null_styler.applymap(lambda x: "null: css;") - null_styler.applymap_index(lambda x: "null: css;", axis=0) - null_styler.applymap_index(lambda x: "null: css;", axis=1) - - with tm.ensure_clean(".xlsx") as path: - with ExcelWriter(path, engine=engine) as writer: - null_styler.to_excel(writer, sheet_name="null_styled") - styler.to_excel(writer, sheet_name="styled") - - openpyxl = pytest.importorskip("openpyxl") # test loading only with openpyxl - wb = openpyxl.load_workbook(path) - - # test null styled index cells does not have expected styles - # test styled cell has expected styles - ui_cell, si_cell = wb["null_styled"].cell(2, 1), wb["styled"].cell(2, 1) - uc_cell, sc_cell = wb["null_styled"].cell(1, 2), wb["styled"].cell(1, 2) - for attr in attrs: - ui_cell, si_cell = getattr(ui_cell, attr), getattr(si_cell, attr) - uc_cell, sc_cell = getattr(uc_cell, attr), getattr(sc_cell, attr) - - if isinstance(expected, dict): - assert ui_cell is None or ui_cell != expected[engine] - assert si_cell == expected[engine] - assert uc_cell is None or uc_cell != expected[engine] - assert sc_cell == expected[engine] - else: - assert ui_cell is None or ui_cell != expected - assert si_cell == expected - assert uc_cell is None or uc_cell != expected - assert sc_cell == expected - - -def test_styler_custom_converter(): - openpyxl = pytest.importorskip("openpyxl") - - def custom_converter(css): - return {"font": {"color": {"rgb": "111222"}}} - - df = DataFrame(np.random.randn(1, 1)) - styler = df.style.applymap(lambda x: "color: #888999") - with tm.ensure_clean(".xlsx") as path: - with ExcelWriter(path, engine="openpyxl") as writer: - ExcelFormatter(styler, style_converter=custom_converter).write( - writer, sheet_name="custom" - ) - - wb = openpyxl.load_workbook(path) - assert wb["custom"].cell(2, 2).font.color.value == "00111222" diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py deleted file mode 100644 index 6f06ef9c09e52..0000000000000 --- a/pandas/tests/io/excel/test_writers.py +++ /dev/null @@ -1,1335 +0,0 @@ -from datetime import ( - date, - datetime, - timedelta, -) -from functools import partial -from io import BytesIO -import os -import re - -import numpy as np -import pytest - -import pandas.util._test_decorators as td - -import pandas as pd -from pandas import ( - DataFrame, - Index, - MultiIndex, - option_context, -) -import pandas._testing as tm - -from pandas.io.excel import ( - ExcelFile, - ExcelWriter, - _OpenpyxlWriter, - _XlsxWriter, - _XlwtWriter, - register_writer, -) - - -@pytest.fixture -def path(ext): - """ - Fixture to open file for use in each test case. - """ - with tm.ensure_clean(ext) as file_path: - yield file_path - - -@pytest.fixture -def set_engine(engine, ext): - """ - Fixture to set engine for use in each test case. - - Rather than requiring `engine=...` to be provided explicitly as an - argument in each test, this fixture sets a global option to dictate - which engine should be used to write Excel files. After executing - the test it rolls back said change to the global option. - """ - option_name = f"io.excel.{ext.strip('.')}.writer" - with option_context(option_name, engine): - yield - - -@pytest.mark.parametrize( - "ext", - [ - pytest.param(".xlsx", marks=[td.skip_if_no("openpyxl"), td.skip_if_no("xlrd")]), - pytest.param(".xlsm", marks=[td.skip_if_no("openpyxl"), td.skip_if_no("xlrd")]), - pytest.param(".xls", marks=[td.skip_if_no("xlwt"), td.skip_if_no("xlrd")]), - pytest.param( - ".xlsx", marks=[td.skip_if_no("xlsxwriter"), td.skip_if_no("xlrd")] - ), - pytest.param(".ods", marks=td.skip_if_no("odf")), - ], -) -class TestRoundTrip: - @pytest.mark.parametrize( - "header,expected", - [(None, DataFrame([np.nan] * 4)), (0, DataFrame({"Unnamed: 0": [np.nan] * 3}))], - ) - def test_read_one_empty_col_no_header(self, ext, header, expected): - # xref gh-12292 - filename = "no_header" - df = DataFrame([["", 1, 100], ["", 2, 200], ["", 3, 300], ["", 4, 400]]) - - with tm.ensure_clean(ext) as path: - df.to_excel(path, filename, index=False, header=False) - result = pd.read_excel( - path, sheet_name=filename, usecols=[0], header=header - ) - - tm.assert_frame_equal(result, expected) - - @pytest.mark.parametrize( - "header,expected", - [(None, DataFrame([0] + [np.nan] * 4)), (0, DataFrame([np.nan] * 4))], - ) - def test_read_one_empty_col_with_header(self, ext, header, expected): - filename = "with_header" - df = DataFrame([["", 1, 100], ["", 2, 200], ["", 3, 300], ["", 4, 400]]) - - with tm.ensure_clean(ext) as path: - df.to_excel(path, "with_header", index=False, header=True) - result = pd.read_excel( - path, sheet_name=filename, usecols=[0], header=header - ) - - tm.assert_frame_equal(result, expected) - - def test_set_column_names_in_parameter(self, ext): - # GH 12870 : pass down column names associated with - # keyword argument names - refdf = DataFrame([[1, "foo"], [2, "bar"], [3, "baz"]], columns=["a", "b"]) - - with tm.ensure_clean(ext) as pth: - with ExcelWriter(pth) as writer: - refdf.to_excel(writer, "Data_no_head", header=False, index=False) - refdf.to_excel(writer, "Data_with_head", index=False) - - refdf.columns = ["A", "B"] - - with ExcelFile(pth) as reader: - xlsdf_no_head = pd.read_excel( - reader, sheet_name="Data_no_head", header=None, names=["A", "B"] - ) - xlsdf_with_head = pd.read_excel( - reader, - sheet_name="Data_with_head", - index_col=None, - names=["A", "B"], - ) - - tm.assert_frame_equal(xlsdf_no_head, refdf) - tm.assert_frame_equal(xlsdf_with_head, refdf) - - def test_creating_and_reading_multiple_sheets(self, ext): - # see gh-9450 - # - # Test reading multiple sheets, from a runtime - # created Excel file with multiple sheets. - def tdf(col_sheet_name): - d, i = [11, 22, 33], [1, 2, 3] - return DataFrame(d, i, columns=[col_sheet_name]) - - sheets = ["AAA", "BBB", "CCC"] - - dfs = [tdf(s) for s in sheets] - dfs = dict(zip(sheets, dfs)) - - with tm.ensure_clean(ext) as pth: - with ExcelWriter(pth) as ew: - for sheetname, df in dfs.items(): - df.to_excel(ew, sheetname) - - dfs_returned = pd.read_excel(pth, sheet_name=sheets, index_col=0) - - for s in sheets: - tm.assert_frame_equal(dfs[s], dfs_returned[s]) - - def test_read_excel_multiindex_empty_level(self, ext): - # see gh-12453 - with tm.ensure_clean(ext) as path: - df = DataFrame( - { - ("One", "x"): {0: 1}, - ("Two", "X"): {0: 3}, - ("Two", "Y"): {0: 7}, - ("Zero", ""): {0: 0}, - } - ) - - expected = DataFrame( - { - ("One", "x"): {0: 1}, - ("Two", "X"): {0: 3}, - ("Two", "Y"): {0: 7}, - ("Zero", "Unnamed: 4_level_1"): {0: 0}, - } - ) - - df.to_excel(path) - actual = pd.read_excel(path, header=[0, 1], index_col=0) - tm.assert_frame_equal(actual, expected) - - df = DataFrame( - { - ("Beg", ""): {0: 0}, - ("Middle", "x"): {0: 1}, - ("Tail", "X"): {0: 3}, - ("Tail", "Y"): {0: 7}, - } - ) - - expected = DataFrame( - { - ("Beg", "Unnamed: 1_level_1"): {0: 0}, - ("Middle", "x"): {0: 1}, - ("Tail", "X"): {0: 3}, - ("Tail", "Y"): {0: 7}, - } - ) - - df.to_excel(path) - actual = pd.read_excel(path, header=[0, 1], index_col=0) - tm.assert_frame_equal(actual, expected) - - @pytest.mark.parametrize("c_idx_names", [True, False]) - @pytest.mark.parametrize("r_idx_names", [True, False]) - @pytest.mark.parametrize("c_idx_levels", [1, 3]) - @pytest.mark.parametrize("r_idx_levels", [1, 3]) - def test_excel_multindex_roundtrip( - self, ext, c_idx_names, r_idx_names, c_idx_levels, r_idx_levels, request - ): - # see gh-4679 - with tm.ensure_clean(ext) as pth: - if (c_idx_levels == 1 and c_idx_names) and not ( - r_idx_levels == 3 and not r_idx_names - ): - mark = pytest.mark.xfail( - reason="Column index name cannot be serialized unless " - "it's a MultiIndex" - ) - request.node.add_marker(mark) - - # Empty name case current read in as - # unnamed levels, not Nones. - check_names = r_idx_names or r_idx_levels <= 1 - - df = tm.makeCustomDataframe( - 5, 5, c_idx_names, r_idx_names, c_idx_levels, r_idx_levels - ) - df.to_excel(pth) - - act = pd.read_excel( - pth, - index_col=list(range(r_idx_levels)), - header=list(range(c_idx_levels)), - ) - tm.assert_frame_equal(df, act, check_names=check_names) - - df.iloc[0, :] = np.nan - df.to_excel(pth) - - act = pd.read_excel( - pth, - index_col=list(range(r_idx_levels)), - header=list(range(c_idx_levels)), - ) - tm.assert_frame_equal(df, act, check_names=check_names) - - df.iloc[-1, :] = np.nan - df.to_excel(pth) - act = pd.read_excel( - pth, - index_col=list(range(r_idx_levels)), - header=list(range(c_idx_levels)), - ) - tm.assert_frame_equal(df, act, check_names=check_names) - - def test_read_excel_parse_dates(self, ext): - # see gh-11544, gh-12051 - df = DataFrame( - {"col": [1, 2, 3], "date_strings": pd.date_range("2012-01-01", periods=3)} - ) - df2 = df.copy() - df2["date_strings"] = df2["date_strings"].dt.strftime("%m/%d/%Y") - - with tm.ensure_clean(ext) as pth: - df2.to_excel(pth) - - res = pd.read_excel(pth, index_col=0) - tm.assert_frame_equal(df2, res) - - res = pd.read_excel(pth, parse_dates=["date_strings"], index_col=0) - tm.assert_frame_equal(df, res) - - date_parser = lambda x: datetime.strptime(x, "%m/%d/%Y") - res = pd.read_excel( - pth, parse_dates=["date_strings"], date_parser=date_parser, index_col=0 - ) - tm.assert_frame_equal(df, res) - - def test_multiindex_interval_datetimes(self, ext): - # GH 30986 - midx = MultiIndex.from_arrays( - [ - range(4), - pd.interval_range( - start=pd.Timestamp("2020-01-01"), periods=4, freq="6M" - ), - ] - ) - df = DataFrame(range(4), index=midx) - with tm.ensure_clean(ext) as pth: - df.to_excel(pth) - result = pd.read_excel(pth, index_col=[0, 1]) - expected = DataFrame( - range(4), - MultiIndex.from_arrays( - [ - range(4), - [ - "(2020-01-31, 2020-07-31]", - "(2020-07-31, 2021-01-31]", - "(2021-01-31, 2021-07-31]", - "(2021-07-31, 2022-01-31]", - ], - ] - ), - ) - tm.assert_frame_equal(result, expected) - - -@pytest.mark.parametrize( - "engine,ext", - [ - pytest.param( - "openpyxl", - ".xlsx", - marks=[td.skip_if_no("openpyxl"), td.skip_if_no("xlrd")], - ), - pytest.param( - "openpyxl", - ".xlsm", - marks=[td.skip_if_no("openpyxl"), td.skip_if_no("xlrd")], - ), - pytest.param( - "xlwt", ".xls", marks=[td.skip_if_no("xlwt"), td.skip_if_no("xlrd")] - ), - pytest.param( - "xlsxwriter", - ".xlsx", - marks=[td.skip_if_no("xlsxwriter"), td.skip_if_no("xlrd")], - ), - pytest.param("odf", ".ods", marks=td.skip_if_no("odf")), - ], -) -@pytest.mark.usefixtures("set_engine") -class TestExcelWriter: - def test_excel_sheet_size(self, path): - - # GH 26080 - breaking_row_count = 2 ** 20 + 1 - breaking_col_count = 2 ** 14 + 1 - # purposely using two arrays to prevent memory issues while testing - row_arr = np.zeros(shape=(breaking_row_count, 1)) - col_arr = np.zeros(shape=(1, breaking_col_count)) - row_df = DataFrame(row_arr) - col_df = DataFrame(col_arr) - - msg = "sheet is too large" - with pytest.raises(ValueError, match=msg): - row_df.to_excel(path) - - with pytest.raises(ValueError, match=msg): - col_df.to_excel(path) - - def test_excel_sheet_by_name_raise(self, path, engine): - gt = DataFrame(np.random.randn(10, 2)) - gt.to_excel(path) - - with ExcelFile(path) as xl: - df = pd.read_excel(xl, sheet_name=0, index_col=0) - - tm.assert_frame_equal(gt, df) - - msg = "Worksheet named '0' not found" - with pytest.raises(ValueError, match=msg): - pd.read_excel(xl, "0") - - def test_excel_writer_context_manager(self, frame, path): - with ExcelWriter(path) as writer: - frame.to_excel(writer, "Data1") - frame2 = frame.copy() - frame2.columns = frame.columns[::-1] - frame2.to_excel(writer, "Data2") - - with ExcelFile(path) as reader: - found_df = pd.read_excel(reader, sheet_name="Data1", index_col=0) - found_df2 = pd.read_excel(reader, sheet_name="Data2", index_col=0) - - tm.assert_frame_equal(found_df, frame) - tm.assert_frame_equal(found_df2, frame2) - - def test_roundtrip(self, frame, path): - frame = frame.copy() - frame["A"][:5] = np.nan - - frame.to_excel(path, "test1") - frame.to_excel(path, "test1", columns=["A", "B"]) - frame.to_excel(path, "test1", header=False) - frame.to_excel(path, "test1", index=False) - - # test roundtrip - frame.to_excel(path, "test1") - recons = pd.read_excel(path, sheet_name="test1", index_col=0) - tm.assert_frame_equal(frame, recons) - - frame.to_excel(path, "test1", index=False) - recons = pd.read_excel(path, sheet_name="test1", index_col=None) - recons.index = frame.index - tm.assert_frame_equal(frame, recons) - - frame.to_excel(path, "test1", na_rep="NA") - recons = pd.read_excel(path, sheet_name="test1", index_col=0, na_values=["NA"]) - tm.assert_frame_equal(frame, recons) - - # GH 3611 - frame.to_excel(path, "test1", na_rep="88") - recons = pd.read_excel(path, sheet_name="test1", index_col=0, na_values=["88"]) - tm.assert_frame_equal(frame, recons) - - frame.to_excel(path, "test1", na_rep="88") - recons = pd.read_excel( - path, sheet_name="test1", index_col=0, na_values=[88, 88.0] - ) - tm.assert_frame_equal(frame, recons) - - # GH 6573 - frame.to_excel(path, "Sheet1") - recons = pd.read_excel(path, index_col=0) - tm.assert_frame_equal(frame, recons) - - frame.to_excel(path, "0") - recons = pd.read_excel(path, index_col=0) - tm.assert_frame_equal(frame, recons) - - # GH 8825 Pandas Series should provide to_excel method - s = frame["A"] - s.to_excel(path) - recons = pd.read_excel(path, index_col=0) - tm.assert_frame_equal(s.to_frame(), recons) - - def test_mixed(self, frame, path): - mixed_frame = frame.copy() - mixed_frame["foo"] = "bar" - - mixed_frame.to_excel(path, "test1") - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - tm.assert_frame_equal(mixed_frame, recons) - - def test_ts_frame(self, tsframe, path): - df = tsframe - - # freq doesn't round-trip - index = pd.DatetimeIndex(np.asarray(df.index), freq=None) - df.index = index - - df.to_excel(path, "test1") - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - tm.assert_frame_equal(df, recons) - - def test_basics_with_nan(self, frame, path): - frame = frame.copy() - frame["A"][:5] = np.nan - frame.to_excel(path, "test1") - frame.to_excel(path, "test1", columns=["A", "B"]) - frame.to_excel(path, "test1", header=False) - frame.to_excel(path, "test1", index=False) - - @pytest.mark.parametrize("np_type", [np.int8, np.int16, np.int32, np.int64]) - def test_int_types(self, np_type, path): - # Test np.int values read come back as int - # (rather than float which is Excel's format). - df = DataFrame(np.random.randint(-10, 10, size=(10, 2)), dtype=np_type) - df.to_excel(path, "test1") - - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - - int_frame = df.astype(np.int64) - tm.assert_frame_equal(int_frame, recons) - - recons2 = pd.read_excel(path, sheet_name="test1", index_col=0) - tm.assert_frame_equal(int_frame, recons2) - - # Test with convert_float=False comes back as float. - float_frame = df.astype(float) - float_frame.columns = float_frame.columns.astype(float) - float_frame.index = float_frame.index.astype(float) - with tm.assert_produces_warning( - FutureWarning, match="convert_float is deprecated" - ): - recons = pd.read_excel( - path, sheet_name="test1", convert_float=False, index_col=0 - ) - tm.assert_frame_equal(recons, float_frame) - - @pytest.mark.parametrize("np_type", [np.float16, np.float32, np.float64]) - def test_float_types(self, np_type, path): - # Test np.float values read come back as float. - df = DataFrame(np.random.random_sample(10), dtype=np_type) - df.to_excel(path, "test1") - - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0).astype( - np_type - ) - - tm.assert_frame_equal(df, recons) - - @pytest.mark.parametrize("np_type", [np.bool8, np.bool_]) - def test_bool_types(self, np_type, path): - # Test np.bool8 and np.bool_ values read come back as float. - df = DataFrame([1, 0, True, False], dtype=np_type) - df.to_excel(path, "test1") - - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0).astype( - np_type - ) - - tm.assert_frame_equal(df, recons) - - def test_inf_roundtrip(self, path): - df = DataFrame([(1, np.inf), (2, 3), (5, -np.inf)]) - df.to_excel(path, "test1") - - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - - tm.assert_frame_equal(df, recons) - - def test_sheets(self, frame, tsframe, path): - - # freq doesn't round-trip - index = pd.DatetimeIndex(np.asarray(tsframe.index), freq=None) - tsframe.index = index - - frame = frame.copy() - frame["A"][:5] = np.nan - - frame.to_excel(path, "test1") - frame.to_excel(path, "test1", columns=["A", "B"]) - frame.to_excel(path, "test1", header=False) - frame.to_excel(path, "test1", index=False) - - # Test writing to separate sheets - with ExcelWriter(path) as writer: - frame.to_excel(writer, "test1") - tsframe.to_excel(writer, "test2") - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - tm.assert_frame_equal(frame, recons) - recons = pd.read_excel(reader, sheet_name="test2", index_col=0) - tm.assert_frame_equal(tsframe, recons) - assert 2 == len(reader.sheet_names) - assert "test1" == reader.sheet_names[0] - assert "test2" == reader.sheet_names[1] - - def test_colaliases(self, frame, path): - frame = frame.copy() - frame["A"][:5] = np.nan - - frame.to_excel(path, "test1") - frame.to_excel(path, "test1", columns=["A", "B"]) - frame.to_excel(path, "test1", header=False) - frame.to_excel(path, "test1", index=False) - - # column aliases - col_aliases = Index(["AA", "X", "Y", "Z"]) - frame.to_excel(path, "test1", header=col_aliases) - with ExcelFile(path) as reader: - rs = pd.read_excel(reader, sheet_name="test1", index_col=0) - xp = frame.copy() - xp.columns = col_aliases - tm.assert_frame_equal(xp, rs) - - def test_roundtrip_indexlabels(self, merge_cells, frame, path): - frame = frame.copy() - frame["A"][:5] = np.nan - - frame.to_excel(path, "test1") - frame.to_excel(path, "test1", columns=["A", "B"]) - frame.to_excel(path, "test1", header=False) - frame.to_excel(path, "test1", index=False) - - # test index_label - df = DataFrame(np.random.randn(10, 2)) >= 0 - df.to_excel(path, "test1", index_label=["test"], merge_cells=merge_cells) - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0).astype( - np.int64 - ) - df.index.names = ["test"] - assert df.index.names == recons.index.names - - df = DataFrame(np.random.randn(10, 2)) >= 0 - df.to_excel( - path, - "test1", - index_label=["test", "dummy", "dummy2"], - merge_cells=merge_cells, - ) - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0).astype( - np.int64 - ) - df.index.names = ["test"] - assert df.index.names == recons.index.names - - df = DataFrame(np.random.randn(10, 2)) >= 0 - df.to_excel(path, "test1", index_label="test", merge_cells=merge_cells) - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0).astype( - np.int64 - ) - df.index.names = ["test"] - tm.assert_frame_equal(df, recons.astype(bool)) - - frame.to_excel( - path, - "test1", - columns=["A", "B", "C", "D"], - index=False, - merge_cells=merge_cells, - ) - # take 'A' and 'B' as indexes (same row as cols 'C', 'D') - df = frame.copy() - df = df.set_index(["A", "B"]) - - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=[0, 1]) - tm.assert_frame_equal(df, recons) - - def test_excel_roundtrip_indexname(self, merge_cells, path): - df = DataFrame(np.random.randn(10, 4)) - df.index.name = "foo" - - df.to_excel(path, merge_cells=merge_cells) - - with ExcelFile(path) as xf: - result = pd.read_excel(xf, sheet_name=xf.sheet_names[0], index_col=0) - - tm.assert_frame_equal(result, df) - assert result.index.name == "foo" - - def test_excel_roundtrip_datetime(self, merge_cells, tsframe, path): - # datetime.date, not sure what to test here exactly - - # freq does not round-trip - index = pd.DatetimeIndex(np.asarray(tsframe.index), freq=None) - tsframe.index = index - - tsf = tsframe.copy() - - tsf.index = [x.date() for x in tsframe.index] - tsf.to_excel(path, "test1", merge_cells=merge_cells) - - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - - tm.assert_frame_equal(tsframe, recons) - - def test_excel_date_datetime_format(self, engine, ext, path): - # see gh-4133 - # - # Excel output format strings - df = DataFrame( - [ - [date(2014, 1, 31), date(1999, 9, 24)], - [datetime(1998, 5, 26, 23, 33, 4), datetime(2014, 2, 28, 13, 5, 13)], - ], - index=["DATE", "DATETIME"], - columns=["X", "Y"], - ) - df_expected = DataFrame( - [ - [datetime(2014, 1, 31), datetime(1999, 9, 24)], - [datetime(1998, 5, 26, 23, 33, 4), datetime(2014, 2, 28, 13, 5, 13)], - ], - index=["DATE", "DATETIME"], - columns=["X", "Y"], - ) - - with tm.ensure_clean(ext) as filename2: - with ExcelWriter(path) as writer1: - df.to_excel(writer1, "test1") - - with ExcelWriter( - filename2, - date_format="DD.MM.YYYY", - datetime_format="DD.MM.YYYY HH-MM-SS", - ) as writer2: - df.to_excel(writer2, "test1") - - with ExcelFile(path) as reader1: - rs1 = pd.read_excel(reader1, sheet_name="test1", index_col=0) - - with ExcelFile(filename2) as reader2: - rs2 = pd.read_excel(reader2, sheet_name="test1", index_col=0) - - tm.assert_frame_equal(rs1, rs2) - - # Since the reader returns a datetime object for dates, - # we need to use df_expected to check the result. - tm.assert_frame_equal(rs2, df_expected) - - def test_to_excel_interval_no_labels(self, path): - # see gh-19242 - # - # Test writing Interval without labels. - df = DataFrame(np.random.randint(-10, 10, size=(20, 1)), dtype=np.int64) - expected = df.copy() - - df["new"] = pd.cut(df[0], 10) - expected["new"] = pd.cut(expected[0], 10).astype(str) - - df.to_excel(path, "test1") - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - tm.assert_frame_equal(expected, recons) - - def test_to_excel_interval_labels(self, path): - # see gh-19242 - # - # Test writing Interval with labels. - df = DataFrame(np.random.randint(-10, 10, size=(20, 1)), dtype=np.int64) - expected = df.copy() - intervals = pd.cut( - df[0], 10, labels=["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] - ) - df["new"] = intervals - expected["new"] = pd.Series(list(intervals)) - - df.to_excel(path, "test1") - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - tm.assert_frame_equal(expected, recons) - - def test_to_excel_timedelta(self, path): - # see gh-19242, gh-9155 - # - # Test writing timedelta to xls. - df = DataFrame( - np.random.randint(-10, 10, size=(20, 1)), columns=["A"], dtype=np.int64 - ) - expected = df.copy() - - df["new"] = df["A"].apply(lambda x: timedelta(seconds=x)) - expected["new"] = expected["A"].apply( - lambda x: timedelta(seconds=x).total_seconds() / 86400 - ) - - df.to_excel(path, "test1") - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=0) - tm.assert_frame_equal(expected, recons) - - def test_to_excel_periodindex(self, tsframe, path): - xp = tsframe.resample("M", kind="period").mean() - - xp.to_excel(path, "sht1") - - with ExcelFile(path) as reader: - rs = pd.read_excel(reader, sheet_name="sht1", index_col=0) - tm.assert_frame_equal(xp, rs.to_period("M")) - - def test_to_excel_multiindex(self, merge_cells, frame, path): - arrays = np.arange(len(frame.index) * 2).reshape(2, -1) - new_index = MultiIndex.from_arrays(arrays, names=["first", "second"]) - frame.index = new_index - - frame.to_excel(path, "test1", header=False) - frame.to_excel(path, "test1", columns=["A", "B"]) - - # round trip - frame.to_excel(path, "test1", merge_cells=merge_cells) - with ExcelFile(path) as reader: - df = pd.read_excel(reader, sheet_name="test1", index_col=[0, 1]) - tm.assert_frame_equal(frame, df) - - # GH13511 - def test_to_excel_multiindex_nan_label(self, merge_cells, path): - df = DataFrame({"A": [None, 2, 3], "B": [10, 20, 30], "C": np.random.sample(3)}) - df = df.set_index(["A", "B"]) - - df.to_excel(path, merge_cells=merge_cells) - df1 = pd.read_excel(path, index_col=[0, 1]) - tm.assert_frame_equal(df, df1) - - # Test for Issue 11328. If column indices are integers, make - # sure they are handled correctly for either setting of - # merge_cells - def test_to_excel_multiindex_cols(self, merge_cells, frame, path): - arrays = np.arange(len(frame.index) * 2).reshape(2, -1) - new_index = MultiIndex.from_arrays(arrays, names=["first", "second"]) - frame.index = new_index - - new_cols_index = MultiIndex.from_tuples([(40, 1), (40, 2), (50, 1), (50, 2)]) - frame.columns = new_cols_index - header = [0, 1] - if not merge_cells: - header = 0 - - # round trip - frame.to_excel(path, "test1", merge_cells=merge_cells) - with ExcelFile(path) as reader: - df = pd.read_excel( - reader, sheet_name="test1", header=header, index_col=[0, 1] - ) - if not merge_cells: - fm = frame.columns.format(sparsify=False, adjoin=False, names=False) - frame.columns = [".".join(map(str, q)) for q in zip(*fm)] - tm.assert_frame_equal(frame, df) - - def test_to_excel_multiindex_dates(self, merge_cells, tsframe, path): - # try multiindex with dates - new_index = [tsframe.index, np.arange(len(tsframe.index))] - tsframe.index = MultiIndex.from_arrays(new_index) - - tsframe.index.names = ["time", "foo"] - tsframe.to_excel(path, "test1", merge_cells=merge_cells) - with ExcelFile(path) as reader: - recons = pd.read_excel(reader, sheet_name="test1", index_col=[0, 1]) - - tm.assert_frame_equal(tsframe, recons) - assert recons.index.names == ("time", "foo") - - def test_to_excel_multiindex_no_write_index(self, path): - # Test writing and re-reading a MI without the index. GH 5616. - - # Initial non-MI frame. - frame1 = DataFrame({"a": [10, 20], "b": [30, 40], "c": [50, 60]}) - - # Add a MI. - frame2 = frame1.copy() - multi_index = MultiIndex.from_tuples([(70, 80), (90, 100)]) - frame2.index = multi_index - - # Write out to Excel without the index. - frame2.to_excel(path, "test1", index=False) - - # Read it back in. - with ExcelFile(path) as reader: - frame3 = pd.read_excel(reader, sheet_name="test1") - - # Test that it is the same as the initial frame. - tm.assert_frame_equal(frame1, frame3) - - def test_to_excel_float_format(self, path): - df = DataFrame( - [[0.123456, 0.234567, 0.567567], [12.32112, 123123.2, 321321.2]], - index=["A", "B"], - columns=["X", "Y", "Z"], - ) - df.to_excel(path, "test1", float_format="%.2f") - - with ExcelFile(path) as reader: - result = pd.read_excel(reader, sheet_name="test1", index_col=0) - - expected = DataFrame( - [[0.12, 0.23, 0.57], [12.32, 123123.20, 321321.20]], - index=["A", "B"], - columns=["X", "Y", "Z"], - ) - tm.assert_frame_equal(result, expected) - - def test_to_excel_output_encoding(self, ext): - # Avoid mixed inferred_type. - df = DataFrame( - [["\u0192", "\u0193", "\u0194"], ["\u0195", "\u0196", "\u0197"]], - index=["A\u0192", "B"], - columns=["X\u0193", "Y", "Z"], - ) - - with tm.ensure_clean("__tmp_to_excel_float_format__." + ext) as filename: - df.to_excel(filename, sheet_name="TestSheet", encoding="utf8") - result = pd.read_excel(filename, sheet_name="TestSheet", index_col=0) - tm.assert_frame_equal(result, df) - - def test_to_excel_unicode_filename(self, ext, path): - with tm.ensure_clean("\u0192u." + ext) as filename: - try: - f = open(filename, "wb") - except UnicodeEncodeError: - pytest.skip("No unicode file names on this system") - finally: - f.close() - - df = DataFrame( - [[0.123456, 0.234567, 0.567567], [12.32112, 123123.2, 321321.2]], - index=["A", "B"], - columns=["X", "Y", "Z"], - ) - df.to_excel(filename, "test1", float_format="%.2f") - - with ExcelFile(filename) as reader: - result = pd.read_excel(reader, sheet_name="test1", index_col=0) - - expected = DataFrame( - [[0.12, 0.23, 0.57], [12.32, 123123.20, 321321.20]], - index=["A", "B"], - columns=["X", "Y", "Z"], - ) - tm.assert_frame_equal(result, expected) - - @pytest.mark.parametrize("use_headers", [True, False]) - @pytest.mark.parametrize("r_idx_nlevels", [1, 2, 3]) - @pytest.mark.parametrize("c_idx_nlevels", [1, 2, 3]) - def test_excel_010_hemstring( - self, merge_cells, c_idx_nlevels, r_idx_nlevels, use_headers, path - ): - def roundtrip(data, header=True, parser_hdr=0, index=True): - data.to_excel(path, header=header, merge_cells=merge_cells, index=index) - - with ExcelFile(path) as xf: - return pd.read_excel( - xf, sheet_name=xf.sheet_names[0], header=parser_hdr - ) - - # Basic test. - parser_header = 0 if use_headers else None - res = roundtrip(DataFrame([0]), use_headers, parser_header) - - assert res.shape == (1, 2) - assert res.iloc[0, 0] is not np.nan - - # More complex tests with multi-index. - nrows = 5 - ncols = 3 - - # ensure limited functionality in 0.10 - # override of gh-2370 until sorted out in 0.11 - - df = tm.makeCustomDataframe( - nrows, ncols, r_idx_nlevels=r_idx_nlevels, c_idx_nlevels=c_idx_nlevels - ) - - # This if will be removed once multi-column Excel writing - # is implemented. For now fixing gh-9794. - if c_idx_nlevels > 1: - msg = ( - "Writing to Excel with MultiIndex columns and no index " - "\\('index'=False\\) is not yet implemented." - ) - with pytest.raises(NotImplementedError, match=msg): - roundtrip(df, use_headers, index=False) - else: - res = roundtrip(df, use_headers) - - if use_headers: - assert res.shape == (nrows, ncols + r_idx_nlevels) - else: - # First row taken as columns. - assert res.shape == (nrows - 1, ncols + r_idx_nlevels) - - # No NaNs. - for r in range(len(res.index)): - for c in range(len(res.columns)): - assert res.iloc[r, c] is not np.nan - - def test_duplicated_columns(self, path): - # see gh-5235 - df = DataFrame([[1, 2, 3], [1, 2, 3], [1, 2, 3]], columns=["A", "B", "B"]) - df.to_excel(path, "test1") - expected = DataFrame( - [[1, 2, 3], [1, 2, 3], [1, 2, 3]], columns=["A", "B", "B.1"] - ) - - # By default, we mangle. - result = pd.read_excel(path, sheet_name="test1", index_col=0) - tm.assert_frame_equal(result, expected) - - # Explicitly, we pass in the parameter. - result = pd.read_excel( - path, sheet_name="test1", index_col=0, mangle_dupe_cols=True - ) - tm.assert_frame_equal(result, expected) - - # see gh-11007, gh-10970 - df = DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]], columns=["A", "B", "A", "B"]) - df.to_excel(path, "test1") - - result = pd.read_excel(path, sheet_name="test1", index_col=0) - expected = DataFrame( - [[1, 2, 3, 4], [5, 6, 7, 8]], columns=["A", "B", "A.1", "B.1"] - ) - tm.assert_frame_equal(result, expected) - - # see gh-10982 - df.to_excel(path, "test1", index=False, header=False) - result = pd.read_excel(path, sheet_name="test1", header=None) - - expected = DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]]) - tm.assert_frame_equal(result, expected) - - msg = "Setting mangle_dupe_cols=False is not supported yet" - with pytest.raises(ValueError, match=msg): - pd.read_excel(path, sheet_name="test1", header=None, mangle_dupe_cols=False) - - def test_swapped_columns(self, path): - # Test for issue #5427. - write_frame = DataFrame({"A": [1, 1, 1], "B": [2, 2, 2]}) - write_frame.to_excel(path, "test1", columns=["B", "A"]) - - read_frame = pd.read_excel(path, sheet_name="test1", header=0) - - tm.assert_series_equal(write_frame["A"], read_frame["A"]) - tm.assert_series_equal(write_frame["B"], read_frame["B"]) - - def test_invalid_columns(self, path): - # see gh-10982 - write_frame = DataFrame({"A": [1, 1, 1], "B": [2, 2, 2]}) - - with pytest.raises(KeyError, match="Not all names specified"): - write_frame.to_excel(path, "test1", columns=["B", "C"]) - - with pytest.raises( - KeyError, match="'passes columns are not ALL present dataframe'" - ): - write_frame.to_excel(path, "test1", columns=["C", "D"]) - - @pytest.mark.parametrize( - "to_excel_index,read_excel_index_col", - [ - (True, 0), # Include index in write to file - (False, None), # Dont include index in write to file - ], - ) - def test_write_subset_columns(self, path, to_excel_index, read_excel_index_col): - # GH 31677 - write_frame = DataFrame({"A": [1, 1, 1], "B": [2, 2, 2], "C": [3, 3, 3]}) - write_frame.to_excel( - path, "col_subset_bug", columns=["A", "B"], index=to_excel_index - ) - - expected = write_frame[["A", "B"]] - read_frame = pd.read_excel( - path, sheet_name="col_subset_bug", index_col=read_excel_index_col - ) - - tm.assert_frame_equal(expected, read_frame) - - def test_comment_arg(self, path): - # see gh-18735 - # - # Test the comment argument functionality to pd.read_excel. - - # Create file to read in. - df = DataFrame({"A": ["one", "#one", "one"], "B": ["two", "two", "#two"]}) - df.to_excel(path, "test_c") - - # Read file without comment arg. - result1 = pd.read_excel(path, sheet_name="test_c", index_col=0) - - result1.iloc[1, 0] = None - result1.iloc[1, 1] = None - result1.iloc[2, 1] = None - - result2 = pd.read_excel(path, sheet_name="test_c", comment="#", index_col=0) - tm.assert_frame_equal(result1, result2) - - def test_comment_default(self, path): - # Re issue #18735 - # Test the comment argument default to pd.read_excel - - # Create file to read in - df = DataFrame({"A": ["one", "#one", "one"], "B": ["two", "two", "#two"]}) - df.to_excel(path, "test_c") - - # Read file with default and explicit comment=None - result1 = pd.read_excel(path, sheet_name="test_c") - result2 = pd.read_excel(path, sheet_name="test_c", comment=None) - tm.assert_frame_equal(result1, result2) - - def test_comment_used(self, path): - # see gh-18735 - # - # Test the comment argument is working as expected when used. - - # Create file to read in. - df = DataFrame({"A": ["one", "#one", "one"], "B": ["two", "two", "#two"]}) - df.to_excel(path, "test_c") - - # Test read_frame_comment against manually produced expected output. - expected = DataFrame({"A": ["one", None, "one"], "B": ["two", None, None]}) - result = pd.read_excel(path, sheet_name="test_c", comment="#", index_col=0) - tm.assert_frame_equal(result, expected) - - def test_comment_empty_line(self, path): - # Re issue #18735 - # Test that pd.read_excel ignores commented lines at the end of file - - df = DataFrame({"a": ["1", "#2"], "b": ["2", "3"]}) - df.to_excel(path, index=False) - - # Test that all-comment lines at EoF are ignored - expected = DataFrame({"a": [1], "b": [2]}) - result = pd.read_excel(path, comment="#") - tm.assert_frame_equal(result, expected) - - def test_datetimes(self, path): - - # Test writing and reading datetimes. For issue #9139. (xref #9185) - datetimes = [ - datetime(2013, 1, 13, 1, 2, 3), - datetime(2013, 1, 13, 2, 45, 56), - datetime(2013, 1, 13, 4, 29, 49), - datetime(2013, 1, 13, 6, 13, 42), - datetime(2013, 1, 13, 7, 57, 35), - datetime(2013, 1, 13, 9, 41, 28), - datetime(2013, 1, 13, 11, 25, 21), - datetime(2013, 1, 13, 13, 9, 14), - datetime(2013, 1, 13, 14, 53, 7), - datetime(2013, 1, 13, 16, 37, 0), - datetime(2013, 1, 13, 18, 20, 52), - ] - - write_frame = DataFrame({"A": datetimes}) - write_frame.to_excel(path, "Sheet1") - if path.endswith("xlsx") or path.endswith("xlsm"): - pytest.skip( - "Defaults to openpyxl and fails with floating point error on " - "datetimes; may be fixed on newer versions of openpyxl - GH #38644" - ) - read_frame = pd.read_excel(path, sheet_name="Sheet1", header=0) - - tm.assert_series_equal(write_frame["A"], read_frame["A"]) - - def test_bytes_io(self, engine): - # see gh-7074 - with BytesIO() as bio: - df = DataFrame(np.random.randn(10, 2)) - - # Pass engine explicitly, as there is no file path to infer from. - with ExcelWriter(bio, engine=engine) as writer: - df.to_excel(writer) - - bio.seek(0) - reread_df = pd.read_excel(bio, index_col=0) - tm.assert_frame_equal(df, reread_df) - - def test_write_lists_dict(self, path): - # see gh-8188. - df = DataFrame( - { - "mixed": ["a", ["b", "c"], {"d": "e", "f": 2}], - "numeric": [1, 2, 3.0], - "str": ["apple", "banana", "cherry"], - } - ) - df.to_excel(path, "Sheet1") - read = pd.read_excel(path, sheet_name="Sheet1", header=0, index_col=0) - - expected = df.copy() - expected.mixed = expected.mixed.apply(str) - expected.numeric = expected.numeric.astype("int64") - - tm.assert_frame_equal(read, expected) - - def test_render_as_column_name(self, path): - # see gh-34331 - df = DataFrame({"render": [1, 2], "data": [3, 4]}) - df.to_excel(path, "Sheet1") - read = pd.read_excel(path, "Sheet1", index_col=0) - expected = df - tm.assert_frame_equal(read, expected) - - def test_true_and_false_value_options(self, path): - # see gh-13347 - df = DataFrame([["foo", "bar"]], columns=["col1", "col2"]) - expected = df.replace({"foo": True, "bar": False}) - - df.to_excel(path) - read_frame = pd.read_excel( - path, true_values=["foo"], false_values=["bar"], index_col=0 - ) - tm.assert_frame_equal(read_frame, expected) - - def test_freeze_panes(self, path): - # see gh-15160 - expected = DataFrame([[1, 2], [3, 4]], columns=["col1", "col2"]) - expected.to_excel(path, "Sheet1", freeze_panes=(1, 1)) - - result = pd.read_excel(path, index_col=0) - tm.assert_frame_equal(result, expected) - - def test_path_path_lib(self, engine, ext): - df = tm.makeDataFrame() - writer = partial(df.to_excel, engine=engine) - - reader = partial(pd.read_excel, index_col=0) - result = tm.round_trip_pathlib(writer, reader, path=f"foo{ext}") - tm.assert_frame_equal(result, df) - - def test_path_local_path(self, engine, ext): - df = tm.makeDataFrame() - writer = partial(df.to_excel, engine=engine) - - reader = partial(pd.read_excel, index_col=0) - result = tm.round_trip_localpath(writer, reader, path=f"foo{ext}") - tm.assert_frame_equal(result, df) - - def test_merged_cell_custom_objects(self, merge_cells, path): - # see GH-27006 - mi = MultiIndex.from_tuples( - [ - (pd.Period("2018"), pd.Period("2018Q1")), - (pd.Period("2018"), pd.Period("2018Q2")), - ] - ) - expected = DataFrame(np.ones((2, 2)), columns=mi) - expected.to_excel(path) - with tm.assert_produces_warning( - FutureWarning, match="convert_float is deprecated" - ): - result = pd.read_excel( - path, header=[0, 1], index_col=0, convert_float=False - ) - # need to convert PeriodIndexes to standard Indexes for assert equal - expected.columns = expected.columns.set_levels( - [[str(i) for i in mi.levels[0]], [str(i) for i in mi.levels[1]]], - level=[0, 1], - ) - expected.index = expected.index.astype(np.float64) - tm.assert_frame_equal(expected, result) - - @pytest.mark.parametrize("dtype", [None, object]) - def test_raise_when_saving_timezones(self, dtype, tz_aware_fixture, path): - # GH 27008, GH 7056 - tz = tz_aware_fixture - data = pd.Timestamp("2019", tz=tz) - df = DataFrame([data], dtype=dtype) - with pytest.raises(ValueError, match="Excel does not support"): - df.to_excel(path) - - data = data.to_pydatetime() - df = DataFrame([data], dtype=dtype) - with pytest.raises(ValueError, match="Excel does not support"): - df.to_excel(path) - - def test_excel_duplicate_columns_with_names(self, path): - # GH#39695 - df = DataFrame({"A": [0, 1], "B": [10, 11]}) - df.to_excel(path, columns=["A", "B", "A"], index=False) - - result = pd.read_excel(path) - expected = DataFrame([[0, 10, 0], [1, 11, 1]], columns=["A", "B", "A.1"]) - tm.assert_frame_equal(result, expected) - - def test_if_sheet_exists_raises(self, ext): - # GH 40230 - msg = "if_sheet_exists is only valid in append mode (mode='a')" - - with tm.ensure_clean(ext) as f: - with pytest.raises(ValueError, match=re.escape(msg)): - ExcelWriter(f, if_sheet_exists="replace") - - -class TestExcelWriterEngineTests: - @pytest.mark.parametrize( - "klass,ext", - [ - pytest.param(_XlsxWriter, ".xlsx", marks=td.skip_if_no("xlsxwriter")), - pytest.param(_OpenpyxlWriter, ".xlsx", marks=td.skip_if_no("openpyxl")), - pytest.param(_XlwtWriter, ".xls", marks=td.skip_if_no("xlwt")), - ], - ) - def test_ExcelWriter_dispatch(self, klass, ext): - with tm.ensure_clean(ext) as path: - with ExcelWriter(path) as writer: - if ext == ".xlsx" and td.safe_import("xlsxwriter"): - # xlsxwriter has preference over openpyxl if both installed - assert isinstance(writer, _XlsxWriter) - else: - assert isinstance(writer, klass) - - def test_ExcelWriter_dispatch_raises(self): - with pytest.raises(ValueError, match="No engine"): - ExcelWriter("nothing") - - def test_register_writer(self): - # some awkward mocking to test out dispatch and such actually works - called_save = [] - called_write_cells = [] - - class DummyClass(ExcelWriter): - called_save = False - called_write_cells = False - supported_extensions = ["xlsx", "xls"] - engine = "dummy" - - def save(self): - called_save.append(True) - - def write_cells(self, *args, **kwargs): - called_write_cells.append(True) - - def check_called(func): - func() - assert len(called_save) >= 1 - assert len(called_write_cells) >= 1 - del called_save[:] - del called_write_cells[:] - - with option_context("io.excel.xlsx.writer", "dummy"): - path = "something.xlsx" - with tm.ensure_clean(path) as filepath: - register_writer(DummyClass) - with ExcelWriter(filepath) as writer: - assert isinstance(writer, DummyClass) - df = tm.makeCustomDataframe(1, 1) - check_called(lambda: df.to_excel(filepath)) - with tm.ensure_clean("something.xls") as filepath: - check_called(lambda: df.to_excel(filepath, engine="dummy")) - - @pytest.mark.parametrize( - "ext", - [ - pytest.param(".xlsx", marks=td.skip_if_no("xlsxwriter")), - pytest.param(".xlsx", marks=td.skip_if_no("openpyxl")), - pytest.param(".ods", marks=td.skip_if_no("odf")), - ], - ) - def test_engine_kwargs_and_kwargs_raises(self, ext): - # GH 40430 - msg = re.escape("Cannot use both engine_kwargs and **kwargs") - with pytest.raises(ValueError, match=msg): - with ExcelWriter("", engine_kwargs={"a": 1}, b=2): - pass - - -@td.skip_if_no("xlrd") -@td.skip_if_no("openpyxl") -class TestFSPath: - def test_excelfile_fspath(self): - with tm.ensure_clean("foo.xlsx") as path: - df = DataFrame({"A": [1, 2]}) - df.to_excel(path) - with ExcelFile(path) as xl: - result = os.fspath(xl) - assert result == path - - def test_excelwriter_fspath(self): - with tm.ensure_clean("foo.xlsx") as path: - with ExcelWriter(path) as writer: - assert os.fspath(writer) == str(path) diff --git a/pandas/tests/io/excel/test_xlrd.py b/pandas/tests/io/excel/test_xlrd.py deleted file mode 100644 index 2309187b8e9af..0000000000000 --- a/pandas/tests/io/excel/test_xlrd.py +++ /dev/null @@ -1,109 +0,0 @@ -import io - -import pytest - -from pandas.compat._optional import import_optional_dependency - -import pandas as pd -import pandas._testing as tm -from pandas.tests.io.excel import xlrd_version -from pandas.util.version import Version - -from pandas.io.excel import ExcelFile -from pandas.io.excel._base import inspect_excel_format - -xlrd = pytest.importorskip("xlrd") -xlwt = pytest.importorskip("xlwt") - -pytestmark = pytest.mark.filterwarnings( - "ignore:As the xlwt package is no longer maintained:FutureWarning" -) - - -# error: Unsupported operand types for <= ("Version" and "None") -if xlrd_version >= Version("2"): # type: ignore[operator] - exts = [".xls"] -else: - exts = [".xls", ".xlsx", ".xlsm"] - - -@pytest.fixture(params=exts) -def read_ext_xlrd(request): - """ - Valid extensions for reading Excel files with xlrd. - - Similar to read_ext, but excludes .ods, .xlsb, and for xlrd>2 .xlsx, .xlsm - """ - return request.param - - -def test_read_xlrd_book(read_ext_xlrd, frame): - df = frame - - engine = "xlrd" - sheet_name = "SheetA" - - with tm.ensure_clean(read_ext_xlrd) as pth: - df.to_excel(pth, sheet_name) - book = xlrd.open_workbook(pth) - - with ExcelFile(book, engine=engine) as xl: - result = pd.read_excel(xl, sheet_name=sheet_name, index_col=0) - tm.assert_frame_equal(df, result) - - result = pd.read_excel(book, sheet_name=sheet_name, engine=engine, index_col=0) - tm.assert_frame_equal(df, result) - - -def test_excel_file_warning_with_xlsx_file(datapath): - # GH 29375 - path = datapath("io", "data", "excel", "test1.xlsx") - has_openpyxl = import_optional_dependency("openpyxl", errors="ignore") is not None - if not has_openpyxl: - with tm.assert_produces_warning( - FutureWarning, - raise_on_extra_warnings=False, - match="The xlrd engine is no longer maintained", - ): - ExcelFile(path, engine=None) - else: - with tm.assert_produces_warning(None): - pd.read_excel(path, "Sheet1", engine=None) - - -def test_read_excel_warning_with_xlsx_file(datapath): - # GH 29375 - path = datapath("io", "data", "excel", "test1.xlsx") - has_openpyxl = import_optional_dependency("openpyxl", errors="ignore") is not None - if not has_openpyxl: - if xlrd_version >= Version("2"): - with pytest.raises( - ValueError, - match="Your version of xlrd is ", - ): - pd.read_excel(path, "Sheet1", engine=None) - else: - with tm.assert_produces_warning( - FutureWarning, - raise_on_extra_warnings=False, - match="The xlrd engine is no longer maintained", - ): - pd.read_excel(path, "Sheet1", engine=None) - else: - with tm.assert_produces_warning(None): - pd.read_excel(path, "Sheet1", engine=None) - - -@pytest.mark.parametrize( - "file_header", - [ - b"\x09\x00\x04\x00\x07\x00\x10\x00", - b"\x09\x02\x06\x00\x00\x00\x10\x00", - b"\x09\x04\x06\x00\x00\x00\x10\x00", - b"\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1", - ], -) -def test_read_old_xls_files(file_header): - # GH 41226 - f = io.BytesIO(file_header) - assert inspect_excel_format(f) == "xls" diff --git a/pandas/tests/io/excel/test_xlsxwriter.py b/pandas/tests/io/excel/test_xlsxwriter.py deleted file mode 100644 index 79d2f55a9b8ff..0000000000000 --- a/pandas/tests/io/excel/test_xlsxwriter.py +++ /dev/null @@ -1,84 +0,0 @@ -import re -import warnings - -import pytest - -from pandas import DataFrame -import pandas._testing as tm - -from pandas.io.excel import ExcelWriter - -xlsxwriter = pytest.importorskip("xlsxwriter") - -pytestmark = pytest.mark.parametrize("ext", [".xlsx"]) - - -def test_column_format(ext): - # Test that column formats are applied to cells. Test for issue #9167. - # Applicable to xlsxwriter only. - with warnings.catch_warnings(): - # Ignore the openpyxl lxml warning. - warnings.simplefilter("ignore") - openpyxl = pytest.importorskip("openpyxl") - - with tm.ensure_clean(ext) as path: - frame = DataFrame({"A": [123456, 123456], "B": [123456, 123456]}) - - with ExcelWriter(path) as writer: - frame.to_excel(writer) - - # Add a number format to col B and ensure it is applied to cells. - num_format = "#,##0" - write_workbook = writer.book - write_worksheet = write_workbook.worksheets()[0] - col_format = write_workbook.add_format({"num_format": num_format}) - write_worksheet.set_column("B:B", None, col_format) - - read_workbook = openpyxl.load_workbook(path) - try: - read_worksheet = read_workbook["Sheet1"] - except TypeError: - # compat - read_worksheet = read_workbook.get_sheet_by_name(name="Sheet1") - - # Get the number format from the cell. - try: - cell = read_worksheet["B2"] - except TypeError: - # compat - cell = read_worksheet.cell("B2") - - try: - read_num_format = cell.number_format - except AttributeError: - read_num_format = cell.style.number_format._format_code - - assert read_num_format == num_format - - -def test_write_append_mode_raises(ext): - msg = "Append mode is not supported with xlsxwriter!" - - with tm.ensure_clean(ext) as f: - with pytest.raises(ValueError, match=msg): - ExcelWriter(f, engine="xlsxwriter", mode="a") - - -@pytest.mark.parametrize("nan_inf_to_errors", [True, False]) -def test_kwargs(ext, nan_inf_to_errors): - # GH 42286 - kwargs = {"options": {"nan_inf_to_errors": nan_inf_to_errors}} - with tm.ensure_clean(ext) as f: - msg = re.escape("Use of **kwargs is deprecated") - with tm.assert_produces_warning(FutureWarning, match=msg): - with ExcelWriter(f, engine="xlsxwriter", **kwargs) as writer: - assert writer.book.nan_inf_to_errors == nan_inf_to_errors - - -@pytest.mark.parametrize("nan_inf_to_errors", [True, False]) -def test_engine_kwargs(ext, nan_inf_to_errors): - # GH 42286 - engine_kwargs = {"options": {"nan_inf_to_errors": nan_inf_to_errors}} - with tm.ensure_clean(ext) as f: - with ExcelWriter(f, engine="xlsxwriter", engine_kwargs=engine_kwargs) as writer: - assert writer.book.nan_inf_to_errors == nan_inf_to_errors diff --git a/pandas/tests/io/excel/test_xlwt.py b/pandas/tests/io/excel/test_xlwt.py deleted file mode 100644 index ec333defd85ac..0000000000000 --- a/pandas/tests/io/excel/test_xlwt.py +++ /dev/null @@ -1,127 +0,0 @@ -import re - -import numpy as np -import pytest - -from pandas import ( - DataFrame, - MultiIndex, - options, -) -import pandas._testing as tm - -from pandas.io.excel import ( - ExcelWriter, - _XlwtWriter, -) - -xlwt = pytest.importorskip("xlwt") - -pytestmark = pytest.mark.parametrize("ext,", [".xls"]) - - -def test_excel_raise_error_on_multiindex_columns_and_no_index(ext): - # MultiIndex as columns is not yet implemented 9794 - cols = MultiIndex.from_tuples( - [("site", ""), ("2014", "height"), ("2014", "weight")] - ) - df = DataFrame(np.random.randn(10, 3), columns=cols) - - msg = ( - "Writing to Excel with MultiIndex columns and no index " - "\\('index'=False\\) is not yet implemented." - ) - with pytest.raises(NotImplementedError, match=msg): - with tm.ensure_clean(ext) as path: - df.to_excel(path, index=False) - - -def test_excel_multiindex_columns_and_index_true(ext): - cols = MultiIndex.from_tuples( - [("site", ""), ("2014", "height"), ("2014", "weight")] - ) - df = DataFrame(np.random.randn(10, 3), columns=cols) - with tm.ensure_clean(ext) as path: - df.to_excel(path, index=True) - - -def test_excel_multiindex_index(ext): - # MultiIndex as index works so assert no error #9794 - cols = MultiIndex.from_tuples( - [("site", ""), ("2014", "height"), ("2014", "weight")] - ) - df = DataFrame(np.random.randn(3, 10), index=cols) - with tm.ensure_clean(ext) as path: - df.to_excel(path, index=False) - - -def test_to_excel_styleconverter(ext): - hstyle = { - "font": {"bold": True}, - "borders": {"top": "thin", "right": "thin", "bottom": "thin", "left": "thin"}, - "alignment": {"horizontal": "center", "vertical": "top"}, - } - - xls_style = _XlwtWriter._convert_to_style(hstyle) - assert xls_style.font.bold - assert xlwt.Borders.THIN == xls_style.borders.top - assert xlwt.Borders.THIN == xls_style.borders.right - assert xlwt.Borders.THIN == xls_style.borders.bottom - assert xlwt.Borders.THIN == xls_style.borders.left - assert xlwt.Alignment.HORZ_CENTER == xls_style.alignment.horz - assert xlwt.Alignment.VERT_TOP == xls_style.alignment.vert - - -def test_write_append_mode_raises(ext): - msg = "Append mode is not supported with xlwt!" - - with tm.ensure_clean(ext) as f: - with pytest.raises(ValueError, match=msg): - ExcelWriter(f, engine="xlwt", mode="a") - - -def test_to_excel_xlwt_warning(ext): - # GH 26552 - df = DataFrame(np.random.randn(3, 10)) - with tm.ensure_clean(ext) as path: - with tm.assert_produces_warning( - FutureWarning, - match="As the xlwt package is no longer maintained", - ): - df.to_excel(path) - - -def test_option_xls_writer_deprecated(ext): - # GH 26552 - with tm.assert_produces_warning( - FutureWarning, - match="As the xlwt package is no longer maintained", - check_stacklevel=False, - ): - options.io.excel.xls.writer = "xlwt" - - -@pytest.mark.parametrize("style_compression", [0, 2]) -def test_kwargs(ext, style_compression): - # GH 42286 - kwargs = {"style_compression": style_compression} - with tm.ensure_clean(ext) as f: - msg = re.escape("Use of **kwargs is deprecated") - with tm.assert_produces_warning(FutureWarning, match=msg): - with ExcelWriter(f, engine="xlwt", **kwargs) as writer: - assert ( - writer.book._Workbook__styles.style_compression == style_compression - ) - # xlwt won't allow us to close without writing something - DataFrame().to_excel(writer) - - -@pytest.mark.parametrize("style_compression", [0, 2]) -def test_engine_kwargs(ext, style_compression): - # GH 42286 - engine_kwargs = {"style_compression": style_compression} - with tm.ensure_clean(ext) as f: - with ExcelWriter(f, engine="xlwt", engine_kwargs=engine_kwargs) as writer: - assert writer.book._Workbook__styles.style_compression == style_compression - # xlwt won't allow us to close without writing something - DataFrame().to_excel(writer) diff --git a/pandas/tests/io/formats/__init__.py b/pandas/tests/io/formats/__init__.py deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/pandas/tests/io/formats/data/html/datetime64_hourformatter.html b/pandas/tests/io/formats/data/html/datetime64_hourformatter.html deleted file mode 100644 index c92b7218eba76..0000000000000 --- a/pandas/tests/io/formats/data/html/datetime64_hourformatter.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - -
hod
010:10
112:12
diff --git a/pandas/tests/io/formats/data/html/datetime64_monthformatter.html b/pandas/tests/io/formats/data/html/datetime64_monthformatter.html deleted file mode 100644 index 589c8fba858a5..0000000000000 --- a/pandas/tests/io/formats/data/html/datetime64_monthformatter.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - -
months
02016-01
12016-02
diff --git a/pandas/tests/io/formats/data/html/escape_disabled.html b/pandas/tests/io/formats/data/html/escape_disabled.html deleted file mode 100644 index 260a04d26108b..0000000000000 --- a/pandas/tests/io/formats/data/html/escape_disabled.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - -
co - co>l2
str - boldbold
stri>ng2 &boldbold
diff --git a/pandas/tests/io/formats/data/html/escaped.html b/pandas/tests/io/formats/data/html/escaped.html deleted file mode 100644 index d68bdd3df79c4..0000000000000 --- a/pandas/tests/io/formats/data/html/escaped.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
co<l1co>l2
str<ing1 &amp;<type 'str'><type 'str'>
stri>ng2 &amp;<type 'str'><type 'str'>
diff --git a/pandas/tests/io/formats/data/html/gh12031_expected_output.html b/pandas/tests/io/formats/data/html/gh12031_expected_output.html deleted file mode 100644 index 896e154a2b324..0000000000000 --- a/pandas/tests/io/formats/data/html/gh12031_expected_output.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - -
A
06,0
13,1
22,2
diff --git a/pandas/tests/io/formats/data/html/gh13828_expected_output.html b/pandas/tests/io/formats/data/html/gh13828_expected_output.html deleted file mode 100644 index 690d638c31d5b..0000000000000 --- a/pandas/tests/io/formats/data/html/gh13828_expected_output.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
GroupData
0A1.22
1A{na_rep}
diff --git a/pandas/tests/io/formats/data/html/gh14882_expected_output_1.html b/pandas/tests/io/formats/data/html/gh14882_expected_output_1.html deleted file mode 100644 index 4cfd8785de825..0000000000000 --- a/pandas/tests/io/formats/data/html/gh14882_expected_output_1.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
n
abc
1001010
21
32
43
54
65
76
2017
28
39
410
511
612
713
30114
215
316
417
518
619
720
20010121
222
323
424
525
626
727
20128
229
......
633
734
30135
236
337
438
539
640
741
30010142
243
344
445
546
647
748
20149
250
351
452
553
654
755
30156
257
358
459
560
661
762
diff --git a/pandas/tests/io/formats/data/html/gh14882_expected_output_2.html b/pandas/tests/io/formats/data/html/gh14882_expected_output_2.html deleted file mode 100644 index d4e7fd9bd8135..0000000000000 --- a/pandas/tests/io/formats/data/html/gh14882_expected_output_2.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
n
abc
1001010
21
32
43
54
65
76
2017
28
39
410
511
612
713
30114
215
316
417
518
619
720
20010121
222
323
424
525
626
727
.........
30135
236
337
438
539
640
741
30010142
243
344
445
546
647
748
20149
250
351
452
553
654
755
30156
257
358
459
560
661
762
diff --git a/pandas/tests/io/formats/data/html/gh14998_expected_output.html b/pandas/tests/io/formats/data/html/gh14998_expected_output.html deleted file mode 100644 index 62b96493a8ecd..0000000000000 --- a/pandas/tests/io/formats/data/html/gh14998_expected_output.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - -
A
1
diff --git a/pandas/tests/io/formats/data/html/gh15019_expected_output.html b/pandas/tests/io/formats/data/html/gh15019_expected_output.html deleted file mode 100644 index 5fb9d960f4465..0000000000000 --- a/pandas/tests/io/formats/data/html/gh15019_expected_output.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01
1.7640520.400157
0.9787382.240893
......
0.950088-0.151357
-0.1032190.410599
diff --git a/pandas/tests/io/formats/data/html/gh21625_expected_output.html b/pandas/tests/io/formats/data/html/gh21625_expected_output.html deleted file mode 100644 index a87e4ca301d9d..0000000000000 --- a/pandas/tests/io/formats/data/html/gh21625_expected_output.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - -
x
00.200
\ No newline at end of file diff --git a/pandas/tests/io/formats/data/html/gh22270_expected_output.html b/pandas/tests/io/formats/data/html/gh22270_expected_output.html deleted file mode 100644 index 6694c43dc9e68..0000000000000 --- a/pandas/tests/io/formats/data/html/gh22270_expected_output.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - -
x
0100
\ No newline at end of file diff --git a/pandas/tests/io/formats/data/html/gh22579_expected_output.html b/pandas/tests/io/formats/data/html/gh22579_expected_output.html deleted file mode 100644 index 425b0f915ed16..0000000000000 --- a/pandas/tests/io/formats/data/html/gh22579_expected_output.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ab
cdcd
0101010
1111111
2121212
3131313
4141414
5151515
6161616
7171717
8181818
9191919
diff --git a/pandas/tests/io/formats/data/html/gh22783_expected_output.html b/pandas/tests/io/formats/data/html/gh22783_expected_output.html deleted file mode 100644 index 107db43c48639..0000000000000 --- a/pandas/tests/io/formats/data/html/gh22783_expected_output.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...34
1.7640520.400157...2.2408931.867558
-0.9772780.950088...-0.1032190.410599
diff --git a/pandas/tests/io/formats/data/html/gh22783_named_columns_index.html b/pandas/tests/io/formats/data/html/gh22783_named_columns_index.html deleted file mode 100644 index 55ab290920cc5..0000000000000 --- a/pandas/tests/io/formats/data/html/gh22783_named_columns_index.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01...34
1.7640520.400157...2.2408931.867558
-0.9772780.950088...-0.1032190.410599
diff --git a/pandas/tests/io/formats/data/html/gh40024_expected_output.html b/pandas/tests/io/formats/data/html/gh40024_expected_output.html deleted file mode 100644 index 0877c29525d2c..0000000000000 --- a/pandas/tests/io/formats/data/html/gh40024_expected_output.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - -
x
01,000
1test
diff --git a/pandas/tests/io/formats/data/html/gh6131_expected_output.html b/pandas/tests/io/formats/data/html/gh6131_expected_output.html deleted file mode 100644 index cb3a3363ff016..0000000000000 --- a/pandas/tests/io/formats/data/html/gh6131_expected_output.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
d
aaa...ac
bc
baca1.0...NaN
bbcbNaN...NaN
bcccNaN...3.0
diff --git a/pandas/tests/io/formats/data/html/gh8452_expected_output.html b/pandas/tests/io/formats/data/html/gh8452_expected_output.html deleted file mode 100644 index 81ce397a201e0..0000000000000 --- a/pandas/tests/io/formats/data/html/gh8452_expected_output.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ab
cdcd
0353
1464
diff --git a/pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_12.html b/pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_12.html deleted file mode 100644 index 4eb3f5319749d..0000000000000 --- a/pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_12.html +++ /dev/null @@ -1,70 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
00
11
22
33
44
......
5656
5757
5858
5959
6060
-

61 rows × 1 columns

-
diff --git a/pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_4.html b/pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_4.html deleted file mode 100644 index 2b1d97aec517c..0000000000000 --- a/pandas/tests/io/formats/data/html/html_repr_max_rows_10_min_rows_4.html +++ /dev/null @@ -1,46 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
00
11
......
5959
6060
-

61 rows × 1 columns

-
diff --git a/pandas/tests/io/formats/data/html/html_repr_max_rows_12_min_rows_None.html b/pandas/tests/io/formats/data/html/html_repr_max_rows_12_min_rows_None.html deleted file mode 100644 index a539e5a4884a1..0000000000000 --- a/pandas/tests/io/formats/data/html/html_repr_max_rows_12_min_rows_None.html +++ /dev/null @@ -1,78 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
00
11
22
33
44
55
......
5555
5656
5757
5858
5959
6060
-

61 rows × 1 columns

-
diff --git a/pandas/tests/io/formats/data/html/html_repr_max_rows_None_min_rows_12.html b/pandas/tests/io/formats/data/html/html_repr_max_rows_None_min_rows_12.html deleted file mode 100644 index 3e680a505c6d6..0000000000000 --- a/pandas/tests/io/formats/data/html/html_repr_max_rows_None_min_rows_12.html +++ /dev/null @@ -1,269 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
00
11
22
33
44
55
66
77
88
99
1010
1111
1212
1313
1414
1515
1616
1717
1818
1919
2020
2121
2222
2323
2424
2525
2626
2727
2828
2929
3030
3131
3232
3333
3434
3535
3636
3737
3838
3939
4040
4141
4242
4343
4444
4545
4646
4747
4848
4949
5050
5151
5252
5353
5454
5555
5656
5757
5858
5959
6060
-
diff --git a/pandas/tests/io/formats/data/html/html_repr_min_rows_default_no_truncation.html b/pandas/tests/io/formats/data/html/html_repr_min_rows_default_no_truncation.html deleted file mode 100644 index 10f6247e37def..0000000000000 --- a/pandas/tests/io/formats/data/html/html_repr_min_rows_default_no_truncation.html +++ /dev/null @@ -1,105 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
00
11
22
33
44
55
66
77
88
99
1010
1111
1212
1313
1414
1515
1616
1717
1818
1919
-
diff --git a/pandas/tests/io/formats/data/html/html_repr_min_rows_default_truncated.html b/pandas/tests/io/formats/data/html/html_repr_min_rows_default_truncated.html deleted file mode 100644 index 4eb3f5319749d..0000000000000 --- a/pandas/tests/io/formats/data/html/html_repr_min_rows_default_truncated.html +++ /dev/null @@ -1,70 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
00
11
22
33
44
......
5656
5757
5858
5959
6060
-

61 rows × 1 columns

-
diff --git a/pandas/tests/io/formats/data/html/index_1.html b/pandas/tests/io/formats/data/html/index_1.html deleted file mode 100644 index 41221865a7cb7..0000000000000 --- a/pandas/tests/io/formats/data/html/index_1.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ABC
foo11.2one
bar23.4two
baz35.6NaN
diff --git a/pandas/tests/io/formats/data/html/index_2.html b/pandas/tests/io/formats/data/html/index_2.html deleted file mode 100644 index a86ba80a69bb1..0000000000000 --- a/pandas/tests/io/formats/data/html/index_2.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -
ABC
11.2one
23.4two
35.6NaN
diff --git a/pandas/tests/io/formats/data/html/index_3.html b/pandas/tests/io/formats/data/html/index_3.html deleted file mode 100644 index 02edba4961bc7..0000000000000 --- a/pandas/tests/io/formats/data/html/index_3.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ABC
idx
foo11.2one
bar23.4two
baz35.6NaN
diff --git a/pandas/tests/io/formats/data/html/index_4.html b/pandas/tests/io/formats/data/html/index_4.html deleted file mode 100644 index 0d1bf9ffcd717..0000000000000 --- a/pandas/tests/io/formats/data/html/index_4.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ABC
foocar11.2one
bike23.4two
barcar35.6NaN
diff --git a/pandas/tests/io/formats/data/html/index_5.html b/pandas/tests/io/formats/data/html/index_5.html deleted file mode 100644 index c5ac12ecd630e..0000000000000 --- a/pandas/tests/io/formats/data/html/index_5.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ABC
idx1idx2
foocar11.2one
bike23.4two
barcar35.6NaN
diff --git a/pandas/tests/io/formats/data/html/index_formatter.html b/pandas/tests/io/formats/data/html/index_formatter.html deleted file mode 100644 index 7a2f8a9f52a04..0000000000000 --- a/pandas/tests/io/formats/data/html/index_formatter.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fooNone
a01
b23
c45
d67
diff --git a/pandas/tests/io/formats/data/html/index_named_multi_columns_named_multi.html b/pandas/tests/io/formats/data/html/index_named_multi_columns_named_multi.html deleted file mode 100644 index 817b54d77f8b1..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_multi_columns_named_multi.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name.0a
columns.name.1bc
index.name.0index.name.1
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_named_multi_columns_named_standard.html b/pandas/tests/io/formats/data/html/index_named_multi_columns_named_standard.html deleted file mode 100644 index e85965f14075d..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_multi_columns_named_standard.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01
index.name.0index.name.1
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_named_multi_columns_none.html b/pandas/tests/io/formats/data/html/index_named_multi_columns_none.html deleted file mode 100644 index 8c41d2e29f2c0..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_multi_columns_none.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -
index.name.0index.name.1
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_multi.html deleted file mode 100644 index 7af63e893b12e..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_multi.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
bc
index.name.0index.name.1
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_standard.html deleted file mode 100644 index 2f7837864bf88..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_multi_columns_unnamed_standard.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01
index.name.0index.name.1
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_named_standard_columns_named_multi.html b/pandas/tests/io/formats/data/html/index_named_standard_columns_named_multi.html deleted file mode 100644 index ca9b8bd834a9c..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_standard_columns_named_multi.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name.0a
columns.name.1bc
index.name
000
100
diff --git a/pandas/tests/io/formats/data/html/index_named_standard_columns_named_standard.html b/pandas/tests/io/formats/data/html/index_named_standard_columns_named_standard.html deleted file mode 100644 index 6478c99ad85e9..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_standard_columns_named_standard.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01
index.name
000
100
diff --git a/pandas/tests/io/formats/data/html/index_named_standard_columns_none.html b/pandas/tests/io/formats/data/html/index_named_standard_columns_none.html deleted file mode 100644 index 432d8e06d5784..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_standard_columns_none.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
index.name
000
100
diff --git a/pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_multi.html deleted file mode 100644 index d7660872177dc..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_multi.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
bc
index.name
000
100
diff --git a/pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_standard.html deleted file mode 100644 index 4810f66018d3b..0000000000000 --- a/pandas/tests/io/formats/data/html/index_named_standard_columns_unnamed_standard.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -
01
index.name
000
100
diff --git a/pandas/tests/io/formats/data/html/index_none_columns_named_multi.html b/pandas/tests/io/formats/data/html/index_none_columns_named_multi.html deleted file mode 100644 index e111f55be7d25..0000000000000 --- a/pandas/tests/io/formats/data/html/index_none_columns_named_multi.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name.0a
columns.name.1bc
00
00
diff --git a/pandas/tests/io/formats/data/html/index_none_columns_named_standard.html b/pandas/tests/io/formats/data/html/index_none_columns_named_standard.html deleted file mode 100644 index d3a9ba017b43e..0000000000000 --- a/pandas/tests/io/formats/data/html/index_none_columns_named_standard.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
columns.name01
00
00
diff --git a/pandas/tests/io/formats/data/html/index_none_columns_none.html b/pandas/tests/io/formats/data/html/index_none_columns_none.html deleted file mode 100644 index 44899858d9519..0000000000000 --- a/pandas/tests/io/formats/data/html/index_none_columns_none.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - -
00
00
diff --git a/pandas/tests/io/formats/data/html/index_none_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/index_none_columns_unnamed_multi.html deleted file mode 100644 index b21a618328b1b..0000000000000 --- a/pandas/tests/io/formats/data/html/index_none_columns_unnamed_multi.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
a
bc
00
00
diff --git a/pandas/tests/io/formats/data/html/index_none_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/index_none_columns_unnamed_standard.html deleted file mode 100644 index 1249fa5605099..0000000000000 --- a/pandas/tests/io/formats/data/html/index_none_columns_unnamed_standard.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - -
01
00
00
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_multi.html b/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_multi.html deleted file mode 100644 index 95c38c9c8fd28..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_multi.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name.0a
columns.name.1bc
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_standard.html b/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_standard.html deleted file mode 100644 index 9583a21f55f01..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_named_standard.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -
columns.name01
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_none.html b/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_none.html deleted file mode 100644 index 81da7c3619abc..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_none.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - -
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_multi.html deleted file mode 100644 index f620259037b60..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_multi.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a
bc
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_standard.html deleted file mode 100644 index 2ca18c288437b..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_multi_columns_unnamed_standard.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -
01
ab00
c00
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_multi.html b/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_multi.html deleted file mode 100644 index ed3360f898afd..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_multi.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name.0a
columns.name.1bc
000
100
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_standard.html b/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_standard.html deleted file mode 100644 index 54da03858a9a4..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_named_standard.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
columns.name01
000
100
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_none.html b/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_none.html deleted file mode 100644 index 3d958afe4a4ac..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_none.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - -
000
100
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_multi.html deleted file mode 100644 index b57fafbe0ca40..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_multi.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -
a
bc
000
100
diff --git a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_standard.html deleted file mode 100644 index 235ca61a9e63d..0000000000000 --- a/pandas/tests/io/formats/data/html/index_unnamed_standard_columns_unnamed_standard.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
01
000
100
diff --git a/pandas/tests/io/formats/data/html/justify.html b/pandas/tests/io/formats/data/html/justify.html deleted file mode 100644 index 33e4b5715260e..0000000000000 --- a/pandas/tests/io/formats/data/html/justify.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ABC
061223442
13000020
22700001
diff --git a/pandas/tests/io/formats/data/html/multiindex_1.html b/pandas/tests/io/formats/data/html/multiindex_1.html deleted file mode 100644 index 88db177545972..0000000000000 --- a/pandas/tests/io/formats/data/html/multiindex_1.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CL001
CL10101
0abcd
1efgh
diff --git a/pandas/tests/io/formats/data/html/multiindex_2.html b/pandas/tests/io/formats/data/html/multiindex_2.html deleted file mode 100644 index 289ea2202d6b9..0000000000000 --- a/pandas/tests/io/formats/data/html/multiindex_2.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0123
0101
0abcd
1efgh
diff --git a/pandas/tests/io/formats/data/html/multiindex_sparsify_1.html b/pandas/tests/io/formats/data/html/multiindex_sparsify_1.html deleted file mode 100644 index 5b5bcf9ce0a96..0000000000000 --- a/pandas/tests/io/formats/data/html/multiindex_sparsify_1.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01
foo
0001
123
1045
167
diff --git a/pandas/tests/io/formats/data/html/multiindex_sparsify_2.html b/pandas/tests/io/formats/data/html/multiindex_sparsify_2.html deleted file mode 100644 index fd4c6bd23dae2..0000000000000 --- a/pandas/tests/io/formats/data/html/multiindex_sparsify_2.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
foo01
00
foo
0001
123
1045
167
diff --git a/pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_1.html b/pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_1.html deleted file mode 100644 index 42a5ea5eb5899..0000000000000 --- a/pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_1.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01
foo
0001
0123
1045
1167
diff --git a/pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_2.html b/pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_2.html deleted file mode 100644 index 2be61392e8573..0000000000000 --- a/pandas/tests/io/formats/data/html/multiindex_sparsify_false_multi_sparse_2.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
foo01
00
foo
0001
0123
1045
1167
diff --git a/pandas/tests/io/formats/data/html/render_links_false.html b/pandas/tests/io/formats/data/html/render_links_false.html deleted file mode 100644 index 6feb403d63051..0000000000000 --- a/pandas/tests/io/formats/data/html/render_links_false.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -
foobarNone
00https://pandas.pydata.org/?q1=a&q2=bpydata.org
10www.pydata.orgpydata.org
diff --git a/pandas/tests/io/formats/data/html/render_links_true.html b/pandas/tests/io/formats/data/html/render_links_true.html deleted file mode 100644 index 3eb53f3160a77..0000000000000 --- a/pandas/tests/io/formats/data/html/render_links_true.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -
foobarNone
00https://pandas.pydata.org/?q1=a&q2=bpydata.org
10www.pydata.orgpydata.org
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_multi.html deleted file mode 100644 index e66d3c816e67d..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_multi.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fooa...b
c...d
bazef...ef
foobaz
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_standard.html deleted file mode 100644 index 536b371145081..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_named_standard.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01...67
foobaz
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_none.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_none.html deleted file mode 100644 index 0f262495b6c6b..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_none.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
foobaz
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_multi.html deleted file mode 100644 index d472cdecb12c9..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_multi.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a...b
c...d
ef...ef
foobaz
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_standard.html deleted file mode 100644 index 31c71ca3e59f6..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_multi_columns_unnamed_standard.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...67
foobaz
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_multi.html deleted file mode 100644 index 779e84f6ee6d1..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_multi.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fooa...b
c...d
bazef...ef
index.name
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_standard.html deleted file mode 100644 index b86454f5fb11f..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_named_standard.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01...67
index.name
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_none.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_none.html deleted file mode 100644 index d294a507dbce4..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_none.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
index.name
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_multi.html deleted file mode 100644 index 24b776e18bef9..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_multi.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a...b
c...d
ef...ef
index.name
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_standard.html deleted file mode 100644 index a0ca960207ac0..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_named_standard_columns_unnamed_standard.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...67
index.name
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_multi.html deleted file mode 100644 index 6640db4cf8704..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_multi.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fooa...b
c...d
bazef...ef
01...67
89...1415
..................
4849...5455
5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_standard.html deleted file mode 100644 index 364a0b98d6548..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_named_standard.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01...67
01...67
89...1415
..................
4849...5455
5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_none.html b/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_none.html deleted file mode 100644 index e2af1ba42e940..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_none.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...67
89...1415
...............
4849...5455
5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_multi.html deleted file mode 100644 index 8c9a9e244277b..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_multi.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a...b
c...d
ef...ef
01...67
89...1415
...............
4849...5455
5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_standard.html deleted file mode 100644 index b9dcf52619490..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_none_columns_unnamed_standard.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...67
01...67
89...1415
...............
4849...5455
5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_multi.html deleted file mode 100644 index 0590d0dea6669..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_multi.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fooa...b
c...d
bazef...ef
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_standard.html deleted file mode 100644 index 28a2d964675a3..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_named_standard.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01...67
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_none.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_none.html deleted file mode 100644 index 387ac51b17634..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_none.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_multi.html deleted file mode 100644 index 30cd85904be4e..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_multi.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a...b
c...d
ef...ef
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_standard.html deleted file mode 100644 index 81edece220408..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_multi_columns_unnamed_standard.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...67
ace01...67
f89...1415
........................
bde4849...5455
f5657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_multi.html deleted file mode 100644 index 2acacfed3a6d0..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_multi.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fooa...b
c...d
bazef...ef
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_standard.html deleted file mode 100644 index c9bacdbd241a6..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_named_standard.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
columns.name01...67
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_none.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_none.html deleted file mode 100644 index f2696f7d6b46a..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_none.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_multi.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_multi.html deleted file mode 100644 index 37e731520c7d9..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_multi.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a...b
c...d
ef...ef
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_standard.html b/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_standard.html deleted file mode 100644 index 3241ff41c5c58..0000000000000 --- a/pandas/tests/io/formats/data/html/trunc_df_index_unnamed_standard_columns_unnamed_standard.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...67
001...67
189...1415
..................
64849...5455
75657...6263
diff --git a/pandas/tests/io/formats/data/html/truncate.html b/pandas/tests/io/formats/data/html/truncate.html deleted file mode 100644 index a5eb8c5cdbb9b..0000000000000 --- a/pandas/tests/io/formats/data/html/truncate.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01...1819
2001-01-01NaNNaN...NaNNaN
2001-01-02NaNNaN...NaNNaN
2001-01-03NaNNaN...NaNNaN
2001-01-04NaNNaN...NaNNaN
..................
2001-01-17NaNNaN...NaNNaN
2001-01-18NaNNaN...NaNNaN
2001-01-19NaNNaN...NaNNaN
2001-01-20NaNNaN...NaNNaN
diff --git a/pandas/tests/io/formats/data/html/truncate_formatter.html b/pandas/tests/io/formats/data/html/truncate_formatter.html deleted file mode 100644 index 7615ef89d85d1..0000000000000 --- a/pandas/tests/io/formats/data/html/truncate_formatter.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
A...D
01_mod...4
15_mod...8
29_mod...12
313_mod...16
diff --git a/pandas/tests/io/formats/data/html/truncate_multi_index.html b/pandas/tests/io/formats/data/html/truncate_multi_index.html deleted file mode 100644 index 8a295d66db130..0000000000000 --- a/pandas/tests/io/formats/data/html/truncate_multi_index.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
barbaz...fooqux
onetwoone...twoonetwo
baroneNaNNaNNaN...NaNNaNNaN
twoNaNNaNNaN...NaNNaNNaN
bazoneNaNNaNNaN...NaNNaNNaN
...........................
footwoNaNNaNNaN...NaNNaNNaN
quxoneNaNNaNNaN...NaNNaNNaN
twoNaNNaNNaN...NaNNaNNaN
diff --git a/pandas/tests/io/formats/data/html/truncate_multi_index_sparse_off.html b/pandas/tests/io/formats/data/html/truncate_multi_index_sparse_off.html deleted file mode 100644 index 6a7e1b5a59e3b..0000000000000 --- a/pandas/tests/io/formats/data/html/truncate_multi_index_sparse_off.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
barbarbaz...fooquxqux
onetwoone...twoonetwo
baroneNaNNaNNaN...NaNNaNNaN
bartwoNaNNaNNaN...NaNNaNNaN
bazoneNaNNaNNaN...NaNNaNNaN
...........................
footwoNaNNaNNaN...NaNNaNNaN
quxoneNaNNaNNaN...NaNNaNNaN
quxtwoNaNNaNNaN...NaNNaNNaN
diff --git a/pandas/tests/io/formats/data/html/unicode_1.html b/pandas/tests/io/formats/data/html/unicode_1.html deleted file mode 100644 index 72b810181bade..0000000000000 --- a/pandas/tests/io/formats/data/html/unicode_1.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
σ
00.0
11.0
22.0
33.0
44.0
55.0
66.0
77.0
88.0
99.0
diff --git a/pandas/tests/io/formats/data/html/unicode_2.html b/pandas/tests/io/formats/data/html/unicode_2.html deleted file mode 100644 index 79c088093e539..0000000000000 --- a/pandas/tests/io/formats/data/html/unicode_2.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - -
A
0σ
diff --git a/pandas/tests/io/formats/data/html/various_dtypes_formatted.html b/pandas/tests/io/formats/data/html/various_dtypes_formatted.html deleted file mode 100644 index 7d2ede3379213..0000000000000 --- a/pandas/tests/io/formats/data/html/various_dtypes_formatted.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ifIsbco
0formattedformattedformattedformattedformattedformattedformatted
1formattedformattedformattedformattedformattedformattedformatted
diff --git a/pandas/tests/io/formats/data/html/with_classes.html b/pandas/tests/io/formats/data/html/with_classes.html deleted file mode 100644 index 8cee3f0c7052b..0000000000000 --- a/pandas/tests/io/formats/data/html/with_classes.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - -
diff --git a/pandas/tests/io/formats/style/__init__.py b/pandas/tests/io/formats/style/__init__.py deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/pandas/tests/io/formats/style/test_bar.py b/pandas/tests/io/formats/style/test_bar.py deleted file mode 100644 index 19884aaac86a7..0000000000000 --- a/pandas/tests/io/formats/style/test_bar.py +++ /dev/null @@ -1,307 +0,0 @@ -import numpy as np -import pytest - -from pandas import DataFrame - -pytest.importorskip("jinja2") - - -def bar_grad(a=None, b=None, c=None, d=None): - """Used in multiple tests to simplify formatting of expected result""" - ret = [("width", "10em")] - if all(x is None for x in [a, b, c, d]): - return ret - return ret + [ - ( - "background", - f"linear-gradient(90deg,{','.join([x for x in [a, b, c, d] if x])})", - ) - ] - - -def no_bar(): - return bar_grad() - - -def bar_to(x, color="#d65f5f"): - return bar_grad(f" {color} {x:.1f}%", f" transparent {x:.1f}%") - - -def bar_from_to(x, y, color="#d65f5f"): - return bar_grad( - f" transparent {x:.1f}%", - f" {color} {x:.1f}%", - f" {color} {y:.1f}%", - f" transparent {y:.1f}%", - ) - - -@pytest.fixture -def df_pos(): - return DataFrame([[1], [2], [3]]) - - -@pytest.fixture -def df_neg(): - return DataFrame([[-1], [-2], [-3]]) - - -@pytest.fixture -def df_mix(): - return DataFrame([[-3], [1], [2]]) - - -@pytest.mark.parametrize( - "align, exp", - [ - ("left", [no_bar(), bar_to(50), bar_to(100)]), - ("right", [bar_to(100), bar_from_to(50, 100), no_bar()]), - ("mid", [bar_to(33.33), bar_to(66.66), bar_to(100)]), - ("zero", [bar_from_to(50, 66.7), bar_from_to(50, 83.3), bar_from_to(50, 100)]), - ("mean", [bar_to(50), no_bar(), bar_from_to(50, 100)]), - (2.0, [bar_to(50), no_bar(), bar_from_to(50, 100)]), - (np.median, [bar_to(50), no_bar(), bar_from_to(50, 100)]), - ], -) -def test_align_positive_cases(df_pos, align, exp): - # test different align cases for all positive values - result = df_pos.style.bar(align=align)._compute().ctx - expected = {(0, 0): exp[0], (1, 0): exp[1], (2, 0): exp[2]} - assert result == expected - - -@pytest.mark.parametrize( - "align, exp", - [ - ("left", [bar_to(100), bar_to(50), no_bar()]), - ("right", [no_bar(), bar_from_to(50, 100), bar_to(100)]), - ("mid", [bar_from_to(66.66, 100), bar_from_to(33.33, 100), bar_to(100)]), - ("zero", [bar_from_to(33.33, 50), bar_from_to(16.66, 50), bar_to(50)]), - ("mean", [bar_from_to(50, 100), no_bar(), bar_to(50)]), - (-2.0, [bar_from_to(50, 100), no_bar(), bar_to(50)]), - (np.median, [bar_from_to(50, 100), no_bar(), bar_to(50)]), - ], -) -def test_align_negative_cases(df_neg, align, exp): - # test different align cases for all negative values - result = df_neg.style.bar(align=align)._compute().ctx - expected = {(0, 0): exp[0], (1, 0): exp[1], (2, 0): exp[2]} - assert result == expected - - -@pytest.mark.parametrize( - "align, exp", - [ - ("left", [no_bar(), bar_to(80), bar_to(100)]), - ("right", [bar_to(100), bar_from_to(80, 100), no_bar()]), - ("mid", [bar_to(60), bar_from_to(60, 80), bar_from_to(60, 100)]), - ("zero", [bar_to(50), bar_from_to(50, 66.66), bar_from_to(50, 83.33)]), - ("mean", [bar_to(50), bar_from_to(50, 66.66), bar_from_to(50, 83.33)]), - (-0.0, [bar_to(50), bar_from_to(50, 66.66), bar_from_to(50, 83.33)]), - (np.nanmedian, [bar_to(50), no_bar(), bar_from_to(50, 62.5)]), - ], -) -@pytest.mark.parametrize("nans", [True, False]) -def test_align_mixed_cases(df_mix, align, exp, nans): - # test different align cases for mixed positive and negative values - # also test no impact of NaNs and no_bar - expected = {(0, 0): exp[0], (1, 0): exp[1], (2, 0): exp[2]} - if nans: - df_mix.loc[3, :] = np.nan - expected.update({(3, 0): no_bar()}) - result = df_mix.style.bar(align=align)._compute().ctx - assert result == expected - - -@pytest.mark.parametrize( - "align, exp", - [ - ( - "left", - { - "index": [[no_bar(), no_bar()], [bar_to(100), bar_to(100)]], - "columns": [[no_bar(), bar_to(100)], [no_bar(), bar_to(100)]], - "none": [[no_bar(), bar_to(33.33)], [bar_to(66.66), bar_to(100)]], - }, - ), - ( - "mid", - { - "index": [[bar_to(33.33), bar_to(50)], [bar_to(100), bar_to(100)]], - "columns": [[bar_to(50), bar_to(100)], [bar_to(75), bar_to(100)]], - "none": [[bar_to(25), bar_to(50)], [bar_to(75), bar_to(100)]], - }, - ), - ( - "zero", - { - "index": [ - [bar_from_to(50, 66.66), bar_from_to(50, 75)], - [bar_from_to(50, 100), bar_from_to(50, 100)], - ], - "columns": [ - [bar_from_to(50, 75), bar_from_to(50, 100)], - [bar_from_to(50, 87.5), bar_from_to(50, 100)], - ], - "none": [ - [bar_from_to(50, 62.5), bar_from_to(50, 75)], - [bar_from_to(50, 87.5), bar_from_to(50, 100)], - ], - }, - ), - ( - 2, - { - "index": [ - [bar_to(50), no_bar()], - [bar_from_to(50, 100), bar_from_to(50, 100)], - ], - "columns": [ - [bar_to(50), no_bar()], - [bar_from_to(50, 75), bar_from_to(50, 100)], - ], - "none": [ - [bar_from_to(25, 50), no_bar()], - [bar_from_to(50, 75), bar_from_to(50, 100)], - ], - }, - ), - ], -) -@pytest.mark.parametrize("axis", ["index", "columns", "none"]) -def test_align_axis(align, exp, axis): - # test all axis combinations with positive values and different aligns - data = DataFrame([[1, 2], [3, 4]]) - result = ( - data.style.bar(align=align, axis=None if axis == "none" else axis) - ._compute() - .ctx - ) - expected = { - (0, 0): exp[axis][0][0], - (0, 1): exp[axis][0][1], - (1, 0): exp[axis][1][0], - (1, 1): exp[axis][1][1], - } - assert result == expected - - -@pytest.mark.parametrize( - "values, vmin, vmax", - [ - ("positive", 1.5, 2.5), - ("negative", -2.5, -1.5), - ("mixed", -2.5, 1.5), - ], -) -@pytest.mark.parametrize("nullify", [None, "vmin", "vmax"]) # test min/max separately -@pytest.mark.parametrize("align", ["left", "right", "zero", "mid"]) -def test_vmin_vmax_clipping(df_pos, df_neg, df_mix, values, vmin, vmax, nullify, align): - # test that clipping occurs if any vmin > data_values or vmax < data_values - if align == "mid": # mid acts as left or right in each case - if values == "positive": - align = "left" - elif values == "negative": - align = "right" - df = {"positive": df_pos, "negative": df_neg, "mixed": df_mix}[values] - vmin = None if nullify == "vmin" else vmin - vmax = None if nullify == "vmax" else vmax - - clip_df = df.where(df <= (vmax if vmax else 999), other=vmax) - clip_df = clip_df.where(clip_df >= (vmin if vmin else -999), other=vmin) - - result = ( - df.style.bar(align=align, vmin=vmin, vmax=vmax, color=["red", "green"]) - ._compute() - .ctx - ) - expected = clip_df.style.bar(align=align, color=["red", "green"])._compute().ctx - assert result == expected - - -@pytest.mark.parametrize( - "values, vmin, vmax", - [ - ("positive", 0.5, 4.5), - ("negative", -4.5, -0.5), - ("mixed", -4.5, 4.5), - ], -) -@pytest.mark.parametrize("nullify", [None, "vmin", "vmax"]) # test min/max separately -@pytest.mark.parametrize("align", ["left", "right", "zero", "mid"]) -def test_vmin_vmax_widening(df_pos, df_neg, df_mix, values, vmin, vmax, nullify, align): - # test that widening occurs if any vmax > data_values or vmin < data_values - if align == "mid": # mid acts as left or right in each case - if values == "positive": - align = "left" - elif values == "negative": - align = "right" - df = {"positive": df_pos, "negative": df_neg, "mixed": df_mix}[values] - vmin = None if nullify == "vmin" else vmin - vmax = None if nullify == "vmax" else vmax - - expand_df = df.copy() - expand_df.loc[3, :], expand_df.loc[4, :] = vmin, vmax - - result = ( - df.style.bar(align=align, vmin=vmin, vmax=vmax, color=["red", "green"]) - ._compute() - .ctx - ) - expected = expand_df.style.bar(align=align, color=["red", "green"])._compute().ctx - assert result.items() <= expected.items() - - -def test_numerics(): - # test data is pre-selected for numeric values - data = DataFrame([[1, "a"], [2, "b"]]) - result = data.style.bar()._compute().ctx - assert (0, 1) not in result - assert (1, 1) not in result - - -@pytest.mark.parametrize( - "align, exp", - [ - ("left", [no_bar(), bar_to(100, "green")]), - ("right", [bar_to(100, "red"), no_bar()]), - ("mid", [bar_to(25, "red"), bar_from_to(25, 100, "green")]), - ("zero", [bar_from_to(33.33, 50, "red"), bar_from_to(50, 100, "green")]), - ], -) -def test_colors_mixed(align, exp): - data = DataFrame([[-1], [3]]) - result = data.style.bar(align=align, color=["red", "green"])._compute().ctx - assert result == {(0, 0): exp[0], (1, 0): exp[1]} - - -def test_bar_align_height(): - # test when keyword height is used 'no-repeat center' and 'background-size' present - data = DataFrame([[1], [2]]) - result = data.style.bar(align="left", height=50)._compute().ctx - bg_s = "linear-gradient(90deg, #d65f5f 100.0%, transparent 100.0%) no-repeat center" - expected = { - (0, 0): [("width", "10em")], - (1, 0): [ - ("width", "10em"), - ("background", bg_s), - ("background-size", "100% 50.0%"), - ], - } - assert result == expected - - -def test_bar_value_error_raises(): - df = DataFrame({"A": [-100, -60, -30, -20]}) - - msg = "`align` should be in {'left', 'right', 'mid', 'mean', 'zero'} or" - with pytest.raises(ValueError, match=msg): - df.style.bar(align="poorly", color=["#d65f5f", "#5fba7d"]).to_html() - - msg = r"`width` must be a value in \[0, 100\]" - with pytest.raises(ValueError, match=msg): - df.style.bar(width=200).to_html() - - msg = r"`height` must be a value in \[0, 100\]" - with pytest.raises(ValueError, match=msg): - df.style.bar(height=200).to_html() diff --git a/pandas/tests/io/formats/style/test_deprecated.py b/pandas/tests/io/formats/style/test_deprecated.py deleted file mode 100644 index 9c96e3cf1ba81..0000000000000 --- a/pandas/tests/io/formats/style/test_deprecated.py +++ /dev/null @@ -1,165 +0,0 @@ -""" -modules collects tests for Styler methods which have been deprecated -""" -import numpy as np -import pytest - -jinja2 = pytest.importorskip("jinja2") - -from pandas import ( - DataFrame, - IndexSlice, - NaT, - Timestamp, -) -import pandas._testing as tm - - -@pytest.fixture -def df(): - return DataFrame({"A": [0, 1], "B": np.random.randn(2)}) - - -@pytest.mark.parametrize("axis", ["index", "columns"]) -def test_hide_index_columns(df, axis): - with tm.assert_produces_warning(FutureWarning): - getattr(df.style, "hide_" + axis)() - - -def test_set_non_numeric_na(): - # GH 21527 28358 - df = DataFrame( - { - "object": [None, np.nan, "foo"], - "datetime": [None, NaT, Timestamp("20120101")], - } - ) - - with tm.assert_produces_warning(FutureWarning): - ctx = df.style.set_na_rep("NA")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "NA" - assert ctx["body"][0][2]["display_value"] == "NA" - assert ctx["body"][1][1]["display_value"] == "NA" - assert ctx["body"][1][2]["display_value"] == "NA" - - -def test_where_with_one_style(df): - # GH 17474 - def f(x): - return x > 0.5 - - style1 = "foo: bar" - - with tm.assert_produces_warning(FutureWarning): - result = df.style.where(f, style1)._compute().ctx - expected = { - (r, c): [("foo", "bar")] - for r, row in enumerate(df.index) - for c, col in enumerate(df.columns) - if f(df.loc[row, col]) - } - assert result == expected - - -@pytest.mark.parametrize( - "slice_", - [ - IndexSlice[:], - IndexSlice[:, ["A"]], - IndexSlice[[1], :], - IndexSlice[[1], ["A"]], - IndexSlice[:2, ["A", "B"]], - ], -) -def test_where_subset(df, slice_): - # GH 17474 - def f(x): - return x > 0.5 - - style1 = "foo: bar" - style2 = "baz: foo" - - with tm.assert_produces_warning(FutureWarning): - res = df.style.where(f, style1, style2, subset=slice_)._compute().ctx - expected = { - (r, c): [("foo", "bar") if f(df.loc[row, col]) else ("baz", "foo")] - for r, row in enumerate(df.index) - for c, col in enumerate(df.columns) - if row in df.loc[slice_].index and col in df.loc[slice_].columns - } - assert res == expected - - -def test_where_subset_compare_with_applymap(df): - # GH 17474 - def f(x): - return x > 0.5 - - style1 = "foo: bar" - style2 = "baz: foo" - - def g(x): - return style1 if f(x) else style2 - - slices = [ - IndexSlice[:], - IndexSlice[:, ["A"]], - IndexSlice[[1], :], - IndexSlice[[1], ["A"]], - IndexSlice[:2, ["A", "B"]], - ] - - for slice_ in slices: - with tm.assert_produces_warning(FutureWarning): - result = df.style.where(f, style1, style2, subset=slice_)._compute().ctx - expected = df.style.applymap(g, subset=slice_)._compute().ctx - assert result == expected - - -def test_where_kwargs(): - df = DataFrame([[1, 2], [3, 4]]) - - def f(x, val): - return x > val - - with tm.assert_produces_warning(FutureWarning): - res = df.style.where(f, "color:green;", "color:red;", val=2)._compute().ctx - expected = { - (0, 0): [("color", "red")], - (0, 1): [("color", "red")], - (1, 0): [("color", "green")], - (1, 1): [("color", "green")], - } - assert res == expected - - -def test_set_na_rep(): - # GH 21527 28358 - df = DataFrame([[None, None], [1.1, 1.2]], columns=["A", "B"]) - - with tm.assert_produces_warning(FutureWarning): - ctx = df.style.set_na_rep("NA")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "NA" - assert ctx["body"][0][2]["display_value"] == "NA" - - with tm.assert_produces_warning(FutureWarning): - ctx = ( - df.style.set_na_rep("NA") - .format(None, na_rep="-", subset=["B"]) - ._translate(True, True) - ) - assert ctx["body"][0][1]["display_value"] == "NA" - assert ctx["body"][0][2]["display_value"] == "-" - - -def test_precision(df): - styler = df.style - with tm.assert_produces_warning(FutureWarning): - s2 = styler.set_precision(1) - assert styler is s2 - assert styler.precision == 1 - - -def test_render(df): - with tm.assert_produces_warning(FutureWarning): - df.style.render() diff --git a/pandas/tests/io/formats/style/test_format.py b/pandas/tests/io/formats/style/test_format.py deleted file mode 100644 index 5207be992d606..0000000000000 --- a/pandas/tests/io/formats/style/test_format.py +++ /dev/null @@ -1,436 +0,0 @@ -import numpy as np -import pytest - -from pandas import ( - NA, - DataFrame, - IndexSlice, - MultiIndex, - NaT, - Timestamp, - option_context, -) - -pytest.importorskip("jinja2") -from pandas.io.formats.style import Styler -from pandas.io.formats.style_render import _str_escape - - -@pytest.fixture -def df(): - return DataFrame( - data=[[0, -0.609], [1, -1.228]], - columns=["A", "B"], - index=["x", "y"], - ) - - -@pytest.fixture -def styler(df): - return Styler(df, uuid_len=0) - - -def test_display_format(styler): - ctx = styler.format("{:0.1f}")._translate(True, True) - assert all(["display_value" in c for c in row] for row in ctx["body"]) - assert all([len(c["display_value"]) <= 3 for c in row[1:]] for row in ctx["body"]) - assert len(ctx["body"][0][1]["display_value"].lstrip("-")) <= 3 - - -@pytest.mark.parametrize("index", [True, False]) -@pytest.mark.parametrize("columns", [True, False]) -def test_display_format_index(styler, index, columns): - exp_index = ["x", "y"] - if index: - styler.format_index(lambda v: v.upper(), axis=0) # test callable - exp_index = ["X", "Y"] - - exp_columns = ["A", "B"] - if columns: - styler.format_index("*{}*", axis=1) # test string - exp_columns = ["*A*", "*B*"] - - ctx = styler._translate(True, True) - - for r, row in enumerate(ctx["body"]): - assert row[0]["display_value"] == exp_index[r] - - for c, col in enumerate(ctx["head"][1:]): - assert col["display_value"] == exp_columns[c] - - -def test_format_dict(styler): - ctx = styler.format({"A": "{:0.1f}", "B": "{0:.2%}"})._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "0.0" - assert ctx["body"][0][2]["display_value"] == "-60.90%" - - -def test_format_index_dict(styler): - ctx = styler.format_index({0: lambda v: v.upper()})._translate(True, True) - for i, val in enumerate(["X", "Y"]): - assert ctx["body"][i][0]["display_value"] == val - - -def test_format_string(styler): - ctx = styler.format("{:.2f}")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "0.00" - assert ctx["body"][0][2]["display_value"] == "-0.61" - assert ctx["body"][1][1]["display_value"] == "1.00" - assert ctx["body"][1][2]["display_value"] == "-1.23" - - -def test_format_callable(styler): - ctx = styler.format(lambda v: "neg" if v < 0 else "pos")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "pos" - assert ctx["body"][0][2]["display_value"] == "neg" - assert ctx["body"][1][1]["display_value"] == "pos" - assert ctx["body"][1][2]["display_value"] == "neg" - - -def test_format_with_na_rep(): - # GH 21527 28358 - df = DataFrame([[None, None], [1.1, 1.2]], columns=["A", "B"]) - - ctx = df.style.format(None, na_rep="-")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "-" - assert ctx["body"][0][2]["display_value"] == "-" - - ctx = df.style.format("{:.2%}", na_rep="-")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "-" - assert ctx["body"][0][2]["display_value"] == "-" - assert ctx["body"][1][1]["display_value"] == "110.00%" - assert ctx["body"][1][2]["display_value"] == "120.00%" - - ctx = df.style.format("{:.2%}", na_rep="-", subset=["B"])._translate(True, True) - assert ctx["body"][0][2]["display_value"] == "-" - assert ctx["body"][1][2]["display_value"] == "120.00%" - - -def test_format_index_with_na_rep(): - df = DataFrame([[1, 2, 3, 4, 5]], columns=["A", None, np.nan, NaT, NA]) - ctx = df.style.format_index(None, na_rep="--", axis=1)._translate(True, True) - assert ctx["head"][0][1]["display_value"] == "A" - for i in [2, 3, 4, 5]: - assert ctx["head"][0][i]["display_value"] == "--" - - -def test_format_non_numeric_na(): - # GH 21527 28358 - df = DataFrame( - { - "object": [None, np.nan, "foo"], - "datetime": [None, NaT, Timestamp("20120101")], - } - ) - ctx = df.style.format(None, na_rep="-")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "-" - assert ctx["body"][0][2]["display_value"] == "-" - assert ctx["body"][1][1]["display_value"] == "-" - assert ctx["body"][1][2]["display_value"] == "-" - - -@pytest.mark.parametrize( - "func, attr, kwargs", - [ - ("format", "_display_funcs", {}), - ("format_index", "_display_funcs_index", {"axis": 0}), - ("format_index", "_display_funcs_columns", {"axis": 1}), - ], -) -def test_format_clear(styler, func, attr, kwargs): - assert (0, 0) not in getattr(styler, attr) # using default - getattr(styler, func)("{:.2f}", **kwargs) - assert (0, 0) in getattr(styler, attr) # formatter is specified - getattr(styler, func)(**kwargs) - assert (0, 0) not in getattr(styler, attr) # formatter cleared to default - - -@pytest.mark.parametrize( - "escape, exp", - [ - ("html", "<>&"%$#_{}~^\\~ ^ \\ "), - ( - "latex", - '<>\\&"\\%\\$\\#\\_\\{\\}\\textasciitilde \\textasciicircum ' - "\\textbackslash \\textasciitilde \\space \\textasciicircum \\space " - "\\textbackslash \\space ", - ), - ], -) -def test_format_escape_html(escape, exp): - chars = '<>&"%$#_{}~^\\~ ^ \\ ' - df = DataFrame([[chars]]) - - s = Styler(df, uuid_len=0).format("&{0}&", escape=None) - expected = f'&{chars}&' - assert expected in s.to_html() - - # only the value should be escaped before passing to the formatter - s = Styler(df, uuid_len=0).format("&{0}&", escape=escape) - expected = f'&{exp}&' - assert expected in s.to_html() - - # also test format_index() - styler = Styler(DataFrame(columns=[chars]), uuid_len=0) - styler.format_index("&{0}&", escape=None, axis=1) - assert styler._translate(True, True)["head"][0][1]["display_value"] == f"&{chars}&" - styler.format_index("&{0}&", escape=escape, axis=1) - assert styler._translate(True, True)["head"][0][1]["display_value"] == f"&{exp}&" - - -def test_format_escape_na_rep(): - # tests the na_rep is not escaped - df = DataFrame([['<>&"', None]]) - s = Styler(df, uuid_len=0).format("X&{0}>X", escape="html", na_rep="&") - ex = 'X&<>&">X' - expected2 = '&' - assert ex in s.to_html() - assert expected2 in s.to_html() - - # also test for format_index() - df = DataFrame(columns=['<>&"', None]) - styler = Styler(df, uuid_len=0) - styler.format_index("X&{0}>X", escape="html", na_rep="&", axis=1) - ctx = styler._translate(True, True) - assert ctx["head"][0][1]["display_value"] == "X&<>&">X" - assert ctx["head"][0][2]["display_value"] == "&" - - -def test_format_escape_floats(styler): - # test given formatter for number format is not impacted by escape - s = styler.format("{:.1f}", escape="html") - for expected in [">0.0<", ">1.0<", ">-1.2<", ">-0.6<"]: - assert expected in s.to_html() - # tests precision of floats is not impacted by escape - s = styler.format(precision=1, escape="html") - for expected in [">0<", ">1<", ">-1.2<", ">-0.6<"]: - assert expected in s.to_html() - - -@pytest.mark.parametrize("formatter", [5, True, [2.0]]) -@pytest.mark.parametrize("func", ["format", "format_index"]) -def test_format_raises(styler, formatter, func): - with pytest.raises(TypeError, match="expected str or callable"): - getattr(styler, func)(formatter) - - -@pytest.mark.parametrize( - "precision, expected", - [ - (1, ["1.0", "2.0", "3.2", "4.6"]), - (2, ["1.00", "2.01", "3.21", "4.57"]), - (3, ["1.000", "2.009", "3.212", "4.566"]), - ], -) -def test_format_with_precision(precision, expected): - # Issue #13257 - df = DataFrame([[1.0, 2.0090, 3.2121, 4.566]], columns=[1.0, 2.0090, 3.2121, 4.566]) - styler = Styler(df) - styler.format(precision=precision) - styler.format_index(precision=precision, axis=1) - - ctx = styler._translate(True, True) - for col, exp in enumerate(expected): - assert ctx["body"][0][col + 1]["display_value"] == exp # format test - assert ctx["head"][0][col + 1]["display_value"] == exp # format_index test - - -@pytest.mark.parametrize("axis", [0, 1]) -@pytest.mark.parametrize( - "level, expected", - [ - (0, ["X", "X", "_", "_"]), # level int - ("zero", ["X", "X", "_", "_"]), # level name - (1, ["_", "_", "X", "X"]), # other level int - ("one", ["_", "_", "X", "X"]), # other level name - ([0, 1], ["X", "X", "X", "X"]), # both levels - ([0, "zero"], ["X", "X", "_", "_"]), # level int and name simultaneous - ([0, "one"], ["X", "X", "X", "X"]), # both levels as int and name - (["one", "zero"], ["X", "X", "X", "X"]), # both level names, reversed - ], -) -def test_format_index_level(axis, level, expected): - midx = MultiIndex.from_arrays([["_", "_"], ["_", "_"]], names=["zero", "one"]) - df = DataFrame([[1, 2], [3, 4]]) - if axis == 0: - df.index = midx - else: - df.columns = midx - - styler = df.style.format_index(lambda v: "X", level=level, axis=axis) - ctx = styler._translate(True, True) - - if axis == 0: # compare index - result = [ctx["body"][s][0]["display_value"] for s in range(2)] - result += [ctx["body"][s][1]["display_value"] for s in range(2)] - else: # compare columns - result = [ctx["head"][0][s + 1]["display_value"] for s in range(2)] - result += [ctx["head"][1][s + 1]["display_value"] for s in range(2)] - - assert expected == result - - -def test_format_subset(): - df = DataFrame([[0.1234, 0.1234], [1.1234, 1.1234]], columns=["a", "b"]) - ctx = df.style.format( - {"a": "{:0.1f}", "b": "{0:.2%}"}, subset=IndexSlice[0, :] - )._translate(True, True) - expected = "0.1" - raw_11 = "1.123400" - assert ctx["body"][0][1]["display_value"] == expected - assert ctx["body"][1][1]["display_value"] == raw_11 - assert ctx["body"][0][2]["display_value"] == "12.34%" - - ctx = df.style.format("{:0.1f}", subset=IndexSlice[0, :])._translate(True, True) - assert ctx["body"][0][1]["display_value"] == expected - assert ctx["body"][1][1]["display_value"] == raw_11 - - ctx = df.style.format("{:0.1f}", subset=IndexSlice["a"])._translate(True, True) - assert ctx["body"][0][1]["display_value"] == expected - assert ctx["body"][0][2]["display_value"] == "0.123400" - - ctx = df.style.format("{:0.1f}", subset=IndexSlice[0, "a"])._translate(True, True) - assert ctx["body"][0][1]["display_value"] == expected - assert ctx["body"][1][1]["display_value"] == raw_11 - - ctx = df.style.format("{:0.1f}", subset=IndexSlice[[0, 1], ["a"]])._translate( - True, True - ) - assert ctx["body"][0][1]["display_value"] == expected - assert ctx["body"][1][1]["display_value"] == "1.1" - assert ctx["body"][0][2]["display_value"] == "0.123400" - assert ctx["body"][1][2]["display_value"] == raw_11 - - -@pytest.mark.parametrize("formatter", [None, "{:,.1f}"]) -@pytest.mark.parametrize("decimal", [".", "*"]) -@pytest.mark.parametrize("precision", [None, 2]) -@pytest.mark.parametrize("func, col", [("format", 1), ("format_index", 0)]) -def test_format_thousands(formatter, decimal, precision, func, col): - styler = DataFrame([[1000000.123456789]], index=[1000000.123456789]).style - result = getattr(styler, func)( # testing float - thousands="_", formatter=formatter, decimal=decimal, precision=precision - )._translate(True, True) - assert "1_000_000" in result["body"][0][col]["display_value"] - - styler = DataFrame([[1000000]], index=[1000000]).style - result = getattr(styler, func)( # testing int - thousands="_", formatter=formatter, decimal=decimal, precision=precision - )._translate(True, True) - assert "1_000_000" in result["body"][0][col]["display_value"] - - styler = DataFrame([[1 + 1000000.123456789j]], index=[1 + 1000000.123456789j]).style - result = getattr(styler, func)( # testing complex - thousands="_", formatter=formatter, decimal=decimal, precision=precision - )._translate(True, True) - assert "1_000_000" in result["body"][0][col]["display_value"] - - -@pytest.mark.parametrize("formatter", [None, "{:,.4f}"]) -@pytest.mark.parametrize("thousands", [None, ",", "*"]) -@pytest.mark.parametrize("precision", [None, 4]) -@pytest.mark.parametrize("func, col", [("format", 1), ("format_index", 0)]) -def test_format_decimal(formatter, thousands, precision, func, col): - styler = DataFrame([[1000000.123456789]], index=[1000000.123456789]).style - result = getattr(styler, func)( # testing float - decimal="_", formatter=formatter, thousands=thousands, precision=precision - )._translate(True, True) - assert "000_123" in result["body"][0][col]["display_value"] - - styler = DataFrame([[1 + 1000000.123456789j]], index=[1 + 1000000.123456789j]).style - result = getattr(styler, func)( # testing complex - decimal="_", formatter=formatter, thousands=thousands, precision=precision - )._translate(True, True) - assert "000_123" in result["body"][0][col]["display_value"] - - -def test_str_escape_error(): - msg = "`escape` only permitted in {'html', 'latex'}, got " - with pytest.raises(ValueError, match=msg): - _str_escape("text", "bad_escape") - - with pytest.raises(ValueError, match=msg): - _str_escape("text", []) - - _str_escape(2.00, "bad_escape") # OK since dtype is float - - -def test_format_options(): - df = DataFrame({"int": [2000, 1], "float": [1.009, None], "str": ["&<", "&~"]}) - ctx = df.style._translate(True, True) - - # test option: na_rep - assert ctx["body"][1][2]["display_value"] == "nan" - with option_context("styler.format.na_rep", "MISSING"): - ctx_with_op = df.style._translate(True, True) - assert ctx_with_op["body"][1][2]["display_value"] == "MISSING" - - # test option: decimal and precision - assert ctx["body"][0][2]["display_value"] == "1.009000" - with option_context("styler.format.decimal", "_"): - ctx_with_op = df.style._translate(True, True) - assert ctx_with_op["body"][0][2]["display_value"] == "1_009000" - with option_context("styler.format.precision", 2): - ctx_with_op = df.style._translate(True, True) - assert ctx_with_op["body"][0][2]["display_value"] == "1.01" - - # test option: thousands - assert ctx["body"][0][1]["display_value"] == "2000" - with option_context("styler.format.thousands", "_"): - ctx_with_op = df.style._translate(True, True) - assert ctx_with_op["body"][0][1]["display_value"] == "2_000" - - # test option: escape - assert ctx["body"][0][3]["display_value"] == "&<" - assert ctx["body"][1][3]["display_value"] == "&~" - with option_context("styler.format.escape", "html"): - ctx_with_op = df.style._translate(True, True) - assert ctx_with_op["body"][0][3]["display_value"] == "&<" - with option_context("styler.format.escape", "latex"): - ctx_with_op = df.style._translate(True, True) - assert ctx_with_op["body"][1][3]["display_value"] == "\\&\\textasciitilde " - - # test option: formatter - with option_context("styler.format.formatter", {"int": "{:,.2f}"}): - ctx_with_op = df.style._translate(True, True) - assert ctx_with_op["body"][0][1]["display_value"] == "2,000.00" - - -def test_precision_zero(df): - styler = Styler(df, precision=0) - ctx = styler._translate(True, True) - assert ctx["body"][0][2]["display_value"] == "-1" - assert ctx["body"][1][2]["display_value"] == "-1" - - -@pytest.mark.parametrize( - "formatter, exp", - [ - (lambda x: f"{x:.3f}", "9.000"), - ("{:.2f}", "9.00"), - ({0: "{:.1f}"}, "9.0"), - (None, "9"), - ], -) -def test_formatter_options_validator(formatter, exp): - df = DataFrame([[9]]) - with option_context("styler.format.formatter", formatter): - assert f" {exp} " in df.style.to_latex() - - -def test_formatter_options_raises(): - msg = "Value must be an instance of" - with pytest.raises(ValueError, match=msg): - with option_context("styler.format.formatter", ["bad", "type"]): - DataFrame().style.to_latex() - - -def test_1level_multiindex(): - # GH 43383 - midx = MultiIndex.from_product([[1, 2]], names=[""]) - df = DataFrame(-1, index=midx, columns=[0, 1]) - ctx = df.style._translate(True, True) - assert ctx["body"][0][0]["display_value"] == "1" - assert ctx["body"][0][0]["is_visible"] is True - assert ctx["body"][1][0]["display_value"] == "2" - assert ctx["body"][1][0]["is_visible"] is True diff --git a/pandas/tests/io/formats/style/test_highlight.py b/pandas/tests/io/formats/style/test_highlight.py deleted file mode 100644 index 1b579a43370a2..0000000000000 --- a/pandas/tests/io/formats/style/test_highlight.py +++ /dev/null @@ -1,216 +0,0 @@ -import numpy as np -import pytest - -from pandas import ( - NA, - DataFrame, - IndexSlice, -) - -pytest.importorskip("jinja2") - -from pandas.io.formats.style import Styler - - -@pytest.fixture -def df(): - return DataFrame({"A": [0, np.nan, 10], "B": [1, None, 2]}) - - -@pytest.fixture -def styler(df): - return Styler(df, uuid_len=0) - - -def test_highlight_null(styler): - result = styler.highlight_null()._compute().ctx - expected = { - (1, 0): [("background-color", "red")], - (1, 1): [("background-color", "red")], - } - assert result == expected - - -def test_highlight_null_subset(styler): - # GH 31345 - result = ( - styler.highlight_null(null_color="red", subset=["A"]) - .highlight_null(null_color="green", subset=["B"]) - ._compute() - .ctx - ) - expected = { - (1, 0): [("background-color", "red")], - (1, 1): [("background-color", "green")], - } - assert result == expected - - -@pytest.mark.parametrize("f", ["highlight_min", "highlight_max"]) -def test_highlight_minmax_basic(df, f): - expected = { - (0, 1): [("background-color", "red")], - # ignores NaN row, - (2, 0): [("background-color", "red")], - } - if f == "highlight_min": - df = -df - result = getattr(df.style, f)(axis=1, color="red")._compute().ctx - assert result == expected - - -@pytest.mark.parametrize("f", ["highlight_min", "highlight_max"]) -@pytest.mark.parametrize( - "kwargs", - [ - {"axis": None, "color": "red"}, # test axis - {"axis": 0, "subset": ["A"], "color": "red"}, # test subset and ignores NaN - {"axis": None, "props": "background-color: red"}, # test props - ], -) -def test_highlight_minmax_ext(df, f, kwargs): - expected = {(2, 0): [("background-color", "red")]} - if f == "highlight_min": - df = -df - result = getattr(df.style, f)(**kwargs)._compute().ctx - assert result == expected - - -@pytest.mark.parametrize("f", ["highlight_min", "highlight_max"]) -@pytest.mark.parametrize("axis", [None, 0, 1]) -def test_highlight_minmax_nulls(f, axis): - # GH 42750 - expected = { - (1, 0): [("background-color", "yellow")], - (1, 1): [("background-color", "yellow")], - } - if axis == 1: - expected.update({(2, 1): [("background-color", "yellow")]}) - - if f == "highlight_max": - df = DataFrame({"a": [NA, 1, None], "b": [np.nan, 1, -1]}) - else: - df = DataFrame({"a": [NA, -1, None], "b": [np.nan, -1, 1]}) - - result = getattr(df.style, f)(axis=axis)._compute().ctx - assert result == expected - - -@pytest.mark.parametrize( - "kwargs", - [ - {"left": 0, "right": 1}, # test basic range - {"left": 0, "right": 1, "props": "background-color: yellow"}, # test props - {"left": -100, "right": 100, "subset": IndexSlice[[0, 1], :]}, # test subset - {"left": 0, "subset": IndexSlice[[0, 1], :]}, # test no right - {"right": 1}, # test no left - {"left": [0, 0, 11], "axis": 0}, # test left as sequence - {"left": DataFrame({"A": [0, 0, 11], "B": [1, 1, 11]}), "axis": None}, # axis - {"left": 0, "right": [0, 1], "axis": 1}, # test sequence right - ], -) -def test_highlight_between(styler, kwargs): - expected = { - (0, 0): [("background-color", "yellow")], - (0, 1): [("background-color", "yellow")], - } - result = styler.highlight_between(**kwargs)._compute().ctx - assert result == expected - - -@pytest.mark.parametrize( - "arg, map, axis", - [ - ("left", [1, 2], 0), # 0 axis has 3 elements not 2 - ("left", [1, 2, 3], 1), # 1 axis has 2 elements not 3 - ("left", np.array([[1, 2], [1, 2]]), None), # df is (2,3) not (2,2) - ("right", [1, 2], 0), # same tests as above for 'right' not 'left' - ("right", [1, 2, 3], 1), # .. - ("right", np.array([[1, 2], [1, 2]]), None), # .. - ], -) -def test_highlight_between_raises(arg, styler, map, axis): - msg = f"supplied '{arg}' is not correct shape" - with pytest.raises(ValueError, match=msg): - styler.highlight_between(**{arg: map, "axis": axis})._compute() - - -def test_highlight_between_raises2(styler): - msg = "values can be 'both', 'left', 'right', or 'neither'" - with pytest.raises(ValueError, match=msg): - styler.highlight_between(inclusive="badstring")._compute() - - with pytest.raises(ValueError, match=msg): - styler.highlight_between(inclusive=1)._compute() - - -@pytest.mark.parametrize( - "inclusive, expected", - [ - ( - "both", - { - (0, 0): [("background-color", "yellow")], - (0, 1): [("background-color", "yellow")], - }, - ), - ("neither", {}), - ("left", {(0, 0): [("background-color", "yellow")]}), - ("right", {(0, 1): [("background-color", "yellow")]}), - ], -) -def test_highlight_between_inclusive(styler, inclusive, expected): - kwargs = {"left": 0, "right": 1, "subset": IndexSlice[[0, 1], :]} - result = styler.highlight_between(**kwargs, inclusive=inclusive)._compute() - assert result.ctx == expected - - -@pytest.mark.parametrize( - "kwargs", - [ - {"q_left": 0.5, "q_right": 1, "axis": 0}, # base case - {"q_left": 0.5, "q_right": 1, "axis": None}, # test axis - {"q_left": 0, "q_right": 1, "subset": IndexSlice[2, :]}, # test subset - {"q_left": 0.5, "axis": 0}, # test no high - {"q_right": 1, "subset": IndexSlice[2, :], "axis": 1}, # test no low - {"q_left": 0.5, "axis": 0, "props": "background-color: yellow"}, # tst prop - ], -) -def test_highlight_quantile(styler, kwargs): - expected = { - (2, 0): [("background-color", "yellow")], - (2, 1): [("background-color", "yellow")], - } - result = styler.highlight_quantile(**kwargs)._compute().ctx - assert result == expected - - -@pytest.mark.skipif(np.__version__[:4] in ["1.16", "1.17"], reason="Numpy Issue #14831") -@pytest.mark.parametrize( - "f,kwargs", - [ - ("highlight_min", {"axis": 1, "subset": IndexSlice[1, :]}), - ("highlight_max", {"axis": 0, "subset": [0]}), - ("highlight_quantile", {"axis": None, "q_left": 0.6, "q_right": 0.8}), - ("highlight_between", {"subset": [0]}), - ], -) -@pytest.mark.parametrize( - "df", - [ - DataFrame([[0, 10], [20, 30]], dtype=int), - DataFrame([[0, 10], [20, 30]], dtype=float), - DataFrame([[0, 10], [20, 30]], dtype="datetime64[ns]"), - DataFrame([[0, 10], [20, 30]], dtype=str), - DataFrame([[0, 10], [20, 30]], dtype="timedelta64[ns]"), - ], -) -def test_all_highlight_dtypes(f, kwargs, df): - if f == "highlight_quantile" and isinstance(df.iloc[0, 0], (str)): - return None # quantile incompatible with str - if f == "highlight_between": - kwargs["left"] = df.iloc[1, 0] # set the range low for testing - - expected = {(1, 0): [("background-color", "yellow")]} - result = getattr(df.style, f)(**kwargs)._compute().ctx - assert result == expected diff --git a/pandas/tests/io/formats/style/test_html.py b/pandas/tests/io/formats/style/test_html.py deleted file mode 100644 index fad289d5e0d2c..0000000000000 --- a/pandas/tests/io/formats/style/test_html.py +++ /dev/null @@ -1,806 +0,0 @@ -from textwrap import dedent - -import numpy as np -import pytest - -from pandas import ( - DataFrame, - MultiIndex, - option_context, -) - -jinja2 = pytest.importorskip("jinja2") -from pandas.io.formats.style import Styler - -loader = jinja2.PackageLoader("pandas", "io/formats/templates") -env = jinja2.Environment(loader=loader, trim_blocks=True) - - -@pytest.fixture -def styler(): - return Styler(DataFrame([[2.61], [2.69]], index=["a", "b"], columns=["A"])) - - -@pytest.fixture -def styler_mi(): - midx = MultiIndex.from_product([["a", "b"], ["c", "d"]]) - return Styler(DataFrame(np.arange(16).reshape(4, 4), index=midx, columns=midx)) - - -@pytest.fixture -def tpl_style(): - return env.get_template("html_style.tpl") - - -@pytest.fixture -def tpl_table(): - return env.get_template("html_table.tpl") - - -def test_html_template_extends_options(): - # make sure if templates are edited tests are updated as are setup fixtures - # to understand the dependency - with open("pandas/io/formats/templates/html.tpl") as file: - result = file.read() - assert "{% include html_style_tpl %}" in result - assert "{% include html_table_tpl %}" in result - - -def test_exclude_styles(styler): - result = styler.to_html(exclude_styles=True, doctype_html=True) - expected = dedent( - """\ - - - - - - - - - - - - - - - - - - - - - - - -
 A
a2.610000
b2.690000
- - - """ - ) - assert result == expected - - -def test_w3_html_format(styler): - styler.set_uuid("").set_table_styles( - [{"selector": "th", "props": "att2:v2;"}] - ).applymap(lambda x: "att1:v1;").set_table_attributes( - 'class="my-cls1" style="attr3:v3;"' - ).set_td_classes( - DataFrame(["my-cls2"], index=["a"], columns=["A"]) - ).format( - "{:.1f}" - ).set_caption( - "A comprehensive test" - ) - expected = dedent( - """\ - - - - - - - - - - - - - - - - - - - -
A comprehensive test
 A
a2.6
b2.7
- """ - ) - assert expected == styler.to_html() - - -def test_colspan_w3(): - # GH 36223 - df = DataFrame(data=[[1, 2]], columns=[["l0", "l0"], ["l1a", "l1b"]]) - styler = Styler(df, uuid="_", cell_ids=False) - assert 'l0' in styler.to_html() - - -def test_rowspan_w3(): - # GH 38533 - df = DataFrame(data=[[1, 2]], index=[["l0", "l0"], ["l1a", "l1b"]]) - styler = Styler(df, uuid="_", cell_ids=False) - assert 'l0' in styler.to_html() - - -def test_styles(styler): - styler.set_uuid("abc") - styler.set_table_styles([{"selector": "td", "props": "color: red;"}]) - result = styler.to_html(doctype_html=True) - expected = dedent( - """\ - - - - - - - - - - - - - - - - - - - - - - - - -
 A
a2.610000
b2.690000
- - - """ - ) - assert result == expected - - -def test_doctype(styler): - result = styler.to_html(doctype_html=False) - assert "" not in result - assert "" not in result - assert "" not in result - assert "" not in result - - -def test_doctype_encoding(styler): - with option_context("styler.render.encoding", "ASCII"): - result = styler.to_html(doctype_html=True) - assert '' in result - result = styler.to_html(doctype_html=True, encoding="ANSI") - assert '' in result - - -def test_bold_headers_arg(styler): - result = styler.to_html(bold_headers=True) - assert "th {\n font-weight: bold;\n}" in result - result = styler.to_html() - assert "th {\n font-weight: bold;\n}" not in result - - -def test_caption_arg(styler): - result = styler.to_html(caption="foo bar") - assert "foo bar" in result - result = styler.to_html() - assert "foo bar" not in result - - -def test_block_names(tpl_style, tpl_table): - # catch accidental removal of a block - expected_style = { - "before_style", - "style", - "table_styles", - "before_cellstyle", - "cellstyle", - } - expected_table = { - "before_table", - "table", - "caption", - "thead", - "tbody", - "after_table", - "before_head_rows", - "head_tr", - "after_head_rows", - "before_rows", - "tr", - "after_rows", - } - result1 = set(tpl_style.blocks) - assert result1 == expected_style - - result2 = set(tpl_table.blocks) - assert result2 == expected_table - - -def test_from_custom_template_table(tmpdir): - p = tmpdir.mkdir("tpl").join("myhtml_table.tpl") - p.write( - dedent( - """\ - {% extends "html_table.tpl" %} - {% block table %} -

{{custom_title}}

- {{ super() }} - {% endblock table %}""" - ) - ) - result = Styler.from_custom_template(str(tmpdir.join("tpl")), "myhtml_table.tpl") - assert issubclass(result, Styler) - assert result.env is not Styler.env - assert result.template_html_table is not Styler.template_html_table - styler = result(DataFrame({"A": [1, 2]})) - assert "

My Title

\n\n\n - {{ super() }} - {% endblock style %}""" - ) - ) - result = Styler.from_custom_template( - str(tmpdir.join("tpl")), html_style="myhtml_style.tpl" - ) - assert issubclass(result, Styler) - assert result.env is not Styler.env - assert result.template_html_style is not Styler.template_html_style - styler = result(DataFrame({"A": [1, 2]})) - assert '\n\nfull cap" in styler.to_html() - - -@pytest.mark.parametrize("index", [False, True]) -@pytest.mark.parametrize("columns", [False, True]) -@pytest.mark.parametrize("index_name", [True, False]) -def test_sticky_basic(styler, index, columns, index_name): - if index_name: - styler.index.name = "some text" - if index: - styler.set_sticky(axis=0) - if columns: - styler.set_sticky(axis=1) - - left_css = ( - "#T_ {0} {{\n position: sticky;\n background-color: white;\n" - " left: 0px;\n z-index: {1};\n}}" - ) - top_css = ( - "#T_ {0} {{\n position: sticky;\n background-color: white;\n" - " top: {1}px;\n z-index: {2};\n{3}}}" - ) - - res = styler.set_uuid("").to_html() - - # test index stickys over thead and tbody - assert (left_css.format("thead tr th:nth-child(1)", "3 !important") in res) is index - assert (left_css.format("tbody tr th:nth-child(1)", "1") in res) is index - - # test column stickys including if name row - assert ( - top_css.format("thead tr:nth-child(1) th", "0", "2", " height: 25px;\n") in res - ) is (columns and index_name) - assert ( - top_css.format("thead tr:nth-child(2) th", "25", "2", " height: 25px;\n") - in res - ) is (columns and index_name) - assert (top_css.format("thead tr:nth-child(1) th", "0", "2", "") in res) is ( - columns and not index_name - ) - - -@pytest.mark.parametrize("index", [False, True]) -@pytest.mark.parametrize("columns", [False, True]) -def test_sticky_mi(styler_mi, index, columns): - if index: - styler_mi.set_sticky(axis=0) - if columns: - styler_mi.set_sticky(axis=1) - - left_css = ( - "#T_ {0} {{\n position: sticky;\n background-color: white;\n" - " left: {1}px;\n min-width: 75px;\n max-width: 75px;\n z-index: {2};\n}}" - ) - top_css = ( - "#T_ {0} {{\n position: sticky;\n background-color: white;\n" - " top: {1}px;\n height: 25px;\n z-index: {2};\n}}" - ) - - res = styler_mi.set_uuid("").to_html() - - # test the index stickys for thead and tbody over both levels - assert ( - left_css.format("thead tr th:nth-child(1)", "0", "3 !important") in res - ) is index - assert (left_css.format("tbody tr th.level0", "0", "1") in res) is index - assert ( - left_css.format("thead tr th:nth-child(2)", "75", "3 !important") in res - ) is index - assert (left_css.format("tbody tr th.level1", "75", "1") in res) is index - - # test the column stickys for each level row - assert (top_css.format("thead tr:nth-child(1) th", "0", "2") in res) is columns - assert (top_css.format("thead tr:nth-child(2) th", "25", "2") in res) is columns - - -@pytest.mark.parametrize("index", [False, True]) -@pytest.mark.parametrize("columns", [False, True]) -@pytest.mark.parametrize("levels", [[1], ["one"], "one"]) -def test_sticky_levels(styler_mi, index, columns, levels): - styler_mi.index.names, styler_mi.columns.names = ["zero", "one"], ["zero", "one"] - if index: - styler_mi.set_sticky(axis=0, levels=levels) - if columns: - styler_mi.set_sticky(axis=1, levels=levels) - - left_css = ( - "#T_ {0} {{\n position: sticky;\n background-color: white;\n" - " left: {1}px;\n min-width: 75px;\n max-width: 75px;\n z-index: {2};\n}}" - ) - top_css = ( - "#T_ {0} {{\n position: sticky;\n background-color: white;\n" - " top: {1}px;\n height: 25px;\n z-index: {2};\n}}" - ) - - res = styler_mi.set_uuid("").to_html() - - # test no sticking of level0 - assert "#T_ thead tr th:nth-child(1)" not in res - assert "#T_ tbody tr th.level0" not in res - assert "#T_ thead tr:nth-child(1) th" not in res - - # test sticking level1 - assert ( - left_css.format("thead tr th:nth-child(2)", "0", "3 !important") in res - ) is index - assert (left_css.format("tbody tr th.level1", "0", "1") in res) is index - assert (top_css.format("thead tr:nth-child(2) th", "0", "2") in res) is columns - - -def test_sticky_raises(styler): - with pytest.raises(ValueError, match="No axis named bad for object type DataFrame"): - styler.set_sticky(axis="bad") - - -@pytest.mark.parametrize( - "sparse_index, sparse_columns", - [(True, True), (True, False), (False, True), (False, False)], -) -def test_sparse_options(sparse_index, sparse_columns): - cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")]) - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df = DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=ridx, columns=cidx) - styler = df.style - - default_html = styler.to_html() # defaults under pd.options to (True , True) - - with option_context( - "styler.sparse.index", sparse_index, "styler.sparse.columns", sparse_columns - ): - html1 = styler.to_html() - assert (html1 == default_html) is (sparse_index and sparse_columns) - html2 = styler.to_html(sparse_index=sparse_index, sparse_columns=sparse_columns) - assert html1 == html2 - - -@pytest.mark.parametrize("index", [True, False]) -@pytest.mark.parametrize("columns", [True, False]) -def test_applymap_header_cell_ids(styler, index, columns): - # GH 41893 - func = lambda v: "attr: val;" - styler.uuid, styler.cell_ids = "", False - if index: - styler.applymap_index(func, axis="index") - if columns: - styler.applymap_index(func, axis="columns") - - result = styler.to_html() - - # test no data cell ids - assert '2.610000' in result - assert '2.690000' in result - - # test index header ids where needed and css styles - assert ( - 'a' in result - ) is index - assert ( - 'b' in result - ) is index - assert ("#T__level0_row0, #T__level0_row1 {\n attr: val;\n}" in result) is index - - # test column header ids where needed and css styles - assert ( - 'A' in result - ) is columns - assert ("#T__level0_col0 {\n attr: val;\n}" in result) is columns - - -@pytest.mark.parametrize("rows", [True, False]) -@pytest.mark.parametrize("cols", [True, False]) -def test_maximums(styler_mi, rows, cols): - result = styler_mi.to_html( - max_rows=2 if rows else None, - max_columns=2 if cols else None, - ) - - assert ">5" in result # [[0,1], [4,5]] always visible - assert (">8" in result) is not rows # first trimmed vertical element - assert (">2" in result) is not cols # first trimmed horizontal element - - -def test_replaced_css_class_names(styler_mi): - css = { - "row_heading": "ROWHEAD", - # "col_heading": "COLHEAD", - "index_name": "IDXNAME", - # "col": "COL", - "row": "ROW", - # "col_trim": "COLTRIM", - "row_trim": "ROWTRIM", - "level": "LEVEL", - "data": "DATA", - "blank": "BLANK", - } - midx = MultiIndex.from_product([["a", "b"], ["c", "d"]]) - styler_mi = Styler( - DataFrame(np.arange(16).reshape(4, 4), index=midx, columns=midx), - uuid_len=0, - ).set_table_styles(css_class_names=css) - styler_mi.index.names = ["n1", "n2"] - styler_mi.hide(styler_mi.index[1:], axis=0) - styler_mi.hide(styler_mi.columns[1:], axis=1) - styler_mi.applymap_index(lambda v: "color: red;", axis=0) - styler_mi.applymap_index(lambda v: "color: green;", axis=1) - styler_mi.applymap(lambda v: "color: blue;") - expected = dedent( - """\ - - - - - - - - - - - - - - - - - - - - - - - - - - -
 n1a
 n2c
n1n2 
ac0
- """ - ) - result = styler_mi.to_html() - assert result == expected - - -def test_include_css_style_rules_only_for_visible_cells(styler_mi): - # GH 43619 - result = ( - styler_mi.set_uuid("") - .applymap(lambda v: "color: blue;") - .hide(styler_mi.data.columns[1:], axis="columns") - .hide(styler_mi.data.index[1:], axis="index") - .to_html() - ) - expected_styles = dedent( - """\ - - """ - ) - assert expected_styles in result - - -def test_include_css_style_rules_only_for_visible_index_labels(styler_mi): - # GH 43619 - result = ( - styler_mi.set_uuid("") - .applymap_index(lambda v: "color: blue;", axis="index") - .hide(styler_mi.data.columns, axis="columns") - .hide(styler_mi.data.index[1:], axis="index") - .to_html() - ) - expected_styles = dedent( - """\ - - """ - ) - assert expected_styles in result - - -def test_include_css_style_rules_only_for_visible_column_labels(styler_mi): - # GH 43619 - result = ( - styler_mi.set_uuid("") - .applymap_index(lambda v: "color: blue;", axis="columns") - .hide(styler_mi.data.columns[1:], axis="columns") - .hide(styler_mi.data.index, axis="index") - .to_html() - ) - expected_styles = dedent( - """\ - - """ - ) - assert expected_styles in result - - -def test_hiding_index_columns_multiindex_alignment(): - # gh 43644 - midx = MultiIndex.from_product( - [["i0", "j0"], ["i1"], ["i2", "j2"]], names=["i-0", "i-1", "i-2"] - ) - cidx = MultiIndex.from_product( - [["c0"], ["c1", "d1"], ["c2", "d2"]], names=["c-0", "c-1", "c-2"] - ) - df = DataFrame(np.arange(16).reshape(4, 4), index=midx, columns=cidx) - styler = Styler(df, uuid_len=0) - styler.hide(level=1, axis=0).hide(level=0, axis=1) - styler.hide([("j0", "i1", "j2")], axis=0) - styler.hide([("c0", "d1", "d2")], axis=1) - result = styler.to_html() - expected = dedent( - """\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 c-1c1d1
 c-2c2d2c2
i-0i-2   
i0i2012
j2456
j0i28910
- """ - ) - assert result == expected - - -def test_hiding_index_columns_multiindex_trimming(): - # gh 44272 - df = DataFrame(np.arange(64).reshape(8, 8)) - df.columns = MultiIndex.from_product([[0, 1, 2, 3], [0, 1]]) - df.index = MultiIndex.from_product([[0, 1, 2, 3], [0, 1]]) - df.index.names, df.columns.names = ["a", "b"], ["c", "d"] - styler = Styler(df, cell_ids=False, uuid_len=0) - styler.hide([(0, 0), (0, 1), (1, 0)], axis=1).hide([(0, 0), (0, 1), (1, 0)], axis=0) - with option_context("styler.render.max_rows", 4, "styler.render.max_columns", 4): - result = styler.to_html() - - expected = dedent( - """\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 c123
 d1010...
ab     
1127282930...
2035363738...
143444546...
3051525354...
.....................
- """ - ) - - assert result == expected - - -@pytest.mark.parametrize("type", ["data", "index"]) -@pytest.mark.parametrize( - "text, exp, found", - [ - ("no link, just text", False, ""), - ("subdomain not www: sub.web.com", False, ""), - ("www subdomain: www.web.com other", True, "www.web.com"), - ("scheme full structure: http://www.web.com", True, "http://www.web.com"), - ("scheme no top-level: http://www.web", True, "http://www.web"), - ("no scheme, no top-level: www.web", False, "www.web"), - ("https scheme: https://www.web.com", True, "https://www.web.com"), - ("ftp scheme: ftp://www.web", True, "ftp://www.web"), - ("subdirectories: www.web.com/directory", True, "www.web.com/directory"), - ("Multiple domains: www.1.2.3.4", True, "www.1.2.3.4"), - ], -) -def test_rendered_links(type, text, exp, found): - if type == "data": - df = DataFrame([text]) - styler = df.style.format(hyperlinks="html") - else: - df = DataFrame([0], index=[text]) - styler = df.style.format_index(hyperlinks="html") - - rendered = '{0}'.format(found) - result = styler.to_html() - assert (rendered in result) is exp - assert (text in result) is not exp # test conversion done when expected and not - - -def test_multiple_rendered_links(): - links = ("www.a.b", "http://a.c", "https://a.d", "ftp://a.e") - df = DataFrame(["text {} {} text {} {}".format(*links)]) - result = df.style.format(hyperlinks="html").to_html() - href = '{0}' - for link in links: - assert href.format(link) in result - assert href.format("text") not in result diff --git a/pandas/tests/io/formats/style/test_matplotlib.py b/pandas/tests/io/formats/style/test_matplotlib.py deleted file mode 100644 index a350b6fe7546d..0000000000000 --- a/pandas/tests/io/formats/style/test_matplotlib.py +++ /dev/null @@ -1,286 +0,0 @@ -import numpy as np -import pytest - -from pandas import ( - DataFrame, - IndexSlice, - Series, -) - -pytest.importorskip("matplotlib") -pytest.importorskip("jinja2") - -import matplotlib as mpl - -from pandas.io.formats.style import Styler - - -@pytest.fixture -def df(): - return DataFrame([[1, 2], [2, 4]], columns=["A", "B"]) - - -@pytest.fixture -def styler(df): - return Styler(df, uuid_len=0) - - -@pytest.fixture -def df_blank(): - return DataFrame([[0, 0], [0, 0]], columns=["A", "B"], index=["X", "Y"]) - - -@pytest.fixture -def styler_blank(df_blank): - return Styler(df_blank, uuid_len=0) - - -@pytest.mark.parametrize("f", ["background_gradient", "text_gradient"]) -def test_function_gradient(styler, f): - for c_map in [None, "YlOrRd"]: - result = getattr(styler, f)(cmap=c_map)._compute().ctx - assert all("#" in x[0][1] for x in result.values()) - assert result[(0, 0)] == result[(0, 1)] - assert result[(1, 0)] == result[(1, 1)] - - -@pytest.mark.parametrize("f", ["background_gradient", "text_gradient"]) -def test_background_gradient_color(styler, f): - result = getattr(styler, f)(subset=IndexSlice[1, "A"])._compute().ctx - if f == "background_gradient": - assert result[(1, 0)] == [("background-color", "#fff7fb"), ("color", "#000000")] - elif f == "text_gradient": - assert result[(1, 0)] == [("color", "#fff7fb")] - - -@pytest.mark.parametrize( - "axis, expected", - [ - (0, ["low", "low", "high", "high"]), - (1, ["low", "high", "low", "high"]), - (None, ["low", "mid", "mid", "high"]), - ], -) -@pytest.mark.parametrize("f", ["background_gradient", "text_gradient"]) -def test_background_gradient_axis(styler, axis, expected, f): - if f == "background_gradient": - colors = { - "low": [("background-color", "#f7fbff"), ("color", "#000000")], - "mid": [("background-color", "#abd0e6"), ("color", "#000000")], - "high": [("background-color", "#08306b"), ("color", "#f1f1f1")], - } - elif f == "text_gradient": - colors = { - "low": [("color", "#f7fbff")], - "mid": [("color", "#abd0e6")], - "high": [("color", "#08306b")], - } - result = getattr(styler, f)(cmap="Blues", axis=axis)._compute().ctx - for i, cell in enumerate([(0, 0), (0, 1), (1, 0), (1, 1)]): - assert result[cell] == colors[expected[i]] - - -@pytest.mark.parametrize( - "cmap, expected", - [ - ( - "PuBu", - { - (4, 5): [("background-color", "#86b0d3"), ("color", "#000000")], - (4, 6): [("background-color", "#83afd3"), ("color", "#f1f1f1")], - }, - ), - ( - "YlOrRd", - { - (4, 8): [("background-color", "#fd913e"), ("color", "#000000")], - (4, 9): [("background-color", "#fd8f3d"), ("color", "#f1f1f1")], - }, - ), - ( - None, - { - (7, 0): [("background-color", "#48c16e"), ("color", "#f1f1f1")], - (7, 1): [("background-color", "#4cc26c"), ("color", "#000000")], - }, - ), - ], -) -def test_text_color_threshold(cmap, expected): - # GH 39888 - df = DataFrame(np.arange(100).reshape(10, 10)) - result = df.style.background_gradient(cmap=cmap, axis=None)._compute().ctx - for k in expected.keys(): - assert result[k] == expected[k] - - -def test_background_gradient_vmin_vmax(): - # GH 12145 - df = DataFrame(range(5)) - ctx = df.style.background_gradient(vmin=1, vmax=3)._compute().ctx - assert ctx[(0, 0)] == ctx[(1, 0)] - assert ctx[(4, 0)] == ctx[(3, 0)] - - -def test_background_gradient_int64(): - # GH 28869 - df1 = Series(range(3)).to_frame() - df2 = Series(range(3), dtype="Int64").to_frame() - ctx1 = df1.style.background_gradient()._compute().ctx - ctx2 = df2.style.background_gradient()._compute().ctx - assert ctx2[(0, 0)] == ctx1[(0, 0)] - assert ctx2[(1, 0)] == ctx1[(1, 0)] - assert ctx2[(2, 0)] == ctx1[(2, 0)] - - -@pytest.mark.parametrize( - "axis, gmap, expected", - [ - ( - 0, - [1, 2], - { - (0, 0): [("background-color", "#fff7fb"), ("color", "#000000")], - (1, 0): [("background-color", "#023858"), ("color", "#f1f1f1")], - (0, 1): [("background-color", "#fff7fb"), ("color", "#000000")], - (1, 1): [("background-color", "#023858"), ("color", "#f1f1f1")], - }, - ), - ( - 1, - [1, 2], - { - (0, 0): [("background-color", "#fff7fb"), ("color", "#000000")], - (1, 0): [("background-color", "#fff7fb"), ("color", "#000000")], - (0, 1): [("background-color", "#023858"), ("color", "#f1f1f1")], - (1, 1): [("background-color", "#023858"), ("color", "#f1f1f1")], - }, - ), - ( - None, - np.array([[2, 1], [1, 2]]), - { - (0, 0): [("background-color", "#023858"), ("color", "#f1f1f1")], - (1, 0): [("background-color", "#fff7fb"), ("color", "#000000")], - (0, 1): [("background-color", "#fff7fb"), ("color", "#000000")], - (1, 1): [("background-color", "#023858"), ("color", "#f1f1f1")], - }, - ), - ], -) -def test_background_gradient_gmap_array(styler_blank, axis, gmap, expected): - # tests when gmap is given as a sequence and converted to ndarray - result = styler_blank.background_gradient(axis=axis, gmap=gmap)._compute().ctx - assert result == expected - - -@pytest.mark.parametrize( - "gmap, axis", [([1, 2, 3], 0), ([1, 2], 1), (np.array([[1, 2], [1, 2]]), None)] -) -def test_background_gradient_gmap_array_raises(gmap, axis): - # test when gmap as converted ndarray is bad shape - df = DataFrame([[0, 0, 0], [0, 0, 0]]) - msg = "supplied 'gmap' is not correct shape" - with pytest.raises(ValueError, match=msg): - df.style.background_gradient(gmap=gmap, axis=axis)._compute() - - -@pytest.mark.parametrize( - "gmap", - [ - DataFrame( # reverse the columns - [[2, 1], [1, 2]], columns=["B", "A"], index=["X", "Y"] - ), - DataFrame( # reverse the index - [[2, 1], [1, 2]], columns=["A", "B"], index=["Y", "X"] - ), - DataFrame( # reverse the index and columns - [[1, 2], [2, 1]], columns=["B", "A"], index=["Y", "X"] - ), - DataFrame( # add unnecessary columns - [[1, 2, 3], [2, 1, 3]], columns=["A", "B", "C"], index=["X", "Y"] - ), - DataFrame( # add unnecessary index - [[1, 2], [2, 1], [3, 3]], columns=["A", "B"], index=["X", "Y", "Z"] - ), - ], -) -@pytest.mark.parametrize( - "subset, exp_gmap", # exp_gmap is underlying map DataFrame should conform to - [ - (None, [[1, 2], [2, 1]]), - (["A"], [[1], [2]]), # slice only column "A" in data and gmap - (["B", "A"], [[2, 1], [1, 2]]), # reverse the columns in data - (IndexSlice["X", :], [[1, 2]]), # slice only index "X" in data and gmap - (IndexSlice[["Y", "X"], :], [[2, 1], [1, 2]]), # reverse the index in data - ], -) -def test_background_gradient_gmap_dataframe_align(styler_blank, gmap, subset, exp_gmap): - # test gmap given as DataFrame that it aligns to the the data including subset - expected = styler_blank.background_gradient(axis=None, gmap=exp_gmap, subset=subset) - result = styler_blank.background_gradient(axis=None, gmap=gmap, subset=subset) - assert expected._compute().ctx == result._compute().ctx - - -@pytest.mark.parametrize( - "gmap, axis, exp_gmap", - [ - (Series([2, 1], index=["Y", "X"]), 0, [[1, 1], [2, 2]]), # revrse the index - (Series([2, 1], index=["B", "A"]), 1, [[1, 2], [1, 2]]), # revrse the cols - (Series([1, 2, 3], index=["X", "Y", "Z"]), 0, [[1, 1], [2, 2]]), # add idx - (Series([1, 2, 3], index=["A", "B", "C"]), 1, [[1, 2], [1, 2]]), # add col - ], -) -def test_background_gradient_gmap_series_align(styler_blank, gmap, axis, exp_gmap): - # test gmap given as Series that it aligns to the the data including subset - expected = styler_blank.background_gradient(axis=None, gmap=exp_gmap)._compute() - result = styler_blank.background_gradient(axis=axis, gmap=gmap)._compute() - assert expected.ctx == result.ctx - - -@pytest.mark.parametrize( - "gmap, axis", - [ - (DataFrame([[1, 2], [2, 1]], columns=["A", "B"], index=["X", "Y"]), 1), - (DataFrame([[1, 2], [2, 1]], columns=["A", "B"], index=["X", "Y"]), 0), - ], -) -def test_background_gradient_gmap_wrong_dataframe(styler_blank, gmap, axis): - # test giving a gmap in DataFrame but with wrong axis - msg = "'gmap' is a DataFrame but underlying data for operations is a Series" - with pytest.raises(ValueError, match=msg): - styler_blank.background_gradient(gmap=gmap, axis=axis)._compute() - - -def test_background_gradient_gmap_wrong_series(styler_blank): - # test giving a gmap in Series form but with wrong axis - msg = "'gmap' is a Series but underlying data for operations is a DataFrame" - gmap = Series([1, 2], index=["X", "Y"]) - with pytest.raises(ValueError, match=msg): - styler_blank.background_gradient(gmap=gmap, axis=None)._compute() - - -@pytest.mark.parametrize("cmap", ["PuBu", mpl.cm.get_cmap("PuBu")]) -def test_bar_colormap(cmap): - data = DataFrame([[1, 2], [3, 4]]) - ctx = data.style.bar(cmap=cmap, axis=None)._compute().ctx - pubu_colors = { - (0, 0): "#d0d1e6", - (1, 0): "#056faf", - (0, 1): "#73a9cf", - (1, 1): "#023858", - } - for k, v in pubu_colors.items(): - assert v in ctx[k][1][1] - - -def test_bar_color_raises(df): - msg = "`color` must be string or list or tuple of 2 strings" - with pytest.raises(ValueError, match=msg): - df.style.bar(color={"a", "b"}).to_html() - with pytest.raises(ValueError, match=msg): - df.style.bar(color=["a", "b", "c"]).to_html() - - msg = "`color` and `cmap` cannot both be given" - with pytest.raises(ValueError, match=msg): - df.style.bar(color="something", cmap="something else").to_html() diff --git a/pandas/tests/io/formats/style/test_non_unique.py b/pandas/tests/io/formats/style/test_non_unique.py deleted file mode 100644 index b719bf3372038..0000000000000 --- a/pandas/tests/io/formats/style/test_non_unique.py +++ /dev/null @@ -1,140 +0,0 @@ -from textwrap import dedent - -import pytest - -from pandas import ( - DataFrame, - IndexSlice, -) - -pytest.importorskip("jinja2") - -from pandas.io.formats.style import Styler - - -@pytest.fixture -def df(): - return DataFrame( - [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - index=["i", "j", "j"], - columns=["c", "d", "d"], - dtype=float, - ) - - -@pytest.fixture -def styler(df): - return Styler(df, uuid_len=0) - - -def test_format_non_unique(df): - # GH 41269 - - # test dict - html = df.style.format({"d": "{:.1f}"}).to_html() - for val in ["1.000000<", "4.000000<", "7.000000<"]: - assert val in html - for val in ["2.0<", "3.0<", "5.0<", "6.0<", "8.0<", "9.0<"]: - assert val in html - - # test subset - html = df.style.format(precision=1, subset=IndexSlice["j", "d"]).to_html() - for val in ["1.000000<", "4.000000<", "7.000000<", "2.000000<", "3.000000<"]: - assert val in html - for val in ["5.0<", "6.0<", "8.0<", "9.0<"]: - assert val in html - - -@pytest.mark.parametrize("func", ["apply", "applymap"]) -def test_apply_applymap_non_unique_raises(df, func): - # GH 41269 - if func == "apply": - op = lambda s: ["color: red;"] * len(s) - else: - op = lambda v: "color: red;" - - with pytest.raises(KeyError, match="`Styler.apply` and `.applymap` are not"): - getattr(df.style, func)(op)._compute() - - -def test_table_styles_dict_non_unique_index(styler): - styles = styler.set_table_styles( - {"j": [{"selector": "td", "props": "a: v;"}]}, axis=1 - ).table_styles - assert styles == [ - {"selector": "td.row1", "props": [("a", "v")]}, - {"selector": "td.row2", "props": [("a", "v")]}, - ] - - -def test_table_styles_dict_non_unique_columns(styler): - styles = styler.set_table_styles( - {"d": [{"selector": "td", "props": "a: v;"}]}, axis=0 - ).table_styles - assert styles == [ - {"selector": "td.col1", "props": [("a", "v")]}, - {"selector": "td.col2", "props": [("a", "v")]}, - ] - - -def test_tooltips_non_unique_raises(styler): - # ttips has unique keys - ttips = DataFrame([["1", "2"], ["3", "4"]], columns=["c", "d"], index=["a", "b"]) - styler.set_tooltips(ttips=ttips) # OK - - # ttips has non-unique columns - ttips = DataFrame([["1", "2"], ["3", "4"]], columns=["c", "c"], index=["a", "b"]) - with pytest.raises(KeyError, match="Tooltips render only if `ttips` has unique"): - styler.set_tooltips(ttips=ttips) - - # ttips has non-unique index - ttips = DataFrame([["1", "2"], ["3", "4"]], columns=["c", "d"], index=["a", "a"]) - with pytest.raises(KeyError, match="Tooltips render only if `ttips` has unique"): - styler.set_tooltips(ttips=ttips) - - -def test_set_td_classes_non_unique_raises(styler): - # classes has unique keys - classes = DataFrame([["1", "2"], ["3", "4"]], columns=["c", "d"], index=["a", "b"]) - styler.set_td_classes(classes=classes) # OK - - # classes has non-unique columns - classes = DataFrame([["1", "2"], ["3", "4"]], columns=["c", "c"], index=["a", "b"]) - with pytest.raises(KeyError, match="Classes render only if `classes` has unique"): - styler.set_td_classes(classes=classes) - - # classes has non-unique index - classes = DataFrame([["1", "2"], ["3", "4"]], columns=["c", "d"], index=["a", "a"]) - with pytest.raises(KeyError, match="Classes render only if `classes` has unique"): - styler.set_td_classes(classes=classes) - - -def test_hide_columns_non_unique(styler): - ctx = styler.hide(["d"], axis="columns")._translate(True, True) - - assert ctx["head"][0][1]["display_value"] == "c" - assert ctx["head"][0][1]["is_visible"] is True - - assert ctx["head"][0][2]["display_value"] == "d" - assert ctx["head"][0][2]["is_visible"] is False - - assert ctx["head"][0][3]["display_value"] == "d" - assert ctx["head"][0][3]["is_visible"] is False - - assert ctx["body"][0][1]["is_visible"] is True - assert ctx["body"][0][2]["is_visible"] is False - assert ctx["body"][0][3]["is_visible"] is False - - -def test_latex_non_unique(styler): - result = styler.to_latex() - assert result == dedent( - """\ - \\begin{tabular}{lrrr} - & c & d & d \\\\ - i & 1.000000 & 2.000000 & 3.000000 \\\\ - j & 4.000000 & 5.000000 & 6.000000 \\\\ - j & 7.000000 & 8.000000 & 9.000000 \\\\ - \\end{tabular} - """ - ) diff --git a/pandas/tests/io/formats/style/test_style.py b/pandas/tests/io/formats/style/test_style.py deleted file mode 100644 index 915497e614b3a..0000000000000 --- a/pandas/tests/io/formats/style/test_style.py +++ /dev/null @@ -1,1556 +0,0 @@ -import copy -import re -from textwrap import dedent - -import numpy as np -import pytest - -from pandas import ( - Categorical, - DataFrame, - IndexSlice, - MultiIndex, - Series, - option_context, -) -import pandas._testing as tm - -jinja2 = pytest.importorskip("jinja2") -from pandas.io.formats.style import ( # isort:skip - Styler, -) -from pandas.io.formats.style_render import ( - _get_level_lengths, - _get_trimming_maximums, - maybe_convert_css_to_tuples, - non_reducing_slice, -) - - -@pytest.fixture -def mi_df(): - return DataFrame( - [[1, 2], [3, 4]], - index=MultiIndex.from_product([["i0"], ["i1_a", "i1_b"]]), - columns=MultiIndex.from_product([["c0"], ["c1_a", "c1_b"]]), - dtype=int, - ) - - -@pytest.fixture -def mi_styler(mi_df): - return Styler(mi_df, uuid_len=0) - - -@pytest.fixture -def mi_styler_comp(mi_styler): - # comprehensively add features to mi_styler - mi_styler = mi_styler._copy(deepcopy=True) - mi_styler.css = {**mi_styler.css, **{"row": "ROW", "col": "COL"}} - mi_styler.uuid_len = 5 - mi_styler.uuid = "abcde" - mi_styler.set_caption("capt") - mi_styler.set_table_styles([{"selector": "a", "props": "a:v;"}]) - mi_styler.hide(axis="columns") - mi_styler.hide([("c0", "c1_a")], axis="columns", names=True) - mi_styler.hide(axis="index") - mi_styler.hide([("i0", "i1_a")], axis="index", names=True) - mi_styler.set_table_attributes('class="box"') - mi_styler.format(na_rep="MISSING", precision=3) - mi_styler.format_index(precision=2, axis=0) - mi_styler.format_index(precision=4, axis=1) - mi_styler.highlight_max(axis=None) - mi_styler.applymap_index(lambda x: "color: white;", axis=0) - mi_styler.applymap_index(lambda x: "color: black;", axis=1) - mi_styler.set_td_classes( - DataFrame( - [["a", "b"], ["a", "c"]], index=mi_styler.index, columns=mi_styler.columns - ) - ) - mi_styler.set_tooltips( - DataFrame( - [["a2", "b2"], ["a2", "c2"]], - index=mi_styler.index, - columns=mi_styler.columns, - ) - ) - return mi_styler - - -@pytest.mark.parametrize( - "sparse_columns, exp_cols", - [ - ( - True, - [ - {"is_visible": True, "attributes": 'colspan="2"', "value": "c0"}, - {"is_visible": False, "attributes": "", "value": "c0"}, - ], - ), - ( - False, - [ - {"is_visible": True, "attributes": "", "value": "c0"}, - {"is_visible": True, "attributes": "", "value": "c0"}, - ], - ), - ], -) -def test_mi_styler_sparsify_columns(mi_styler, sparse_columns, exp_cols): - exp_l1_c0 = {"is_visible": True, "attributes": "", "display_value": "c1_a"} - exp_l1_c1 = {"is_visible": True, "attributes": "", "display_value": "c1_b"} - - ctx = mi_styler._translate(True, sparse_columns) - - assert exp_cols[0].items() <= ctx["head"][0][2].items() - assert exp_cols[1].items() <= ctx["head"][0][3].items() - assert exp_l1_c0.items() <= ctx["head"][1][2].items() - assert exp_l1_c1.items() <= ctx["head"][1][3].items() - - -@pytest.mark.parametrize( - "sparse_index, exp_rows", - [ - ( - True, - [ - {"is_visible": True, "attributes": 'rowspan="2"', "value": "i0"}, - {"is_visible": False, "attributes": "", "value": "i0"}, - ], - ), - ( - False, - [ - {"is_visible": True, "attributes": "", "value": "i0"}, - {"is_visible": True, "attributes": "", "value": "i0"}, - ], - ), - ], -) -def test_mi_styler_sparsify_index(mi_styler, sparse_index, exp_rows): - exp_l1_r0 = {"is_visible": True, "attributes": "", "display_value": "i1_a"} - exp_l1_r1 = {"is_visible": True, "attributes": "", "display_value": "i1_b"} - - ctx = mi_styler._translate(sparse_index, True) - - assert exp_rows[0].items() <= ctx["body"][0][0].items() - assert exp_rows[1].items() <= ctx["body"][1][0].items() - assert exp_l1_r0.items() <= ctx["body"][0][1].items() - assert exp_l1_r1.items() <= ctx["body"][1][1].items() - - -def test_mi_styler_sparsify_options(mi_styler): - with option_context("styler.sparse.index", False): - html1 = mi_styler.to_html() - with option_context("styler.sparse.index", True): - html2 = mi_styler.to_html() - - assert html1 != html2 - - with option_context("styler.sparse.columns", False): - html1 = mi_styler.to_html() - with option_context("styler.sparse.columns", True): - html2 = mi_styler.to_html() - - assert html1 != html2 - - -@pytest.mark.parametrize( - "rn, cn, max_els, max_rows, max_cols, exp_rn, exp_cn", - [ - (100, 100, 100, None, None, 12, 6), # reduce to (12, 6) < 100 elements - (1000, 3, 750, None, None, 250, 3), # dynamically reduce rows to 250, keep cols - (4, 1000, 500, None, None, 4, 125), # dynamically reduce cols to 125, keep rows - (1000, 3, 750, 10, None, 10, 3), # overwrite above dynamics with max_row - (4, 1000, 500, None, 5, 4, 5), # overwrite above dynamics with max_col - (100, 100, 700, 50, 50, 25, 25), # rows cols below given maxes so < 700 elmts - ], -) -def test_trimming_maximum(rn, cn, max_els, max_rows, max_cols, exp_rn, exp_cn): - rn, cn = _get_trimming_maximums( - rn, cn, max_els, max_rows, max_cols, scaling_factor=0.5 - ) - assert (rn, cn) == (exp_rn, exp_cn) - - -@pytest.mark.parametrize( - "option, val", - [ - ("styler.render.max_elements", 6), - ("styler.render.max_rows", 3), - ], -) -def test_render_trimming_rows(option, val): - # test auto and specific trimming of rows - df = DataFrame(np.arange(120).reshape(60, 2)) - with option_context(option, val): - ctx = df.style._translate(True, True) - assert len(ctx["head"][0]) == 3 # index + 2 data cols - assert len(ctx["body"]) == 4 # 3 data rows + trimming row - assert len(ctx["body"][0]) == 3 # index + 2 data cols - - -@pytest.mark.parametrize( - "option, val", - [ - ("styler.render.max_elements", 6), - ("styler.render.max_columns", 2), - ], -) -def test_render_trimming_cols(option, val): - # test auto and specific trimming of cols - df = DataFrame(np.arange(30).reshape(3, 10)) - with option_context(option, val): - ctx = df.style._translate(True, True) - assert len(ctx["head"][0]) == 4 # index + 2 data cols + trimming col - assert len(ctx["body"]) == 3 # 3 data rows - assert len(ctx["body"][0]) == 4 # index + 2 data cols + trimming col - - -def test_render_trimming_mi(): - midx = MultiIndex.from_product([[1, 2], [1, 2, 3]]) - df = DataFrame(np.arange(36).reshape(6, 6), columns=midx, index=midx) - with option_context("styler.render.max_elements", 4): - ctx = df.style._translate(True, True) - - assert len(ctx["body"][0]) == 5 # 2 indexes + 2 data cols + trimming row - assert {"attributes": 'rowspan="2"'}.items() <= ctx["body"][0][0].items() - assert {"class": "data row0 col_trim"}.items() <= ctx["body"][0][4].items() - assert {"class": "data row_trim col_trim"}.items() <= ctx["body"][2][4].items() - assert len(ctx["body"]) == 3 # 2 data rows + trimming row - - -def test_render_empty_mi(): - # GH 43305 - df = DataFrame(index=MultiIndex.from_product([["A"], [0, 1]], names=[None, "one"])) - expected = dedent( - """\ - > - - -   - one - - - """ - ) - assert expected in df.style.to_html() - - -@pytest.mark.parametrize("comprehensive", [True, False]) -@pytest.mark.parametrize("render", [True, False]) -@pytest.mark.parametrize("deepcopy", [True, False]) -def test_copy(comprehensive, render, deepcopy, mi_styler, mi_styler_comp): - styler = mi_styler_comp if comprehensive else mi_styler - styler.uuid_len = 5 - - s2 = copy.deepcopy(styler) if deepcopy else copy.copy(styler) # make copy and check - assert s2 is not styler - - if render: - styler.to_html() - - excl = [ - "na_rep", # deprecated - "precision", # deprecated - "cellstyle_map", # render time vars.. - "cellstyle_map_columns", - "cellstyle_map_index", - "template_latex", # render templates are class level - "template_html", - "template_html_style", - "template_html_table", - ] - if not deepcopy: # check memory locations are equal for all included attributes - for attr in [a for a in styler.__dict__ if (not callable(a) and a not in excl)]: - assert id(getattr(s2, attr)) == id(getattr(styler, attr)) - else: # check memory locations are different for nested or mutable vars - shallow = [ - "data", - "columns", - "index", - "uuid_len", - "uuid", - "caption", - "cell_ids", - "hide_index_", - "hide_columns_", - "hide_index_names", - "hide_column_names", - "table_attributes", - ] - for attr in shallow: - assert id(getattr(s2, attr)) == id(getattr(styler, attr)) - - for attr in [ - a - for a in styler.__dict__ - if (not callable(a) and a not in excl and a not in shallow) - ]: - if getattr(s2, attr) is None: - assert id(getattr(s2, attr)) == id(getattr(styler, attr)) - else: - assert id(getattr(s2, attr)) != id(getattr(styler, attr)) - - -def test_clear(mi_styler_comp): - # NOTE: if this test fails for new features then 'mi_styler_comp' should be updated - # to ensure proper testing of the 'copy', 'clear', 'export' methods with new feature - # GH 40675 - styler = mi_styler_comp - styler._compute() # execute applied methods - - clean_copy = Styler(styler.data, uuid=styler.uuid) - - excl = [ - "data", - "index", - "columns", - "uuid", - "uuid_len", # uuid is set to be the same on styler and clean_copy - "cell_ids", - "cellstyle_map", # execution time only - "cellstyle_map_columns", # execution time only - "cellstyle_map_index", # execution time only - "precision", # deprecated - "na_rep", # deprecated - "template_latex", # render templates are class level - "template_html", - "template_html_style", - "template_html_table", - ] - # tests vars are not same vals on obj and clean copy before clear (except for excl) - for attr in [a for a in styler.__dict__ if not (callable(a) or a in excl)]: - res = getattr(styler, attr) == getattr(clean_copy, attr) - if hasattr(res, "__iter__") and len(res) > 0: - assert not all(res) # some element in iterable differs - elif hasattr(res, "__iter__") and len(res) == 0: - pass # empty array - else: - assert not res # explicit var differs - - # test vars have same vales on obj and clean copy after clearing - styler.clear() - for attr in [a for a in styler.__dict__ if not (callable(a))]: - res = getattr(styler, attr) == getattr(clean_copy, attr) - assert all(res) if hasattr(res, "__iter__") else res - - -def test_export(mi_styler_comp, mi_styler): - exp_attrs = [ - "_todo", - "hide_index_", - "hide_index_names", - "hide_columns_", - "hide_column_names", - "table_attributes", - "table_styles", - "css", - ] - for attr in exp_attrs: - check = getattr(mi_styler, attr) == getattr(mi_styler_comp, attr) - assert not ( - all(check) if (hasattr(check, "__iter__") and len(check) > 0) else check - ) - - export = mi_styler_comp.export() - used = mi_styler.use(export) - for attr in exp_attrs: - check = getattr(used, attr) == getattr(mi_styler_comp, attr) - assert all(check) if (hasattr(check, "__iter__") and len(check) > 0) else check - - used.to_html() - - -def test_hide_raises(mi_styler): - msg = "`subset` and `level` cannot be passed simultaneously" - with pytest.raises(ValueError, match=msg): - mi_styler.hide(axis="index", subset="something", level="something else") - - msg = "`level` must be of type `int`, `str` or list of such" - with pytest.raises(ValueError, match=msg): - mi_styler.hide(axis="index", level={"bad": 1, "type": 2}) - - -@pytest.mark.parametrize("level", [1, "one", [1], ["one"]]) -def test_hide_index_level(mi_styler, level): - mi_styler.index.names, mi_styler.columns.names = ["zero", "one"], ["zero", "one"] - ctx = mi_styler.hide(axis="index", level=level)._translate(False, True) - assert len(ctx["head"][0]) == 3 - assert len(ctx["head"][1]) == 3 - assert len(ctx["head"][2]) == 4 - assert ctx["head"][2][0]["is_visible"] - assert not ctx["head"][2][1]["is_visible"] - - assert ctx["body"][0][0]["is_visible"] - assert not ctx["body"][0][1]["is_visible"] - assert ctx["body"][1][0]["is_visible"] - assert not ctx["body"][1][1]["is_visible"] - - -@pytest.mark.parametrize("level", [1, "one", [1], ["one"]]) -@pytest.mark.parametrize("names", [True, False]) -def test_hide_columns_level(mi_styler, level, names): - mi_styler.columns.names = ["zero", "one"] - if names: - mi_styler.index.names = ["zero", "one"] - ctx = mi_styler.hide(axis="columns", level=level)._translate(True, False) - assert len(ctx["head"]) == (2 if names else 1) - - -@pytest.mark.parametrize("method", ["applymap", "apply"]) -@pytest.mark.parametrize("axis", ["index", "columns"]) -def test_apply_map_header(method, axis): - # GH 41893 - df = DataFrame({"A": [0, 0], "B": [1, 1]}, index=["C", "D"]) - func = { - "apply": lambda s: ["attr: val" if ("A" in v or "C" in v) else "" for v in s], - "applymap": lambda v: "attr: val" if ("A" in v or "C" in v) else "", - } - - # test execution added to todo - result = getattr(df.style, f"{method}_index")(func[method], axis=axis) - assert len(result._todo) == 1 - assert len(getattr(result, f"ctx_{axis}")) == 0 - - # test ctx object on compute - result._compute() - expected = { - (0, 0): [("attr", "val")], - } - assert getattr(result, f"ctx_{axis}") == expected - - -@pytest.mark.parametrize("method", ["apply", "applymap"]) -@pytest.mark.parametrize("axis", ["index", "columns"]) -def test_apply_map_header_mi(mi_styler, method, axis): - # GH 41893 - func = { - "apply": lambda s: ["attr: val;" if "b" in v else "" for v in s], - "applymap": lambda v: "attr: val" if "b" in v else "", - } - result = getattr(mi_styler, f"{method}_index")(func[method], axis=axis)._compute() - expected = {(1, 1): [("attr", "val")]} - assert getattr(result, f"ctx_{axis}") == expected - - -def test_apply_map_header_raises(mi_styler): - # GH 41893 - with pytest.raises(ValueError, match="No axis named bad for object type DataFrame"): - mi_styler.applymap_index(lambda v: "attr: val;", axis="bad")._compute() - - -class TestStyler: - def setup_method(self, method): - np.random.seed(24) - self.s = DataFrame({"A": np.random.permutation(range(6))}) - self.df = DataFrame({"A": [0, 1], "B": np.random.randn(2)}) - self.f = lambda x: x - self.g = lambda x: x - - def h(x, foo="bar"): - return Series(f"color: {foo}", index=x.index, name=x.name) - - self.h = h - self.styler = Styler(self.df) - self.attrs = DataFrame({"A": ["color: red", "color: blue"]}) - self.dataframes = [ - self.df, - DataFrame({"f": [1.0, 2.0], "o": ["a", "b"], "c": Categorical(["a", "b"])}), - ] - self.blank_value = " " - - def test_init_non_pandas(self): - msg = "``data`` must be a Series or DataFrame" - with pytest.raises(TypeError, match=msg): - Styler([1, 2, 3]) - - def test_init_series(self): - result = Styler(Series([1, 2])) - assert result.data.ndim == 2 - - def test_repr_html_ok(self): - self.styler._repr_html_() - - def test_repr_html_mathjax(self): - # gh-19824 / 41395 - assert "tex2jax_ignore" not in self.styler._repr_html_() - - with option_context("styler.html.mathjax", False): - assert "tex2jax_ignore" in self.styler._repr_html_() - - def test_update_ctx(self): - self.styler._update_ctx(self.attrs) - expected = {(0, 0): [("color", "red")], (1, 0): [("color", "blue")]} - assert self.styler.ctx == expected - - def test_update_ctx_flatten_multi_and_trailing_semi(self): - attrs = DataFrame({"A": ["color: red; foo: bar", "color:blue ; foo: baz;"]}) - self.styler._update_ctx(attrs) - expected = { - (0, 0): [("color", "red"), ("foo", "bar")], - (1, 0): [("color", "blue"), ("foo", "baz")], - } - assert self.styler.ctx == expected - - def test_render(self): - df = DataFrame({"A": [0, 1]}) - style = lambda x: Series(["color: red", "color: blue"], name=x.name) - s = Styler(df, uuid="AB").apply(style) - s.to_html() - # it worked? - - def test_multiple_render(self): - # GH 39396 - s = Styler(self.df, uuid_len=0).applymap(lambda x: "color: red;", subset=["A"]) - s.to_html() # do 2 renders to ensure css styles not duplicated - assert ( - '" in s.to_html() - ) - - def test_render_empty_dfs(self): - empty_df = DataFrame() - es = Styler(empty_df) - es.to_html() - # An index but no columns - DataFrame(columns=["a"]).style.to_html() - # A column but no index - DataFrame(index=["a"]).style.to_html() - # No IndexError raised? - - def test_render_double(self): - df = DataFrame({"A": [0, 1]}) - style = lambda x: Series( - ["color: red; border: 1px", "color: blue; border: 2px"], name=x.name - ) - s = Styler(df, uuid="AB").apply(style) - s.to_html() - # it worked? - - def test_set_properties(self): - df = DataFrame({"A": [0, 1]}) - result = df.style.set_properties(color="white", size="10px")._compute().ctx - # order is deterministic - v = [("color", "white"), ("size", "10px")] - expected = {(0, 0): v, (1, 0): v} - assert result.keys() == expected.keys() - for v1, v2 in zip(result.values(), expected.values()): - assert sorted(v1) == sorted(v2) - - def test_set_properties_subset(self): - df = DataFrame({"A": [0, 1]}) - result = ( - df.style.set_properties(subset=IndexSlice[0, "A"], color="white") - ._compute() - .ctx - ) - expected = {(0, 0): [("color", "white")]} - assert result == expected - - def test_empty_index_name_doesnt_display(self): - # https://github.com/pandas-dev/pandas/pull/12090#issuecomment-180695902 - df = DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]}) - result = df.style._translate(True, True) - assert len(result["head"]) == 1 - expected = { - "class": "blank level0", - "type": "th", - "value": self.blank_value, - "is_visible": True, - "display_value": self.blank_value, - } - assert expected.items() <= result["head"][0][0].items() - - def test_index_name(self): - # https://github.com/pandas-dev/pandas/issues/11655 - df = DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]}) - result = df.set_index("A").style._translate(True, True) - expected = { - "class": "index_name level0", - "type": "th", - "value": "A", - "is_visible": True, - "display_value": "A", - } - assert expected.items() <= result["head"][1][0].items() - - def test_numeric_columns(self): - # https://github.com/pandas-dev/pandas/issues/12125 - # smoke test for _translate - df = DataFrame({0: [1, 2, 3]}) - df.style._translate(True, True) - - def test_apply_axis(self): - df = DataFrame({"A": [0, 0], "B": [1, 1]}) - f = lambda x: [f"val: {x.max()}" for v in x] - result = df.style.apply(f, axis=1) - assert len(result._todo) == 1 - assert len(result.ctx) == 0 - result._compute() - expected = { - (0, 0): [("val", "1")], - (0, 1): [("val", "1")], - (1, 0): [("val", "1")], - (1, 1): [("val", "1")], - } - assert result.ctx == expected - - result = df.style.apply(f, axis=0) - expected = { - (0, 0): [("val", "0")], - (0, 1): [("val", "1")], - (1, 0): [("val", "0")], - (1, 1): [("val", "1")], - } - result._compute() - assert result.ctx == expected - result = df.style.apply(f) # default - result._compute() - assert result.ctx == expected - - @pytest.mark.parametrize("axis", [0, 1]) - def test_apply_series_return(self, axis): - # GH 42014 - df = DataFrame([[1, 2], [3, 4]], index=["X", "Y"], columns=["X", "Y"]) - - # test Series return where len(Series) < df.index or df.columns but labels OK - func = lambda s: Series(["color: red;"], index=["Y"]) - result = df.style.apply(func, axis=axis)._compute().ctx - assert result[(1, 1)] == [("color", "red")] - assert result[(1 - axis, axis)] == [("color", "red")] - - # test Series return where labels align but different order - func = lambda s: Series(["color: red;", "color: blue;"], index=["Y", "X"]) - result = df.style.apply(func, axis=axis)._compute().ctx - assert result[(0, 0)] == [("color", "blue")] - assert result[(1, 1)] == [("color", "red")] - assert result[(1 - axis, axis)] == [("color", "red")] - assert result[(axis, 1 - axis)] == [("color", "blue")] - - @pytest.mark.parametrize("index", [False, True]) - @pytest.mark.parametrize("columns", [False, True]) - def test_apply_dataframe_return(self, index, columns): - # GH 42014 - df = DataFrame([[1, 2], [3, 4]], index=["X", "Y"], columns=["X", "Y"]) - idxs = ["X", "Y"] if index else ["Y"] - cols = ["X", "Y"] if columns else ["Y"] - df_styles = DataFrame("color: red;", index=idxs, columns=cols) - result = df.style.apply(lambda x: df_styles, axis=None)._compute().ctx - - assert result[(1, 1)] == [("color", "red")] # (Y,Y) styles always present - assert (result[(0, 1)] == [("color", "red")]) is index # (X,Y) only if index - assert (result[(1, 0)] == [("color", "red")]) is columns # (Y,X) only if cols - assert (result[(0, 0)] == [("color", "red")]) is (index and columns) # (X,X) - - @pytest.mark.parametrize( - "slice_", - [ - IndexSlice[:], - IndexSlice[:, ["A"]], - IndexSlice[[1], :], - IndexSlice[[1], ["A"]], - IndexSlice[:2, ["A", "B"]], - ], - ) - @pytest.mark.parametrize("axis", [0, 1]) - def test_apply_subset(self, slice_, axis): - result = ( - self.df.style.apply(self.h, axis=axis, subset=slice_, foo="baz") - ._compute() - .ctx - ) - expected = { - (r, c): [("color", "baz")] - for r, row in enumerate(self.df.index) - for c, col in enumerate(self.df.columns) - if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns - } - assert result == expected - - @pytest.mark.parametrize( - "slice_", - [ - IndexSlice[:], - IndexSlice[:, ["A"]], - IndexSlice[[1], :], - IndexSlice[[1], ["A"]], - IndexSlice[:2, ["A", "B"]], - ], - ) - def test_applymap_subset(self, slice_): - result = ( - self.df.style.applymap(lambda x: "color:baz;", subset=slice_)._compute().ctx - ) - expected = { - (r, c): [("color", "baz")] - for r, row in enumerate(self.df.index) - for c, col in enumerate(self.df.columns) - if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns - } - assert result == expected - - @pytest.mark.parametrize( - "slice_", - [ - IndexSlice[:, IndexSlice["x", "A"]], - IndexSlice[:, IndexSlice[:, "A"]], - IndexSlice[:, IndexSlice[:, ["A", "C"]]], # missing col element - IndexSlice[IndexSlice["a", 1], :], - IndexSlice[IndexSlice[:, 1], :], - IndexSlice[IndexSlice[:, [1, 3]], :], # missing row element - IndexSlice[:, ("x", "A")], - IndexSlice[("a", 1), :], - ], - ) - def test_applymap_subset_multiindex(self, slice_): - # GH 19861 - # edited for GH 33562 - warn = None - msg = "indexing on a MultiIndex with a nested sequence of labels" - if ( - isinstance(slice_[-1], tuple) - and isinstance(slice_[-1][-1], list) - and "C" in slice_[-1][-1] - ): - warn = FutureWarning - elif ( - isinstance(slice_[0], tuple) - and isinstance(slice_[0][1], list) - and 3 in slice_[0][1] - ): - warn = FutureWarning - - idx = MultiIndex.from_product([["a", "b"], [1, 2]]) - col = MultiIndex.from_product([["x", "y"], ["A", "B"]]) - df = DataFrame(np.random.rand(4, 4), columns=col, index=idx) - - with tm.assert_produces_warning(warn, match=msg): - df.style.applymap(lambda x: "color: red;", subset=slice_).to_html() - - def test_applymap_subset_multiindex_code(self): - # https://github.com/pandas-dev/pandas/issues/25858 - # Checks styler.applymap works with multindex when codes are provided - codes = np.array([[0, 0, 1, 1], [0, 1, 0, 1]]) - columns = MultiIndex( - levels=[["a", "b"], ["%", "#"]], codes=codes, names=["", ""] - ) - df = DataFrame( - [[1, -1, 1, 1], [-1, 1, 1, 1]], index=["hello", "world"], columns=columns - ) - pct_subset = IndexSlice[:, IndexSlice[:, "%":"%"]] - - def color_negative_red(val): - color = "red" if val < 0 else "black" - return f"color: {color}" - - df.loc[pct_subset] - df.style.applymap(color_negative_red, subset=pct_subset) - - def test_empty(self): - df = DataFrame({"A": [1, 0]}) - s = df.style - s.ctx = {(0, 0): [("color", "red")], (1, 0): [("", "")]} - - result = s._translate(True, True)["cellstyle"] - expected = [ - {"props": [("color", "red")], "selectors": ["row0_col0"]}, - {"props": [("", "")], "selectors": ["row1_col0"]}, - ] - assert result == expected - - def test_duplicate(self): - df = DataFrame({"A": [1, 0]}) - s = df.style - s.ctx = {(0, 0): [("color", "red")], (1, 0): [("color", "red")]} - - result = s._translate(True, True)["cellstyle"] - expected = [ - {"props": [("color", "red")], "selectors": ["row0_col0", "row1_col0"]} - ] - assert result == expected - - def test_init_with_na_rep(self): - # GH 21527 28358 - df = DataFrame([[None, None], [1.1, 1.2]], columns=["A", "B"]) - - ctx = Styler(df, na_rep="NA")._translate(True, True) - assert ctx["body"][0][1]["display_value"] == "NA" - assert ctx["body"][0][2]["display_value"] == "NA" - - def test_caption(self): - styler = Styler(self.df, caption="foo") - result = styler.to_html() - assert all(["caption" in result, "foo" in result]) - - styler = self.df.style - result = styler.set_caption("baz") - assert styler is result - assert styler.caption == "baz" - - def test_uuid(self): - styler = Styler(self.df, uuid="abc123") - result = styler.to_html() - assert "abc123" in result - - styler = self.df.style - result = styler.set_uuid("aaa") - assert result is styler - assert result.uuid == "aaa" - - def test_unique_id(self): - # See https://github.com/pandas-dev/pandas/issues/16780 - df = DataFrame({"a": [1, 3, 5, 6], "b": [2, 4, 12, 21]}) - result = df.style.to_html(uuid="test") - assert "test" in result - ids = re.findall('id="(.*?)"', result) - assert np.unique(ids).size == len(ids) - - def test_table_styles(self): - style = [{"selector": "th", "props": [("foo", "bar")]}] # default format - styler = Styler(self.df, table_styles=style) - result = " ".join(styler.to_html().split()) - assert "th { foo: bar; }" in result - - styler = self.df.style - result = styler.set_table_styles(style) - assert styler is result - assert styler.table_styles == style - - # GH 39563 - style = [{"selector": "th", "props": "foo:bar;"}] # css string format - styler = self.df.style.set_table_styles(style) - result = " ".join(styler.to_html().split()) - assert "th { foo: bar; }" in result - - def test_table_styles_multiple(self): - ctx = self.df.style.set_table_styles( - [ - {"selector": "th,td", "props": "color:red;"}, - {"selector": "tr", "props": "color:green;"}, - ] - )._translate(True, True)["table_styles"] - assert ctx == [ - {"selector": "th", "props": [("color", "red")]}, - {"selector": "td", "props": [("color", "red")]}, - {"selector": "tr", "props": [("color", "green")]}, - ] - - def test_table_styles_dict_multiple_selectors(self): - # GH 44011 - result = self.df.style.set_table_styles( - [{"selector": "th,td", "props": [("border-left", "2px solid black")]}] - )._translate(True, True)["table_styles"] - - expected = [ - {"selector": "th", "props": [("border-left", "2px solid black")]}, - {"selector": "td", "props": [("border-left", "2px solid black")]}, - ] - - assert result == expected - - def test_maybe_convert_css_to_tuples(self): - expected = [("a", "b"), ("c", "d e")] - assert maybe_convert_css_to_tuples("a:b;c:d e;") == expected - assert maybe_convert_css_to_tuples("a: b ;c: d e ") == expected - expected = [] - assert maybe_convert_css_to_tuples("") == expected - - def test_maybe_convert_css_to_tuples_err(self): - msg = "Styles supplied as string must follow CSS rule formats" - with pytest.raises(ValueError, match=msg): - maybe_convert_css_to_tuples("err") - - def test_table_attributes(self): - attributes = 'class="foo" data-bar' - styler = Styler(self.df, table_attributes=attributes) - result = styler.to_html() - assert 'class="foo" data-bar' in result - - result = self.df.style.set_table_attributes(attributes).to_html() - assert 'class="foo" data-bar' in result - - def test_apply_none(self): - def f(x): - return DataFrame( - np.where(x == x.max(), "color: red", ""), - index=x.index, - columns=x.columns, - ) - - result = DataFrame([[1, 2], [3, 4]]).style.apply(f, axis=None)._compute().ctx - assert result[(1, 1)] == [("color", "red")] - - def test_trim(self): - result = self.df.style.to_html() # trim=True - assert result.count("#") == 0 - - result = self.df.style.highlight_max().to_html() - assert result.count("#") == len(self.df.columns) - - def test_export(self): - f = lambda x: "color: red" if x > 0 else "color: blue" - g = lambda x, z: f"color: {z}" if x > 0 else f"color: {z}" - style1 = self.styler - style1.applymap(f).applymap(g, z="b").highlight_max()._compute() # = render - result = style1.export() - style2 = self.df.style - style2.use(result) - assert style1._todo == style2._todo - style2.to_html() - - def test_bad_apply_shape(self): - df = DataFrame([[1, 2], [3, 4]], index=["A", "B"], columns=["X", "Y"]) - - msg = "resulted in the apply method collapsing to a Series." - with pytest.raises(ValueError, match=msg): - df.style._apply(lambda x: "x") - - msg = "created invalid {} labels" - with pytest.raises(ValueError, match=msg.format("index")): - df.style._apply(lambda x: [""]) - - with pytest.raises(ValueError, match=msg.format("index")): - df.style._apply(lambda x: ["", "", "", ""]) - - with pytest.raises(ValueError, match=msg.format("index")): - df.style._apply(lambda x: Series(["a:v;", ""], index=["A", "C"]), axis=0) - - with pytest.raises(ValueError, match=msg.format("columns")): - df.style._apply(lambda x: ["", "", ""], axis=1) - - with pytest.raises(ValueError, match=msg.format("columns")): - df.style._apply(lambda x: Series(["a:v;", ""], index=["X", "Z"]), axis=1) - - msg = "returned ndarray with wrong shape" - with pytest.raises(ValueError, match=msg): - df.style._apply(lambda x: np.array([[""], [""]]), axis=None) - - def test_apply_bad_return(self): - def f(x): - return "" - - df = DataFrame([[1, 2], [3, 4]]) - msg = ( - "must return a DataFrame or ndarray when passed to `Styler.apply` " - "with axis=None" - ) - with pytest.raises(TypeError, match=msg): - df.style._apply(f, axis=None) - - @pytest.mark.parametrize("axis", ["index", "columns"]) - def test_apply_bad_labels(self, axis): - def f(x): - return DataFrame(**{axis: ["bad", "labels"]}) - - df = DataFrame([[1, 2], [3, 4]]) - msg = f"created invalid {axis} labels." - with pytest.raises(ValueError, match=msg): - df.style._apply(f, axis=None) - - def test_get_level_lengths(self): - index = MultiIndex.from_product([["a", "b"], [0, 1, 2]]) - expected = { - (0, 0): 3, - (0, 3): 3, - (1, 0): 1, - (1, 1): 1, - (1, 2): 1, - (1, 3): 1, - (1, 4): 1, - (1, 5): 1, - } - result = _get_level_lengths(index, sparsify=True, max_index=100) - tm.assert_dict_equal(result, expected) - - expected = { - (0, 0): 1, - (0, 1): 1, - (0, 2): 1, - (0, 3): 1, - (0, 4): 1, - (0, 5): 1, - (1, 0): 1, - (1, 1): 1, - (1, 2): 1, - (1, 3): 1, - (1, 4): 1, - (1, 5): 1, - } - result = _get_level_lengths(index, sparsify=False, max_index=100) - tm.assert_dict_equal(result, expected) - - def test_get_level_lengths_un_sorted(self): - index = MultiIndex.from_arrays([[1, 1, 2, 1], ["a", "b", "b", "d"]]) - expected = { - (0, 0): 2, - (0, 2): 1, - (0, 3): 1, - (1, 0): 1, - (1, 1): 1, - (1, 2): 1, - (1, 3): 1, - } - result = _get_level_lengths(index, sparsify=True, max_index=100) - tm.assert_dict_equal(result, expected) - - expected = { - (0, 0): 1, - (0, 1): 1, - (0, 2): 1, - (0, 3): 1, - (1, 0): 1, - (1, 1): 1, - (1, 2): 1, - (1, 3): 1, - } - result = _get_level_lengths(index, sparsify=False, max_index=100) - tm.assert_dict_equal(result, expected) - - def test_mi_sparse_index_names(self): - # Test the class names and displayed value are correct on rendering MI names - df = DataFrame( - {"A": [1, 2]}, - index=MultiIndex.from_arrays( - [["a", "a"], [0, 1]], names=["idx_level_0", "idx_level_1"] - ), - ) - result = df.style._translate(True, True) - head = result["head"][1] - expected = [ - { - "class": "index_name level0", - "display_value": "idx_level_0", - "is_visible": True, - }, - { - "class": "index_name level1", - "display_value": "idx_level_1", - "is_visible": True, - }, - { - "class": "blank col0", - "display_value": self.blank_value, - "is_visible": True, - }, - ] - for i, expected_dict in enumerate(expected): - assert expected_dict.items() <= head[i].items() - - def test_mi_sparse_column_names(self): - df = DataFrame( - np.arange(16).reshape(4, 4), - index=MultiIndex.from_arrays( - [["a", "a", "b", "a"], [0, 1, 1, 2]], - names=["idx_level_0", "idx_level_1"], - ), - columns=MultiIndex.from_arrays( - [["C1", "C1", "C2", "C2"], [1, 0, 1, 0]], names=["colnam_0", "colnam_1"] - ), - ) - result = Styler(df, cell_ids=False)._translate(True, True) - - for level in [0, 1]: - head = result["head"][level] - expected = [ - { - "class": "blank", - "display_value": self.blank_value, - "is_visible": True, - }, - { - "class": f"index_name level{level}", - "display_value": f"colnam_{level}", - "is_visible": True, - }, - ] - for i, expected_dict in enumerate(expected): - assert expected_dict.items() <= head[i].items() - - def test_hide_column_headers(self): - ctx = self.styler.hide(axis="columns")._translate(True, True) - assert len(ctx["head"]) == 0 # no header entries with an unnamed index - - self.df.index.name = "some_name" - ctx = self.df.style.hide(axis="columns")._translate(True, True) - assert len(ctx["head"]) == 1 - # index names still visible, changed in #42101, reverted in 43404 - - def test_hide_single_index(self): - # GH 14194 - # single unnamed index - ctx = self.df.style._translate(True, True) - assert ctx["body"][0][0]["is_visible"] - assert ctx["head"][0][0]["is_visible"] - ctx2 = self.df.style.hide(axis="index")._translate(True, True) - assert not ctx2["body"][0][0]["is_visible"] - assert not ctx2["head"][0][0]["is_visible"] - - # single named index - ctx3 = self.df.set_index("A").style._translate(True, True) - assert ctx3["body"][0][0]["is_visible"] - assert len(ctx3["head"]) == 2 # 2 header levels - assert ctx3["head"][0][0]["is_visible"] - - ctx4 = self.df.set_index("A").style.hide(axis="index")._translate(True, True) - assert not ctx4["body"][0][0]["is_visible"] - assert len(ctx4["head"]) == 1 # only 1 header levels - assert not ctx4["head"][0][0]["is_visible"] - - def test_hide_multiindex(self): - # GH 14194 - df = DataFrame( - {"A": [1, 2], "B": [1, 2]}, - index=MultiIndex.from_arrays( - [["a", "a"], [0, 1]], names=["idx_level_0", "idx_level_1"] - ), - ) - ctx1 = df.style._translate(True, True) - # tests for 'a' and '0' - assert ctx1["body"][0][0]["is_visible"] - assert ctx1["body"][0][1]["is_visible"] - # check for blank header rows - assert len(ctx1["head"][0]) == 4 # two visible indexes and two data columns - - ctx2 = df.style.hide(axis="index")._translate(True, True) - # tests for 'a' and '0' - assert not ctx2["body"][0][0]["is_visible"] - assert not ctx2["body"][0][1]["is_visible"] - # check for blank header rows - assert len(ctx2["head"][0]) == 3 # one hidden (col name) and two data columns - assert not ctx2["head"][0][0]["is_visible"] - - def test_hide_columns_single_level(self): - # GH 14194 - # test hiding single column - ctx = self.df.style._translate(True, True) - assert ctx["head"][0][1]["is_visible"] - assert ctx["head"][0][1]["display_value"] == "A" - assert ctx["head"][0][2]["is_visible"] - assert ctx["head"][0][2]["display_value"] == "B" - assert ctx["body"][0][1]["is_visible"] # col A, row 1 - assert ctx["body"][1][2]["is_visible"] # col B, row 1 - - ctx = self.df.style.hide("A", axis="columns")._translate(True, True) - assert not ctx["head"][0][1]["is_visible"] - assert not ctx["body"][0][1]["is_visible"] # col A, row 1 - assert ctx["body"][1][2]["is_visible"] # col B, row 1 - - # test hiding mulitiple columns - ctx = self.df.style.hide(["A", "B"], axis="columns")._translate(True, True) - assert not ctx["head"][0][1]["is_visible"] - assert not ctx["head"][0][2]["is_visible"] - assert not ctx["body"][0][1]["is_visible"] # col A, row 1 - assert not ctx["body"][1][2]["is_visible"] # col B, row 1 - - def test_hide_columns_index_mult_levels(self): - # GH 14194 - # setup dataframe with multiple column levels and indices - i1 = MultiIndex.from_arrays( - [["a", "a"], [0, 1]], names=["idx_level_0", "idx_level_1"] - ) - i2 = MultiIndex.from_arrays( - [["b", "b"], [0, 1]], names=["col_level_0", "col_level_1"] - ) - df = DataFrame([[1, 2], [3, 4]], index=i1, columns=i2) - ctx = df.style._translate(True, True) - # column headers - assert ctx["head"][0][2]["is_visible"] - assert ctx["head"][1][2]["is_visible"] - assert ctx["head"][1][3]["display_value"] == "1" - # indices - assert ctx["body"][0][0]["is_visible"] - # data - assert ctx["body"][1][2]["is_visible"] - assert ctx["body"][1][2]["display_value"] == "3" - assert ctx["body"][1][3]["is_visible"] - assert ctx["body"][1][3]["display_value"] == "4" - - # hide top column level, which hides both columns - ctx = df.style.hide("b", axis="columns")._translate(True, True) - assert not ctx["head"][0][2]["is_visible"] # b - assert not ctx["head"][1][2]["is_visible"] # 0 - assert not ctx["body"][1][2]["is_visible"] # 3 - assert ctx["body"][0][0]["is_visible"] # index - - # hide first column only - ctx = df.style.hide([("b", 0)], axis="columns")._translate(True, True) - assert not ctx["head"][0][2]["is_visible"] # b - assert ctx["head"][0][3]["is_visible"] # b - assert not ctx["head"][1][2]["is_visible"] # 0 - assert not ctx["body"][1][2]["is_visible"] # 3 - assert ctx["body"][1][3]["is_visible"] - assert ctx["body"][1][3]["display_value"] == "4" - - # hide second column and index - ctx = df.style.hide([("b", 1)], axis=1).hide(axis=0)._translate(True, True) - assert not ctx["body"][0][0]["is_visible"] # index - assert len(ctx["head"][0]) == 3 - assert ctx["head"][0][1]["is_visible"] # b - assert ctx["head"][1][1]["is_visible"] # 0 - assert not ctx["head"][1][2]["is_visible"] # 1 - assert not ctx["body"][1][3]["is_visible"] # 4 - assert ctx["body"][1][2]["is_visible"] - assert ctx["body"][1][2]["display_value"] == "3" - - # hide top row level, which hides both rows so body empty - ctx = df.style.hide("a", axis="index")._translate(True, True) - assert ctx["body"] == [] - - # hide first row only - ctx = df.style.hide(("a", 0), axis="index")._translate(True, True) - for i in [0, 1, 2, 3]: - assert "row1" in ctx["body"][0][i]["class"] # row0 not included in body - assert ctx["body"][0][i]["is_visible"] - - def test_pipe(self): - def set_caption_from_template(styler, a, b): - return styler.set_caption(f"Dataframe with a = {a} and b = {b}") - - styler = self.df.style.pipe(set_caption_from_template, "A", b="B") - assert "Dataframe with a = A and b = B" in styler.to_html() - - # Test with an argument that is a (callable, keyword_name) pair. - def f(a, b, styler): - return (a, b, styler) - - styler = self.df.style - result = styler.pipe((f, "styler"), a=1, b=2) - assert result == (1, 2, styler) - - def test_no_cell_ids(self): - # GH 35588 - # GH 35663 - df = DataFrame(data=[[0]]) - styler = Styler(df, uuid="_", cell_ids=False) - styler.to_html() - s = styler.to_html() # render twice to ensure ctx is not updated - assert s.find('') != -1 - - @pytest.mark.parametrize( - "classes", - [ - DataFrame( - data=[["", "test-class"], [np.nan, None]], - columns=["A", "B"], - index=["a", "b"], - ), - DataFrame(data=[["test-class"]], columns=["B"], index=["a"]), - DataFrame(data=[["test-class", "unused"]], columns=["B", "C"], index=["a"]), - ], - ) - def test_set_data_classes(self, classes): - # GH 36159 - df = DataFrame(data=[[0, 1], [2, 3]], columns=["A", "B"], index=["a", "b"]) - s = Styler(df, uuid_len=0, cell_ids=False).set_td_classes(classes).to_html() - assert '0' in s - assert '1' in s - assert '2' in s - assert '3' in s - # GH 39317 - s = Styler(df, uuid_len=0, cell_ids=True).set_td_classes(classes).to_html() - assert '0' in s - assert '1' in s - assert '2' in s - assert '3' in s - - def test_set_data_classes_reindex(self): - # GH 39317 - df = DataFrame( - data=[[0, 1, 2], [3, 4, 5], [6, 7, 8]], columns=[0, 1, 2], index=[0, 1, 2] - ) - classes = DataFrame( - data=[["mi", "ma"], ["mu", "mo"]], - columns=[0, 2], - index=[0, 2], - ) - s = Styler(df, uuid_len=0).set_td_classes(classes).to_html() - assert '0' in s - assert '2' in s - assert '4' in s - assert '6' in s - assert '8' in s - - def test_chaining_table_styles(self): - # GH 35607 - df = DataFrame(data=[[0, 1], [1, 2]], columns=["A", "B"]) - styler = df.style.set_table_styles( - [{"selector": "", "props": [("background-color", "yellow")]}] - ).set_table_styles( - [{"selector": ".col0", "props": [("background-color", "blue")]}], - overwrite=False, - ) - assert len(styler.table_styles) == 2 - - def test_column_and_row_styling(self): - # GH 35607 - df = DataFrame(data=[[0, 1], [1, 2]], columns=["A", "B"]) - s = Styler(df, uuid_len=0) - s = s.set_table_styles({"A": [{"selector": "", "props": [("color", "blue")]}]}) - assert "#T_ .col0 {\n color: blue;\n}" in s.to_html() - s = s.set_table_styles( - {0: [{"selector": "", "props": [("color", "blue")]}]}, axis=1 - ) - assert "#T_ .row0 {\n color: blue;\n}" in s.to_html() - - @pytest.mark.parametrize("len_", [1, 5, 32, 33, 100]) - def test_uuid_len(self, len_): - # GH 36345 - df = DataFrame(data=[["A"]]) - s = Styler(df, uuid_len=len_, cell_ids=False).to_html() - strt = s.find('id="T_') - end = s[strt + 6 :].find('"') - if len_ > 32: - assert end == 32 - else: - assert end == len_ - - @pytest.mark.parametrize("len_", [-2, "bad", None]) - def test_uuid_len_raises(self, len_): - # GH 36345 - df = DataFrame(data=[["A"]]) - msg = "``uuid_len`` must be an integer in range \\[0, 32\\]." - with pytest.raises(TypeError, match=msg): - Styler(df, uuid_len=len_, cell_ids=False).to_html() - - @pytest.mark.parametrize( - "slc", - [ - IndexSlice[:, :], - IndexSlice[:, 1], - IndexSlice[1, :], - IndexSlice[[1], [1]], - IndexSlice[1, [1]], - IndexSlice[[1], 1], - IndexSlice[1], - IndexSlice[1, 1], - slice(None, None, None), - [0, 1], - np.array([0, 1]), - Series([0, 1]), - ], - ) - def test_non_reducing_slice(self, slc): - df = DataFrame([[0, 1], [2, 3]]) - - tslice_ = non_reducing_slice(slc) - assert isinstance(df.loc[tslice_], DataFrame) - - @pytest.mark.parametrize("box", [list, Series, np.array]) - def test_list_slice(self, box): - # like dataframe getitem - subset = box(["A"]) - - df = DataFrame({"A": [1, 2], "B": [3, 4]}, index=["A", "B"]) - expected = IndexSlice[:, ["A"]] - - result = non_reducing_slice(subset) - tm.assert_frame_equal(df.loc[result], df.loc[expected]) - - def test_non_reducing_slice_on_multiindex(self): - # GH 19861 - dic = { - ("a", "d"): [1, 4], - ("a", "c"): [2, 3], - ("b", "c"): [3, 2], - ("b", "d"): [4, 1], - } - df = DataFrame(dic, index=[0, 1]) - idx = IndexSlice - slice_ = idx[:, idx["b", "d"]] - tslice_ = non_reducing_slice(slice_) - - result = df.loc[tslice_] - expected = DataFrame({("b", "d"): [4, 1]}) - tm.assert_frame_equal(result, expected) - - @pytest.mark.parametrize( - "slice_", - [ - IndexSlice[:, :], - # check cols - IndexSlice[:, IndexSlice[["a"]]], # inferred deeper need list - IndexSlice[:, IndexSlice[["a"], ["c"]]], # inferred deeper need list - IndexSlice[:, IndexSlice["a", "c", :]], - IndexSlice[:, IndexSlice["a", :, "e"]], - IndexSlice[:, IndexSlice[:, "c", "e"]], - IndexSlice[:, IndexSlice["a", ["c", "d"], :]], # check list - IndexSlice[:, IndexSlice["a", ["c", "d", "-"], :]], # allow missing - IndexSlice[:, IndexSlice["a", ["c", "d", "-"], "e"]], # no slice - # check rows - IndexSlice[IndexSlice[["U"]], :], # inferred deeper need list - IndexSlice[IndexSlice[["U"], ["W"]], :], # inferred deeper need list - IndexSlice[IndexSlice["U", "W", :], :], - IndexSlice[IndexSlice["U", :, "Y"], :], - IndexSlice[IndexSlice[:, "W", "Y"], :], - IndexSlice[IndexSlice[:, "W", ["Y", "Z"]], :], # check list - IndexSlice[IndexSlice[:, "W", ["Y", "Z", "-"]], :], # allow missing - IndexSlice[IndexSlice["U", "W", ["Y", "Z", "-"]], :], # no slice - # check simultaneous - IndexSlice[IndexSlice[:, "W", "Y"], IndexSlice["a", "c", :]], - ], - ) - def test_non_reducing_multi_slice_on_multiindex(self, slice_): - # GH 33562 - cols = MultiIndex.from_product([["a", "b"], ["c", "d"], ["e", "f"]]) - idxs = MultiIndex.from_product([["U", "V"], ["W", "X"], ["Y", "Z"]]) - df = DataFrame(np.arange(64).reshape(8, 8), columns=cols, index=idxs) - - msg = "indexing on a MultiIndex with a nested sequence of labels" - warn = None - for lvl in [0, 1]: - key = slice_[lvl] - if isinstance(key, tuple): - for subkey in key: - if isinstance(subkey, list) and "-" in subkey: - # not present in the index level, ignored, will raise in future - warn = FutureWarning - - with tm.assert_produces_warning(warn, match=msg): - expected = df.loc[slice_] - - with tm.assert_produces_warning(warn, match=msg): - result = df.loc[non_reducing_slice(slice_)] - tm.assert_frame_equal(result, expected) - - -def test_hidden_index_names(mi_df): - mi_df.index.names = ["Lev0", "Lev1"] - mi_styler = mi_df.style - ctx = mi_styler._translate(True, True) - assert len(ctx["head"]) == 3 # 2 column index levels + 1 index names row - - mi_styler.hide(axis="index", names=True) - ctx = mi_styler._translate(True, True) - assert len(ctx["head"]) == 2 # index names row is unparsed - for i in range(4): - assert ctx["body"][0][i]["is_visible"] # 2 index levels + 2 data values visible - - mi_styler.hide(axis="index", level=1) - ctx = mi_styler._translate(True, True) - assert len(ctx["head"]) == 2 # index names row is still hidden - assert ctx["body"][0][0]["is_visible"] is True - assert ctx["body"][0][1]["is_visible"] is False - - -def test_hidden_column_names(mi_df): - mi_df.columns.names = ["Lev0", "Lev1"] - mi_styler = mi_df.style - ctx = mi_styler._translate(True, True) - assert ctx["head"][0][1]["display_value"] == "Lev0" - assert ctx["head"][1][1]["display_value"] == "Lev1" - - mi_styler.hide(names=True, axis="columns") - ctx = mi_styler._translate(True, True) - assert ctx["head"][0][1]["display_value"] == " " - assert ctx["head"][1][1]["display_value"] == " " - - mi_styler.hide(level=0, axis="columns") - ctx = mi_styler._translate(True, True) - assert len(ctx["head"]) == 1 # no index names and only one visible column headers - assert ctx["head"][0][1]["display_value"] == " " - - -@pytest.mark.parametrize("caption", [1, ("a", "b", "c"), (1, "s")]) -def test_caption_raises(mi_styler, caption): - msg = "`caption` must be either a string or 2-tuple of strings." - with pytest.raises(ValueError, match=msg): - mi_styler.set_caption(caption) - - -def test_hiding_headers_over_index_no_sparsify(): - # GH 43464 - midx = MultiIndex.from_product([[1, 2], ["a", "a", "b"]]) - df = DataFrame(9, index=midx, columns=[0]) - ctx = df.style._translate(False, False) - assert len(ctx["body"]) == 6 - ctx = df.style.hide((1, "a"), axis=0)._translate(False, False) - assert len(ctx["body"]) == 4 - assert "row2" in ctx["body"][0][0]["class"] - - -def test_hiding_headers_over_columns_no_sparsify(): - # GH 43464 - midx = MultiIndex.from_product([[1, 2], ["a", "a", "b"]]) - df = DataFrame(9, columns=midx, index=[0]) - ctx = df.style._translate(False, False) - for ix in [(0, 1), (0, 2), (1, 1), (1, 2)]: - assert ctx["head"][ix[0]][ix[1]]["is_visible"] is True - ctx = df.style.hide((1, "a"), axis="columns")._translate(False, False) - for ix in [(0, 1), (0, 2), (1, 1), (1, 2)]: - assert ctx["head"][ix[0]][ix[1]]["is_visible"] is False - - -def test_get_level_lengths_mi_hidden(): - # GH 43464 - index = MultiIndex.from_arrays([[1, 1, 1, 2, 2, 2], ["a", "a", "b", "a", "a", "b"]]) - expected = { - (0, 2): 1, - (0, 3): 1, - (0, 4): 1, - (0, 5): 1, - (1, 2): 1, - (1, 3): 1, - (1, 4): 1, - (1, 5): 1, - } - result = _get_level_lengths( - index, - sparsify=False, - max_index=100, - hidden_elements=[0, 1, 0, 1], # hidden element can repeat if duplicated index - ) - tm.assert_dict_equal(result, expected) - - -def test_row_trimming_hide_index(): - # gh 43703 - df = DataFrame([[1], [2], [3], [4], [5]]) - with option_context("styler.render.max_rows", 2): - ctx = df.style.hide([0, 1], axis="index")._translate(True, True) - assert len(ctx["body"]) == 3 - for r, val in enumerate(["3", "4", "..."]): - assert ctx["body"][r][1]["display_value"] == val - - -def test_row_trimming_hide_index_mi(): - # gh 44247 - df = DataFrame([[1], [2], [3], [4], [5]]) - df.index = MultiIndex.from_product([[0], [0, 1, 2, 3, 4]]) - with option_context("styler.render.max_rows", 2): - ctx = df.style.hide([(0, 0), (0, 1)], axis="index")._translate(True, True) - assert len(ctx["body"]) == 3 - - # level 0 index headers (sparsified) - assert {"value": 0, "attributes": 'rowspan="2"', "is_visible": True}.items() <= ctx[ - "body" - ][0][0].items() - assert {"value": 0, "attributes": "", "is_visible": False}.items() <= ctx["body"][ - 1 - ][0].items() - assert {"value": "...", "is_visible": True}.items() <= ctx["body"][2][0].items() - - for r, val in enumerate(["2", "3", "..."]): - assert ctx["body"][r][1]["display_value"] == val # level 1 index headers - for r, val in enumerate(["3", "4", "..."]): - assert ctx["body"][r][2]["display_value"] == val # data values - - -def test_col_trimming_hide_columns(): - # gh 44272 - df = DataFrame([[1, 2, 3, 4, 5]]) - with option_context("styler.render.max_columns", 2): - ctx = df.style.hide([0, 1], axis="columns")._translate(True, True) - - assert len(ctx["head"][0]) == 6 # blank, [0, 1 (hidden)], [2 ,3 (visible)], + trim - for c, vals in enumerate([(1, False), (2, True), (3, True), ("...", True)]): - assert ctx["head"][0][c + 2]["value"] == vals[0] - assert ctx["head"][0][c + 2]["is_visible"] == vals[1] - - assert len(ctx["body"][0]) == 6 # index + 2 hidden + 2 visible + trimming col - - -def test_no_empty_apply(mi_styler): - # 45313 - mi_styler.apply(lambda s: ["a:v;"] * 2, subset=[False, False]) - mi_styler._compute() diff --git a/pandas/tests/io/formats/style/test_to_latex.py b/pandas/tests/io/formats/style/test_to_latex.py deleted file mode 100644 index 145cd832ab270..0000000000000 --- a/pandas/tests/io/formats/style/test_to_latex.py +++ /dev/null @@ -1,992 +0,0 @@ -from textwrap import dedent - -import numpy as np -import pytest - -from pandas import ( - DataFrame, - MultiIndex, - option_context, -) - -pytest.importorskip("jinja2") -from pandas.io.formats.style import Styler -from pandas.io.formats.style_render import ( - _parse_latex_cell_styles, - _parse_latex_css_conversion, - _parse_latex_header_span, - _parse_latex_table_styles, - _parse_latex_table_wrapping, -) - - -@pytest.fixture -def df(): - return DataFrame({"A": [0, 1], "B": [-0.61, -1.22], "C": ["ab", "cd"]}) - - -@pytest.fixture -def df_ext(): - return DataFrame( - {"A": [0, 1, 2], "B": [-0.61, -1.22, -2.22], "C": ["ab", "cd", "de"]} - ) - - -@pytest.fixture -def styler(df): - return Styler(df, uuid_len=0, precision=2) - - -def test_minimal_latex_tabular(styler): - expected = dedent( - """\ - \\begin{tabular}{lrrl} - & A & B & C \\\\ - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\end{tabular} - """ - ) - assert styler.to_latex() == expected - - -def test_tabular_hrules(styler): - expected = dedent( - """\ - \\begin{tabular}{lrrl} - \\toprule - & A & B & C \\\\ - \\midrule - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\bottomrule - \\end{tabular} - """ - ) - assert styler.to_latex(hrules=True) == expected - - -def test_tabular_custom_hrules(styler): - styler.set_table_styles( - [ - {"selector": "toprule", "props": ":hline"}, - {"selector": "bottomrule", "props": ":otherline"}, - ] - ) # no midrule - expected = dedent( - """\ - \\begin{tabular}{lrrl} - \\hline - & A & B & C \\\\ - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\otherline - \\end{tabular} - """ - ) - assert styler.to_latex() == expected - - -def test_column_format(styler): - # default setting is already tested in `test_latex_minimal_tabular` - styler.set_table_styles([{"selector": "column_format", "props": ":cccc"}]) - - assert "\\begin{tabular}{rrrr}" in styler.to_latex(column_format="rrrr") - styler.set_table_styles([{"selector": "column_format", "props": ":r|r|cc"}]) - assert "\\begin{tabular}{r|r|cc}" in styler.to_latex() - - -def test_siunitx_cols(styler): - expected = dedent( - """\ - \\begin{tabular}{lSSl} - {} & {A} & {B} & {C} \\\\ - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\end{tabular} - """ - ) - assert styler.to_latex(siunitx=True) == expected - - -def test_position(styler): - assert "\\begin{table}[h!]" in styler.to_latex(position="h!") - assert "\\end{table}" in styler.to_latex(position="h!") - styler.set_table_styles([{"selector": "position", "props": ":b!"}]) - assert "\\begin{table}[b!]" in styler.to_latex() - assert "\\end{table}" in styler.to_latex() - - -@pytest.mark.parametrize("env", [None, "longtable"]) -def test_label(styler, env): - assert "\n\\label{text}" in styler.to_latex(label="text", environment=env) - styler.set_table_styles([{"selector": "label", "props": ":{more §text}"}]) - assert "\n\\label{more :text}" in styler.to_latex(environment=env) - - -def test_position_float_raises(styler): - msg = "`position_float` should be one of 'raggedright', 'raggedleft', 'centering'," - with pytest.raises(ValueError, match=msg): - styler.to_latex(position_float="bad_string") - - msg = "`position_float` cannot be used in 'longtable' `environment`" - with pytest.raises(ValueError, match=msg): - styler.to_latex(position_float="centering", environment="longtable") - - -@pytest.mark.parametrize("label", [(None, ""), ("text", "\\label{text}")]) -@pytest.mark.parametrize("position", [(None, ""), ("h!", "{table}[h!]")]) -@pytest.mark.parametrize("caption", [(None, ""), ("text", "\\caption{text}")]) -@pytest.mark.parametrize("column_format", [(None, ""), ("rcrl", "{tabular}{rcrl}")]) -@pytest.mark.parametrize("position_float", [(None, ""), ("centering", "\\centering")]) -def test_kwargs_combinations( - styler, label, position, caption, column_format, position_float -): - result = styler.to_latex( - label=label[0], - position=position[0], - caption=caption[0], - column_format=column_format[0], - position_float=position_float[0], - ) - assert label[1] in result - assert position[1] in result - assert caption[1] in result - assert column_format[1] in result - assert position_float[1] in result - - -def test_custom_table_styles(styler): - styler.set_table_styles( - [ - {"selector": "mycommand", "props": ":{myoptions}"}, - {"selector": "mycommand2", "props": ":{myoptions2}"}, - ] - ) - expected = dedent( - """\ - \\begin{table} - \\mycommand{myoptions} - \\mycommand2{myoptions2} - """ - ) - assert expected in styler.to_latex() - - -def test_cell_styling(styler): - styler.highlight_max(props="itshape:;Huge:--wrap;") - expected = dedent( - """\ - \\begin{tabular}{lrrl} - & A & B & C \\\\ - 0 & 0 & \\itshape {\\Huge -0.61} & ab \\\\ - 1 & \\itshape {\\Huge 1} & -1.22 & \\itshape {\\Huge cd} \\\\ - \\end{tabular} - """ - ) - assert expected == styler.to_latex() - - -def test_multiindex_columns(df): - cidx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df.columns = cidx - expected = dedent( - """\ - \\begin{tabular}{lrrl} - & \\multicolumn{2}{r}{A} & B \\\\ - & a & b & c \\\\ - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\end{tabular} - """ - ) - s = df.style.format(precision=2) - assert expected == s.to_latex() - - # non-sparse - expected = dedent( - """\ - \\begin{tabular}{lrrl} - & A & A & B \\\\ - & a & b & c \\\\ - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\end{tabular} - """ - ) - s = df.style.format(precision=2) - assert expected == s.to_latex(sparse_columns=False) - - -def test_multiindex_row(df_ext): - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df_ext.index = ridx - expected = dedent( - """\ - \\begin{tabular}{llrrl} - & & A & B & C \\\\ - \\multirow[c]{2}{*}{A} & a & 0 & -0.61 & ab \\\\ - & b & 1 & -1.22 & cd \\\\ - B & c & 2 & -2.22 & de \\\\ - \\end{tabular} - """ - ) - styler = df_ext.style.format(precision=2) - result = styler.to_latex() - assert expected == result - - # non-sparse - expected = dedent( - """\ - \\begin{tabular}{llrrl} - & & A & B & C \\\\ - A & a & 0 & -0.61 & ab \\\\ - A & b & 1 & -1.22 & cd \\\\ - B & c & 2 & -2.22 & de \\\\ - \\end{tabular} - """ - ) - result = styler.to_latex(sparse_index=False) - assert expected == result - - -def test_multirow_naive(df_ext): - ridx = MultiIndex.from_tuples([("X", "x"), ("X", "y"), ("Y", "z")]) - df_ext.index = ridx - expected = dedent( - """\ - \\begin{tabular}{llrrl} - & & A & B & C \\\\ - X & x & 0 & -0.61 & ab \\\\ - & y & 1 & -1.22 & cd \\\\ - Y & z & 2 & -2.22 & de \\\\ - \\end{tabular} - """ - ) - styler = df_ext.style.format(precision=2) - result = styler.to_latex(multirow_align="naive") - assert expected == result - - -def test_multiindex_row_and_col(df_ext): - cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")]) - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df_ext.index, df_ext.columns = ridx, cidx - expected = dedent( - """\ - \\begin{tabular}{llrrl} - & & \\multicolumn{2}{l}{Z} & Y \\\\ - & & a & b & c \\\\ - \\multirow[b]{2}{*}{A} & a & 0 & -0.61 & ab \\\\ - & b & 1 & -1.22 & cd \\\\ - B & c & 2 & -2.22 & de \\\\ - \\end{tabular} - """ - ) - styler = df_ext.style.format(precision=2) - result = styler.to_latex(multirow_align="b", multicol_align="l") - assert result == expected - - # non-sparse - expected = dedent( - """\ - \\begin{tabular}{llrrl} - & & Z & Z & Y \\\\ - & & a & b & c \\\\ - A & a & 0 & -0.61 & ab \\\\ - A & b & 1 & -1.22 & cd \\\\ - B & c & 2 & -2.22 & de \\\\ - \\end{tabular} - """ - ) - result = styler.to_latex(sparse_index=False, sparse_columns=False) - assert result == expected - - -@pytest.mark.parametrize( - "multicol_align, siunitx, header", - [ - ("naive-l", False, " & A & &"), - ("naive-r", False, " & & & A"), - ("naive-l", True, "{} & {A} & {} & {}"), - ("naive-r", True, "{} & {} & {} & {A}"), - ], -) -def test_multicol_naive(df, multicol_align, siunitx, header): - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("A", "c")]) - df.columns = ridx - level1 = " & a & b & c" if not siunitx else "{} & {a} & {b} & {c}" - col_format = "lrrl" if not siunitx else "lSSl" - expected = dedent( - f"""\ - \\begin{{tabular}}{{{col_format}}} - {header} \\\\ - {level1} \\\\ - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\end{{tabular}} - """ - ) - styler = df.style.format(precision=2) - result = styler.to_latex(multicol_align=multicol_align, siunitx=siunitx) - assert expected == result - - -def test_multi_options(df_ext): - cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")]) - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df_ext.index, df_ext.columns = ridx, cidx - styler = df_ext.style.format(precision=2) - - expected = dedent( - """\ - & & \\multicolumn{2}{r}{Z} & Y \\\\ - & & a & b & c \\\\ - \\multirow[c]{2}{*}{A} & a & 0 & -0.61 & ab \\\\ - """ - ) - result = styler.to_latex() - assert expected in result - - with option_context("styler.latex.multicol_align", "l"): - assert " & & \\multicolumn{2}{l}{Z} & Y \\\\" in styler.to_latex() - - with option_context("styler.latex.multirow_align", "b"): - assert "\\multirow[b]{2}{*}{A} & a & 0 & -0.61 & ab \\\\" in styler.to_latex() - - -def test_multiindex_columns_hidden(): - df = DataFrame([[1, 2, 3, 4]]) - df.columns = MultiIndex.from_tuples([("A", 1), ("A", 2), ("A", 3), ("B", 1)]) - s = df.style - assert "{tabular}{lrrrr}" in s.to_latex() - s.set_table_styles([]) # reset the position command - s.hide([("A", 2)], axis="columns") - assert "{tabular}{lrrr}" in s.to_latex() - - -@pytest.mark.parametrize( - "option, value", - [ - ("styler.sparse.index", True), - ("styler.sparse.index", False), - ("styler.sparse.columns", True), - ("styler.sparse.columns", False), - ], -) -def test_sparse_options(df_ext, option, value): - cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")]) - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df_ext.index, df_ext.columns = ridx, cidx - styler = df_ext.style - - latex1 = styler.to_latex() - with option_context(option, value): - latex2 = styler.to_latex() - assert (latex1 == latex2) is value - - -def test_hidden_index(styler): - styler.hide(axis="index") - expected = dedent( - """\ - \\begin{tabular}{rrl} - A & B & C \\\\ - 0 & -0.61 & ab \\\\ - 1 & -1.22 & cd \\\\ - \\end{tabular} - """ - ) - assert styler.to_latex() == expected - - -@pytest.mark.parametrize("environment", ["table", "figure*", None]) -def test_comprehensive(df_ext, environment): - # test as many low level features simultaneously as possible - cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")]) - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df_ext.index, df_ext.columns = ridx, cidx - stlr = df_ext.style - stlr.set_caption("mycap") - stlr.set_table_styles( - [ - {"selector": "label", "props": ":{fig§item}"}, - {"selector": "position", "props": ":h!"}, - {"selector": "position_float", "props": ":centering"}, - {"selector": "column_format", "props": ":rlrlr"}, - {"selector": "toprule", "props": ":toprule"}, - {"selector": "midrule", "props": ":midrule"}, - {"selector": "bottomrule", "props": ":bottomrule"}, - {"selector": "rowcolors", "props": ":{3}{pink}{}"}, # custom command - ] - ) - stlr.highlight_max(axis=0, props="textbf:--rwrap;cellcolor:[rgb]{1,1,0.6}--rwrap") - stlr.highlight_max(axis=None, props="Huge:--wrap;", subset=[("Z", "a"), ("Z", "b")]) - - expected = ( - """\ -\\begin{table}[h!] -\\centering -\\caption{mycap} -\\label{fig:item} -\\rowcolors{3}{pink}{} -\\begin{tabular}{rlrlr} -\\toprule - & & \\multicolumn{2}{r}{Z} & Y \\\\ - & & a & b & c \\\\ -\\midrule -\\multirow[c]{2}{*}{A} & a & 0 & \\textbf{\\cellcolor[rgb]{1,1,0.6}{-0.61}} & ab \\\\ - & b & 1 & -1.22 & cd \\\\ -B & c & \\textbf{\\cellcolor[rgb]{1,1,0.6}{{\\Huge 2}}} & -2.22 & """ - """\ -\\textbf{\\cellcolor[rgb]{1,1,0.6}{de}} \\\\ -\\bottomrule -\\end{tabular} -\\end{table} -""" - ).replace("table", environment if environment else "table") - result = stlr.format(precision=2).to_latex(environment=environment) - assert result == expected - - -def test_environment_option(styler): - with option_context("styler.latex.environment", "bar-env"): - assert "\\begin{bar-env}" in styler.to_latex() - assert "\\begin{foo-env}" in styler.to_latex(environment="foo-env") - - -def test_parse_latex_table_styles(styler): - styler.set_table_styles( - [ - {"selector": "foo", "props": [("attr", "value")]}, - {"selector": "bar", "props": [("attr", "overwritten")]}, - {"selector": "bar", "props": [("attr", "baz"), ("attr2", "ignored")]}, - {"selector": "label", "props": [("", "{fig§item}")]}, - ] - ) - assert _parse_latex_table_styles(styler.table_styles, "bar") == "baz" - - # test '§' replaced by ':' [for CSS compatibility] - assert _parse_latex_table_styles(styler.table_styles, "label") == "{fig:item}" - - -def test_parse_latex_cell_styles_basic(): # test nesting - cell_style = [("itshape", "--rwrap"), ("cellcolor", "[rgb]{0,1,1}--rwrap")] - expected = "\\itshape{\\cellcolor[rgb]{0,1,1}{text}}" - assert _parse_latex_cell_styles(cell_style, "text") == expected - - -@pytest.mark.parametrize( - "wrap_arg, expected", - [ # test wrapping - ("", "\\ "), - ("--wrap", "{\\ }"), - ("--nowrap", "\\ "), - ("--lwrap", "{\\} "), - ("--dwrap", "{\\}{}"), - ("--rwrap", "\\{}"), - ], -) -def test_parse_latex_cell_styles_braces(wrap_arg, expected): - cell_style = [("", f"{wrap_arg}")] - assert _parse_latex_cell_styles(cell_style, "") == expected - - -def test_parse_latex_header_span(): - cell = {"attributes": 'colspan="3"', "display_value": "text", "cellstyle": []} - expected = "\\multicolumn{3}{Y}{text}" - assert _parse_latex_header_span(cell, "X", "Y") == expected - - cell = {"attributes": 'rowspan="5"', "display_value": "text", "cellstyle": []} - expected = "\\multirow[X]{5}{*}{text}" - assert _parse_latex_header_span(cell, "X", "Y") == expected - - cell = {"display_value": "text", "cellstyle": []} - assert _parse_latex_header_span(cell, "X", "Y") == "text" - - cell = {"display_value": "text", "cellstyle": [("bfseries", "--rwrap")]} - assert _parse_latex_header_span(cell, "X", "Y") == "\\bfseries{text}" - - -def test_parse_latex_table_wrapping(styler): - styler.set_table_styles( - [ - {"selector": "toprule", "props": ":value"}, - {"selector": "bottomrule", "props": ":value"}, - {"selector": "midrule", "props": ":value"}, - {"selector": "column_format", "props": ":value"}, - ] - ) - assert _parse_latex_table_wrapping(styler.table_styles, styler.caption) is False - assert _parse_latex_table_wrapping(styler.table_styles, "some caption") is True - styler.set_table_styles( - [ - {"selector": "not-ignored", "props": ":value"}, - ], - overwrite=False, - ) - assert _parse_latex_table_wrapping(styler.table_styles, None) is True - - -def test_short_caption(styler): - result = styler.to_latex(caption=("full cap", "short cap")) - assert "\\caption[short cap]{full cap}" in result - - -@pytest.mark.parametrize( - "css, expected", - [ - ([("color", "red")], [("color", "{red}")]), # test color and input format types - ( - [("color", "rgb(128, 128, 128 )")], - [("color", "[rgb]{0.502, 0.502, 0.502}")], - ), - ( - [("color", "rgb(128, 50%, 25% )")], - [("color", "[rgb]{0.502, 0.500, 0.250}")], - ), - ( - [("color", "rgba(128,128,128,1)")], - [("color", "[rgb]{0.502, 0.502, 0.502}")], - ), - ([("color", "#FF00FF")], [("color", "[HTML]{FF00FF}")]), - ([("color", "#F0F")], [("color", "[HTML]{FF00FF}")]), - ([("font-weight", "bold")], [("bfseries", "")]), # test font-weight and types - ([("font-weight", "bolder")], [("bfseries", "")]), - ([("font-weight", "normal")], []), - ([("background-color", "red")], [("cellcolor", "{red}--lwrap")]), - ( - [("background-color", "#FF00FF")], # test background-color command and wrap - [("cellcolor", "[HTML]{FF00FF}--lwrap")], - ), - ([("font-style", "italic")], [("itshape", "")]), # test font-style and types - ([("font-style", "oblique")], [("slshape", "")]), - ([("font-style", "normal")], []), - ([("color", "red /*--dwrap*/")], [("color", "{red}--dwrap")]), # css comments - ([("background-color", "red /* --dwrap */")], [("cellcolor", "{red}--dwrap")]), - ], -) -def test_parse_latex_css_conversion(css, expected): - result = _parse_latex_css_conversion(css) - assert result == expected - - -@pytest.mark.parametrize( - "env, inner_env", - [ - (None, "tabular"), - ("table", "tabular"), - ("longtable", "longtable"), - ], -) -@pytest.mark.parametrize( - "convert, exp", [(True, "bfseries"), (False, "font-weightbold")] -) -def test_parse_latex_css_convert_minimal(styler, env, inner_env, convert, exp): - # parameters ensure longtable template is also tested - styler.highlight_max(props="font-weight:bold;") - result = styler.to_latex(convert_css=convert, environment=env) - expected = dedent( - f"""\ - 0 & 0 & \\{exp} -0.61 & ab \\\\ - 1 & \\{exp} 1 & -1.22 & \\{exp} cd \\\\ - \\end{{{inner_env}}} - """ - ) - assert expected in result - - -def test_parse_latex_css_conversion_option(): - css = [("command", "option--latex--wrap")] - expected = [("command", "option--wrap")] - result = _parse_latex_css_conversion(css) - assert result == expected - - -def test_styler_object_after_render(styler): - # GH 42320 - pre_render = styler._copy(deepcopy=True) - styler.to_latex( - column_format="rllr", - position="h", - position_float="centering", - hrules=True, - label="my lab", - caption="my cap", - ) - - assert pre_render.table_styles == styler.table_styles - assert pre_render.caption == styler.caption - - -def test_longtable_comprehensive(styler): - result = styler.to_latex( - environment="longtable", hrules=True, label="fig:A", caption=("full", "short") - ) - expected = dedent( - """\ - \\begin{longtable}{lrrl} - \\caption[short]{full} \\label{fig:A} \\\\ - \\toprule - & A & B & C \\\\ - \\midrule - \\endfirsthead - \\caption[]{full} \\\\ - \\toprule - & A & B & C \\\\ - \\midrule - \\endhead - \\midrule - \\multicolumn{4}{r}{Continued on next page} \\\\ - \\midrule - \\endfoot - \\bottomrule - \\endlastfoot - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\end{longtable} - """ - ) - assert result == expected - - -def test_longtable_minimal(styler): - result = styler.to_latex(environment="longtable") - expected = dedent( - """\ - \\begin{longtable}{lrrl} - & A & B & C \\\\ - \\endfirsthead - & A & B & C \\\\ - \\endhead - \\multicolumn{4}{r}{Continued on next page} \\\\ - \\endfoot - \\endlastfoot - 0 & 0 & -0.61 & ab \\\\ - 1 & 1 & -1.22 & cd \\\\ - \\end{longtable} - """ - ) - assert result == expected - - -@pytest.mark.parametrize( - "sparse, exp, siunitx", - [ - (True, "{} & \\multicolumn{2}{r}{A} & {B}", True), - (False, "{} & {A} & {A} & {B}", True), - (True, " & \\multicolumn{2}{r}{A} & B", False), - (False, " & A & A & B", False), - ], -) -def test_longtable_multiindex_columns(df, sparse, exp, siunitx): - cidx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df.columns = cidx - with_si = "{} & {a} & {b} & {c} \\\\" - without_si = " & a & b & c \\\\" - expected = dedent( - f"""\ - \\begin{{longtable}}{{l{"SS" if siunitx else "rr"}l}} - {exp} \\\\ - {with_si if siunitx else without_si} - \\endfirsthead - {exp} \\\\ - {with_si if siunitx else without_si} - \\endhead - """ - ) - result = df.style.to_latex( - environment="longtable", sparse_columns=sparse, siunitx=siunitx - ) - assert expected in result - - -@pytest.mark.parametrize( - "caption, cap_exp", - [ - ("full", ("{full}", "")), - (("full", "short"), ("{full}", "[short]")), - ], -) -@pytest.mark.parametrize("label, lab_exp", [(None, ""), ("tab:A", " \\label{tab:A}")]) -def test_longtable_caption_label(styler, caption, cap_exp, label, lab_exp): - cap_exp1 = f"\\caption{cap_exp[1]}{cap_exp[0]}" - cap_exp2 = f"\\caption[]{cap_exp[0]}" - - expected = dedent( - f"""\ - {cap_exp1}{lab_exp} \\\\ - & A & B & C \\\\ - \\endfirsthead - {cap_exp2} \\\\ - """ - ) - assert expected in styler.to_latex( - environment="longtable", caption=caption, label=label - ) - - -@pytest.mark.parametrize("index", [True, False]) -@pytest.mark.parametrize( - "columns, siunitx", - [ - (True, True), - (True, False), - (False, False), - ], -) -def test_apply_map_header_render_mi(df_ext, index, columns, siunitx): - cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")]) - ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")]) - df_ext.index, df_ext.columns = ridx, cidx - styler = df_ext.style - - func = lambda v: "bfseries: --rwrap" if "A" in v or "Z" in v or "c" in v else None - - if index: - styler.applymap_index(func, axis="index") - if columns: - styler.applymap_index(func, axis="columns") - - result = styler.to_latex(siunitx=siunitx) - - expected_index = dedent( - """\ - \\multirow[c]{2}{*}{\\bfseries{A}} & a & 0 & -0.610000 & ab \\\\ - \\bfseries{} & b & 1 & -1.220000 & cd \\\\ - B & \\bfseries{c} & 2 & -2.220000 & de \\\\ - """ - ) - assert (expected_index in result) is index - - exp_cols_si = dedent( - """\ - {} & {} & \\multicolumn{2}{r}{\\bfseries{Z}} & {Y} \\\\ - {} & {} & {a} & {b} & {\\bfseries{c}} \\\\ - """ - ) - exp_cols_no_si = """\ - & & \\multicolumn{2}{r}{\\bfseries{Z}} & Y \\\\ - & & a & b & \\bfseries{c} \\\\ -""" - assert ((exp_cols_si if siunitx else exp_cols_no_si) in result) is columns - - -def test_repr_option(styler): - assert "