Coverage for src / lexigram / admin / ui / columns / column / base.py: 88%
48 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-11 17:07 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-11 17:07 +0800
1"""
2Base Column class with core functionality.
3"""
5from __future__ import annotations
7from abc import ABC, abstractmethod
8from typing import TYPE_CHECKING, Any
10if TYPE_CHECKING:
11 from collections.abc import Callable
14class Column(ABC):
15 """Base class for all table columns with fluent API.
17 This class implements the Builder pattern, allowing configuration
18 through method chaining. All configuration methods return `self`
19 to enable fluent syntax.
21 Attributes:
22 name: Column field name (supports nested fields like "user.name")
23 label: Display label for column header
25 Example:
26 >>> column = TextColumn("name").sortable().searchable()
27 >>> column = DateColumn("created_at").datetime().relative()
28 """
30 def __init__(self, name: str, label: str | None = None):
31 """
32 Initialize a column.
34 Args:
35 name: Column field name (database column). Supports nested
36 fields using dot notation (e.g., "user.email")
37 label: Display label (defaults to title-cased name)
38 """
39 self.name = name
40 self.label = label or name.replace("_", " ").title()
41 self._sortable = False
42 self._searchable = False
43 self._toggleable = True
44 self._copyable = False
45 self._filterable = False
46 self._filter_instance = None # Store Filter instance
47 self._exportable = True
48 self._limit = None
49 self._wrap = False
50 self._alignment = "left"
51 self._width: int | None = None
52 self._tooltip: str | None = None
53 self._format_callback: Callable | None = None
54 self._visible = True
55 self._visible_callback: Callable | None = None
56 self._visibility_classes: list[str] = []
57 self._pinned: str | None = None # 'left' or 'right'
58 self._masker: Callable[[Any], str] | None = None
60 def get_value(self, record: dict) -> Any:
61 """Extract value from record."""
62 # Support nested keys like "user.name"
63 keys = self.name.split(".")
64 value = record
65 for key in keys:
66 if isinstance(value, dict):
67 value = value.get(key) # type: ignore[assignment]
68 else:
69 value = getattr(value, key, None)
70 if value is None:
71 break
72 return value
74 def is_searchable(self) -> bool:
75 """Check if this column is searchable."""
76 return self._searchable
78 def is_sortable(self) -> bool:
79 """Check if this column is sortable."""
80 return self._sortable
82 def get_filter_instance(self) -> Any:
83 """Get the filter instance associated with this column."""
84 return self._filter_instance
86 def format_value(self, value: Any) -> Any:
87 """
88 Format the value using the configured format callback.
90 Args:
91 value: The raw value from the record
93 Returns:
94 Formatted value
95 """
96 if self._format_callback:
97 return self._format_callback(value)
98 return value
100 @abstractmethod
101 def render(self, value: Any, record: dict) -> Any:
102 """
103 Render the column value as HTML.
104 """
107AbstractColumn = Column