indico_toolkit 6.14.0__py3-none-any.whl

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.
Files changed (83) hide show
  1. indico_toolkit/__init__.py +24 -0
  2. indico_toolkit/association/__init__.py +15 -0
  3. indico_toolkit/association/association.py +65 -0
  4. indico_toolkit/association/extracted_tokens.py +106 -0
  5. indico_toolkit/association/line_items.py +189 -0
  6. indico_toolkit/association/positioning.py +301 -0
  7. indico_toolkit/association/splitting.py +41 -0
  8. indico_toolkit/auto_populate/__init__.py +3 -0
  9. indico_toolkit/auto_populate/populator.py +362 -0
  10. indico_toolkit/auto_populate/types.py +66 -0
  11. indico_toolkit/auto_review/__init__.py +6 -0
  12. indico_toolkit/auto_review/auto_review_functions.py +123 -0
  13. indico_toolkit/auto_review/auto_reviewer.py +62 -0
  14. indico_toolkit/client.py +35 -0
  15. indico_toolkit/errors.py +32 -0
  16. indico_toolkit/etloutput/__init__.py +210 -0
  17. indico_toolkit/etloutput/cell.py +47 -0
  18. indico_toolkit/etloutput/errors.py +16 -0
  19. indico_toolkit/etloutput/etloutput.py +110 -0
  20. indico_toolkit/etloutput/range.py +30 -0
  21. indico_toolkit/etloutput/table.py +44 -0
  22. indico_toolkit/etloutput/token.py +25 -0
  23. indico_toolkit/indico_wrapper/__init__.py +15 -0
  24. indico_toolkit/indico_wrapper/dataset.py +114 -0
  25. indico_toolkit/indico_wrapper/doc_extraction.py +79 -0
  26. indico_toolkit/indico_wrapper/download.py +193 -0
  27. indico_toolkit/indico_wrapper/indico_wrapper.py +119 -0
  28. indico_toolkit/indico_wrapper/modelop.py +200 -0
  29. indico_toolkit/indico_wrapper/reviewer.py +111 -0
  30. indico_toolkit/indico_wrapper/workflow.py +231 -0
  31. indico_toolkit/metrics/__init__.py +11 -0
  32. indico_toolkit/metrics/compare_ground_truth.py +123 -0
  33. indico_toolkit/metrics/compare_models.py +180 -0
  34. indico_toolkit/metrics/metrics.py +373 -0
  35. indico_toolkit/metrics/plotting.py +102 -0
  36. indico_toolkit/ocr/__init__.py +9 -0
  37. indico_toolkit/ocr/customocr_object.py +42 -0
  38. indico_toolkit/ocr/ondoc_object.py +93 -0
  39. indico_toolkit/ocr/standard_object.py +54 -0
  40. indico_toolkit/pipelines/__init__.py +3 -0
  41. indico_toolkit/pipelines/file_processing.py +157 -0
  42. indico_toolkit/polling/__init__.py +8 -0
  43. indico_toolkit/polling/autoreview.py +204 -0
  44. indico_toolkit/polling/downstream.py +145 -0
  45. indico_toolkit/polling/queries.py +68 -0
  46. indico_toolkit/py.typed +0 -0
  47. indico_toolkit/results/__init__.py +104 -0
  48. indico_toolkit/results/document.py +78 -0
  49. indico_toolkit/results/errors.py +4 -0
  50. indico_toolkit/results/model.py +60 -0
  51. indico_toolkit/results/normalization.py +159 -0
  52. indico_toolkit/results/predictionlist.py +395 -0
  53. indico_toolkit/results/predictions/__init__.py +88 -0
  54. indico_toolkit/results/predictions/box.py +58 -0
  55. indico_toolkit/results/predictions/citation.py +47 -0
  56. indico_toolkit/results/predictions/classification.py +50 -0
  57. indico_toolkit/results/predictions/documentextraction.py +160 -0
  58. indico_toolkit/results/predictions/extraction.py +35 -0
  59. indico_toolkit/results/predictions/formextraction.py +121 -0
  60. indico_toolkit/results/predictions/group.py +29 -0
  61. indico_toolkit/results/predictions/prediction.py +41 -0
  62. indico_toolkit/results/predictions/span.py +43 -0
  63. indico_toolkit/results/predictions/summarization.py +103 -0
  64. indico_toolkit/results/predictions/unbundling.py +51 -0
  65. indico_toolkit/results/result.py +152 -0
  66. indico_toolkit/results/review.py +32 -0
  67. indico_toolkit/results/utilities.py +73 -0
  68. indico_toolkit/retry.py +94 -0
  69. indico_toolkit/snapshots/__init__.py +3 -0
  70. indico_toolkit/snapshots/snapshot.py +340 -0
  71. indico_toolkit/structure/__init__.py +3 -0
  72. indico_toolkit/structure/create_structure.py +232 -0
  73. indico_toolkit/structure/queries.py +119 -0
  74. indico_toolkit/structure/utils.py +16 -0
  75. indico_toolkit/types/__init__.py +12 -0
  76. indico_toolkit/types/classification.py +92 -0
  77. indico_toolkit/types/extractions.py +227 -0
  78. indico_toolkit/types/predictions.py +28 -0
  79. indico_toolkit/types/workflow_object.py +133 -0
  80. indico_toolkit-6.14.0.dist-info/LICENSE +21 -0
  81. indico_toolkit-6.14.0.dist-info/METADATA +144 -0
  82. indico_toolkit-6.14.0.dist-info/RECORD +83 -0
  83. indico_toolkit-6.14.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,16 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ModelTaskType(Enum):
5
+ """
6
+ Issues with SDK 7/15/22-- need to hard code this here, new SDK release with fix is
7
+ imminent
8
+ """
9
+
10
+ CLASSIFICATION = 1
11
+ FORM_EXTRACTION = 2
12
+ OBJECT_DETECTION = 3
13
+ CLASSIFICATION_MULTIPLE = 4
14
+ REGRESSION = 5
15
+ ANNOTATION = 6
16
+ CLASSIFICATION_UNBUNDLING = 7
@@ -0,0 +1,12 @@
1
+ from .classification import Classification, ClassificationMGP
2
+ from .extractions import Extractions
3
+ from .predictions import Predictions
4
+ from .workflow_object import WorkflowResult
5
+
6
+ __all__ = (
7
+ "Classification",
8
+ "ClassificationMGP",
9
+ "Extractions",
10
+ "Predictions",
11
+ "WorkflowResult",
12
+ )
@@ -0,0 +1,92 @@
1
+ from operator import itemgetter
2
+ from typing import Dict
3
+
4
+ from ..pipelines import FileProcessing
5
+
6
+ try:
7
+ import pandas as pd
8
+
9
+ _PANDAS_INSTALLED = True
10
+ except ImportError as error:
11
+ _PANDAS_INSTALLED = False
12
+ _IMPORT_ERROR = error
13
+
14
+
15
+ class Classification:
16
+ """
17
+ Functionality for classification predictions
18
+ """
19
+
20
+ def __init__(self, prediction: dict):
21
+ self._pred = prediction
22
+
23
+ @property
24
+ def label(self) -> str:
25
+ return self._pred["label"]
26
+
27
+ @property
28
+ def labels(self) -> list:
29
+ return list(self.confidence_scores.keys())
30
+
31
+ @property
32
+ def confidence(self) -> float:
33
+ return self.confidence_scores[self.label]
34
+
35
+ def set_confidence_key_to_max_value(self):
36
+ """
37
+ Overwite confidence dictionary to just max confidence float
38
+ """
39
+ self._pred["confidence"] = self._pred["confidence"][self.label]
40
+
41
+ @property
42
+ def confidence_scores(self) -> Dict[str, float]:
43
+ return self._pred["confidence"]
44
+
45
+ def to_csv(
46
+ self, save_path, filename: str = "", append_if_exists: bool = True
47
+ ) -> None:
48
+ if not _PANDAS_INSTALLED:
49
+ raise RuntimeError(
50
+ "saving predictions to CSV requires additional dependencies: "
51
+ "`pip install indico-toolkit[predictions]`"
52
+ ) from _IMPORT_ERROR
53
+
54
+ results = {filename: self._pred}
55
+ df = pd.DataFrame(results).transpose()
56
+ df["filename"] = filename
57
+ if append_if_exists and FileProcessing.file_exists(save_path):
58
+ df.to_csv(save_path, mode="a", header=False, index=False)
59
+ else:
60
+ df.to_csv(save_path, index=False)
61
+
62
+
63
+ class ClassificationMGP(Classification):
64
+ """
65
+ Classification wrapper to account for
66
+ ModelGroupPredict returning a varied json output compared with Workflow
67
+
68
+ EXAMPLE:::
69
+ {'Type A': 0.99, 'Type B': 0.01}
70
+ """
71
+
72
+ @property
73
+ def label(self) -> str:
74
+ return max(self._pred.items(), key=itemgetter(1))[0]
75
+
76
+ @property
77
+ def labels(self) -> list:
78
+ return list(self._pred.keys())
79
+
80
+ @property
81
+ def confidence(self) -> float:
82
+ return self._pred[self.label]
83
+
84
+ def set_confidence_key_to_max_value(self):
85
+ """
86
+ Overwite confidence dictionary to just max confidence float
87
+ """
88
+ self._pred["confidence"] = self.confidence
89
+
90
+ @property
91
+ def confidence_scores(self) -> Dict[str, float]:
92
+ return self._pred
@@ -0,0 +1,227 @@
1
+ from collections import Counter, defaultdict
2
+ from copy import deepcopy
3
+ from typing import Dict, Iterable, List, Set, Union
4
+
5
+ from ..errors import ToolkitInputError
6
+ from ..pipelines import FileProcessing
7
+
8
+ try:
9
+ import pandas as pd
10
+
11
+ _PANDAS_INSTALLED = True
12
+ except ImportError as error:
13
+ _PANDAS_INSTALLED = False
14
+ _IMPORT_ERROR = error
15
+
16
+
17
+ class Extractions:
18
+ """
19
+ Functionality for common extraction prediction use cases
20
+ """
21
+
22
+ def __init__(self, predictions: List[dict]):
23
+ self._preds = predictions
24
+ self.removed_predictions = []
25
+
26
+ @property
27
+ def to_dict_by_label(self) -> Dict[str, list]:
28
+ """
29
+ Generate a dictionary where key is label string and value is list of all
30
+ predictions of that label
31
+ """
32
+ prediction_label_map = defaultdict(list)
33
+ for pred in self._preds:
34
+ prediction_label_map[pred["label"]].append(pred)
35
+ return prediction_label_map
36
+
37
+ @property
38
+ def num_predictions(self) -> int:
39
+ return len(self._preds)
40
+
41
+ def remove_by_confidence(self, confidence: float = 0.95, labels: List[str] = None):
42
+ """
43
+ Remove predictions that are less than given confidence
44
+ Args:
45
+ confidence (float, optional): confidence theshold. Defaults to 0.95.
46
+ labels (List[str], optional): Labels where this applies,
47
+ if None applies to all. Defaults to None.
48
+ """
49
+ high_conf_preds = []
50
+ for pred in self._preds:
51
+ label = pred["label"]
52
+ if labels and label not in labels:
53
+ high_conf_preds.append(pred)
54
+ elif pred["confidence"][label] >= confidence:
55
+ high_conf_preds.append(pred)
56
+ else:
57
+ self.removed_predictions.append(pred)
58
+ self._preds = high_conf_preds
59
+
60
+ def remove_except_max_confidence(self, labels: List[str]):
61
+ """
62
+ Removes all predictions except the highest confidence within each specified
63
+ class
64
+ """
65
+ label_set = self.label_set
66
+ for label in labels:
67
+ if label not in label_set:
68
+ continue
69
+ max_pred = self._select_max_confidence(label)
70
+ self.remove_all_by_label([label])
71
+ self.removed_predictions.remove(max_pred)
72
+ self._preds.append(max_pred)
73
+
74
+ def set_confidence_key_to_max_value(self, inplace: bool = True):
75
+ """
76
+ Overwite confidence dictionary to just max confidence float to make preds more
77
+ readable.
78
+ """
79
+ if inplace:
80
+ self._set_confidence_key_to_max_value(self._preds)
81
+ else:
82
+ return self._set_confidence_key_to_max_value(deepcopy(self._preds))
83
+
84
+ @staticmethod
85
+ def _set_confidence_key_to_max_value(preds):
86
+ for pred in preds:
87
+ pred["confidence"] = pred["confidence"][pred["label"]]
88
+ return preds
89
+
90
+ def remove_keys(self, keys_to_remove: List[str] = ["start", "end"]):
91
+ """
92
+ Remove specified keys from prediction dictionaries
93
+ """
94
+ for pred in self._preds:
95
+ for key in keys_to_remove:
96
+ pred.pop(key)
97
+
98
+ def remove_all_by_label(self, labels: Iterable[str]):
99
+ """
100
+ Remove all predictions in list of labels
101
+ """
102
+ preds = []
103
+ for p in self._preds:
104
+ if p["label"] in labels:
105
+ self.removed_predictions.append(p)
106
+ else:
107
+ preds.append(p)
108
+ self._preds = preds
109
+
110
+ def remove_human_added_predictions(self):
111
+ """
112
+ Remove predictions that were not added by the model (i.e. added by scripted or
113
+ human review)
114
+ """
115
+ self._preds = [
116
+ i for i in self._preds if not self.is_manually_added_prediction(i)
117
+ ]
118
+
119
+ def to_list(self):
120
+ return self._preds
121
+
122
+ @staticmethod
123
+ def is_manually_added_prediction(prediction: dict) -> bool:
124
+ if isinstance(prediction["start"], int) and isinstance(prediction["end"], int):
125
+ if prediction["end"] > prediction["start"]:
126
+ return False
127
+ return True
128
+
129
+ @staticmethod
130
+ def get_label_set(predictions: List[dict]) -> Set[str]:
131
+ """
132
+ Get the included labels from a list of predictions
133
+ """
134
+ return set([i["label"] for i in predictions])
135
+
136
+ def get_text_values(self, label: str) -> List[str]:
137
+ """
138
+ Get all text values for a given label
139
+ """
140
+ return [i["text"] for i in self._preds if i["label"] == label]
141
+
142
+ @property
143
+ def label_set(self):
144
+ return self.get_label_set(self._preds)
145
+
146
+ def _select_max_confidence(self, label: str) -> dict:
147
+ """
148
+ Get the highest confidence prediction for a given field
149
+ """
150
+ max_pred = None
151
+ confidence = 0
152
+ for pred in self[label]:
153
+ pred_confidence = pred["confidence"][label]
154
+ if pred_confidence >= confidence:
155
+ max_pred = pred
156
+ confidence = pred_confidence
157
+ return max_pred
158
+
159
+ @property
160
+ def label_count_dict(self) -> Dict[str, int]:
161
+ """
162
+ Get count of occurrences of each label
163
+ """
164
+ return dict(Counter(i["label"] for i in self._preds))
165
+
166
+ def exist_multiple_vals_for_label(self, label: str) -> bool:
167
+ """
168
+ Check whether multiple unique text vals for field
169
+ """
170
+ if len(set(self.get_text_values(label))) > 1:
171
+ return True
172
+ return False
173
+
174
+ def get_most_common_text_value(self, label: str) -> Union[str, None]:
175
+ """
176
+ Return the most common text value. If there is a tie- returns None.
177
+ """
178
+ if label not in self.label_set:
179
+ raise ToolkitInputError(f"There are no predictions for: '{label}'")
180
+ text_vals = self.get_text_values(label)
181
+ if len(set(text_vals)) == 1:
182
+ return text_vals[0]
183
+ most_common = Counter(text_vals).most_common(2)
184
+ if most_common[0][1] > most_common[1][1]:
185
+ return most_common[0][0]
186
+ return None
187
+
188
+ def __len__(self):
189
+ return len(self._preds)
190
+
191
+ def __repr__(self):
192
+ return f"{self.num_predictions} Extractions:\n\n{self._preds}"
193
+
194
+ def __getitem__(self, label: str) -> List[dict]:
195
+ return [i for i in self._preds if i["label"] == label]
196
+
197
+ def to_csv(
198
+ self,
199
+ save_path: str,
200
+ filename: str = "",
201
+ append_if_exists: bool = True,
202
+ include_start_end: bool = False,
203
+ ) -> None:
204
+ """
205
+ Write three column CSV ('confidence', 'label', 'text')
206
+ Args:
207
+ save_path (str): path to write CSV
208
+ include_start_end (bool): include columns for start/end indexes
209
+ append_if_exists (bool): if path exists, append to that CSV
210
+ filename (str, optional): the file where the preds were derived from.
211
+ Defaults to "".
212
+ """
213
+ if not _PANDAS_INSTALLED:
214
+ raise RuntimeError(
215
+ "saving predictions to CSV requires additional dependencies: "
216
+ "`pip install indico-toolkit[predictions]`"
217
+ ) from _IMPORT_ERROR
218
+
219
+ preds = self.set_confidence_key_to_max_value(inplace=False)
220
+ df = pd.DataFrame(preds)
221
+ if not include_start_end:
222
+ df.drop(["start", "end"], axis=1, inplace=True)
223
+ df["filename"] = filename
224
+ if append_if_exists and FileProcessing.file_exists(save_path):
225
+ df.to_csv(save_path, mode="a", header=False, index=False)
226
+ else:
227
+ df.to_csv(save_path, index=False)
@@ -0,0 +1,28 @@
1
+ from ..errors import ToolkitInputError
2
+ from .classification import Classification, ClassificationMGP
3
+ from .extractions import Extractions
4
+
5
+
6
+ class Predictions:
7
+ """
8
+ Factory class for predictions
9
+ """
10
+
11
+ @staticmethod
12
+ def get_obj(predictions):
13
+ """
14
+ Returns:
15
+ Extractions object or Classification object depending on predictions type
16
+ """
17
+ if isinstance(predictions, list):
18
+ return Extractions(predictions)
19
+ elif isinstance(predictions, dict):
20
+ if "label" in predictions:
21
+ return Classification(predictions)
22
+ else:
23
+ return ClassificationMGP(predictions)
24
+ else:
25
+ raise ToolkitInputError(
26
+ f"Unable to process predictions with type {type(predictions)}. "
27
+ f"Predictions: {predictions}"
28
+ )
@@ -0,0 +1,133 @@
1
+ from typing import List
2
+
3
+ from ..errors import ToolkitInputError
4
+ from .predictions import Predictions
5
+
6
+
7
+ class WorkflowResult:
8
+ def __init__(self, result: dict, model_name: str = None):
9
+ """
10
+ Common functionality for workflow result object
11
+
12
+ Args:
13
+ result (dict): raw workflow result object
14
+ model_name (str, optional): Extraction/Classification model name.
15
+ Defaults to None.
16
+ """
17
+ self.result = result
18
+ self.model_name = model_name
19
+
20
+ def _check_is_valid_model_name(self) -> None:
21
+ if self.model_name not in self.available_model_names:
22
+ raise ToolkitInputError(
23
+ f"{self.model_name} is not an available model name. "
24
+ f"Options: {self.available_model_names}"
25
+ )
26
+
27
+ def __repr__(self):
28
+ return f"WorkflowResult object, Submission ID: {self.submission_id}"
29
+
30
+ @property
31
+ def get_predictions(self) -> Predictions:
32
+ """
33
+ Return predictions without human review
34
+ """
35
+ self._set_model_name()
36
+ preds = self.document_results[self.model_name]
37
+ if "pre_review" in preds:
38
+ preds = preds["pre_review"]
39
+ return Predictions.get_obj(preds)
40
+
41
+ @property
42
+ def pre_review_predictions(self) -> Predictions:
43
+ """
44
+ Return predictions before human review
45
+ """
46
+ self._set_model_name()
47
+ preds = self.document_results[self.model_name]
48
+ if "pre_review" in preds:
49
+ preds = preds["pre_review"]
50
+ return Predictions.get_obj(preds)
51
+ else:
52
+ return Predictions.get_obj([])
53
+
54
+ @property
55
+ def post_reviews_predictions(self) -> Predictions:
56
+ """
57
+ Return predictions after human review
58
+ """
59
+ self._set_model_name()
60
+ preds = self.document_results[self.model_name]
61
+ if "post_reviews" in preds:
62
+ post_review_preds = []
63
+ reviews = preds["post_reviews"]
64
+ for review in reviews:
65
+ post_review_preds.append(Predictions.get_obj(review))
66
+ return post_review_preds
67
+ else:
68
+ return Predictions.get_obj([])
69
+
70
+ @property
71
+ def final_predictions(self) -> Predictions:
72
+ self._set_model_name()
73
+ preds = self.document_results[self.model_name]
74
+ if "final" in preds:
75
+ preds = preds["final"]
76
+ return Predictions.get_obj(preds)
77
+ else:
78
+ return Predictions.get_obj([])
79
+
80
+ def _set_model_name(self):
81
+ """
82
+ Attempts to select the relevant model name if not already specified.
83
+ Raises error if multiple models are available and self.model_name specified.
84
+ """
85
+ if self.model_name:
86
+ self._check_is_valid_model_name()
87
+ elif len(self.available_model_names) > 1:
88
+ raise ToolkitInputError(
89
+ "Multiple models available, you must set self.model_name to one of "
90
+ f"{self.available_model_names}"
91
+ )
92
+ else:
93
+ self.model_name = self.available_model_names[0]
94
+
95
+ @property
96
+ def etl_url(self) -> str:
97
+ return self.result["etl_output"]
98
+
99
+ @property
100
+ def document_results(self) -> dict:
101
+ return self.result["results"]["document"]["results"]
102
+
103
+ @property
104
+ def available_model_names(self) -> List[str]:
105
+ return list(self.document_results.keys())
106
+
107
+ @property
108
+ def submission_id(self) -> str:
109
+ return self.result["submission_id"]
110
+
111
+ @property
112
+ def errors(self) -> list:
113
+ return self.result["errors"]
114
+
115
+ @property
116
+ def review_id(self) -> int:
117
+ return self.result["review_id"]
118
+
119
+ @property
120
+ def reviewer_id(self) -> int:
121
+ return self.result["reviewer_id"]
122
+
123
+ @property
124
+ def review_notes(self) -> int:
125
+ return self.result["review_notes"]
126
+
127
+ @property
128
+ def review_rejected(self) -> int:
129
+ return self.result["review_rejected"]
130
+
131
+ @property
132
+ def admin_review(self) -> bool:
133
+ return self.result["admin_review"]
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 IndicoDataSolutions
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.3
2
+ Name: indico-toolkit
3
+ Version: 6.14.0
4
+ Summary: Classes, functions, and abstractions for Indico IPA
5
+ License: MIT
6
+ Author: Indico Solutions Engineering
7
+ Author-email: solutionsengineering@indicodata.ai
8
+ Requires-Python: >=3.10
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Provides-Extra: all
16
+ Provides-Extra: downloads
17
+ Provides-Extra: examples
18
+ Provides-Extra: metrics
19
+ Provides-Extra: predictions
20
+ Provides-Extra: snapshots
21
+ Requires-Dist: indico-client (>=6.14.0,<7.0.0)
22
+ Requires-Dist: pandas (>=2.2.3,<3.0.0) ; extra == "all"
23
+ Requires-Dist: pandas (>=2.2.3,<3.0.0) ; extra == "downloads"
24
+ Requires-Dist: pandas (>=2.2.3,<3.0.0) ; extra == "examples"
25
+ Requires-Dist: pandas (>=2.2.3,<3.0.0) ; extra == "metrics"
26
+ Requires-Dist: pandas (>=2.2.3,<3.0.0) ; extra == "predictions"
27
+ Requires-Dist: pandas (>=2.2.3,<3.0.0) ; extra == "snapshots"
28
+ Requires-Dist: plotly (>=5.2.1,<6.0.0) ; extra == "all"
29
+ Requires-Dist: plotly (>=5.2.1,<6.0.0) ; extra == "metrics"
30
+ Requires-Dist: tqdm (>=4.50.0,<5.0.0) ; extra == "all"
31
+ Requires-Dist: tqdm (>=4.50.0,<5.0.0) ; extra == "downloads"
32
+ Project-URL: source, https://github.com/IndicoDataSolutions/Indico-Solutions-Toolkit
33
+ Description-Content-Type: text/markdown
34
+
35
+ # Indico Toolkit
36
+
37
+ **This repository contains software that is not officially supported by Indico. It may
38
+ be outdated or contain bugs. The operations it performs are potentially destructive.
39
+ Use at your own risk.**
40
+
41
+ Classes, functions, and abstractions for building workflows using the Indico IPA
42
+ (Intelligent Process Automation) platform.
43
+
44
+ - [Polling Classes](https://github.com/IndicoDataSolutions/indico-toolkit-python/tree/main/indico_toolkit/polling/__init__.py)
45
+ that implement best-practices polling behavior for Auto Review and Downstream
46
+ processes. Easily plug in business logic without the boilerplate.
47
+ - [Result File](https://github.com/IndicoDataSolutions/indico-toolkit-python/blob/main/indico_toolkit/results/__init__.py)
48
+ and [Etl Output](https://github.com/IndicoDataSolutions/indico-toolkit-python/blob/main/indico_toolkit/etloutput/__init__.py)
49
+ Data Classes that parse standard IPA JSON output into idiomatic, type-safe Python dataclasses.
50
+ - [Metrics Classes](https://github.com/IndicoDataSolutions/indico-toolkit-python/blob/main/indico_toolkit/metrics/__init__.py)
51
+ to compare model performance, evaluate ground truth, and plot statistics.
52
+ - [Snapshot Classes](https://github.com/IndicoDataSolutions/indico-toolkit-python/blob/main/indico_toolkit/snapshots/snapshot.py)
53
+ to concatenate, merge, filter, and manipulate snapshot CSVs.
54
+
55
+ ...and more in the [Examples](https://github.com/IndicoDataSolutions/indico-toolkit-python/tree/main/examples) folder.
56
+
57
+
58
+ ## Installation
59
+
60
+ **Indico Toolkit does not use semantic versioning.**
61
+
62
+ Indico Toolkit versions match the minimum IPA version required to use its functionality.
63
+ E.g. `indico-toolkit==6.14.0` makes use of functionality introduced in IPA 6.14, and
64
+ some functionality requires IPA 6.14 or later to use.
65
+
66
+ ```bash
67
+ pip install indico-toolkit
68
+ ```
69
+
70
+ Some functionality requires optional dependencies that can be installed with extras.
71
+
72
+ ```bash
73
+ pip install 'indico-toolkit[all]'
74
+ pip install 'indico-toolkit[downloads]'
75
+ pip install 'indico-toolkit[examples]'
76
+ pip install 'indico-toolkit[metrics]'
77
+ pip install 'indico-toolkit[predictions]'
78
+ pip install 'indico-toolkit[snapshots]'
79
+ ```
80
+
81
+
82
+ ## Contributing
83
+
84
+ Indico Toolkit uses Poetry 2.X for package and dependency management.
85
+
86
+
87
+ ### Setup
88
+
89
+ Clone the source repository with Git.
90
+
91
+ ```bash
92
+ git clone git@github.com:IndicoDataSolutions/indico-toolkit-python.git
93
+ ```
94
+
95
+ Install dependencies with Poetry.
96
+
97
+ ```bash
98
+ poetry install
99
+ ```
100
+
101
+ Formatting, linting, type checking, and tests are defined as
102
+ [Poe](https://poethepoet.natn.io/) tasks in `pyproject.toml`.
103
+
104
+ ```bash
105
+ poetry run poe {format,check,test,all}
106
+ ```
107
+
108
+ Code changes or additions should pass `poetry run poe all` before opening a PR.
109
+
110
+
111
+ ### Tests
112
+
113
+ Indico Toolkit has three test suites: required unit tests, extra unit tests, and
114
+ integration tests.
115
+
116
+ By default, only required unit tests are executed. Extra unit tests and integration
117
+ tests are skipped.
118
+
119
+ ```bash
120
+ poetry run poe {test,all}
121
+ ```
122
+
123
+ Extra unit tests are skipped when their dependencies are not installed. To execute extra
124
+ unit tests, install one or more extras and run the tests.
125
+
126
+ ```bash
127
+ poetry install --all-extras
128
+ poetry run poe {test,all}
129
+ ```
130
+
131
+ Integration tests make API calls to an IPA environment and require a host and API token
132
+ to execute. These tests create datasets, setup workflows, and train models. **Expect
133
+ them to take tens of minutes to run.**
134
+
135
+ ```bash
136
+ poetry run poe test-integration \
137
+ --host try.indico.io \
138
+ --token indico_api_token.txt
139
+ ```
140
+
141
+ Make liberal use of pytest's `--last-failed` and `--failed-first`
142
+ [flags](https://docs.pytest.org/en/stable/how-to/cache.html) to speed up integration
143
+ test execution when writing code.
144
+