Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7a6dc13

Browse files
committed
Fix for SF bug #1175396: readline() will now read one more character, if
the last character read is "\r" (and size is None, i.e. we're allowed to call read() multiple times), so that we can return the correct line ending (this additional character might be a "\n"). If the stream is temporarily exhausted, we might return the wrong line ending (if the last character read is "\r" and the next one (after the byte stream provides more data) is "\n", but at least the atcr member ensure that we get the correct number of lines (i.e. this "\n" will not be treated as another line ending.)
1 parent cf18a5d commit 7a6dc13

2 files changed

Lines changed: 91 additions & 9 deletions

File tree

Lib/codecs.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,15 @@ def readline(self, size=None, keepends=True):
310310
data = data[1:]
311311
if data:
312312
self.atcr = data.endswith(u"\r")
313+
# If we're at a "\r" (and are allowed to read more), read one
314+
# extra character (which might be a "\n") to get a proper
315+
# line ending (If the stream is temporarily exhausted we return
316+
# the wrong line ending, but at least we won't generate a bogus
317+
# second line.
318+
if self.atcr and size is None:
319+
data += self.read(size=1, chars=1)
320+
self.atcr = data.endswith(u"\r")
321+
313322
line += data
314323
lines = line.splitlines(True)
315324
if lines:

Lib/test/test_codecs.py

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,88 @@ def readalllines(input, keepends=True):
7373
# reader has to look ahead whether this is a lone \r or a \r\n
7474
for size in xrange(80):
7575
for lineend in u"\n \r\n \r \u2028".split():
76-
s = size*u"a" + lineend + u"xxx\n"
77-
self.assertEqual(
78-
getreader(s).readline(keepends=True),
79-
size*u"a" + lineend,
80-
)
81-
self.assertEqual(
82-
getreader(s).readline(keepends=False),
83-
size*u"a",
84-
)
76+
s = 10*(size*u"a" + lineend + u"xxx\n")
77+
reader = getreader(s)
78+
for i in xrange(10):
79+
self.assertEqual(
80+
reader.readline(keepends=True),
81+
size*u"a" + lineend,
82+
)
83+
reader = getreader(s)
84+
for i in xrange(10):
85+
self.assertEqual(
86+
reader.readline(keepends=False),
87+
size*u"a",
88+
)
89+
90+
def test_bug1175396(self):
91+
s = [
92+
'<%!--===================================================\r\n',
93+
' BLOG index page: show recent articles,\r\n',
94+
' today\'s articles, or articles of a specific date.\r\n',
95+
'========================================================--%>\r\n',
96+
'<%@inputencoding="ISO-8859-1"%>\r\n',
97+
'<%@pagetemplate=TEMPLATE.y%>\r\n',
98+
'<%@import=import frog.util, frog%>\r\n',
99+
'<%@import=import frog.objects%>\r\n',
100+
'<%@import=from frog.storageerrors import StorageError%>\r\n',
101+
'<%\r\n',
102+
'\r\n',
103+
'import logging\r\n',
104+
'log=logging.getLogger("Snakelets.logger")\r\n',
105+
'\r\n',
106+
'\r\n',
107+
'user=self.SessionCtx.user\r\n',
108+
'storageEngine=self.SessionCtx.storageEngine\r\n',
109+
'\r\n',
110+
'\r\n',
111+
'def readArticlesFromDate(date, count=None):\r\n',
112+
' entryids=storageEngine.listBlogEntries(date)\r\n',
113+
' entryids.reverse() # descending\r\n',
114+
' if count:\r\n',
115+
' entryids=entryids[:count]\r\n',
116+
' try:\r\n',
117+
' return [ frog.objects.BlogEntry.load(storageEngine, date, Id) for Id in entryids ]\r\n',
118+
' except StorageError,x:\r\n',
119+
' log.error("Error loading articles: "+str(x))\r\n',
120+
' self.abort("cannot load articles")\r\n',
121+
'\r\n',
122+
'showdate=None\r\n',
123+
'\r\n',
124+
'arg=self.Request.getArg()\r\n',
125+
'if arg=="today":\r\n',
126+
' #-------------------- TODAY\'S ARTICLES\r\n',
127+
' self.write("<h2>Today\'s articles</h2>")\r\n',
128+
' showdate = frog.util.isodatestr() \r\n',
129+
' entries = readArticlesFromDate(showdate)\r\n',
130+
'elif arg=="active":\r\n',
131+
' #-------------------- ACTIVE ARTICLES redirect\r\n',
132+
' self.Yredirect("active.y")\r\n',
133+
'elif arg=="login":\r\n',
134+
' #-------------------- LOGIN PAGE redirect\r\n',
135+
' self.Yredirect("login.y")\r\n',
136+
'elif arg=="date":\r\n',
137+
' #-------------------- ARTICLES OF A SPECIFIC DATE\r\n',
138+
' showdate = self.Request.getParameter("date")\r\n',
139+
' self.write("<h2>Articles written on %s</h2>"% frog.util.mediumdatestr(showdate))\r\n',
140+
' entries = readArticlesFromDate(showdate)\r\n',
141+
'else:\r\n',
142+
' #-------------------- RECENT ARTICLES\r\n',
143+
' self.write("<h2>Recent articles</h2>")\r\n',
144+
' dates=storageEngine.listBlogEntryDates()\r\n',
145+
' if dates:\r\n',
146+
' entries=[]\r\n',
147+
' SHOWAMOUNT=10\r\n',
148+
' for showdate in dates:\r\n',
149+
' entries.extend( readArticlesFromDate(showdate, SHOWAMOUNT-len(entries)) )\r\n',
150+
' if len(entries)>=SHOWAMOUNT:\r\n',
151+
' break\r\n',
152+
' \r\n',
153+
]
154+
stream = StringIO.StringIO("".join(s).encode(self.encoding))
155+
reader = codecs.getreader(self.encoding)(stream)
156+
for (i, line) in enumerate(reader):
157+
self.assertEqual(line, s[i])
85158

86159
def test_readlinequeue(self):
87160
q = Queue()

0 commit comments

Comments
 (0)