|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2016 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing classes and functions to dump variable contents. |
|
8 """ |
|
9 |
|
10 import contextlib |
|
11 import sys |
|
12 |
|
13 from collections.abc import ItemsView, KeysView, ValuesView |
|
14 |
|
15 from DebugConfig import ConfigQtNames, ConfigKnownQtTypes, BatchSize |
|
16 |
|
17 # |
|
18 # This code was inspired by pydevd. |
|
19 # |
|
20 |
|
21 ############################################################ |
|
22 ## Classes implementing resolvers for various compound types |
|
23 ############################################################ |
|
24 |
|
25 |
|
26 class BaseResolver: |
|
27 """ |
|
28 Base class of the resolver class tree. |
|
29 """ |
|
30 |
|
31 def resolve(self, var, attribute): |
|
32 """ |
|
33 Public method to get an attribute from a variable. |
|
34 |
|
35 @param var variable to extract an attribute or value from |
|
36 @type any |
|
37 @param attribute name of the attribute to extract |
|
38 @type str |
|
39 @return value of the attribute |
|
40 @rtype any |
|
41 """ |
|
42 return getattr(var, attribute, None) |
|
43 |
|
44 def getVariableList(self, var): |
|
45 """ |
|
46 Public method to get the attributes of a variable as a list. |
|
47 |
|
48 @param var variable to be converted |
|
49 @type any |
|
50 @return list containing the variable attributes |
|
51 @rtype list |
|
52 """ |
|
53 d = [] |
|
54 for name in dir(var): |
|
55 with contextlib.suppress(Exception): |
|
56 attribute = getattr(var, name) |
|
57 d.append((name, attribute)) |
|
58 |
|
59 return d |
|
60 |
|
61 |
|
62 ############################################################ |
|
63 ## Default Resolver |
|
64 ############################################################ |
|
65 |
|
66 |
|
67 class DefaultResolver(BaseResolver): |
|
68 """ |
|
69 Class used to resolve the default way. |
|
70 """ |
|
71 |
|
72 def getVariableList(self, var): |
|
73 """ |
|
74 Public method to get the attributes of a variable as a list. |
|
75 |
|
76 @param var variable to be converted |
|
77 @type any |
|
78 @yield tuple containing the batch start index and a list |
|
79 containing the variable attributes |
|
80 @ytype tuple of (int, list) |
|
81 """ |
|
82 d = [] |
|
83 for name in dir(var): |
|
84 with contextlib.suppress(Exception): |
|
85 attribute = getattr(var, name) |
|
86 d.append((name, attribute)) |
|
87 |
|
88 yield -1, d |
|
89 while True: |
|
90 yield -2, [] |
|
91 |
|
92 |
|
93 ############################################################ |
|
94 ## Resolver for Dictionaries |
|
95 ############################################################ |
|
96 |
|
97 |
|
98 class DictResolver(BaseResolver): |
|
99 """ |
|
100 Class used to resolve from a dictionary. |
|
101 """ |
|
102 |
|
103 def resolve(self, var, attribute): |
|
104 """ |
|
105 Public method to get an attribute from a variable. |
|
106 |
|
107 @param var variable to extract an attribute or value from |
|
108 @type dict |
|
109 @param attribute name of the attribute to extract |
|
110 @type str |
|
111 @return value of the attribute |
|
112 @rtype any |
|
113 """ |
|
114 if " (ID:" not in attribute: |
|
115 try: |
|
116 return var[attribute] |
|
117 except Exception: |
|
118 return getattr(var, attribute, None) |
|
119 |
|
120 expectedID = int(attribute.split(" (ID:")[-1][:-1]) |
|
121 for key, value in var.items(): |
|
122 if id(key) == expectedID: |
|
123 return value |
|
124 |
|
125 return None |
|
126 |
|
127 def keyToStr(self, key): |
|
128 """ |
|
129 Public method to get a string representation for a key. |
|
130 |
|
131 @param key key to be converted |
|
132 @type any |
|
133 @return string representation of the given key |
|
134 @rtype str |
|
135 """ |
|
136 if isinstance(key, str): |
|
137 key = repr(key) |
|
138 # Special handling for bytes object |
|
139 # Raw and f-Strings are always converted to str |
|
140 if key[0] == "b": |
|
141 key = key[1:] |
|
142 |
|
143 return key # __IGNORE_WARNING_M834__ |
|
144 |
|
145 def getVariableList(self, var): |
|
146 """ |
|
147 Public method to get the attributes of a variable as a list. |
|
148 |
|
149 @param var variable to be converted |
|
150 @type any |
|
151 @yield tuple containing the batch start index and a list |
|
152 containing the variable attributes |
|
153 @ytype tuple of (int, list) |
|
154 """ |
|
155 d = [] |
|
156 start = count = 0 |
|
157 allItems = list(var.items()) |
|
158 try: |
|
159 # Fast path: all items from same type |
|
160 allItems.sort(key=lambda x: x[0]) |
|
161 except TypeError: |
|
162 # Slow path: only sort items with same type (Py3 only) |
|
163 allItems.sort(key=lambda x: (str(x[0]), x[0])) |
|
164 |
|
165 for key, value in allItems: |
|
166 key = "{0} (ID:{1})".format(self.keyToStr(key), id(key)) |
|
167 d.append((key, value)) |
|
168 count += 1 |
|
169 if count >= BatchSize: |
|
170 yield start, d |
|
171 start += count |
|
172 count = 0 |
|
173 d = [] |
|
174 |
|
175 if d: |
|
176 yield start, d |
|
177 |
|
178 # in case it has additional fields |
|
179 d = super().getVariableList(var) |
|
180 yield -1, d |
|
181 |
|
182 while True: |
|
183 yield -2, [] |
|
184 |
|
185 |
|
186 ############################################################ |
|
187 ## Resolver for Lists and Tuples |
|
188 ############################################################ |
|
189 |
|
190 |
|
191 class ListResolver(BaseResolver): |
|
192 """ |
|
193 Class used to resolve from a tuple or list. |
|
194 """ |
|
195 |
|
196 def resolve(self, var, attribute): |
|
197 """ |
|
198 Public method to get an attribute from a variable. |
|
199 |
|
200 @param var variable to extract an attribute or value from |
|
201 @type tuple or list |
|
202 @param attribute name of the attribute to extract |
|
203 @type str |
|
204 @return value of the attribute |
|
205 @rtype any |
|
206 """ |
|
207 try: |
|
208 return var[int(attribute)] |
|
209 except Exception: |
|
210 return getattr(var, str(attribute), None) |
|
211 |
|
212 def getVariableList(self, var): |
|
213 """ |
|
214 Public method to get the attributes of a variable as a list. |
|
215 |
|
216 @param var variable to be converted |
|
217 @type any |
|
218 @yield tuple containing the batch start index and a list |
|
219 containing the variable attributes |
|
220 @ytype tuple of (int, list) |
|
221 """ |
|
222 d = [] |
|
223 start = count = 0 |
|
224 for idx, value in enumerate(var): |
|
225 d.append((idx, value)) |
|
226 count += 1 |
|
227 if count >= BatchSize: |
|
228 yield start, d |
|
229 start = idx + 1 |
|
230 count = 0 |
|
231 d = [] |
|
232 |
|
233 if d: |
|
234 yield start, d |
|
235 |
|
236 # in case it has additional fields |
|
237 d = super().getVariableList(var) |
|
238 yield -1, d |
|
239 |
|
240 while True: |
|
241 yield -2, [] |
|
242 |
|
243 |
|
244 ############################################################ |
|
245 ## Resolver for dict_items, dict_keys and dict_values |
|
246 ############################################################ |
|
247 |
|
248 |
|
249 class DictViewResolver(ListResolver): |
|
250 """ |
|
251 Class used to resolve from dict views. |
|
252 """ |
|
253 |
|
254 def resolve(self, var, attribute): |
|
255 """ |
|
256 Public method to get an attribute from a variable. |
|
257 |
|
258 @param var variable to extract an attribute or value from |
|
259 @type dict_items, dict_keys or dict_values |
|
260 @param attribute id of the value to extract |
|
261 @type str |
|
262 @return value of the attribute |
|
263 @rtype any |
|
264 """ |
|
265 return super().resolve(list(var), attribute) |
|
266 |
|
267 def getVariableList(self, var): |
|
268 """ |
|
269 Public method to get the attributes of a variable as a list. |
|
270 |
|
271 @param var variable to be converted |
|
272 @type any |
|
273 @yield tuple containing the batch start index and a list |
|
274 containing the variable attributes |
|
275 @ytype tuple of (int, list) |
|
276 """ |
|
277 yield from super().getVariableList(list(var)) |
|
278 |
|
279 |
|
280 ############################################################ |
|
281 ## Resolver for Sets and Frozensets |
|
282 ############################################################ |
|
283 |
|
284 |
|
285 class SetResolver(BaseResolver): |
|
286 """ |
|
287 Class used to resolve from a set or frozenset. |
|
288 """ |
|
289 |
|
290 def resolve(self, var, attribute): |
|
291 """ |
|
292 Public method to get an attribute from a variable. |
|
293 |
|
294 @param var variable to extract an attribute or value from |
|
295 @type tuple or list |
|
296 @param attribute id of the value to extract |
|
297 @type str |
|
298 @return value of the attribute |
|
299 @rtype any |
|
300 """ |
|
301 if attribute.startswith("'ID: "): |
|
302 attribute = attribute.split(None, 1)[1][:-1] |
|
303 try: |
|
304 attribute = int(attribute) |
|
305 except Exception: |
|
306 return getattr(var, attribute, None) |
|
307 |
|
308 for v in var: |
|
309 if id(v) == attribute: |
|
310 return v |
|
311 |
|
312 return None |
|
313 |
|
314 def getVariableList(self, var): |
|
315 """ |
|
316 Public method to get the attributes of a variable as a list. |
|
317 |
|
318 @param var variable to be converted |
|
319 @type any |
|
320 @yield tuple containing the batch start index and a list |
|
321 containing the variable attributes |
|
322 @ytype tuple of (int, list) |
|
323 """ |
|
324 d = [] |
|
325 start = count = 0 |
|
326 for value in var: |
|
327 count += 1 |
|
328 d.append(("'ID: {0}'".format(id(value)), value)) |
|
329 if count >= BatchSize: |
|
330 yield start, d |
|
331 start += count |
|
332 count = 0 |
|
333 d = [] |
|
334 |
|
335 if d: |
|
336 yield start, d |
|
337 |
|
338 # in case it has additional fields |
|
339 d = super().getVariableList(var) |
|
340 yield -1, d |
|
341 |
|
342 while True: |
|
343 yield -2, [] |
|
344 |
|
345 |
|
346 ############################################################ |
|
347 ## Resolver for Numpy Arrays |
|
348 ############################################################ |
|
349 |
|
350 |
|
351 class NdArrayResolver(BaseResolver): |
|
352 """ |
|
353 Class used to resolve from numpy ndarray including some meta data. |
|
354 """ |
|
355 |
|
356 def __isNumeric(self, arr): |
|
357 """ |
|
358 Private method to check, if an array is of a numeric type. |
|
359 |
|
360 @param arr array to check |
|
361 @type ndarray |
|
362 @return flag indicating a numeric array |
|
363 @rtype bool |
|
364 """ |
|
365 try: |
|
366 return arr.dtype.kind in "biufc" |
|
367 except AttributeError: |
|
368 return False |
|
369 |
|
370 def resolve(self, var, attribute): |
|
371 """ |
|
372 Public method to get an attribute from a variable. |
|
373 |
|
374 @param var variable to extract an attribute or value from |
|
375 @type ndarray |
|
376 @param attribute id of the value to extract |
|
377 @type str |
|
378 @return value of the attribute |
|
379 @rtype any |
|
380 """ |
|
381 if attribute == "min": |
|
382 if self.__isNumeric(var): |
|
383 return var.min() |
|
384 else: |
|
385 return None |
|
386 |
|
387 if attribute == "max": |
|
388 if self.__isNumeric(var): |
|
389 return var.max() |
|
390 else: |
|
391 return None |
|
392 |
|
393 if attribute == "mean": |
|
394 if self.__isNumeric(var): |
|
395 return var.mean() |
|
396 else: |
|
397 return None |
|
398 |
|
399 try: |
|
400 return var[int(attribute)] |
|
401 except Exception: |
|
402 return getattr(var, attribute, None) |
|
403 |
|
404 return None |
|
405 |
|
406 def getVariableList(self, var): |
|
407 """ |
|
408 Public method to get the attributes of a variable as a list. |
|
409 |
|
410 @param var variable to be converted |
|
411 @type any |
|
412 @yield tuple containing the batch start index and a list |
|
413 containing the variable attributes |
|
414 @ytype tuple of (int, list) |
|
415 """ |
|
416 d = [] |
|
417 start = count = 0 |
|
418 try: |
|
419 len(var) # Check if it's an unsized object, e.g. np.ndarray(()) |
|
420 allItems = var.tolist() |
|
421 except TypeError: # TypeError: len() of unsized object |
|
422 allItems = [] |
|
423 |
|
424 for idx, value in enumerate(allItems): |
|
425 d.append((str(idx), value)) |
|
426 count += 1 |
|
427 if count >= BatchSize: |
|
428 yield start, d |
|
429 start += count |
|
430 count = 0 |
|
431 d = [] |
|
432 |
|
433 if d: |
|
434 yield start, d |
|
435 |
|
436 # in case it has additional fields |
|
437 d = super().getVariableList(var) |
|
438 |
|
439 if var.size > 1024 * 1024: |
|
440 d.append( |
|
441 ("min", "ndarray too big, calculating min would slow down debugging") |
|
442 ) |
|
443 d.append( |
|
444 ("max", "ndarray too big, calculating max would slow down debugging") |
|
445 ) |
|
446 d.append( |
|
447 ("mean", "ndarray too big, calculating mean would slow down debugging") |
|
448 ) |
|
449 elif self.__isNumeric(var): |
|
450 if var.size == 0: |
|
451 d.append(("min", "empty array")) |
|
452 d.append(("max", "empty array")) |
|
453 d.append(("mean", "empty array")) |
|
454 else: |
|
455 d.append(("min", var.min())) |
|
456 d.append(("max", var.max())) |
|
457 d.append(("mean", var.mean())) |
|
458 else: |
|
459 d.append(("min", "not a numeric object")) |
|
460 d.append(("max", "not a numeric object")) |
|
461 d.append(("mean", "not a numeric object")) |
|
462 |
|
463 yield -1, d |
|
464 |
|
465 while True: |
|
466 yield -2, [] |
|
467 |
|
468 |
|
469 ############################################################ |
|
470 ## Resolver for Django Multi Value Dictionaries |
|
471 ############################################################ |
|
472 |
|
473 |
|
474 class MultiValueDictResolver(DictResolver): |
|
475 """ |
|
476 Class used to resolve from Django multi value dictionaries. |
|
477 """ |
|
478 |
|
479 def resolve(self, var, attribute): |
|
480 """ |
|
481 Public method to get an attribute from a variable. |
|
482 |
|
483 @param var variable to extract an attribute or value from |
|
484 @type MultiValueDict |
|
485 @param attribute name of the attribute to extract |
|
486 @type str |
|
487 @return value of the attribute |
|
488 @rtype any |
|
489 """ |
|
490 if " (ID:" not in attribute: |
|
491 try: |
|
492 return var[attribute] |
|
493 except Exception: |
|
494 return getattr(var, attribute, None) |
|
495 |
|
496 expectedID = int(attribute.split(" (ID:")[-1][:-1]) |
|
497 for key in var: |
|
498 if id(key) == expectedID: |
|
499 return var.getlist(key) |
|
500 |
|
501 return None |
|
502 |
|
503 def getVariableList(self, var): |
|
504 """ |
|
505 Public method to get the attributes of a variable as a list. |
|
506 |
|
507 @param var variable to be converted |
|
508 @type any |
|
509 @yield tuple containing the batch start index and a list |
|
510 containing the variable attributes |
|
511 @ytype tuple of (int, list) |
|
512 """ |
|
513 d = [] |
|
514 start = count = 0 |
|
515 allKeys = list(var.keys()) |
|
516 try: |
|
517 # Fast path: all items from same type |
|
518 allKeys.sort() |
|
519 except TypeError: |
|
520 # Slow path: only sort items with same type (Py3 only) |
|
521 allKeys.sort(key=lambda x: (str(x), x)) |
|
522 |
|
523 for key in allKeys: |
|
524 dkey = "{0} (ID:{1})".format(self.keyToStr(key), id(key)) |
|
525 d.append((dkey, var.getlist(key))) |
|
526 count += 1 |
|
527 if count >= BatchSize: |
|
528 yield start, d |
|
529 start += count |
|
530 count = 0 |
|
531 d = [] |
|
532 |
|
533 if d: |
|
534 yield start, d |
|
535 |
|
536 # in case it has additional fields |
|
537 d = super(DictResolver, self).getVariableList(var) |
|
538 yield -1, d |
|
539 |
|
540 while True: |
|
541 yield -2, [] |
|
542 |
|
543 |
|
544 ############################################################ |
|
545 ## Resolver for array.array |
|
546 ############################################################ |
|
547 |
|
548 |
|
549 class ArrayResolver(BaseResolver): |
|
550 """ |
|
551 Class used to resolve from array.array including some meta data. |
|
552 """ |
|
553 |
|
554 TypeCodeMap = { |
|
555 "b": "int (signed char)", |
|
556 "B": "int (unsigned char)", |
|
557 "u": "Unicode character (Py_UNICODE)", |
|
558 "h": "int (signed short)", |
|
559 "H": "int (unsigned short)", |
|
560 "i": "int (signed int)", |
|
561 "I": "int (unsigned int)", |
|
562 "l": "int (signed long)", |
|
563 "L": "int (unsigned long)", |
|
564 "q": "int (signed long long)", |
|
565 "Q": "int (unsigned long long)", |
|
566 "f": "float (float)", |
|
567 "d": "float (double)", |
|
568 } |
|
569 |
|
570 def resolve(self, var, attribute): |
|
571 """ |
|
572 Public method to get an attribute from a variable. |
|
573 |
|
574 @param var variable to extract an attribute or value from |
|
575 @type array.array |
|
576 @param attribute id of the value to extract |
|
577 @type str |
|
578 @return value of the attribute |
|
579 @rtype any |
|
580 """ |
|
581 try: |
|
582 return var[int(attribute)] |
|
583 except Exception: |
|
584 return getattr(var, attribute, None) |
|
585 |
|
586 return None |
|
587 |
|
588 def getVariableList(self, var): |
|
589 """ |
|
590 Public method to get the attributes of a variable as a list. |
|
591 |
|
592 @param var variable to be converted |
|
593 @type any |
|
594 @yield tuple containing the batch start index and a list |
|
595 containing the variable attributes |
|
596 @ytype tuple of (int, list) |
|
597 """ |
|
598 d = [] |
|
599 start = count = 0 |
|
600 allItems = var.tolist() |
|
601 |
|
602 for idx, value in enumerate(allItems): |
|
603 d.append((str(idx), value)) |
|
604 count += 1 |
|
605 if count >= BatchSize: |
|
606 yield start, d |
|
607 start += count |
|
608 count = 0 |
|
609 d = [] |
|
610 |
|
611 if d: |
|
612 yield start, d |
|
613 |
|
614 # in case it has additional fields |
|
615 d = super().getVariableList(var) |
|
616 |
|
617 # Special data for array type: convert typecode to readable text |
|
618 d.append(("type", self.TypeCodeMap.get(var.typecode, "illegal type"))) |
|
619 |
|
620 yield -1, d |
|
621 |
|
622 while True: |
|
623 yield -2, [] |
|
624 |
|
625 |
|
626 ############################################################ |
|
627 ## PySide / PyQt Resolver |
|
628 ############################################################ |
|
629 |
|
630 |
|
631 class QtResolver(BaseResolver): |
|
632 """ |
|
633 Class used to resolve the Qt implementations. |
|
634 """ |
|
635 |
|
636 def resolve(self, var, attribute): |
|
637 """ |
|
638 Public method to get an attribute from a variable. |
|
639 |
|
640 @param var variable to extract an attribute or value from |
|
641 @type Qt objects |
|
642 @param attribute name of the attribute to extract |
|
643 @type str |
|
644 @return value of the attribute |
|
645 @rtype any |
|
646 """ |
|
647 if attribute == "internalPointer": |
|
648 return var.internalPointer() |
|
649 |
|
650 return getattr(var, attribute, None) |
|
651 |
|
652 def getVariableList(self, var): |
|
653 """ |
|
654 Public method to get the attributes of a variable as a list. |
|
655 |
|
656 @param var variable to be converted |
|
657 @type any |
|
658 @yield tuple containing the batch start index and a list |
|
659 containing the variable attributes |
|
660 @ytype tuple of (int, list) |
|
661 """ |
|
662 d = [] |
|
663 attributes = () |
|
664 # Gently handle exception which could occure as special |
|
665 # cases, e.g. already deleted C++ objects, str conversion.. |
|
666 with contextlib.suppress(Exception): |
|
667 qttype = type(var).__name__ |
|
668 |
|
669 if qttype in ("QLabel", "QPushButton"): |
|
670 attributes = ("text",) |
|
671 elif qttype == "QByteArray": |
|
672 d.append(("bytes", bytes(var))) |
|
673 d.append(("hex", "QByteArray", "{0}".format(var.toHex()))) |
|
674 d.append(("base64", "QByteArray", "{0}".format(var.toBase64()))) |
|
675 d.append( |
|
676 ( |
|
677 "percent encoding", |
|
678 "QByteArray", |
|
679 "{0}".format(var.toPercentEncoding()), |
|
680 ) |
|
681 ) |
|
682 elif qttype in ("QPoint", "QPointF"): |
|
683 attributes = ("x", "y") |
|
684 elif qttype in ("QRect", "QRectF"): |
|
685 attributes = ("x", "y", "width", "height") |
|
686 elif qttype in ("QSize", "QSizeF"): |
|
687 attributes = ("width", "height") |
|
688 elif qttype == "QColor": |
|
689 attributes = ("name",) |
|
690 r, g, b, a = var.getRgb() |
|
691 d.append(("rgba", "{0:d}, {1:d}, {2:d}, {3:d}".format(r, g, b, a))) |
|
692 h, s, v, a = var.getHsv() |
|
693 d.append(("hsva", "{0:d}, {1:d}, {2:d}, {3:d}".format(h, s, v, a))) |
|
694 c, m, y, k, a = var.getCmyk() |
|
695 d.append( |
|
696 ("cmyka", "{0:d}, {1:d}, {2:d}, {3:d}, {4:d}".format(c, m, y, k, a)) |
|
697 ) |
|
698 elif qttype in ("QDate", "QTime", "QDateTime"): |
|
699 d.append((qttype[1:].lower(), var.toString())) |
|
700 elif qttype == "QDir": |
|
701 attributes = ("path", "absolutePath", "canonicalPath") |
|
702 elif qttype == "QFile": |
|
703 attributes = ("fileName",) |
|
704 elif qttype == "QFont": |
|
705 attributes = ("family", "pointSize", "weight", "bold", "italic") |
|
706 elif qttype == "QUrl": |
|
707 d.append(("url", var.toString())) |
|
708 attributes = ("scheme", "userName", "password", "host", "port", "path") |
|
709 elif qttype == "QModelIndex": |
|
710 valid = var.isValid() |
|
711 d.append(("valid", valid)) |
|
712 if valid: |
|
713 d.append(("internalPointer", var.internalPointer())) |
|
714 attributes = ("row", "column", "internalId") |
|
715 elif qttype in ("QRegExp", "QRegularExpression"): |
|
716 attributes = ("pattern",) |
|
717 |
|
718 # GUI stuff |
|
719 elif qttype == "QAction": |
|
720 d.append(("shortcut", var.shortcut().toString())) |
|
721 attributes = ("objectName", "text", "iconText", "toolTip", "whatsThis") |
|
722 |
|
723 elif qttype == "QKeySequence": |
|
724 d.append(("keySequence", var.toString())) |
|
725 |
|
726 # XML stuff |
|
727 elif qttype == "QDomAttr": |
|
728 attributes = ("name", "var") |
|
729 elif qttype in ("QDomCharacterData", "QDomComment", "QDomText"): |
|
730 attributes = ("data",) |
|
731 elif qttype == "QDomDocument": |
|
732 d.append(("text", var.toString())) |
|
733 elif qttype == "QDomElement": |
|
734 attributes = ("tagName", "text") |
|
735 |
|
736 # Networking stuff |
|
737 elif qttype == "QHostAddress": |
|
738 d.append(("address", var.toString())) |
|
739 |
|
740 # PySide specific |
|
741 elif qttype == "EnumType": # Not in PyQt possible |
|
742 for key, value in var.values.items(): |
|
743 d.append((key, int(value))) |
|
744 |
|
745 for attribute in attributes: |
|
746 d.append((attribute, getattr(var, attribute)())) |
|
747 |
|
748 # add additional fields |
|
749 if qttype != "EnumType": |
|
750 d.extend(super().getVariableList(var)) |
|
751 |
|
752 yield -1, d |
|
753 while True: |
|
754 yield -2, [] |
|
755 |
|
756 |
|
757 defaultResolver = DefaultResolver() |
|
758 dictResolver = DictResolver() |
|
759 listResolver = ListResolver() |
|
760 dictViewResolver = DictViewResolver() |
|
761 setResolver = SetResolver() |
|
762 ndarrayResolver = NdArrayResolver() |
|
763 multiValueDictResolver = MultiValueDictResolver() |
|
764 arrayResolver = ArrayResolver() |
|
765 qtResolver = QtResolver() |
|
766 |
|
767 |
|
768 ############################################################ |
|
769 ## Methods to determine the type of a variable and the |
|
770 ## resolver class to use |
|
771 ############################################################ |
|
772 |
|
773 _TypeMap = _ArrayTypes = None |
|
774 _TryArray = _TryNumpy = _TryDjango = True |
|
775 _MapCount = 0 |
|
776 |
|
777 |
|
778 def _initTypeMap(): |
|
779 """ |
|
780 Protected function to initialize the type map. |
|
781 """ |
|
782 global _TypeMap |
|
783 |
|
784 # Type map for special handling of array types. |
|
785 # All other types not listed here use the default resolver. |
|
786 _TypeMap = [ |
|
787 (tuple, listResolver), |
|
788 (list, listResolver), |
|
789 (dict, dictResolver), |
|
790 (set, setResolver), |
|
791 (frozenset, setResolver), |
|
792 (ItemsView, dictViewResolver), # Since Python 3.0 |
|
793 (KeysView, dictViewResolver), |
|
794 (ValuesView, dictViewResolver), |
|
795 ] |
|
796 |
|
797 |
|
798 # Initialize the static type map |
|
799 _initTypeMap() |
|
800 |
|
801 |
|
802 def updateTypeMap(): |
|
803 """ |
|
804 Public function to update the type map based on module imports. |
|
805 """ |
|
806 global _TypeMap, _ArrayTypes, _TryArray, _TryNumpy, _TryDjango, _MapCount |
|
807 |
|
808 # array.array may not be imported (yet) |
|
809 if _TryArray and "array" in sys.modules: |
|
810 import array |
|
811 |
|
812 _TypeMap.append((array.array, arrayResolver)) |
|
813 _TryArray = False |
|
814 |
|
815 # numpy may not be imported (yet) |
|
816 if _TryNumpy and "numpy" in sys.modules: |
|
817 import numpy |
|
818 |
|
819 _TypeMap.append((numpy.ndarray, ndarrayResolver)) |
|
820 _TryNumpy = False |
|
821 |
|
822 # django may not be imported (yet) |
|
823 if _TryDjango and "django" in sys.modules: |
|
824 from django.utils.datastructures import MultiValueDict |
|
825 |
|
826 # it should go before dict |
|
827 _TypeMap.insert(0, (MultiValueDict, multiValueDictResolver)) |
|
828 _TryDjango = False |
|
829 |
|
830 # If _TypeMap changed, rebuild the _ArrayTypes tuple |
|
831 if _MapCount != len(_TypeMap): |
|
832 _ArrayTypes = tuple(typ for typ, _resolver in _TypeMap) |
|
833 _MapCount = len(_TypeMap) |
|
834 |
|
835 |
|
836 def getResolver(obj): |
|
837 """ |
|
838 Public method to get the resolver based on the type info of an object. |
|
839 |
|
840 @param obj object to get resolver for |
|
841 @type any |
|
842 @return resolver |
|
843 @rtype BaseResolver |
|
844 """ |
|
845 # Between PyQt and PySide the returned type is different (class vs. type) |
|
846 typeStr = str(type(obj)).split(" ", 1)[-1] |
|
847 typeStr = typeStr[1:-2] |
|
848 |
|
849 if typeStr.startswith(ConfigQtNames) and typeStr.endswith(ConfigKnownQtTypes): |
|
850 return qtResolver |
|
851 |
|
852 for typeData, resolver in _TypeMap: # __IGNORE_WARNING_M507__ |
|
853 if isinstance(obj, typeData): |
|
854 return resolver |
|
855 |
|
856 return defaultResolver |
|
857 |
|
858 |
|
859 # |
|
860 # eflag: noqa = Y113 |