Obtain the unpacked marks that are stored on an object. If obj is a class and consider_mro is true, return marks applied to this class and all of its super-classes in MRO order. If consider_mro is false, only return marks applied directly to this class.
(
obj: object | type,
*,
consider_mro: bool = True,
)
| 418 | |
| 419 | |
| 420 | def get_unpacked_marks( |
| 421 | obj: object | type, |
| 422 | *, |
| 423 | consider_mro: bool = True, |
| 424 | ) -> list[Mark]: |
| 425 | """Obtain the unpacked marks that are stored on an object. |
| 426 | |
| 427 | If obj is a class and consider_mro is true, return marks applied to |
| 428 | this class and all of its super-classes in MRO order. If consider_mro |
| 429 | is false, only return marks applied directly to this class. |
| 430 | """ |
| 431 | if isinstance(obj, type): |
| 432 | if not consider_mro: |
| 433 | mark_lists = [obj.__dict__.get("pytestmark", [])] |
| 434 | else: |
| 435 | mark_lists = [ |
| 436 | x.__dict__.get("pytestmark", []) for x in reversed(obj.__mro__) |
| 437 | ] |
| 438 | mark_list = [] |
| 439 | for item in mark_lists: |
| 440 | if isinstance(item, list): |
| 441 | mark_list.extend(item) |
| 442 | else: |
| 443 | mark_list.append(item) |
| 444 | else: |
| 445 | mark_attribute = getattr(obj, "pytestmark", []) |
| 446 | if mark_attribute is None: |
| 447 | warnings.warn( |
| 448 | "Module defines a `__getattr__` which returns None for " |
| 449 | "'pytestmark' instead of raising AttributeError. " |
| 450 | "Make sure `__getattr__` raises AttributeError for " |
| 451 | "attributes it does not provide. " |
| 452 | "See https://github.com/pytest-dev/pytest/issues/8265", |
| 453 | PytestCollectionWarning, |
| 454 | stacklevel=2, |
| 455 | ) |
| 456 | mark_list = [] |
| 457 | elif isinstance(mark_attribute, list): |
| 458 | mark_list = mark_attribute |
| 459 | else: |
| 460 | mark_list = [mark_attribute] |
| 461 | return list(normalize_mark_list(mark_list)) |
| 462 | |
| 463 | |
| 464 | def normalize_mark_list( |