Return list of attribute-descriptor tuples. For each name in dir(cls), the return list contains a 4-tuple with these elements: 0. The name (a string). 1. The kind of attribute this is, one of these strings: 'class method' created via classmethod()
(cls)
| 539 | Attribute = namedtuple('Attribute', 'name kind defining_class object') |
| 540 | |
| 541 | def classify_class_attrs(cls): |
| 542 | """Return list of attribute-descriptor tuples. |
| 543 | |
| 544 | For each name in dir(cls), the return list contains a 4-tuple |
| 545 | with these elements: |
| 546 | |
| 547 | 0. The name (a string). |
| 548 | |
| 549 | 1. The kind of attribute this is, one of these strings: |
| 550 | 'class method' created via classmethod() |
| 551 | 'static method' created via staticmethod() |
| 552 | 'property' created via property() |
| 553 | 'method' any other flavor of method or descriptor |
| 554 | 'data' not a method |
| 555 | |
| 556 | 2. The class which defined this attribute (a class). |
| 557 | |
| 558 | 3. The object as obtained by calling getattr; if this fails, or if the |
| 559 | resulting object does not live anywhere in the class' mro (including |
| 560 | metaclasses) then the object is looked up in the defining class's |
| 561 | dict (found by walking the mro). |
| 562 | |
| 563 | If one of the items in dir(cls) is stored in the metaclass it will now |
| 564 | be discovered and not have None be listed as the class in which it was |
| 565 | defined. Any items whose home class cannot be discovered are skipped. |
| 566 | """ |
| 567 | |
| 568 | mro = getmro(cls) |
| 569 | metamro = getmro(type(cls)) # for attributes stored in the metaclass |
| 570 | metamro = tuple(cls for cls in metamro if cls not in (type, object)) |
| 571 | class_bases = (cls,) + mro |
| 572 | all_bases = class_bases + metamro |
| 573 | names = dir(cls) |
| 574 | # :dd any DynamicClassAttributes to the list of names; |
| 575 | # this may result in duplicate entries if, for example, a virtual |
| 576 | # attribute with the same name as a DynamicClassAttribute exists. |
| 577 | for base in mro: |
| 578 | for k, v in base.__dict__.items(): |
| 579 | if isinstance(v, types.DynamicClassAttribute) and v.fget is not None: |
| 580 | names.append(k) |
| 581 | result = [] |
| 582 | processed = set() |
| 583 | |
| 584 | for name in names: |
| 585 | # Get the object associated with the name, and where it was defined. |
| 586 | # Normal objects will be looked up with both getattr and directly in |
| 587 | # its class' dict (in case getattr fails [bug #1785], and also to look |
| 588 | # for a docstring). |
| 589 | # For DynamicClassAttributes on the second pass we only look in the |
| 590 | # class's dict. |
| 591 | # |
| 592 | # Getting an obj from the __dict__ sometimes reveals more than |
| 593 | # using getattr. Static and class methods are dramatic examples. |
| 594 | homecls = None |
| 595 | get_obj = None |
| 596 | dict_obj = None |
| 597 | if name not in processed: |
| 598 | try: |
nothing calls this directly
no test coverage detected
searching dependent graphs…