Skip to content

Commit

Permalink
[table] Improve column name support
Browse files Browse the repository at this point in the history
Use __set_name__ instead of explicitly passing name to .cell(), and use self.attribute if present.
  • Loading branch information
alexrudy committed Mar 21, 2024
1 parent 95f5e66 commit ca4160b
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 16 deletions.
17 changes: 13 additions & 4 deletions src/bootlace/table/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@ def __tag__(self) -> tags.html_tag:
@attrs.define
class ColumnBase(ABC):
heading: Heading = attrs.field(converter=maybe(Heading)) # type: ignore
attribute: str | None = None
_attribute: str | None = None

def __set_name__(self, owner: type, name: str) -> None:
self._attribute = self._attribute or name

@property
def attribute(self) -> str:
if self._attribute is None:
raise ValueError("column must be named in Table or attribute= parameter must be provided")
return self._attribute

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


Expand Down Expand Up @@ -106,8 +115,8 @@ def render(self, items: list[Any]) -> tags.html_tag:
for item in items:
id = getattr(item, "id", None)
tr = tags.tr(id=f"item-{id}" if id else None)
for column_name, column in self.columns.items():
td = column.cell(column_name, item)
for column in self.columns.values():
td = column.cell(item)
tr.add(td)
tbody.add(tr)
table.add(tbody)
Expand Down
16 changes: 8 additions & 8 deletions src/bootlace/table/columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
@attrs.define
class Column(ColumnBase):

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


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

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


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

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


@attrs.define
class Datetime(ColumnBase):

def cell(self, name: str, value: Any) -> tags.html_tag:
return tags.td(getattr(value, name).isoformat())
def cell(self, value: Any) -> tags.html_tag:
return tags.td(getattr(value, self.attribute).isoformat())
16 changes: 12 additions & 4 deletions tests/table/test_columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ class Item:
when: dt.datetime = dt.datetime(2021, 1, 1, 12, 18, 5)


def test_unnamed_column() -> None:

col = EditColumn(heading="Edit", endpoint="index")

with pytest.raises(ValueError):
col.attribute


@pytest.mark.usefixtures("homepage")
def test_edit_column(app: Flask) -> None:

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

with app.test_request_context("/"):
td = col.cell("editor", Item())
td = col.cell(Item())

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

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

with app.test_request_context("/"):
td = col.cell("check", Item())
td = col.cell(Item())

expected = f"""
<td>
Expand All @@ -56,7 +64,7 @@ def test_check_column(app: Flask) -> None:
</td>"""

with app.test_request_context("/"):
td = col.cell("check", Item(check=False))
td = col.cell(Item(check=False))

expected = f"""
<td>
Expand Down Expand Up @@ -84,7 +92,7 @@ def test_datetime_column(app: Flask) -> None:

assert_same_html(expected_heading, str(th))

td = col.cell("when", Item())
td = col.cell(Item())

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

Expand Down

0 comments on commit ca4160b

Please sign in to comment.