Skip to content

Commit ca4160b

Browse files
committed
[table] Improve column name support
Use __set_name__ instead of explicitly passing name to .cell(), and use self.attribute if present.
1 parent 95f5e66 commit ca4160b

File tree

3 files changed

+33
-16
lines changed

3 files changed

+33
-16
lines changed

src/bootlace/table/base.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,19 @@ def __tag__(self) -> tags.html_tag:
3030
@attrs.define
3131
class ColumnBase(ABC):
3232
heading: Heading = attrs.field(converter=maybe(Heading)) # type: ignore
33-
attribute: str | None = None
33+
_attribute: str | None = None
34+
35+
def __set_name__(self, owner: type, name: str) -> None:
36+
self._attribute = self._attribute or name
37+
38+
@property
39+
def attribute(self) -> str:
40+
if self._attribute is None:
41+
raise ValueError("column must be named in Table or attribute= parameter must be provided")
42+
return self._attribute
3443

3544
@abstractmethod
36-
def cell(self, name: str, value: Any) -> tags.html_tag:
45+
def cell(self, value: Any) -> tags.html_tag:
3746
raise NotImplementedError("Subclasses must implement this method")
3847

3948

@@ -106,8 +115,8 @@ def render(self, items: list[Any]) -> tags.html_tag:
106115
for item in items:
107116
id = getattr(item, "id", None)
108117
tr = tags.tr(id=f"item-{id}" if id else None)
109-
for column_name, column in self.columns.items():
110-
td = column.cell(column_name, item)
118+
for column in self.columns.values():
119+
td = column.cell(item)
111120
tr.add(td)
112121
tbody.add(tr)
113122
table.add(tbody)

src/bootlace/table/columns.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@
1212
@attrs.define
1313
class Column(ColumnBase):
1414

15-
def cell(self, name: str, value: Any) -> tags.html_tag:
16-
return tags.td(getattr(value, name))
15+
def cell(self, value: Any) -> tags.html_tag:
16+
return tags.td(getattr(value, self.attribute))
1717

1818

1919
@attrs.define
2020
class EditColumn(ColumnBase):
2121
endpoint: str = attrs.field(default=".edit")
2222

23-
def cell(self, name: str, value: Any) -> tags.html_tag:
23+
def cell(self, value: Any) -> tags.html_tag:
2424
id = getattr(value, "id", None)
25-
return tags.td(tags.a(getattr(value, name), href=url_for(self.endpoint, id=id)))
25+
return tags.td(tags.a(getattr(value, self.attribute), href=url_for(self.endpoint, id=id)))
2626

2727

2828
@attrs.define
@@ -31,14 +31,14 @@ class CheckColumn(ColumnBase):
3131
yes: Icon = attrs.field(default=Icon("check", width=16, height=16))
3232
no: Icon = attrs.field(default=Icon("x", width=16, height=16))
3333

34-
def cell(self, name: str, value: Any) -> tags.html_tag:
35-
if getattr(value, name):
34+
def cell(self, value: Any) -> tags.html_tag:
35+
if getattr(value, self.attribute):
3636
return tags.td(as_tag(self.yes))
3737
return tags.td(as_tag(self.no))
3838

3939

4040
@attrs.define
4141
class Datetime(ColumnBase):
4242

43-
def cell(self, name: str, value: Any) -> tags.html_tag:
44-
return tags.td(getattr(value, name).isoformat())
43+
def cell(self, value: Any) -> tags.html_tag:
44+
return tags.td(getattr(value, self.attribute).isoformat())

tests/table/test_columns.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ class Item:
2424
when: dt.datetime = dt.datetime(2021, 1, 1, 12, 18, 5)
2525

2626

27+
def test_unnamed_column() -> None:
28+
29+
col = EditColumn(heading="Edit", endpoint="index")
30+
31+
with pytest.raises(ValueError):
32+
col.attribute
33+
34+
2735
@pytest.mark.usefixtures("homepage")
2836
def test_edit_column(app: Flask) -> None:
2937

@@ -34,7 +42,7 @@ def test_edit_column(app: Flask) -> None:
3442
assert str(th) == "<span>Edit</span>"
3543

3644
with app.test_request_context("/"):
37-
td = col.cell("editor", Item())
45+
td = col.cell(Item())
3846

3947
expected = '<td><a href="/?id=1">editor</a></td>'
4048

@@ -46,7 +54,7 @@ def test_check_column(app: Flask) -> None:
4654
col = CheckColumn(heading="Check", attribute="check")
4755

4856
with app.test_request_context("/"):
49-
td = col.cell("check", Item())
57+
td = col.cell(Item())
5058

5159
expected = f"""
5260
<td>
@@ -56,7 +64,7 @@ def test_check_column(app: Flask) -> None:
5664
</td>"""
5765

5866
with app.test_request_context("/"):
59-
td = col.cell("check", Item(check=False))
67+
td = col.cell(Item(check=False))
6068

6169
expected = f"""
6270
<td>
@@ -84,7 +92,7 @@ def test_datetime_column(app: Flask) -> None:
8492

8593
assert_same_html(expected_heading, str(th))
8694

87-
td = col.cell("when", Item())
95+
td = col.cell(Item())
8896

8997
expected = "<td>2021-01-01T12:18:05</td>"
9098

0 commit comments

Comments
 (0)