<p dir="auto">When using iter_lines with chunk_size other than None, it can generate an extra blank line if the end of a chunk lands on a delimiter.</p>
<h2 dir="auto">Reproduction Steps</h2>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import StringIO
import requests

def getTestFile():
    f = StringIO.StringIO()
    f.write('a-b')
    f.seek(0)
    return f

r = requests.Response()
r.raw = getTestFile()
print [l for l in r.iter_lines(delimiter='-')]

r = requests.Response()
r.raw = getTestFile()
print [l for l in r.iter_lines(delimiter='-', chunk_size=2)]"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-v">StringIO</span>
<span class="pl-k">import</span> <span class="pl-s1">requests</span>

<span class="pl-k">def</span> <span class="pl-en">getTestFile</span>():
    <span class="pl-s1">f</span> <span class="pl-c1">=</span> <span class="pl-v">StringIO</span>.<span class="pl-v">StringIO</span>()
    <span class="pl-s1">f</span>.<span class="pl-en">write</span>(<span class="pl-s">'a-b'</span>)
    <span class="pl-s1">f</span>.<span class="pl-en">seek</span>(<span class="pl-c1">0</span>)
    <span class="pl-k">return</span> <span class="pl-s1">f</span>

<span class="pl-s1">r</span> <span class="pl-c1">=</span> <span class="pl-s1">requests</span>.<span class="pl-v">Response</span>()
<span class="pl-s1">r</span>.<span class="pl-s1">raw</span> <span class="pl-c1">=</span> <span class="pl-en">getTestFile</span>()
<span class="pl-s1">print</span> [<span class="pl-s1">l</span> <span class="pl-s1">for</span> <span class="pl-s1">l</span> <span class="pl-c1">in</span> <span class="pl-s1">r</span>.<span class="pl-en">iter_lines</span>(<span class="pl-s1">delimiter</span><span class="pl-c1">=</span><span class="pl-s">'-'</span>)]

<span class="pl-s1">r</span> <span class="pl-c1">=</span> <span class="pl-s1">requests</span>.<span class="pl-v">Response</span>()
<span class="pl-s1">r</span>.<span class="pl-s1">raw</span> <span class="pl-c1">=</span> <span class="pl-en">getTestFile</span>()
<span class="pl-s1">print</span> [<span class="pl-s1">l</span> <span class="pl-s1">for</span> <span class="pl-s1">l</span> <span class="pl-c1">in</span> <span class="pl-s1">r</span>.<span class="pl-en">iter_lines</span>(<span class="pl-s1">delimiter</span><span class="pl-c1">=</span><span class="pl-s">'-'</span>, <span class="pl-s1">chunk_size</span><span class="pl-c1">=</span><span class="pl-c1">2</span>)]</pre></div>
<h2 dir="auto">Expected Result</h2>
<p dir="auto">['a', 'b']<br>
['a', 'b']</p>
<h2 dir="auto">Actual Result</h2>
<p dir="auto">['a', 'b']<br>
['a', '', 'b']</p>
<h2 dir="auto">Proposed Fix</h2>
<p dir="auto">I modified iter_lines as follows, and the above test passes:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="    def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter=None):
        &quot;&quot;&quot;Iterates over the response data, one line at a time.  When
        stream=True is set on the request, this avoids reading the
        content at once into memory for large responses.

        .. note:: This method is not reentrant safe.
        &quot;&quot;&quot;

        pending = None

        for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode):

            if pending is not None:
                chunk = pending + chunk

            if delimiter:
                lines = chunk.split(delimiter)
            else:
                lines = chunk.splitlines()

            if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:
                pending = lines.pop()
            elif lines and lines[-1] == '':
                pending = lines.pop()
            else:
                pending = None

            for line in lines:
                yield line

        if pending is not None:
            yield pending"><pre class="notranslate">    <span class="pl-k">def</span> <span class="pl-en">iter_lines</span>(<span class="pl-s1">self</span>, <span class="pl-s1">chunk_size</span><span class="pl-c1">=</span><span class="pl-v">ITER_CHUNK_SIZE</span>, <span class="pl-s1">decode_unicode</span><span class="pl-c1">=</span><span class="pl-c1">None</span>, <span class="pl-s1">delimiter</span><span class="pl-c1">=</span><span class="pl-c1">None</span>):
        <span class="pl-s">"""Iterates over the response data, one line at a time.  When</span>
<span class="pl-s">        stream=True is set on the request, this avoids reading the</span>
<span class="pl-s">        content at once into memory for large responses.</span>
<span class="pl-s"></span>
<span class="pl-s">        .. note:: This method is not reentrant safe.</span>
<span class="pl-s">        """</span>

        <span class="pl-s1">pending</span> <span class="pl-c1">=</span> <span class="pl-c1">None</span>

        <span class="pl-k">for</span> <span class="pl-s1">chunk</span> <span class="pl-c1">in</span> <span class="pl-s1">self</span>.<span class="pl-en">iter_content</span>(<span class="pl-s1">chunk_size</span><span class="pl-c1">=</span><span class="pl-s1">chunk_size</span>, <span class="pl-s1">decode_unicode</span><span class="pl-c1">=</span><span class="pl-s1">decode_unicode</span>):

            <span class="pl-k">if</span> <span class="pl-s1">pending</span> <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-c1">None</span>:
                <span class="pl-s1">chunk</span> <span class="pl-c1">=</span> <span class="pl-s1">pending</span> <span class="pl-c1">+</span> <span class="pl-s1">chunk</span>

            <span class="pl-k">if</span> <span class="pl-s1">delimiter</span>:
                <span class="pl-s1">lines</span> <span class="pl-c1">=</span> <span class="pl-s1">chunk</span>.<span class="pl-en">split</span>(<span class="pl-s1">delimiter</span>)
            <span class="pl-k">else</span>:
                <span class="pl-s1">lines</span> <span class="pl-c1">=</span> <span class="pl-s1">chunk</span>.<span class="pl-en">splitlines</span>()

            <span class="pl-k">if</span> <span class="pl-s1">lines</span> <span class="pl-c1">and</span> <span class="pl-s1">lines</span>[<span class="pl-c1">-</span><span class="pl-c1">1</span>] <span class="pl-c1">and</span> <span class="pl-s1">chunk</span> <span class="pl-c1">and</span> <span class="pl-s1">lines</span>[<span class="pl-c1">-</span><span class="pl-c1">1</span>][<span class="pl-c1">-</span><span class="pl-c1">1</span>] <span class="pl-c1">==</span> <span class="pl-s1">chunk</span>[<span class="pl-c1">-</span><span class="pl-c1">1</span>]:
                <span class="pl-s1">pending</span> <span class="pl-c1">=</span> <span class="pl-s1">lines</span>.<span class="pl-en">pop</span>()
            <span class="pl-k">elif</span> <span class="pl-s1">lines</span> <span class="pl-c1">and</span> <span class="pl-s1">lines</span>[<span class="pl-c1">-</span><span class="pl-c1">1</span>] <span class="pl-c1">==</span> <span class="pl-s">''</span>:
                <span class="pl-s1">pending</span> <span class="pl-c1">=</span> <span class="pl-s1">lines</span>.<span class="pl-en">pop</span>()
            <span class="pl-k">else</span>:
                <span class="pl-s1">pending</span> <span class="pl-c1">=</span> <span class="pl-c1">None</span>

            <span class="pl-k">for</span> <span class="pl-s1">line</span> <span class="pl-c1">in</span> <span class="pl-s1">lines</span>:
                <span class="pl-k">yield</span> <span class="pl-s1">line</span>

        <span class="pl-k">if</span> <span class="pl-s1">pending</span> <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-c1">None</span>:
            <span class="pl-k">yield</span> <span class="pl-s1">pending</span></pre></div>
<h2 dir="auto">System Information</h2>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ python -m requests.help"><pre class="notranslate"><code class="notranslate">$ python -m requests.help
</code></pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{
  &quot;chardet&quot;: {
    &quot;version&quot;: &quot;3.0.3&quot;
  }, 
  &quot;cryptography&quot;: {
    &quot;version&quot;: &quot;&quot;
  }, 
  &quot;implementation&quot;: {
    &quot;name&quot;: &quot;CPython&quot;, 
    &quot;version&quot;: &quot;2.7.13&quot;
  }, 
  &quot;platform&quot;: {
    &quot;release&quot;: &quot;16.6.0&quot;, 
    &quot;system&quot;: &quot;Darwin&quot;
  }, 
  &quot;pyOpenSSL&quot;: {
    &quot;openssl_version&quot;: &quot;&quot;, 
    &quot;version&quot;: null
  }, 
  &quot;requests&quot;: {
    &quot;version&quot;: &quot;2.17.3&quot;
  }, 
  &quot;system_ssl&quot;: {
    &quot;version&quot;: &quot;100020bf&quot;
  }, 
  &quot;urllib3&quot;: {
    &quot;version&quot;: &quot;1.21.1&quot;
  }, 
  &quot;using_pyopenssl&quot;: false
}"><pre class="notranslate"><code class="notranslate">{
  "chardet": {
    "version": "3.0.3"
  }, 
  "cryptography": {
    "version": ""
  }, 
  "implementation": {
    "name": "CPython", 
    "version": "2.7.13"
  }, 
  "platform": {
    "release": "16.6.0", 
    "system": "Darwin"
  }, 
  "pyOpenSSL": {
    "openssl_version": "", 
    "version": null
  }, 
  "requests": {
    "version": "2.17.3"
  }, 
  "system_ssl": {
    "version": "100020bf"
  }, 
  "urllib3": {
    "version": "1.21.1"
  }, 
  "using_pyopenssl": false
}
</code></pre></div>
<p dir="auto">This command is only available on Requests v2.16.4 and greater. Otherwise,<br>
please provide some basic information about your system (Python version,<br>
operating system, &amp;c).</p>
<p dir="auto">Here is a small test program to demonstrate the bug:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import requests

url = &quot;http://lohas.pixnet.net/blog&quot;
r = requests.get(url)
iter_lines = [line for line in r.iter_lines(chunk_size=7, decode_unicode=False)]
split_lines = r.content.splitlines()
for index, (iline, sline) in enumerate(zip(iter_lines, split_lines)):
	if iline != sline:
		print(&quot;line {} is broken&quot;.format(index))
		print(iline, len(iline))
		print(sline, len(sline))
		break"><pre class="notranslate"><code class="notranslate">import requests

url = "http://lohas.pixnet.net/blog"
r = requests.get(url)
iter_lines = [line for line in r.iter_lines(chunk_size=7, decode_unicode=False)]
split_lines = r.content.splitlines()
for index, (iline, sline) in enumerate(zip(iter_lines, split_lines)):
	if iline != sline:
		print("line {} is broken".format(index))
		print(iline, len(iline))
		print(sline, len(sline))
		break
</code></pre></div>
<p dir="auto">Expected behavior:<br>
r.iter_lines() should give the same result as r.content.splitlines()</p>
<p dir="auto">Actual behavior:<br>
The test program generates the following output:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="line 275 is broken
b'' 0
b'\t\t\t&lt;tbody&gt;' 10"><pre class="notranslate"><code class="notranslate">line 275 is broken
b'' 0
b'\t\t\t&lt;tbody&gt;' 10
</code></pre></div>
<p dir="auto">Changing chunk_size can break different lines.</p>