Inject a hidden autouse, class scoped fixture into the collected class object that invokes setup_class/teardown_class if either or both are available. Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with other fixtures (#517).
(self)
| 822 | return super().collect() |
| 823 | |
| 824 | def _inject_setup_class_fixture(self) -> None: |
| 825 | """Inject a hidden autouse, class scoped fixture into the collected class object |
| 826 | that invokes setup_class/teardown_class if either or both are available. |
| 827 | |
| 828 | Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with |
| 829 | other fixtures (#517). |
| 830 | """ |
| 831 | setup_class = _get_first_non_fixture_func(self.obj, ("setup_class",)) |
| 832 | teardown_class = getattr(self.obj, "teardown_class", None) |
| 833 | if setup_class is None and teardown_class is None: |
| 834 | return |
| 835 | |
| 836 | @fixtures.fixture( |
| 837 | autouse=True, |
| 838 | scope="class", |
| 839 | # Use a unique name to speed up lookup. |
| 840 | name=f"_xunit_setup_class_fixture_{self.obj.__qualname__}", |
| 841 | ) |
| 842 | def xunit_setup_class_fixture(cls) -> Generator[None, None, None]: |
| 843 | if setup_class is not None: |
| 844 | func = getimfunc(setup_class) |
| 845 | _call_with_optional_argument(func, self.obj) |
| 846 | yield |
| 847 | if teardown_class is not None: |
| 848 | func = getimfunc(teardown_class) |
| 849 | _call_with_optional_argument(func, self.obj) |
| 850 | |
| 851 | self.obj.__pytest_setup_class = xunit_setup_class_fixture |
| 852 | |
| 853 | def _inject_setup_method_fixture(self) -> None: |
| 854 | """Inject a hidden autouse, function scoped fixture into the collected class object |