altera-data-suite 1.0.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.
Files changed (44) hide show
  1. altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/PKG-INFO +21 -0
  2. altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/SOURCES.txt +48 -0
  3. altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/dependency_links.txt +1 -0
  4. altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/entry_points.txt +5 -0
  5. altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/requires.txt +11 -0
  6. altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/top_level.txt +1 -0
  7. altera_data_suite-1.0.0/MANIFEST.in +5 -0
  8. altera_data_suite-1.0.0/PKG-INFO +21 -0
  9. altera_data_suite-1.0.0/README.md +40 -0
  10. altera_data_suite-1.0.0/orangecontrib/__init__.py +3 -0
  11. altera_data_suite-1.0.0/orangecontrib/custom/__init__.py +0 -0
  12. altera_data_suite-1.0.0/orangecontrib/custom/widgets/__init__.py +28 -0
  13. altera_data_suite-1.0.0/orangecontrib/custom/widgets/cleaner.py +139 -0
  14. altera_data_suite-1.0.0/orangecontrib/custom/widgets/columns_manager.py +213 -0
  15. altera_data_suite-1.0.0/orangecontrib/custom/widgets/filter_builder.py +166 -0
  16. altera_data_suite-1.0.0/orangecontrib/custom/widgets/header_promoter.py +178 -0
  17. altera_data_suite-1.0.0/orangecontrib/custom/widgets/horizontal_stack.py +173 -0
  18. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/3-squares.svg +6 -0
  19. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/category.svg +27 -0
  20. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/cleaner.svg +29 -0
  21. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/color_filter.svg +21 -0
  22. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/column_manager.svg +16 -0
  23. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/edit_column.svg +19 -0
  24. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/filter.svg +17 -0
  25. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/header_promoter.svg +12 -0
  26. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/hstack.svg +17 -0
  27. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/link.svg +23 -0
  28. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/multishift.svg +17 -0
  29. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/passthrough.svg +11 -0
  30. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/pdf_converter.svg +99 -0
  31. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/regex.svg +12 -0
  32. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/regular_filter.svg +4 -0
  33. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/settings.svg +29 -0
  34. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/shift.svg +14 -0
  35. altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/spreadsheet.svg +104 -0
  36. altera_data_suite-1.0.0/orangecontrib/custom/widgets/multishift.py +143 -0
  37. altera_data_suite-1.0.0/orangecontrib/custom/widgets/passthrough.py +84 -0
  38. altera_data_suite-1.0.0/orangecontrib/custom/widgets/pdf_converter.py +354 -0
  39. altera_data_suite-1.0.0/orangecontrib/custom/widgets/regex.py +174 -0
  40. altera_data_suite-1.0.0/orangecontrib/custom/widgets/settings.py +106 -0
  41. altera_data_suite-1.0.0/orangecontrib/custom/widgets/web_utils.py +213 -0
  42. altera_data_suite-1.0.0/pyproject.toml +3 -0
  43. altera_data_suite-1.0.0/setup.cfg +4 -0
  44. altera_data_suite-1.0.0/setup.py +33 -0
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: altera-data-suite
3
+ Version: 1.0.0
4
+ Summary: Altera Data Suite for Orange3
5
+ Author: Your Name
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: orange3
8
+ Requires-Dist: PyQt6
9
+ Requires-Dist: PyQt6-WebEngine
10
+ Requires-Dist: pandas
11
+ Requires-Dist: numpy
12
+ Requires-Dist: keyring
13
+ Requires-Dist: requests
14
+ Requires-Dist: pymupdf
15
+ Requires-Dist: camelot-py
16
+ Requires-Dist: pypdfium2
17
+ Requires-Dist: Pillow
18
+ Dynamic: author
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
21
+ Dynamic: summary
@@ -0,0 +1,48 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ Altera_Data_Suite.egg-info/PKG-INFO
6
+ Altera_Data_Suite.egg-info/SOURCES.txt
7
+ Altera_Data_Suite.egg-info/dependency_links.txt
8
+ Altera_Data_Suite.egg-info/entry_points.txt
9
+ Altera_Data_Suite.egg-info/requires.txt
10
+ Altera_Data_Suite.egg-info/top_level.txt
11
+ altera_data_suite.egg-info/PKG-INFO
12
+ altera_data_suite.egg-info/SOURCES.txt
13
+ altera_data_suite.egg-info/dependency_links.txt
14
+ altera_data_suite.egg-info/entry_points.txt
15
+ altera_data_suite.egg-info/requires.txt
16
+ altera_data_suite.egg-info/top_level.txt
17
+ orangecontrib/__init__.py
18
+ orangecontrib/custom/__init__.py
19
+ orangecontrib/custom/widgets/__init__.py
20
+ orangecontrib/custom/widgets/cleaner.py
21
+ orangecontrib/custom/widgets/columns_manager.py
22
+ orangecontrib/custom/widgets/filter_builder.py
23
+ orangecontrib/custom/widgets/header_promoter.py
24
+ orangecontrib/custom/widgets/horizontal_stack.py
25
+ orangecontrib/custom/widgets/multishift.py
26
+ orangecontrib/custom/widgets/passthrough.py
27
+ orangecontrib/custom/widgets/pdf_converter.py
28
+ orangecontrib/custom/widgets/regex.py
29
+ orangecontrib/custom/widgets/settings.py
30
+ orangecontrib/custom/widgets/web_utils.py
31
+ orangecontrib/custom/widgets/icons/3-squares.svg
32
+ orangecontrib/custom/widgets/icons/category.svg
33
+ orangecontrib/custom/widgets/icons/cleaner.svg
34
+ orangecontrib/custom/widgets/icons/color_filter.svg
35
+ orangecontrib/custom/widgets/icons/column_manager.svg
36
+ orangecontrib/custom/widgets/icons/edit_column.svg
37
+ orangecontrib/custom/widgets/icons/filter.svg
38
+ orangecontrib/custom/widgets/icons/header_promoter.svg
39
+ orangecontrib/custom/widgets/icons/hstack.svg
40
+ orangecontrib/custom/widgets/icons/link.svg
41
+ orangecontrib/custom/widgets/icons/multishift.svg
42
+ orangecontrib/custom/widgets/icons/passthrough.svg
43
+ orangecontrib/custom/widgets/icons/pdf_converter.svg
44
+ orangecontrib/custom/widgets/icons/regex.svg
45
+ orangecontrib/custom/widgets/icons/regular_filter.svg
46
+ orangecontrib/custom/widgets/icons/settings.svg
47
+ orangecontrib/custom/widgets/icons/shift.svg
48
+ orangecontrib/custom/widgets/icons/spreadsheet.svg
@@ -0,0 +1,5 @@
1
+ [orange.widgets]
2
+ Altera Data Suite = orangecontrib.custom.widgets
3
+
4
+ [orange3.addon]
5
+ altera_data_suite = orangecontrib.custom
@@ -0,0 +1,11 @@
1
+ orange3
2
+ PyQt6
3
+ PyQt6-WebEngine
4
+ pandas
5
+ numpy
6
+ keyring
7
+ requests
8
+ pymupdf
9
+ camelot-py
10
+ pypdfium2
11
+ Pillow
@@ -0,0 +1,5 @@
1
+ include orangecontrib/example/tutorials/*.ows
2
+ include orangecontrib/example/widgets/icons/*
3
+ recursive-include orangecontrib/custom/widgets/web_UI *
4
+
5
+
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: altera-data-suite
3
+ Version: 1.0.0
4
+ Summary: Altera Data Suite for Orange3
5
+ Author: Your Name
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: orange3
8
+ Requires-Dist: PyQt6
9
+ Requires-Dist: PyQt6-WebEngine
10
+ Requires-Dist: pandas
11
+ Requires-Dist: numpy
12
+ Requires-Dist: keyring
13
+ Requires-Dist: requests
14
+ Requires-Dist: pymupdf
15
+ Requires-Dist: camelot-py
16
+ Requires-Dist: pypdfium2
17
+ Requires-Dist: Pillow
18
+ Dynamic: author
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
21
+ Dynamic: summary
@@ -0,0 +1,40 @@
1
+ Orange3 Example Add-on
2
+ ======================
3
+
4
+ This is an example add-on for [Orange3](http://orange.biolab.si). Add-on can extend Orange either
5
+ in scripting or GUI part, or in both. We here focus on the GUI part and implement a simple (empty) widget,
6
+ register it with Orange and add a new workflow with this widget to example tutorials.
7
+
8
+ Installation
9
+ ------------
10
+
11
+ To install the add-on from source run
12
+
13
+ pip install .
14
+
15
+ To register this add-on with Orange, but keep the code in the development directory (do not copy it to
16
+ Python's site-packages directory), run
17
+
18
+ pip install -e .
19
+
20
+ Documentation / widget help can be built by running
21
+
22
+ make html htmlhelp
23
+
24
+ from the doc directory.
25
+
26
+ Usage
27
+ -----
28
+
29
+ After the installation, the widget from this add-on is registered with Orange. To run Orange from the terminal,
30
+ use
31
+
32
+ orange-canvas
33
+
34
+ or
35
+
36
+ python -m Orange.canvas
37
+
38
+ The new widget appears in the toolbox bar under the section Example.
39
+
40
+ ![screenshot](https://github.com/biolab/orange3-example-addon/blob/master/screenshot.png)
@@ -0,0 +1,3 @@
1
+ __import__("pkg_resources").declare_namespace(__name__)
2
+ # orangecontrib is a namespace modules shared by multiple Orange add-on so it
3
+ # needs to declare namespace.
@@ -0,0 +1,28 @@
1
+ import sysconfig
2
+
3
+ # Category metadata.
4
+
5
+ # Category icon show in the menu
6
+ ICON = "icons/category.svg"
7
+
8
+ # Background color for category background in menu
9
+ # and widget icon background in workflow.
10
+ BACKGROUND = "#e0e0e0"
11
+
12
+ # Location of widget help files.
13
+ WIDGET_HELP_PATH = (
14
+ # Development documentation
15
+ # You need to build help pages manually using
16
+ # make htmlhelp
17
+ # inside doc folder
18
+ ("{DEVELOP_ROOT}/doc/_build/htmlhelp/index.html", None),
19
+ # Documentation included in wheel
20
+ # Correct DATA_FILES entry is needed in setup.py and documentation has to be built
21
+ # before the wheel is created.
22
+ ("{}/help/orange3-example/index.html".format(sysconfig.get_path("data")), None),
23
+ # Online documentation url, used when the local documentation is not available.
24
+ # Url should point to a page with a section Widgets. This section should
25
+ # includes links to documentation pages of each widget. Matching is
26
+ # performed by comparing link caption to widget name.
27
+ ("http://orange3-example-addon.readthedocs.io/en/latest/", ""),
28
+ )
@@ -0,0 +1,139 @@
1
+ import os, json
2
+ from PyQt6.QtCore import QObject, pyqtSlot
3
+ from Orange.widgets import widget
4
+ from Orange.widgets.widget import Input, Output
5
+ from Orange.widgets.settings import Setting
6
+ from Orange.data import Table, StringVariable
7
+ from .web_utils import WebEngineMixin
8
+ from .auxiliary_functions import _o2d, _d2o, _aaco
9
+
10
+
11
+ class _Br(QObject):
12
+ def __init__(self, _v, _pw):
13
+ super().__init__()
14
+ self._v = _v
15
+ self._pw = _pw
16
+ self._pj = []
17
+ self._ld = False
18
+ self._v.loadFinished.connect(self._ol)
19
+
20
+ def _ol(self, ok):
21
+ if ok:
22
+ self._ld = True
23
+ for _j in self._pj:
24
+ self._v.page().runJavaScript(_j)
25
+ self._pj.clear()
26
+
27
+ def _rj(self, _j):
28
+ if self._ld:
29
+ self._v.page().runJavaScript(_j)
30
+ else:
31
+ self._pj.append(_j)
32
+
33
+ def _sc(self, _d):
34
+ self._rj(f"window.updateColumnDefinitions&&updateColumnDefinitions({_d});")
35
+
36
+ def _rs(self, _s):
37
+ self._rj(f"window.restoreCleaningState&&restoreCleaningState({_s});")
38
+
39
+ def _sn(self):
40
+ self._rj("window.showNoDataMessage&&showNoDataMessage();")
41
+
42
+ @pyqtSlot(str)
43
+ def cleaningChanged(self, _s):
44
+ self._pw._occ(_s)
45
+
46
+
47
+ class OWCleaner(WebEngineMixin, widget.OWWidget):
48
+ name = "Cleaner"
49
+ description = "Clean and transform text columns with various operations"
50
+ category = "Altera Data Suite"
51
+ icon = "icons/cleaner.svg"
52
+ priority = 30
53
+
54
+ class Inputs:
55
+ data = Input("Input Table", Table)
56
+
57
+ class Outputs:
58
+ cleaned_data = Output("Cleaned Data", Table)
59
+
60
+ cleaning_state = Setting('{"operations":[]}')
61
+ DESTROY_TIMEOUT = 300
62
+ want_main_area = True
63
+ want_control_area = False
64
+ resizing_enabled = True
65
+
66
+ class Error(widget.OWWidget.Error):
67
+ license_error = widget.Msg("License error: {}")
68
+
69
+ def __init__(self):
70
+ super().__init__()
71
+ self._id = None
72
+ self._od = None
73
+ self._df = None
74
+ self._tc = []
75
+ _h = os.path.join(os.path.dirname(__file__), "UI", "cleaner_ui", "index.html")
76
+ self.setup_webengine_lazy(_h, _Br, zoom_factor=0.9)
77
+
78
+ def on_webengine_ready(self):
79
+ if self._id is not None and self._tc:
80
+ self.bridge._sc(json.dumps(self._tc))
81
+ self.bridge._rs(self.cleaning_state)
82
+ self._ac()
83
+ elif self.web_loaded and self.bridge:
84
+ self.bridge._sn()
85
+
86
+ def on_webengine_show(self):
87
+ pass
88
+
89
+ @Inputs.data
90
+ def set_data(self, data):
91
+ self.Error.clear()
92
+ if data is None:
93
+ self._id = None
94
+ self._df = None
95
+ self._od = None
96
+ self._tc = []
97
+ self.Outputs.cleaned_data.send(None)
98
+ if self.web_loaded and self.bridge:
99
+ self.bridge._sn()
100
+ return
101
+ self._id = data
102
+ self._od = data.domain
103
+ self._df = _o2d(data)
104
+ self._tc = [
105
+ v.name
106
+ for v in list(data.domain.attributes)
107
+ + list(data.domain.class_vars)
108
+ + list(data.domain.metas)
109
+ if isinstance(v, StringVariable)
110
+ ]
111
+ self._ac()
112
+ if self.web_loaded and self.bridge:
113
+ if self._tc:
114
+ self.bridge._sc(json.dumps(self._tc))
115
+ self.bridge._rs(self.cleaning_state)
116
+ else:
117
+ self.bridge._sn()
118
+
119
+ def _occ(self, _s):
120
+ self.cleaning_state = _s
121
+ self._ac()
122
+
123
+ def _ac(self):
124
+ if self._df is None:
125
+ self.Outputs.cleaned_data.send(None)
126
+ return
127
+ try:
128
+ if not json.loads(self.cleaning_state).get("operations"):
129
+ self.Outputs.cleaned_data.send(self._id)
130
+ return
131
+ self.Outputs.cleaned_data.send(
132
+ _d2o(_aaco(self._df, self.cleaning_state), self._od)
133
+ )
134
+ except RuntimeError as _e:
135
+ self.Error.license_error(str(_e))
136
+ self.Outputs.cleaned_data.send(None)
137
+ except Exception as _e:
138
+ print(f"[CLEANER] Cleaning error: {_e}")
139
+ self.Outputs.cleaned_data.send(self._id)
@@ -0,0 +1,213 @@
1
+ import os, json
2
+ from PyQt6.QtCore import QObject, pyqtSlot
3
+ from Orange.widgets import widget
4
+ from Orange.widgets.widget import Input, Output
5
+ from Orange.widgets.settings import Setting
6
+ from Orange.data import Table
7
+ from .web_utils import WebEngineMixin
8
+ from .auxiliary_functions import _o2do, _gci, _icc, _asc, _acc, _d2ocm, _bpp
9
+
10
+
11
+ class _Br(QObject):
12
+ def __init__(self, _v, _pw):
13
+ super().__init__()
14
+ self._v = _v
15
+ self._pw = _pw
16
+ self._pj = []
17
+ self._ld = False
18
+ self._v.loadFinished.connect(self._ol)
19
+
20
+ def _ol(self, ok):
21
+ if ok:
22
+ self._ld = True
23
+ for _j in self._pj:
24
+ self._v.page().runJavaScript(_j)
25
+ self._pj.clear()
26
+
27
+ def _rj(self, _j):
28
+ if self._ld:
29
+ self._v.page().runJavaScript(_j)
30
+ else:
31
+ self._pj.append(_j)
32
+
33
+ def _std(self, _d):
34
+ self._rj(f"window.initializeTable&&initializeTable({_d});")
35
+
36
+ def _sn(self):
37
+ self._rj("window.showNoDataMessage&&showNoDataMessage();")
38
+
39
+ def _rs(self, _s):
40
+ self._rj(f"window.restoreColumnState&&restoreColumnState({_s});")
41
+
42
+ @pyqtSlot(str)
43
+ def columnsChanged(self, _s):
44
+ self._pw._occ(_s)
45
+
46
+ @pyqtSlot()
47
+ def resetRequested(self):
48
+ self._pw._orr()
49
+
50
+
51
+ class OWColumnManager(WebEngineMixin, widget.OWWidget):
52
+ name = "Column Manager"
53
+ description = (
54
+ "Reorder, rename, add, and delete columns with drag-and-drop interface"
55
+ )
56
+ category = "Altera Data Suite"
57
+ icon = "icons/column_manager.svg"
58
+ priority = 20
59
+
60
+ class Inputs:
61
+ data = Input("Input Table", Table)
62
+
63
+ class Outputs:
64
+ modified_data = Output("Modified Data", Table)
65
+
66
+ column_state = Setting('{"columns":[],"originalInputFields":[]}', schema_only=True)
67
+ want_main_area = True
68
+ want_control_area = False
69
+ resizing_enabled = True
70
+
71
+ class Error(widget.OWWidget.Error):
72
+ invalid_data = widget.Msg("Unable to process data: {}")
73
+ license_error = widget.Msg("License error: {}")
74
+
75
+ def __init__(self):
76
+ super().__init__()
77
+ self._id = None
78
+ self._od = None
79
+ self._df = None
80
+ self.setMinimumWidth(800)
81
+ self.setMinimumHeight(600)
82
+ _h = os.path.join(
83
+ os.path.dirname(__file__), "UI", "columns_manager_ui", "index.html"
84
+ )
85
+ self.setup_webengine_lazy(_h, _Br, zoom_factor=0.9)
86
+
87
+ def on_webengine_ready(self):
88
+ if self._id is not None:
89
+ self.set_data(self._id)
90
+ elif self.web_loaded and self.bridge:
91
+ self.bridge._sn()
92
+
93
+ @Inputs.data
94
+ def set_data(self, data):
95
+ self.Error.clear()
96
+ if data is None:
97
+ self._id = None
98
+ self._df = None
99
+ self._od = None
100
+ self.Outputs.modified_data.send(None)
101
+ if self.web_loaded and self.bridge:
102
+ self.bridge._sn()
103
+ return
104
+ self._id = data
105
+ self._od = data.domain
106
+ self._df = _o2do(data)
107
+ _ci = _gci(data, self._df)
108
+ _oif = {c["field"] for c in _ci}
109
+ _sdc = []
110
+ try:
111
+ _ss = json.loads(self.column_state)
112
+ _sc = _ss.get("columns", [])
113
+ _sdc = _ss.get("deletedColumns", [])
114
+ _sof = _ss.get("originalInputFields", [])
115
+ if _sc:
116
+ if set(_sof) == _oif or _icc(_sc, _ci):
117
+ _ci = _asc(_sc, _ci, self.column_state)
118
+ if set(_sof) != _oif:
119
+ self.column_state = json.dumps(
120
+ {
121
+ "columns": _ci,
122
+ "deletedColumns": _sdc,
123
+ "originalInputFields": list(_oif),
124
+ }
125
+ )
126
+ else:
127
+ _sdc = []
128
+ self.column_state = json.dumps(
129
+ {
130
+ "columns": _ci,
131
+ "deletedColumns": [],
132
+ "originalInputFields": list(_oif),
133
+ }
134
+ )
135
+ else:
136
+ _sdc = []
137
+ self.column_state = json.dumps(
138
+ {
139
+ "columns": _ci,
140
+ "deletedColumns": [],
141
+ "originalInputFields": list(_oif),
142
+ }
143
+ )
144
+ except Exception:
145
+ _sdc = []
146
+ self.column_state = json.dumps(
147
+ {
148
+ "columns": _ci,
149
+ "deletedColumns": [],
150
+ "originalInputFields": list(_oif),
151
+ }
152
+ )
153
+ try:
154
+ self._df = _acc(self._df, _ci)
155
+ _js = _bpp(self._df, _ci, _sdc, preview_rows=100)
156
+ if self.web_loaded and self.bridge:
157
+ self.bridge._std(_js)
158
+ self._ao()
159
+ except RuntimeError as _e:
160
+ self.Error.license_error(str(_e))
161
+ self.Outputs.modified_data.send(None)
162
+
163
+ def _occ(self, _s):
164
+ try:
165
+ _st = json.loads(_s)
166
+ _ci = _st.get("columns", [])
167
+ _dc = _st.get("deletedColumns", [])
168
+ try:
169
+ _oif = json.loads(self.column_state).get("originalInputFields", [])
170
+ except Exception:
171
+ _oif = (
172
+ [c["field"] for c in _gci(self._id, self._df)] if self._id else []
173
+ )
174
+ self.column_state = json.dumps(
175
+ {"columns": _ci, "deletedColumns": _dc, "originalInputFields": _oif}
176
+ )
177
+ if self._df is not None:
178
+ self._df = _acc(self._df, _ci)
179
+ self._ao()
180
+ except RuntimeError as _e:
181
+ self.Error.license_error(str(_e))
182
+ self.Outputs.modified_data.send(None)
183
+ except Exception:
184
+ import traceback
185
+
186
+ traceback.print_exc()
187
+
188
+ def _orr(self):
189
+ if self._id is not None:
190
+ self.column_state = (
191
+ '{"columns":[],"deletedColumns":[],"originalInputFields":[]}'
192
+ )
193
+ self.set_data(self._id)
194
+
195
+ def _ao(self):
196
+ if self._df is None or len(self._df.columns) == 0:
197
+ self.Outputs.modified_data.send(None)
198
+ return
199
+ try:
200
+ _ci = json.loads(self.column_state).get("columns", [])
201
+ if not _ci:
202
+ self.Outputs.modified_data.send(self._id)
203
+ return
204
+ self.Outputs.modified_data.send(_d2ocm(self._df, _ci, self._od))
205
+ except RuntimeError as _e:
206
+ self.Error.license_error(str(_e))
207
+ self.Outputs.modified_data.send(None)
208
+ except Exception as _e:
209
+ import traceback
210
+
211
+ traceback.print_exc()
212
+ self.Error.invalid_data(str(_e))
213
+ self.Outputs.modified_data.send(None)