Skip to content

Commit

Permalink
feat: raise helpful error if from_column used for LocTitle
Browse files Browse the repository at this point in the history
machow committed Dec 13, 2023

Verified

This commit was signed with the committer’s verified signature.
1 parent 672085f commit 4e593ad
Showing 4 changed files with 59 additions and 16 deletions.
5 changes: 5 additions & 0 deletions great_tables/_locations.py
Original file line number Diff line number Diff line change
@@ -366,6 +366,11 @@ def set_style(loc: Loc, data: GTData, style: List[str]) -> GTData:

@set_style.register
def _(loc: LocTitle, data: GTData, style: List[CellStyle]) -> GTData:
# validate ----
for entry in style:
entry._raise_if_has_from_column(loc)

# set ----
if loc.groups == "title":
info = StyleInfo(locname="title", locnum=1, styles=style)
elif loc.groups == "subtitle":
48 changes: 32 additions & 16 deletions great_tables/_styles.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from __future__ import annotations

from dataclasses import dataclass, fields, replace
from typing import Any, Callable, Literal, List
from typing import TYPE_CHECKING, Any, Callable, Literal, List
from typing_extensions import Self

from ._tbl_data import TblData, _get_cell


if TYPE_CHECKING:
from ._locations import Loc


# Cell Styles ==========================================================================
# TODO: stubbed out the styles in helpers.R as dataclasses while I was reading it,
# but have no worked on any runtime validation, etc..
@@ -69,6 +73,16 @@ def _from_row(self, data: TblData, row: int) -> Self:

return replace(self, **new_fields)

def _raise_if_has_from_column(self, loc: Loc):
for field in fields(self):
attr = getattr(self, field.name)
if isinstance(attr, FromColumn):
raise TypeError(
f"Location type {type(loc)} cannot use FromColumn."
f"\n\nStyle type: {type(self)}"
f"\nField with FromColumn: {field.name}"
)


@dataclass
class CellStyleText(CellStyle):
@@ -129,12 +143,12 @@ class CellStyleText(CellStyle):
"""

color: str | FromColumn | None = None
font: str | None = None
size: str | None = None
align: Literal["center", "left", "right", "justify"] | None = None
v_align: Literal["middle", "top", "bottom"] | None = None
style: Literal["normal", "italic", "oblique"] | None = None
weight: Literal["normal", "bold", "bolder", "lighter"] | None = None
font: str | FromColumn | None = None
size: str | FromColumn | None = None
align: Literal["center", "left", "right", "justify"] | FromColumn | None = None
v_align: Literal["middle", "top", "bottom"] | FromColumn | None = None
style: Literal["normal", "italic", "oblique"] | FromColumn | None = None
weight: Literal["normal", "bold", "bolder", "lighter"] | FromColumn | None = None
stretch: Literal[
"normal",
"condensed",
@@ -145,12 +159,14 @@ class CellStyleText(CellStyle):
"expanded",
"extra-expanded",
"ultra-expanded",
] | None = None
decorate: Literal["overline", "line-through", "underline", "underline overline"] | None = None
transform: Literal["uppercase", "lowercase", "capitalize"] | None = None
] | FromColumn | None = None
decorate: Literal[
"overline", "line-through", "underline", "underline overline"
] | FromColumn | None = None
transform: Literal["uppercase", "lowercase", "capitalize"] | FromColumn | None = None
whitespace: Literal[
"normal", "nowrap", "pre", "pre-wrap", "pre-line", "break-spaces"
] | None = None
] | FromColumn | None = None

def _to_html_style(self) -> str:
rendered = ""
@@ -202,7 +218,7 @@ class CellStyleFill(CellStyle):
value.
"""

color: str
color: str | FromColumn
# alpha: Optional[float] = None

def _to_html_style(self) -> str:
@@ -241,10 +257,10 @@ class CellStyleBorders(CellStyle):

sides: Literal["all", "top", "bottom", "left", "right"] | List[
Literal["all", "top", "bottom", "left", "right"]
] = "all"
color: str = "#000000"
style: str = "solid"
weight: str = "1px"
] | FromColumn = "all"
color: str | FromColumn = "#000000"
style: str | FromColumn = "solid"
weight: str | FromColumn = "1px"

def _to_html_style(self) -> str:
# If sides is an empty list, return an empty string
9 changes: 9 additions & 0 deletions tests/__snapshots__/test_locations.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# serializer version: 1
# name: test_set_style_loc_title_from_column_error
'''
Location type <class 'great_tables._locations.LocTitle'> cannot use FromColumn.

Style type: <class 'great_tables._styles.CellStyleText'>
Field with FromColumn: color
'''
# ---
13 changes: 13 additions & 0 deletions tests/test_locations.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
from great_tables._locations import (
LocColumnSpanners,
LocBody,
LocTitle,
CellPos,
resolve,
resolve_vector_i,
@@ -104,3 +105,15 @@ def test_set_style_loc_body_from_column():
assert len(cell_info.styles) == 1
assert isinstance(cell_info.styles[0], CellStyleText)
assert cell_info.styles[0].color == "blue"


def test_set_style_loc_title_from_column_error(snapshot):
df = pd.DataFrame({"x": [1, 2], "color": ["red", "blue"]})
gt_df = GT(df)
loc = LocTitle("title")
style = CellStyleText(color=FromColumn("color"))

with pytest.raises(TypeError) as exc_info:
set_style(loc, gt_df, [style])

assert snapshot == exc_info.value.args[0]

0 comments on commit 4e593ad

Please sign in to comment.