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