# Buggy code
def apply(self, func, axis=0, raw=False, result_type=None, args=(), **kwds):
    axis = self._get_axis_number(axis)
    query_compiler = super(DataFrame, self).apply(
        func, axis=axis, raw=raw, result_type=result_type, args=args, **kwds
    )
    if not isinstance(query_compiler, type(self._query_compiler)):
        return query_compiler
    # This is the simplest way to determine the return type, but there are checks
    # in pandas that verify that some results are created. This is a challenge for
    # empty DataFrames, but fortunately they only happen when the `func` type is
    # a list or a dictionary, which means that the return type won't change from
    # type(self), so we catch that error and use `self.__name__` for the return
    # type.
    try:
        if axis == 0:
            init_kwargs = {"index": self.index}
        else:
            init_kwargs = {"columns": self.columns}
        return_type = type(
            getattr(pandas, self.__name__)(**init_kwargs).apply(
                func, axis=axis, raw=raw, result_type=result_type, args=args, **kwds
            )
        ).__name__
    except Exception:
        return_type = self.__name__
    if return_type not in ["DataFrame", "Series"]:
        return query_compiler.to_pandas().squeeze()
    else:
        result = getattr(sys.modules[self.__module__], return_type)(
            query_compiler=query_compiler
        )
        if isinstance(result, Series):
            if axis == 0 and result.name == self.index[0] or result.name == 0:
                result.name = None
            elif axis == 1 and result.name == self.columns[0] or result.name == 0:
                result.name = None
        return result


# Traceback (RecursionError)
Traceback (most recent call last):
File "1.py", line 14, in <module>
ref = df["a"].add(df["b"])
File "/localdisk/ilyaenko/modin/modin/pandas/series.py", line 376, in add
return super(Series, new_self).add(
File "/localdisk/ilyaenko/modin/modin/pandas/series.py", line 376, in add
return super(Series, new_self).add(
File "/localdisk/ilyaenko/modin/modin/pandas/series.py", line 376, in add
return super(Series, new_self).add(
[Previous line repeated 978 more times]
...
RecursionError: maximum recursion depth exceeded while calling a Python object

# Fixed code
def apply(self, func, axis=0, raw=False, result_type=None, args=(), **kwds):
    axis = self._get_axis_number(axis)
    query_compiler = super(DataFrame, self).apply(
        func, axis=axis, raw=raw, result_type=result_type, args=args, **kwds
    )
    if not isinstance(query_compiler, type(self._query_compiler)):
        return query_compiler
    # This is the simplest way to determine the return type, but there are checks
    # in pandas that verify that some results are created. This is a challenge for
    # empty DataFrames, but fortunately they only happen when the `func` type is
    # a list or a dictionary, which means that the return type won't change from
    # type(self), so we catch that error and use `type(self).__name__` for the return
    # type.
    try:
        if axis == 0:
            init_kwargs = {"index": self.index}
        else:
            init_kwargs = {"columns": self.columns}
        return_type = type(
            getattr(pandas, type(self).__name__)(**init_kwargs).apply(
                func, axis=axis, raw=raw, result_type=result_type, args=args, **kwds
            )
        ).__name__
    except Exception:
        return_type = type(self).__name__
    if return_type not in ["DataFrame", "Series"]:
        return query_compiler.to_pandas().squeeze()
    else:
        result = getattr(sys.modules[self.__module__], return_type)(
            query_compiler=query_compiler
        )
        if isinstance(result, Series):
            if axis == 0 and result.name == self.index[0] or result.name == 0:
                result.name = None
            elif axis == 1 and result.name == self.columns[0] or result.name == 0:
                result.name = None
        return result