Module apparent.reports

Reporting functionality for collected results

Expand source code
#  Copyright (c) Arnon Moscona 2023. under Apache2 license

"""Reporting functionality for collected results"""
from typing import Iterable, List, Optional

from apparent.timing import TimerRegistry, TimerRegistryType, Units

ALL_TIMER_FIELDS = ('timer_name', 'mean', 'count', 'max', 'min', 'stdevp')
DEFAULT_TIMER_FIELDS = ('timer_name', 'mean', 'count', 'max')
DEFAULT_TIMER_SORT_FIELD = 'mean'


def timer_summary_table(fields: Iterable[str] = DEFAULT_TIMER_FIELDS,
                        sort_field: str = DEFAULT_TIMER_SORT_FIELD,
                        units: Units = Units.MSEC,
                        digits: int = 3,
                        registry: Optional[TimerRegistryType] = None) -> List[List[str]]:
    """
    Produces a CSV-like table of timer results. Highly recommended to use tabulate for presentation.
    Args:
        fields: the fields of TimerResults to include
        sort_field: the field to sort the results by. Time and count fields are sorted descending.
        units: The unites to use on all results. Default is Units.MSEC
        digits: The number of digits to round results to (the report is for human consumption)
        registry: the timer regitry to use. Rarely used parameter.

    Returns:
        A CSV-like report: list of lists, all strings. You can get it nicely formatted with the tabulate package.
        Example `print(tabulate(report, headers='firstrow', tablefmt='rounded_outline'))`
    """
    registry = registry or TimerRegistry
    fields = fields or DEFAULT_TIMER_FIELDS

    # validate inputs
    bad_fields = [f for f in fields if f not in ALL_TIMER_FIELDS]
    if bad_fields:
        raise ValueError(f'invalid field(s) {bad_fields}')
    if sort_field not in ALL_TIMER_FIELDS:
        raise ValueError(f'invalid sort field {sort_field}')
    if digits < 0:
        digits = 0

    # collect all results
    results = [timer.results().convert(units) for timer in registry.timers()]

    # sort (sort order depends on field)
    reverse = sort_field in {'mean', 'min', 'max', 'count'}
    results.sort(key=lambda r: getattr(r, sort_field), reverse=reverse)
    results = [r.round(digits) for r in results]

    return [list(fields)] + [[str(getattr(r, f)) for f in fields] for r in results]

Functions

def timer_summary_table(fields: Iterable[str] = ('timer_name', 'mean', 'count', 'max'), sort_field: str = 'mean', units: Units = Units.MSEC, digits: int = 3, registry: Optional[~TimerRegistryType] = None) ‑> List[List[str]]

Produces a CSV-like table of timer results. Highly recommended to use tabulate for presentation.

Args

fields
the fields of TimerResults to include
sort_field
the field to sort the results by. Time and count fields are sorted descending.
units
The unites to use on all results. Default is Units.MSEC
digits
The number of digits to round results to (the report is for human consumption)
registry
the timer regitry to use. Rarely used parameter.

Returns

A CSV-like report: list of lists, all strings. You can get it nicely formatted with the tabulate package. Example print(tabulate(report, headers='firstrow', tablefmt='rounded_outline'))

Expand source code
def timer_summary_table(fields: Iterable[str] = DEFAULT_TIMER_FIELDS,
                        sort_field: str = DEFAULT_TIMER_SORT_FIELD,
                        units: Units = Units.MSEC,
                        digits: int = 3,
                        registry: Optional[TimerRegistryType] = None) -> List[List[str]]:
    """
    Produces a CSV-like table of timer results. Highly recommended to use tabulate for presentation.
    Args:
        fields: the fields of TimerResults to include
        sort_field: the field to sort the results by. Time and count fields are sorted descending.
        units: The unites to use on all results. Default is Units.MSEC
        digits: The number of digits to round results to (the report is for human consumption)
        registry: the timer regitry to use. Rarely used parameter.

    Returns:
        A CSV-like report: list of lists, all strings. You can get it nicely formatted with the tabulate package.
        Example `print(tabulate(report, headers='firstrow', tablefmt='rounded_outline'))`
    """
    registry = registry or TimerRegistry
    fields = fields or DEFAULT_TIMER_FIELDS

    # validate inputs
    bad_fields = [f for f in fields if f not in ALL_TIMER_FIELDS]
    if bad_fields:
        raise ValueError(f'invalid field(s) {bad_fields}')
    if sort_field not in ALL_TIMER_FIELDS:
        raise ValueError(f'invalid sort field {sort_field}')
    if digits < 0:
        digits = 0

    # collect all results
    results = [timer.results().convert(units) for timer in registry.timers()]

    # sort (sort order depends on field)
    reverse = sort_field in {'mean', 'min', 'max', 'count'}
    results.sort(key=lambda r: getattr(r, sort_field), reverse=reverse)
    results = [r.round(digits) for r in results]

    return [list(fields)] + [[str(getattr(r, f)) for f in fields] for r in results]