SankeyExcelParser 1.0.0b0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. SankeyExcelParser/__init__.py +0 -0
  2. SankeyExcelParser/io_excel.py +1867 -0
  3. SankeyExcelParser/io_excel_constants.py +811 -0
  4. SankeyExcelParser/sankey.py +3138 -0
  5. SankeyExcelParser/sankey_utils/__init__.py +0 -0
  6. SankeyExcelParser/sankey_utils/data.py +1118 -0
  7. SankeyExcelParser/sankey_utils/excel_source.py +31 -0
  8. SankeyExcelParser/sankey_utils/flux.py +344 -0
  9. SankeyExcelParser/sankey_utils/functions.py +278 -0
  10. SankeyExcelParser/sankey_utils/node.py +340 -0
  11. SankeyExcelParser/sankey_utils/protos/__init__.py +0 -0
  12. SankeyExcelParser/sankey_utils/protos/flux.py +84 -0
  13. SankeyExcelParser/sankey_utils/protos/node.py +386 -0
  14. SankeyExcelParser/sankey_utils/protos/sankey_object.py +135 -0
  15. SankeyExcelParser/sankey_utils/protos/tag_group.py +95 -0
  16. SankeyExcelParser/sankey_utils/sankey_object.py +165 -0
  17. SankeyExcelParser/sankey_utils/table_object.py +37 -0
  18. SankeyExcelParser/sankey_utils/tag.py +95 -0
  19. SankeyExcelParser/sankey_utils/tag_group.py +206 -0
  20. SankeyExcelParser/su_trace.py +239 -0
  21. SankeyExcelParser/tests/integration/__init__.py +0 -0
  22. SankeyExcelParser/tests/integration/test_base.py +356 -0
  23. SankeyExcelParser/tests/integration/test_run_check_input.py +100 -0
  24. SankeyExcelParser/tests/integration/test_run_conversions.py +96 -0
  25. SankeyExcelParser/tests/integration/test_run_load_input.py +94 -0
  26. SankeyExcelParser/tests/unit/__init__.py +0 -0
  27. SankeyExcelParser-1.0.0b0.data/scripts/run_parse_and_write_excel.py +155 -0
  28. SankeyExcelParser-1.0.0b0.data/scripts/run_parse_excel.py +115 -0
  29. SankeyExcelParser-1.0.0b0.dist-info/METADATA +113 -0
  30. SankeyExcelParser-1.0.0b0.dist-info/RECORD +32 -0
  31. SankeyExcelParser-1.0.0b0.dist-info/WHEEL +5 -0
  32. SankeyExcelParser-1.0.0b0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,386 @@
1
+ """
2
+ Author : Vincent LE DOZE
3
+ Date : 31/05/23
4
+
5
+ This file contains descriptions for proto Node class
6
+
7
+ """
8
+
9
+ # External libs ---------------------------------------------------------------
10
+ import re
11
+
12
+ # Local modules -----------------------------------------------------
13
+ from SankeyExcelParser.sankey_utils.sankey_object import SankeyObject
14
+ from SankeyExcelParser.sankey_utils.functions import _stdStr, _convertColorToHex
15
+
16
+
17
+ # CLASS ----------------------------------------------------------------------------
18
+ LOCALISATION_OPTIONS = {
19
+ 'Local': ['locale?', 'domestique'],
20
+ 'Echange': ['echanges?']}
21
+
22
+
23
+ class _ProtoNodeUnit(object):
24
+ """
25
+ Define unit for a data object
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ **kwargs
31
+ ):
32
+ self._natural_unit = None
33
+ self._equivalent_unit = None
34
+ self._equivalent_to_natural = None
35
+ self._natural_to_equivalent = None
36
+ self._other_conversions = {}
37
+ self.update(**kwargs)
38
+
39
+ def update(
40
+ self,
41
+ **kwargs
42
+ ):
43
+ for key, value in kwargs.items():
44
+ setattr(self, key, value)
45
+
46
+ @property
47
+ def natural_unit(self):
48
+ return self._natural_unit
49
+
50
+ @natural_unit.setter
51
+ def natural_unit(self, _):
52
+ # None case
53
+ if _ is None:
54
+ self._natural_unit = None
55
+ return
56
+ # Real affectation
57
+ try:
58
+ self._natural_unit = str(_)
59
+ except Exception:
60
+ pass
61
+
62
+ @property
63
+ def equivalent_unit(self):
64
+ return self._equivalent_unit
65
+
66
+ @property
67
+ def equivalent_to_natural(self):
68
+ return self._equivalent_to_natural
69
+
70
+ @property
71
+ def natural_to_equivalent(self):
72
+ return self._natural_to_equivalent
73
+
74
+ @natural_to_equivalent.setter
75
+ def natural_to_equivalent(self, _):
76
+ # None case
77
+ if _ is None:
78
+ self._natural_to_equivalent = None
79
+ return
80
+ # Real affectation
81
+ try:
82
+ self._natural_to_equivalent = float(_)
83
+ # TODO: div 0 protection ? Or enough with try ?
84
+ self._equivalent_to_natural = (1.0/self._natural_to_equivalent)
85
+ except Exception:
86
+ pass
87
+
88
+ @property
89
+ def other_conversions(self):
90
+ return self._other_conversions
91
+
92
+ def add_other_conversion(self, name, value):
93
+ try:
94
+ f_value = float(value)
95
+ s_name = str(name)
96
+ # NAN protection
97
+ if (f_value != f_value):
98
+ return
99
+ self._other_conversions[s_name] = f_value
100
+ except Exception:
101
+ pass
102
+
103
+
104
+ class _ProtoNode(SankeyObject):
105
+ """
106
+ Define a prototype for node object.
107
+ Does nothing except defining attributes.
108
+ Inherits from `SankeyObject`
109
+
110
+ Parameters
111
+ ----------
112
+
113
+ :param id: Node id (standardized)
114
+ :type id: str
115
+
116
+ :param name: Node name (not standardized, as set by the user)
117
+ :type name: str
118
+
119
+ :param level: Parenthood level of the node.
120
+ 1=Node without parents,
121
+ 2+: Node with parents, ...
122
+ :type level: int
123
+
124
+ :param type: parenthood relationships
125
+ 'SR': Single root,
126
+ 'PR': parent root,
127
+ 'BC': base child,
128
+ 'PC': parent child
129
+ :type level: str
130
+
131
+ :param parents: Lists the parent nodes of the 'self' node.
132
+ :type parents: list [Node, ...]
133
+
134
+ :param children_grps: Lists the groups of child nodes of the 'self' node.
135
+ :type children_grps: list [list[Node, ...], ...]
136
+
137
+ :param input_flux: List of all flux that arrive to this node.
138
+ :type input_flux: list [Flux, ...]
139
+
140
+ :param output_flux: List of all flux that depart from this node.
141
+ :type output_flux: list [Flux, ...]
142
+
143
+ :param mat_balance: Do we respect or not of the matter balance.
144
+ 1: matter balance is respected,
145
+ 0: not respected.
146
+ :type mat_balance: int
147
+
148
+ :param color: Color applied to the node on application
149
+ :type color: str
150
+
151
+ :param definition: Node definition
152
+ :type definition: str
153
+ """
154
+
155
+ def __init__(
156
+ self,
157
+ name: str,
158
+ level: int,
159
+ **kwargs
160
+ ):
161
+ # Init super
162
+ SankeyObject.__init__(self)
163
+ # Id : keep only lower alphanumeric + spaces replaced with "_"
164
+ self._id = re.sub(r'[^a-z0-9 ]', '', _stdStr(name))\
165
+ .title().replace(' ', '')
166
+ # Init default value
167
+ self._name = name
168
+ self._level = level
169
+ # Parents & children
170
+ self._type = None
171
+ self._parents = []
172
+ self._children_grps = [[]]
173
+ self._create_new_children_grp = False
174
+ # Flux
175
+ self._input_flux = []
176
+ self._output_flux = []
177
+ # MFA
178
+ self._unit = {}
179
+ self._mat_balance = None
180
+ # Display on OpenSankey
181
+ self._color = None
182
+ self._definition = None
183
+
184
+ @property
185
+ def id(self):
186
+ return self._id
187
+
188
+ @property
189
+ def name(self):
190
+ return self._name
191
+
192
+ @property
193
+ def level(self):
194
+ return self._level
195
+
196
+ @level.setter
197
+ def level(self, _):
198
+ try:
199
+ self._level = max(1, int(_))
200
+ except Exception:
201
+ pass
202
+
203
+ @property
204
+ def type(self):
205
+ return self._type
206
+
207
+ @type.setter
208
+ def type(self, _):
209
+ if isinstance(_, str):
210
+ upper_ = _.upper()
211
+ if upper_ in ['SR', 'PR', 'BC', 'PC']:
212
+ self._type = upper_
213
+
214
+ @property
215
+ def mat_balance(self):
216
+ return self._mat_balance
217
+
218
+ @mat_balance.setter
219
+ def mat_balance(self, _):
220
+ try:
221
+ self._mat_balance = int(_)
222
+ except Exception:
223
+ pass
224
+
225
+ @property
226
+ def color(self):
227
+ return self._color
228
+
229
+ @property
230
+ def color_in_hex(self):
231
+ return _convertColorToHex(self._color, default_color='#808080') # Grey by default
232
+
233
+ @color.setter
234
+ def color(self, _):
235
+ if type(_) is str:
236
+ if len(_) > 0:
237
+ self._color = _
238
+
239
+ @property
240
+ def definition(self):
241
+ return self._definition
242
+
243
+ @definition.setter
244
+ def definition(self, _):
245
+ if type(_) is str:
246
+ self._definition = None
247
+ if len(_) > 0:
248
+ self._definition = _
249
+ return
250
+ if _ is None:
251
+ self._definition = None
252
+
253
+ @property
254
+ def parents(self):
255
+ return self._parents.copy()
256
+
257
+ def get_all_parents(self, limit=-1):
258
+ # if limit < 0, output = all existing parent, grand-parents, grand-grand-parents, etc...
259
+ if limit < 0:
260
+ if len(self._parents) == 0:
261
+ return []
262
+ else:
263
+ all_parents = self._parents.copy() # Beware modifying references
264
+ for parent in self._parents:
265
+ all_parents += parent.get_all_parents()
266
+ return all_parents
267
+ # if limit = 0, output = current node parents
268
+ # if limit = 1, output = current node parents + grand-parents
269
+ # if limit = 2, outpur = current node parents + grand-parents + grand-grand-parents
270
+ # etc...
271
+ elif limit == 0:
272
+ return self._parents
273
+ else:
274
+ all_parents = self._parents.copy()
275
+ for parent in self._parents:
276
+ all_parents += parent.get_all_parents(limit=limit-1)
277
+ return all_parents
278
+
279
+ @property
280
+ def children_grps(self):
281
+ return [_.copy() for _ in self._children_grps]
282
+
283
+ def get_brothers_grps(self):
284
+ """
285
+ Return dict of list of brothers nodes, ie nodes that share the same parent as self.
286
+ Brothers are referenced by their shared parents
287
+
288
+ Returns
289
+ -------
290
+ :return: Groups of existing brothers per parents
291
+ :rtype: list[ list[bro1, bro2, ...], ... ]
292
+ """
293
+ brothers = []
294
+ # No parents -> No brothers
295
+ if len(self.parents) == 0:
296
+ return brothers
297
+ # There are parents
298
+ for parent in self.parents:
299
+ for grp in parent.children_grps:
300
+ # Parent can have children grp where self does not belong
301
+ if self in grp:
302
+ # Remove self from brothers
303
+ grp.remove(self) # Safe : With children_grps setter, grp is a copy
304
+ brothers.append(grp)
305
+ return brothers
306
+
307
+ @property
308
+ def input_flux(self):
309
+ return self._input_flux.copy()
310
+
311
+ @property
312
+ def output_flux(self):
313
+ return self._output_flux.copy()
314
+
315
+ @property
316
+ def unit(self):
317
+ return self._unit
318
+
319
+ @property
320
+ def has_unit(self):
321
+ return len(self._unit) > 0
322
+
323
+ @property
324
+ def unit_localisation(self):
325
+ return list(self._unit.keys())
326
+
327
+ def get_natural_unit(self, localisation=None):
328
+ try:
329
+ if localisation is None:
330
+ return self._unit[self.unit_localisation[0]].natural_unit
331
+ else:
332
+ return self._unit[localisation].natural_unit
333
+ except Exception:
334
+ pass
335
+ return None
336
+
337
+ def add_natural_unit(self, _, localisation='Local'):
338
+ if localisation is not None:
339
+ if localisation in self._unit.keys():
340
+ self._unit[localisation].natural_unit = _
341
+ else:
342
+ self._unit[localisation] = _ProtoNodeUnit(natural_unit=_)
343
+
344
+ def get_factor(self, localisation=None):
345
+ try:
346
+ if localisation is None:
347
+ return self._unit[self.unit_localisation[0]].natural_to_equivalent
348
+ else:
349
+ return self._unit[localisation].natural_to_equivalent
350
+ except Exception:
351
+ pass
352
+ return None
353
+
354
+ def add_factor(self, _, localisation='Local'):
355
+ if localisation is not None:
356
+ if localisation in self._unit.keys():
357
+ self._unit[localisation].natural_to_equivalent = _
358
+ else:
359
+ self._unit[localisation] = _ProtoNodeUnit(natural_to_equivalent=_)
360
+
361
+ def get_other_factors(self, localisation=None):
362
+ try:
363
+ if localisation is None:
364
+ return self._unit[self.unit_localisation[0]].other_conversions
365
+ else:
366
+ return self._unit[localisation].other_conversions
367
+ except Exception:
368
+ pass
369
+ return None
370
+
371
+ def add_other_factor(self, name, factor, localisation='Local'):
372
+ if localisation is not None:
373
+ if localisation not in self._unit.keys():
374
+ self._unit[localisation] = _ProtoNodeUnit()
375
+ self._unit[localisation].add_other_conversion(name, factor)
376
+
377
+ def match_localisation(self, _):
378
+ try:
379
+ localisation = str(_)
380
+ for localisation_option, localisation_res in LOCALISATION_OPTIONS.items():
381
+ for localisation_re in localisation_res:
382
+ if re.fullmatch(localisation_re, _stdStr(localisation)):
383
+ return localisation_option
384
+ except Exception:
385
+ pass
386
+ return None
@@ -0,0 +1,135 @@
1
+ """
2
+ Author : Vincent LE DOZE
3
+ Date : 31/05/23
4
+
5
+ This file contains descriptions for sankey proto class
6
+
7
+ """
8
+
9
+
10
+ # Local modules -----------------------------------------------------
11
+ from SankeyExcelParser.sankey_utils.table_object import TableObject
12
+
13
+
14
+ # CLASS ----------------------------------------------------------------------------
15
+ class _ProtoToolTip(object):
16
+ """
17
+ Proto class for Tooltip
18
+
19
+ Parameters
20
+ ----------
21
+ :param name: Tooltip name
22
+ :type name: str
23
+
24
+ :param description: Tooltip description
25
+ :type description: str
26
+
27
+ :param content: Tooltip content
28
+ :type content: str
29
+ """
30
+ def __init__(
31
+ self,
32
+ **kwargs
33
+ ):
34
+ self._name = None
35
+ self._description = None
36
+ self._content = None
37
+ self.update(**kwargs)
38
+
39
+ def update(
40
+ self,
41
+ **kwargs
42
+ ):
43
+ for key, value in kwargs.items():
44
+ setattr(self, key, value)
45
+
46
+ @property
47
+ def name(self):
48
+ return self._name
49
+
50
+ @name.setter
51
+ def name(self, _):
52
+ # None case
53
+ if _ is None:
54
+ self._name = None
55
+ return
56
+ # Real affectation
57
+ try:
58
+ self._name = str(_)
59
+ except Exception:
60
+ pass
61
+
62
+ @property
63
+ def description(self):
64
+ return self._description
65
+
66
+ @description.setter
67
+ def description(self, _):
68
+ # None case
69
+ if _ is None:
70
+ self._description = None
71
+ return
72
+ # Real affectation
73
+ try:
74
+ self._description = str(_)
75
+ except Exception:
76
+ pass
77
+
78
+ @property
79
+ def content(self):
80
+ return self._content
81
+
82
+ @content.setter
83
+ def content(self, _):
84
+ # None case
85
+ if _ is None:
86
+ self._content = None
87
+ return
88
+ # Real affectation
89
+ try:
90
+ self._content = str(_)
91
+ except Exception:
92
+ pass
93
+
94
+
95
+ class _ProtoSankeyObject(TableObject):
96
+ """
97
+ Proto class for SankeyObject.
98
+ Define a generic sankey object.
99
+ herits from TableObject.
100
+
101
+ Parameters
102
+ ----------
103
+ :param tags: List of tags of this object.
104
+ :type tags: list [_ProtoTag, ...]
105
+ """
106
+
107
+ def __init__(self):
108
+ # Init parent class
109
+ TableObject.__init__(self)
110
+ # Init attributes
111
+ self._tags = []
112
+ self._taggs = []
113
+ # List of tooltips
114
+ self._tooltips = {}
115
+
116
+ @property
117
+ def tags(self):
118
+ return self._tags
119
+
120
+ @property
121
+ def taggs(self):
122
+ return self._taggs
123
+
124
+ @property
125
+ def tooltips(self):
126
+ return self._tooltips
127
+
128
+ def add_tooltip(self, name, description, content):
129
+ self._tooltips[name] = _ProtoToolTip(
130
+ name=name,
131
+ description=description,
132
+ content=content)
133
+
134
+ def update_tooltip(self, name, **kwargs):
135
+ self._tooltips[name].update(**kwargs)
@@ -0,0 +1,95 @@
1
+ """
2
+ Author : Vincent LE DOZE
3
+ Date : 31/05/23
4
+
5
+ This file contains descriptions for proto TagGroup class
6
+
7
+ """
8
+
9
+ # Local modules -----------------------------------------------------
10
+ from SankeyExcelParser.sankey_utils.table_object import TableObject
11
+ from SankeyExcelParser.sankey_utils.functions import _stdStr
12
+
13
+
14
+ # CLASS ----------------------------------------------------------------------------
15
+ class _ProtoTagGroup(TableObject):
16
+ """
17
+ Proto class for TagGroup
18
+ Define a Tag Group object.
19
+
20
+ Parameters
21
+ ----------
22
+ :param name: Name of the groupe (standardized)
23
+ :type name: str
24
+
25
+ :param name_unformatted: Name of the groupe (not standardized, as written by the user)
26
+ :type name_unformatted: str
27
+
28
+ :param tags: All tags contained by the group as dictionnary, with standardized tags name as entries.
29
+ :type tags: dict = {str: Tag, ...}
30
+
31
+ :param is_palette: Is the tag group a palette.
32
+ :type is_palette: int
33
+
34
+ :param colormap: Color map for tags colors.
35
+ :type colormap: str
36
+
37
+ :param color: Colors for each tags.
38
+ :type color: str
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ name: str,
44
+ taggtype: str
45
+ ):
46
+ # Init parent class
47
+ TableObject.__init__(self)
48
+ # Init attributes
49
+ self._name = _stdStr(name)
50
+ self._name_unformatted = name
51
+ self._type = taggtype
52
+ self._tags = {}
53
+ self._anti_tags = None
54
+ self._antagonists_taggs = []
55
+ self._is_palette = None
56
+ self._colormap = None
57
+
58
+ @property
59
+ def name(self):
60
+ return self._name
61
+
62
+ @property
63
+ def name_unformatted(self):
64
+ return self._name_unformatted
65
+
66
+ @property
67
+ def type(self):
68
+ return self._type
69
+
70
+ @property
71
+ def is_palette(self):
72
+ return self._is_palette
73
+
74
+ @is_palette.setter
75
+ def is_palette(self, _):
76
+ try:
77
+ self._is_palette = int(_)
78
+ except Exception:
79
+ pass
80
+
81
+ @property
82
+ def has_palette(self):
83
+ try:
84
+ return (self._is_palette > 0)
85
+ except Exception:
86
+ return False
87
+
88
+ @property
89
+ def colormap(self):
90
+ return self._colormap
91
+
92
+ @colormap.setter
93
+ def colormap(self, _):
94
+ if type(_) is str:
95
+ self._colormap = _