Return the first node by MRO order that defines an attribute. Arguments: cls (Any): Child class to traverse. attr (str): Name of attribute to find. stop (Set[Any]): A set of types that if reached will stop the search. monkey_patched (Sequence): Use on
(cls, attr, stop=None, monkey_patched=None)
| 12 | |
| 13 | |
| 14 | def mro_lookup(cls, attr, stop=None, monkey_patched=None): |
| 15 | """Return the first node by MRO order that defines an attribute. |
| 16 | |
| 17 | Arguments: |
| 18 | cls (Any): Child class to traverse. |
| 19 | attr (str): Name of attribute to find. |
| 20 | stop (Set[Any]): A set of types that if reached will stop |
| 21 | the search. |
| 22 | monkey_patched (Sequence): Use one of the stop classes |
| 23 | if the attributes module origin isn't in this list. |
| 24 | Used to detect monkey patched attributes. |
| 25 | |
| 26 | Returns: |
| 27 | Any: The attribute value, or :const:`None` if not found. |
| 28 | """ |
| 29 | stop = set() if not stop else stop |
| 30 | monkey_patched = [] if not monkey_patched else monkey_patched |
| 31 | for node in cls.mro(): |
| 32 | if node in stop: |
| 33 | try: |
| 34 | value = node.__dict__[attr] |
| 35 | module_origin = value.__module__ |
| 36 | except (AttributeError, KeyError): |
| 37 | pass |
| 38 | else: |
| 39 | if module_origin not in monkey_patched: |
| 40 | return node |
| 41 | return |
| 42 | if attr in node.__dict__: |
| 43 | return node |
| 44 | |
| 45 | |
| 46 | class FallbackContext: |