pyrevit.output

Usage

This module provides access to the output window for the currently running pyRevit command. The proper way to access this wrapper object is through the get_output() of pyrevit.script module. This method, in return uses the pyrevit.output module to get access to the output wrapper.

Example:
>>> from pyrevit import script
>>> output = script.get_output()

Here is the source of pyrevit.script.get_output(). As you can see this functions calls the pyrevit.output.get_output() to receive the output wrapper.

def get_output():
    """Return object wrapping output window for current script.

    Returns:
        :obj:`pyrevit.output.PyRevitOutputWindow`: Output wrapper object
    """
    return output.get_output()

Documentation

Provide access to output window and its functionality.

class pyrevit.output.PyRevitOutputWindow

Wrapper to interact with the output window.

add_style(style_code, attribs=None)

Inject style tag into current html head of the output window.

Parameters:
  • style_code (str) – css styling code
  • attribs (dict) – dictionary of attribute names and value

Example

>>> output = pyrevit.output.get_output()
>>> output.add_style('body { color: blue; }')
close()

Close the window.

close_others(all_open_outputs=False)

Close all other windows that belong to the current command.

Parameters:all_open_outputs (bool) – Close all any other windows if True
debug_mode

Set debug mode on output window and stream.

This will cause the output window to print information about the buffer stream and other aspects of the output window mechanism.

static emojize(md_str)

Replace emoji codes with emoji images and print.

Parameters:md_str (str) – string containing emoji code

Example

>>> output = pyrevit.output.get_output()
>>> output.emojize('Process completed. :thumbs_up:')
get_head_html()

str: Return inner code of html head element.

get_height()

int: Return current window height.

get_title()

str: Return current window title.

get_width()

int: Return current window width.

hide()

Hide the window.

hide_progress()

Hide output window progress bar.

inject_script(script_code, attribs=None)

Inject script tag into current html head of the output window.

Parameters:
  • script_code (str) – javascript code
  • attribs (dict) – dictionary of attribute names and value

Example

>>> output = pyrevit.output.get_output()
>>> output.inject_script('',   # no script since it's a link
                         {'src': js_script_file_path})
inject_to_head(element_tag, element_contents, attribs=None)

Inject html element to current html head of the output window.

Parameters:
  • element_tag (str) – html tag of the element e.g. ‘div’
  • element_contents (str) – html code of the element contents
  • attribs (dict) – dictionary of attribute names and value

Example

>>> output = pyrevit.output.get_output()
>>> output.inject_to_head('script',
                          '',   # no script since it's a link
                          {'src': js_script_file_path})
insert_divider()

Add horizontal rule to the output window.

static linkify(element_ids, title=None)

Create clickable link for the provided element ids.

This method, creates the link but does not print it directly.

Parameters:
  • element_ids (list of ElementId) –
  • element_ids – single or multiple ids
  • title (str) – tile of the link. defaults to list of element ids

Example

>>> output = pyrevit.output.get_output()
>>> for idx, elid in enumerate(element_ids):
>>>     print('{}: {}'.format(idx+1, output.linkify(elid)))
lock_size()

Lock window size.

make_bar_chart()

PyRevitOutputChart: Return bar chart object.

make_bubble_chart()

PyRevitOutputChart: Return bubble chart object.

make_chart()

PyRevitOutputChart: Return chart object.

make_doughnut_chart()

PyRevitOutputChart: Return dougnut chart object.

make_line_chart()

PyRevitOutputChart: Return line chart object.

make_pie_chart()

PyRevitOutputChart: Return pie chart object.

make_polar_chart()

PyRevitOutputChart: Return polar chart object.

make_radar_chart()

PyRevitOutputChart: Return radar chart object.

make_stacked_chart()

PyRevitOutputChart: Return stacked chart object.

next_page()

Add hidden next page tag to the output window.

This is helpful to silently separate the output to multiple pages for better printing.

open_page(dest_file)

Open html page in output window.

Parameters:dest_file (str) – full path of the target html file
open_url(dest_url)

Open url page in output window.

Parameters:dest_url (str) – web url of the target page
output_id

str – Return id of the output window.

In current implementation, Id of output window is equal to the unique id of the pyRevit command it belongs to. This means that all output windows belonging to the same pyRevit command, will have identical output_id values.

output_uniqueid

str – Return unique id of the output window.

In current implementation, unique id of output window is a GUID string generated when the output window is opened. This id is unique to the instance of output window.

static print_code(code_str)

Print code to the output window with special formatting.

Example

>>> output = pyrevit.output.get_output()
>>> output.print_code('value = 12')
static print_html(html_str)

Add the html code to the output window.

Example

>>> output = pyrevit.output.get_output()
>>> output.print_html('<strong>Title</strong>')
static print_md(md_str)

Process markdown code and print to output window.

Example

>>> output = pyrevit.output.get_output()
>>> output.print_md('### Title')
print_table(table_data, columns=[], formats=[], title='', last_line_style='')

Print provided data in a table in output window.

Parameters:
  • table_data (list of iterables) – 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

Example

>>> data = [
... ['row1', 'data', 'data', 80 ],
... ['row2', 'data', 'data', 45 ],
... ]
>>> output.print_table(
... table_data=data,
... title="Example Table",
... columns=["Row Name", "Column 1", "Column 2", "Percentage"],
... formats=['', '', '', '{}%'],
... last_line_style='color:red;'
... )
renderer

Return html renderer inside output window.

Returns:System.Windows.Forms.WebBrowser (In current implementation)
reset_progress()

Reset output window progress bar to zero.

resize(width, height)

Resize window to the new width and height.

save_contents(dest_file)

Save html code of the window.

Parameters:dest_file (str) – full path of the destination html file
self_destruct(seconds)

Set self-destruct (close window) timer.

Parameters:seconds (int) – number of seconds after which window is closed.
set_font(font_family, font_size)

Set window font family to the new font family and size.

Parameters:
  • font_family (str) – font family name e.g. ‘Courier New’
  • font_size (int) – font size e.g. 16
set_height(height)

Set window height to the new height.

set_title(new_title)

Set window title to the new title.

set_width(width)

Set window width to the new width.

show()

Show the window.

unhide_progress()

Unhide output window progress bar.

update_progress(cur_value, max_value)

Activate and update the output window progress bar.

Parameters:
  • cur_value (float) – current progress value e.g. 50
  • max_value (float) – total value e.g. 100

Example

>>> output = pyrevit.output.get_output()
>>> for i in range(100):
>>>     output.update_progress(i, 100)
window

PyRevitBaseClasses.ScriptOutput – Return output window object.

pyrevit.output.get_default_stylesheet()

Return default css stylesheet used by output window.

pyrevit.output.get_output()

pyrevit.output.PyRevitOutputWindow : Return output window.

pyrevit.output.get_stylesheet()

Return active css stylesheet used by output window.

pyrevit.output.reset_stylesheet()

Reset active stylesheet to default.

pyrevit.output.set_stylesheet(stylesheet)

Set active css stylesheet used by output window.

Parameters:stylesheet (str) – full path to stylesheet file

Implementation

"""Provide access to output window and its functionality."""

from __future__ import print_function
import os.path as op
import itertools

from pyrevit import EXEC_PARAMS
from pyrevit.compat import safe_strtype
from pyrevit import framework
from pyrevit import coreutils
from pyrevit.coreutils import logger
from pyrevit.coreutils import markdown, charts
from pyrevit.coreutils import emoji
from pyrevit.coreutils import envvars
from pyrevit.coreutils.loadertypes import EnvDictionaryKeys
from pyrevit.coreutils.loadertypes import ScriptOutputManager
from pyrevit.output import linkmaker
from pyrevit.userconfig import user_config


mlogger = logger.get_logger(__name__)


DEFAULT_STYLESHEET_NAME = 'outputstyles.css'


def set_stylesheet(stylesheet):
    """Set active css stylesheet used by output window.

    Args:
        stylesheet (str): full path to stylesheet file
    """
    envvars.set_pyrevit_env_var(EnvDictionaryKeys.outputStyleSheet,
                                stylesheet)


def get_stylesheet():
    """Return active css stylesheet used by output window."""
    return envvars.get_pyrevit_env_var(EnvDictionaryKeys.outputStyleSheet)


def get_default_stylesheet():
    """Return default css stylesheet used by output window."""
    return op.join(op.dirname(__file__), DEFAULT_STYLESHEET_NAME)


def reset_stylesheet():
    """Reset active stylesheet to default."""
    envvars.set_pyrevit_env_var(EnvDictionaryKeys.outputStyleSheet,
                                get_default_stylesheet())


# setup output window stylesheet
if not EXEC_PARAMS.doc_mode:
    active_stylesheet = \
        user_config.core.get_option('outputstylesheet',
                                    default_value=get_default_stylesheet())
    set_stylesheet(active_stylesheet)


class PyRevitOutputWindow(object):
    """Wrapper to interact with the output window."""

    @property
    def window(self):
        """``PyRevitBaseClasses.ScriptOutput``: Return output window object."""
        return EXEC_PARAMS.window_handle

    @property
    def renderer(self):
        """Return html renderer inside output window.

        Returns:
            ``System.Windows.Forms.WebBrowser`` (In current implementation)
        """
        if self.window:
            return self.window.renderer

    @property
    def output_id(self):
        """str: Return id of the output window.

        In current implementation, Id of output window is equal to the
        unique id of the pyRevit command it belongs to. This means that all
        output windows belonging to the same pyRevit command, will have
        identical output_id values.
        """
        if self.window:
            return self.window.OutputId

    @property
    def output_uniqueid(self):
        """str: Return unique id of the output window.

        In current implementation, unique id of output window is a GUID string
        generated when the output window is opened. This id is unique to the
        instance of output window.
        """
        if self.window:
            return self.window.OutputUniqueId

    @property
    def debug_mode(self):
        """Set debug mode on output window and stream.

        This will cause the output window to print information about the
        buffer stream and other aspects of the output window mechanism.
        """
        return EXEC_PARAMS.pyrevit_command.OutputStream.PrintDebugInfo

    @debug_mode.setter
    def debug_mode(self, value):
        EXEC_PARAMS.pyrevit_command.OutputStream.PrintDebugInfo = value

    def _get_head_element(self):
        return self.renderer.Document.GetElementsByTagName('head')[0]

    def self_destruct(self, seconds):
        """Set self-destruct (close window) timer.

        Args:
            seconds (int): number of seconds after which window is closed.
        """
        if self.window:
            self.window.SelfDestructTimer(seconds)

    def inject_to_head(self, element_tag, element_contents, attribs=None):
        """Inject html element to current html head of the output window.

        Args:
            element_tag (str): html tag of the element e.g. 'div'
            element_contents (str): html code of the element contents
            attribs (:obj:`dict`): dictionary of attribute names and value

        Example:
            >>> output = pyrevit.output.get_output()
            >>> output.inject_to_head('script',
                                      '',   # no script since it's a link
                                      {'src': js_script_file_path})
        """
        html_element = self.renderer.Document.CreateElement(element_tag)
        if element_contents:
            html_element.InnerHtml = element_contents

        if attribs:
            for attribute, value in attribs.items():
                html_element.SetAttribute(attribute, value)

        # inject the script into head
        head_el = self._get_head_element()
        head_el.AppendChild(html_element)

    def inject_script(self, script_code, attribs=None):
        """Inject script tag into current html head of the output window.

        Args:
            script_code (str): javascript code
            attribs (:obj:`dict`): dictionary of attribute names and value

        Example:
            >>> output = pyrevit.output.get_output()
            >>> output.inject_script('',   # no script since it's a link
                                     {'src': js_script_file_path})
        """
        self.inject_to_head('script', script_code, attribs=attribs)

    def add_style(self, style_code, attribs=None):
        """Inject style tag into current html head of the output window.

        Args:
            style_code (str): css styling code
            attribs (:obj:`dict`): dictionary of attribute names and value

        Example:
            >>> output = pyrevit.output.get_output()
            >>> output.add_style('body { color: blue; }')
        """
        self.inject_to_head('style', style_code, attribs=attribs)

    def get_head_html(self):
        """str: Return inner code of html head element."""
        return self._get_head_element().InnerHtml

    def set_title(self, new_title):
        """Set window title to the new title."""
        if self.window:
            self.window.Title = new_title

    def set_width(self, width):
        """Set window width to the new width."""
        if self.window:
            self.window.Width = width

    def set_height(self, height):
        """Set window height to the new height."""
        if self.window:
            self.window.Height = height

    def set_font(self, font_family, font_size):
        """Set window font family to the new font family and size.

        Args:
            font_family (str): font family name e.g. 'Courier New'
            font_size (int): font size e.g. 16
        """
        # noinspection PyUnresolvedReferences
        self.renderer.Font = \
            framework.Drawing.Font(font_family,
                                   font_size,
                                   framework.Drawing.FontStyle.Regular,
                                   framework.Drawing.GraphicsUnit.Point)

    def resize(self, width, height):
        """Resize window to the new width and height."""
        self.set_width(width)
        self.set_height(height)

    def get_title(self):
        """str: Return current window title."""
        if self.window:
            return self.window.Text

    def get_width(self):
        """int: Return current window width."""
        if self.window:
            return self.window.Width

    def get_height(self):
        """int: Return current window height."""
        if self.window:
            return self.window.Height

    def close(self):
        """Close the window."""
        if self.window:
            self.window.Close()

    def close_others(self, all_open_outputs=False):
        """Close all other windows that belong to the current command.

        Args:
            all_open_outputs (bool): Close all any other windows if True
        """
        if all_open_outputs:
            ScriptOutputManager.CloseActiveOutputWindows(self.window)
        else:
            ScriptOutputManager.CloseActiveOutputWindows(self.window,
                                                         self.output_id)

    def hide(self):
        """Hide the window."""
        if self.window:
            self.window.Hide()

    def show(self):
        """Show the window."""
        if self.window:
            self.window.Show()

    def lock_size(self):
        """Lock window size."""
        if self.window:
            self.window.LockSize()

    def save_contents(self, dest_file):
        """Save html code of the window.

        Args:
            dest_file (str): full path of the destination html file
        """
        if self.renderer:
            html = \
                self.renderer.Document.Body.OuterHtml.encode('ascii', 'ignore')
            doc_txt = self.renderer.DocumentText
            full_html = doc_txt.lower().replace('<body></body>', html)
            with open(dest_file, 'w') as output_file:
                output_file.write(full_html)

    def open_url(self, dest_url):
        """Open url page in output window.

        Args:
            dest_url (str): web url of the target page
        """
        if self.renderer:
            self.renderer.Navigate(dest_url, False)

    def open_page(self, dest_file):
        """Open html page in output window.

        Args:
            dest_file (str): full path of the target html file
        """
        self.show()
        self.open_url('file:///' + dest_file)

    def update_progress(self, cur_value, max_value):
        """Activate and update the output window progress bar.

        Args:
            cur_value (float): current progress value e.g. 50
            max_value (float): total value e.g. 100

        Example:
            >>> output = pyrevit.output.get_output()
            >>> for i in range(100):
            >>>     output.update_progress(i, 100)
        """
        if self.window:
            self.window.UpdateProgressBar(cur_value, max_value)

    def reset_progress(self):
        """Reset output window progress bar to zero."""
        if self.window:
            self.window.UpdateProgressBar(0, 1)

    def hide_progress(self):
        """Hide output window progress bar."""
        if self.window:
            self.window.SetProgressBarVisibility(False)

    def unhide_progress(self):
        """Unhide output window progress bar."""
        if self.window:
            self.window.SetProgressBarVisibility(True)

    @staticmethod
    def emojize(md_str):
        """Replace emoji codes with emoji images and print.

        Args:
            md_str (str): string containing emoji code

        Example:
            >>> output = pyrevit.output.get_output()
            >>> output.emojize('Process completed. :thumbs_up:')
        """
        print(emoji.emojize(md_str), end="")

    @staticmethod
    def print_html(html_str):
        """Add the html code to the output window.

        Example:
            >>> output = pyrevit.output.get_output()
            >>> output.print_html('<strong>Title</strong>')
        """
        print(coreutils.prepare_html_str(emoji.emojize(html_str)),
              end="")

    @staticmethod
    def print_code(code_str):
        """Print code to the output window with special formatting.

        Example:
            >>> output = pyrevit.output.get_output()
            >>> output.print_code('value = 12')
        """
        code_div = '<div class="code">{}</div>'
        print(coreutils.prepare_html_str(
                code_div.format(
                    code_str.replace('    ', '&nbsp;'*4))), end="")

    @staticmethod
    def print_md(md_str):
        """Process markdown code and print to output window.

        Example:
            >>> output = pyrevit.output.get_output()
            >>> output.print_md('### Title')
        """
        tables_ext = 'pyrevit.coreutils.markdown.extensions.tables'
        markdown_html = markdown.markdown(md_str, extensions=[tables_ext])
        markdown_html = markdown_html.replace('\n', '').replace('\r', '')
        html_code = emoji.emojize(coreutils.prepare_html_str(markdown_html))
        print(html_code, end="")

    def print_table(self, table_data, columns=[], formats=[],
                    title='', last_line_style=''):
        """Print provided data in a table in output window.

        Args:
            table_data (:obj:`list` of iterables): 2D array of data
            title (str): table title
            columns (:obj:`list` str): list of column names
            formats (:obj:`list` str): column data formats
            last_line_style (str): css style of last row

        Example:
            >>> data = [
            ... ['row1', 'data', 'data', 80 ],
            ... ['row2', 'data', 'data', 45 ],
            ... ]
            >>> output.print_table(
            ... table_data=data,
            ... title="Example Table",
            ... columns=["Row Name", "Column 1", "Column 2", "Percentage"],
            ... formats=['', '', '', '{}%'],
            ... last_line_style='color:red;'
            ... )
        """
        if last_line_style:
            self.add_style('tr:last-child {{ {style} }}'
                           .format(style=last_line_style))

        zipper = itertools.izip_longest
        adjust_base_col = '|'
        adjust_extra_col = ':---|'
        base_col = '|'
        extra_col = '{data}|'

        # find max column count
        max_col = max([len(x) for x in table_data])

        header = ''
        if columns:
            header = base_col
            for idx, col_name in zipper(range(max_col), columns, fillvalue=''):
                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)

    def insert_divider(self):
        """Add horizontal rule to the output window."""
        self.print_md('-----')

    def next_page(self):
        """Add hidden next page tag to the output window.

        This is helpful to silently separate the output to multiple pages
        for better printing.
        """
        self.print_html('<div class="nextpage"></div><div>&nbsp</div>')

    @staticmethod
    def linkify(element_ids, title=None):
        """Create clickable link for the provided element ids.

        This method, creates the link but does not print it directly.

        Args:
            element_ids (`ElementId`) or
            element_ids (:obj:`list` of `ElementId`): single or multiple ids
            title (str): tile of the link. defaults to list of element ids

        Example:
            >>> output = pyrevit.output.get_output()
            >>> for idx, elid in enumerate(element_ids):
            >>>     print('{}: {}'.format(idx+1, output.linkify(elid)))
        """
        return coreutils.prepare_html_str(
            linkmaker.make_link(element_ids, contents=title)
            )

    def make_chart(self):
        """:obj:`PyRevitOutputChart`: Return chart object."""
        return charts.PyRevitOutputChart(self)

    def make_line_chart(self):
        """:obj:`PyRevitOutputChart`: Return line chart object."""
        return charts.PyRevitOutputChart(self, chart_type=charts.LINE_CHART)

    def make_stacked_chart(self):
        """:obj:`PyRevitOutputChart`: Return stacked chart object."""
        chart = charts.PyRevitOutputChart(self, chart_type=charts.LINE_CHART)
        chart.options.scales = {'yAxes': [{'stacked': True, }]}
        return chart

    def make_bar_chart(self):
        """:obj:`PyRevitOutputChart`: Return bar chart object."""
        return charts.PyRevitOutputChart(self, chart_type=charts.BAR_CHART)

    def make_radar_chart(self):
        """:obj:`PyRevitOutputChart`: Return radar chart object."""
        return charts.PyRevitOutputChart(self, chart_type=charts.RADAR_CHART)

    def make_polar_chart(self):
        """:obj:`PyRevitOutputChart`: Return polar chart object."""
        return charts.PyRevitOutputChart(self, chart_type=charts.POLAR_CHART)

    def make_pie_chart(self):
        """:obj:`PyRevitOutputChart`: Return pie chart object."""
        return charts.PyRevitOutputChart(self, chart_type=charts.PIE_CHART)

    def make_doughnut_chart(self):
        """:obj:`PyRevitOutputChart`: Return dougnut chart object."""
        return charts.PyRevitOutputChart(self,
                                         chart_type=charts.DOUGHNUT_CHART)

    def make_bubble_chart(self):
        """:obj:`PyRevitOutputChart`: Return bubble chart object."""
        return charts.PyRevitOutputChart(self, chart_type=charts.BUBBLE_CHART)


def get_output():
    """:obj:`pyrevit.output.PyRevitOutputWindow` : Return output window."""
    return PyRevitOutputWindow()