Skip to content

Commit faa77f3

Browse files
authored
Merge pull request #38 from posit-dev/String-literal-ValueErrors
Throw string literal value errors when an invalid string is passed to a Literal[str] param
2 parents 8891f28 + 4a65d3e commit faa77f3

File tree

9 files changed

+103
-30
lines changed

9 files changed

+103
-30
lines changed

gt_extras/colors.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ def gt_highlight_cols(
8484
gte.gt_highlight_cols(gt, columns="hp")
8585
```
8686
"""
87+
# Throw if `font_weight` is not one of the allowed values
88+
if isinstance(font_weight, str):
89+
if font_weight not in ["normal", "bold", "bolder", "lighter"]:
90+
raise ValueError("Font_weight must be one of 'normal', 'bold', 'bolder', or 'lighter', or an integer")
91+
elif not isinstance(font_weight, (int, float)):
92+
raise TypeError("Font_weight must be an int, float, or str")
93+
8794
if alpha:
8895
fill = _html_color(colors=[fill], alpha=alpha)[0]
8996

gt_extras/html.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def with_tooltip(
7070
An HTML string containing the formatted tooltip element.
7171
"""
7272

73-
# Throw if `text_decoration_style` is not one of the three allowed values
73+
# Throw if `text_decoration_style` is not one of the allowed values
7474
if text_decoration_style not in [None, "solid", "dotted"]:
7575
raise ValueError("Text_decoration_style must be one of `None`, 'solid', or 'dotted'")
7676

gt_extras/icons.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ def fa_icon_repeat(
105105
--------
106106
See `icon_svg()` in the `faicons` package for further implementation details.
107107
"""
108+
# Throw if `a11y` is not one of the allowed values
109+
if a11y not in [None, "deco", "sem"]:
110+
raise ValueError("A11y must be one of `None`, 'deco', or 'sem'")
111+
108112
if repeats < 0:
109113
raise ValueError("repeats must be >= 0")
110114

gt_extras/plotting.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ def gt_plt_bar(
114114
"""
115115
# A version with svg.py
116116

117+
# Throw if `scale_type` is not one of the allowed values
118+
if scale_type not in [None, "percent", "number"]:
119+
raise ValueError("Scale_type must be one of `None`, 'percent', or 'number'")
120+
117121
if bar_height > height:
118122
bar_height = height
119123
warnings.warn(
@@ -186,7 +190,7 @@ def _make_bar_html(
186190
if stroke_color is None:
187191
stroke_color = "#FFFFFF00"
188192

189-
def make_bar(scaled_val: int, original_val: int) -> str:
193+
def _make_bar(scaled_val: int, original_val: int) -> str:
190194
return _make_bar_html(
191195
scaled_val=scaled_val,
192196
original_val=original_val,
@@ -215,7 +219,7 @@ def make_bar(scaled_val: int, original_val: int) -> str:
215219
# Apply the scaled value for each row, so the bar is proportional
216220
for i, scaled_val in enumerate(scaled_vals):
217221
res = res.fmt(
218-
lambda original_val, scaled_val=scaled_val: make_bar(
222+
lambda original_val, scaled_val=scaled_val: _make_bar(
219223
original_val=original_val,
220224
scaled_val=scaled_val,
221225
),

gt_extras/tests/test_colors.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ def test_gt_highlight_cols_alpha(mini_gt):
2222
assert "#80bcd833" in html
2323

2424

25+
def test_gt_highlight_cols_font_weight_invalid_string(mini_gt):
26+
with pytest.raises(
27+
ValueError,
28+
match="Font_weight must be one of 'normal', 'bold', 'bolder', or 'lighter', or an integer",
29+
):
30+
gt_highlight_cols(mini_gt, font_weight="invalid")
31+
32+
33+
@pytest.mark.parametrize("invalid_weight", [(1.5, 5), [], {}, None])
34+
def test_gt_highlight_cols_font_weight_invalid_type(mini_gt, invalid_weight):
35+
with pytest.raises(TypeError, match="Font_weight must be an int, float, or str"):
36+
gt_highlight_cols(mini_gt, font_weight=invalid_weight)
37+
38+
2539
def test_gt_hulk_col_numeric_snap(snapshot, mini_gt):
2640
res = gt_hulk_col_numeric(mini_gt)
2741
assert_rendered_body(snapshot, gt=res)

gt_extras/tests/test_html.py

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,48 @@
33
from great_tables import GT
44
from gt_extras.html import gt_hyperlink, with_tooltip
55

6+
67
def test_gt_hyperlink_basic():
78
result = gt_hyperlink("Google", "https://google.com")
89
expected = '<a href="https://google.com" target="_blank">Google</a>'
910
assert result == expected
1011

12+
1113
def test_gt_hyperlink_new_tab_false():
1214
result = gt_hyperlink("Google", "https://google.com", new_tab=False)
1315
expected = '<a href="https://google.com" target="_self">Google</a>'
1416
assert result == expected
1517

18+
1619
def test_gt_hyperlink_new_tab_true():
1720
result = gt_hyperlink("GitHub", "https://github.com", new_tab=True)
1821
expected = '<a href="https://github.com" target="_blank">GitHub</a>'
1922
assert result == expected
2023

24+
2125
def test_gt_hyperlink_empty_text():
2226
result = gt_hyperlink("", "https://example.com")
2327
expected = '<a href="https://example.com" target="_blank"></a>'
2428
assert result == expected
2529

30+
2631
def test_gt_hyperlink_in_table():
27-
df = pd.DataFrame({
28-
"Name": ["Google", "GitHub"],
29-
"Link": [
30-
gt_hyperlink("Visit Google", "https://google.com"),
31-
gt_hyperlink("View GitHub", "https://github.com", new_tab=False)
32-
]
33-
})
34-
32+
df = pd.DataFrame(
33+
{
34+
"Name": ["Google", "GitHub"],
35+
"Link": [
36+
gt_hyperlink("Visit Google", "https://google.com"),
37+
gt_hyperlink("View GitHub", "https://github.com", new_tab=False),
38+
],
39+
}
40+
)
41+
3542
gt_table = GT(df)
3643
html_output = gt_table.as_raw_html()
37-
38-
assert '<a href="https://google.com" target="_blank">Visit Google</a>' in html_output
44+
45+
assert (
46+
'<a href="https://google.com" target="_blank">Visit Google</a>' in html_output
47+
)
3948
assert "https://github.com" in html_output
4049
assert 'target="_blank"' in html_output
4150
assert 'target="_self"' in html_output
@@ -46,40 +55,49 @@ def test_with_tooltip_basic():
4655
expected = '<abbr style="cursor: help; text-decoration: underline; text-decoration-style: dotted; color: blue; " title="Number One">1</abbr>'
4756
assert result == expected
4857

58+
4959
def test_with_tooltip_underline_style():
5060
result = with_tooltip("1", "Number One", text_decoration_style="solid")
5161
expected = '<abbr style="cursor: help; text-decoration: underline; text-decoration-style: solid; color: blue; " title="Number One">1</abbr>'
5262
assert result == expected
5363

64+
5465
def test_with_tooltip_underline_fail():
5566
with pytest.raises(ValueError):
5667
with_tooltip("1", "Number One", text_decoration_style="underline")
5768

69+
5870
def test_with_tooltip_no_decoration():
5971
result = with_tooltip("1", "Number One", text_decoration_style=None)
6072
expected = '<abbr style="cursor: help; text-decoration: none; color: blue; " title="Number One">1</abbr>'
6173
assert result == expected
6274

75+
6376
def test_with_tooltip_no_color():
6477
result = with_tooltip("1", "Number One", color=None)
6578
expected = '<abbr style="cursor: help; text-decoration: underline; text-decoration-style: dotted; " title="Number One">1</abbr>'
6679
assert result == expected
6780

68-
def test_with_tooltip_in_table():
69-
df = pd.DataFrame({
70-
"Number": ["1", "2"],
71-
"Description": [
72-
with_tooltip("1", "Number One"),
73-
with_tooltip("2", "Number Two", text_decoration_style="solid", color="red")
74-
]
75-
})
76-
81+
82+
def test_with_tooltip_in_table():
83+
df = pd.DataFrame(
84+
{
85+
"Number": ["1", "2"],
86+
"Description": [
87+
with_tooltip("1", "Number One"),
88+
with_tooltip(
89+
"2", "Number Two", text_decoration_style="solid", color="red"
90+
),
91+
],
92+
}
93+
)
94+
7795
html_output = GT(df).as_raw_html()
78-
96+
7997
assert 'title="Number One"' in html_output
8098
assert 'title="Number Two"' in html_output
81-
assert 'cursor: help' in html_output
82-
assert 'text-decoration-style: dotted' in html_output
83-
assert 'text-decoration-style: solid' in html_output
84-
assert 'color: blue' in html_output
85-
assert 'color: red' in html_output
99+
assert "cursor: help" in html_output
100+
assert "text-decoration-style: dotted" in html_output
101+
assert "text-decoration-style: solid" in html_output
102+
assert "color: blue" in html_output
103+
assert "color: red" in html_output

gt_extras/tests/test_icons.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,10 @@ def test_gt_fa_rating_multiple_columns():
135135

136136
assert html.count("<svg") == 20
137137
assert "out of 5" in html
138+
139+
140+
def test_fa_icon_repeat_a11y_invalid_string():
141+
with pytest.raises(
142+
ValueError, match="A11y must be one of `None`, 'deco', or 'sem'"
143+
):
144+
fa_icon_repeat(a11y="invalid")

gt_extras/tests/test_plotting.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ def test_gt_plt_bar_no_stroke_color(mini_gt):
6464
assert html.count("#FFFFFF00") == 3
6565

6666

67+
def test_gt_plt_bar_scale_type_invalid_string(mini_gt):
68+
with pytest.raises(
69+
ValueError, match="Scale_type must be one of `None`, 'percent', or 'number'"
70+
):
71+
gt_plt_bar(mini_gt, scale_type="invalid")
72+
73+
6774
def test_gt_plt_bar_type_error(mini_gt):
6875
with pytest.raises(TypeError, match="Invalid column type provided"):
6976
gt_plt_bar(gt=mini_gt, columns=["char"]).as_raw_html()

gt_extras/tests/test_themes.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,59 +22,71 @@ def test_theme_538_fonts_snap(snapshot, mini_gt):
2222
themed_gt = gt_theme_538(gt=mini_gt)
2323
assert_rendered_global_imports(snapshot, themed_gt)
2424

25+
2526
def test_theme_espn_fonts_snap(snapshot, mini_gt):
2627
themed_gt = gt_theme_espn(gt=mini_gt)
2728
assert_rendered_global_imports(snapshot, themed_gt)
2829

30+
2931
def test_theme_nytimes_fonts_snap(snapshot, mini_gt):
3032
themed_gt = gt_theme_nytimes(gt=mini_gt)
3133
assert_rendered_global_imports(snapshot, themed_gt)
3234

35+
3336
def test_theme_guardian_fonts_snap(snapshot, mini_gt):
3437
themed_gt = gt_theme_guardian(gt=mini_gt)
3538
assert_rendered_global_imports(snapshot, themed_gt)
3639

40+
3741
def test_theme_excel_fonts_snap(snapshot, mini_gt):
3842
themed_gt = gt_theme_excel(gt=mini_gt)
3943
assert_rendered_global_imports(snapshot, themed_gt)
4044

45+
4146
def test_theme_excel_color(mini_gt):
4247
themed_gt = gt_theme_excel(gt=mini_gt, color="lightblue")
4348
html = themed_gt.as_raw_html()
4449
assert "lightblue" in html
4550

51+
4652
def test_theme_dot_matrix_fonts_snap(snapshot, mini_gt):
4753
themed_gt = gt_theme_dot_matrix(gt=mini_gt)
4854
assert_rendered_global_imports(snapshot, themed_gt)
4955

56+
5057
def test_theme_dot_matrix_color(mini_gt):
5158
themed_gt = gt_theme_dot_matrix(gt=mini_gt, color="lightblue")
5259
html = themed_gt.as_raw_html()
5360
assert "lightblue" in html
5461

62+
5563
def test_theme_dark_fonts_snap(snapshot, mini_gt):
5664
themed_gt = gt_theme_dark(gt=mini_gt)
5765
assert_rendered_global_imports(snapshot, themed_gt)
5866

67+
5968
def test_theme_pff_fonts_snap(snapshot, mini_gt):
6069
themed_gt = gt_theme_pff(gt=mini_gt)
6170
assert_rendered_global_imports(snapshot, themed_gt)
6271

72+
6373
def test_theme_pff_dividers(mini_gt):
6474
themed_gt = gt_theme_pff(gt=mini_gt, divider="num")
6575
html = themed_gt.as_raw_html()
6676
print(html)
6777
assert "border-left: 2px solid lightgrey" in html
6878

79+
6980
def test_theme_pff_spanner(mini_gt):
7081
gt_with_spanner = mini_gt.tab_spanner("Spanner Label", columns=["num", "char"])
7182
themed_gt = gt_theme_pff(gt=gt_with_spanner, spanners=["Spanner Label"])
7283
html = themed_gt.as_raw_html()
73-
assert "Spanner Label" in html
84+
assert "Spanner Label" in html
7485
# This assertion ensures the blank spanner is created
7586
assert '<span class="gt_column_spanner"> </span>' in html
7687

88+
7789
def test_theme_pff_rank_col(mini_gt):
7890
themed_gt = gt_theme_pff(gt=mini_gt, rank_col="num")
7991
html = themed_gt.as_raw_html()
80-
assert "#e4e8ec" in html
92+
assert "#e4e8ec" in html

0 commit comments

Comments
 (0)