Skip to content

Commit 5fcb4a1

Browse files
committed
feat(Table): define row_attrs property
It's both a getter and setter! closes #76
1 parent 4382adc commit 5fcb4a1

4 files changed

Lines changed: 128 additions & 1 deletion

File tree

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Unreleased
22
----------
3+
- Feat: ``Table`` objects now have ``row_attrs`` property.
34
- Fixed: Infinite loop on parsing tables containing ``\r``. (this is just to prevent infinite loop, CRLF line endings are not supported)
45

56
v0.49.4

tests/test_table.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,3 +572,94 @@ def test_partially_invalid_table(): # 107
572572
def test_data_with_carriage_return(): # 107
573573
# this used to hang
574574
assert Table('{|\n}\n\r').data() == [[]]
575+
576+
577+
def test_row_attrs_getter():
578+
# simple case
579+
assert Table(
580+
'{|\n'
581+
'|- style="background: black;"\n'
582+
'| cell1\n'
583+
'|- style="background: white;"\n'
584+
'| cell2\n'
585+
'|}'
586+
).row_attrs == [
587+
{'style': 'background: black;'},
588+
{'style': 'background: white;'},
589+
]
590+
591+
# multiple attrs on a row
592+
assert Table(
593+
'{|\n'
594+
'|-style="color: red;" bgcolor=yellow"\n'
595+
'| cell1\n'
596+
'|}'
597+
).row_attrs == [
598+
{'style': 'color: red;', 'bgcolor': 'yellow'},
599+
]
600+
601+
# test middle row with no attrs
602+
assert Table(
603+
'{|\n'
604+
'|- style="background: black;"\n'
605+
'| cell1\n'
606+
'|-\n'
607+
'| cell2\n'
608+
'|- style="background: white;"\n'
609+
'| cell3\n'
610+
'|}'
611+
).row_attrs == [
612+
{'style': 'background: black;'},
613+
{},
614+
{'style': 'background: white;'},
615+
]
616+
617+
618+
def test_row_attrs_containing_comment():
619+
assert Table(
620+
'{|\n'
621+
'|- style="color: red;" <!--comment--> bgcolor=yellow\n'
622+
'| cell1\n'
623+
'|}'
624+
).row_attrs == [
625+
{'style': 'color: red;', 'bgcolor': 'yellow'},
626+
]
627+
628+
629+
def test_row_attrs_containing_template():
630+
assert Table(
631+
'{|\n'
632+
'|- style={{text|"color: red;"}}\n'
633+
'| cell1\n'
634+
'|}'
635+
).row_attrs == [
636+
{'style': '{{text|"color: red;"}}'},
637+
]
638+
639+
640+
def test_row_attrs_setter():
641+
table = Table(
642+
'{|\n'
643+
'|- style="background: black;"\n'
644+
'| cell1\n'
645+
'|-\n'
646+
'| cell2\n'
647+
'|- style="background: white;"\n'
648+
'| cell3\n'
649+
'|}'
650+
)
651+
table.row_attrs = [
652+
{'style': 'color: white;'},
653+
{'style': 'color: black;'},
654+
{},
655+
]
656+
assert table.string == (
657+
'{|\n'
658+
'|- style="color: white;"\n'
659+
'| cell1\n'
660+
'|- style="color: black;"\n'
661+
'| cell2\n'
662+
'|-\n'
663+
'| cell3\n'
664+
'|}'
665+
)

wikitextparser/_spans.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@
123123
# HTML tags
124124
# Tags:
125125
# https://infra.spec.whatwg.org/#ascii-whitespace
126-
SPACE_CHARS = rb' \t\n\u000C\r' # \s - \v
126+
# \0 was added as a special case for wikitextparser
127+
SPACE_CHARS = rb' \t\n\u000C\r\0' # \s - \v
127128
# http://stackoverflow.com/a/93029/2705757
128129
# chrs = (chr(i) for i in range(sys.maxunicode))
129130
# control_chars = ''.join(c for c in chrs if unicodedata.category(c) == 'Cc')

wikitextparser/_table.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
(?:\n[\|\!]|\|\|)
3838
""", DOTALL | VERBOSE).match
3939
T = TypeVar('T')
40+
FIND_ROWS = rc(rb'\|-(.*)').finditer
4041

4142

4243
HEAD_DIGITS = rc(rb'\s*+\d+').match
@@ -312,6 +313,39 @@ def caption_attrs(self, attrs: str) -> None:
312313
if end != -1:
313314
self[m.end('preattrs'):end] = attrs
314315

316+
@property
317+
def row_attrs(self) -> list[dict]:
318+
"""Row attributes.
319+
320+
Use the setter of this property to set attributes for all rows.
321+
Note that it will overwrite all the existing attr values.
322+
"""
323+
shadow = self._table_shadow
324+
string = self.string
325+
attrs = []
326+
append = attrs.append
327+
for row_match in FIND_ROWS(shadow):
328+
s, e = row_match.span(1)
329+
spans = ATTRS_MATCH(shadow, s, e).spans
330+
append({
331+
string[ns: ne]: string[vs: ve]
332+
for (ns, ne), (vs, ve) in
333+
zip(spans('attr_name'), spans('attr_value'))
334+
})
335+
return attrs
336+
337+
@row_attrs.setter
338+
def row_attrs(self, attrs: list[dict]):
339+
for row_match, attrs_dict in reversed(
340+
[*zip(FIND_ROWS(self._table_shadow), attrs)]
341+
):
342+
s, e = row_match.span(1)
343+
del self[s: e]
344+
self.insert(s, ''.join([
345+
f' {name}="{value}"' if value else f' {name}'
346+
for name, value in attrs_dict.items()
347+
]))
348+
315349

316350
def _apply_attr_spans(
317351
table_attrs: List[List[Dict[str, str]]], table_data: List[List[T]]

0 commit comments

Comments
 (0)