Question about ast.literal_eval

Discussion in 'Python' started by Frank Millman, May 20, 2013.

  1. Hi all

    I am trying to emulate a SQL check constraint in Python. Quoting from
    the PostgreSQL docs, "A check constraint is the most generic constraint
    type. It allows you to specify that the value in a certain column must
    satisfy a Boolean (truth-value) expression."

    The problem is that I want to store the constraint as a string, and I
    was hoping to use ast.literal_eval to evaluate it, but it does not work.

    >>> x = 'abc'
    >>> x in ('abc', xyz')

    True
    >>> b = "x in ('abc', 'xyz')"
    >>> eval(b)

    True
    >>> from ast import literal_eval
    >>> literal_eval(b)

    ValueError: malformed node or string: <_ast.Compare object at ...>

    Is there a safe way to do what I want? I am using python 3.3.

    Thanks

    Frank Millman
    Frank Millman, May 20, 2013
    #1
    1. Advertising

  2. Frank Millman

    Guest

    On Monday, May 20, 2013 2:05:48 AM UTC-5, Frank Millman wrote:
    > Hi all
    >
    >
    >
    > I am trying to emulate a SQL check constraint in Python. Quoting from
    >
    > the PostgreSQL docs, "A check constraint is the most generic constraint
    >
    > type. It allows you to specify that the value in a certain column must
    >
    > satisfy a Boolean (truth-value) expression."
    >
    >
    >
    > The problem is that I want to store the constraint as a string, and I
    >
    > was hoping to use ast.literal_eval to evaluate it, but it does not work.
    >
    >
    >
    > >>> x = 'abc'

    >
    > >>> x in ('abc', xyz')

    >
    > True
    >
    > >>> b = "x in ('abc', 'xyz')"

    >
    > >>> eval(b)

    >
    > True
    >
    > >>> from ast import literal_eval

    >
    > >>> literal_eval(b)

    >
    > ValueError: malformed node or string: <_ast.Compare object at ...>
    >
    >
    >
    > Is there a safe way to do what I want? I am using python 3.3.
    >
    >
    >
    > Thanks
    >
    >
    >
    > Frank Millman


    You might find the asteval module (https://pypi.python.org/pypi/asteval) useful. It provides a relatively safe "eval", for example:

    >>> import asteval
    >>> a = asteval.Interpreter()
    >>> a.eval('x = "abc"')
    >>> a.eval('x in ("abc", "xyz")')

    True
    >>> a.eval('import os')

    NotImplementedError
    import os
    'Import' not supported
    >>> a.eval('__import__("os")')

    NameError
    __import__("os")
    name '__import__' is not defined

    This works by maintaining an internal namespace (a flat dictionary), and walking the AST generated for the expression. It supports most Python syntax,
    including if, for, while, and try/except blocks, and function definitions, and with the notable exceptions of eval, exec, class, lambda, yield, and import. This requires Python2.6 and higher, and does work with Python3.3.

    Of course, it is not guaranteed to be completely safe, but it does disallowimports, which seems like the biggest vulnerability concern listed here. Currently, there is no explicit protection against long-running calculations for denial of service attacks. If you're exposing an SQL database to user-generated code, that may be worth considering.

    Cheers,

    --Matt Newville
    , May 21, 2013
    #2
    1. Advertising

  3. On 21/05/2013 04:39, wrote:
    >
    > You might find the asteval module (https://pypi.python.org/pypi/asteval) useful. It provides a relatively safe "eval", for example:
    >
    > >>> import asteval
    > >>> a = asteval.Interpreter()
    > >>> a.eval('x = "abc"')
    > >>> a.eval('x in ("abc", "xyz")')

    > True
    > >>> a.eval('import os')

    > NotImplementedError
    > import os
    > 'Import' not supported
    > >>> a.eval('__import__("os")')

    > NameError
    > __import__("os")
    > name '__import__' is not defined
    >
    > This works by maintaining an internal namespace (a flat dictionary), and walking the AST generated for the expression. It supports most Python syntax,
    > including if, for, while, and try/except blocks, and function definitions, and with the notable exceptions of eval, exec, class, lambda, yield, and import. This requires Python2.6 and higher, and does work with Python3.3.
    >
    > Of course, it is not guaranteed to be completely safe, but it does disallow imports, which seems like the biggest vulnerability concern listed here. Currently, there is no explicit protection against long-running calculations for denial of service attacks. If you're exposing an SQL database to user-generated code, that may be worth considering.


    Thanks for this, Matt. I will definitely look into it.

    Frank
    Frank Millman, May 21, 2013
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Carlos Nepomuceno

    RE: Question about ast.literal_eval

    Carlos Nepomuceno, May 20, 2013, in forum: Python
    Replies:
    0
    Views:
    79
    Carlos Nepomuceno
    May 20, 2013
  2. Chris Angelico

    Re: Question about ast.literal_eval

    Chris Angelico, May 20, 2013, in forum: Python
    Replies:
    0
    Views:
    93
    Chris Angelico
    May 20, 2013
  3. Frank Millman

    Re: Question about ast.literal_eval

    Frank Millman, May 20, 2013, in forum: Python
    Replies:
    0
    Views:
    85
    Frank Millman
    May 20, 2013
  4. Chris Angelico

    Re: Question about ast.literal_eval

    Chris Angelico, May 20, 2013, in forum: Python
    Replies:
    0
    Views:
    78
    Chris Angelico
    May 20, 2013
  5. Carlos Nepomuceno

    RE: Question about ast.literal_eval

    Carlos Nepomuceno, May 20, 2013, in forum: Python
    Replies:
    1
    Views:
    104
    Steven D'Aprano
    May 20, 2013
Loading...

Share This Page