From ff820f4fe57edb17def9f8779999180d3e5b4b58 Mon Sep 17 00:00:00 2001 From: Kevin Salmon <136859499+nasmovk@users.noreply.github.com> Date: Thu, 25 Sep 2025 18:33:25 +0200 Subject: [PATCH 1/7] Update __init__.py Rewrite of the print_table output method. This is in response to the need for greater control over column widths and other formatting options. The method is rewritten to directly output an HTML table instead of the original markdown approach. It introduces more CSS options through classes. This in turn allows different formatting options to be specified for each table in the same output window (which was limited in the original). The new funcionality can be optionally called with new kwargs. If these are not specified, the original functionality of the old print_table is maintained. It adds some data validation to check that arguments of type list are of the same length. Finally, this contribution should male it easier to later implement HTML colspan options to make more flexible tables. --- pyrevitlib/pyrevit/output/__init__.py | 250 ++++++++++++++++++++------ 1 file changed, 199 insertions(+), 51 deletions(-) diff --git a/pyrevitlib/pyrevit/output/__init__.py b/pyrevitlib/pyrevit/output/__init__.py index 011c8c337..c43610aad 100644 --- a/pyrevitlib/pyrevit/output/__init__.py +++ b/pyrevitlib/pyrevit/output/__init__.py @@ -28,7 +28,7 @@ from pyrevit import coreutils from pyrevit.coreutils import logger from pyrevit.coreutils import markdown, charts -from pyrevit.coreutils import envvars +from pyrevit.coreutils import envvars, random from pyrevit.runtime.types import ScriptConsoleManager from pyrevit.output import linkmaker from pyrevit.userconfig import user_config @@ -544,16 +544,104 @@ def print_md(md_str): html_code = coreutils.prepare_html_str(markdown_html) print(html_code, end="") - def print_table(self, table_data, columns=None, formats=None, - title='', last_line_style=''): - """Print provided data in a table in output window. + def table_html_header(self, columns, table_uid): + """Helper method for print_table() method + + Return html row for the table header + Args: + columns (list[str]): list of column names + table_uid (str): a unique ID for this table's CSS classes + + """ + html_head = "" + for i, c in enumerate(columns): + html_head += "{}".format(table_uid, i, c) + # pyRevit original print_table uses align='left'. + # This is now overridden by CSS if specified + html_head += "" + + return html_head + + + def table_check_input_lists(self, + table_data, + columns, + formats, + input_kwargs): + """Helper method for print_table() method + + Check that the table_data is present and is a list + Check that table_data rows are of the same length + Check that all print_table() kwargs of type list are of the right length + + Args: + table_data(iterable[Any]]): The whole table data + columns (list[str]): columns + formats (list[str]): formats + input_kwargs (iterable[Any]]): list of arg lists + + Return: + True if input lists are OK to proceed to build the table + False if not, with a relevant warning message + """ + + # First check positional and named keyword args + if not table_data: + return False, "No table_data list" + if not isinstance(table_data, list): + return False, "table_data is not a list" + else: # table_data is a list. The first sublist must also be a list + first_data_row = table_data[0] + if not isinstance(first_data_row, list): + return False, "table_data's first row is not a list" + else: + len_data_row = len(first_data_row) + if not all(len(row) == len_data_row for row in table_data): + return False, "Not all rows of table_data are of equal length" + + if columns and len_data_row != len(columns): # columns is allowed to be None + return False, "Column head list length not equal to data row" + + if formats and len_data_row != len(formats): # formats is allowed to be None + return False, "Formats list length not equal to data row" + + # Next check **kwargs + # Loop through the lists and return if not a list or len not equal + for l in input_kwargs: + if not l: # No kwarg is OK beacause they are optional + return True, "kwarg None" + if not isinstance(l, list): + return False, "One of the print_table kwargs that should be a list is not a list ({})".format(l) + else: + if len(l) != len_data_row: + return False, "print_table kwarg list length problem (should match {} columns)".format(len_data_row) + + return True, "Inputs OK" + + + def print_table(self, + table_data, + title='', + columns=None, + formats=None, + last_line_style='', + **kwargs): + """Print provided data in a HTML table in output window. + The same window can output several tables, each with their own formatting options. Args: table_data (list[iterable[Any]]): 2D array of data title (str): table title columns (list[str]): list of column names - formats (list[str]): column data formats - last_line_style (str): css style of last row + formats (list[str]): column data formats using python string formatting + last_line_style (str): css style of last row of data (NB applies to all tables in this output) + new kwargs: + column_head_align_styles (list[str]): list css align-text styles for header row + column_data_align_styles (list[str]): list css align-text styles for data rows + column_widths (list[str]): list of CSS widths in either px or % or 'auto' or a combination + column_vertical_border_style (str): CSS compact border definition + table_width_style (str): CSS to use for width for the whole table, in either px or % + repeat_head_as_foot (bool): Repeat the header row at the table foot (useful for long tables) Examples: ```python @@ -566,57 +654,117 @@ def print_table(self, table_data, columns=None, formats=None, title="Example Table", columns=["Row Name", "Column 1", "Column 2", "Percentage"], formats=['', '', '', '{}%'], - last_line_style='color:red;' + last_line_style='color:red;', + # new kwargs: + col_head_align_styles = ["left", "left", "center", "right"], + col_data_align_styles = ["left", "left", "center", "right"], + column_widths = ["100px", "100px", "500px", "100px"], | ["115px", "75px", "auto", "auto"] + column_vertical_border_style = "border:black solid 1px", + table_width_style='width:100%', + repeat_head_as_foot=True ) + Returns: + Directly prints: + print_md of the title (str): + print_html of the generated HTML table with formatting. ``` """ - if not columns: - columns = [] - if not formats: - formats = [] - - if last_line_style: - self.add_style('tr:last-child {{ {style} }}' - .format(style=last_line_style)) - zipper = itertools.izip_longest #pylint: disable=E1101 - adjust_base_col = '|' - adjust_extra_col = ':---|' - base_col = '|' - extra_col = '{data}|' + # Get user formatting options from kwargs + column_head_align_styles = kwargs.get("column_head_align_styles", None) + column_data_align_styles = kwargs.get("column_data_align_styles", None) + column_widths = kwargs.get("column_widths", None) + column_vertical_border_style = kwargs.get("column_vertical_border_style", None) + table_width_style = kwargs.get("table_width_style", None) + repeat_head_as_foot = kwargs.get("repeat_head_as_foot", False) + + # Set a unique ID for each table + # This is used in HTML tags to define CSS classes for formatting per table + table_uid = random.randint(10000, 99999) + + # Validate input arguments should be lists: + input_kwargs = [column_head_align_styles, column_data_align_styles, column_widths] + inputs_ok, inputs_msg = self.table_check_input_lists(table_data, + columns, + formats, + input_kwargs) + + if not inputs_ok: + self.print_md('### :warning: {} '.format(inputs_msg)) + return - # find max column count - max_col = max([len(x) for x in table_data]) - - header = '' + if last_line_style: + # Adds a CCS class to allow a last-row format per table (if several in the same output) + self.add_style('tr.data-row-{}:last-child {{ {style} }}'.format(table_uid, style=last_line_style)) + + if column_head_align_styles: + for i, s in enumerate(column_head_align_styles): + self.add_style('.head_title-{}-{} {{ text-align:{style} }}'.format(table_uid, i, style=s)) + + if column_data_align_styles: + for i, s in enumerate(column_data_align_styles): + self.add_style('.data_cell-{}-{} {{ text-align:{style} }}'.format(table_uid, i, style=s)) + + if table_width_style: + self.add_style('.tab-{} {{ width:{} }}'.format(table_uid, table_width_style)) + + # Open HTML table and its CSS class + html = "".format(table_uid) + + # Build colgroup if user argument specifies column widths + if column_widths: + COL = "" + html += '' + for w in column_widths: + html += COL.format(w) + html += "" + + # Build header row (column titles) if requested if columns: - header = base_col - for idx, col_name in zipper(range(max_col), columns, fillvalue=''): #pylint: disable=W0612 - header += extra_col.format(data=col_name) - - header += '\n' - - justifier = adjust_base_col - for idx in range(max_col): - justifier += adjust_extra_col - - justifier += '\n' - - rows = '' - for entry in table_data: - row = base_col - for idx, attrib, attr_format \ - in zipper(range(max_col), entry, formats, fillvalue=''): - if attr_format: - value = attr_format.format(attrib) - else: - value = attrib - row += extra_col.format(data=value) - rows += row + '\n' - - table = header + justifier + rows - self.print_md('### {title}'.format(title=title)) - self.print_md(table) + html_head = self.table_html_header(columns, table_uid) + html += html_head + else: + html_head ="" + repeat_head_as_foot = False + + if column_vertical_border_style: + border_style = "style='{}'".format(column_vertical_border_style) + else: + border_style = "" + + # Build body rows from 2D python list table_data + html += "" + for row in table_data: + # Build an HTML data row with CSS class for this table + html += "".format(table_uid) + for i, cell_data in enumerate(row): + + # Slight workaround to be backwards compatible with pyRevit original print_table + # pyRevit documentation gives the example: formats=['', '', '', '{}%'], + # ie, sometimes giving an empty string, sometimes a placeholder with string formatting + if formats: # If format options provided + if len(formats[i])<1: # Test for the empty string case + format_placeholder = "{}" + else: + format_placeholder = formats[i] + + cell_data = format_placeholder.format(cell_data) # Insert data with or without formatting + + html += "".format(table_uid, i, border_style, cell_data) + html += "" + + # Re-insert header row at the end, if requested and if column titles provided + if repeat_head_as_foot: + html += html_head + + + html += "" + html += "
{}
" # Close table + + if title: + self.print_md('### {title}'.format(title=title)) + self.print_html(html) + def print_image(self, image_path): r"""Prints given image to the output. From 7cafb3bf377598fe0601cc9038c91b6ddc3792c9 Mon Sep 17 00:00:00 2001 From: Kevin Salmon <136859499+nasmovk@users.noreply.github.com> Date: Fri, 26 Sep 2025 18:51:35 +0200 Subject: [PATCH 2/7] Update __init__.py Small optimisation removing superfluous else s in the table_check_input_lists method --- pyrevitlib/pyrevit/output/__init__.py | 28 +++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/pyrevitlib/pyrevit/output/__init__.py b/pyrevitlib/pyrevit/output/__init__.py index c43610aad..c6f5089b8 100644 --- a/pyrevitlib/pyrevit/output/__init__.py +++ b/pyrevitlib/pyrevit/output/__init__.py @@ -590,14 +590,13 @@ def table_check_input_lists(self, return False, "No table_data list" if not isinstance(table_data, list): return False, "table_data is not a list" - else: # table_data is a list. The first sublist must also be a list - first_data_row = table_data[0] - if not isinstance(first_data_row, list): - return False, "table_data's first row is not a list" - else: - len_data_row = len(first_data_row) - if not all(len(row) == len_data_row for row in table_data): - return False, "Not all rows of table_data are of equal length" + # table_data is a list. The first sublist must also be a list + first_data_row = table_data[0] + if not isinstance(first_data_row, list): + return False, "table_data's first row is not a list" + len_data_row = len(first_data_row) + if not all(len(row) == len_data_row for row in table_data): + return False, "Not all rows of table_data are of equal length" if columns and len_data_row != len(columns): # columns is allowed to be None return False, "Column head list length not equal to data row" @@ -608,13 +607,12 @@ def table_check_input_lists(self, # Next check **kwargs # Loop through the lists and return if not a list or len not equal for l in input_kwargs: - if not l: # No kwarg is OK beacause they are optional - return True, "kwarg None" - if not isinstance(l, list): - return False, "One of the print_table kwargs that should be a list is not a list ({})".format(l) - else: - if len(l) != len_data_row: - return False, "print_table kwarg list length problem (should match {} columns)".format(len_data_row) + if not l: # No kwarg is OK beacause they are optional + return True, "kwarg None" + if not isinstance(l, list): + return False, "One of the print_table kwargs that should be a list is not a list ({})".format(l) + if len(l) != len_data_row: + return False, "print_table kwarg list length problem (should match {} columns)".format(len_data_row) return True, "Inputs OK" From 15d37ed7ac24317ef1bb9ffa77dc3bec17ad1499 Mon Sep 17 00:00:00 2001 From: Kevin Salmon <136859499+nasmovk@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:59:35 +0200 Subject: [PATCH 3/7] Update __init__.py Minor update, addin the border style to the header row. --- pyrevitlib/pyrevit/output/__init__.py | 68 ++++++++++++++++----------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/pyrevitlib/pyrevit/output/__init__.py b/pyrevitlib/pyrevit/output/__init__.py index c6f5089b8..0dde3cfc7 100644 --- a/pyrevitlib/pyrevit/output/__init__.py +++ b/pyrevitlib/pyrevit/output/__init__.py @@ -544,7 +544,8 @@ def print_md(md_str): html_code = coreutils.prepare_html_str(markdown_html) print(html_code, end="") - def table_html_header(self, columns, table_uid): + + def table_html_header(self, columns, table_uid, border_style): """Helper method for print_table() method Return html row for the table header @@ -553,7 +554,7 @@ def table_html_header(self, columns, table_uid): table_uid (str): a unique ID for this table's CSS classes """ - html_head = "" + html_head = "".format(border_style) for i, c in enumerate(columns): html_head += "{}".format(table_uid, i, c) # pyRevit original print_table uses align='left'. @@ -591,9 +592,9 @@ def table_check_input_lists(self, if not isinstance(table_data, list): return False, "table_data is not a list" # table_data is a list. The first sublist must also be a list - first_data_row = table_data[0] + first_data_row = list(table_data[0]) if not isinstance(first_data_row, list): - return False, "table_data's first row is not a list" + return False, "table_data's first row is not a list or tuple ({})".format(type(first_data_row)) len_data_row = len(first_data_row) if not all(len(row) == len_data_row for row in table_data): return False, "Not all rows of table_data are of equal length" @@ -616,12 +617,12 @@ def table_check_input_lists(self, return True, "Inputs OK" - + def print_table(self, table_data, - title='', columns=None, formats=None, + title='', last_line_style='', **kwargs): """Print provided data in a HTML table in output window. @@ -633,13 +634,14 @@ def print_table(self, columns (list[str]): list of column names formats (list[str]): column data formats using python string formatting last_line_style (str): css style of last row of data (NB applies to all tables in this output) - new kwargs: - column_head_align_styles (list[str]): list css align-text styles for header row - column_data_align_styles (list[str]): list css align-text styles for data rows - column_widths (list[str]): list of CSS widths in either px or % or 'auto' or a combination - column_vertical_border_style (str): CSS compact border definition - table_width_style (str): CSS to use for width for the whole table, in either px or % - repeat_head_as_foot (bool): Repeat the header row at the table foot (useful for long tables) + column_head_align_styles (list[str]): list css align-text styles for header row + column_data_align_styles (list[str]): list css align-text styles for data rows + column_widths (list[str]): list of CSS widths in either px or % + column_vertical_border_style (str): CSS compact border definition + table_width_style (str): CSS to use for width for the whole table, in either px or % + repeat_head_as_foot (bool): Repeat the header row at the table foot (useful for long tables) + row_striping (bool): False to override the default white-grey row stripes and make all white) + Examples: ```python @@ -653,13 +655,14 @@ def print_table(self, columns=["Row Name", "Column 1", "Column 2", "Percentage"], formats=['', '', '', '{}%'], last_line_style='color:red;', - # new kwargs: - col_head_align_styles = ["left", "left", "center", "right"], - col_data_align_styles = ["left", "left", "center", "right"], - column_widths = ["100px", "100px", "500px", "100px"], | ["115px", "75px", "auto", "auto"] - column_vertical_border_style = "border:black solid 1px", - table_width_style='width:100%', - repeat_head_as_foot=True + col_head_align_styles = ["left", "left", "center", "right"], + col_data_align_styles = ["left", "left", "center", "right"], + column_widths = ["100px", "100px", "500px", "100px"], + column_vertical_border_style = "border:black solid 1px", + table_width_style='width:100%', + repeat_head_as_foot=True, + row_striping=False + ) Returns: Directly prints: @@ -675,6 +678,8 @@ def print_table(self, column_vertical_border_style = kwargs.get("column_vertical_border_style", None) table_width_style = kwargs.get("table_width_style", None) repeat_head_as_foot = kwargs.get("repeat_head_as_foot", False) + row_striping = kwargs.get("row_striping", True) + # Set a unique ID for each table # This is used in HTML tags to define CSS classes for formatting per table @@ -691,6 +696,11 @@ def print_table(self, self.print_md('### :warning: {} '.format(inputs_msg)) return + + if not row_striping: + # Override default original pyRevit white-grey row striping. Makes all rows white. + self.add_style('tr.data-row-{} {{ {style} }}'.format(table_uid, style="background-color: #ffffff")) + if last_line_style: # Adds a CCS class to allow a last-row format per table (if several in the same output) self.add_style('tr.data-row-{}:last-child {{ {style} }}'.format(table_uid, style=last_line_style)) @@ -706,6 +716,7 @@ def print_table(self, if table_width_style: self.add_style('.tab-{} {{ width:{} }}'.format(table_uid, table_width_style)) + # Open HTML table and its CSS class html = "".format(table_uid) @@ -716,19 +727,20 @@ def print_table(self, for w in column_widths: html += COL.format(w) html += "" - + + if column_vertical_border_style: + border_style = "style='{}'".format(column_vertical_border_style) + else: + border_style = "" + # Build header row (column titles) if requested if columns: - html_head = self.table_html_header(columns, table_uid) + html_head = self.table_html_header(columns, table_uid, border_style) html += html_head else: html_head ="" repeat_head_as_foot = False - - if column_vertical_border_style: - border_style = "style='{}'".format(column_vertical_border_style) - else: - border_style = "" + # Build body rows from 2D python list table_data html += "" @@ -739,7 +751,7 @@ def print_table(self, # Slight workaround to be backwards compatible with pyRevit original print_table # pyRevit documentation gives the example: formats=['', '', '', '{}%'], - # ie, sometimes giving an empty string, sometimes a placeholder with string formatting + # Sometimes giving an empty string, sometimes a placeholder with string formatting if formats: # If format options provided if len(formats[i])<1: # Test for the empty string case format_placeholder = "{}" From d79f772c7873f4f1c396d0fee7bc608c54f19bfe Mon Sep 17 00:00:00 2001 From: Kevin Salmon <136859499+nasmovk@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:11:34 +0200 Subject: [PATCH 4/7] Update __init__.py 2025-10-01. Following JMC comments 31: Remove random import (from pyrevit.coreutils) 97: Add new __init__ to PyRevitOutputWindow class for a _table_counter 610: Correct logical error in kwarg validation 686: Implement _table_counter 755: Replace verbose if with a compact one. --- pyrevitlib/pyrevit/output/__init__.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pyrevitlib/pyrevit/output/__init__.py b/pyrevitlib/pyrevit/output/__init__.py index 0dde3cfc7..fade46a8a 100644 --- a/pyrevitlib/pyrevit/output/__init__.py +++ b/pyrevitlib/pyrevit/output/__init__.py @@ -28,7 +28,7 @@ from pyrevit import coreutils from pyrevit.coreutils import logger from pyrevit.coreutils import markdown, charts -from pyrevit.coreutils import envvars, random +from pyrevit.coreutils import envvars from pyrevit.runtime.types import ScriptConsoleManager from pyrevit.output import linkmaker from pyrevit.userconfig import user_config @@ -92,7 +92,10 @@ def reset_stylesheet(): class PyRevitOutputWindow(object): """Wrapper to interact with the output window.""" - + + def __init__(self): # Mutable instance variable, which is incremented each time you print a table. + self._table_counter = 0 # initialize the counter + @property def window(self): """``PyRevitLabs.PyRevit.Runtime.ScriptConsole``: Return output window object.""" @@ -609,7 +612,7 @@ def table_check_input_lists(self, # Loop through the lists and return if not a list or len not equal for l in input_kwargs: if not l: # No kwarg is OK beacause they are optional - return True, "kwarg None" + continue if not isinstance(l, list): return False, "One of the print_table kwargs that should be a list is not a list ({})".format(l) if len(l) != len_data_row: @@ -681,9 +684,10 @@ def print_table(self, row_striping = kwargs.get("row_striping", True) - # Set a unique ID for each table + # Get a unique ID for each table from _table_counter # This is used in HTML tags to define CSS classes for formatting per table - table_uid = random.randint(10000, 99999) + self._table_counter+=1 + table_uid = self._table_counter # Validate input arguments should be lists: input_kwargs = [column_head_align_styles, column_data_align_styles, column_widths] @@ -753,10 +757,7 @@ def print_table(self, # pyRevit documentation gives the example: formats=['', '', '', '{}%'], # Sometimes giving an empty string, sometimes a placeholder with string formatting if formats: # If format options provided - if len(formats[i])<1: # Test for the empty string case - format_placeholder = "{}" - else: - format_placeholder = formats[i] + format_placeholder = formats[i] if formats[i] else "{}" cell_data = format_placeholder.format(cell_data) # Insert data with or without formatting From c6e0dad2b0ad588a08712b9336cb4571c11072b9 Mon Sep 17 00:00:00 2001 From: Jean-Marc Couffin Date: Wed, 1 Oct 2025 08:43:18 -0400 Subject: [PATCH 5/7] syntax, comments and black formating --- pyrevitlib/pyrevit/output/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyrevitlib/pyrevit/output/__init__.py b/pyrevitlib/pyrevit/output/__init__.py index fade46a8a..5606e3781 100644 --- a/pyrevitlib/pyrevit/output/__init__.py +++ b/pyrevitlib/pyrevit/output/__init__.py @@ -93,8 +93,8 @@ def reset_stylesheet(): class PyRevitOutputWindow(object): """Wrapper to interact with the output window.""" - def __init__(self): # Mutable instance variable, which is incremented each time you print a table. - self._table_counter = 0 # initialize the counter + def __init__(self): + self._table_counter = 0 @property def window(self): @@ -686,7 +686,7 @@ def print_table(self, # Get a unique ID for each table from _table_counter # This is used in HTML tags to define CSS classes for formatting per table - self._table_counter+=1 + self._table_counter += 1 table_uid = self._table_counter # Validate input arguments should be lists: From af3d76bcb33e92495d2d1cfaff49de2d4238272a Mon Sep 17 00:00:00 2001 From: Jean-Marc Couffin Date: Wed, 1 Oct 2025 08:45:21 -0400 Subject: [PATCH 6/7] nitpicking --- pyrevitlib/pyrevit/output/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pyrevitlib/pyrevit/output/__init__.py b/pyrevitlib/pyrevit/output/__init__.py index 5606e3781..4138b8ca3 100644 --- a/pyrevitlib/pyrevit/output/__init__.py +++ b/pyrevitlib/pyrevit/output/__init__.py @@ -34,15 +34,12 @@ from pyrevit.userconfig import user_config from pyrevit import DB - -#pylint: disable=W0703,C0302,C0103 mlogger = logger.get_logger(__name__) - DEFAULT_STYLESHEET_NAME = 'outputstyles.css' -def docclosing_eventhandler(sender, args): #pylint: disable=W0613 +def docclosing_eventhandler(sender, args): """Close all output window on document closing.""" ScriptConsoleManager.CloseActiveOutputWindows() From cc2330862043a86cd36cf0a2b17f1ec799a6271e Mon Sep 17 00:00:00 2001 From: Jean-Marc Couffin Date: Mon, 6 Oct 2025 21:46:42 -0400 Subject: [PATCH 7/7] Enhance table HTML header and input validation in PyRevitOutputWindow - Added border_style parameter to table_html_header method for customizable table header styling. - Updated docstrings for table_html_header and table_check_input_lists methods to include examples and clarify argument types. - Improved input validation in table_check_input_lists to ensure consistent list lengths and provide detailed error messages. --- pyrevitlib/pyrevit/output/__init__.py | 114 ++++++++++++++++++++------ 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/pyrevitlib/pyrevit/output/__init__.py b/pyrevitlib/pyrevit/output/__init__.py index 4138b8ca3..ed69bd53c 100644 --- a/pyrevitlib/pyrevit/output/__init__.py +++ b/pyrevitlib/pyrevit/output/__init__.py @@ -549,14 +549,46 @@ def table_html_header(self, columns, table_uid, border_style): """Helper method for print_table() method Return html " \ + # "" \ + # "" \ + # "" \ + # "" + + # Without border style + header_html = output.table_html_header( + columns, table_uid, "") + # Returns: "" \ + # "" \ + # "" \ + # "" \ + # "" + ``` """ html_head = "".format(border_style) for i, c in enumerate(columns): - html_head += "".format(table_uid, i, c) + html_head += \ + "".format( + table_uid, i, c) # pyRevit original print_table uses align='left'. # This is now overridden by CSS if specified html_head += "" @@ -565,25 +597,59 @@ def table_html_header(self, columns, table_uid, border_style): def table_check_input_lists(self, - table_data, - columns, - formats, - input_kwargs): + table_data, + columns, + formats, + input_kwargs): """Helper method for print_table() method Check that the table_data is present and is a list Check that table_data rows are of the same length - Check that all print_table() kwargs of type list are of the right length + Check that all print_table() kwargs of type list are of correct length Args: - table_data(iterable[Any]]): The whole table data - columns (list[str]): columns - formats (list[str]): formats - input_kwargs (iterable[Any]]): list of arg lists + table_data (list[list[Any]]): The whole table data as 2D list + columns (list[str]): list of column names + formats (list[str]): list of format strings for each column + input_kwargs (list[list[Any]]): list of additional argument lists - Return: - True if input lists are OK to proceed to build the table - False if not, with a relevant warning message + Returns: + tuple: (bool, str) - (True/False, message) indicating result + + Examples: + ```python + output = pyrevit.output.get_output() + + # Valid table data + table_data = [["John", 25, "NYC"], ["Jane", 30, "LA"]] + columns = ["Name", "Age", "City"] + formats = ["", "{} years", ""] + input_kwargs = [["left", "center", "right"], + ["100px", "80px", "120px"]] + + is_valid, message = output.table_check_input_lists( + table_data, columns, formats, input_kwargs) + # Returns: (True, "Inputs OK") + + # Invalid - mismatched column count + table_data = [["John", 25], ["Jane", 30, "LA"]] # Inconsistent + is_valid, message = output.table_check_input_lists( + table_data, columns, formats, input_kwargs) + # Returns: (False, "Not all rows of table_data are of " + # "equal length") + + # Invalid - wrong number of columns + columns = ["Name", "Age"] # Only 2 columns but data has 3 + is_valid, message = output.table_check_input_lists( + table_data, columns, formats, input_kwargs) + # Returns: (False, "Column head list length not equal " + # "to data row") + + # Invalid - empty table data + is_valid, message = output.table_check_input_lists( + [], columns, formats, input_kwargs) + # Returns: (False, "No table_data list") + ``` """ # First check positional and named keyword args @@ -607,24 +673,24 @@ def table_check_input_lists(self, # Next check **kwargs # Loop through the lists and return if not a list or len not equal - for l in input_kwargs: - if not l: # No kwarg is OK beacause they are optional + for kwarg_list in input_kwargs: + if not kwarg_list: # No kwarg is OK beacause they are optional continue - if not isinstance(l, list): - return False, "One of the print_table kwargs that should be a list is not a list ({})".format(l) - if len(l) != len_data_row: + if not isinstance(kwarg_list, list): + return False, "One of the print_table kwargs that should be a list is not a list ({})".format(kwarg_list) + if len(kwarg_list) != len_data_row: return False, "print_table kwarg list length problem (should match {} columns)".format(len_data_row) return True, "Inputs OK" def print_table(self, - table_data, - columns=None, - formats=None, - title='', - last_line_style='', - **kwargs): + table_data, + columns=None, + formats=None, + title='', + last_line_style='', + **kwargs): """Print provided data in a HTML table in output window. The same window can output several tables, each with their own formatting options.
row for the table header + Args: columns (list[str]): list of column names table_uid (str): a unique ID for this table's CSS classes + border_style (str): CSS border style string for table cells + Returns: + str: HTML string containing the table header row + + Examples: + ```python + output = pyrevit.output.get_output() + + # Basic usage - called internally by print_table() + columns = ["Name", "Age", "City"] + table_uid = 1 + border_style = "border: 1px solid black;" + header_html = output.table_html_header( + columns, table_uid, border_style) + # Returns: "
NameAgeCity
NameAgeCity
{}{}