From 3e74a6116e2a6b7450e492a911a990d05d972e27 Mon Sep 17 00:00:00 2001 From: hasansezertasan Date: Tue, 28 May 2024 01:50:07 +0300 Subject: [PATCH 1/6] Add support for `computed_field` in `Table` component. --- src/python-fastui/fastui/components/tables.py | 19 +++++--- .../tests/test_tables_display.py | 46 +++++++++++++++---- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/python-fastui/fastui/components/tables.py b/src/python-fastui/fastui/components/tables.py index 9044ef3d..22328d51 100644 --- a/src/python-fastui/fastui/components/tables.py +++ b/src/python-fastui/fastui/components/tables.py @@ -44,16 +44,21 @@ def _fill_columns(self) -> _te.Self: raise ValueError('Cannot infer model from empty data, please set `Table(..., model=MyModel)`') if self.columns is None: - self.columns = [ - display.DisplayLookup(field=name, title=field.title) - for name, field in data_model_type.model_fields.items() - ] + self.columns = [] + for name, field in data_model_type.model_fields.items(): + self.columns.append(display.DisplayLookup(field=name, title=field.title)) + for name, field in data_model_type.model_computed_fields.items(): + self.columns.append(display.DisplayLookup(field=name, title=field.title)) + else: # add pydantic titles to columns that don't have them for column in (c for c in self.columns if c.title is None): - field = data_model_type.model_fields.get(column.field) - if field and field.title: - column.title = field.title + model_field = data_model_type.model_fields.get(column.field) + computed_field = data_model_type.model_computed_fields.get(column.field) + if model_field and model_field.title: + column.title = model_field.title + elif computed_field and computed_field.title: + column.title = computed_field.title return self @classmethod diff --git a/src/python-fastui/tests/test_tables_display.py b/src/python-fastui/tests/test_tables_display.py index d1ab281b..5211d462 100644 --- a/src/python-fastui/tests/test_tables_display.py +++ b/src/python-fastui/tests/test_tables_display.py @@ -1,13 +1,18 @@ import pytest from fastui import components from fastui.components import display -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, computed_field class User(BaseModel): id: int name: str = Field(title='Name') + @computed_field + @property + def representation(self) -> str: + return f'{self.id}: {self.name}' + users = [User(id=1, name='john'), User(id=2, name='jack')] @@ -17,21 +22,40 @@ def test_table_no_columns(): # insert_assert(table.model_dump(by_alias=True, exclude_none=True)) assert table.model_dump(by_alias=True, exclude_none=True) == { - 'data': [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'jack'}], - 'columns': [{'field': 'id'}, {'field': 'name', 'title': 'Name'}], + 'data': [ + {'id': 1, 'name': 'john', 'representation': '1: john'}, + {'id': 2, 'name': 'jack', 'representation': '2: jack'} + ], + 'columns': [ + {'field': 'id'}, + {'field': 'name', 'title': 'Name'}, + {'field': 'representation'} + ], 'type': 'Table', } def test_table_columns(): table = components.Table( - data=users, columns=[display.DisplayLookup(field='id', title='ID'), display.DisplayLookup(field='name')] + data=users, + columns=[ + display.DisplayLookup(field='id', title='ID'), + display.DisplayLookup(field='name'), + display.DisplayLookup(field='representation'), + ], ) # insert_assert(table.model_dump(by_alias=True, exclude_none=True)) assert table.model_dump(by_alias=True, exclude_none=True) == { - 'data': [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'jack'}], - 'columns': [{'title': 'ID', 'field': 'id'}, {'field': 'name', 'title': 'Name'}], + 'data': [ + {'id': 1, 'name': 'john', 'representation': '1: john'}, + {'id': 2, 'name': 'jack', 'representation': '2: jack'}, + ], + 'columns': [ + {'title': 'ID', 'field': 'id'}, + {'title': 'Name', 'field': 'name'}, + {'field': 'representation'}, + ], 'type': 'Table', } @@ -47,7 +71,11 @@ def test_table_empty_data_model(): # insert_assert(table.model_dump(by_alias=True, exclude_none=True)) assert table.model_dump(by_alias=True, exclude_none=True) == { 'data': [], - 'columns': [{'field': 'id'}, {'title': 'Name', 'field': 'name'}], + 'columns': [ + {'field': 'id'}, + {'title': 'Name', 'field': 'name'}, + {'field': 'representation'}, + ], 'type': 'Table', } @@ -57,7 +85,7 @@ def test_display_no_fields(): # insert_assert(d.model_dump(by_alias=True, exclude_none=True)) assert d.model_dump(by_alias=True, exclude_none=True) == { - 'data': {'id': 1, 'name': 'john'}, + 'data': {'id': 1, 'name': 'john', 'representation': '1: john'}, 'fields': [{'field': 'id'}, {'title': 'Name', 'field': 'name'}], 'type': 'Details', } @@ -70,7 +98,7 @@ def test_display_fields(): # insert_assert(d.model_dump(by_alias=True, exclude_none=True)) assert d.model_dump(by_alias=True, exclude_none=True) == { - 'data': {'id': 1, 'name': 'john'}, + 'data': {'id': 1, 'name': 'john', 'representation': '1: john'}, 'fields': [{'title': 'ID', 'field': 'id'}, {'title': 'Name', 'field': 'name'}], 'type': 'Details', } From 6835414e83997bae519a079dec52b60ae96b8af1 Mon Sep 17 00:00:00 2001 From: hasansezertasan Date: Tue, 28 May 2024 01:56:02 +0300 Subject: [PATCH 2/6] Remove trailing-whitespace --- src/python-fastui/tests/test_tables_display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python-fastui/tests/test_tables_display.py b/src/python-fastui/tests/test_tables_display.py index 5211d462..e3c76e97 100644 --- a/src/python-fastui/tests/test_tables_display.py +++ b/src/python-fastui/tests/test_tables_display.py @@ -23,7 +23,7 @@ def test_table_no_columns(): # insert_assert(table.model_dump(by_alias=True, exclude_none=True)) assert table.model_dump(by_alias=True, exclude_none=True) == { 'data': [ - {'id': 1, 'name': 'john', 'representation': '1: john'}, + {'id': 1, 'name': 'john', 'representation': '1: john'}, {'id': 2, 'name': 'jack', 'representation': '2: jack'} ], 'columns': [ From fd804ea14d7f85ff8409e87f2f0d4632e9005a62 Mon Sep 17 00:00:00 2001 From: hasansezertasan Date: Tue, 28 May 2024 01:58:16 +0300 Subject: [PATCH 3/6] Lint --- src/python-fastui/tests/test_tables_display.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/python-fastui/tests/test_tables_display.py b/src/python-fastui/tests/test_tables_display.py index e3c76e97..43bdd922 100644 --- a/src/python-fastui/tests/test_tables_display.py +++ b/src/python-fastui/tests/test_tables_display.py @@ -26,11 +26,7 @@ def test_table_no_columns(): {'id': 1, 'name': 'john', 'representation': '1: john'}, {'id': 2, 'name': 'jack', 'representation': '2: jack'} ], - 'columns': [ - {'field': 'id'}, - {'field': 'name', 'title': 'Name'}, - {'field': 'representation'} - ], + 'columns': [{'field': 'id'}, {'field': 'name', 'title': 'Name'}, {'field': 'representation'}], 'type': 'Table', } From 7b858c2b4da1ad79c252a9ceb1f8a4c06aa2cb89 Mon Sep 17 00:00:00 2001 From: hasansezertasan Date: Tue, 28 May 2024 02:03:21 +0300 Subject: [PATCH 4/6] Remove ending commas --- src/python-fastui/tests/test_tables_display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python-fastui/tests/test_tables_display.py b/src/python-fastui/tests/test_tables_display.py index 43bdd922..05b161f5 100644 --- a/src/python-fastui/tests/test_tables_display.py +++ b/src/python-fastui/tests/test_tables_display.py @@ -45,7 +45,7 @@ def test_table_columns(): assert table.model_dump(by_alias=True, exclude_none=True) == { 'data': [ {'id': 1, 'name': 'john', 'representation': '1: john'}, - {'id': 2, 'name': 'jack', 'representation': '2: jack'}, + {'id': 2, 'name': 'jack', 'representation': '2: jack'} ], 'columns': [ {'title': 'ID', 'field': 'id'}, From 3e09fd8a8124051339847cc705703cf31ed20471 Mon Sep 17 00:00:00 2001 From: hasansezertasan Date: Tue, 28 May 2024 02:06:33 +0300 Subject: [PATCH 5/6] Linted and formatted with make commands. --- src/python-fastui/tests/test_tables_display.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python-fastui/tests/test_tables_display.py b/src/python-fastui/tests/test_tables_display.py index 05b161f5..d01a8e86 100644 --- a/src/python-fastui/tests/test_tables_display.py +++ b/src/python-fastui/tests/test_tables_display.py @@ -24,7 +24,7 @@ def test_table_no_columns(): assert table.model_dump(by_alias=True, exclude_none=True) == { 'data': [ {'id': 1, 'name': 'john', 'representation': '1: john'}, - {'id': 2, 'name': 'jack', 'representation': '2: jack'} + {'id': 2, 'name': 'jack', 'representation': '2: jack'}, ], 'columns': [{'field': 'id'}, {'field': 'name', 'title': 'Name'}, {'field': 'representation'}], 'type': 'Table', @@ -45,7 +45,7 @@ def test_table_columns(): assert table.model_dump(by_alias=True, exclude_none=True) == { 'data': [ {'id': 1, 'name': 'john', 'representation': '1: john'}, - {'id': 2, 'name': 'jack', 'representation': '2: jack'} + {'id': 2, 'name': 'jack', 'representation': '2: jack'}, ], 'columns': [ {'title': 'ID', 'field': 'id'}, From b7a01b9f31e618119ca47a5822c030a2a57d5143 Mon Sep 17 00:00:00 2001 From: hasansezertasan Date: Tue, 28 May 2024 02:08:15 +0300 Subject: [PATCH 6/6] Add title to computed_field for coverage. --- src/python-fastui/tests/test_tables_display.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/python-fastui/tests/test_tables_display.py b/src/python-fastui/tests/test_tables_display.py index d01a8e86..c1c2274b 100644 --- a/src/python-fastui/tests/test_tables_display.py +++ b/src/python-fastui/tests/test_tables_display.py @@ -8,7 +8,7 @@ class User(BaseModel): id: int name: str = Field(title='Name') - @computed_field + @computed_field(title='Representation') @property def representation(self) -> str: return f'{self.id}: {self.name}' @@ -26,7 +26,11 @@ def test_table_no_columns(): {'id': 1, 'name': 'john', 'representation': '1: john'}, {'id': 2, 'name': 'jack', 'representation': '2: jack'}, ], - 'columns': [{'field': 'id'}, {'field': 'name', 'title': 'Name'}, {'field': 'representation'}], + 'columns': [ + {'field': 'id'}, + {'field': 'name', 'title': 'Name'}, + {'field': 'representation', 'title': 'Representation'}, + ], 'type': 'Table', } @@ -50,7 +54,7 @@ def test_table_columns(): 'columns': [ {'title': 'ID', 'field': 'id'}, {'title': 'Name', 'field': 'name'}, - {'field': 'representation'}, + {'title': 'Representation', 'field': 'representation'}, ], 'type': 'Table', } @@ -70,7 +74,7 @@ def test_table_empty_data_model(): 'columns': [ {'field': 'id'}, {'title': 'Name', 'field': 'name'}, - {'field': 'representation'}, + {'title': 'Representation', 'field': 'representation'}, ], 'type': 'Table', }