Skip to content

Commit 1dbad06

Browse files
authored
Merge pull request #220 from IndicoDataSolutions/mawelborn/fix-rowspan-colspan
Account for Row and Column Spans in ETL Output Tables
2 parents ef09df5 + f83c2ef commit 1dbad06

File tree

12 files changed

+180
-23
lines changed

12 files changed

+180
-23
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and versions match the minimum IPA version required to use functionality.
77

88

9+
## [v7.2.1] - 2025-09-09
10+
11+
### Fixed
12+
13+
- Account for row spans and column spans in ETL output tables.
14+
Affects `Table.from_dict()`, `Range.from_dict()`, and `EtlOutput.table_cell_for()`.
15+
- Narrow `AutoReviewed.changes` type to v3 result file changes,
16+
as that's the only version supported by `results` and `polling` modules.
17+
18+
919
## [v7.2.0] - 2025-06-17
1020

1121
### Added
@@ -255,6 +265,7 @@ This is the first major version release tested to work on Indico 6.X.
255265
- Row Association now also sorting on 'bbtop'.
256266

257267

268+
[v7.2.1]: https://github.com/IndicoDataSolutions/indico-toolkit-python/compare/v7.2.0...v7.2.1
258269
[v7.2.0]: https://github.com/IndicoDataSolutions/indico-toolkit-python/compare/v6.14.2...v7.2.0
259270
[v6.14.2]: https://github.com/IndicoDataSolutions/indico-toolkit-python/compare/v6.14.1...v6.14.2
260271
[v6.14.1]: https://github.com/IndicoDataSolutions/indico-toolkit-python/compare/v6.14.0...v6.14.1

indico_toolkit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
"ToolkitStaggeredLoopError",
2222
"ToolkitStatusError",
2323
)
24-
__version__ = "7.2.0"
24+
__version__ = "7.2.1"

indico_toolkit/etloutput/etloutput.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,11 @@ def table_cell_for(self, token: Token) -> "tuple[Table, Cell]":
9696
else:
9797
raise TableCellNotFoundError(f"no table contains {token!r}")
9898

99-
try:
100-
row_index = bisect_left(
101-
table.rows, token_vmid, key=lambda row: row[0].box.bottom
102-
)
103-
row = table.rows[row_index]
104-
105-
cell_index = bisect_left(row, token_hmid, key=attrgetter("box.right"))
106-
cell = row[cell_index]
107-
except (IndexError, ValueError) as error:
108-
raise TableCellNotFoundError(f"no cell contains {token!r}") from error
109-
110-
return table, cell
99+
for cell in table.cells:
100+
if (
101+
(cell.box.top <= token_vmid <= cell.box.bottom) and
102+
(cell.box.left <= token_hmid <= cell.box.right)
103+
): # fmt: skip
104+
return table, cell
105+
else:
106+
raise TableCellNotFoundError(f"no cell contains {token!r}")

indico_toolkit/etloutput/range.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ def from_dict(cell: object) -> "Range":
2121
columns = get(cell, list, "columns")
2222

2323
return Range(
24-
row=rows[0],
25-
column=columns[0],
24+
row=min(rows),
25+
column=min(columns),
2626
rowspan=len(rows),
2727
columnspan=len(columns),
2828
rows=tuple(rows),

indico_toolkit/etloutput/table.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,35 @@ def from_dict(table: object) -> "Table":
2020
"""
2121
page = get(table, int, "page_num")
2222
get(table, dict, "position")["page_num"] = page
23+
row_count = get(table, int, "num_rows")
24+
column_count = get(table, int, "num_columns")
2325

2426
cells = tuple(
2527
sorted(
2628
(Cell.from_dict(cell, page) for cell in get(table, list, "cells")),
2729
key=attrgetter("range"),
2830
)
2931
)
32+
cells_by_row_col = {
33+
(row, column): cell
34+
for cell in cells
35+
for row in cell.range.rows
36+
for column in cell.range.columns
37+
}
3038
rows = tuple(
31-
tuple(cell for cell in cells if row in cell.range.rows)
32-
for row in range(get(table, int, "num_rows"))
33-
)
39+
tuple(
40+
cells_by_row_col[row, column]
41+
for column in range(column_count)
42+
)
43+
for row in range(row_count)
44+
) # fmt: skip
3445
columns = tuple(
35-
tuple(cell for cell in cells if column in cell.range.columns)
36-
for column in range(get(table, int, "num_columns"))
37-
)
46+
tuple(
47+
cells_by_row_col[row, column]
48+
for row in range(row_count)
49+
)
50+
for column in range(column_count)
51+
) # fmt: skip
3852

3953
return Table(
4054
box=Box.from_dict(get(table, dict, "position")),

indico_toolkit/polling/autoreview.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
@dataclass
3232
class AutoReviewed:
33-
changes: "dict[str, Any] | list[dict[str, Any]]"
33+
changes: "list[dict[str, Any]]"
3434
reject: bool = False
3535
stp: bool = False
3636

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ authors = [
1212
readme = "README.md"
1313
urls = { source = "https://github.com/IndicoDataSolutions/Indico-Solutions-Toolkit" }
1414
requires-python = ">=3.10"
15-
version = "7.2.0"
15+
version = "7.2.1"
1616
dependencies = ["indico-client (>=6.14.0,<7.0.0)"]
1717

1818
[project.optional-dependencies]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"email_metadata":{},"full_text":"indico-file:///storage/submission/4725/112731/112257/full_text.txt","num_pages":1,"pages":[{"blocks":"indico-file:///storage/submission/4725/112731/112257/page_0_blocks.json","characters":"indico-file:///storage/submission/4725/112731/112257/page_0_chars.json","doc_offset":{"end":151,"start":0},"dpi":{"dpix":300,"dpiy":300},"filename":"Rowspan Colspan Sample.png","image":"indico-file:///storage/submission/4725/112731/112257/original_page_0.png","page_info":"indico-file:///storage/submission/4725/112731/112257/page_info_0.json","page_num":0,"size":{"height":3883,"width":2556},"tables":"indico-file:///storage/submission/4725/112731/112257/tables_0.json","text":"indico-file:///storage/submission/4725/112731/112257/page_0_text.txt","thumbnail":"indico-file:///storage/submission/4725/112731/112257/original_thumbnail_0.png","tokens":"indico-file:///storage/submission/4725/112731/112257/page_0_tokens.json"}]}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Rowspan / Colspan Sample
2+
Alfa Bravo Charlie Delta
3+
Echo Foxtrot Golf
4+
Hotel India Juliett
5+
Kilo Mike
6+
November Lima Oscar
7+
formatted by Markdeep 1.18_d
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"block_offset":{"end":7,"start":0},"doc_offset":{"end":7,"start":0},"page_num":0,"page_offset":{"end":7,"start":0},"position":{"bbBot":287,"bbLeft":561,"bbRight":1015,"bbTop":192,"bottom":287,"left":561,"right":1015,"top":192},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Rowspan"},{"block_offset":{"end":9,"start":8},"doc_offset":{"end":9,"start":8},"page_num":0,"page_offset":{"end":9,"start":8},"position":{"bbBot":290,"bbLeft":1070,"bbRight":1123,"bbTop":187,"bottom":290,"left":1070,"right":1123,"top":187},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"/"},{"block_offset":{"end":17,"start":10},"doc_offset":{"end":17,"start":10},"page_num":0,"page_offset":{"end":17,"start":10},"position":{"bbBot":291,"bbLeft":1158,"bbRight":1547,"bbTop":185,"bottom":291,"left":1158,"right":1547,"top":185},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Colspan"},{"block_offset":{"end":24,"start":18},"doc_offset":{"end":24,"start":18},"page_num":0,"page_offset":{"end":24,"start":18},"position":{"bbBot":288,"bbLeft":1601,"bbRight":1978,"bbTop":184,"bottom":288,"left":1601,"right":1978,"top":184},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Sample"},{"block_offset":{"end":4,"start":0},"doc_offset":{"end":29,"start":25},"page_num":0,"page_offset":{"end":29,"start":25},"position":{"bbBot":520,"bbLeft":772,"bbRight":858,"bbTop":477,"bottom":520,"left":772,"right":858,"top":477},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Alfa"},{"block_offset":{"end":10,"start":5},"doc_offset":{"end":35,"start":30},"page_num":0,"page_offset":{"end":35,"start":30},"position":{"bbBot":520,"bbLeft":1109,"bbRight":1242,"bbTop":476,"bottom":520,"left":1109,"right":1242,"top":476},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Bravo"},{"block_offset":{"end":18,"start":11},"doc_offset":{"end":43,"start":36},"page_num":0,"page_offset":{"end":43,"start":36},"position":{"bbBot":521,"bbLeft":1358,"bbRight":1523,"bbTop":475,"bottom":521,"left":1358,"right":1523,"top":475},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Charlie"},{"block_offset":{"end":24,"start":19},"doc_offset":{"end":49,"start":44},"page_num":0,"page_offset":{"end":49,"start":44},"position":{"bbBot":518,"bbLeft":1635,"bbRight":1757,"bbTop":473,"bottom":518,"left":1635,"right":1757,"top":473},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Delta"},{"block_offset":{"end":29,"start":25},"doc_offset":{"end":54,"start":50},"page_num":0,"page_offset":{"end":54,"start":50},"position":{"bbBot":697,"bbLeft":767,"bbRight":875,"bbTop":652,"bottom":697,"left":767,"right":875,"top":652},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Echo"},{"block_offset":{"end":37,"start":30},"doc_offset":{"end":62,"start":55},"page_num":0,"page_offset":{"end":62,"start":55},"position":{"bbBot":648,"bbLeft":1106,"bbRight":1269,"bbTop":592,"bottom":648,"left":1106,"right":1269,"top":592},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Foxtrot"},{"block_offset":{"end":43,"start":39},"doc_offset":{"end":68,"start":64},"page_num":0,"page_offset":{"end":68,"start":64},"position":{"bbBot":640,"bbLeft":1636,"bbRight":1727,"bbTop":597,"bottom":640,"left":1636,"right":1727,"top":597},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Golf"},{"block_offset":{"end":50,"start":45},"doc_offset":{"end":75,"start":70},"page_num":0,"page_offset":{"end":75,"start":70},"position":{"bbBot":754,"bbLeft":1106,"bbRight":1231,"bbTop":698,"bottom":754,"left":1106,"right":1231,"top":698},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Hotel"},{"block_offset":{"end":56,"start":51},"doc_offset":{"end":81,"start":76},"page_num":0,"page_offset":{"end":81,"start":76},"position":{"bbBot":748,"bbLeft":1355,"bbRight":1465,"bbTop":706,"bottom":748,"left":1355,"right":1465,"top":706},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"India"},{"block_offset":{"end":64,"start":57},"doc_offset":{"end":89,"start":82},"page_num":0,"page_offset":{"end":89,"start":82},"position":{"bbBot":749,"bbLeft":1636,"bbRight":1771,"bbTop":703,"bottom":749,"left":1636,"right":1771,"top":703},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Juliett"},{"block_offset":{"end":69,"start":65},"doc_offset":{"end":94,"start":90},"page_num":0,"page_offset":{"end":94,"start":90},"position":{"bbBot":867,"bbLeft":765,"bbRight":852,"bbTop":811,"bottom":867,"left":765,"right":852,"top":811},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Kilo"},{"block_offset":{"end":76,"start":72},"doc_offset":{"end":101,"start":97},"page_num":0,"page_offset":{"end":101,"start":97},"position":{"bbBot":857,"bbLeft":1633,"bbRight":1738,"bbTop":813,"bottom":857,"left":1633,"right":1738,"top":813},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Mike"},{"block_offset":{"end":85,"start":77},"doc_offset":{"end":110,"start":102},"page_num":0,"page_offset":{"end":110,"start":102},"position":{"bbBot":968,"bbLeft":767,"bbRight":1001,"bbTop":923,"bottom":968,"left":767,"right":1001,"top":923},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"November"},{"block_offset":{"end":90,"start":86},"doc_offset":{"end":115,"start":111},"page_num":0,"page_offset":{"end":115,"start":111},"position":{"bbBot":914,"bbLeft":1108,"bbRight":1216,"bbTop":867,"bottom":914,"left":1108,"right":1216,"top":867},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Lima"},{"block_offset":{"end":97,"start":92},"doc_offset":{"end":122,"start":117},"page_num":0,"page_offset":{"end":122,"start":117},"position":{"bbBot":963,"bbLeft":1637,"bbRight":1772,"bbTop":922,"bottom":963,"left":1637,"right":1772,"top":922},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Oscar"},{"block_offset":{"end":9,"start":0},"doc_offset":{"end":132,"start":123},"page_num":0,"page_offset":{"end":132,"start":123},"position":{"bbBot":1393,"bbLeft":2007,"bbRight":2145,"bbTop":1352,"bottom":1393,"left":2007,"right":2145,"top":1352},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"formatted"},{"block_offset":{"end":12,"start":10},"doc_offset":{"end":135,"start":133},"page_num":0,"page_offset":{"end":135,"start":133},"position":{"bbBot":1390,"bbLeft":2154,"bbRight":2187,"bbTop":1352,"bottom":1390,"left":2154,"right":2187,"top":1352},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"by"},{"block_offset":{"end":21,"start":13},"doc_offset":{"end":144,"start":136},"page_num":0,"page_offset":{"end":144,"start":136},"position":{"bbBot":1390,"bbLeft":2196,"bbRight":2342,"bbTop":1351,"bottom":1390,"left":2196,"right":2342,"top":1351},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"Markdeep"},{"block_offset":{"end":28,"start":22},"doc_offset":{"end":151,"start":145},"page_num":0,"page_offset":{"end":151,"start":145},"position":{"bbBot":1390,"bbLeft":2354,"bbRight":2448,"bbTop":1351,"bottom":1390,"left":2354,"right":2448,"top":1351},"style":{"background_color":null,"bold":null,"font_face":null,"font_size":null,"handwriting":false,"italic":null,"text_color":null,"underlined":null},"text":"1.18_d"}]

0 commit comments

Comments
 (0)