Skip to content
8 changes: 7 additions & 1 deletion pandas/core/config_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,12 @@ def register_converter_cb(key):
will not be used in Jupyter Notebook.
"""


def _is_formatter(x):
if not (x is None or callable(x) or isinstance(x, (dict, str))):
raise ValueError("Value must have type 'callable, dict, str' or None.")


with cf.config_prefix("styler"):
cf.register_option("sparse.index", True, styler_sparse_index_doc, validator=is_bool)

Expand Down Expand Up @@ -851,7 +857,7 @@ def register_converter_cb(key):
"format.formatter",
None,
styler_formatter,
validator=is_instance_factory([type(None), dict, callable, str]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

umm why doesn't this work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x = '{:.2f}'

    def inner(x) -> None:
>       if not isinstance(x, _type):
E       TypeError: isinstance() arg 2 must be a type or tuple of types
x = <function <lambda> at 0x1251dd160>

    def inner(x) -> None:
>       if not isinstance(x, _type):
E       TypeError: isinstance() arg 2 must be a type or tuple of types

Also the signature of of the is_instance_factory struggles with callable:

>>> isinstance(lambda x: x, callable)
False
>>> isinstance(lambda x: x, type(callable))
False
>>> callable(lambda x: x)
True

Copy link
Contributor Author

@attack68 attack68 Sep 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok fixed: callable != Callable !!!

validator=_is_formatter,
)

cf.register_option("html.mathjax", True, styler_mathjax, validator=is_bool)
17 changes: 17 additions & 0 deletions pandas/tests/io/formats/style/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,20 @@ def test_precision_zero(df):
ctx = styler._translate(True, True)
assert ctx["body"][0][2]["display_value"] == "-1"
assert ctx["body"][1][2]["display_value"] == "-1"


def test_format_options_validator():
df = DataFrame([[9]])
with option_context("styler.format.formatter", lambda x: f"{x:.3f}"):
assert " 9.000 " in df.style.to_latex()
with option_context("styler.format.formatter", "{:.2f}"):
assert " 9.00 " in df.style.to_latex()
with option_context("styler.format.formatter", {0: "{:.1f}"}):
assert " 9.0 " in df.style.to_latex()
with option_context("styler.format.formatter", None):
assert " 9 " in df.style.to_latex()

msg = "Value must have type"
with pytest.raises(ValueError, match=msg):
with option_context("styler.format.formatter", ["bad", "type"]):
df.style.to_latex()