Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_expansion_limit(self):
'''make sure the expansion limit is working by tracking recursive
parsing count, and also checking that the word isn't expanded'''
counter = [0]
class countingparser(parser._parser):
def __init__(self, *args, **kwargs):
super(countingparser, self).__init__(*args, **kwargs)
counter[0] += 1
old = parser._parser
parser._parser = countingparser
try:
s = 'a $(b $(c $(d $(e))))'
self.assertASTEquals(s,
commandnode(s,
wordnode('a'),
wordnode('$(b $(c $(d $(e))))', '$(b $(c $(d $(e))))', [
comsubnode('$(b $(c $(d $(e))))',
commandnode('b $(c $(d $(e)))',
wordnode('b'),
wordnode('$(c $(d $(e)))')
)
)
])
),
wordnode('a'),
wordnode('$(b $(c $(d $(e))))', '$(b $(c $(d $(e))))', [
comsubnode('$(b $(c $(d $(e))))',
commandnode('b $(c $(d $(e)))',
wordnode('b'),
wordnode('$(c $(d $(e)))')
)
)
])
),
expansionlimit=1
)
self.assertEquals(counter[0], 3)
finally:
parser._parser = old
s = 'a $(b $(c))'
for i in [None] + list(range(2, 5)):
self.assertASTEquals(s,
commandnode(s,
wordnode('a'),
wordnode('$(b $(c))', '$(b $(c))', [
comsubnode('$(b $(c))',
commandnode('b $(c)',
wordnode('b'),
wordnode('$(c)', '$(c)', [
comsubnode('$(c)',
commandnode('c',
wordnode('c')
)
)
def parsesingle(s, strictmode=True, expansionlimit=None, convertpos=False):
'''like parse, but only consumes a single top level node, e.g. parsing
'a\nb' will only return a node for 'a', leaving b unparsed'''
p = _parser(s, strictmode=strictmode, expansionlimit=expansionlimit)
tree = p.parse()
if convertpos:
ast.posconverter(s).visit(tree)
return tree
- command - a simple command
- pipeline - a series of simple commands
- list - a series of one or more pipelines
- compound - contains constructs for { list; }, (list), if, for..
leafs are word nodes (which in turn can also contain any of the
aforementioned nodes due to command substitutions).
when strictmode is set to False, we will:
- skip reading a heredoc if we're at the end of the input
expansionlimit is used to limit the amount of recursive parsing done due to
command substitutions found during word expansion.
'''
p = _parser(s, strictmode=strictmode, expansionlimit=expansionlimit)
parts = [p.parse()]
class endfinder(ast.nodevisitor):
def __init__(self):
self.end = -1
def visitheredoc(self, node, value):
self.end = node.pos[1]
# find the 'real' end incase we have a heredoc in there
ef = _endfinder()
ef.visit(parts[-1])
index = max(parts[-1].pos[1], ef.end) + 1
while index < len(s):
part = _parser(s[index:], strictmode=strictmode).parse()
if not isinstance(part, ast.node):
'''
p = _parser(s, strictmode=strictmode, expansionlimit=expansionlimit)
parts = [p.parse()]
class endfinder(ast.nodevisitor):
def __init__(self):
self.end = -1
def visitheredoc(self, node, value):
self.end = node.pos[1]
# find the 'real' end incase we have a heredoc in there
ef = _endfinder()
ef.visit(parts[-1])
index = max(parts[-1].pos[1], ef.end) + 1
while index < len(s):
part = _parser(s[index:], strictmode=strictmode).parse()
if not isinstance(part, ast.node):
break
ast.posshifter(index).visit(part)
parts.append(part)
ef = _endfinder()
ef.visit(parts[-1])
index = max(parts[-1].pos[1], ef.end) + 1
if convertpos:
for tree in parts:
ast.posconverter(s).visit(tree)
return parts
def split(s):
'''a utility function that mimics shlex.split but handles more
complex shell constructs such as command substitutions inside words
>>> list(split('a b"c"\\'d\\''))
['a', 'bcd']
>>> list(split('a "b $(c)" $(d) \\'$(e)\\''))
['a', 'b $(c)', '$(d)', '$(e)']
>>> list(split('a b\\n'))
['a', 'b', '\\n']
'''
p = _parser(s)
for t in p.tok:
if t.ttype == tokenizer.tokentype.WORD:
quoted = bool(t.flags & flags.word.QUOTED)
doublequoted = quoted and t.value[0] == '"'
parts, expandedword = subst._expandwordinternal(p, t, 0,
doublequoted, 0, 0)
yield expandedword
else:
yield s[t.lexpos:t.endlexpos]