← eval4_submission

rich_2725

resolved RESOLVED PASS · 18 tool calls · 109 s · Textualize/rich

Task input

fix table rendering order of box elements

## Type of changes

- [x] Bug fix
- [ ] New feature
- [ ] Documentation / docstrings
- [x] Tests
- [ ] Other

## Checklist

- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.
- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.
- [x] I've added tests for new code.
- [x] I accept that @willmcgugan may be pedantic in the code review.

## Description

* Previously "mid" box elements appeared in last line of table (footer), while "footer" box elements appeared mid table body. Reversed that order so mid is truly mid, footer is truly footer.
* Tested with:

    ```
    table.box.head_left = '1'
    table.box.head_vertical = '2'
    table.box.head_right = '3'

    table.box.mid_left = '4'
    table.box.mid_vertical = '5'
    table.box.mid_right = '6'

    table.box.foot_left = '7'
    table.box.foot_vertical = '8'
    table.box.foot_right = '9'
    ```

  After change, correct ordering:

    ```
    +--------------------------------------------------------------------------+
    1Date        2Title                            2  Production2    Box Office3
    |------------ --------------------------------- ------------ --------------|
    4Dec 20, 20195Star Wars: The Rise of Skywalker 5$275,000,0005  $375,126,1186
    4May 25, 20185Solo: A Star Wars Story          5$275,000,0005  $393,151,3476
    7Dec 15, 20178Star Wars Ep. VIII: The Last Jedi8$262,000,0008$1,332,539,8899
    +--------------------------------------------------------------------------+
    ```

* All non-skipped prior automated tests pass. No automated tests added. Unclear that additional test for box ordering would add proportionate value.

Tool calls (19)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"table.box\" rich | head -20"
}
{"status": "ok", "stdout": "rich/box.py:475: table.box = getattr(box, box_name)\n", "exit_code": 0}
full
{"status": "ok", "stdout": "rich/box.py:475:        table.box = getattr(box, box_name)\n", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"Table\" rich | grep \"render\" | head -20"
}
{"status": "ok", "stdout": "rich/table.py:929: with timer(\"Table render\"):\nrich/_log_render.py:9: from .table import Table\nrich/_log_render.py:42: ) -> \"Ta
full
{"status": "ok", "stdout": "rich/table.py:929:    with timer(\"Table render\"):\nrich/_log_render.py:9:    from .table import Table\nrich/_log_render.py:42:    ) -> \"Table\":\nrich/_log_render.py:44:        from .table import Table\nrich/_log_render.py:46:        output = Table.grid(padding=(0, 1))\nrich/__main__.py:90:    def comparison(renderable1: RenderableType, renderable2: RenderableType) -> Table:\n", "exit_code": 0}
3read_file
{
 "filepath": "rich/table.py",
 "start_line": 929
}
{"status": "ok", "filepath": "rich/table.py", "content": " with timer(\"Table render\"):\n table = Table(\n title=\"Star Wars Movies\",\n caption=\"Rich example
full
{"status": "ok", "filepath": "rich/table.py", "content": "    with timer(\"Table render\"):\n        table = Table(\n            title=\"Star Wars Movies\",\n            caption=\"Rich example table\",\n            caption_justify=\"right\",\n        )\n\n        table.add_column(\n            \"Released\", header_style=\"bright_cyan\", style=\"cyan\", no_wrap=True\n        )\n        table.add_column(\"Title\", style=\"magenta\")\n        table.add_column(\"Box Office\", justify=\"right\", style=\"green\")\n\n        table.add_row(\n            \"Dec 20, 2019\",\n            \"Star Wars: The Rise of Skywalker\",\n            \"$952,110,690\",\n        )\n        table.add_row(\"May 25, 2018\", \"Solo: A Star Wars Story\", \"$393,151,347\")\n        table.add_row(\n            \"Dec 15, 2017\",\n            \"Star Wars Ep. V111: The Last Jedi\",\n            \"$1,332,539,889\",\n            style=\"on black\",\n            end_section=True,\n        )\n        table.add_row(\n            \"Dec 16, 2016\",\n            \"Rogue One: A Star Wars Story\",\n            \"$1,332,439,889\",\n        )\n\n        def header(text: str) -> None:\n            console.print()\n            console.rule(highlight(text))\n            console.print()\n\n        console = Console()\n        highlight = ReprHighlighter()\n        header(\"Example Table\")\n        console.print(table, justify=\"center\")\n\n        table.expand = True\n        header(\"expand=True\")\n        console.print(table)\n\n        table.width = 50\n        header(\"width=50\")\n\n        console.print(table, justify=\"center\")\n\n        table.width = None\n        table.expand = False\n        table.row_styles = [\"dim\", \"none\"]\n        header(\"row_styles=['dim', 'none']\")\n\n        console.print(table, justify=\"center\")\n\n        table.width = None\n        table.expand = False\n        table.row_styles = [\"dim\", \"none\"]\n        table.leading = 1\n        header(\"leading=1, row_styles=['d
4run_command
{
 "command": "grep -n \"def __rich_console__\" rich/table.py"
}
{"status": "ok", "stdout": "470: def __rich_console__(\n", "exit_code": 0}
full
{"status": "ok", "stdout": "470:    def __rich_console__(\n", "exit_code": 0}
5read_file
{
 "filepath": "rich/table.py",
 "start_line": 470,
 "end_line": 700
}
{"status": "ok", "filepath": "rich/table.py", "content": " def __rich_console__(\n self, console: \"Console\", options: \"ConsoleOptions\"\n ) -> \"RenderResult
full
{"status": "ok", "filepath": "rich/table.py", "content": "    def __rich_console__(\n        self, console: \"Console\", options: \"ConsoleOptions\"\n    ) -> \"RenderResult\":\n        if not self.columns:\n            yield Segment(\"\\n\")\n            return\n\n        max_width = options.max_width\n        if self.width is not None:\n            max_width = self.width\n\n        extra_width = self._extra_width\n        widths = self._calculate_column_widths(\n            console, options.update_width(max_width - extra_width)\n        )\n        table_width = sum(widths) + extra_width\n\n        render_options = options.update(\n            width=table_width, highlight=self.highlight, height=None\n        )\n\n        def render_annotation(\n            text: TextType, style: StyleType, justify: \"JustifyMethod\" = \"center\"\n        ) -> \"RenderResult\":\n            render_text = (\n                console.render_str(text, style=style, highlight=False)\n                if isinstance(text, str)\n                else text\n            )\n            return console.render(\n                render_text, options=render_options.update(justify=justify)\n            )\n\n        if self.title:\n            yield from render_annotation(\n                self.title,\n                style=Style.pick_first(self.title_style, \"table.title\"),\n                justify=self.title_justify,\n            )\n        yield from self._render(console, render_options, widths)\n        if self.caption:\n            yield from render_annotation(\n                self.caption,\n                style=Style.pick_first(self.caption_style, \"table.caption\"),\n                justify=self.caption_justify,\n            )\n\n    def _calculate_column_widths(\n        self, console: \"Console\", options: \"ConsoleOptions\"\n    ) -> List[int]:\n        \"\"\"Calculate the widths of each column, including padding, not including borders.\"\"\"\n        max_width = options.max_width\n        
6read_file
{
 "end_line": 800,
 "filepath": "rich/table.py",
 "start_line": 620
}
{"status": "ok", "filepath": "rich/table.py", "content": " def _get_cells(\n self, console: \"Console\", column_index: int, column: Column\n ) -> Iterable[_Cell
full
{"status": "ok", "filepath": "rich/table.py", "content": "    def _get_cells(\n        self, console: \"Console\", column_index: int, column: Column\n    ) -> Iterable[_Cell]:\n        \"\"\"Get all the cells with padding and optional header.\"\"\"\n\n        collapse_padding = self.collapse_padding\n        pad_edge = self.pad_edge\n        padding = self.padding\n        any_padding = any(padding)\n\n        first_column = column_index == 0\n        last_column = column_index == len(self.columns) - 1\n\n        _padding_cache: Dict[Tuple[bool, bool], Tuple[int, int, int, int]] = {}\n\n        def get_padding(first_row: bool, last_row: bool) -> Tuple[int, int, int, int]:\n            cached = _padding_cache.get((first_row, last_row))\n            if cached:\n                return cached\n            top, right, bottom, left = padding\n\n            if collapse_padding:\n                if not first_column:\n                    left = max(0, left - right)\n                if not last_row:\n                    bottom = max(0, top - bottom)\n\n            if not pad_edge:\n                if first_column:\n                    left = 0\n                if last_column:\n                    right = 0\n                if first_row:\n                    top = 0\n                if last_row:\n                    bottom = 0\n            _padding = (top, right, bottom, left)\n            _padding_cache[(first_row, last_row)] = _padding\n            return _padding\n\n        raw_cells: List[Tuple[StyleType, \"RenderableType\"]] = []\n        _append = raw_cells.append\n        get_style = console.get_style\n        if self.show_header:\n            header_style = get_style(self.header_style or \"\") + get_style(\n                column.header_style\n            )\n            _append((header_style, column.header))\n        cell_style = get_style(column.style or \"\")\n        for cell in column.cells:\n            _append((cell_style, cell))\n        if self.show_footer:\n  
7read_file
{
 "end_line": 850,
 "filepath": "rich/table.py",
 "start_line": 770
}
{"status": "ok", "filepath": "rich/table.py", "content": " _Segment = Segment\n if _box:\n box_segments = [\n (\n _Segment(_box.head_left, border_style),\n _Seg
full
{"status": "ok", "filepath": "rich/table.py", "content": "        _Segment = Segment\n        if _box:\n            box_segments = [\n                (\n                    _Segment(_box.head_left, border_style),\n                    _Segment(_box.head_right, border_style),\n                    _Segment(_box.head_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.foot_left, border_style),\n                    _Segment(_box.foot_right, border_style),\n                    _Segment(_box.foot_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.mid_left, border_style),\n                    _Segment(_box.mid_right, border_style),\n                    _Segment(_box.mid_vertical, border_style),\n                ),\n            ]\n            if show_edge:\n                yield _Segment(_box.get_top(widths), border_style)\n                yield new_line\n        else:\n            box_segments = []\n\n        get_row_style = self.get_row_style\n        get_style = console.get_style\n\n        for index, (first, last, row_cell) in enumerate(loop_first_last(row_cells)):\n            header_row = first and show_header\n            footer_row = last and show_footer\n            row = (\n                self.rows[index - show_header]\n                if (not header_row and not footer_row)\n                else None\n            )\n            max_height = 1\n            cells: List[List[List[Segment]]] = []\n            if header_row or footer_row:\n                row_style = Style.null()\n            else:\n                row_style = get_style(\n                    get_row_style(console, index - 1 if show_header else index)\n                )\n            for width, cell, column in zip(widths, row_cell, columns):\n                render_options = options.update(\n                    width=width,\n                    justify=column.justify,\n                    no_wrap=column.no_wrap
8read_file
{
 "end_line": 920,
 "filepath": "rich/table.py",
 "start_line": 851
}
{"status": "ok", "filepath": "rich/table.py", "content": " align_cell(\n cell,\n _cell.vertical,\n width,\n get_style(_cell.style) + row_style,\n ),\n width,\n
full
{"status": "ok", "filepath": "rich/table.py", "content": "                    align_cell(\n                        cell,\n                        _cell.vertical,\n                        width,\n                        get_style(_cell.style) + row_style,\n                    ),\n                    width,\n                    max_height,\n                )\n                for width, _cell, cell, column in zip(widths, row_cell, cells, columns)\n            ]\n\n            if _box:\n                if last and show_footer:\n                    yield _Segment(\n                        _box.get_row(widths, \"foot\", edge=show_edge), border_style\n                    )\n                    yield new_line\n                left, right, _divider = box_segments[0 if first else (2 if last else 1)]\n\n                # If the column divider is whitespace also style it with the row background\n                divider = (\n                    _divider\n                    if _divider.text.strip()\n                    else _Segment(\n                        _divider.text, row_style.background_style + _divider.style\n                    )\n                )\n                for line_no in range(max_height):\n                    if show_edge:\n                        yield left\n                    for last_cell, rendered_cell in loop_last(cells):\n                        yield from rendered_cell[line_no]\n                        if not last_cell:\n                            yield divider\n                    if show_edge:\n                        yield right\n                    yield new_line\n            else:\n                for line_no in range(max_height):\n                    for rendered_cell in cells:\n                        yield from rendered_cell[line_no]\n                    yield new_line\n            if _box and first and show_header:\n                yield _Segment(\n                    _box.get_row(widths, \"head\", edge=show_edge), border_style\n             
9read_file
{
 "end_line": 810,
 "filepath": "rich/table.py",
 "start_line": 770
}
{"status": "ok", "filepath": "rich/table.py", "content": " _Segment = Segment\n if _box:\n box_segments = [\n (\n _Segment(_box.head_left, border_style),\n _Seg
full
{"status": "ok", "filepath": "rich/table.py", "content": "        _Segment = Segment\n        if _box:\n            box_segments = [\n                (\n                    _Segment(_box.head_left, border_style),\n                    _Segment(_box.head_right, border_style),\n                    _Segment(_box.head_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.foot_left, border_style),\n                    _Segment(_box.foot_right, border_style),\n                    _Segment(_box.foot_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.mid_left, border_style),\n                    _Segment(_box.mid_right, border_style),\n                    _Segment(_box.mid_vertical, border_style),\n                ),\n            ]\n            if show_edge:\n                yield _Segment(_box.get_top(widths), border_style)\n                yield new_line\n        else:\n            box_segments = []\n\n        get_row_style = self.get_row_style\n        get_style = console.get_style\n\n        for index, (first, last, row_cell) in enumerate(loop_first_last(row_cells)):\n            header_row = first and show_header\n            footer_row = last and show_footer\n            row = (\n                self.rows[index - show_header]\n                if (not header_row and not footer_row)\n                else None\n            )\n            max_height = 1\n            cells: List[List[List[Segment]]] = []\n            if header_row or footer_row:\n                row_style = Style.null()\n            else:\n", "start_line": 770, "end_line": 810, "total_lines": 1000, "is_truncated": false}
10read_file
{
 "end_line": 880,
 "filepath": "rich/table.py",
 "start_line": 860
}
{"status": "ok", "filepath": "rich/table.py", "content": " for width, _cell, cell, column in zip(widths, row_cell, cells, columns)\n ]\n\n if _box:\n if last an
full
{"status": "ok", "filepath": "rich/table.py", "content": "                for width, _cell, cell, column in zip(widths, row_cell, cells, columns)\n            ]\n\n            if _box:\n                if last and show_footer:\n                    yield _Segment(\n                        _box.get_row(widths, \"foot\", edge=show_edge), border_style\n                    )\n                    yield new_line\n                left, right, _divider = box_segments[0 if first else (2 if last else 1)]\n\n                # If the column divider is whitespace also style it with the row background\n                divider = (\n                    _divider\n                    if _divider.text.strip()\n                    else _Segment(\n                        _divider.text, row_style.background_style + _divider.style\n                    )\n                )\n                for line_no in range(max_height):\n                    if show_edge:\n", "start_line": 860, "end_line": 880, "total_lines": 1000, "is_truncated": false}
11edit_file
{
 "filepath": "rich/table.py",
 "new_string": "            box_segments = [\n                (\n                    _Segment(_box.head_left, border_style),\n                    _Segment(_box.head_right, border_style),\n                    _Segment(_box.head_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.mid_left, border_style),\n                    _Segment(_box.mid_right, border_style),\n                    _Segment(_box.mid_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.foot_left, border_style),\n                    _Segment(_box.foot_right, border_style),\n                    _Segment(_box.foot_vertical, border_style),\n                ),\n            ]",
 "old_string": "            box_segments = [\n                (\n                    _Segment(_box.head_left, border_style),\n                    _Segment(_box.head_right, border_style),\n                    _Segment(_box.head_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.foot_left, border_style),\n                    _Segment(_box.foot_right, border_style),\n                    _Segment(_box.foot_vertical, border_style),\n                ),\n                (\n                    _Segment(_box.mid_left, border_style),\n                    _Segment(_box.mid_right, border_style),\n                    _Segment(_box.mid_vertical, border_style),\n                ),\n            ]"
}
{"status": "ok", "filepath": "rich/table.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/table.py\n+++ b/rich/table.py\n@@ -776,14 +776,14 @@\n
full
{"status": "ok", "filepath": "rich/table.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/table.py\n+++ b/rich/table.py\n@@ -776,14 +776,14 @@\n                     _Segment(_box.head_vertical, border_style),\n                 ),\n                 (\n+                    _Segment(_box.mid_left, border_style),\n+                    _Segment(_box.mid_right, border_style),\n+                    _Segment(_box.mid_vertical, border_style),\n+                ),\n+                (\n                     _Segment(_box.foot_left, border_style),\n                     _Segment(_box.foot_right, border_style),\n                     _Segment(_box.foot_vertical, border_style),\n-                ),\n-                (\n-                    _Segment(_box.mid_left, border_style),\n-                    _Segment(_box.mid_right, border_style),\n-                    _Segment(_box.mid_vertical, border_style),\n                 ),\n             ]\n             if show_edge:\n", "is_truncated": false}
12write_file
{
 "content": "from rich.console import Console\nfrom rich.table import Table\nfrom rich.box import Box\n\nconsole = Console(force_terminal=True, width=100)\ntable = Table(show_header=True, show_footer=True, show_edge=True)\n\ntable.box.head_left = '1'\ntable.box.head_vertical = '2'\ntable.box.head_right = '3'\n\ntable.box.mid_left = '4'\ntable.box.mid_vertical = '5'\ntable.box.mid_right = '6'\n\ntable.box.foot_left = '7'\ntable.box.foot_vertical = '8'\ntable.box.foot_right = '9'\n\ntable.add_column(\"Date\")\ntable.add_column(\"Title\")\ntable.add_column(\"Box Office\")\n\ntable.add_row(\"Dec 20, 2019\", \"Star Wars: The Rise of Skywalker\", \"$375,126,118\")\ntable.add_row(\"May 25, 2018\", \"Solo: A Star Wars Story\", \"$393,151,347\")\ntable.add_row(\"Dec 15, 2017\", \"Star Wars Ep. VIII: The Last Jedi\", \"$1,332,539,889\")\n\n# Set footer for columns\nfor col in table.columns:\n    col.footer = \"Footer\"\n\nconsole.print(table)\n",
 "filepath": "/tmp/test_table_box.py"
}
{"status": "ok", "filepath": "/tmp/test_table_box.py", "size": 877}
full
{"status": "ok", "filepath": "/tmp/test_table_box.py", "size": 877}
13-14 ×2run_command
{
 "command": "python3 /tmp/test_table_box.py"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open f
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open file '/tmp/swe_work/eval4_submission/rich_2725/a/tmp/test_table_box.py': [Errno 2] No such file or directory\n", "exit_code": 2}}
15run_command
{
 "command": "ls -l /tmp/test_table_box.py"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "ls: cannot access '/t
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "ls: cannot access '/tmp/swe_work/eval4_submission/rich_2725/a/tmp/test_table_box.py': No such file or directory\n", "exit_code": 2}}
16write_file
{
 "content": "from rich.console import Console\nfrom rich.table import Table\nfrom rich.box import Box\n\nconsole = Console(force_terminal=True, width=100)\ntable = Table(show_header=True, show_footer=True, show_edge=True)\n\ntable.box.head_left = '1'\ntable.box.head_vertical = '2'\ntable.box.head_right = '3'\n\ntable.box.mid_left = '4'\ntable.box.mid_vertical = '5'\ntable.box.mid_right = '6'\n\ntable.box.foot_left = '7'\ntable.box.foot_vertical = '8'\ntable.box.foot_right = '9'\n\ntable.add_column(\"Date\")\ntable.add_column(\"Title\")\ntable.add_column(\"Box Office\")\n\ntable.add_row(\"Dec 20, 2019\", \"Star Wars: The Rise of Skywalker\", \"$375,126,118\")\ntable.add_row(\"May 25, 2018\", \"Solo: A Star Wars Story\", \"$393,151,347\")\ntable.add_row(\"Dec 15, 2017\", \"Star Wars Ep. VIII: The Last Jedi\", \"$1,332,539,889\")\n\n# Set footer for columns\nfor col in table.columns:\n    col.footer = \"Footer\"\n\nconsole.print(table)\n",
 "filepath": "test_table_box.py"
}
{"status": "ok", "filepath": "test_table_box.py", "size": 877}
full
{"status": "ok", "filepath": "test_table_box.py", "size": 877}
17run_command
{
 "command": "python3 test_table_box.py"
}
{"status": "ok", "stdout": "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501
full
{"status": "ok", "stdout": "\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n1 Date         2 Title                             2 Box Office     3\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n4 Dec 20, 2019 5 Star Wars: The Rise of Skywalker  5 $375,126,118   6\n4 May 25, 2018 5 Solo: A Star Wars Story           5 $393,151,347   6\n4 Dec 15, 2017 5 Star Wars Ep. VIII: The Last Jedi 5 $1,332,539,889 6\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n7 Footer       8 Footer                            8 Footer         9\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2
18run_command
{
 "command": "rm test_table_box.py"
}
{"status": "ok", "stdout": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "exit_code": 0}
19submit_patch
[]
{"status": "ok", "patch_size": 2172, "files_changed": 2}
full
{"status": "ok", "patch_size": 2172, "files_changed": 2}

Patch

diff --git a/rich/table.py b/rich/table.py
index fe4054cf..44e457be 100644
--- a/rich/table.py
+++ b/rich/table.py
@@ -775,16 +775,16 @@ class Table(JupyterMixin):
                     _Segment(_box.head_right, border_style),
                     _Segment(_box.head_vertical, border_style),
                 ),
-                (
-                    _Segment(_box.foot_left, border_style),
-                    _Segment(_box.foot_right, border_style),
-                    _Segment(_box.foot_vertical, border_style),
-                ),
                 (
                     _Segment(_box.mid_left, border_style),
                     _Segment(_box.mid_right, border_style),
                     _Segment(_box.mid_vertical, border_style),
                 ),
+                (
+                    _Segment(_box.foot_left, border_style),
+                    _Segment(_box.foot_right, border_style),
+                    _Segment(_box.foot_vertical, border_style),
+                ),
             ]
             if show_edge:
                 yield _Segment(_box.get_top(widths), border_style)
diff --git a/tmp/test_table_box.py b/tmp/test_table_box.py
new file mode 100644
index 00000000..60894dcb
--- /dev/null
+++ b/tmp/test_table_box.py
@@ -0,0 +1,32 @@
+from rich.console import Console
+from rich.table import Table
+from rich.box import Box
+
+console = Console(force_terminal=True, width=100)
+table = Table(show_header=True, show_footer=True, show_edge=True)
+
+table.box.head_left = '1'
+table.box.head_vertical = '2'
+table.box.head_right = '3'
+
+table.box.mid_left = '4'
+table.box.mid_vertical = '5'
+table.box.mid_right = '6'
+
+table.box.foot_left = '7'
+table.box.foot_vertical = '8'
+table.box.foot_right = '9'
+
+table.add_column("Date")
+table.add_column("Title")
+table.add_column("Box Office")
+
+table.add_row("Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$375,126,118")
+table.add_row("May 25, 2018", "Solo: A Star Wars Story", "$393,151,347")
+table.add_row("Dec 15, 2017", "Star Wars Ep. VIII: The Last Jedi", "$1,332,539,889")
+
+# Set footer for columns
+for col in table.columns:
+    col.footer = "Footer"
+
+console.print(table)

Test output

show
...................                                                      [100%]
19 passed in 0.20s