| 410 | return False |
| 411 | |
| 412 | def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: |
| 413 | if not getattr(self.obj, "__test__", True): |
| 414 | return [] |
| 415 | |
| 416 | # Avoid random getattrs and peek in the __dict__ instead. |
| 417 | dicts = [getattr(self.obj, "__dict__", {})] |
| 418 | if isinstance(self.obj, type): |
| 419 | for basecls in self.obj.__mro__: |
| 420 | dicts.append(basecls.__dict__) |
| 421 | |
| 422 | # In each class, nodes should be definition ordered. Since Python 3.6, |
| 423 | # __dict__ is definition ordered. |
| 424 | seen: Set[str] = set() |
| 425 | dict_values: List[List[Union[nodes.Item, nodes.Collector]]] = [] |
| 426 | ihook = self.ihook |
| 427 | for dic in dicts: |
| 428 | values: List[Union[nodes.Item, nodes.Collector]] = [] |
| 429 | # Note: seems like the dict can change during iteration - |
| 430 | # be careful not to remove the list() without consideration. |
| 431 | for name, obj in list(dic.items()): |
| 432 | if name in IGNORED_ATTRIBUTES: |
| 433 | continue |
| 434 | if name in seen: |
| 435 | continue |
| 436 | seen.add(name) |
| 437 | res = ihook.pytest_pycollect_makeitem( |
| 438 | collector=self, name=name, obj=obj |
| 439 | ) |
| 440 | if res is None: |
| 441 | continue |
| 442 | elif isinstance(res, list): |
| 443 | values.extend(res) |
| 444 | else: |
| 445 | values.append(res) |
| 446 | dict_values.append(values) |
| 447 | |
| 448 | # Between classes in the class hierarchy, reverse-MRO order -- nodes |
| 449 | # inherited from base classes should come before subclasses. |
| 450 | result = [] |
| 451 | for values in reversed(dict_values): |
| 452 | result.extend(values) |
| 453 | return result |
| 454 | |
| 455 | def _genfunctions(self, name: str, funcobj) -> Iterator["Function"]: |
| 456 | modulecol = self.getparent(Module) |