Skip to content

Commit e6be64f

Browse files
authored
Merge pull request #282 from lubomir/fix-config-parsing
Fix RecursionError in parsing config with comments
2 parents b889d2c + a5a1750 commit e6be64f

2 files changed

Lines changed: 46 additions & 10 deletions

File tree

kobo/conf.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,18 +184,18 @@ def _assert_token(self, *args):
184184

185185
def _get_token(self, skip_newline=True):
186186
"""Get a new token from token generator."""
187-
self._tok_number, self._tok_value, self._tok_begin, self._tok_end, self._tok_line = next(self._tokens)
188-
self._tok_name = token.tok_name.get(self._tok_number, None)
189-
190-
if self._debug:
191-
print("%2s %16s %s" % (self._tok_number, self._tok_name, self._tok_value.strip()))
187+
while True:
188+
self._tok_number, self._tok_value, self._tok_begin, self._tok_end, self._tok_line = next(self._tokens)
189+
self._tok_name = token.tok_name.get(self._tok_number, None)
192190

193-
# skip some tokens
194-
if self._tok_name in ["COMMENT", "INDENT", "DEDENT"]:
195-
self._get_token(skip_newline=skip_newline)
191+
if self._debug:
192+
print("%2s %16s %s" % (self._tok_number, self._tok_name, self._tok_value.strip()))
196193

197-
if skip_newline and self._tok_name in ["NL", "NEWLINE"]:
198-
self._get_token()
194+
if self._tok_name in ["COMMENT", "INDENT", "DEDENT"]:
195+
continue
196+
if skip_newline and self._tok_name in ["NL", "NEWLINE"]:
197+
continue
198+
break
199199

200200
def _get_NAME(self):
201201
"""Return a NAME token value."""

tests/test_conf.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,39 @@ def test_duplicate_keys(self):
184184

185185
self.assertEqual(str(ctx.exception),
186186
"Duplicate dict key 'bar' in file None on line 3")
187+
188+
189+
class TestManyComments(unittest.TestCase):
190+
"""
191+
Regression tests for RecursionError with many consecutive comment/blank
192+
lines.
193+
"""
194+
195+
def _make_config_with_comments(self, n):
196+
lines = ["# comment %d" % i for i in range(n)]
197+
lines.append("x = 1")
198+
return "\n".join(lines)
199+
200+
def test_many_comments_from_string(self):
201+
cfg = self._make_config_with_comments(1000)
202+
conf = PyConfigParser()
203+
conf.load_from_string(cfg)
204+
self.assertEqual(conf["x"], 1)
205+
206+
def test_many_comments_from_file(self):
207+
cfg = self._make_config_with_comments(1000)
208+
conf = PyConfigParser()
209+
with tempfile.NamedTemporaryFile(mode="w", suffix=".conf", delete=False) as f:
210+
f.write(cfg)
211+
path = f.name
212+
try:
213+
conf.load_from_file(path)
214+
self.assertEqual(conf["x"], 1)
215+
finally:
216+
os.unlink(path)
217+
218+
def test_many_blank_lines_from_string(self):
219+
cfg = "\n" * 1000 + "x = 1\n"
220+
conf = PyConfigParser()
221+
conf.load_from_string(cfg)
222+
self.assertEqual(conf["x"], 1)

0 commit comments

Comments
 (0)