Skip to content

Commit

Permalink
Add formatter and editor classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Kuethe committed Sep 24, 2024
1 parent 5e6b419 commit a7ddcf3
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 21 deletions.
17 changes: 14 additions & 3 deletions docs/examples/getting_started/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pandas as pd
from pytabulator.shiny_bindings import output_tabulator, render_tabulator
from pytabulator.tabulator import Tabulator
from pytabulator.editors import NumberEditor, StarEditor, ProgressEditor
from pytabulator.formatters import StarFormatter
from shiny import App, render, ui

app_ui = ui.page_fluid(
Expand All @@ -23,12 +25,21 @@ def tabulator():
return (
Tabulator(df)
.set_options(height=311)
.set_column_formatter_star("Pclass", 3)
.set_column_formatter_tick_cross("Survived", hozAlign="center")
# .set_column_formatter_star("Pclass", 3)
.set_column_formatter("Pclass", StarFormatter(stars=3), hoz_align="center")
.set_column_formatter_tick_cross("Survived", hoz_align="center")
# .set_column_editor("Fare", "number", dict(min=0, max=10))
.set_column_editor_number("Fare", min_=0, max_=5)
.set_column_title("Pclass", "PassengerClass")
.set_column_editor("Name", "input", hoz_align="center")
.set_column_editor(["Name", "Sex"], "input", hoz_align="center")
.set_column_editor("PassengerId", NumberEditor(min=0, max=1000, step=1))
.set_column_editor("Pclass", StarEditor())
.set_column_formatter("Fare", "progress")
.set_column_editor(
"Fare",
ProgressEditor(min=0, max=100, element_attributes=dict(title="Hey ho")),
hoz_align="left",
)
)

@render.code
Expand Down
6 changes: 4 additions & 2 deletions pytabulator/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ def as_camel_dict_recursive(snake_dict: dict) -> dict:
camel_case_dict = {}
for k, v in snake_dict.items():
if v is not None:
camel_key = snake_to_camel_case(k) if "_" in k else k

if isinstance(v, dict):
camel_case_dict[snake_to_camel_case(k)] = as_camel_dict_recursive(v)
camel_case_dict[camel_key] = as_camel_dict_recursive(v)
else:
camel_case_dict[snake_to_camel_case(k)] = v
camel_case_dict[camel_key] = v

return camel_case_dict
47 changes: 47 additions & 0 deletions pytabulator/editors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from pydantic import BaseModel

from typing import Optional

from ._utils import as_camel_dict_recursive
from enum import Enum


class Editors(Enum):
NUMBER = "number"
INPUT = "input"
STAR = "star"
PROGRESS = "progress"


class Editor(BaseModel):
@property
def name(self) -> str:
return ""

def to_dict(self) -> dict:
return as_camel_dict_recursive(self.model_dump(exclude_none=True))


class NumberEditor(Editor):
min: Optional[float] = None
max: Optional[float] = None
step: Optional[float] = None

@property
def name(self) -> str:
return Editors.NUMBER.value


class StarEditor(Editor):
@property
def name(self) -> str:
return Editors.STAR.value

class ProgressEditor(Editor):
min: Optional[float] = None
max: Optional[float] = None
element_attributes: Optional[dict] = None

@property
def name(self) -> str:
return Editors.PROGRESS.value
24 changes: 24 additions & 0 deletions pytabulator/formatters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from enum import Enum
from pydantic import BaseModel
from typing import Optional
from ._utils import as_camel_dict_recursive

class Formatters(Enum):
STAR = "star"
PROGRESS = "progress"
TICK_CROSS = "tickCross"

class Formatter(BaseModel):
def to_dict(self) -> dict:
return as_camel_dict_recursive(self.model_dump(exclude_none=True))

@property
def name(self) -> str:
return ""

class StarFormatter(Formatter):
stars: Optional[int] = None

@property
def name(self) -> str:
return Formatters.STAR.value
72 changes: 56 additions & 16 deletions pytabulator/tabulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

from .tabulator_options import TabulatorOptions
from .utils import create_columns

from .editors import Editor
from .formatters import Formatter

class Tabulator(object):
"""Tabulator
Expand Down Expand Up @@ -42,65 +43,104 @@ def _find_column(self, col_name: str) -> tuple:

return None, None

# ----- Column generics -----
def update_column(self, col_name: str, **kwargs: Any) -> Self:
# Update single column
def _update_column(self, col_name: str, **kwargs: Any) -> Self:
i, col = self._find_column(col_name)
if col is not None:
self._options.columns[i] = col | as_camel_dict_recursive(kwargs)

return self

# ----- Column generics -----
def update_column(self, col_name: str | list, **kwargs: Any) -> Self:
col_names = [col_name] if isinstance(col_name, str) else col_name
for col_name in col_names:
self._update_column(col_name, **kwargs)

return self

def set_column_formatter(
self,
col_name: str,
formatter: str,
col_name: str | list,
formatter: str | Formatter,
formatter_params: dict = None,
**kwargs: Any,
) -> Self:
if isinstance(formatter, Formatter):
formatter_name = formatter.name
formatter_params = formatter.to_dict()
else:
formatter_name = formatter

return self.update_column(
col_name,
**dict(
formatter=formatter,
formatter=formatter_name,
formatterParams=formatter_params or dict(),
**kwargs,
),
)

# ----- Column formatters -----
def set_column_editor(self, col_name: str, editor: str, editor_params: dict = None, validator: Any = None, **kwargs: Any) -> Self:
def set_column_editor(
self,
col_name: str | list,
editor: str | Editor,
editor_params: dict = None,
validator: Any = None,
**kwargs: Any,
) -> Self:
if isinstance(editor, Editor):
editor_name = editor.name
editor_params = editor.to_dict()
else:
editor_name = editor

return self.update_column(
col_name,
**dict(
editor=editor,
editor=editor_name,
editorParams=editor_params or dict(),
validator = validator,
validator=validator,
**kwargs,
),
)

def set_column_formatter_star(self, col_name: str, stars: int, **kwargs) -> Self:
# ----- Column formatters -----
def set_column_formatter_star(
self, col_name: str | list, stars: int, **kwargs
) -> Self:
formatter_params = dict(stars=stars)
self.set_column_formatter(
col_name, "star", formatter_params, hozAlign="center", **kwargs
)
return self

def set_column_formatter_tick_cross(self, col_name, **kwargs) -> Self:
def set_column_formatter_tick_cross(self, col_name: str | list, **kwargs) -> Self:
self.set_column_formatter(col_name, "tickCross", **kwargs)
return self

# ----- Column editor -----
def set_column_editor_number(self, col_name: str, min_: float = None, max_: float = None, **kwargs) -> Self:
editor_params = dict(min=min_, max=max_)
return self.set_column_editor(col_name, "number", editor_params, **kwargs)
def set_column_editor_number(
self,
col_name: str | list,
min_value: float = None,
max_value: float = None,
step: float = None,
validator=None,
**kwargs,
) -> Self:
editor_params = dict(min=min_value, max=max_value, step=step)
return self.set_column_editor(
col_name, "number", editor_params, validator, **kwargs
)

# ----- Column headers -----
def set_column_title(self, col_name: str, title: str, **kwargs) -> Self:
return self.update_column(col_name, title=title, **kwargs)

# ----- Misc -----
def set_options(self, **kwargs) -> Self:
self._options = self._options.model_copy(update = kwargs)
self._options = self._options.model_copy(update=kwargs)
return self

def to_dict(self) -> dict:
Expand Down

0 comments on commit a7ddcf3

Please sign in to comment.