Parsing a Python expression without evaluation












0















I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.



For example:




  1. cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)

  2. 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?










share|improve this question





























    0















    I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.



    For example:




    1. cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)

    2. 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?










    share|improve this question



























      0












      0








      0








      I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.



      For example:




      1. cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)

      2. 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?










      share|improve this question
















      I have an app written in Electron/Typescript and I need to validate that a user input is a valid Python expression.



      For example:




      1. cos(PARAMPOLY.engineeringValue1) + cos(PARAMPOLY.engineeringValue2)

      2. 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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 22 '18 at 11:32









      Martijn Pieters

      715k13825002313




      715k13825002313










      asked Nov 22 '18 at 11:22









      Julieng31Julieng31

      133




      133
























          1 Answer
          1






          active

          oldest

          votes


















          1














          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.






          share|improve this answer


























          • 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 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











          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
          });


          }
          });














          draft saved

          draft discarded


















          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









          1














          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.






          share|improve this answer


























          • 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 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
















          1














          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.






          share|improve this answer


























          • 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 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














          1












          1








          1







          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.






          share|improve this answer















          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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 22 '18 at 11:56

























          answered Nov 22 '18 at 11:24









          Martijn PietersMartijn 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 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



















          • 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 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

















          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




















          draft saved

          draft discarded




















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          MongoDB - Not Authorized To Execute Command

          How to fix TextFormField cause rebuild widget in Flutter

          in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith