{ "info": { "author": "Marko Mikulicic", "author_email": "mmikulicic@gmail.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Topic :: Software Development :: Code Generators", "Topic :: Software Development :: Compilers", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Pre-processors" ], "description": "MetaContext\n===========\n\nIt's always been possible to write domain specific languages in python, but it's rigid syntax, the lack of smalltalk like \"blocks\"\n(or at least anonymous closures which can contain statements) make it hard, if not impossible, to design slick DSL.\n\nThis library provides a powerful language extension mechanism that tries to follow the python language design principles\nand avoid creating confusing syntax constructs that will break compatibilities with editor extensions such as emacs flymake.\n\nWith MetaContext you can define macros which can manipulate the AST of it's body and inject abitrary code.\n\nExample\n-------\n\nImagine you want to build a pattern matching construct. Without MetaContext you could design the DSL like this::\n\n with pattern_match(msg) as case:\n\n @case(('something', ANY))\n def _(value):\n do_something_with(value)\n\n @case(('error', ANY))\n def _(e):\n handle_error(e)\n\n\nThe `pattern_match` context manager can check if at least one case has been executed and raise a `NoMatch` exception\notherwise.\n\nHowever this DSL has two problems:\n\n 1. It's more verbose than necessary\n 2. It requires the case mangers to be contained in closures which cannot break out of loops, perform (non local) returns,\n yield out of a generator etc.\n\nWith MetaContext you can define the DSL as::\n\n with pattern_match(msg):\n with case(('something', ANY)) as value:\n do_something_with(value)\n with case(('error', ANY)) as e:\n handle_error(e)\n\nThis construct will allow you to interact nicely with generator based coroutines (like twisted inline callbacks)::\n\n with pattern_match(msg):\n with case(('something', ANY)) as value:\n res = yield do_something_with(value)\n do_something_else(res)\n with case(('error', ANY)) as e:\n handle_error(e)\n\nOr perform returns::\n\n with pattern_match(msg):\n with case(('something', ANY)) as value:\n res = do_something_with(value)\n if is_it_the_correct_one(res):\n return\n with case(ANY):\n pass\n\n\nAnother possible use case is retryng a body in case of exceptions::\n\n with retry(IOException):\n do_something()\n do_something_else()\n\nWhich would have been written as::\n\n while True:\n try:\n do_something()\n do_something_else()\n except IOException:\n pass\n else:\n break\n\nHow to create your own meta context mangers\n--------------------------------------------\n\nJust create a `Keyword` subclass::\n\n class retry(Keyword):\n def __init__(self, *excs):\n self.exceptions = excs\n\n def transform(self, translator, body, args, var):\n # ... return a transformed python AST object\n # you will get the `with` body in `body`\n\n\nHow to use your meta context manger\n------------------------------------\n\nIf you want to use your meta context manger, you first have to register\nthe MetaContext import hook::\n\n import metacontext\n metacontext.register_importer_hook()\n\nThen every source file that imports a symbol that resolves to a subclass of `Keyword` will\nbe intercepted by the import hook and it's AST will be given to the meta context mangers\nwhich will usually transform the body of the `with` statement::\n\n from yourpackage.retrymanger import retry\n\n # ...\n\n with retry():\n # ....\n\n\nMacro definition language\n-------------------------\n\nManiuplating the AST directly is a verbose and cumbersome process, especially since\nyou have to care about preserving original line number information for debugging and stack trace purposes.\n\nMetaContext offers a macro definition DSL that you can use to quickly create your own meta context mangers:\n\nThe macro definition DSL itself is built using MetaContext constructs::\n\n class retry(Keyword):\n def __init__(self, *excs):\n self.exceptions = excs\n\n def template(self, translator, body, args, var):\n with quote() as q:\n while True:\n try:\n unquote_stmts(body)\n except IOException:\n pass\n else:\n break\n\n return q\n\nThe MetaContext library will do it's best to preserve the original line number of the unquoted statements\nso that you can seamlessly use your constructs in your sources as if they were native python.\n\nNotes\n-----\n\nCurrently, since the library is in development, the modules which you want to transform with MetaContext have to\ncontain this line as the first line of their source::\n\n #- LANGUAGE compile-time-context-manager -#\n\nThis restriction will be lifted as soon as we make sure we can correctly handle all the import hook rough edges.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mmikulicic/metacontext", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "metacontext", "package_url": "https://pypi.org/project/metacontext/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/metacontext/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/mmikulicic/metacontext" }, "release_url": "https://pypi.org/project/metacontext/0.2.2/", "requires_dist": null, "requires_python": null, "summary": "Metaprogramming with context managers", "version": "0.2.2" }, "last_serial": 794710, "releases": { "0.2": [ { "comment_text": "", "digests": { "md5": "f762d979091fdab066a5f14c6542e6f6", "sha256": "80850f3af71693bc9bfe77a9506265836eaa426b2853f8141c7afd0fa407a02d" }, "downloads": -1, "filename": "metacontext-0.2-py2.7.egg", "has_sig": false, "md5_digest": "f762d979091fdab066a5f14c6542e6f6", "packagetype": "bdist_egg", "python_version": "2.7", "requires_python": null, "size": 21849, "upload_time": "2012-07-21T13:33:07", "url": "https://files.pythonhosted.org/packages/75/1a/fcd63134b61605f1c3aee66d46d315bcb3d41e822c7fbb8c30eaf272df8f/metacontext-0.2-py2.7.egg" }, { "comment_text": "", "digests": { "md5": "3eb62f8bf96e1aaf7df429fae8a9a93d", "sha256": "108067e0887de7c8df6b0943431302b382155ebeb84a2dc0376350ebb3fe3888" }, "downloads": -1, "filename": "metacontext-0.2.tar.gz", "has_sig": false, "md5_digest": "3eb62f8bf96e1aaf7df429fae8a9a93d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9170, "upload_time": "2012-07-21T13:33:13", "url": "https://files.pythonhosted.org/packages/2a/7c/0ac0c3cdb8f60147d35d1ce6f2a246f92c656b04535911b81dfb2bf991a8/metacontext-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "f38ffd26b96b44115a1a6b193b7fa7a8", "sha256": "8fbb856fd157e394a1506962a4ae653baf6bd2e75e2334ade4444bb2e806c60f" }, "downloads": -1, "filename": "metacontext-0.2.1-py2.7.egg", "has_sig": false, "md5_digest": "f38ffd26b96b44115a1a6b193b7fa7a8", "packagetype": "bdist_egg", "python_version": "2.7", "requires_python": null, "size": 21849, "upload_time": "2012-07-21T14:41:09", "url": "https://files.pythonhosted.org/packages/6a/08/a2584e620ad48662455a0de4d311fdbc346cd60b845855203971334b47f6/metacontext-0.2.1-py2.7.egg" }, { "comment_text": "", "digests": { "md5": "d4aee8d2ccded50966a9dc8ff12d65d1", "sha256": "8d6da97c4cfbaa7cb77ea1882b8efcfbc36a9eb8992305a142901932c9d4faaf" }, "downloads": -1, "filename": "metacontext-0.2.1.tar.gz", "has_sig": false, "md5_digest": "d4aee8d2ccded50966a9dc8ff12d65d1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9177, "upload_time": "2012-07-21T14:41:06", "url": "https://files.pythonhosted.org/packages/77/4c/583ce2f2dd9e569136b8420bf97466671125d9f5ba74366186892dcc4012/metacontext-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "0fff5291f9048785cd0168d245f7e577", "sha256": "36331eced6b4ba42da5a8da41765f5a10cdaeb5499f452d4fcf167aef9e4fed0" }, "downloads": -1, "filename": "metacontext-0.2.2-py2.7.egg", "has_sig": false, "md5_digest": "0fff5291f9048785cd0168d245f7e577", "packagetype": "bdist_egg", "python_version": "2.7", "requires_python": null, "size": 22009, "upload_time": "2012-07-21T15:09:07", "url": "https://files.pythonhosted.org/packages/96/f3/eb12132597720fae515c82225b253623012854f12a39aaba371f2b6d3b32/metacontext-0.2.2-py2.7.egg" }, { "comment_text": "", "digests": { "md5": "1c63340a0918c64095ff39ee1cf158e7", "sha256": "7bdd2f507a1e4d304508ef8f8216d132f98606c7b96813f4164d39df3c49d536" }, "downloads": -1, "filename": "metacontext-0.2.2.tar.gz", "has_sig": false, "md5_digest": "1c63340a0918c64095ff39ee1cf158e7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9178, "upload_time": "2012-07-21T15:08:57", "url": "https://files.pythonhosted.org/packages/93/14/ebdf5411c510bbe556fa1d9cc76cb98e8ae222784cde87b91d3e5fc78ca8/metacontext-0.2.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0fff5291f9048785cd0168d245f7e577", "sha256": "36331eced6b4ba42da5a8da41765f5a10cdaeb5499f452d4fcf167aef9e4fed0" }, "downloads": -1, "filename": "metacontext-0.2.2-py2.7.egg", "has_sig": false, "md5_digest": "0fff5291f9048785cd0168d245f7e577", "packagetype": "bdist_egg", "python_version": "2.7", "requires_python": null, "size": 22009, "upload_time": "2012-07-21T15:09:07", "url": "https://files.pythonhosted.org/packages/96/f3/eb12132597720fae515c82225b253623012854f12a39aaba371f2b6d3b32/metacontext-0.2.2-py2.7.egg" }, { "comment_text": "", "digests": { "md5": "1c63340a0918c64095ff39ee1cf158e7", "sha256": "7bdd2f507a1e4d304508ef8f8216d132f98606c7b96813f4164d39df3c49d536" }, "downloads": -1, "filename": "metacontext-0.2.2.tar.gz", "has_sig": false, "md5_digest": "1c63340a0918c64095ff39ee1cf158e7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9178, "upload_time": "2012-07-21T15:08:57", "url": "https://files.pythonhosted.org/packages/93/14/ebdf5411c510bbe556fa1d9cc76cb98e8ae222784cde87b91d3e5fc78ca8/metacontext-0.2.2.tar.gz" } ] }