how to convert string to list or tuple

John Roth newsgroups at jhrothjr.com
Sun May 29 13:13:39 EDT 2005


"Duncan Booth" <duncan.booth at invalid.invalid> wrote in message 
news:Xns9665B54CBAA38duncanbooth at 127.0.0.1...
> Dan Bishop wrote:
>
>> Simon Brunning wrote:
>>> [...]
>>
>> Or if you do use eval, don't give it access to any names.
>>
>>> [...]
>> os.system("rm -rf *")
>> Traceback (most recent call last):
>>   File "<stdin>", line 1, in ?
>>   File "<string>", line 0, in ?
>> NameError: name 'os' is not defined
>>
> Have you tried giving it the string '__import__("os").system("rm -rf *")'?
> [Don't try that at home children!]
>
> Even if you take steps to avoid that working by hiding the builtins, there
> are still too many ways to do nasty things with eval for it ever to be
> safe.

There was a posting here Nov 5, 2003 by Huaiyu Zhu at IBM Almaden
that shows how to do eval type stuff safely. The basic notion is to use the
compiler and then check the ast to see if the result fits the straitjacket 
you
want to put it into. Pass / Fail; trying to fix it up if it's "close" is 
usually a
real bad idea.

He gives an example, and there's a much more extensive set of working
code in the taBase.py module of PyFit that handles lists, tuples and
dicts which contain arbitrary literals including complex and arbitrarily 
nested
lists, tuples and dicts.

------- code snippet starts here --------

    def _safeEval(self, s):
        """
        Evaluate strings that only contain the following structures:
        const,  tuple,  list,   dict
        Taken from c.l.py newsgroup posting Nov 5, 2003 by Huaiyu Zhu at IBM 
Almaden
        """
        #print "in _safeEval. input: '%s'" % s
        node1 = compiler.parse(s)

        # !!! special case of attempting to compile a lone string
        if node1.doc is not None and len(node1.node.nodes) == 0:
            #print "in _safeEval. string: '%s' found as docstring" % 
node1.doc
            return node1.doc

        #print "in _safeEval. nodes: '%s'" % (node1,)
        stmts = node1.node.nodes
        assert len(stmts) == 1
        node = compiler.parse(s).node.nodes[0]
        assert node.__class__ == compiler.ast.Discard
        nodes = node.getChildNodes()
        assert len(nodes) == 1
        result = self._safeAssemble(nodes[0])
        #print "in _safeEval result: '%s'" % (result,)
        return result

    seq_types = {
        compiler.ast.Tuple: tuple,
        compiler.ast.List: list,
        }
    map_types = {
        compiler.ast.Dict: dict,
        }

    oper_types = {
        compiler.ast.Add: operator.add,
        compiler.ast.Sub: operator.sub,
        }

    builtin_consts = {
        "True": True,
        "False": False,
        "None": None,
        }

    def _safeAssemble(self, node):
        """ Recursively assemble parsed ast node """
        cls = node.__class__
        if cls == compiler.ast.Const:
            return node.value
        elif cls in self.seq_types:
            nodes = node.nodes
            args = map(self._safeAssemble, nodes)
            return self.seq_types[cls](args)
        elif cls in self.map_types:
            keys, values = zip(*node.items)
            keys = map(self._safeAssemble, keys)
            values = map(self._safeAssemble, values)
            return self.map_types[cls](zip(keys, values))
        elif cls in self.oper_types:
            left = self._safeAssemble(node.left)
            right = self._safeAssemble(node.right)
            if type(left) == type(1.0j) or type(right) == type(1.0j):
                return self.oper_types[cls](left, right)
            else:
                raise FitException, ("Parse001",)
        elif cls == compiler.ast.Name:
            result = self.builtin_consts.get(node.name, "?")
            if result != "?":
                return result
            else:
                raise FitException, ("Parse002", node.name)
        else:
            raise FitException, ("Parse003", cls)

------- end of code snippet -----------

John Roth


> 




More information about the Python-list mailing list