Skip to content

Commit 1e6d5fd

Browse files
authored
Fix Tabulator 'starts' and 'ends' header filters (#8719)
1 parent 432007a commit 1e6d5fd

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

panel/tests/widgets/test_tables.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3072,6 +3072,63 @@ def test_header_filters_categorial_dtype():
30723072
widget.filters = [{'field': 'model', 'type': 'like', 'value': 'A'}]
30733073
assert widget.current_view.size == 1
30743074

3075+
3076+
@pytest.mark.parametrize('pagination', ['local', 'remote', None])
3077+
def test_header_filter_starts(pagination):
3078+
df = pd.DataFrame({'word': ['alpha', 'alphabet', 'beta', 'Alphanumeric']})
3079+
widget = Tabulator(df, header_filters=True, pagination=pagination)
3080+
3081+
widget.filters = [{'field': 'word', 'type': 'starts', 'value': 'bet'}]
3082+
3083+
assert list(widget.current_view['word']) == ['beta']
3084+
3085+
3086+
@pytest.mark.parametrize('pagination', ['local', 'remote', None])
3087+
def test_header_filter_starts_is_case_insensitive(pagination):
3088+
df = pd.DataFrame({'word': ['alpha', 'alphabet', 'beta', 'Alphanumeric']})
3089+
widget = Tabulator(df, header_filters=True, pagination=pagination)
3090+
3091+
widget.filters = [{'field': 'word', 'type': 'starts', 'value': 'ALPHA'}]
3092+
3093+
assert list(widget.current_view['word']) == ['alpha', 'alphabet', 'Alphanumeric']
3094+
3095+
3096+
@pytest.mark.parametrize('pagination', ['local', 'remote', None])
3097+
def test_header_filter_ends(pagination):
3098+
df = pd.DataFrame({'word': ['alpha', 'alphabet', 'beta', 'Alphanumeric']})
3099+
widget = Tabulator(df, header_filters=True, pagination=pagination)
3100+
3101+
widget.filters = [{'field': 'word', 'type': 'ends', 'value': 'a'}]
3102+
3103+
assert list(widget.current_view['word']) == ['alpha', 'beta']
3104+
3105+
3106+
@pytest.mark.parametrize('pagination', ['local', 'remote', None])
3107+
def test_header_filter_ends_is_case_insensitive(pagination):
3108+
df = pd.DataFrame({'word': ['alpha', 'alphabet', 'beta', 'Alphanumeric']})
3109+
widget = Tabulator(df, header_filters=True, pagination=pagination)
3110+
3111+
widget.filters = [{'field': 'word', 'type': 'ends', 'value': 'IC'}]
3112+
3113+
assert list(widget.current_view['word']) == ['Alphanumeric']
3114+
3115+
3116+
@pytest.mark.parametrize(('op', 'value', 'expected'), [
3117+
('=', 2, [2]),
3118+
('!=', 2, [1, 3, 4]),
3119+
('<', 3, [1, 2]),
3120+
('<=', 2, [1, 2]),
3121+
('>', 2, [3, 4]),
3122+
('>=', 3, [3, 4]),
3123+
('in', [1, 3], [1, 3]),
3124+
])
3125+
def test_header_filter_comparison_operators(op, value, expected):
3126+
widget = Tabulator(pd.DataFrame({'n': [1, 2, 3, 4]}), header_filters=True)
3127+
3128+
widget.filters = [{'field': 'n', 'type': op, 'value': value}]
3129+
3130+
assert list(widget.current_view['n']) == expected
3131+
30753132
@pytest.mark.parametrize('aggs', [{}, {'Country': 'sum'}, {'Country': {'Int': 'sum', 'Float': 'mean'}}])
30763133
def test_tabulator_aggregators(document, comm, df_agg, aggs):
30773134
tabulator = Tabulator(df_agg, hierarchical=True, aggregators=aggs)

panel/widgets/tables.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,9 +608,9 @@ def _get_header_filters(self, df: pd.DataFrame) -> list[pd.Series | np.ndarray]:
608608
elif op == 'like':
609609
filters.append(col.str.contains(val, case=False, regex=False))
610610
elif op == 'starts':
611-
filters.append(col.str.startsWith(val))
611+
filters.append(col.str.lower().str.startswith(val.lower()))
612612
elif op == 'ends':
613-
filters.append(col.str.endsWith(val))
613+
filters.append(col.str.lower().str.endswith(val.lower()))
614614
elif op == 'keywords':
615615
match_all = filt_def.get(col_name, {}).get('matchAll', False)
616616
sep = filt_def.get(col_name, {}).get('separator', ' ')

0 commit comments

Comments
 (0)