indico_toolkit 6.14.1__tar.gz → 7.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/PKG-INFO +1 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/__init__.py +1 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/client.py +1 -1
- indico_toolkit-7.2.0/indico_toolkit/etloutput/__init__.py +157 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/etloutput/cell.py +1 -1
- indico_toolkit-7.2.0/indico_toolkit/etloutput/errors.py +16 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/etloutput/etloutput.py +27 -27
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/etloutput/range.py +1 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/etloutput/table.py +1 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/etloutput/token.py +1 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/indico_wrapper/__init__.py +0 -6
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/ocr/__init__.py +0 -2
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/polling/autoreview.py +6 -6
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/polling/downstream.py +4 -4
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/polling/queries.py +3 -3
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/__init__.py +28 -28
- indico_toolkit-7.2.0/indico_toolkit/results/document.py +57 -0
- indico_toolkit-7.2.0/indico_toolkit/results/normalization.py +82 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictionlist.py +82 -95
- indico_toolkit-7.2.0/indico_toolkit/results/predictions/__init__.py +64 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/box.py +4 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/citation.py +4 -4
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/classification.py +5 -11
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/documentextraction.py +10 -74
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/formextraction.py +15 -20
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/group.py +9 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/prediction.py +4 -10
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/span.py +1 -1
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/summarization.py +38 -13
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/unbundling.py +18 -13
- indico_toolkit-7.2.0/indico_toolkit/results/result.py +136 -0
- indico_toolkit-7.2.0/indico_toolkit/results/task.py +32 -0
- indico_toolkit-7.2.0/indico_toolkit/results/utils.py +101 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/pyproject.toml +1 -1
- indico_toolkit-6.14.1/indico_toolkit/auto_populate/__init__.py +0 -3
- indico_toolkit-6.14.1/indico_toolkit/auto_populate/populator.py +0 -362
- indico_toolkit-6.14.1/indico_toolkit/auto_populate/types.py +0 -66
- indico_toolkit-6.14.1/indico_toolkit/etloutput/__init__.py +0 -210
- indico_toolkit-6.14.1/indico_toolkit/etloutput/errors.py +0 -16
- indico_toolkit-6.14.1/indico_toolkit/indico_wrapper/dataset.py +0 -114
- indico_toolkit-6.14.1/indico_toolkit/indico_wrapper/doc_extraction.py +0 -79
- indico_toolkit-6.14.1/indico_toolkit/indico_wrapper/reviewer.py +0 -111
- indico_toolkit-6.14.1/indico_toolkit/ocr/customocr_object.py +0 -42
- indico_toolkit-6.14.1/indico_toolkit/results/document.py +0 -78
- indico_toolkit-6.14.1/indico_toolkit/results/model.py +0 -60
- indico_toolkit-6.14.1/indico_toolkit/results/normalization.py +0 -159
- indico_toolkit-6.14.1/indico_toolkit/results/predictions/__init__.py +0 -88
- indico_toolkit-6.14.1/indico_toolkit/results/result.py +0 -152
- indico_toolkit-6.14.1/indico_toolkit/results/utils.py +0 -73
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/LICENSE +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/README.md +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/association/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/association/association.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/association/extracted_tokens.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/association/line_items.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/association/positioning.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/association/splitting.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/auto_review/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/auto_review/auto_review_functions.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/auto_review/auto_reviewer.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/errors.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/indico_wrapper/download.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/indico_wrapper/indico_wrapper.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/indico_wrapper/modelop.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/indico_wrapper/workflow.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/metrics/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/metrics/compare_ground_truth.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/metrics/compare_models.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/metrics/metrics.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/metrics/plotting.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/ocr/ondoc_object.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/ocr/standard_object.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/pipelines/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/pipelines/file_processing.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/polling/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/py.typed +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/errors.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/predictions/extraction.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/results/review.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/retry.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/snapshots/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/snapshots/snapshot.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/structure/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/structure/create_structure.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/structure/queries.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/structure/utils.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/types/__init__.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/types/classification.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/types/extractions.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/types/predictions.py +0 -0
- {indico_toolkit-6.14.1 → indico_toolkit-7.2.0}/indico_toolkit/types/workflow_object.py +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, TypeAlias, TypeVar
|
|
2
|
+
|
|
3
|
+
from ..results import NULL_BOX, NULL_SPAN, Box, Span
|
|
4
|
+
from ..results.utils import get, has, json_loaded, str_decoded
|
|
5
|
+
from .cell import Cell, CellType
|
|
6
|
+
from .errors import EtlOutputError, TableCellNotFoundError, TokenNotFoundError
|
|
7
|
+
from .etloutput import EtlOutput
|
|
8
|
+
from .range import Range
|
|
9
|
+
from .table import Table
|
|
10
|
+
from .token import Token
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Awaitable, Callable
|
|
14
|
+
|
|
15
|
+
__all__ = (
|
|
16
|
+
"Box",
|
|
17
|
+
"Cell",
|
|
18
|
+
"CellType",
|
|
19
|
+
"EtlOutput",
|
|
20
|
+
"EtlOutputError",
|
|
21
|
+
"load",
|
|
22
|
+
"load_async",
|
|
23
|
+
"NULL_BOX",
|
|
24
|
+
"NULL_SPAN",
|
|
25
|
+
"Range",
|
|
26
|
+
"Span",
|
|
27
|
+
"Table",
|
|
28
|
+
"TableCellNotFoundError",
|
|
29
|
+
"Token",
|
|
30
|
+
"TokenNotFoundError",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
Loadable: TypeAlias = "dict[str, object] | list[object] | str | bytes"
|
|
34
|
+
Readable = TypeVar("Readable")
|
|
35
|
+
URI: TypeAlias = str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def load(
|
|
39
|
+
etl_output: "Loadable | Readable",
|
|
40
|
+
*,
|
|
41
|
+
reader: "Callable[[Readable | URI], Loadable]",
|
|
42
|
+
text: bool = True,
|
|
43
|
+
tokens: bool = True,
|
|
44
|
+
tables: bool = True,
|
|
45
|
+
) -> EtlOutput:
|
|
46
|
+
"""
|
|
47
|
+
Load `etl_output` as an `EtlOutput` dataclass.
|
|
48
|
+
|
|
49
|
+
`etl_output` can be a dict, JSON string/bytes, or something that can be read by
|
|
50
|
+
`reader` to produce a loadable type.
|
|
51
|
+
|
|
52
|
+
`reader` must be able to load Indico storage URIs as lists or JSON strings/bytes.
|
|
53
|
+
|
|
54
|
+
Use `text`, `tokens`, and `tables` to specify what not to load.
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
result = results.load(submission.result_file, reader=read_uri)
|
|
58
|
+
etl_outputs = {
|
|
59
|
+
document: etloutput.load(document.etl_output_uri, reader=read_uri)
|
|
60
|
+
for document in result.documents
|
|
61
|
+
if not document.failed
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
"""
|
|
65
|
+
if not isinstance(etl_output, dict):
|
|
66
|
+
if (isinstance(etl_output, str) and etl_output.startswith("{")) or (
|
|
67
|
+
isinstance(etl_output, bytes) and etl_output.startswith(b"{")
|
|
68
|
+
):
|
|
69
|
+
etl_output = json_loaded(etl_output)
|
|
70
|
+
else:
|
|
71
|
+
etl_output = json_loaded(reader(etl_output)) # type: ignore[arg-type]
|
|
72
|
+
|
|
73
|
+
pages = get(etl_output, list, "pages")
|
|
74
|
+
|
|
75
|
+
if text and has(pages, str, 0, "text"):
|
|
76
|
+
text_pages = map(
|
|
77
|
+
lambda page: str_decoded(reader(get(page, str, "text"))), pages # type: ignore[arg-type]
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
text_pages = () # type: ignore[assignment]
|
|
81
|
+
|
|
82
|
+
if tokens and has(pages, str, 0, "tokens"):
|
|
83
|
+
token_dict_pages = map(
|
|
84
|
+
lambda page: json_loaded(reader(get(page, str, "tokens"))), pages
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
token_dict_pages = () # type: ignore[assignment]
|
|
88
|
+
|
|
89
|
+
if tables and has(pages, str, 0, "tables"):
|
|
90
|
+
table_dict_pages = map(
|
|
91
|
+
lambda page: json_loaded(reader(get(page, str, "tables"))), pages
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
table_dict_pages = () # type: ignore[assignment]
|
|
95
|
+
|
|
96
|
+
return EtlOutput.from_pages(text_pages, token_dict_pages, table_dict_pages)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
async def load_async(
|
|
100
|
+
etl_output: "Loadable | Readable",
|
|
101
|
+
*,
|
|
102
|
+
reader: "Callable[[Readable | URI], Awaitable[Loadable]]",
|
|
103
|
+
text: bool = True,
|
|
104
|
+
tokens: bool = True,
|
|
105
|
+
tables: bool = True,
|
|
106
|
+
) -> EtlOutput:
|
|
107
|
+
"""
|
|
108
|
+
Load `etl_output` as an `EtlOutput` dataclass.
|
|
109
|
+
|
|
110
|
+
`etl_output` can be a dict, JSON string/bytes, or something that can be read by
|
|
111
|
+
`reader` to produce a loadable type.
|
|
112
|
+
|
|
113
|
+
`reader` must be able to load Indico storage URIs as lists or JSON strings/bytes.
|
|
114
|
+
|
|
115
|
+
Use `text`, `tokens`, and `tables` to specify what not to load.
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
result = await results.load_async(submission.result_file, reader=read_uri)
|
|
119
|
+
etl_outputs = {
|
|
120
|
+
document: await etloutput.load_async(document.etl_output_uri, reader=read_uri)
|
|
121
|
+
for document in result.documents
|
|
122
|
+
if not document.failed
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
"""
|
|
126
|
+
if not isinstance(etl_output, dict):
|
|
127
|
+
if (isinstance(etl_output, str) and etl_output.startswith("{")) or (
|
|
128
|
+
isinstance(etl_output, bytes) and etl_output.startswith(b"{")
|
|
129
|
+
):
|
|
130
|
+
etl_output = json_loaded(etl_output)
|
|
131
|
+
else:
|
|
132
|
+
etl_output = json_loaded(await reader(etl_output)) # type: ignore[arg-type]
|
|
133
|
+
|
|
134
|
+
pages = get(etl_output, list, "pages")
|
|
135
|
+
|
|
136
|
+
if text and has(pages, str, 0, "text"):
|
|
137
|
+
text_pages = [
|
|
138
|
+
str_decoded(await reader(get(page, str, "text"))) for page in pages # type: ignore[arg-type]
|
|
139
|
+
]
|
|
140
|
+
else:
|
|
141
|
+
text_pages = () # type: ignore[assignment]
|
|
142
|
+
|
|
143
|
+
if tokens and has(pages, str, 0, "tokens"):
|
|
144
|
+
token_dict_pages = [
|
|
145
|
+
json_loaded(await reader(get(page, str, "tokens"))) for page in pages
|
|
146
|
+
]
|
|
147
|
+
else:
|
|
148
|
+
token_dict_pages = () # type: ignore[assignment]
|
|
149
|
+
|
|
150
|
+
if tables and has(pages, str, 0, "tables"):
|
|
151
|
+
table_dict_pages = [
|
|
152
|
+
json_loaded(await reader(get(page, str, "tables"))) for page in pages
|
|
153
|
+
]
|
|
154
|
+
else:
|
|
155
|
+
table_dict_pages = () # type: ignore[assignment]
|
|
156
|
+
|
|
157
|
+
return EtlOutput.from_pages(text_pages, token_dict_pages, table_dict_pages)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class EtlOutputError(Exception):
|
|
2
|
+
"""
|
|
3
|
+
Raised when an error occurs accessing `EtlOutput` values.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TokenNotFoundError(EtlOutputError):
|
|
8
|
+
"""
|
|
9
|
+
Raised when a `Token` can't be found for a `Span`.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TableCellNotFoundError(EtlOutputError):
|
|
14
|
+
"""
|
|
15
|
+
Raised when a `Table` and `Cell` can't be found for a `Token`.
|
|
16
|
+
"""
|
|
@@ -28,30 +28,30 @@ class EtlOutput:
|
|
|
28
28
|
|
|
29
29
|
@staticmethod
|
|
30
30
|
def from_pages(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
text_pages: "Iterable[str]",
|
|
32
|
+
token_dict_pages: "Iterable[Iterable[object]]",
|
|
33
|
+
table_dict_pages: "Iterable[Iterable[object]]",
|
|
34
34
|
) -> "EtlOutput":
|
|
35
35
|
"""
|
|
36
|
-
Create an `EtlOutput` from
|
|
36
|
+
Create an `EtlOutput` from pages of text, tokens, and tables.
|
|
37
37
|
"""
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
text_pages = tuple(text_pages)
|
|
39
|
+
token_pages = tuple(
|
|
40
40
|
tuple(sorted(map(Token.from_dict, token_dict_page), key=attrgetter("span")))
|
|
41
|
-
for token_dict_page in
|
|
41
|
+
for token_dict_page in token_dict_pages
|
|
42
42
|
)
|
|
43
|
-
|
|
43
|
+
table_pages = tuple(
|
|
44
44
|
tuple(sorted(map(Table.from_dict, table_dict_page), key=attrgetter("box")))
|
|
45
|
-
for table_dict_page in
|
|
45
|
+
for table_dict_page in table_dict_pages
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
return EtlOutput(
|
|
49
|
-
text="\n".join(
|
|
50
|
-
text_on_page=
|
|
51
|
-
tokens=tuple(itertools.chain.from_iterable(
|
|
52
|
-
tokens_on_page=
|
|
53
|
-
tables=tuple(itertools.chain.from_iterable(
|
|
54
|
-
tables_on_page=
|
|
49
|
+
text="\n".join(text_pages),
|
|
50
|
+
text_on_page=text_pages,
|
|
51
|
+
tokens=tuple(itertools.chain.from_iterable(token_pages)),
|
|
52
|
+
tokens_on_page=token_pages,
|
|
53
|
+
tables=tuple(itertools.chain.from_iterable(table_pages)),
|
|
54
|
+
tables_on_page=table_pages,
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
def token_for(self, span: Span) -> Token:
|
|
@@ -64,21 +64,21 @@ class EtlOutput:
|
|
|
64
64
|
first = bisect_right(tokens, span.start, key=attrgetter("span.end"))
|
|
65
65
|
last = bisect_left(tokens, span.end, lo=first, key=attrgetter("span.start"))
|
|
66
66
|
tokens = tokens[first:last]
|
|
67
|
-
|
|
68
|
-
return Token(
|
|
69
|
-
text=self.text[span.slice],
|
|
70
|
-
span=span,
|
|
71
|
-
box=Box(
|
|
72
|
-
page=min(token.box.page for token in tokens),
|
|
73
|
-
top=min(token.box.top for token in tokens),
|
|
74
|
-
left=min(token.box.left for token in tokens),
|
|
75
|
-
right=max(token.box.right for token in tokens),
|
|
76
|
-
bottom=max(token.box.bottom for token in tokens),
|
|
77
|
-
),
|
|
78
|
-
)
|
|
79
67
|
except (IndexError, ValueError) as error:
|
|
80
68
|
raise TokenNotFoundError(f"no token contains {span!r}") from error
|
|
81
69
|
|
|
70
|
+
return Token(
|
|
71
|
+
text=self.text[span.slice],
|
|
72
|
+
box=Box(
|
|
73
|
+
page=span.page,
|
|
74
|
+
top=min(token.box.top for token in tokens),
|
|
75
|
+
left=min(token.box.left for token in tokens),
|
|
76
|
+
right=max(token.box.right for token in tokens),
|
|
77
|
+
bottom=max(token.box.bottom for token in tokens),
|
|
78
|
+
),
|
|
79
|
+
span=span,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
82
|
def table_cell_for(self, token: Token) -> "tuple[Table, Cell]":
|
|
83
83
|
"""
|
|
84
84
|
Return the `Table` and `Cell` that contain the midpoint of `token`.
|
|
@@ -16,7 +16,7 @@ class Table:
|
|
|
16
16
|
@staticmethod
|
|
17
17
|
def from_dict(table: object) -> "Table":
|
|
18
18
|
"""
|
|
19
|
-
Create a `Table` from a
|
|
19
|
+
Create a `Table` from a table dictionary.
|
|
20
20
|
"""
|
|
21
21
|
page = get(table, int, "page_num")
|
|
22
22
|
get(table, dict, "position")["page_num"] = page
|
|
@@ -13,7 +13,7 @@ class Token:
|
|
|
13
13
|
@staticmethod
|
|
14
14
|
def from_dict(token: object) -> "Token":
|
|
15
15
|
"""
|
|
16
|
-
Create a `Token` from a
|
|
16
|
+
Create a `Token` from a token dictionary.
|
|
17
17
|
"""
|
|
18
18
|
get(token, dict, "position")["page_num"] = get(token, int, "page_num")
|
|
19
19
|
get(token, dict, "doc_offset")["page_num"] = get(token, int, "page_num")
|
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
from .dataset import Datasets
|
|
2
|
-
from .doc_extraction import DocExtraction
|
|
3
1
|
from .download import Download
|
|
4
2
|
from .indico_wrapper import IndicoWrapper
|
|
5
|
-
from .reviewer import Reviewer
|
|
6
3
|
from .workflow import Workflow
|
|
7
4
|
|
|
8
5
|
__all__ = (
|
|
9
|
-
"Datasets",
|
|
10
|
-
"DocExtraction",
|
|
11
6
|
"Download",
|
|
12
7
|
"IndicoWrapper",
|
|
13
|
-
"Reviewer",
|
|
14
8
|
"Workflow",
|
|
15
9
|
)
|
|
@@ -3,8 +3,8 @@ import logging
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
|
-
from indico import AsyncIndicoClient, IndicoConfig
|
|
7
|
-
from indico.queries import (
|
|
6
|
+
from indico import AsyncIndicoClient, IndicoConfig
|
|
7
|
+
from indico.queries import (
|
|
8
8
|
GetSubmission,
|
|
9
9
|
JobStatus,
|
|
10
10
|
RetrieveStorageObject,
|
|
@@ -41,7 +41,7 @@ class AutoReviewPoller:
|
|
|
41
41
|
and submits the review results concurrently.
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
-
def __init__(
|
|
44
|
+
def __init__( # type: ignore[no-any-unimported]
|
|
45
45
|
self,
|
|
46
46
|
config: IndicoConfig,
|
|
47
47
|
workflow_id: int,
|
|
@@ -53,7 +53,7 @@ class AutoReviewPoller:
|
|
|
53
53
|
load_etl_output: bool = True,
|
|
54
54
|
load_text: bool = True,
|
|
55
55
|
load_tokens: bool = True,
|
|
56
|
-
load_tables: bool =
|
|
56
|
+
load_tables: bool = True,
|
|
57
57
|
retry_count: int = 4,
|
|
58
58
|
retry_wait: float = 1,
|
|
59
59
|
retry_backoff: float = 4,
|
|
@@ -96,8 +96,8 @@ class AutoReviewPoller:
|
|
|
96
96
|
*(self._reap_workers() for _ in range(self._worker_count)),
|
|
97
97
|
)
|
|
98
98
|
|
|
99
|
-
async def _retrieve_storage_object(self,
|
|
100
|
-
return await self._client_call(RetrieveStorageObject(
|
|
99
|
+
async def _retrieve_storage_object(self, uri: str) -> "Any":
|
|
100
|
+
return await self._client_call(RetrieveStorageObject(uri))
|
|
101
101
|
|
|
102
102
|
async def _spawn_workers(self) -> None:
|
|
103
103
|
"""
|
|
@@ -2,12 +2,12 @@ import asyncio
|
|
|
2
2
|
import logging
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
from indico import AsyncIndicoClient, IndicoConfig
|
|
6
|
-
from indico.queries import (
|
|
5
|
+
from indico import AsyncIndicoClient, IndicoConfig
|
|
6
|
+
from indico.queries import (
|
|
7
7
|
GetSubmission,
|
|
8
8
|
UpdateSubmission,
|
|
9
9
|
)
|
|
10
|
-
from indico.types import Submission
|
|
10
|
+
from indico.types import Submission
|
|
11
11
|
|
|
12
12
|
from ..retry import retry
|
|
13
13
|
from .queries import SubmissionIdsPendingDownstream
|
|
@@ -29,7 +29,7 @@ class DownstreamPoller:
|
|
|
29
29
|
them concurrently, and marks them as retrieved.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
def __init__(
|
|
32
|
+
def __init__( # type: ignore[no-any-unimported]
|
|
33
33
|
self,
|
|
34
34
|
config: IndicoConfig,
|
|
35
35
|
workflow_id: int,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING
|
|
2
2
|
|
|
3
|
-
from indico.queries import GraphQLRequest
|
|
3
|
+
from indico.queries import GraphQLRequest
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class SubmissionIdsPendingAutoReview(GraphQLRequest): # type: ignore[misc]
|
|
9
|
+
class SubmissionIdsPendingAutoReview(GraphQLRequest): # type: ignore[misc, no-any-unimported]
|
|
10
10
|
QUERY = """
|
|
11
11
|
query SubmissionIdsPendingAutoReview($workflowIds: [Int]) {
|
|
12
12
|
submissions(
|
|
@@ -33,7 +33,7 @@ class SubmissionIdsPendingAutoReview(GraphQLRequest): # type: ignore[misc]
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class SubmissionIdsPendingDownstream(GraphQLRequest): # type: ignore[misc]
|
|
36
|
+
class SubmissionIdsPendingDownstream(GraphQLRequest): # type: ignore[misc, no-any-unimported]
|
|
37
37
|
QUERY = """
|
|
38
38
|
query SubmissionIdsPendingDownstream($workflowIds: [Int]) {
|
|
39
39
|
submissions(
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, TypeAlias, TypeVar, overload
|
|
3
2
|
|
|
4
3
|
from .document import Document
|
|
5
4
|
from .errors import ResultError
|
|
6
|
-
from .model import ModelGroup, ModelGroupType
|
|
7
5
|
from .predictionlist import PredictionList
|
|
8
6
|
from .predictions import (
|
|
9
7
|
NULL_BOX,
|
|
@@ -23,7 +21,8 @@ from .predictions import (
|
|
|
23
21
|
)
|
|
24
22
|
from .result import Result
|
|
25
23
|
from .review import Review, ReviewType
|
|
26
|
-
from .
|
|
24
|
+
from .task import Task, TaskType
|
|
25
|
+
from .utils import json_loaded
|
|
27
26
|
|
|
28
27
|
if TYPE_CHECKING:
|
|
29
28
|
from collections.abc import Awaitable, Callable
|
|
@@ -40,8 +39,6 @@ __all__ = (
|
|
|
40
39
|
"Group",
|
|
41
40
|
"load",
|
|
42
41
|
"load_async",
|
|
43
|
-
"ModelGroup",
|
|
44
|
-
"ModelGroupType",
|
|
45
42
|
"NULL_BOX",
|
|
46
43
|
"NULL_CITATION",
|
|
47
44
|
"NULL_SPAN",
|
|
@@ -53,16 +50,24 @@ __all__ = (
|
|
|
53
50
|
"ReviewType",
|
|
54
51
|
"Span",
|
|
55
52
|
"Summarization",
|
|
53
|
+
"Task",
|
|
54
|
+
"TaskType",
|
|
56
55
|
"Unbundling",
|
|
57
56
|
)
|
|
58
57
|
|
|
58
|
+
Loadable: TypeAlias = "dict[str, object] | str | bytes"
|
|
59
|
+
Readable = TypeVar("Readable")
|
|
59
60
|
|
|
61
|
+
|
|
62
|
+
@overload
|
|
63
|
+
def load(result: Loadable) -> Result: ...
|
|
64
|
+
@overload
|
|
65
|
+
def load(result: Readable, *, reader: "Callable[[Readable], Loadable]") -> Result: ...
|
|
60
66
|
def load(result: object, *, reader: "Callable[..., object] | None" = None) -> Result:
|
|
61
67
|
"""
|
|
62
|
-
Load `result` as a Result dataclass.
|
|
68
|
+
Load `result` as a `Result` dataclass. `result` can be a dict or JSON string/bytes.
|
|
63
69
|
|
|
64
|
-
`
|
|
65
|
-
to produce either.
|
|
70
|
+
If `reader` is provided, it should read `result` to produce a loadable type.
|
|
66
71
|
|
|
67
72
|
```
|
|
68
73
|
for result_file in result_folder.glob("*.json"):
|
|
@@ -72,33 +77,28 @@ def load(result: object, *, reader: "Callable[..., object] | None" = None) -> Re
|
|
|
72
77
|
if reader:
|
|
73
78
|
result = reader(result)
|
|
74
79
|
|
|
75
|
-
return
|
|
80
|
+
return Result.from_dict(json_loaded(result))
|
|
76
81
|
|
|
77
82
|
|
|
83
|
+
@overload
|
|
84
|
+
async def load_async(result: Loadable) -> Result: ...
|
|
85
|
+
@overload
|
|
86
|
+
async def load_async(
|
|
87
|
+
result: Readable, *, reader: "Callable[[Readable], Awaitable[Loadable]]"
|
|
88
|
+
) -> Result: ...
|
|
78
89
|
async def load_async(
|
|
79
90
|
result: object, *, reader: "Callable[..., Awaitable[object]] | None" = None
|
|
80
91
|
) -> Result:
|
|
81
92
|
"""
|
|
82
|
-
Load `result` as a Result dataclass.
|
|
93
|
+
Load `result` as a `Result` dataclass. `result` can be a dict or JSON string/bytes.
|
|
94
|
+
|
|
95
|
+
If `reader` is provided, it should read `result` to produce a loadable type.
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
```
|
|
98
|
+
result = await results.load_async(submission.result_file, reader=read_uri)
|
|
99
|
+
```
|
|
86
100
|
"""
|
|
87
101
|
if reader:
|
|
88
102
|
result = await reader(result)
|
|
89
103
|
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def _load(result: object) -> Result:
|
|
94
|
-
if isinstance(result, str) and result.strip().startswith("{"):
|
|
95
|
-
result = json.loads(result)
|
|
96
|
-
|
|
97
|
-
file_version = get(result, int, "file_version")
|
|
98
|
-
|
|
99
|
-
if file_version == 1:
|
|
100
|
-
return Result.from_v1_dict(result)
|
|
101
|
-
elif file_version == 3:
|
|
102
|
-
return Result.from_v3_dict(result)
|
|
103
|
-
else:
|
|
104
|
-
raise ResultError(f"unsupported file version `{file_version!r}`")
|
|
104
|
+
return Result.from_dict(json_loaded(result))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from .utils import get
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True, order=True)
|
|
7
|
+
class Document:
|
|
8
|
+
id: int
|
|
9
|
+
name: str
|
|
10
|
+
etl_output_uri: str
|
|
11
|
+
failed: bool
|
|
12
|
+
error: str
|
|
13
|
+
traceback: str
|
|
14
|
+
|
|
15
|
+
# Auto review changes must reproduce all model and component sections that were
|
|
16
|
+
# present in the original result file. This may not be possible from the
|
|
17
|
+
# predictions alone--if a model or component had an empty section because it didn't
|
|
18
|
+
# produce predictions or if all of the predictions for that section were dropped.
|
|
19
|
+
# As such, the model and component IDs seen when parsing a result file are tracked
|
|
20
|
+
# per-document so that the empty sections can be reproduced later.
|
|
21
|
+
_model_ids: "frozenset[str]"
|
|
22
|
+
_component_ids: "frozenset[str]"
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def from_dict(document: object) -> "Document":
|
|
26
|
+
"""
|
|
27
|
+
Create a `Document` from a document dictionary.
|
|
28
|
+
"""
|
|
29
|
+
model_results = get(document, dict, "model_results", "ORIGINAL")
|
|
30
|
+
component_results = get(document, dict, "component_results", "ORIGINAL")
|
|
31
|
+
|
|
32
|
+
return Document(
|
|
33
|
+
id=get(document, int, "submissionfile_id"),
|
|
34
|
+
name=get(document, str, "input_filename"),
|
|
35
|
+
etl_output_uri=get(document, str, "etl_output"),
|
|
36
|
+
failed=False,
|
|
37
|
+
error="",
|
|
38
|
+
traceback="",
|
|
39
|
+
_model_ids=frozenset(model_results.keys()),
|
|
40
|
+
_component_ids=frozenset(component_results.keys()),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def from_errored_file_dict(errored_file: object) -> "Document":
|
|
45
|
+
"""
|
|
46
|
+
Create a `Document` from an errored file dictionary.
|
|
47
|
+
"""
|
|
48
|
+
return Document(
|
|
49
|
+
id=get(errored_file, int, "submissionfile_id"),
|
|
50
|
+
name=get(errored_file, str, "input_filename"),
|
|
51
|
+
etl_output_uri="",
|
|
52
|
+
failed=True,
|
|
53
|
+
error=get(errored_file, str, "error"),
|
|
54
|
+
traceback=get(errored_file, str, "traceback"),
|
|
55
|
+
_model_ids=frozenset(),
|
|
56
|
+
_component_ids=frozenset(),
|
|
57
|
+
)
|