{"id":8963213,"url":"https://github.com/DataBrewery/expressions","last_synced_at":"2025-08-11T11:33:02.983Z","repository":{"id":9782753,"uuid":"11756323","full_name":"DataBrewery/expressions","owner":"DataBrewery","description":"Simple arithmetic expression parser","archived":false,"fork":false,"pushed_at":"2022-03-24T07:14:53.000Z","size":58,"stargazers_count":37,"open_issues_count":3,"forks_count":14,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-08-22T05:34:09.399Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DataBrewery.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-07-30T04:16:20.000Z","updated_at":"2024-01-06T13:52:25.000Z","dependencies_parsed_at":"2022-09-17T15:51:41.744Z","dependency_job_id":null,"html_url":"https://github.com/DataBrewery/expressions","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataBrewery%2Fexpressions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataBrewery%2Fexpressions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataBrewery%2Fexpressions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DataBrewery%2Fexpressions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DataBrewery","download_url":"https://codeload.github.com/DataBrewery/expressions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229536349,"owners_count":18088556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-05-02T22:51:49.041Z","updated_at":"2024-12-13T11:30:24.340Z","avatar_url":"https://github.com/DataBrewery.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"Expressions\n===========\n\nArithmetic expression parser library.  Embed customized expression evaluation\ninto your application or library. Example uses:\n\n* Safely process an expression entered through a web application,\n  for example some formula to be plotted. The library allows safe translation\n  of such expression without exposing any application's internals\n* precompiler that checks for allowed and denied identifiers in an expression\n* have a common expression language through your application regardless of the\n  backend languages\n* compile arithmetic expression to any other expression tree (semantic), for\n  example [SQLAlchemy](http://docs.sqlalchemy.org/en/rel_0_7/core/expression_api.html) expression objects\n\n\nPart of the [Data Brewery](http://databrewery.org)\n\nInstallation\n------------\n\nInstall using pip:\n\n    pip install expressions\n\nExpressions sources are available at [Github](https://github.com/DataBrewery/expressions)\n\nWorks with Python 2.7 and Python 3.3. Uses [Grako](https://bitbucket.org/apalala/grako).\n\nQuick Start\n-----------\n\n```python\nfrom expressions import Compiler\n\ncompiler = Compiler()\nresult = compiler.compile(\"min(a, b) * 2\")\n```\n\nResult from the default (non-extended) compiler will be abstract semantic\ngraph containing nodes *Literal*, *Variable*, *Function*, *Binary* and *Unary*\noperators. Subclasses of `Compiler` can yield different outputs by\nimplementing just few simple methods which represent semantic graph nodes\n(same as the objects).\n\nExample\n-------\n\nHere is an example compiler that allows only certain variables. The list of\nallowed variables is provided in the compilation context:\n\n```python\n    from expressions import Compiler, ExpressionError\n\n    class AllowingCompiler(Compiler):\n        def compile_literal(self, context, literal):\n            return repr(literal)\n\n        def compile_variable(self, context, variable):\n            if context and variable not in context:\n                raise ExpressionError(\"Variable %s is not allowed\" % variable)\n \n            return variable\n\n        def compile_binary(self, context, operator, op1, op2):\n            return \"(%s %s %s)\" % (op1, operator, op2)\n\n        def compile_function(self, context, function, args):\n            arglist = \", \" % args\n            return \"%s(%s)\" % (function, arglist)\n```\n\nAllow only `a` and `b` variables:\n\n    compiler = AllowingCompiler()\n\n    allowed_variables = [\"a\", \"b\"]\n\nTry to compile and execute the expression:\n\n    result = compiler.compile(\"a + b\", allowed_variables)\n\n    a = 1\n    b = 1\n    print(eval(result))\n\nThis will fail, because only `a` and `b` are allowed, `c` is not:\n\n    result = compiler.compile(\"a + c\", allowed_variables)\n\n\nSee the examples source directory for more examples such as very simplified\nexpression-to-SQLAlchemy compiler.\n\nSyntax\n======\n\nExample expressions:\n\n```sql\n    1 + 1\n    (a + b) ^ 2\n    sum(amount) / count()\n    date.year = 2010 and amount \u003e 10\n```\n\n* Binary arithmetic operators: `+`, `-`, `*`, `/`, `%` (modulo), `^` (power)\n* Binary comparison operators: `\u003c`, `\u003c=`, `=`, `\u003e=`, `\u003e`, `in`, `is`\n* Binary bit-wise operators: `|` (or), `\u0026` (and), `\u003c\u003c` (shift left), `\u003e\u003e` (shift right)\n* Binary logical operators: `and`, `or`\n* Unary operators: `+`, `-`, `~` (bit-wise not)\n\n* Function call: `function_name(arg1, arg2, ...)`\n\n*Variable* and *function* names are either regular identifiers or identifiers\nseparated by `.`. There is no value dereference and the dot `.` is just\nnamespace composition operator for variable names. Example variable names:\n`amount`, `date.year`, `product.name`.\n\nThe suggested meaning of the operators is based mostly on the\n[PostgreSQL operators](http://www.postgresql.org/docs/9.0/static/functions.html)\n\nWriting a compiler\n==================\n\nTo write a custom compiler subclass a `Compiler` class and implement all of\nsome of the following methods:\n\n* *compile_function(context, reference, args)* – compile a function call. The\n  `reference` is the same kind of object as passed to the\n  *compile_variable()*, `args` is list of function arguments. Default\n  implementation returns an object with attributes `reference` and `args`\n* *compile_binary(context, operator, left, right)* – compile a binary\n  operator `operator` with two operands `left` and `right`. Default\n  implementation returns an object with attributes `operator`, `left` and `right`\n* *compile_unary(context, operator, operand)* – compile a unary `operator` with\n  a single `operand`. Default implementation returns an object with attributes\n  `operator` and `operand`.\n* *compile_variable(context, variable)* – compile a variable reference\n  `variable` which is an object with properties `name` and `reference`. `name`\n  is the full variable name (joined with `.`), `reference` is a list of\n  variable name components. Return value should be either evaluated variable\n  as a constant or some other useful variable reference.\n* *compile_literal(context, literal)* – compile an integer, float or a string\n  object `literal`. Default implementation just passes the argument. You\n  rarely need to override this method.\n* *finalize(context, object)* – return the final compilation result.\n\n\nWhen compiling function arguments or operator operands you should check\nwhether they are literals or instances of a `Variable`. For example:\n\n```python\n    def compile_function(context, reference, args):\n        # Assume that the context is a dictionary with variables and functions\n\n        values = []\n        for arg in args:\n            if isinstance(arg, Variable):\n                value = context[arg.name]\n            else:\n                value = arg\n            values.append(value)\n\n        function = context[reference.name]\n\n        return function(*args)\n```\n\nExample compiler: Identifier Preprocessor\n\nThe following compiler is included in the library:\n\n```python\n    class IdentifierPreprocessor(Compiler):\n        def __init__(self):\n            super(IdentifierPreprocessor, self).__init__()\n\n            self.variables = set()\n            self.functions = set()\n\n        def compile_variable(self, context, variable):\n            self.variables.add(variable)\n            return variable\n\n        def compile_function(self, context, function, args):\n            self.functions.add(function)\n            return function\n```\n\nUse:\n\n```python\n\u003e\u003e\u003e preproc = IdentifierPreprocessor()\n\u003e\u003e\u003e preproc.compile(\"a + b\")\n\u003e\u003e\u003e preproc.compile(\"sum(amount)\")\n```\n\nThe `preproc.variables` will contain *Variable* objects for `a`, `b` and\n`amount`, the `proproc.functions` will contain one *Variable* object `sum`:\n\n```python\n\u003e\u003e\u003e print(preproc.variables)\n{Variable(amount), Variable(b), Variable(a)}\n\u003e\u003e\u003e print(preproc.functions)\n{Variable(sum)}\n```\n\nNote that the *Variable* object represents any named object reference – both\nvariables and functions.\n\nClasses\n=======\n\nThe following classes are provided by the library:\n\n* *Compiler* – core compiler class that generates default structure,\n  `compile_*` methods can be overriden to generate custom results\n* *IdentifierPreprocessor* – a *Compiler* subclass with two attributes\n  `variables` and `functions` containing list of `Variable` objects collected\n  from the compiled expression. Can be used for validation or preparation of\n  variables\n\n\nWhat Expressions is *not*\n-------------------------\n\n* This is *not* a Python expression compiler. The grammar is based on very\n  basic SQL grammar and few other simple SQL grammar features might be added in\n  the future. There is no SQL compatibility guaranteed though. It is not meant\n  to be a rich expression, but a small subset of quite common expressions to\n  allow easy translation to other languages or object structures. Main use is\n  arithmetic expression support for a modular application with different\n  backends\n\n* It is *not* an expression of an object-oriented language – it does not have\n  access to object attributes – the '.' dot operator is just an attribute name\n  concatenation. The compiler receives full object reference as a string and\n  as a list of reference components.\n\n\nLicense\n-------\n\nExpressions framework is licensed under the MIT license.\n\nFor more information see the LICENSE file.\n\n\nAuthor\n------\n\nStefan Urbanek, stefan.urbanek@gmail.com, Twitter: @Stiivi\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDataBrewery%2Fexpressions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDataBrewery%2Fexpressions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDataBrewery%2Fexpressions/lists"}