Repository: pytest-dev/pytest
File: src/_pytest/fixtures.py (Python)

Code before:
        # An overriding fixture can request its own name (possibly indirectly);
        # in this case it gets the value of the fixture it overrides, one level
        # up.
        # Check how many `argname`s deep we are, and take the next one.
        # `fixturedefs` is sorted from furthest to closest, so use negative
        # indexing to go in reverse.
        index = -1
        for request in self._iter_chain():
            if request.fixturename == argname:
                index -= 1
        # If already consumed all of the available levels, fail.
        if -index > len(fixturedefs):
            raise FixtureLookupError(argname, self)
        fixturedef = fixturedefs[index]

        # Check for attempted use of an async fixture by a sync test
        # `self.scope` here is not the scope of the requested fixture, but the scope of
        # the requester.
        if (
            self.scope == "function"
            and not inspect.iscoroutinefunction(self._pyfuncitem.obj)
            and (
                inspect.iscoroutinefunction(fixturedef.func)
                or inspect.isasyncgenfunction(fixturedef.func)
            )
        ):
            if fixturedef._autouse:
                warnings.warn(
                    PytestRemovedIn9Warning(
                        "Sync test requested an async fixture with autouse=True. "
                        "If you intended to use the fixture you may want to make the "
                        "test asynchronous. If you did not intend to use it you should "
                        "restructure your test setup. "
                        "This will turn into an error in pytest 9."
                    ),
                    stacklevel=3,
                )
            else:
                raise FixtureLookupError(
                    argname,
                    self,
                    (
                        "ERROR: Sync test requested async fixture. "
                        "You may want to make the test asynchronous and run it with "
                        "a suitable async framework test plugin."
                    ),
                )

        # Prepare a SubRequest object for calling the fixture.
        try:
            callspec = self._pyfuncitem.callspec

Review comment (suggestion):
I'm not *100%* sure this is the place to do the check, and am also not 100% it can't be triggered by a sync fixture requesting an async fixture. But for the latter I think it's covered by the `self.scope == "function"` check, where if `self` is a fixture requesting another fixture it's because it's higher-scoped.
So while this appears to function robustly, it might be making somewhat sketchy assumptions.

Code after:
        # An overriding fixture can request its own name (possibly indirectly);
        # in this case it gets the value of the fixture it overrides, one level
        # up.
        # Check how many `argname`s deep we are, and take the next one.
        # `fixturedefs` is sorted from furthest to closest, so use negative
        # indexing to go in reverse.
        index = -1
        for request in self._iter_chain():
            if request.fixturename == argname:
                index -= 1
        # If already consumed all of the available levels, fail.
        if -index > len(fixturedefs):
            raise FixtureLookupError(argname, self)
        fixturedef = fixturedefs[index]

        # Prepare a SubRequest object for calling the fixture.
        try:
            callspec = self._pyfuncitem.callspec
        except AttributeError:
            callspec = None
        if callspec is not None and argname in callspec.params:
            param = callspec.params[argname]
            param_index = callspec.indices[argname]
            # The parametrize invocation scope overrides the fixture's scope.
            scope = callspec._arg2scope[argname]
        else:
            param = NOTSET
            param_index = 0
            scope = fixturedef._scope
            self._check_fixturedef_without_param(fixturedef)
        self._check_scope(fixturedef, scope)
        subrequest = SubRequest(
            self, scope, param, param_index, fixturedef, _ispytest=True
        )

        # Make sure the fixture value is cached, running it if it isn't
        fixturedef.execute(request=subrequest)

        self._fixture_defs[argname] = fixturedef
        return fixturedef

    def _check_fixturedef_without_param(self, fixturedef: FixtureDef[object]) -> None:
        """Check that this request is allowed to execute this fixturedef without
        a param."""
        funcitem = self._pyfuncitem
        has_params = fixturedef.params is not None
        fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
        if has_params and fixtures_not_supported:
            msg = (
                f"{funcitem.name} does not support fixtures, maybe unittest.TestCase subclass?\n"
                f"Node id: {funcitem.nodeid}\n"