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.
- altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/PKG-INFO +21 -0
- altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/SOURCES.txt +48 -0
- altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/dependency_links.txt +1 -0
- altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/entry_points.txt +5 -0
- altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/requires.txt +11 -0
- altera_data_suite-1.0.0/Altera_Data_Suite.egg-info/top_level.txt +1 -0
- altera_data_suite-1.0.0/MANIFEST.in +5 -0
- altera_data_suite-1.0.0/PKG-INFO +21 -0
- altera_data_suite-1.0.0/README.md +40 -0
- altera_data_suite-1.0.0/orangecontrib/__init__.py +3 -0
- altera_data_suite-1.0.0/orangecontrib/custom/__init__.py +0 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/__init__.py +28 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/cleaner.py +139 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/columns_manager.py +213 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/filter_builder.py +166 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/header_promoter.py +178 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/horizontal_stack.py +173 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/3-squares.svg +6 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/category.svg +27 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/cleaner.svg +29 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/color_filter.svg +21 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/column_manager.svg +16 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/edit_column.svg +19 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/filter.svg +17 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/header_promoter.svg +12 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/hstack.svg +17 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/link.svg +23 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/multishift.svg +17 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/passthrough.svg +11 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/pdf_converter.svg +99 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/regex.svg +12 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/regular_filter.svg +4 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/settings.svg +29 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/shift.svg +14 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/icons/spreadsheet.svg +104 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/multishift.py +143 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/passthrough.py +84 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/pdf_converter.py +354 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/regex.py +174 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/settings.py +106 -0
- altera_data_suite-1.0.0/orangecontrib/custom/widgets/web_utils.py +213 -0
- altera_data_suite-1.0.0/pyproject.toml +3 -0
- altera_data_suite-1.0.0/setup.cfg +4 -0
- 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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
orangecontrib
|
|
@@ -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
|
+

|
|
File without changes
|
|
@@ -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)
|