| 168 | |
| 169 | |
| 170 | def tabulate(tabular_data, headers=(), tablefmt="simple", floatfmt="g", stralign="left", numalign=None): |
| 171 | rows = [list(row) for row in tabular_data] |
| 172 | |
| 173 | def fmt(val): |
| 174 | if isinstance(val, str): |
| 175 | return val |
| 176 | if isinstance(val, (bool, int)): |
| 177 | return str(val) |
| 178 | try: |
| 179 | return format(val, floatfmt) |
| 180 | except (TypeError, ValueError): |
| 181 | return str(val) |
| 182 | |
| 183 | formatted = [[fmt(c) for c in row] for row in rows] |
| 184 | hdrs = [str(h) for h in headers] if headers else None |
| 185 | |
| 186 | ncols = max((len(r) for r in formatted), default=0) |
| 187 | if hdrs: |
| 188 | ncols = max(ncols, len(hdrs)) |
| 189 | if ncols == 0: |
| 190 | return "" |
| 191 | |
| 192 | for r in formatted: |
| 193 | r.extend([""] * (ncols - len(r))) |
| 194 | if hdrs: |
| 195 | hdrs.extend([""] * (ncols - len(hdrs))) |
| 196 | |
| 197 | widths = [0] * ncols |
| 198 | if hdrs: |
| 199 | for i in range(ncols): |
| 200 | widths[i] = len(hdrs[i]) |
| 201 | for row in formatted: |
| 202 | for i in range(ncols): |
| 203 | widths[i] = max(widths[i], max(len(ln) for ln in row[i].split('\n'))) |
| 204 | |
| 205 | def _align(s, w): |
| 206 | if stralign == "center": |
| 207 | return s.center(w) |
| 208 | return s.ljust(w) |
| 209 | |
| 210 | if tablefmt == "html": |
| 211 | parts = ["<table>"] |
| 212 | if hdrs: |
| 213 | parts.append("<thead>") |
| 214 | parts.append("<tr>" + "".join(f"<th>{h}</th>" for h in hdrs) + "</tr>") |
| 215 | parts.append("</thead>") |
| 216 | parts.append("<tbody>") |
| 217 | for row in formatted: |
| 218 | parts.append("<tr>" + "".join(f"<td>{c}</td>" for c in row) + "</tr>") |
| 219 | parts.append("</tbody>") |
| 220 | parts.append("</table>") |
| 221 | return "\n".join(parts) |
| 222 | |
| 223 | if tablefmt == "simple_grid": |
| 224 | def _sep(left, mid, right): |
| 225 | return left + mid.join("\u2500" * (w + 2) for w in widths) + right |
| 226 | |
| 227 | top, mid_sep, bot = _sep("\u250c", "\u252c", "\u2510"), _sep("\u251c", "\u253c", "\u2524"), _sep("\u2514", "\u2534", "\u2518") |