Embedding Guide

Using embed()

pw console is invoked by calling PwConsoleEmbed().embed() in your own Python script.

pw_console embed class.

class pw_console.embed.PwConsoleEmbed(global_vars=None, local_vars=None, loggers: Optional[Union[Dict[str, Iterable[logging.Logger]], Iterable]] = None, test_mode=False, repl_startup_message: Optional[str] = None, help_text: Optional[str] = None, app_title: Optional[str] = None, config_file_path: Optional[Union[str, pathlib.Path]] = None)

Bases: object

Embed class for customizing the console before startup.

__init__(global_vars=None, local_vars=None, loggers: Optional[Union[Dict[str, Iterable[logging.Logger]], Iterable]] = None, test_mode=False, repl_startup_message: Optional[str] = None, help_text: Optional[str] = None, app_title: Optional[str] = None, config_file_path: Optional[Union[str, pathlib.Path]] = None) None

Call this to embed pw console at the call point within your program.

Example usage:

import logging

from pw_console import PwConsoleEmbed

# Create the pw_console embed instance
console = PwConsoleEmbed(
    global_vars=globals(),
    local_vars=locals(),
    loggers={
        'Host Logs': [
            logging.getLogger(__package__),
            logging.getLogger(__file__)
        ],
        'Device Logs': [
            logging.getLogger('usb_gadget')
        ],
    },
    app_title='My Awesome Console',
    config_file_path='/home/user/project/.pw_console.yaml',
)
# Optional: Add custom completions
console.add_sentence_completer(
    {
        'some_function', 'Function',
        'some_variable', 'Variable',
    }
)

# Setup Python loggers to output to a file instead of STDOUT.
console.setup_python_logging()

# Then run the console with:
console.embed()
Parameters
  • global_vars – Dictionary representing the desired global symbol table. Similar to what is returned by globals().

  • local_vars – Dictionary representing the desired local symbol table. Similar to what is returned by locals().

  • loggers – Dict with keys of log window titles and values of logging.getLogger() instances in lists. Each key that should be shown in the pw console user interface.

  • app_title – Custom title text displayed in the user interface.

  • repl_startup_message – Custom text shown by default in the repl output pane.

  • help_text – Custom text shown at the top of the help window before keyboard shortcuts.

  • config_file_path – Path to a pw_console yaml config file.

add_bottom_toolbar(toolbar: pw_console.widgets.window_pane_toolbar.WindowPaneToolbar) None

Include a toolbar plugin to display at the bottom of the screen.

Bottom toolbars appear below all window panes and span the full width of the screen.

Parameters

toolbar – Instance of the WindowPaneToolbar class.

add_sentence_completer(word_meta_dict: Dict[str, str], ignore_case=True)

Include a custom completer that matches on the entire repl input.

Parameters

word_meta_dict – Dictionary representing the sentence completions and descriptions. Keys are completion text, values are descriptions.

add_top_toolbar(toolbar: pw_console.widgets.window_pane_toolbar.WindowPaneToolbar) None

Include a toolbar plugin to display on the top of the screen.

Top toolbars appear above all window panes and just below the main menu bar. They span the full width of the screen.

Parameters

toolbar – Instance of the WindowPaneToolbar class.

add_window_plugin(window_pane: pw_console.widgets.window_pane.WindowPane) None

Include a custom window pane plugin.

Parameters

window_pane – Any instance of the WindowPane class.

embed()

Start the console.

hide_windows(*window_titles)

Hide window panes specified by title on console startup.

setup_python_logging(last_resort_filename: Optional[str] = None)

Disable log handlers for full screen prompt_toolkit applications.

Parameters

last_resort_filename – If specified use this file as a fallback for unhandled python logging messages. Normally Python will output any log messages with no handlers to STDERR as a fallback. If none, a temp file will be created instead.

Adding Plugins

User plugin instances are created before starting-up and passed to the Pigweed Console embed instance. Typically, a console is started by creating a PwConsoleEmbed() instance, calling customization functions, then calling .embed() as shown in Using embed(). Adding plugins functions similarly by calling add_top_toolbar, add_bottom_toolbar or add_window_plugin. For example:

# Create plugin instances
user_toolbar1 = DeviceStatusToolbar(device=client.client.channel(1))
user_toolbar2 = BandwithToolbar()
user_device_window = CustomWindowPlugin()

console = PwConsoleEmbed(
    global_vars=local_variables,
    loggers={
        'Device Logs': [logging.getLogger('rpc_device')],
        'Host Logs': [logging.getLogger()],
    },
    ...
)

# Add toolbar plugins
console.add_top_toolbar(user_toolbar1)
console.add_bottom_toolbar(user_toolbar2)

# Add Window plugins
console.add_window_plugin(user_device_window)

# Start the console
console.embed()

Adding Log Metadata

pw_console can display log messages in a table with justified columns for metadata fields provided by pw_log_tokenized.

It is also possible to manually add values that should be displayed in columns using the extra keyword argument when logging from Python. See the Python’s logging documentation for how extra works. A dict of name, value pairs can be passed in as the extra_metadata_fields variable. For example, the following code will create a log message with two custom columns titled module and timestamp.

import logging

LOG = logging.getLogger('log_source_1')

LOG.info(
    'Hello there!',
    extra={
        'extra_metadata_fields': {
            'module': 'cool',
            'timestamp': 1.2345,
        }
    }
)

Debugging Serial Data

pw_console is often used to communicate with devices using pySerial and it may be necessary to monitor the raw data flowing over the wire to help with debugging. pw_console provides a simple wrapper for a pySerial instances that log data for each read and write call.

# Instead of 'import serial' use this import:
from pw_console.pyserial_wrapper import SerialWithLogging

serial_device = SerialWithLogging('/dev/ttyUSB0', 115200, timeout=1)

With the above example each serial_device.read and write call will create a log message to the pw_console.serial_debug_logger Python logger. This logger can then be included as a log window pane in the PwConsoleEmbed() call.

import logging
from pw_console import PwConsoleEmbed

console = PwConsoleEmbed(
    global_vars=globals(),
    local_vars=locals(),
    loggers={
        'Host Logs': [
            # Root Python logger
            logging.getLogger(''),
            # Your current Python package logger.
            logging.getLogger(__package__)
        ],
        'Device Logs': [
            logging.getLogger('usb_gadget')
        ],
        'Serial Debug': [
            # New log window to display serial read and writes
            logging.getLogger('pw_console.serial_debug_logger')
        ],
    },
    app_title='CoolConsole',
)
# Then run the console with:
console.embed()
Serial debug pw_console screenshot.

Screenshot of issuing an Echo RPC with serial debug logging.