Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Lib/shlex.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ def push_source(self, newstream, newfile=None):
"Push an input source onto the lexer's input source stack."
if isinstance(newstream, str):
newstream = StringIO(newstream)
self.filestack.appendleft((self.infile, self.instream, self.lineno))
self.filestack.appendleft((self.infile, self.instream, self.lineno,
self.state))
self.infile = newfile
self.instream = newstream
self.lineno = 1
self.state = ' '
if self.debug:
if newfile is not None:
print('shlex: pushing to file %s' % (self.infile,))
Expand All @@ -90,11 +92,11 @@ def push_source(self, newstream, newfile=None):
def pop_source(self):
"Pop the input source stack."
self.instream.close()
(self.infile, self.instream, self.lineno) = self.filestack.popleft()
(self.infile, self.instream, self.lineno,
self.state) = self.filestack.popleft()
if self.debug:
print('shlex: popping to %s, line %d' \
% (self.instream, self.lineno))
self.state = ' '

def get_token(self):
"Get a token from the input stream (or from stack if it's nonempty)"
Expand Down
41 changes: 41 additions & 0 deletions Lib/test/test_shlex.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,24 @@ def testPushSourceStream(self):
s.push_source(io.StringIO("hello"))
self.assertListEqual(list(s), ["hello", "world"])

def testPushSourceKeepsPushback(self):
s = shlex.shlex("parent")
stream = io.StringIO("child")
s.push_token("pushed")
s.push_source(stream)
self.assertListEqual(list(s), ["pushed", "child", "parent"])
self.assertTrue(stream.closed)

def testPushSourceAfterEOF(self):
for posix in (False, True):
with self.subTest(posix=posix):
s = shlex.shlex("parent", posix=posix)
self.assertEqual(list(s), ["parent"])
stream = io.StringIO("child")
s.push_source(stream)
self.assertEqual(list(s), ["child"])
self.assertTrue(stream.closed)

def testPushSourceStreamDebug(self):
s = shlex.shlex("")
stream = io.StringIO("hello")
Expand Down Expand Up @@ -514,6 +532,29 @@ def testSourceInclusion(self):
s.sourcehook = lambda f: (f, io.StringIO("included"))
self.assertEqual(list(s), ["included", "remaining"])

def testSourceInclusionAtEOF(self):
for posix in (False, True):
with self.subTest(posix=posix):
s = shlex.shlex("trigger filename", posix=posix)
s.source = "trigger"
stream = io.StringIO("included")
s.sourcehook = lambda f: (f, stream)
self.assertEqual(list(s), ["included"])
self.assertTrue(stream.closed)

def testNestedSourceInclusionAtEOF(self):
for posix in (False, True):
with self.subTest(posix=posix):
streams = {
"child": io.StringIO("trigger grandchild"),
"grandchild": io.StringIO("included"),
}
s = shlex.shlex("trigger child", posix=posix)
s.source = "trigger"
s.sourcehook = lambda f: (f, streams[f])
self.assertEqual(list(s), ["included"])
self.assertTrue(all(stream.closed for stream in streams.values()))

def testGetTokenPopsPushbackDebug(self):
s = shlex.shlex("")
s.push_token("hello")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :class:`shlex.shlex` source inclusion when the source filename is the
final token in a stream.
Loading