{ "info": { "author": "Timoth Watts", "author_email": "tim@readevalprint.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": ".. image:: logo.jpeg\n :target: logo.jpeg\n\nSnek Lang \n========================\n\n.. image:: https://travis-ci.org/readevalprint/sneklang.svg?branch=master\n :target: https://travis-ci.org/readevalprint/sneklang\n :alt: Build Status\n\n.. image:: https://coveralls.io/repos/github/readevalprint/sneklang/badge.svg?branch=master&1\n :target: https://coveralls.io/r/readevalprint/sneklang?branch=master\n :alt: Coverage Status\n\n.. image:: https://badge.fury.io/py/sneklang.svg\n :target: https://badge.fury.io/py/sneklang\n :alt: PyPI Version\n\nBasic Usage\n-----------\n\n``snek_eval`` returns a list of all the expressions in the provided code.\nGenerally you care about the last one. \n\n\nTo get very simple evaluating:\n\n.. code-block:: python\n\n from sneklang import snek_eval\n\n snek_eval(\"'Hi!' + ' world!'\")\n\nreturns ``[Hi! World!]``.\n\nExpressions can be as complex and convoluted as you want:\n\n.. code-block:: python\n\n snek_eval(\"21 + 19 / 7 + (8 % 3) ** 9\")\n\nreturns ``[535.714285714]``.\n\nYou can add your own functions in as well.\n\n.. code-block:: python\n\n snek_eval(\"square(11)\", scope={\"square\": lambda x: x*x})\n\nreturns ``[121]``.\n\n\nTry some dictionary or set comprehension.\n\n.. code-block:: python\n\n >>> from sneklang import snek_eval\n >>> snek_eval(\"{a:b for a,b in [('a', 1), ('b',2)]}\")\n [{'a': 1, 'b': 2}]\n\n >>> snek_eval(\"{a*a for a in [1,2,3]}\")\n [{1, 4, 9}]\n\n\nYou can even define functions within the sand box at evaluation time.\n\n.. code-block:: python\n\n >>> from sneklang import snek_eval\n >>> snek_eval('''\n ... def my_function(x): \n ... return x + 3\n ... \n ... my_function(5)\n ... \n ... ''')\n [None, 8]\n\n\nAdvanced Usage\n--------------\n\n\n\n\nSome times you will want to run a dynamically defined sandboxed funtion in your app.\n\n.. code-block:: python\n\n >>> user_scope = {}\n >>> out = snek_eval('''\n ... def my_function(x=2): \n ... return x ** 3\n ... ''', scope=user_scope)\n >>> user_func = user_scope['my_function']\n >>> user_func()\n 8\n\n\nOr maybe create a decorator\n\n.. code-block:: python\n\n >>> user_scope = {}\n >>> out = snek_eval('''\n ... def foo_decorator(func): \n ... def inner(s):\n ... return \"this is foo\", func(s)\n ... return inner\n ...\n ... @foo_decorator \n ... def bar(s):\n ... return \"this is bar\", s\n ... \n ... output = bar(\"BAZ\")\n ... ''', scope=user_scope)\n >>> user_scope['output']\n ('this is foo', ('this is bar', 'BAZ'))\n\n\n\nYou can also delete variables and catch exception\n\n.. code-block:: python\n\n >>> user_scope = {}\n >>> out = snek_eval('''\n ... a = [1, 2, 3, 4, 5, 6, 7]\n ... del a[3:5]\n ... try:\n ... a[10]\n ... except Exception as e:\n ... b = \"We got an error: \" + str(e)\n ... ''', scope=user_scope)\n >>> user_scope['a']\n [1, 2, 3, 6, 7]\n >>> user_scope['b']\n 'We got an error: list index out of range at line: 5, column:4'\n\n\n.. code-block:: python\n\n >>> user_scope = {}\n >>> out = snek_eval('''\n ... try:\n ... raise Exception(\"this is my last resort\")\n ... except Exception as e:\n ... exc = e\n ... ''', scope=user_scope)\n >>> user_scope['exc']\n SnekRuntimeError('this is my last resort at line: 3, column:3')\n\n.. code-block:: python\n\n >>> user_scope = {}\n >>> out = snek_eval('''\n ... try:\n ... try:\n ... 1/0\n ... except Exception as e:\n ... raise Exception(\"oh no\") from e\n ... except Exception as e:\n ... exc = e\n ... ''', scope=user_scope)\n >>> user_scope['exc']\n SnekRuntimeError('oh no at line: 6, column:8')\n\n\nAnd sometimes, users write crappy code... `MAX_CALL_DEPTH` is configurable, of course.\nHere you can see some extreamly ineffecient code to multiply a number by 2\n\n.. code-block:: python\n\n >>> from sneklang import InvalidExpression, CallTooDeep\n >>> user_scope = {}\n >>> out = snek_eval('''\n ... def multiply_by_2(x): \n ... return (2 + multiply_by_2(x-1)) if x > 0 else 0\n ... ''', scope=user_scope)\n\n >>> multiply_by_2 = user_scope['multiply_by_2']\n >>> multiply_by_2(5)\n 10\n >>> try:\n ... multiply_by_2(50)\n ... except CallTooDeep as e:\n ... print('oh no! {}'.format(e))\n oh no! Sorry, stack is to large. The MAX_CALL_DEPTH is 32. at line: 3, column:15\n\n\n\n >>> try:\n ... snek_eval(\"int('foo is not a number')\")\n ... except ValueError as e:\n ... print('oh no! {}'.format(e))\n oh no! invalid literal for int() with base 10: 'foo is not a number'\n\n\n\nLimited Power\n~~~~~~~~~~~~~\n\nAlso note, the ``**`` operator has been locked down by default to have a\nmaximum input value of ``4000000``, which makes it somewhat harder to make\nexpressions which go on for ever. You can change this limit by changing the\n``sneklang.POWER_MAX`` module level value to whatever is an appropriate value\nfor you (and the hardware that you're running on) or if you want to completely\nremove all limitations, you can set the ``s.operators[ast.Pow] = operator.pow``\nor make your own function.\n\nOn my computer, ``9**9**5`` evaluates almost instantly, but ``9**9**6`` takes\nover 30 seconds. Since ``9**7`` is ``4782969``, and so over the ``POWER_MAX``\nlimit, it throws a ``NumberTooHigh`` exception for you. (Otherwise it would go\non for hours, or until the computer runs out of memory)\n\nStrings (and other Iterables) Safety\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThere are also limits on string length (100000 characters,\n``MAX_STRING_LENGTH``). This can be changed if you wish.\n\nRelated to this, if you try to create a silly long string/bytes/list, by doing\n``'i want to break free'.split() * 9999999999`` for instance, it will block you.\n\nIf Expressions\n--------------\n\nYou can use python style ``if x then y else z`` type expressions:\n\n.. code-block:: python\n\n >>> snek_eval(\"'equal' if x == y else 'not equal'\", scope={\"x\": 1, \"y\": 2})\n ['not equal']\n\nwhich, of course, can be nested:\n\n.. code-block:: python\n\n >>> snek_eval(\"'a' if 1 == 2 else 'b' if 2 == 3 else 'c'\")\n ['c']\n\n\nFunctions\n---------\n\nYou can define functions which you'd like the expresssions to have access to:\n\n.. code-block:: python\n\n >>> snek_eval(\"double(21)\", scope={\"double\": lambda x:x*2})\n [42]\n\nYou can define \"real\" functions to pass in rather than lambdas, of course too,\nand even re-name them so that expressions can be shorter\n\n.. code-block:: python\n\n >>> def square(x):\n ... return x ** 2\n >>> snek_eval(\"s(10) + square(2)\", scope={\"s\": square, \"square\":square})\n [104]\n\nIf you don't provide your own ``scope`` dict, then the the following defaults\nare provided in the ``DEFAULT_SCOPE`` dict:\n\n+----------------+--------------------------------------------------+\n| ``int(x)`` | Convert ``x`` to an ``int``. |\n+----------------+--------------------------------------------------+\n| ``float(x)`` | Convert ``x`` to a ``float``. |\n+----------------+--------------------------------------------------+\n| ``str(x)`` | Convert ``x`` to a ``str`` (``unicode`` in py2) |\n+----------------+--------------------------------------------------+\n\n.. code-block:: python\n\n >>> snek_eval(\"a + b\", scope={\"a\": 11, \"b\": 100})\n [111]\n\n >>> snek_eval(\"a + b\", scope={\"a\": \"Hi \", \"b\": \"world!\"})\n ['Hi world!']\n\nYou can also hand the scope of variable enames over to a function, if you prefer:\n\n\n.. code-block:: python\n\n >>> class case_insensitive_scope(dict):\n ... def __getitem__(self, key):\n ... return super().__getitem__(key.lower())\n ... def __setitem__(self, key, value):\n ... return super().__setitem__(key.lower(), value)\n\n >>> snek_eval('''\n ... FOOBAR\n ... foobar\n ... FooBar''', scope=case_insensitive_scope({'foobar': 42}))\n [42, 42, 42]\n\n.. code-block:: python\n\n >>> import sneklang\n >>> import random\n >>> my_scope = {}\n >>> my_scope.update(\n ... square=(lambda x:x*x),\n ... randint=(lambda top: int(random.random() * top))\n ... )\n >>> snek_eval('square(randint(int(\"1\")))', scope=my_scope)\n [0]\n\n\n\nOther...\n--------\n\n\nObject attributes that start with ``_`` or ``func_`` are disallowed by default.\nIf you really need that (BE CAREFUL!), then modify the module global\n``sneklang.DISALLOW_PREFIXES``.\n\nA few builtin functions are listed in ``sneklang.DISALLOW_FUNCTIONS``. ``type``, ``open``, etc.\nIf you need to give access to this kind of functionality to your expressions, then be very\ncareful. You'd be better wrapping the functions in your own safe wrappers.\n\nThe initial idea came from J.F. Sebastian on Stack Overflow\n( http://stackoverflow.com/a/9558001/1973500 ) with modifications and many improvements,\nsee the head of the main file for contributors list.\n\nThen danthedeckie on Github with simpleeval(https://github.com/danthedeckie/simpleeval)\n\nI've filled it out a bit more to allow safe funtion definitions, and better scope management.\n\nPlease read the ``test_snek.py`` file for other potential gotchas or\ndetails. I'm very happy to accept pull requests, suggestions, or other issues.\nEnjoy!\n\nDeveloping\n----------\n\nRun tests::\n\n $ make test\n\nOr to set the tests running on every file change:\n\n $ make autotest\n\n(requires ``entr``)", "description_content_type": "text/x-rst", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/readevalprint/sneklang", "keywords": "sandbox,parse,ast", "license": "", "maintainer": "", "maintainer_email": "", "name": "sneklang", "package_url": "https://pypi.org/project/sneklang/", "platform": "", "project_url": "https://pypi.org/project/sneklang/", "project_urls": { "Homepage": "https://github.com/readevalprint/sneklang" }, "release_url": "https://pypi.org/project/sneklang/0.4.5/", "requires_dist": null, "requires_python": "", "summary": "Experimental minimal subset of Python for safe evaluation", "version": "0.4.5" }, "last_serial": 5868859, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "515b22db8a1607404990ccbf5fa1322b", "sha256": "3c840d3cff6f4b236b2a565c8038fe6ecc0cd209d466d3717244e49ecc359c8a" }, "downloads": -1, "filename": "sneklang-0.1.0.tar.gz", "has_sig": false, "md5_digest": "515b22db8a1607404990ccbf5fa1322b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11524, "upload_time": "2019-02-19T17:43:17", "url": "https://files.pythonhosted.org/packages/fa/b1/957446d0206f58fd3904f4e2e17e42a3643552a9b4d37ef4f50a8115c2f6/sneklang-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "8cc2a8e87d7953a94592e8a6cd1fbd39", "sha256": "5b081e705b1ab6225780f8f52741e0c9174b3845f3fbf0c10607112cc17dd74b" }, "downloads": -1, "filename": "sneklang-0.2.0.tar.gz", "has_sig": false, "md5_digest": "8cc2a8e87d7953a94592e8a6cd1fbd39", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13157, "upload_time": "2019-02-22T13:18:07", "url": "https://files.pythonhosted.org/packages/96/92/22fd95b6918bc86767527974f4f3f2667a61a49690472fa67b502dde5e26/sneklang-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "45344712e40e6c857a0218025389da11", "sha256": "3439a6339b153531acd435809da0eb355c1744890f825abc7e2e5b4e9c47a0bf" }, "downloads": -1, "filename": "sneklang-0.3.0.tar.gz", "has_sig": false, "md5_digest": "45344712e40e6c857a0218025389da11", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15287, "upload_time": "2019-05-08T13:44:35", "url": "https://files.pythonhosted.org/packages/03/9a/7f5318b39ac3d6a9ec0b29e7cfaf65aa88ebc506af853b5f4e19d12be76b/sneklang-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "c199d49fcd1e133362ecbe2c87f07fb8", "sha256": "cbcd856e13f20945b3095fb1f22cf1cab138db65f1b628303c4a1eae01d558aa" }, "downloads": -1, "filename": "sneklang-0.3.1.tar.gz", "has_sig": false, "md5_digest": "c199d49fcd1e133362ecbe2c87f07fb8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15629, "upload_time": "2019-07-11T09:34:28", "url": "https://files.pythonhosted.org/packages/80/1d/b31d5b0fb40d3a6540faba0dc15ff565a2bd559e3d84fe5d9208564b945b/sneklang-0.3.1.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "3c59d8be11bc6b61902558a3d3022dab", "sha256": "ac88b1e32b12de754c72ab48c682a91d7cb1fedec461049780875950b3e9fd94" }, "downloads": -1, "filename": "sneklang-0.4.0.tar.gz", "has_sig": false, "md5_digest": "3c59d8be11bc6b61902558a3d3022dab", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15849, "upload_time": "2019-08-19T11:11:27", "url": "https://files.pythonhosted.org/packages/51/6e/0cb91d26114ea5b08f1114140addcdafb5823f676e6dce7da33b3adb8deb/sneklang-0.4.0.tar.gz" } ], "0.4.3": [ { "comment_text": "", "digests": { "md5": "e2e57128c734e3a84807eca2a96a283e", "sha256": "cee2d21efe273b6a33a3266e0d40210f33beb8c7623c94d4d14e0914e1c325ac" }, "downloads": -1, "filename": "sneklang-0.4.3.tar.gz", "has_sig": false, "md5_digest": "e2e57128c734e3a84807eca2a96a283e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17810, "upload_time": "2019-09-10T11:55:32", "url": "https://files.pythonhosted.org/packages/71/77/3c46b0433ad7c4f2994ecf24a4a1181f873d3944af9b29ed34624c134e05/sneklang-0.4.3.tar.gz" } ], "0.4.5": [ { "comment_text": "", "digests": { "md5": "88ca5021c24d1fb041ff0ba2c6cb736d", "sha256": "941939e38d65c5983a9da938b366690909fc0b24859e4778d261c8c9aa254ef1" }, "downloads": -1, "filename": "sneklang-0.4.5.tar.gz", "has_sig": false, "md5_digest": "88ca5021c24d1fb041ff0ba2c6cb736d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17838, "upload_time": "2019-09-22T11:55:15", "url": "https://files.pythonhosted.org/packages/f1/23/da8755fabaa24619ce8e677b16a4abf0ad34a2bb56c77fc94deaebd797e5/sneklang-0.4.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "88ca5021c24d1fb041ff0ba2c6cb736d", "sha256": "941939e38d65c5983a9da938b366690909fc0b24859e4778d261c8c9aa254ef1" }, "downloads": -1, "filename": "sneklang-0.4.5.tar.gz", "has_sig": false, "md5_digest": "88ca5021c24d1fb041ff0ba2c6cb736d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17838, "upload_time": "2019-09-22T11:55:15", "url": "https://files.pythonhosted.org/packages/f1/23/da8755fabaa24619ce8e677b16a4abf0ad34a2bb56c77fc94deaebd797e5/sneklang-0.4.5.tar.gz" } ] }