Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataTable refactor - Adds cell updating and sorting functionality #1638

Merged
merged 148 commits into from
Feb 14, 2023

Conversation

darrenburns
Copy link
Member

@darrenburns darrenburns commented Jan 23, 2023

Rows and columns in the DataTable have been decoupled from their current visual location.

API Changes

  • A sort method was added to the DataTable, allowing you to supply one or more column keys. Rows will be re-ordered using the provided keys.
  • A new method update_cell(row_key, column_key, value, update_width) was added to the DataTable, which can be used to update the value of a cell identified by (row_key, column_key).
  • A similar method update_coordinate(coordinate, value, update_width) was added which can be used to update the cell which is currently present at coordinate.
  • add_row and add_column have been updated to accept a key argument. If this key is not supplied, the DataTable will generate a key for you. This key will be returned from calls to add_row and add_column and can be used to reference the row and column regardless of where it’s currently located on the screen. This means that if you sort the rows in your table, you can always use the key of that row to reference it, even if its coordinate/index has changed.
  • Similarly, add_rows and add_columns have been updated to return list[RowKey] and list[ColumnKey] respectively.
  • get_cell_value has been renamed to get_value_at(coordinate) - this seems more appropriate given our new distinction between spatial coordinates and cells identified by row/column keys.
  • A new version of get_cell_value exists which returns the value of a cell given a RowKey and ColumnKey.
  • cursor_cell was renamed to cursor_coordinate since cells and coordinates are no longer the same things. It was renamed to make that more explicit.
    • The method validate_cursor_cell was renamed to validate_cursor_coordinate.
    • The method watch_cursor_cell was renamed to watch_cursor_coordinate.
  • hover_cell renamed to hover_coordinate for similar reasons.
    • The method validate_hover_cell was renamed to validate_hover_coordinate.
  • row_count is now a property. Previously it was an attribute that was manually kept in sync.
  • Public attributes data, columns and rows are re-structured to all be dicts keyed by row and column keys.
    • Ordering can no longer be relied upon when interacting with these structures. These structures store data but have no say in where it is located on the screen.
  • New public properties ordered_rows and ordered_columns have been added, which return list[Row] and list[Column] respectively. The ordering of these lists reflects the positioning of the rows and columns you see on screen.
  • Row/column/cell keys are accessible as attributes on the events emitted from the DataTable.
  • Public method refresh_cell was changed to refresh_coordinate(coordinate). (Although I'm not sure what the use case for this being public is).
  • New public methods for validating coordinates are within the bounds of the DataTable and used extensively internally. Allows you to say "can I move my cursor to here without it being clamped?" before moving it.
  • Fixes The three DataTable *Selected methods report wrong selection location when caused by mouse selection #1723
  • Makes the filter module public.

Please review the following checklist.

  • Docstrings on all new or modified functions / classes
  • Updated documentation
  • Updated CHANGELOG.md (where appropriate)

src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@willmcgugan willmcgugan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some comments to consider.

Pretty sure this will be good to merge early next week.

src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
@darrenburns darrenburns changed the title DataTable internals updates DataTable refactor - Adds cell updating and sorting functionality Feb 9, 2023
@ofek
Copy link
Contributor

ofek commented Feb 11, 2023

I think there is a bug where if a cell's initial value is an empty string then the cell can no longer be updated after row creation:

import asyncio

from textual.app import App
from textual.widgets import DataTable, Footer, Header, Switch

BACKGROUND_TASKS = []

class Listing(DataTable):
    def on_mount(self):
        super().on_mount()

        self.add_column('', key='status')
        self.add_column('', key='title')
        self.show_header = False
        self.cursor_type = 'row'

        self.call_after_refresh(lambda: BACKGROUND_TASKS.append(asyncio.create_task(self.__on_mount())))

    async def __on_mount(self):
        # self.add_row('something', 'title1', key='foo')
        self.add_row('', 'title1', key='foo')

class MyApp(App):
    def compose(self):
        yield Header()
        yield Switch()
        yield Listing()
        yield Footer()

    async def on_switch_changed(self, event: Switch.Changed):
        listing = self.query_one(Listing)
        listing.update_cell('foo', 'status', '✓' if event.value else '')

if __name__ == '__main__':
    app = MyApp()
    app.run()

@darrenburns
Copy link
Member Author

@ofek Since all the cells in that column are the empty string (including the label), the width will be calculated as 0. The width of a column will only be recomputed if you pass update_width=True to your call to update_cell.

@darrenburns darrenburns marked this pull request as ready for review February 14, 2023 10:28
src/textual/_two_way_dict.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@willmcgugan willmcgugan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. Just a few minor requests.

src/textual/widgets/_data_table.py Outdated Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
src/textual/widgets/_data_table.py Show resolved Hide resolved
@willmcgugan willmcgugan merged commit 07a968a into main Feb 14, 2023
@willmcgugan willmcgugan deleted the datatable-cell-keys branch February 14, 2023 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The three DataTable *Selected methods report wrong selection location when caused by mouse selection
4 participants