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

Code before:
        if inspect.isclass(function):
            raise ValueError("class fixtures not supported (maybe in the future)")

        if isinstance(function, FixtureFunctionDefinition):
            raise ValueError(
                f"@pytest.fixture is being applied more than once to the same function {function.__name__!r}"
            )

        if hasattr(function, "pytestmark"):
            warnings.warn(MARKED_FIXTURE, stacklevel=2)

        fixture_definition = FixtureFunctionDefinition(function, self)

        name = self.name or function.__name__
        if name == "request":
            location = getlocation(function)
            fail(
                f"'request' is a reserved word for fixtures, use another name:\n  {location}",
                pytrace=False,
            )

        return fixture_definition


# TODO: paramspec/return type annotation tracking and storing
class FixtureFunctionDefinition:
    def __init__(
        self,
        function: Callable[..., Any],
        fixture_function_marker: FixtureFunctionMarker,
        instance: type | None = None,
    ):
        self.name = fixture_function_marker.name or function.__name__
        self.__name__ = self.name
        self._fixture_function_marker = fixture_function_marker
        self._fixture_function = function
        self._instance = instance

    def __repr__(self) -> str:
        return f"<pytest_fixture({self._fixture_function})>"

    def __get__(self, instance, owner=None):
        return FixtureFunctionDefinition(
            self._fixture_function, self._fixture_function_marker, instance
        )

    def __call__(self, *args: Any, **kwds: Any) -> Any:
        message = (
            f'Fixture "{self.name}" called directly. Fixtures are not meant to be called directly,\n'
            "but are created automatically when test functions request them as parameters.\n"
            "See https://docs.pytest.org/en/stable/explanation/fixtures.html for more information about fixtures, and\n"

Review comment (suggestion):
While this type is not public, it's seems like something that plugin might start to use directly. For this, we have an "opt in" mechanism which makes it clear the ctor is internal and can change between pytest versions without warning. The mechanism is to add a `_ispytest: bool = False,` parameter, always call with `_ispytest=True` inside of pytest, and issue a warning when it's `False`. There are many examples in the code you can copy from.

Code after:
        if isinstance(function, FixtureFunctionDefinition):
            raise ValueError(
                f"@pytest.fixture is being applied more than once to the same function {function.__name__!r}"
            )

        if hasattr(function, "pytestmark"):
            warnings.warn(MARKED_FIXTURE, stacklevel=2)

        fixture_definition = FixtureFunctionDefinition(
            function=function, fixture_function_marker=self, _ispytest=True
        )

        name = self.name or function.__name__
        if name == "request":
            location = getlocation(function)
            fail(
                f"'request' is a reserved word for fixtures, use another name:\n  {location}",
                pytrace=False,
            )

        return fixture_definition


# TODO: paramspec/return type annotation tracking and storing
class FixtureFunctionDefinition:
    def __init__(
        self,
        *,
        function: Callable[..., Any],
        fixture_function_marker: FixtureFunctionMarker,
        instance: object | None = None,
        _ispytest: bool = False,
    ) -> None:
        check_ispytest(_ispytest)
        self.name = fixture_function_marker.name or function.__name__
        # In order to show the function that this fixture contains in messages.
        # Set the __name__ to be same as the function __name__ or the given fixture name.
        self.__name__ = self.name
        self._fixture_function_marker = fixture_function_marker
        if instance is not None:
            self._fixture_function = cast(
                Callable[..., Any], function.__get__(instance)
            )
        else:
            self._fixture_function = function
        functools.update_wrapper(self, function)

    def __repr__(self) -> str:
        return f"<pytest_fixture({self._fixture_function})>"

    def __get__(self, instance, owner=None):