Пример #1
0
def test_empty_kvitable_with_labels_render_text():
    kvit = KVITable({'foo':[], 'dog':[]})
    show = kvit.render(as_format='ascii')
    assert '\n'.join([
        '| foo | dog | Value |',
        '+-----+-----+-------+',
    ]) == show
Пример #2
0
def test_pretty_table_printer():
    # Functional equivalence to
    # https://pypi.org/project/pretty-table-printer
    # https://github.com/cfmeyers/pretty_table_printer
    # (tests/test_pretty_table_printer.py
    # test_it_knows_how_to_print_itself)
    #
    # delta:
    #  * KVITable doesn't have explicit field widths/truncation (implicit in pretty_table_printer?)
    #  * KVITable default alignment is right instead of left
    #  * KVITable doesn't show a bottom border
    kvit = KVITable(valuecol_name='name')
    kvit.add('Sam', id=1)
    kvit.add('Layla', id=2)
    kvit.add('Jack Gabriel', id=3)
    rows = kvit.get_rows()
    assert [ [ 1, 'Sam' ],
             [ 2, 'Layla' ],
             [ 3, 'Jack Gabriel' ],
    ] == rows
    show = kvit.render()
    assert '\n'.join([
        '| id |         name |',
        '+----+--------------+',
        '|  1 |          Sam |',
        '|  2 |        Layla |',
        '|  3 | Jack Gabriel |',
    ]) == show
Пример #3
0
def test_empty_kvitable_get():
    kvit = KVITable()
    with pytest.raises(IndexError) as idxerr:
        foo = kvit.get(('foo', 'bar'), moo="cow")
    assert 'foo' in str(idxerr.value)
    assert 'bar' in str(idxerr.value)
    assert 'moo' in str(idxerr.value)
    assert 'cow' in str(idxerr.value)
Пример #4
0
def test_empty_kvitable_render_text():
    kvit = KVITable()
    show = kvit.render(as_format='ascii')
    assert '\n'.join([
        '| Value |',
        '+-------+',
        '|       |',
    ]) == show
Пример #5
0
def test_kvitable_initial_kv_dict():
    kvit = KVITable({'moo':['cow'], 'foo':['bar', 'baz']})
    kvit.add("hi", ('moo', "cow"), foo='bar')
    kvit.add("howdy", ('moo', "cow"), foo='baz')
    hello = kvit.get(('foo', 'bar'), moo="cow")
    assert hello == "hi"
    hello2 = kvit.get(moo="cow", foo='baz')
    assert hello2 == "howdy"
Пример #6
0
def test_non_leaf_kvitable_add_uses_default_key_val():
    kvit = KVITable()
    kvit.add("hi", ('moo', "cow"), foo='bar')
    kvit.add("oops", ('moo', "dog"))
    rows = kvit.get_rows()
    assert [
        ['cow', 'bar', 'hi'],
        ['dog', '', 'oops'],
    ] == rows
Пример #7
0
def test_zoo_no_subtype_colstack_render(zoo_table):
    kv = zoo_table.keyvals()
    subtype_idx = list(kv.keys()).index('Subtype')
    del kv['Subtype']
    zt2 = KVITable(kv,
                   valuecol_name='Count',
                   default_factory=int,
                   kv_frozen=False)
    for row in zoo_table.get_rows():
        del row[subtype_idx]
        zt2.add(lambda v: v + row[-1], *tuple(zip(kv, row[:-1])))
    show = zt2.render(row_repeat=False,
                      sort_vals=True,
                      row_group=['Location', 'Biome', 'Category'],
                      colstack_at='Name')
    assert '\n'.join([
        '|  Location |    Biome | Category |      Diet | Bear | Giraffe | Hippo | Lion | Penguin | Rhino | <- Name',
        '+-----------+----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|        LA |   Jungle |   Animal | Herbivore |      |         |     1 |      |         |       |',
        '|           +----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|           | Savannah |   Animal | Carnivore |      |         |       |    4 |         |       |',
        '|           |          |          | Herbivore |      |       2 |       |      |         |     3 |',
        '+-----------+----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|     Miami |    Polar |     Bird | Carnivore |      |         |       |      |      20 |       |',
        '|           +----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|           | Savannah |   Animal | Carnivore |      |         |       |    2 |         |       |',
        '|           |          |          | Herbivore |      |       3 |       |      |         |       |',
        '+-----------+----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|  New York | Savannah |   Animal | Carnivore |      |         |       |    3 |         |       |',
        '+-----------+----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '| San Diego |   Jungle |   Animal |  Omnivore |    1 |         |       |      |         |       |',
        '|           +----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|           |   Plains |   Animal |  Omnivore |    2 |         |       |      |         |       |',
        '|           +----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|           |    Polar |   Animal |  Omnivore |    1 |         |       |      |         |       |',
        '|           |          +----------+-----------+------+---------+-------+------+---------+-------+',
        '|           |          |     Bird | Carnivore |      |         |       |      |      10 |       |',
        '|           +----------+----------+-----------+------+---------+-------+------+---------+-------+',
        '|           | Savannah |   Animal | Carnivore |      |         |       |    9 |         |       |',
        '+-----------+----------+----------+-----------+------+---------+-------+------+---------+-------+',
    ]) == show
Пример #8
0
def test_non_frozen_kvitable_add_key():
    kvit = KVITable({'foo':['bar','baz']}, kv_frozen=False)
    kvit.add("hi", foo='bar')
    kvit.add("yo", foo='baz', dog='woof')
    rows = kvit.get_rows()
    assert [
        [ 'bar', '', 'hi' ],
        [ 'baz', 'woof', 'yo'],
    ] == rows
    show = kvit.render()
    assert '\n'.join([
        '| foo |  dog | Value |',
        '+-----+------+-------+',
        '| bar |      |    hi |',
        '| baz | woof |    yo |',
    ]) == show
Пример #9
0
def test_non_frozen_kvitable_add_deep_key():
    kvit = KVITable({'foo':['bar','baz'],
                     'moon':['beam', 'pie'],
    },
                    kv_frozen=False,
                    valuecol_name='says',
                    keyval_factory=lambda key: '?')
    kvit.add("hi", foo='bar', moon='pie')
    kvit.add("yo", foo='baz', moon='beam', dog='woof')
    kvit.add("Excellent!", foo='Bill', moon='Ted', dog='arf arf')
    rows = kvit.get_rows()
    assert [
        [ 'Bill', 'Ted', 'arf arf', 'Excellent!'],
        [ 'bar', 'pie', '?', 'hi' ],
        [ 'baz', 'beam', 'woof', 'yo'],
    ] == rows
    show = kvit.render(sort_vals=True)
    assert '\n'.join([
        '|  foo | moon |     dog |       says |',
        '+------+------+---------+------------+',
        '| Bill |  Ted | arf arf | Excellent! |',
        '|  bar |  pie |       ? |         hi |',
        '|  baz | beam |    woof |         yo |',
    ]) == show
Пример #10
0
def test_table_printer():
    # Functional equivalence to https://pypi.org/project/table_printer
    # delta:
    #  * KVITable does not support left/right/center alignment
    #  * KVITable does not support explicit field widths
    kvit = KVITable(valuecol_name='Description')
    kvit.add('World', Title='Hello')
    kvit.add('1 title', Title='TOTAL')
    show = kvit.render(row_group=['Title'])
    assert '\n'.join([
        '| Title | Description |',
        '+-------+-------------+',
        '| Hello |       World |',
        '+-------+-------------+',
        '| TOTAL |     1 title |',
        '+-------+-------------+',
    ]) == show
Пример #11
0
def build_kvitable():
    kvit = KVITable({'system': [ 'x86_64-linux', 'x86_64-darwin' ],
                     'Branch': ['master', 'develop', 'PR-feature'],
                     'Strategy': ['submodules', 'HEADs'],
                     'ghcver': ['ghc844', 'ghc865', 'ghc882'],
                     },
                    kv_frozen=True)
    kvit.add('+', system='x86_64-linux', Strategy='submodules', ghcver='ghc844', Branch='PR-feature')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='HEADs', ghcver='ghc865', Branch='PR-feature')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='submodules', ghcver='ghc882', Branch='develop')
    kvit.add('+', system='x86_64-linux', Strategy='HEADs', ghcver='ghc865', Branch='develop')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='submodules', ghcver='ghc844', Branch='master')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='HEADs', ghcver='ghc844', Branch='master')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='HEADs', ghcver='ghc865', Branch='master')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='HEADs', ghcver='ghc882', Branch='master')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='submodules', ghcver='ghc865', Branch='master')
    kvit.add('+', system='x86_64-linux', Strategy='HEADs', ghcver='ghc844', Branch='develop')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='HEADs', ghcver='ghc882', Branch='PR-feature')
    kvit.add('FAIL*1', system='x86_64-linux', Strategy='submodules', ghcver='ghc882', Branch='PR-feature')
    kvit.add('+', system='x86_64-linux', Strategy='submodules', ghcver='ghc865', Branch='PR-feature')
    kvit.add('+', system='x86_64-linux', Strategy='submodules', ghcver='ghc844', Branch='develop')
    kvit.add('+', system='x86_64-linux', Strategy='HEADs', ghcver='ghc844', Branch='develop')
    kvit.add('+', system='x86_64-darwin', Strategy='HEADs', ghcver='ghc844', Branch='develop')
    return kvit
Пример #12
0
def test_kvitable_cannot_extend_leaf():
    kvit = KVITable()
    kvit.add("hi", ('moo', "cow"), foo='bar')
    with pytest.raises(IndexError) as idxerr:
        kvit.add("woof", ('moo', "cow"), foo='bar', dog='bark')
    assert 'overwrite leaf' in str(idxerr.value)
Пример #13
0
def test_frozen_kvitable_add_key_key_refused():
    kvit = KVITable({'foo':['bar','baz']}, kv_frozen=True)
    kvit.add("hi", foo='bar')
    with pytest.raises(IndexError) as idxerr:
        kvit.add("oops", ('dog', "bark"), foo='baz')
    assert 'kv_frozen' in str(idxerr.value)
Пример #14
0
def test_kvitable_initial_kv_list():
    kvit = KVITable(['moo', 'foo'])
    kvit.add("hi", ('moo', "cow"), foo='bar')
    hello = kvit.get(('foo', 'bar'), moo="cow")
    assert hello == "hi"
Пример #15
0
def zoo_table():
    kvit = KVITable({'Location': ['San Diego', 'LA', 'Miami', 'New York'],
                     'Biome': ['Savannah', 'Jungle', 'Polar'],
                     'Category': ['Animal', 'Reptile', 'Bird'],
                     'Diet': ['Herbivore', 'Carnivore'],
                     'Name': [],
                     },
                    valuecol_name='Count',
                    default_factory=int,
                    kv_frozen=False)
    inc = lambda v: v+1
    kvit.add(3, ('Diet', 'Carnivore'), ('Category', "Animal"), ('Biome', "Savannah"), Name='Lion', Location='New York')
    kvit.add(2, ('Diet', 'Carnivore'), ('Category', "Animal"), ('Biome', "Savannah"), Name='Lion', Location='Miami')
    kvit.add(4, ('Diet', 'Carnivore'), ('Category', "Animal"), ('Biome', "Savannah"), Name='Lion', Location='LA')
    kvit.add(8, ('Diet', 'Carnivore'), ('Category', "Animal"), ('Biome', "Savannah"), Name='Lion', Location='San Diego')
    kvit.add(2, Location='LA', Biome='Savannah', Category='Animal', Name='Giraffe', Diet='Herbivore')
    kvit.add(1, Location='LA', Biome='Jungle', Category='Animal', Name='Hippo', Diet='Herbivore')
    kvit.add(3, Location='LA', Biome='Savannah', Category='Animal', Diet='Herbivore', Name='Rhino')
    kvit.add(20, Location='Miami', Biome='Polar', Category='Bird', Diet='Carnivore', Subtype='Gentoo', Name='Penguin')
    kvit.add(8, Location='San Diego', Biome='Polar', Category='Bird', Diet='Carnivore', Subtype='Emperor', Name='Penguin')
    kvit.add(2, Location='San Diego', Biome='Polar', Category='Bird', Diet='Carnivore', Subtype='Gentoo', Name='Penguin')
    kvit.add(3, Location='Miami', Biome='Savannah', Category='Animal', Diet='Herbivore', Name='Giraffe', Subtype='Reticulated')
    kvit.add(inc, Category='Animal', Diet='Carnivore', Biome="Savannah", Location='San Diego', Name='Lion')
    kvit.add(inc, Location='San Diego', Biome='Polar', Category='Animal', Subtype='Polar', Name='Bear', Diet='Omnivore')
    kvit.add(inc, Location='San Diego', Biome='Jungle', Category='Animal', Subtype='Sun', Name='Bear', Diet='Omnivore')
    kvit.add(inc, Location='San Diego', Biome='Plains', Category='Animal', Subtype='Brown', Name='Bear', Diet='Omnivore')
    kvit.add(inc, Location='San Diego', Biome='Plains', Category='Animal', Subtype='Black', Name='Bear', Diet='Omnivore')
    return kvit
Пример #16
0
def test_ptable():
    # Functional equivalence to https://pypi.org/project/PTable
    #
    # delta:
    #  * KVITable default alignment is right instead of left
    kvit = KVITable(valuecol_name='Annual Rainfall')
    kvit.add(600.5, ('City name', 'Adelaide'), Area=1295, Population=1158259)
    kvit.add(1146.4, ('City name', 'Brisbane'), Area=5905, Population=1857594)
    kvit.add(1714.7, ('City name', 'Darwin'), Area=112, Population=120900)
    kvit.add(619.5, ('City name', 'Hobart'), Area=1357, Population=205556)
    kvit.add(646.9, ('City name', 'Melbourne'), Area=1566, Population=3806092)
    kvit.add(869.4, ('City name', 'Perth'), Area=5386, Population=1554769)
    kvit.add(1214.8, ('City name', 'Sydney'), Area=2058, Population=4336374)
    show = kvit.render()
    print(show)
    assert '\n'.join([
        '| City name | Area | Population | Annual Rainfall |',
        '+-----------+------+------------+-----------------+',
        '|  Adelaide | 1295 |    1158259 |           600.5 |',
        '|  Brisbane | 5905 |    1857594 |          1146.4 |',
        '|    Darwin |  112 |     120900 |          1714.7 |',
        '|    Hobart | 1357 |     205556 |           619.5 |',
        '| Melbourne | 1566 |    3806092 |           646.9 |',
        '|     Perth | 5386 |    1554769 |           869.4 |',
        '|    Sydney | 2058 |    4336374 |          1214.8 |',
    ]) == show
Пример #17
0
def test_frozen_kvitable_initial_kv_list_refuses_new_values():
    kvit = KVITable(['moo', 'foo'], kv_frozen=True)
    with pytest.raises(IndexError) as idxerr:
        kvit.add("hi", ('moo', "cow"), foo='bar')
    assert 'frozen' in str(idxerr.value)
Пример #18
0
def medium_kvitable():
    kvit = KVITable({'compiler': [ 'gcc7', 'gcc8', 'clang6', 'clang7' ],
                     'debug': ['yes', 'no'],
                     'optimization': [0, 1, 3],
                     },
                    kv_frozen=True)
    kvit.add('good', compiler='gcc7', debug='yes', optimization=0)
    kvit.add('bad', compiler='gcc7', debug='no', optimization=0)
    kvit.add('ugly', compiler='gcc7', debug='yes', optimization=3)
    kvit.add('good', compiler='gcc8', debug='yes', optimization=0)
    kvit.add('ok', compiler='clang6', debug='yes', optimization=0)
    kvit.add('good', compiler='clang7', debug='no', optimization=1)
    kvit.add('good', compiler='clang7', debug='no', optimization=3)
    kvit.add('good', compiler='clang7', debug='yes', optimization=3)
    kvit.add(True, compiler='gcc8', debug='yes', optimization=3)
    kvit.add('bad', compiler='gcc8', debug='yes', optimization=1)
    kvit.add('good', compiler='clang7', debug='no', optimization=0)
    kvit.add('good', compiler='gcc7', debug='no', optimization=1)
    return kvit
Пример #19
0
def test_empty_frozen_kvitable_add_refused():
    kvit = KVITable(kv_frozen=True)
    with pytest.raises(IndexError) as idxerr:
        kvit.add("hi", ('moo', "cow"), foo='bar')
    assert "frozen" in str(idxerr.value)
Пример #20
0
def html_summary(repdata, base_builder_url=None):
    section_hdrfun = lambda msg: '<br/><hr class="section_line"/><br/><h2>' + msg + '</h2><br/>'
    subsection_hdrfun = lambda msg: '<br/><h3>' + msg + '</h3>'
    entshow_fun = tcell_entshow(base_builder_url)

    projects = set(
        [sr.project for sr in repdata if isinstance(sr, StatusReport)])

    summary = KVITable(default_factory=int, valuecol_name='Total')
    summary.add(len(projects), Element='Projects')
    summary.add(len(
        set([
            sr.branch for sr in repdata
            if isinstance(sr, StatusReport) and sr.branchtype == 'pullreq'
        ])),
                Element='Pull Requests')

    projtable = KVITable(
        {
            'Project':
            sorted(
                list(
                    set([
                        sr.project
                        for sr in repdata if isinstance(sr, StatusReport)
                    ]))),
            'Status': ['TOTAL', 'ok', 'FAIL', 'pending'],
        },
        valuecol_name='Number',
        kv_frozen=False,
        default_factory=int)

    fulltable = KVITable(
        {
            'Branch': [],
            'system': ['x86-64_linux'],
            'Strategy': ['regular', 'submodules', 'HEADs'],
            'Project': [],
        },
        valuecol_name='Build Status',
        default_factory=lambda: None,
        keyval_factory=lambda key: 'x86_64-linux'
        if key == 'system' else 'n/a',
        kv_frozen=False)

    mkDetailTable = lambda: KVITable(
        {
            'system': ['x86-64_linux'],
            'Branch': [],
            'Strategy': ['regular', 'submodules', 'HEADs'],
        },
        valuecol_name='Build Status',
        default_factory=lambda: None,
        keyval_factory=lambda key: 'x86_64-linux' if key == 'system' else '',
        kv_frozen=False)
    detailtables = defaultdict(mkDetailTable)
    projtable_sts = lambda s: {
        'initial_success': 'ok',
        'succeeded': 'ok',
        # 'pending': 'pending',
    }.get(s, 'FAIL')

    for sr in repdata:

        if isinstance(sr, Notify):
            summary.add(_inc, Element='Notifications')

        elif isinstance(sr, PendingStatus):
            prev = [
                r for r in repdata if isinstance(r, StatusReport)
                and r.project == sr.project and r.buildname == sr.buildname
            ]
            if not prev:
                summary.add(_inc, Element='Builds')
                projtable.add(_inc, Project=sr.project, Status="TOTAL")
            else:
                projtable.add(_dec,
                              Project=sr.project,
                              Status=projtable_sts(prev[0].status))
            projtable.add(_inc, Project=sr.project, Status="pending")
            vars = tuple([(v.varname, v.varvalue) for v in sr.bldvars])

            fulltable.add(TCell_PendingBld(sr.project, sr.buildname),
                          *vars,
                          Project=sr.project,
                          Branch=tbl_branch(sr),
                          Strategy=sr.strategy)
            detailtables[sr.project].add(TCell_PendingBld(
                sr.project, sr.buildname),
                                         *vars,
                                         Branch=tbl_branch(sr),
                                         Strategy=sr.strategy)

        elif isinstance(sr, NewPending):
            summary.add(_inc, Element='Builds')
            projectname = sr.bldcfg.projectname
            buildname = buildcfg_name(sr.bldcfg)
            tbl_brname = tbl_branch_(buildname, sr.bldcfg.branchname)
            projtable.add(_inc, Project=projectname, Status="TOTAL")
            projtable.add(_inc, Project=projectname, Status="pending")
            vars = tuple([(v.varname, v.varvalue) for v in sr.bldcfg.bldvars])

            fulltable.add(TCell_PendingBld(projectname, buildname),
                          *vars,
                          Project=projectname,
                          Branch=tbl_brname,
                          Strategy=sr.bldcfg.strategy)
            detailtables[sr.bldcfg.projectname].add(
                TCell_PendingBld(projectname, buildname),
                *vars,
                Branch=tbl_brname,
                Strategy=sr.bldcfg.strategy)

        elif isinstance(sr, StatusReport):
            summary.add(_inc, Element='Builds')

            projtable.add(_inc,
                          Project=sr.project,
                          Status=projtable_sts(sr.status))
            projtable.add(_inc, Project=sr.project, Status='TOTAL')

            bldres = {
                'initial_success': TCell_GoodBld,
                'succeeded': TCell_GoodBld,
                'fixed': TCell_GoodBld,
                'bad_config': TCell_BadCfgBld,
            }.get(sr.status,
                  lambda proj, name: TCell_FailBld(proj, name, sr.status))(
                      sr.project, sr.buildname)

            fulltable.add(bldres,
                          *tuple([(v.varname, v.varvalue)
                                  for v in sr.bldvars]),
                          Project=sr.project,
                          Branch=tbl_branch(sr),
                          Strategy=sr.strategy)

            detailtables[sr.project].add(bldres,
                                         *tuple([(v.varname, v.varvalue)
                                                 for v in sr.bldvars]),
                                         Branch=tbl_branch(sr),
                                         Strategy=sr.strategy)

    return '\n\n'.join([
        summary.render(as_format='html', sort_vals=True),
        section_hdrfun('Per-project Build Status Summary ::'),
        projtable.render(row_group=['Project'],
                         row_repeat=False,
                         sort_vals=False,
                         as_format='html',
                         caption='Per-project Build Status Summary',
                         colstack_at='Status'),
        section_hdrfun('Combined Details ::'),
        fulltable.render(
            row_group=['system', 'Branch', 'Strategy'],
            row_repeat=False,
            sort_vals=True,
            entrystr=entshow_fun,
            as_format='html',
            caption='Combined Details',
            colstack_at=(list(fulltable.keyvals().keys()) + [None])[4],
        ),
        section_hdrfun('Individual Project Summaries ::'), '\n\n'.join([
            subsection_hdrfun('Project %s:\n' % p) + detailtables[p].render(
                row_repeat=False,
                as_format='html',
                caption='Project %s' % p,
                sort_vals=True,
                colstack_at=(list(detailtables[p].keyvals().keys()) +
                             [None])[3],
                row_group=['system', 'Branch'],
                entrystr=entshow_fun,
            ) for p in sorted(projects)
        ])
    ])
Пример #21
0
def test_empty_kvitable_add():
    kvit = KVITable()
    kvit.add("hi", ('moo', "cow"), foo='bar')
    hello = kvit.get(('foo', 'bar'), moo="cow")
    assert hello == "hi"
Пример #22
0
def test_empty_kvitable_render_html():
    kvit = KVITable()
    show = kvit.render(as_format='html')
    assert 'Value' in show
Пример #23
0
def test_empty_kvitable_create():
    kvit = KVITable()
Пример #24
0
def test_empty_kvitable_with_labels_render_html():
    kvit = KVITable({'foo':[], 'dog':[]})
    show = kvit.render(as_format='html')
    assert 'Value' in show
Пример #25
0
def text_summary(repdata):
    sepline = '=' * 60
    hashline = '#' * 60
    banner = '\n\n%(sepline)s\n%(hashline)s\n%(sepline)s\n\n' % locals()
    section_hdrfun = lambda msg: banner + msg
    subsection_hdrfun = lambda msg: msg + '\n'
    entshow_fun = _show_with_fail

    projects = set(
        [sr.project for sr in repdata if isinstance(sr, StatusReport)])

    summary = KVITable(default_factory=int, valuecol_name='Total')
    summary.add(len(projects), Element='Projects')
    summary.add(len(
        set([
            sr.branch for sr in repdata
            if isinstance(sr, StatusReport) and sr.branchtype == 'pullreq'
        ])),
                Element='Pull Requests')

    projtable = KVITable(
        {
            'Project':
            sorted(
                list(
                    set([
                        sr.project
                        for sr in repdata if isinstance(sr, StatusReport)
                    ]))),
            'Status': ['TOTAL', 'ok', 'FAIL', 'pending'],
        },
        valuecol_name='Number',
        kv_frozen=False,
        default_factory=int)

    fulltable = KVITable(
        {
            'Branch': [],
            'system': ['x86-64_linux'],
            'Strategy': ['regular', 'submodules', 'HEADs'],
            'Project': [],
        },
        valuecol_name='Build Status',
        default_factory=FailCount,
        keyval_factory=lambda key: 'x86_64-linux'
        if key == 'system' else 'n/a',
        kv_frozen=False)

    mkDetailTable = lambda: KVITable(
        {
            'system': ['x86-64_linux'],
            'Branch': [],
            'Strategy': ['regular', 'submodules', 'HEADs'],
        },
        valuecol_name='Build Status',
        default_factory=FailCount,
        keyval_factory=lambda key: 'x86_64-linux' if key == 'system' else '',
        kv_frozen=False)
    detailtables = defaultdict(mkDetailTable)
    projtable_sts = lambda s: {
        'initial_success': 'ok',
        'succeeded': 'ok',
        # 'pending': 'pending',
    }.get(s, 'FAIL')

    for sr in repdata:

        if isinstance(sr, Notify):
            summary.add(_inc, Element='Notifications')

        elif isinstance(sr, PendingStatus):
            prev = [
                r for r in repdata if isinstance(r, StatusReport)
                and r.project == sr.project and r.buildname == sr.buildname
            ]
            if not prev:
                summary.add(_inc, Element='Builds')
                projtable.add(_inc, Project=sr.project, Status="TOTAL")
            else:
                projtable.add(_dec,
                              Project=sr.project,
                              Status=projtable_sts(prev[0].status))
            projtable.add(_inc, Project=sr.project, Status="pending")
            vars = tuple([(v.varname, v.varvalue) for v in sr.bldvars])

            fulltable.add(PendingBld,
                          *vars,
                          Project=sr.project,
                          Branch=tbl_branch(sr),
                          Strategy=sr.strategy)
            detailtables[sr.project].add(PendingBld,
                                         *vars,
                                         Branch=tbl_branch(sr),
                                         Strategy=sr.strategy)

        elif isinstance(sr, NewPending):
            summary.add(_inc, Element='Builds')
            projtable.add(_inc, Project=sr.bldcfg.projectname, Status="TOTAL")
            projtable.add(_inc,
                          Project=sr.bldcfg.projectname,
                          Status="pending")
            vars = tuple([(v.varname, v.varvalue) for v in sr.bldcfg.bldvars])
            buildname = buildcfg_name(sr.bldcfg)
            tbl_brname = tbl_branch_(buildname, sr.bldcfg.branchname)

            fulltable.add(PendingBld,
                          *vars,
                          Project=sr.bldcfg.projectname,
                          Branch=tbl_brname,
                          Strategy=sr.bldcfg.strategy)
            detailtables[sr.bldcfg.projectname].add(
                PendingBld,
                *vars,
                Branch=tbl_brname,
                Strategy=sr.bldcfg.strategy)

        elif isinstance(sr, StatusReport):
            summary.add(_inc, Element='Builds')

            projtable.add(_inc,
                          Project=sr.project,
                          Status=projtable_sts(sr.status))
            projtable.add(_inc, Project=sr.project, Status='TOTAL')

            bldres = _add_if_int({
                'initial_success': '+',
                'succeeded': '+',
                'fixed': '+',
                'bad_config': '-CFG',
            }.get(sr.status, sr.status))
            vars = tuple([(v.varname, v.varvalue) for v in sr.bldvars])

            fulltable.add(bldres,
                          *vars,
                          Project=sr.project,
                          Branch=tbl_branch(sr),
                          Strategy=sr.strategy)

            detailtables[sr.project].add(bldres,
                                         *vars,
                                         Branch=tbl_branch(sr),
                                         Strategy=sr.strategy)

    keytable = KVITable({'Symbol': []},
                        valuecol_name='Meaning',
                        kv_frozen=False)
    keytable.add('Success', Symbol='+')
    keytable.add("'n' build components failed", Symbol='FAIL*n')
    keytable.add('Build configuration error', Symbol='-CFG')
    keytable.add('Pending, no previous builds', Symbol='??')
    keytable.add('Pending, previously suceeding', Symbol='(+)?')
    keytable.add('Pending, previous config error', Symbol='(-CFG)?')
    keytable.add("Pending, previously 'n' components failed", Symbol='(-n)?')

    return '\n\n'.join([
        summary.render(
            as_format='ascii',
            sort_vals=True,
        ),
        section_hdrfun('Per-project Build Status Summary ::'),
        projtable.render(row_group=['Project'],
                         row_repeat=False,
                         sort_vals=False,
                         as_format='ascii',
                         colstack_at='Status'),
        section_hdrfun('Combined Details ::'),
        fulltable.render(
            row_group=['system', 'Branch', 'Strategy'],
            row_repeat=False,
            sort_vals=True,
            entrystr=entshow_fun,
            as_format='ascii',
            colstack_at=(list(fulltable.keyvals().keys()) + [None])[4],
        ),
        section_hdrfun('Individual Project Summaries ::'),
        '\n\n'.join([
            subsection_hdrfun('Project %s:\n' % p) + detailtables[p].render(
                row_repeat=False,
                sort_vals=True,
                as_format='ascii',
                colstack_at=(list(detailtables[p].keyvals().keys()) +
                             [None])[3],
                row_group=['system', 'Branch'],
                entrystr=entshow_fun,
            ) for p in sorted(projects)
        ]),
        section_hdrfun('KEY ::'),
        keytable.render(as_format='ascii'),
    ])