{ "info": { "author": "Jakob Stemberger", "author_email": "yaccob@gmx.net", "bugtrack_url": null, "classifiers": [ "Programming Language :: Python :: 2.7" ], "description": "Temptation\n==========\n\nTemptation is a simple and straightforward template engine with an\nextensible grammar.\n\nObjectives\n==========\n\nRegular-expression-based\n------------------------\n\nSubstitution in *temptation* templates is based on regular expressions.\n\nApart from the obvious limitations regarding nested\nsubstitution-expressions (they may be supported to a certain extent)\nthis comes with two advantages:\n\n- Extensibility\n- Efficient regular-expression scanning rather than complex parsing.\n\nSemantic expression substitution\n--------------------------------\n\nRather than always expecting key-value pairs as input *temptation*\nprovides the ability to apply different substitution algorithms on\ndifferent template-expressions.\n\nExtensibility\n-------------\n\nThe regular-expression based grammar can easily be extended or\ncustomized by adding custom matchers.\n\nMVC-based templating\n--------------------\n\nTemplate languages are a way to separate the view (presentation) from\nthe data model.\n\nMany (if not most) template languages support control structures like\nconditions or loops. So their templates combine presentation with\ncontrol.\n\n*temptation* intentionally doesn\u2019t.\n\nThis comes with limitations and with advantages. An obvious limitation\nis that with using *temptation* on its own you can\u2019t process data in a\nnon-linear way. There is only one path from the beginning to the end of\nthe template.\n\nAdvantages are:\n\n- The linear approach keeps templates simple and very well readable.\n- Templates are easy to test.\n- *temptation* templates can easily be be used by external controllers\n that care about more complex transformation-related issues like\n conditional processing or iteration.\n\n *ynot* is a transformator making use of the *temptation* grammar and\n this reference-implementation. See `ynot overview on\n github `__.\n\nLimited support for nested template expressions\n-----------------------------------------------\n\nThis is not implemented yet because I didn\u2019t find a reasonable use-case.\nBut it could be added quite easily if it turns out that it makes sense.\n\nSetup\n=====\n\n.. code:: bash\n\n $ pip install temptation\n\nBy installing *temptation* via ``pip`` you automatically get the command\nline interface of *temptation* installed as well.\n\nCommand-Line-Interface (CLI)\n============================\n\nThe purpose of the command line interface is to support processing\ndata-files (``yaml`` or ``json``) against a single template-file.\n\nTo get help on the (currently quite limited) command-line options just\nenter\n\n``temtation -h``\n\nand you\u2019ll see an output like this:\n\n::\n\n Usage: scripts/temptation [OPTION] -t template datafile...\n\n Resolve template for datafiles. Datafiles can be yaml or json\n\n Options:\n --version show program version number and exit\n -h, --help show this help message and exit\n -t TEMPLATEFILENAME, --template=TEMPLATEFILENAME\n Template to be resoved\n\nIn the current version if you use multiple data-files as input they need\nto be in ``yaml`` format and every file must begin with a\ndocument-separator (``---``).\n\nThis limitation may be removed in future versions so that it will also\nbe possible to process multiple \u2018json\u2019 data-files which is currently not\npossible because json doesn\u2019t support multiple documents.\n\nCommand-line Expample\n---------------------\n\nLet\u2019s say we have this text file \u2026\n\n``temlate.txt``:\n\n::\n\n ${greeting} ${name}!\n\n\u2026 and the following data-files:\n\n``data1.yaml``:\n\n.. code:: yaml\n\n ---\n greeting: Hello\n name: world\n\n``data2.yaml``:\n\n.. code:: yaml\n\n ---\n greeting: Good morning\n name: Donald Duck\n\nNow let\u2019s see how *temptation* applies the template to the data-files:\n\n::\n\n $ temptation -t template.text data*.yaml\n Hello world!\n Good morning Donald Duck!\n\nQuite simple, right?\n\nImports\n=======\n\nThe following samples assume that you have imported the ``Template``\nclass like this:\n\n.. code:: python\n\n >>> from temptation import Template\n\nSamples\n=======\n\nJust static text\n----------------\n\nAny text that\u2019s not a *temptation* expression is left unchanged.\n\n.. code:: python\n\n >>> Template(\"Hello world\").resolve()\n u'Hello world'\n\nThere are some pre-defined *temptation* expressions:\n\n- ``${key}``: Map resolution\n- ``@{jsonpath}``: Jsonpath resolution for single match\n- ``@*{jsonpath}``: Jsonpath resolution for multiple match\n- ``!{python expression}``: Python evaluation expression\n\nIf you need to use a literal that matches those expressions you need to\nescape it with a backslash ``\\`` like this:\n\n``\\${whatever}``\n\nIn the expanded template the backslash will be removed but the\nexpression won\u2019t be evaluated.\n\nLiteral baskslashes can be escaped by a backslash as well. So ``\\\\`` in\nthe template will be presented as ``\\`` in the output. You will see\nsamples for this further down.\n\nLet\u2019s now see samples for the pre-defined *temptation* expressions and\nhow they are expanded.\n\nMap resolution: ``${key}``\n--------------------------\n\nOne of the pre-defined *temptation* expressions is a simple key-value\nsubstitution.\n\nThe expression\u2019s value is interpreted as a key that will be substituted\nby the corresponding value of the input data.\n\n.. code:: python\n\n >>> Template(\"${greeting} ${name}\").resolve({\"greeting\": \"Hello\", \"name\": \"world\"})\n u'Hello world'\n\nEscaping tags: ``\\${key}``\n--------------------------\n\nAny pre-defined (or custom) *temptation* expression can be escaped by\npreceding it with a backslash. A backslash itself can be escaped by\nanother backslash.\n\n.. code:: python\n\n >>> Template(r\"Hello \\${name}\").resolve({\"name\": \"world\"})\n u'Hello ${name}'\n\n >>> Template(r\"Hello \\\\${name}\").resolve({\"name\": \"world\"})\n u'Hello \\\\world'\n\nJsonpath resolution for single match: ``@{jsonpath-espression}``\n----------------------------------------------------------------\n\nThe jsonpath expansion is based on the\n`jsonpath-ng `__\nimplementation, so the syntax is predetermined by this implementation.\nPlease read the linked documentation for details.\n\nA jsonpath result always returns an array of matches. This array may\ncontain 0..n items. To represent a result that matches multiple items\n*temptation* is enclosing the matches in brackets:\n``[item1, item2, ...]``.\n\nIn a template you\u2019re often interested in a single match and don\u2019t want\nthis to be enclosed in brackets. That\u2019s why *temptation* supports the\n*single match* resolution. It will omit the enclosing brackets if there\nis a single match. In case of multiple matches it will log a warning and\nenclose the result in brackets.\n\n.. code:: python\n\n >>> context = {\"items\": [{\"item\": \"first item\"}, {\"item\": \"second item\"}]}\n >>> Template(\"Hello @{$.items[0].item} and @{$.items[1].item}\").resolve(context)\n u'Hello first item and second item'\n\n >>> Template(u\"Hello @{$..item}\").resolve(context)\n u\"Hello ['first item', 'second item']\"\n\nJsonpath resolution for multiple matches: ``@*{jsonpath expression}``\n---------------------------------------------------------------------\n\nWhenever you don\u2019t expect a single match but want to consistently\npresent the result as a list, you can use this *temptation* expression.\n\n.. code:: python\n\n >>> context = {\"items\": [{\"item\": \"first item\"}, {\"item\": \"second item\"}]}\n >>> Template(\"Hello @*{$.items[0].item} and @*{$.items[1].item}\").resolve(context)\n u\"Hello ['first item'] and ['second item']\"\n\n >>> Template(u\"Hello @*{$..item}\").resolve(context)\n u\"Hello ['first item', 'second item']\"\n\nEvaluation resolution: ``!{python expression}``\n-----------------------------------------------\n\nThe python-evaluation resolution allows to expand a *temptation*\nexpression to the result of any python expression.\n\nCurrently the pre-defined evaluation expression is limited to the use of\nmodules that are imported in the ``template.default_resolvers`` module.\nIt\u2019s planned to provide a more flexible solution for importing\nadditional modules to be accessible from evaluation expressions.\n\n.. code:: python\n\n >>> Template(u\"Hello !{7 + 5}\").resolve()\n u'Hello 12'\n\n >>> context = {\"values\": [1, 3, 5, 7]}\n >>> Template(u\"Hello !{context['values'][2] + context['values'][3]}\").resolve(context)\n u'Hello 12'\n\n >>> template = \"\"\"${greeting} ${name}\n ... This is a very personal letter. To emphasize how well I know you\n ... I add best regards to your !{len(context['children'])} children !{\", \".join([child for child in context[\"children\"]])}.\n ... \"\"\"\n >>> context = [{\"name\": \"Mr. Template\", \"greeting\": \"Hello\", \"children\": [\"Jeff\", \"Henriette\", \"Mark\"]}, {\"name\": \"Mrs. Temptation\", \"greeting\": \"Dear\", \"children\": []}]\n >>> for item in context:\n ... Template(template).resolve(item)\n u'Hello Mr. Template\\nThis is a very personal letter. To emphasize how well I know you\\nI add best regards to your 3 children Jeff, Henriette, Mark.\\n'\n u'Dear Mrs. Temptation\\nThis is a very personal letter. To emphasize how well I know you\\nI add best regards to your 0 children .\\n'\n\nAdding your own matchers\n========================\n\nYou can extend *temptation*\\ \u2019s capabilities by implementing your own\nmatchers.\n\nTo do so you must first import the ``Resolvers`` class:\n\nImport Matcher\n--------------\n\n.. code:: python\n\n >>> from temptation import Matcher\n\nCustom matcher sample\n---------------------\n\n.. code:: python\n\n >>> def resolve_foo(expression, match, context):\n ... return \"foo-{0}\".format(expression)\n\n >>> foomatcher = Matcher(\"foomatcher\", tag=r\"\\$foo\", samples=[\"$foo{}\"], processor=resolve_foo)\n >>> barmatcher = Matcher(\"barmatcher\", tag=r\"\\$bar\", samples=[\"$bar{}\"], processor=lambda expression, match, context: \"{0}-bar\".format(expression))\n\n >>> template = \"Hello $foo{something} and $bar{something_else}\"\n >>> Template(template).add_matcher(foomatcher).add_matcher(barmatcher).resolve()\n u'Hello foo-something and something_else-bar'\n\nResolvers are validated against samples\n---------------------------------------\n\nIt is also ensured that samples don\u2019t match with other matchers. This is\nan attempt to help avoiding ambiguities (but obviously doesn\u2019t guarantee\nthat there is no intersection between regular expressions of different\nmatchers).\n\n.. code:: python\n\n >>> foomatcher = Matcher(\"foomatcher\", tag=r\"\\$x\", samples=[\"$x{whatever}\"])\n >>> barmatcher = Matcher(\"barmatcher\", tag=r\"\\$xx*\", samples=[\"$xxx{whatever}\"])\n\n >>> template = Template(\"\").add_matcher(foomatcher)\n >>> template.add_matcher(barmatcher)\n Traceback (most recent call last):\n ...\n Exception: sample '$x{whatever}' for matcher 'foomatcher' also matches matcher 'barmatcher'\n\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "https://github.com/yaccob/temptation/archive/0.1.1.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/yaccob/temptation", "keywords": "temptation,template-engine,template,yaml,json,transform,jsonpath,json-path", "license": "Apache 2.0", "maintainer": "", "maintainer_email": "", "name": "temptation", "package_url": "https://pypi.org/project/temptation/", "platform": "", "project_url": "https://pypi.org/project/temptation/", "project_urls": { "Download": "https://github.com/yaccob/temptation/archive/0.1.1.tar.gz", "Homepage": "https://github.com/yaccob/temptation" }, "release_url": "https://pypi.org/project/temptation/0.1.1/", "requires_dist": [ "PyYaml", "jsonpath-ng" ], "requires_python": "", "summary": "Temptation is a simple and straightforward template engine supporting semantic substitution expressions.", "version": "0.1.1" }, "last_serial": 3597320, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "fae652bdfd1a6bdba89af4a4ba6114f7", "sha256": "c6051c03f7b3878e97dc26bffda4e3b49feb8e99c6409454575f8d351197dd83" }, "downloads": -1, "filename": "temptation-0.1.0-py2-none-any.whl", "has_sig": false, "md5_digest": "fae652bdfd1a6bdba89af4a4ba6114f7", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 13150, "upload_time": "2018-02-17T06:44:53", "url": "https://files.pythonhosted.org/packages/d4/55/a55f9410e833e4e6a6a067aec60780f416f037b20d6677cf6e67289ff393/temptation-0.1.0-py2-none-any.whl" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "a285ca8c72d8a7ac32be65977a43bf2c", "sha256": "7cdadc243bf83f2a0231dd4be76f1ec78440858fd63203c8060320663a391cad" }, "downloads": -1, "filename": "temptation-0.1.1-py2-none-any.whl", "has_sig": false, "md5_digest": "a285ca8c72d8a7ac32be65977a43bf2c", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 13267, "upload_time": "2018-02-19T22:18:27", "url": "https://files.pythonhosted.org/packages/d3/77/e7efb197a33845034e1bc9a3a623b1c4a404081060a7a00f0440c174b90d/temptation-0.1.1-py2-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a285ca8c72d8a7ac32be65977a43bf2c", "sha256": "7cdadc243bf83f2a0231dd4be76f1ec78440858fd63203c8060320663a391cad" }, "downloads": -1, "filename": "temptation-0.1.1-py2-none-any.whl", "has_sig": false, "md5_digest": "a285ca8c72d8a7ac32be65977a43bf2c", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 13267, "upload_time": "2018-02-19T22:18:27", "url": "https://files.pythonhosted.org/packages/d3/77/e7efb197a33845034e1bc9a3a623b1c4a404081060a7a00f0440c174b90d/temptation-0.1.1-py2-none-any.whl" } ] }