Skip to content

Commit d001bbd

Browse files
committed
Add class to pass mmCIF value through a function
Add a new class ihm.format.ChangeFuncValueFilter which is called for each selected data item and can modify the value by passing it through a given function.
1 parent c8ec9fa commit d001bbd

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

docs/format.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ The :mod:`ihm.format` Python module
2121

2222
.. autoclass:: ChangeValueFilter
2323

24+
.. autoclass:: ChangeFuncValueFilter
25+
2426
.. autoclass:: RemoveItemFilter
2527

2628
.. autoclass:: ChangeKeywordFilter

ihm/format.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,42 @@ def loop_filter(t):
753753
return loop_filter
754754

755755

756+
class ChangeFuncValueFilter(Filter):
757+
"""Change any token that sets a data item to x to be f(x).
758+
759+
For example, this could be used to perform a search and replace on
760+
a string, or match against a regex.
761+
762+
:param callable func: A function that is given the existing value
763+
of the data item, the category name (e.g. ``_atom_site``),
764+
and the keyword name (e.g. ``auth_seq_id``), and should return
765+
the new value of the data item (perhaps unchanged).
766+
767+
See :class:`Filter` for a description of the ``target`` parameter.
768+
"""
769+
def __init__(self, target, func):
770+
super().__init__(target)
771+
self.func = func
772+
773+
def filter_category(self, tok):
774+
if self.match_token_keyword(tok):
775+
tok.value = self.func(tok.value, tok.category, tok.keyword)
776+
return tok
777+
778+
def get_loop_filter(self, tok):
779+
if self.match_token_category(tok):
780+
try:
781+
keyword_index = tok.keyword_index(self.keyword)
782+
except ValueError:
783+
return
784+
785+
def loop_filter(t):
786+
item = t.items[keyword_index]
787+
item.value = self.func(item.value, tok.category, self.keyword)
788+
return t
789+
return loop_filter
790+
791+
756792
class RemoveItemFilter(Filter):
757793
"""Remove any token from the file that sets the given data item.
758794

test/test_format.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,47 @@ def test_cif_token_reader_filter(self):
11841184
_foo.baz
11851185
newa b c d
11861186
x y
1187+
""")
1188+
1189+
def test_cif_token_reader_change_func_value_filter(self):
1190+
"""Test CifTokenReader class with ChangeFuncValueFilter"""
1191+
class MyFunc:
1192+
def __init__(self):
1193+
self.calls = []
1194+
1195+
def __call__(self, value, category, keyword):
1196+
self.calls.append((value, category, keyword))
1197+
return value.upper()
1198+
1199+
cif = """
1200+
data_foo_bar
1201+
#
1202+
_cat1.bar old
1203+
#
1204+
loop_
1205+
_foo.bar
1206+
_foo.baz
1207+
a b c d
1208+
x y
1209+
"""
1210+
f = MyFunc()
1211+
r = ihm.format.CifTokenReader(StringIO(cif))
1212+
filters = [ihm.format.ChangeFuncValueFilter(".bar", f)]
1213+
tokens = list(r.read_file(filters))
1214+
new_cif = "".join(x.as_mmcif() for x in tokens)
1215+
self.assertEqual(f.calls,
1216+
[('old', '_cat1', 'bar'), ('a', '_foo', 'bar'),
1217+
('c', '_foo', 'bar'), ('x', '_foo', 'bar')])
1218+
self.assertEqual(new_cif, """
1219+
data_foo_bar
1220+
#
1221+
_cat1.bar OLD
1222+
#
1223+
loop_
1224+
_foo.bar
1225+
_foo.baz
1226+
A b C d
1227+
X y
11871228
""")
11881229

11891230
def test_cif_token_reader_replace_category_filter(self):

0 commit comments

Comments
 (0)