def readline(self, size=None):
<EOL>if self._closed:<EOL><INDENT>raise IOError("<STR_LIT>")<EOL><DEDENT>if not (self._flags & self.FLAG_READ):<EOL><INDENT>raise IOError("<STR_LIT>")<EOL><DEDENT>line = self._rbuffer<EOL>truncated = False<EOL>while True:<EOL><INDENT>if (<EOL>self._at_trailing_cr<EOL>and self._flags & self.FLAG_UNIVERSAL_NEWLINE<EOL>and len(line) > <NUM_LIT:0><EOL>):<EOL><INDENT>if line[<NUM_LIT:0>] == linefeed_byte_value:<EOL><INDENT>line = line[<NUM_LIT:1>:]<EOL>self._record_newline(crlf)<EOL><DEDENT>else:<EOL><INDENT>self._record_newline(cr_byte)<EOL><DEDENT>self._at_trailing_cr = False<EOL><DEDENT>if (size is not None) and (size >= <NUM_LIT:0>):<EOL><INDENT>if len(line) >= size:<EOL><INDENT>self._rbuffer = line[size:]<EOL>line = line[:size]<EOL>truncated = True<EOL>break<EOL><DEDENT>n = size - len(line)<EOL><DEDENT>else:<EOL><INDENT>n = self._bufsize<EOL><DEDENT>if linefeed_byte in line or (<EOL>self._flags & self.FLAG_UNIVERSAL_NEWLINE and cr_byte in line<EOL>):<EOL><INDENT>break<EOL><DEDENT>try:<EOL><INDENT>new_data = self._read(n)<EOL><DEDENT>except EOFError:<EOL><INDENT>new_data = None<EOL><DEDENT>if (new_data is None) or (len(new_data) == <NUM_LIT:0>):<EOL><INDENT>self._rbuffer = bytes()<EOL>self._pos += len(line)<EOL>return line if self._flags & self.FLAG_BINARY else u(line)<EOL><DEDENT>line += new_data<EOL>self._realpos += len(new_data)<EOL><DEDENT>pos = line.find(linefeed_byte)<EOL>if self._flags & self.FLAG_UNIVERSAL_NEWLINE:<EOL><INDENT>rpos = line.find(cr_byte)<EOL>if (rpos >= <NUM_LIT:0>) and (rpos < pos or pos < <NUM_LIT:0>):<EOL><INDENT>pos = rpos<EOL><DEDENT><DEDENT>if pos == -<NUM_LIT:1>:<EOL><INDENT>self._pos += len(line)<EOL>return line if self._flags & self.FLAG_BINARY else u(line)<EOL><DEDENT>xpos = pos + <NUM_LIT:1><EOL>if (<EOL>line[pos] == cr_byte_value<EOL>and xpos < len(line)<EOL>and line[xpos] == linefeed_byte_value<EOL>):<EOL><INDENT>xpos += <NUM_LIT:1><EOL><DEDENT>if truncated:<EOL><INDENT>self._rbuffer = line[xpos:] + self._rbuffer<EOL><DEDENT>else:<EOL><INDENT>self._rbuffer = line[xpos:]<EOL><DEDENT>lf = line[pos:xpos]<EOL>line = line[:pos] + linefeed_byte<EOL>if (len(self._rbuffer) == <NUM_LIT:0>) and (lf == cr_byte):<EOL><INDENT>self._at_trailing_cr = True<EOL><DEDENT>else:<EOL><INDENT>self._record_newline(lf)<EOL><DEDENT>self._pos += len(line)<EOL>return line if self._flags & self.FLAG_BINARY else u(line)<EOL>
Read one entire line from the file.  A trailing newline character is
kept in the string (but may be absent when a file ends with an
incomplete line).  If the size argument is present and non-negative, it
is a maximum byte count (including the trailing newline) and an
incomplete line may be returned.  An empty string is returned only when
EOF is encountered immediately.

.. note::
    Unlike stdio's ``fgets``, the returned string contains null
    characters (``'\\0'``) if they occurred in the input.

:param int size: maximum length of returned string.
:returns:
    next line of the file, or an empty string if the end of the
    file has been reached.

    If the file was opened in binary (``'b'``) mode: bytes are returned
    Else: the encoding of the file is assumed to be UTF-8 and character
    strings (`str`) are returned