Ejemplo n.º 1
0
    def __init__(self, cells=None, styles=None, nature=None):
        """
        Construct a table object from a collection of cells and a dictionary of styles.

        :type  cells: typing.Iterable[benker.cell.Cell]
        :param cells: Collection of cells.

        :type  styles: typing.Dict[str, str]
        :param styles:
            Dictionary of key-value pairs, where *keys* are the style names.

        :type nature: str
        :ivar nature:
            User-defined string value.
            Table *nature* is similar to HTML ``@class`` attribute,
            you can use it do identify the styles to apply to your table.
        """
        super(Table, self).__init__(styles, nature)
        self._grid = Grid(cells)
Ejemplo n.º 2
0
def test_g6():
    # fmt: off
    g6 = Grid([
        Cell("a", x=1, y=1), Cell("bb", x=2, y=1),
        Cell("cc", x=1, y=2), Cell("d", x=2, y=2)
    ])
    actual = draw(g6)
    expected = textwrap.dedent("""\
    +-----------+-----------+
    |     a     |    bb     |
    +-----------+-----------+
    |    cc     |     d     |
    +-----------+-----------+""")
    assert expected == actual
Ejemplo n.º 3
0
def test_g1():
    # fmt: off
    g1 = Grid([
        Cell("aaa", x=1, y=1, width=2), Cell("bb", x=3, y=1),
        Cell("cc", x=1, y=2), Cell("dddddddddd", x=2, y=2, width=2)
    ])
    actual = draw(g1)
    expected = textwrap.dedent("""\
    +-----------------------+-----------+
    |    aaa                |    bb     |
    +-----------+-----------------------+
    |    cc     | ddddddddd             |
    +-----------+-----------------------+""")
    assert expected == actual
Ejemplo n.º 4
0
def test_g5():
    # fmt: off
    g5 = Grid([
        Cell("aa", x=1, y=1, height=2), Cell("bb", x=2, y=1), Cell("cccc", x=3, y=1),
        Cell("ddd", x=2, y=2), Cell("eeeee", x=3, y=2),
        Cell("ff", x=1, y=3, width=2), Cell("gggggg", x=3, y=3),
    ])
    actual = draw(g5)
    expected = textwrap.dedent("""\
    +-----------+-----------+-----------+
    |    aa     |    bb     |   cccc    |
    |           +-----------+-----------+
    |           |    ddd    |   eeeee   |
    +-----------------------+-----------+
    |    ff                 |  gggggg   |
    +-----------------------+-----------+""")
    assert expected == actual
Ejemplo n.º 5
0
def test_g4():
    # fmt: off
    g4 = Grid([
        Cell("aa", x=1, y=1, height=2), Cell("bbb", x=2, y=1, width=2),
        Cell("ccc", x=2, y=2, height=2), Cell("dd", x=3, y=2),
        Cell("eeee", x=1, y=3), Cell("ffffff", x=3, y=3),
    ])
    actual = draw(g4)
    expected = textwrap.dedent("""\
    +-----------+-----------------------+
    |    aa     |    bbb                |
    |           +-----------+-----------+
    |           |    ccc    |    dd     |
    +-----------|           +-----------+
    |   eeee    |           |  ffffff   |
    +-----------+-----------+-----------+""")
    assert expected == actual
Ejemplo n.º 6
0
class Table(Styled, MutableMapping):
    """
    Table data structure used to simplify conversion to CALS or HTML.

    Short demonstration:

    .. doctest:: table_demo

        >>> from benker.cell import Cell
        >>> from benker.table import Table

        >>> table = Table(styles={'frame': 'all'})

        >>> table[(1, 1)] = Cell("one")
        >>> table.rows[1].insert_cell("two")

        >>> table[(2, 1)]
        <Cell('two', styles={}, nature=None, x=2, y=1, width=1, height=1)>

        >>> table.cols[1].insert_cell("alpha")
        >>> table.cols[2].insert_cell("beta")
        >>> (1, 2) in table
        True

        >>> del table[(1, 2)]
        >>> (1, 2) in table
        False

        >>> len(table)
        3

        >>> for cell in table:
        ...     print(cell)
        one
        two
        beta

        >>> for row in table.rows:
        ...     print(row)
        [one, two]
        [beta]

        >>> table.merge((1, 2), (2, 2))
        >>> print(table)
        +-----------+-----------+
        |    one    |    two    |
        +-----------------------+
        |   beta                |
        +-----------------------+

        >>> table.expand((1, 1), width=3)
        >>> print(table)
        +-----------------------------------------------+
        |              onetwo                           |
        +-----------------------+-----------+-----------+
        |   beta                |           |           |
        +-----------------------+-----------+-----------+
    """

    rows = ViewsProperty(RowView)
    cols = ViewsProperty(ColView)

    def __init__(self, cells=None, styles=None, nature=None):
        """
        Construct a table object from a collection of cells and a dictionary of styles.

        :type  cells: typing.Iterable[benker.cell.Cell]
        :param cells: Collection of cells.

        :type  styles: typing.Dict[str, str]
        :param styles:
            Dictionary of key-value pairs, where *keys* are the style names.

        :type nature: str
        :ivar nature:
            User-defined string value.
            Table *nature* is similar to HTML ``@class`` attribute,
            you can use it do identify the styles to apply to your table.
        """
        super(Table, self).__init__(styles, nature)
        self._grid = Grid(cells)

    def __str__(self):
        return str(self._grid)

    @property
    def bounding_box(self):
        """
        Bounding box of the table (``None`` if the table is empty).

        :rtype: benker.box.Box
        :return: The bounding box.
        """
        return self._grid.bounding_box

    def _refresh_views(self, cell=None):
        """
        Refresh all the rows and column views.
        """
        if cell:
            self.rows.adopt_cell(cell)
            self.cols.adopt_cell(cell)
        else:
            self.rows.refresh_all()
            self.cols.refresh_all()

    def __contains__(self, coord):
        """
        Check if the table contains a cell (a owned cell) at the given coordinates.

        :type  coord: Coord or tuple(int, int)
        :param coord: Coordinates in the tables (1-indexed).

        :return: ``True`` if the table contains a cell at the given
            coordinates, else ``False``.
        """
        return coord in self._grid

    def __setitem__(self, coord, cell):
        """
        Insert a cell in the table at the given coordinates.

        :type  coord: Coord or tuple(int, int)
        :param coord: Coordinates in the tables (1-indexed).

        :type  cell: benker.cell.Cell
        :param cell: Cell to insert.
        """
        self._grid[coord] = cell
        # get the cell with its new coordinates:
        cell = self._grid[coord]
        self._refresh_views(cell)

    def __delitem__(self, coord):
        """
        Delete a cell from the table at the given coordinates.

        :type  coord: Coord or tuple(int, int)
        :param coord: Coordinates in the tables (1-indexed).
        """
        del self._grid[coord]
        self._refresh_views()

    def __getitem__(self, coord):
        """
        Get a cell at the given coordinates.

        :type  coord: Coord or tuple(int, int)
        :param coord: Coordinates in the tables (1-indexed).

        :rtype: benker.cell.Cell
        :return: The cell.
        """
        return self._grid[coord]

    def __len__(self):
        return len(self._grid)

    def __iter__(self):
        return iter(self._grid)

    def merge(self, start, end, content_appender=None):
        self._grid.merge(start, end, content_appender=content_appender)
        self._refresh_views()

    def expand(self, coord, width=0, height=0, content_appender=None):
        self._grid.expand(coord, width=width, height=height, content_appender=content_appender)
        self._refresh_views()

    def fill_missing(self, bounding_box, content, styles=None, nature=None):
        """
        Fill the missing cells in the table.

        This method is useful when some rows has missing cells (holes).

        :type  bounding_box: Box
        :param bounding_box:
            The bounding box delimiting the cells/rows to fill if missing.

        :param content:
            User-defined cell content. It can be of any type: ``None``,
            :class:`str`, :class:`int`, :class:`float`, a container (:class:`list`),
            a XML element, etc. The same content can be shared by several cells, it's
            your own responsibility to handle the copy (or deep copy) of the *content*
            reference when needed.

        :type  styles: typing.Dict[str, str]
        :param styles:
            User-defined cell styles: a dictionary of key-value pairs.
            This values are useful to store some HTML-like styles (border-style,
            border-width, border-color, vertical-align, text-align, etc.).
            Of course, we are not tied to the HTML-like styles, you can use your own
            list of styles.

        :type nature: str
        :ivar nature: a way to distinguish the body cells, from the header and the footer.
            The default value is ``None``, but you can use "body", "header", "footer" or whatever
            is suitable for your needs.
            If set to ``None``, the cell nature is inherited from the row nature.

        .. versionadded:: 0.5.0
        """
        for y in range(bounding_box.min.y, bounding_box.max.y + 1):
            for x in range(bounding_box.min.x, bounding_box.max.x + 1):
                if (x, y) not in self:
                    cell = Cell(content, styles=styles, nature=nature, x=x, y=y)
                    self[(x, y)] = cell