# Buggy code
def wrapped(self, raw):
    """
    Wraps the raw IO object (`RawIOBase`) in buffers, text decoding,
    and newline handling.
    """
    # pylint:disable=too-many-branches
    result = raw
    buffering = self.buffering

    line_buffering = False
    if buffering == 1 or buffering < 0 and raw.isatty():
        buffering = -1
        line_buffering = True
    if buffering < 0:
        buffering = self.default_buffer_size
        try:
            bs = os.fstat(raw.fileno()).st_blksize
        except (OSError, AttributeError):
            pass
        else:
            if bs > 1:
                buffering = bs
    if buffering < 0:  # pragma: no cover
        raise ValueError("invalid buffering size")

    if buffering != 0:
        if self.updating:
            Buffer = io.BufferedRandom
        elif self.creating or self.writing or self.appending:
            Buffer = io.BufferedWriter
        elif self.reading:
            Buffer = io.BufferedReader
        else:  # prgama: no cover
            raise ValueError("unknown mode: %r" % self.mode)

        try:
            result = Buffer(raw, buffering)
        except AttributeError:
            # Python 2 file() objects don't have the readable/writable
            # attributes. But they handle their own buffering.
            result = raw

    if self.binary:
        return result
    if PY2 and self.native:
        # Neither text mode nor binary mode specified.
        if self.universal:
            # universal was requested, e.g., 'rU'
            result = UniversalNewlineBytesWrapper(result, line_buffering)
    else:
        result = io.TextIOWrapper(
            result, self.encoding, self.errors, self.newline, line_buffering
        )

    try:
        result.mode = self.mode
    except (AttributeError, TypeError):
        # AttributeError: No such attribute
        # TypeError: Readonly attribute (py2)
        pass
    return result


# Traceback (AttributeError)
$ python
Python 3.7.5 (default, Nov 20 2019, 09:21:52)
[GCC 9.2.1 20191008] on linux
Type "help", "copyright", "credits" or "license" for more information.
import sys
import gevent.fileobject
gevent.fileobject.FileObjectThread(sys.stdin).readline()
Traceback (most recent call last):
File "/home/davidlawson/virtualenvs/scrapers_37/lib/python3.7/site-packages/gevent/threadpool.py", line 120, in __run_task
thread_result.set(func(*args, **kwargs))
AttributeError: '_io.TextIOWrapper' object has no attribute 'readinto'
2020-03-10T13:35:10Z (<ThreadPoolWorker at 0x7ffba1fb1ec0 thread_ident=0x7ffba1f87700 hub=<Hub at 0x7ffba21997d0 thread_ident=0x7ffba2de9740>>, <built-in method readline of _io.TextIOWrapper object at 0x7ffba24ce910>) failed with AttributeError

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/davidlawson/virtualenvs/scrapers_37/lib/python3.7/site-packages/gevent/_fileobjectcommon.py", line 525, in thread_method
return threadpool.apply(method, args, kwargs)
File "/home/davidlawson/virtualenvs/scrapers_37/lib/python3.7/site-packages/gevent/pool.py", line 161, in apply
return self.spawn(func, *args, **kwds).get()
File "src/gevent/event.py", line 279, in gevent._event.AsyncResult.get
File "src/gevent/event.py", line 307, in gevent._event.AsyncResult.get
File "src/gevent/event.py", line 297, in gevent._event.AsyncResult.get
File "src/gevent/event.py", line 277, in gevent._event.AsyncResult._raise_exception
File "/home/davidlawson/virtualenvs/scrapers_37/lib/python3.7/site-packages/gevent/_compat.py", line 62, in reraise
raise value.with_traceback(tb)
File "/home/davidlawson/virtualenvs/scrapers_37/lib/python3.7/site-packages/gevent/threadpool.py", line 120, in __run_task
thread_result.set(func(*args, **kwargs))
AttributeError: '_io.TextIOWrapper' object has no attribute 'readinto'

# Fixed code
def wrapped(self, raw):
    """
    Wraps the raw IO object (`RawIOBase` or `io.TextIOBase`) in
    buffers, text decoding, and newline handling.
    """
    # pylint:disable=too-many-branches
    result = raw
    buffering = self.buffering

    line_buffering = False
    if buffering == 1 or buffering < 0 and raw.isatty():
        buffering = -1
        line_buffering = True
    if buffering < 0:
        buffering = self.default_buffer_size
        try:
            bs = os.fstat(raw.fileno()).st_blksize
        except (OSError, AttributeError):
            pass
        else:
            if bs > 1:
                buffering = bs
    if buffering < 0:  # pragma: no cover
        raise ValueError("invalid buffering size")

    if not isinstance(raw, io.BufferedIOBase) and (
        not hasattr(raw, "buffer") or raw.buffer is None
    ):
        # Need to wrap our own buffering around it. If it
        # is already buffered, don't do so.
        if buffering != 0:
            if self.updating:
                Buffer = io.BufferedRandom
            elif self.creating or self.writing or self.appending:
                Buffer = io.BufferedWriter
            elif self.reading:
                Buffer = io.BufferedReader
            else:  # prgama: no cover
                raise ValueError("unknown mode: %r" % self.mode)

            try:
                result = Buffer(raw, buffering)
            except AttributeError:
                # Python 2 file() objects don't have the readable/writable
                # attributes. But they handle their own buffering.
                result = raw

    if self.binary:
        if isinstance(raw, io.TextIOBase):
            # Can't do it. The TextIO object will have its own buffer, and
            # trying to read from the raw stream or the buffer without going through
            # the TextIO object is likely to lead to problems with the codec.
            raise ValueError("Unable to perform binary IO on top of text IO stream")
        return result

    # Either native or text at this point.
    if PY2 and self.native:
        # Neither text mode nor binary mode specified.
        if self.universal:
            # universal was requested, e.g., 'rU'
            result = UniversalNewlineBytesWrapper(result, line_buffering)
    else:
        # Python 2 and text mode, or Python 3 and either text or native (both are the same)
        if not isinstance(raw, io.TextIOBase):
            # Avoid double-wrapping a TextIOBase in another TextIOWrapper.
            # That tends not to work. See https://github.com/gevent/gevent/issues/1542
            result = io.TextIOWrapper(
                result, self.encoding, self.errors, self.newline, line_buffering
            )

    if result is not raw:
        # Set the mode, if possible, but only if we created a new
        # object.
        try:
            result.mode = self.mode
        except (AttributeError, TypeError):
            # AttributeError: No such attribute
            # TypeError: Readonly attribute (py2)
            pass

    return result