Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor GT.opt_all_caps() #436

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 90 additions & 43 deletions great_tables/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -893,8 +893,8 @@

locations
Which locations should undergo this text transformation? By default it includes all of
the `"column_labels"`, the `"stub"`, and the `"row_group"` locations. However, we could
just choose one or two of those.
the `loc.column_labels`, the `loc.stub"`, and the `loc.row_group` locations. However, we
could just choose one or two of those.

Returns
-------
Expand All @@ -909,7 +909,7 @@
in all row groups is transformed to all caps using the `opt_all_caps()` method.

```{python}
from great_tables import GT, exibble, md
from great_tables import GT, exibble, loc, md

(
GT(
Expand All @@ -927,51 +927,98 @@
.opt_all_caps()
)
```
`opt_all_caps()` accepts a `locations` parameter that allows us to specify which components
should be transformed. For example, if we only want to ensure that all text in the stub and all
row groups is converted to all caps:
```{python}
(
GT(
exibble[["num", "char", "currency", "row", "group"]],
rowname_col="row",
groupname_col="group"
)
.tab_header(
title=md("Data listing from **exibble**"),
subtitle=md("`exibble` is a **Great Tables** dataset.")
)
.fmt_number(columns="num")
.fmt_currency(columns="currency")
.tab_source_note(source_note="This is only a subset of the dataset.")
.opt_all_caps(locations=[loc.stub, loc.row_group])
)
```
"""
# Importing `great_tables._locations` at the top will cause a circular import error.
# The type annotation for `locations` should be:
# `Loc | list[Loc] = [LocColumnLabels, LocStub, LocRowGroups]`
from great_tables._locations import Loc, LocColumnLabels, LocStub, LocRowGroups

# If providing a scalar string value, normalize it to be in a list
if not isinstance(locations, list):
locations = _utils._str_scalar_to_list(cast(str, locations))

# Ensure that the `locations` value is a list of strings
_utils._assert_str_list(locations)

# TODO: Ensure that all values within `locations` are valid
if not locations:
locations = [LocColumnLabels, LocStub, LocRowGroups]

Check warning on line 957 in great_tables/_options.py

View check run for this annotation

Codecov / codecov/patch

great_tables/_options.py#L957

Added line #L957 was not covered by tests

# Set new options for `locations` selected, or, reset to default options
# if `all_caps` is False
# TODO: the code constantly reassigns res, in order to prepare for a
# world where options are not mutating the GT options object.
# TODO: is there a way to set multiple options at once?
res = self
if all_caps:
if "column_labels" in locations:
res = tab_options(res, column_labels_font_size="80%")
res = tab_options(res, column_labels_font_weight="bolder")
res = tab_options(res, column_labels_text_transform="uppercase")

if "stub" in locations:
res = tab_options(res, stub_font_size="80%")
res = tab_options(res, stub_font_weight="bolder")
res = tab_options(res, stub_text_transform="uppercase")

if "row_group" in locations:
res = tab_options(res, row_group_font_size="80%")
res = tab_options(res, row_group_font_weight="bolder")
res = tab_options(res, row_group_text_transform="uppercase")
# If providing a Loc object, normalize it to be in a list
if not isinstance(locations, list):
locations = [locations]

# Ensure that all values within `locations` are valid
# A `try-except` block is needed here because the first argument of `issubclass()` must be a
# class.
for location in locations:
try:
issubclass(location, Loc)
except TypeError as exc:
raise AssertionError(
"Only `loc.column_labels`, `loc.stub` and `loc.row_group` are allowed in the locations."
) from exc

# if `all_caps` is False, reset options to default, or, set new options
# for `locations` selected
if not all_caps:
return tab_options(

Check warning on line 977 in great_tables/_options.py

View check run for this annotation

Codecov / codecov/patch

great_tables/_options.py#L977

Added line #L977 was not covered by tests
self,
column_labels_font_size="100%",
column_labels_font_weight="normal",
column_labels_text_transform="inherit",
stub_font_size="100%",
stub_font_weight="initial",
stub_text_transform="inherit",
row_group_font_size="100%",
row_group_font_weight="initial",
row_group_text_transform="inherit",
)

else:
res = tab_options(res, column_labels_font_size="100%")
res = tab_options(res, column_labels_font_weight="normal")
res = tab_options(res, column_labels_text_transform="inherit")
res = tab_options(res, stub_font_size="100%")
res = tab_options(res, stub_font_weight="initial")
res = tab_options(res, stub_text_transform="inherit")
res = tab_options(res, row_group_font_size="100%")
res = tab_options(res, row_group_font_weight="initial")
res = tab_options(res, row_group_text_transform="inherit")
info = [
(
LocColumnLabels,
{
"column_labels_font_size": "80%",
"column_labels_font_weight": "bolder",
"column_labels_text_transform": "uppercase",
},
),
(
LocStub,
{
"stub_font_size": "80%",
"stub_font_weight": "bolder",
"stub_text_transform": "uppercase",
},
),
(
LocRowGroups,
{
"row_group_font_size": "80%",
"row_group_font_weight": "bolder",
"row_group_text_transform": "uppercase",
},
),
]
d = {}
for location, params in info:
if location in locations:
d |= params

return res
return tab_options(self, **d)


def opt_table_outline(
Expand Down
3 changes: 2 additions & 1 deletion great_tables/loc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
LocBody as body,
LocStub as stub,
LocColumnLabels as column_labels,
LocRowGroups as row_group,
)

__all__ = ("body", "stub", "column_labels")
__all__ = ("body", "stub", "column_labels", "row_group")
74 changes: 72 additions & 2 deletions tests/test_options.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pandas as pd
import pytest
from great_tables import GT, exibble, md
from great_tables import GT, exibble, loc, md
from great_tables._scss import compile_scss
from great_tables._gt_data import default_fonts_list

Expand Down Expand Up @@ -328,7 +328,6 @@ def test_scss_from_opt_table_outline(gt_tbl: GT, snapshot):


def test_opt_table_font_add_font():

gt_tbl = GT(exibble).opt_table_font(font="Arial", weight="bold", style="italic")

assert gt_tbl._options.table_font_names.value == ["Arial"] + default_fonts_list
Expand Down Expand Up @@ -369,3 +368,74 @@ def test_opt_table_font_raises():
GT(exibble).opt_table_font(font=None, stack=None)

assert "Either `font=` or `stack=` must be provided." in exc_info.value.args[0]


def test_opt_all_caps(gt_tbl: GT):
tbl = gt_tbl.opt_all_caps(locations=loc.column_labels)

assert tbl._options.column_labels_font_size.value == "80%"
assert tbl._options.column_labels_font_weight.value == "bolder"
assert tbl._options.column_labels_text_transform.value == "uppercase"

tbl = gt_tbl.opt_all_caps(locations=[loc.column_labels, loc.stub])

assert tbl._options.column_labels_font_size.value == "80%"
assert tbl._options.column_labels_font_weight.value == "bolder"
assert tbl._options.column_labels_text_transform.value == "uppercase"

assert tbl._options.stub_font_size.value == "80%"
assert tbl._options.stub_font_weight.value == "bolder"
assert tbl._options.stub_text_transform.value == "uppercase"

tbl = gt_tbl.opt_all_caps(locations=[loc.column_labels, loc.stub, loc.row_group])

assert tbl._options.column_labels_font_size.value == "80%"
assert tbl._options.column_labels_font_weight.value == "bolder"
assert tbl._options.column_labels_text_transform.value == "uppercase"

assert tbl._options.stub_font_size.value == "80%"
assert tbl._options.stub_font_weight.value == "bolder"
assert tbl._options.stub_text_transform.value == "uppercase"

assert tbl._options.row_group_font_size.value == "80%"
assert tbl._options.row_group_font_weight.value == "bolder"
assert tbl._options.row_group_text_transform.value == "uppercase"

# Activate the following tests once the circular import issue is resolved.
# tbl = gt_tbl.opt_all_caps()

# assert tbl._options.column_labels_font_size.value == "80%"
# assert tbl._options.column_labels_font_weight.value == "bolder"
# assert tbl._options.column_labels_text_transform.value == "uppercase"

# assert tbl._options.stub_font_size.value == "80%"
# assert tbl._options.stub_font_weight.value == "bolder"
# assert tbl._options.stub_text_transform.value == "uppercase"

# assert tbl._options.row_group_font_size.value == "80%"
# assert tbl._options.row_group_font_weight.value == "bolder"
# assert tbl._options.row_group_text_transform.value == "uppercase"

# tbl = gt_tbl.opt_all_caps(all_caps=False)

# assert tbl._options.column_labels_font_size.value == "100%"
# assert tbl._options.column_labels_font_weight.value == "normal"
# assert tbl._options.column_labels_text_transform.value == "inherit"

# assert tbl._options.stub_font_size.value == "100%"
# assert tbl._options.stub_font_weight.value == "initial"
# assert tbl._options.stub_text_transform.value == "inherit"

# assert tbl._options.row_group_font_size.value == "100%"
# assert tbl._options.row_group_font_weight.value == "initial"
# assert tbl._options.row_group_text_transform.value == "inherit"


def test_opt_all_caps_raises(gt_tbl: GT):
with pytest.raises(AssertionError) as exc_info:
gt_tbl.opt_all_caps(locations="column_labels")

assert (
"Only `loc.column_labels`, `loc.stub` and `loc.row_group` are allowed in the locations."
in exc_info.value.args[0]
)
Loading