Skip to content

Commit

Permalink
feat(api): support passing a format string to Table.relabel
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrist committed Mar 28, 2023
1 parent 3b0f8db commit 0583959
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
37 changes: 32 additions & 5 deletions ibis/expr/types/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1724,18 +1724,20 @@ def relabel(
self,
substitutions: Mapping[str, str]
| Callable[[str], str | None]
| str
| Literal["snake_case"],
) -> Table:
"""Rename columns in the table.
Parameters
----------
substitutions
A mapping or function from old to new column names. If a column
isn't in the mapping (or if the callable returns None) it is left
with its original name. May also pass the string ``"snake_case"``,
which will relabel all columns to use a ``snake_case`` naming
convention.
A mapping, function, or format string mapping old to new column
names. If a column isn't in the mapping (or if the callable returns
None) it is left with its original name. May also pass a format
string to rename all columns, like ``"prefix_{name}"``. Also
accepts the literal string ``"snake_case"``, which will relabel all
columns to use a ``snake_case`` naming convention.
Returns
-------
Expand Down Expand Up @@ -1790,6 +1792,17 @@ def relabel(
│ PAL0708 │ 1 │ Adelie Penguin (Pygoscelis adeliae) │
└────────────┴───────────────┴─────────────────────────────────────┘
Relabel columns using a format string
>>> t.relabel("p_{name}").head(1)
┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ p_studyName ┃ p_Sample Number ┃ p_Species ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ string │ int64 │ string │
├─────────────┼─────────────────┼─────────────────────────────────────┤
│ PAL0708 │ 1 │ Adelie Penguin (Pygoscelis adeliae) │
└─────────────┴─────────────────┴─────────────────────────────────────┘
Relabel column names using a callable
>>> t.relabel(str.upper).head(1)
Expand Down Expand Up @@ -1818,6 +1831,20 @@ def rename(c):
c = c.replace("-", "_")
return c.lower()

elif isinstance(substitutions, str):

def rename(name):
return substitutions.format(name=name)

# Detect the case of missing or extra format string parameters
try:
dummy_name1 = "_unlikely_column_name_1_"
dummy_name2 = "_unlikely_column_name_2_"
invalid = rename(dummy_name1) == rename(dummy_name2)
except KeyError:
invalid = True
if invalid:
raise ValueError("Format strings must take a single parameter `name`")
else:
rename = substitutions

Expand Down
14 changes: 14 additions & 0 deletions ibis/tests/expr/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,20 @@ def test_column_relabel():
table.relabel({"missing": "oops"})


def test_relabel_format_string():
t = ibis.table({"x": "int", "y": "int", "z": "int"})

res = t.relabel("_{name}_")
sol = t.relabel({"x": "_x_", "y": "_y_", "z": "_z_"})
assert_equal(res, sol)

with pytest.raises(ValueError, match="Format strings must"):
t.relabel("no format string parameter")

with pytest.raises(ValueError, match="Format strings must"):
t.relabel("{unknown} format string parameter")


def test_relabel_snake_case():
cases = [
("cola", "cola"),
Expand Down

0 comments on commit 0583959

Please sign in to comment.