From f967017d7d09d8aa7e91150946131543aeaf5db4 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 13 Sep 2025 16:08:16 +0200 Subject: [PATCH] Robust test for callable objects - If the object implements a custom `__getattr__`, or if its `__call__` is itself not callable, you may get misleading results. - Instead use the built-in `callable` function. Not only is it more robust, but it makes the intent clear and the code more readable. --- tabulate/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tabulate/__init__.py b/tabulate/__init__.py index e100c09..e1756f8 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -1480,7 +1480,7 @@ def _normalize_tabular_data(tabular_data, headers, showindex="default"): index = None if hasattr(tabular_data, "keys") and hasattr(tabular_data, "values"): # dict-like and pandas.DataFrame? - if hasattr(tabular_data.values, "__call__"): + if callable(tabular_data.values): # likely a conventional dict keys = tabular_data.keys() try: @@ -2515,7 +2515,7 @@ def _build_row(padded_cells, colwidths, colaligns, rowfmt): "Return a string which represents a row of data cells." if not rowfmt: return None - if hasattr(rowfmt, "__call__"): + if callable(rowfmt): return rowfmt(padded_cells, colwidths, colaligns) else: return _build_simple_row(padded_cells, rowfmt) @@ -2566,7 +2566,7 @@ def _build_line(colwidths, colaligns, linefmt): "Return a string which represents a horizontal line." if not linefmt: return None - if hasattr(linefmt, "__call__"): + if callable(linefmt): return linefmt(colwidths, colaligns) else: begin, fill, sep, end = linefmt