Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #45590 > unrolled thread

Question about ast.literal_eval

Started byFrank Millman <frank@chagford.com>
First post2013-05-20 09:05 +0200
Last post2013-05-21 07:54 +0200
Articles 3 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Question about ast.literal_eval Frank Millman <frank@chagford.com> - 2013-05-20 09:05 +0200
    Re: Question about ast.literal_eval matt.newville@gmail.com - 2013-05-20 19:39 -0700
      Re: Question about ast.literal_eval Frank Millman <frank@chagford.com> - 2013-05-21 07:54 +0200

#45590 — Question about ast.literal_eval

FromFrank Millman <frank@chagford.com>
Date2013-05-20 09:05 +0200
SubjectQuestion about ast.literal_eval
Message-ID<mailman.1863.1369033561.3114.python-list@python.org>
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

[toc] | [next] | [standalone]


#45636

Frommatt.newville@gmail.com
Date2013-05-20 19:39 -0700
Message-ID<bd9faee1-5b93-46d6-b403-091bf071cc77@googlegroups.com>
In reply to#45590
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 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.

Cheers,

--Matt Newville

[toc] | [prev] | [next] | [standalone]


#45644

FromFrank Millman <frank@chagford.com>
Date2013-05-21 07:54 +0200
Message-ID<mailman.1904.1369115684.3114.python-list@python.org>
In reply to#45636
On 21/05/2013 04:39, matt.newville@gmail.com 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


[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web