Parsing a Python expression without evaluation
I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.
For example:
cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)
x + y + z
I have no way of producing the correct type and value of the operands for these expressions. I need something which parses the expression and tells me if there is an expression error.
The Python eval()
function parses and evaluates the expression. I need only a parsing.
Is there something for that need?
python parsing
add a comment |
I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.
For example:
cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)
x + y + z
I have no way of producing the correct type and value of the operands for these expressions. I need something which parses the expression and tells me if there is an expression error.
The Python eval()
function parses and evaluates the expression. I need only a parsing.
Is there something for that need?
python parsing
add a comment |
I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.
For example:
cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)
x + y + z
I have no way of producing the correct type and value of the operands for these expressions. I need something which parses the expression and tells me if there is an expression error.
The Python eval()
function parses and evaluates the expression. I need only a parsing.
Is there something for that need?
python parsing
I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.
For example:
cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)
x + y + z
I have no way of producing the correct type and value of the operands for these expressions. I need something which parses the expression and tells me if there is an expression error.
The Python eval()
function parses and evaluates the expression. I need only a parsing.
Is there something for that need?
python parsing
python parsing
edited Nov 22 '18 at 11:32
Martijn Pieters♦
715k13825002313
715k13825002313
asked Nov 22 '18 at 11:22
Julieng31Julieng31
133
133
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You may want full compilation into a full Python code object, or you can just parse into an abstract syntax tree. You can use the compile()
function to achieve either, or just use ast.parse()
to produce the tree.
Parsing into an AST tokenizes the input and outputs a tree of syntax objects that you can then further analyse or transform. Compiling into bytecode goes one step further, using that AST to create a Python code object that you can optionally execute with either eval()
or the exec()
function; note that the latter always returns None
and is probably not the best choice to evaluate an expression code object.
eval(string)
uses eval(compile(string, "<stdin>", "eval"))
to compile a string argument to a code object, then execute it, so compile(string, "<stdin>", "eval")
would give you the same result without execution.
Use "eval"
as the mode if only an expression is valid, or "exec"
if full Python statements are to be accepted. compile()
(and ast.parse()
) raises a SyntaxError
exception if the input is not a valid Python expression ("eval"
) or not valid statements ("exec"
).
Demo:
>>> example1 = "cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)"
>>> example2 = "x + y + z"
>>> compile(example1, "<stdin>", "eval")
<code object <module> at 0x111c2eae0, file "<stdin>", line 1>
>>> compile(example2, "<stdin>", "eval")
<code object <module> at 0x111c2e540, file "<stdin>", line 1>
>>> result2 = _
>>> eval(result2, {"x": 42, "y": 81, "z": 117})
240
>>> compile("not a valid expression", "<stdin>", "eval")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1
not a valid expression
^
SyntaxError: invalid syntax
Parsing to an AST would let you discover what names the code expects to be able to access; you can collect names by looking for Name
nodes:
>>> import ast
>>> tree1 = ast.parse(example1)
>>> tree2 = ast.parse(example2)
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue1', ctx=Load())], keywords=), op=Add(), right=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue2', ctx=Load())], keywords=)))"
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=BinOp(left=Name(id='x', ctx=Load()), op=Add(), right=Name(id='y', ctx=Load())), op=Add(), right=Name(id='z', ctx=Load())))"
>>> {node.id for node in ast.walk(tree1) if isinstance(node, ast.Name)}
{'cos', 'PARAMPOLY'}
>>> {node.id for node in ast.walk(tree2) if isinstance(node, ast.Name)}
{'x', 'z', 'y'}
Note that the above ignored context, so the PARAMPONLY
attribute name is listed too. Write a ast.NodeVisitor
subclass if you need to process a syntax tree with more context.
Thanks a lot for your explanation. To go further, imagine I expect math vocabulary items like "cos" and "sin" in the expression provided by the user and I want to check it. ex : 1 - IN : cos(a) + sin(b) OUT : OK 2 - IN : cos(a,b) OUT NOK 3 - IN fake(a) OUT NOK 4 - IN tan(a) OUT NOK As I undertand, parsing is not enough, I need to use eval expression but I don't know how to manage operand.from math import * print(eval('cos(a) + sin(b)', {'cos': cos, 'sin': sin}))
Do you have any idea ?
– Julieng31
Nov 22 '18 at 15:37
@Julieng31: if you need to evaluate mathematical expressions, then see Evaluating a mathematical expression in a string, where one of the answers led to github.com/danthedeckie/simpleeval, which is, at the very least, a starting point for what you want to do. The latter uses the AST to then drive expression execution in a safe and controlled way.
– Martijn Pieters♦
Nov 22 '18 at 15:43
@Julieng31: at any rate, something likecos(a b)
would be parsed into aCall()
expression, withcos
as the name of the callable, with two arguments. You can then use something like the function signature or information you stored up front to see if that call could work at all (len(inspect.signature(math.cos).parameters)
is1
, so no, that call would fail).
– Martijn Pieters♦
Nov 22 '18 at 15:46
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53429859%2fparsing-a-python-expression-without-evaluation%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You may want full compilation into a full Python code object, or you can just parse into an abstract syntax tree. You can use the compile()
function to achieve either, or just use ast.parse()
to produce the tree.
Parsing into an AST tokenizes the input and outputs a tree of syntax objects that you can then further analyse or transform. Compiling into bytecode goes one step further, using that AST to create a Python code object that you can optionally execute with either eval()
or the exec()
function; note that the latter always returns None
and is probably not the best choice to evaluate an expression code object.
eval(string)
uses eval(compile(string, "<stdin>", "eval"))
to compile a string argument to a code object, then execute it, so compile(string, "<stdin>", "eval")
would give you the same result without execution.
Use "eval"
as the mode if only an expression is valid, or "exec"
if full Python statements are to be accepted. compile()
(and ast.parse()
) raises a SyntaxError
exception if the input is not a valid Python expression ("eval"
) or not valid statements ("exec"
).
Demo:
>>> example1 = "cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)"
>>> example2 = "x + y + z"
>>> compile(example1, "<stdin>", "eval")
<code object <module> at 0x111c2eae0, file "<stdin>", line 1>
>>> compile(example2, "<stdin>", "eval")
<code object <module> at 0x111c2e540, file "<stdin>", line 1>
>>> result2 = _
>>> eval(result2, {"x": 42, "y": 81, "z": 117})
240
>>> compile("not a valid expression", "<stdin>", "eval")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1
not a valid expression
^
SyntaxError: invalid syntax
Parsing to an AST would let you discover what names the code expects to be able to access; you can collect names by looking for Name
nodes:
>>> import ast
>>> tree1 = ast.parse(example1)
>>> tree2 = ast.parse(example2)
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue1', ctx=Load())], keywords=), op=Add(), right=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue2', ctx=Load())], keywords=)))"
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=BinOp(left=Name(id='x', ctx=Load()), op=Add(), right=Name(id='y', ctx=Load())), op=Add(), right=Name(id='z', ctx=Load())))"
>>> {node.id for node in ast.walk(tree1) if isinstance(node, ast.Name)}
{'cos', 'PARAMPOLY'}
>>> {node.id for node in ast.walk(tree2) if isinstance(node, ast.Name)}
{'x', 'z', 'y'}
Note that the above ignored context, so the PARAMPONLY
attribute name is listed too. Write a ast.NodeVisitor
subclass if you need to process a syntax tree with more context.
Thanks a lot for your explanation. To go further, imagine I expect math vocabulary items like "cos" and "sin" in the expression provided by the user and I want to check it. ex : 1 - IN : cos(a) + sin(b) OUT : OK 2 - IN : cos(a,b) OUT NOK 3 - IN fake(a) OUT NOK 4 - IN tan(a) OUT NOK As I undertand, parsing is not enough, I need to use eval expression but I don't know how to manage operand.from math import * print(eval('cos(a) + sin(b)', {'cos': cos, 'sin': sin}))
Do you have any idea ?
– Julieng31
Nov 22 '18 at 15:37
@Julieng31: if you need to evaluate mathematical expressions, then see Evaluating a mathematical expression in a string, where one of the answers led to github.com/danthedeckie/simpleeval, which is, at the very least, a starting point for what you want to do. The latter uses the AST to then drive expression execution in a safe and controlled way.
– Martijn Pieters♦
Nov 22 '18 at 15:43
@Julieng31: at any rate, something likecos(a b)
would be parsed into aCall()
expression, withcos
as the name of the callable, with two arguments. You can then use something like the function signature or information you stored up front to see if that call could work at all (len(inspect.signature(math.cos).parameters)
is1
, so no, that call would fail).
– Martijn Pieters♦
Nov 22 '18 at 15:46
add a comment |
You may want full compilation into a full Python code object, or you can just parse into an abstract syntax tree. You can use the compile()
function to achieve either, or just use ast.parse()
to produce the tree.
Parsing into an AST tokenizes the input and outputs a tree of syntax objects that you can then further analyse or transform. Compiling into bytecode goes one step further, using that AST to create a Python code object that you can optionally execute with either eval()
or the exec()
function; note that the latter always returns None
and is probably not the best choice to evaluate an expression code object.
eval(string)
uses eval(compile(string, "<stdin>", "eval"))
to compile a string argument to a code object, then execute it, so compile(string, "<stdin>", "eval")
would give you the same result without execution.
Use "eval"
as the mode if only an expression is valid, or "exec"
if full Python statements are to be accepted. compile()
(and ast.parse()
) raises a SyntaxError
exception if the input is not a valid Python expression ("eval"
) or not valid statements ("exec"
).
Demo:
>>> example1 = "cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)"
>>> example2 = "x + y + z"
>>> compile(example1, "<stdin>", "eval")
<code object <module> at 0x111c2eae0, file "<stdin>", line 1>
>>> compile(example2, "<stdin>", "eval")
<code object <module> at 0x111c2e540, file "<stdin>", line 1>
>>> result2 = _
>>> eval(result2, {"x": 42, "y": 81, "z": 117})
240
>>> compile("not a valid expression", "<stdin>", "eval")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1
not a valid expression
^
SyntaxError: invalid syntax
Parsing to an AST would let you discover what names the code expects to be able to access; you can collect names by looking for Name
nodes:
>>> import ast
>>> tree1 = ast.parse(example1)
>>> tree2 = ast.parse(example2)
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue1', ctx=Load())], keywords=), op=Add(), right=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue2', ctx=Load())], keywords=)))"
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=BinOp(left=Name(id='x', ctx=Load()), op=Add(), right=Name(id='y', ctx=Load())), op=Add(), right=Name(id='z', ctx=Load())))"
>>> {node.id for node in ast.walk(tree1) if isinstance(node, ast.Name)}
{'cos', 'PARAMPOLY'}
>>> {node.id for node in ast.walk(tree2) if isinstance(node, ast.Name)}
{'x', 'z', 'y'}
Note that the above ignored context, so the PARAMPONLY
attribute name is listed too. Write a ast.NodeVisitor
subclass if you need to process a syntax tree with more context.
Thanks a lot for your explanation. To go further, imagine I expect math vocabulary items like "cos" and "sin" in the expression provided by the user and I want to check it. ex : 1 - IN : cos(a) + sin(b) OUT : OK 2 - IN : cos(a,b) OUT NOK 3 - IN fake(a) OUT NOK 4 - IN tan(a) OUT NOK As I undertand, parsing is not enough, I need to use eval expression but I don't know how to manage operand.from math import * print(eval('cos(a) + sin(b)', {'cos': cos, 'sin': sin}))
Do you have any idea ?
– Julieng31
Nov 22 '18 at 15:37
@Julieng31: if you need to evaluate mathematical expressions, then see Evaluating a mathematical expression in a string, where one of the answers led to github.com/danthedeckie/simpleeval, which is, at the very least, a starting point for what you want to do. The latter uses the AST to then drive expression execution in a safe and controlled way.
– Martijn Pieters♦
Nov 22 '18 at 15:43
@Julieng31: at any rate, something likecos(a b)
would be parsed into aCall()
expression, withcos
as the name of the callable, with two arguments. You can then use something like the function signature or information you stored up front to see if that call could work at all (len(inspect.signature(math.cos).parameters)
is1
, so no, that call would fail).
– Martijn Pieters♦
Nov 22 '18 at 15:46
add a comment |
You may want full compilation into a full Python code object, or you can just parse into an abstract syntax tree. You can use the compile()
function to achieve either, or just use ast.parse()
to produce the tree.
Parsing into an AST tokenizes the input and outputs a tree of syntax objects that you can then further analyse or transform. Compiling into bytecode goes one step further, using that AST to create a Python code object that you can optionally execute with either eval()
or the exec()
function; note that the latter always returns None
and is probably not the best choice to evaluate an expression code object.
eval(string)
uses eval(compile(string, "<stdin>", "eval"))
to compile a string argument to a code object, then execute it, so compile(string, "<stdin>", "eval")
would give you the same result without execution.
Use "eval"
as the mode if only an expression is valid, or "exec"
if full Python statements are to be accepted. compile()
(and ast.parse()
) raises a SyntaxError
exception if the input is not a valid Python expression ("eval"
) or not valid statements ("exec"
).
Demo:
>>> example1 = "cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)"
>>> example2 = "x + y + z"
>>> compile(example1, "<stdin>", "eval")
<code object <module> at 0x111c2eae0, file "<stdin>", line 1>
>>> compile(example2, "<stdin>", "eval")
<code object <module> at 0x111c2e540, file "<stdin>", line 1>
>>> result2 = _
>>> eval(result2, {"x": 42, "y": 81, "z": 117})
240
>>> compile("not a valid expression", "<stdin>", "eval")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1
not a valid expression
^
SyntaxError: invalid syntax
Parsing to an AST would let you discover what names the code expects to be able to access; you can collect names by looking for Name
nodes:
>>> import ast
>>> tree1 = ast.parse(example1)
>>> tree2 = ast.parse(example2)
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue1', ctx=Load())], keywords=), op=Add(), right=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue2', ctx=Load())], keywords=)))"
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=BinOp(left=Name(id='x', ctx=Load()), op=Add(), right=Name(id='y', ctx=Load())), op=Add(), right=Name(id='z', ctx=Load())))"
>>> {node.id for node in ast.walk(tree1) if isinstance(node, ast.Name)}
{'cos', 'PARAMPOLY'}
>>> {node.id for node in ast.walk(tree2) if isinstance(node, ast.Name)}
{'x', 'z', 'y'}
Note that the above ignored context, so the PARAMPONLY
attribute name is listed too. Write a ast.NodeVisitor
subclass if you need to process a syntax tree with more context.
You may want full compilation into a full Python code object, or you can just parse into an abstract syntax tree. You can use the compile()
function to achieve either, or just use ast.parse()
to produce the tree.
Parsing into an AST tokenizes the input and outputs a tree of syntax objects that you can then further analyse or transform. Compiling into bytecode goes one step further, using that AST to create a Python code object that you can optionally execute with either eval()
or the exec()
function; note that the latter always returns None
and is probably not the best choice to evaluate an expression code object.
eval(string)
uses eval(compile(string, "<stdin>", "eval"))
to compile a string argument to a code object, then execute it, so compile(string, "<stdin>", "eval")
would give you the same result without execution.
Use "eval"
as the mode if only an expression is valid, or "exec"
if full Python statements are to be accepted. compile()
(and ast.parse()
) raises a SyntaxError
exception if the input is not a valid Python expression ("eval"
) or not valid statements ("exec"
).
Demo:
>>> example1 = "cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)"
>>> example2 = "x + y + z"
>>> compile(example1, "<stdin>", "eval")
<code object <module> at 0x111c2eae0, file "<stdin>", line 1>
>>> compile(example2, "<stdin>", "eval")
<code object <module> at 0x111c2e540, file "<stdin>", line 1>
>>> result2 = _
>>> eval(result2, {"x": 42, "y": 81, "z": 117})
240
>>> compile("not a valid expression", "<stdin>", "eval")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1
not a valid expression
^
SyntaxError: invalid syntax
Parsing to an AST would let you discover what names the code expects to be able to access; you can collect names by looking for Name
nodes:
>>> import ast
>>> tree1 = ast.parse(example1)
>>> tree2 = ast.parse(example2)
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue1', ctx=Load())], keywords=), op=Add(), right=Call(func=Name(id='cos', ctx=Load()), args=[Attribute(value=Name(id='PARAMPOLY', ctx=Load()), attr='engineeringValue2', ctx=Load())], keywords=)))"
>>> ast.dump(tree2.body[0])
"Expr(value=BinOp(left=BinOp(left=Name(id='x', ctx=Load()), op=Add(), right=Name(id='y', ctx=Load())), op=Add(), right=Name(id='z', ctx=Load())))"
>>> {node.id for node in ast.walk(tree1) if isinstance(node, ast.Name)}
{'cos', 'PARAMPOLY'}
>>> {node.id for node in ast.walk(tree2) if isinstance(node, ast.Name)}
{'x', 'z', 'y'}
Note that the above ignored context, so the PARAMPONLY
attribute name is listed too. Write a ast.NodeVisitor
subclass if you need to process a syntax tree with more context.
edited Nov 22 '18 at 11:56
answered Nov 22 '18 at 11:24
Martijn Pieters♦Martijn Pieters
715k13825002313
715k13825002313
Thanks a lot for your explanation. To go further, imagine I expect math vocabulary items like "cos" and "sin" in the expression provided by the user and I want to check it. ex : 1 - IN : cos(a) + sin(b) OUT : OK 2 - IN : cos(a,b) OUT NOK 3 - IN fake(a) OUT NOK 4 - IN tan(a) OUT NOK As I undertand, parsing is not enough, I need to use eval expression but I don't know how to manage operand.from math import * print(eval('cos(a) + sin(b)', {'cos': cos, 'sin': sin}))
Do you have any idea ?
– Julieng31
Nov 22 '18 at 15:37
@Julieng31: if you need to evaluate mathematical expressions, then see Evaluating a mathematical expression in a string, where one of the answers led to github.com/danthedeckie/simpleeval, which is, at the very least, a starting point for what you want to do. The latter uses the AST to then drive expression execution in a safe and controlled way.
– Martijn Pieters♦
Nov 22 '18 at 15:43
@Julieng31: at any rate, something likecos(a b)
would be parsed into aCall()
expression, withcos
as the name of the callable, with two arguments. You can then use something like the function signature or information you stored up front to see if that call could work at all (len(inspect.signature(math.cos).parameters)
is1
, so no, that call would fail).
– Martijn Pieters♦
Nov 22 '18 at 15:46
add a comment |
Thanks a lot for your explanation. To go further, imagine I expect math vocabulary items like "cos" and "sin" in the expression provided by the user and I want to check it. ex : 1 - IN : cos(a) + sin(b) OUT : OK 2 - IN : cos(a,b) OUT NOK 3 - IN fake(a) OUT NOK 4 - IN tan(a) OUT NOK As I undertand, parsing is not enough, I need to use eval expression but I don't know how to manage operand.from math import * print(eval('cos(a) + sin(b)', {'cos': cos, 'sin': sin}))
Do you have any idea ?
– Julieng31
Nov 22 '18 at 15:37
@Julieng31: if you need to evaluate mathematical expressions, then see Evaluating a mathematical expression in a string, where one of the answers led to github.com/danthedeckie/simpleeval, which is, at the very least, a starting point for what you want to do. The latter uses the AST to then drive expression execution in a safe and controlled way.
– Martijn Pieters♦
Nov 22 '18 at 15:43
@Julieng31: at any rate, something likecos(a b)
would be parsed into aCall()
expression, withcos
as the name of the callable, with two arguments. You can then use something like the function signature or information you stored up front to see if that call could work at all (len(inspect.signature(math.cos).parameters)
is1
, so no, that call would fail).
– Martijn Pieters♦
Nov 22 '18 at 15:46
Thanks a lot for your explanation. To go further, imagine I expect math vocabulary items like "cos" and "sin" in the expression provided by the user and I want to check it. ex : 1 - IN : cos(a) + sin(b) OUT : OK 2 - IN : cos(a,b) OUT NOK 3 - IN fake(a) OUT NOK 4 - IN tan(a) OUT NOK As I undertand, parsing is not enough, I need to use eval expression but I don't know how to manage operand.
from math import * print(eval('cos(a) + sin(b)', {'cos': cos, 'sin': sin}))
Do you have any idea ?– Julieng31
Nov 22 '18 at 15:37
Thanks a lot for your explanation. To go further, imagine I expect math vocabulary items like "cos" and "sin" in the expression provided by the user and I want to check it. ex : 1 - IN : cos(a) + sin(b) OUT : OK 2 - IN : cos(a,b) OUT NOK 3 - IN fake(a) OUT NOK 4 - IN tan(a) OUT NOK As I undertand, parsing is not enough, I need to use eval expression but I don't know how to manage operand.
from math import * print(eval('cos(a) + sin(b)', {'cos': cos, 'sin': sin}))
Do you have any idea ?– Julieng31
Nov 22 '18 at 15:37
@Julieng31: if you need to evaluate mathematical expressions, then see Evaluating a mathematical expression in a string, where one of the answers led to github.com/danthedeckie/simpleeval, which is, at the very least, a starting point for what you want to do. The latter uses the AST to then drive expression execution in a safe and controlled way.
– Martijn Pieters♦
Nov 22 '18 at 15:43
@Julieng31: if you need to evaluate mathematical expressions, then see Evaluating a mathematical expression in a string, where one of the answers led to github.com/danthedeckie/simpleeval, which is, at the very least, a starting point for what you want to do. The latter uses the AST to then drive expression execution in a safe and controlled way.
– Martijn Pieters♦
Nov 22 '18 at 15:43
@Julieng31: at any rate, something like
cos(a b)
would be parsed into a Call()
expression, with cos
as the name of the callable, with two arguments. You can then use something like the function signature or information you stored up front to see if that call could work at all (len(inspect.signature(math.cos).parameters)
is 1
, so no, that call would fail).– Martijn Pieters♦
Nov 22 '18 at 15:46
@Julieng31: at any rate, something like
cos(a b)
would be parsed into a Call()
expression, with cos
as the name of the callable, with two arguments. You can then use something like the function signature or information you stored up front to see if that call could work at all (len(inspect.signature(math.cos).parameters)
is 1
, so no, that call would fail).– Martijn Pieters♦
Nov 22 '18 at 15:46
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53429859%2fparsing-a-python-expression-without-evaluation%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown