Skip to content

Commit

Permalink
Neatly format the existing params as a table
Browse files Browse the repository at this point in the history
  • Loading branch information
joelostblom committed Mar 22, 2022
1 parent f648471 commit 1a84e1d
Showing 1 changed file with 74 additions and 20 deletions.
94 changes: 74 additions & 20 deletions altair/utils/schemapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import inspect
import json
import textwrap
from itertools import zip_longest

import jsonschema
import numpy as np
Expand Down Expand Up @@ -116,30 +117,83 @@ def __str__(self):
for val in schema_path[:-1]
if val not in ("properties", "additionalProperties", "patternProperties")
)

if hasattr(vegalite, schema_path.split(".")[-1]):
altair_class = "altair." + schema_path.split(".")[-1]
vegalite_core_class = getattr(vegalite, schema_path.split(".")[-1])
param_dict_keys = inspect.signature(vegalite_core_class).parameters.keys()
param_names = (
"Existing parameter names are: "
+ str([name for name in param_dict_keys if name != "kwds"])[1:-1]
)
altair_class = "altair." + schema_path.split(".")[-1]
return """Invalid specification
{}, validating {!r}

{} has no parameter named {!r}
{}
See the help for {} to read the full description of these parameters
""".format(
schema_path,
self.validator,
altair_class,
list(self.instance.keys())[0],
textwrap.fill(param_names, subsequent_indent=" " * 12, width=80),
altair_class,
# Everything from here until the return statement is to format
# param names into a table so that they are easier to read
param_names, name_lengths = zip(
*[(name, len(name)) for name in param_dict_keys if name != "kwds"]
)
# Worst case scenario with the same longest param name in the same
# row for all columns
max_name_length = max(name_lengths)
max_column_width = 80
# Output a square table if not too big (since it is easier to read)
num_param_names = len(param_names)
square_columns = int(np.ceil(num_param_names**0.5))
columns = min(max_column_width // max_name_length, square_columns)
# Compute roughly equal column heights to evenly divide the param names
def split_into_equal_parts(n, p):
return [n // p + 1] * (n % p) + [n // p] * (p - n % p)

column_heights = split_into_equal_parts(num_param_names, columns)

# Section the param names into columns and compute their widths
param_names_columns = []
column_max_widths = []
last_end_idx = 0
for ch in column_heights:
param_names_columns.append(
param_names[last_end_idx : last_end_idx + ch]
)
column_max_widths.append(
max([len(param_name) for param_name in param_names_columns[-1]])
)
last_end_idx = ch + last_end_idx

# Transpose the param name columns into rows to facilitate looping
param_names_rows = []
for li in zip_longest(*param_names_columns, fillvalue=""):
param_names_rows.append(li)
# Build the table as a string by iterating over and formatting the rows
param_names_table = ""
for param_names_row in param_names_rows:
for num, param_name in enumerate(param_names_row):
# Set column width based on the longest param in the column
max_name_length_column = column_max_widths[num]
column_pad = 3
param_names_table += "{:<{}}".format(
param_name, max_name_length_column + column_pad
)
# Insert newlines and spacing after the last element in each row
if num == (len(param_names_row) - 1):
param_names_table += "\n"
# 16 is the indendation of the returned multiline string below
param_names_table += " " * 16

# cleandoc removes multiline string indentation in the output
return inspect.cleandoc(
"""Invalid specification
{}, validating {!r}
{} has no parameter named {!r}
Existing parameter names are:
{}
See the help for {} to read the full description of these parameters
""".format(
schema_path,
self.validator,
altair_class,
list(self.instance.keys())[0],
param_names_table,
altair_class,
)
)
# Fall back on the less informative error message
else:
Expand Down

0 comments on commit 1a84e1d

Please sign in to comment.