{ "info": { "author": "Jonathan Ferretti", "author_email": "jon@jonathanferretti.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4" ], "description": "Sourcerer\r\n=========\r\n\r\n![image](https://img.shields.io/pypi/v/sourcerer.svg)\r\n\r\nProgramatically generate PEP8 python source code\r\n\r\n### Running examples\r\n\r\n```bash\r\nshark@tack ~/sourcerer/examples $ python swagger_to_flask.py ../sample_data/uber.yaml\r\nshark@tack ~/sourcerer/examples $ python call_example.py\r\n```\r\n\r\n### Generate code from code\r\n\r\nLet\u2019s start with the absolute basics\r\n\r\n```python\r\nfrom sourcerer import Document, Statement\r\n\r\n# The most important class in Sourcerer is the statement. Just about everything is a statement.\r\n# Statements hold source code, and have a child scope. They can hold other statements.\r\n# Even a document is just a special kind of Statement.\r\n# A Document job is to hold statements and then output its contents.\r\ndoc = Document()\r\n\r\n# Now we make a generic statement to assign 1 to x\r\ns = Statement(\"x = 1\")\r\n\r\n# Add it to the document.\r\n# add_child() is a member function of Statement. It will append to a Statements child scope.\r\ndoc.add_child(s)\r\n\r\n# Now output the current document\r\n# output() without an output_file_name will output to standard out.\r\n\r\ndoc.output()\r\n```\r\n\r\n**Output**:\r\n\r\n```python\r\nx = 1\r\n```\r\n\r\nLet\u2019s use some of the purpose built tools in Sourcerer to make this easier to generate.\r\n\r\n```python\r\nfrom sourcerer import Document, Name\r\n\r\ndoc = Document()\r\n\r\n# Names are variable/function/class/etc... names\r\n# We'll use a good name\r\ngood_name = Name(\"descriptive_name\")\r\n\r\n# and a bad name\r\nbad_name = Name(\"1@*plz_help\")\r\n\r\n# Add both the children at once\r\n\r\ndoc.add_children([good_name, bad_name])\r\n\r\ndoc.output()\r\n```\r\n\r\n**Output**:\r\n\r\n```python\r\ndescriptive_name\r\nplz_help\r\n```\r\n\r\nNotice the bad name has been transformed into a valid python name, this behavior can be turned off by setting validate=False\r\n\r\nLet\u2019s get back to that naive assignment we first made. We can improve it using Name and Assignment. We\u2019ll also use Num just for good practice.\r\n\r\n```python\r\nfrom sourcerer import Document, Name, Assignment, Num\r\n\r\ndoc = Document()\r\n\r\n# We'll wrap this up in one line because it's not that long.\r\n# Num can take a string, int, long, float, etc...\r\na = Assignment(Name(\"x\"), Num(\"1\"))\r\n\r\ndoc.add_child(a)\r\n\r\ndoc.output()\r\n```\r\n\r\n**Output**:\r\n\r\n```python\r\nx = 1\r\n```\r\n\r\nNow that we\u2019re warmed up, let\u2019s do something more interesting. How about some functions?\r\n\r\n```python\r\nfrom sourcerer import Document, FunctionDef, Return, Str, Num, Name, Assignment, DecoratorDef, Call\r\n\r\ndoc = Document()\r\n\r\n# A function that returns 0\r\nfunc_a = FunctionDef(name=Name(\"get_a_zero\"))\r\nret_a = Return(Num(\"0\"))\r\n\r\nfunc_a.add_child(ret_a)\r\ndoc.add_child(func_a)\r\n\r\n# A function that passes. We'll put it in an list for easier consumption later\r\nfunc_b = [FunctionDef(name=Name(\"just_pass\")),\r\n Return(_type=\"pass\")\r\n]\r\n\r\n# Cascade the list of statements\r\ndoc.create_lineage(func_b)\r\n\r\n# A function with args, and a *arg\r\nfunc_c = [FunctionDef(name=Name(\"so_many_args\"), arg_names=[\"a1\", Name(\"a2\")], varargs=\"args\"),\r\n Return(Str(\"Not enough time\"))\r\n]\r\n\r\ndoc.create_lineage(func_c)\r\n\r\n# A function with kwargs, and a **\r\nfunc_d = [FunctionDef(name=Name(\"so_many_kwargs\"), kwarg_pairs={Name(\"a1\"):\"val\"}, keywords=\"kwargs\"),\r\n Return()\r\n]\r\n\r\ndoc.create_lineage(func_d)\r\n\r\n# A function decorated function. Philosophy: If things get complicated, just make them a list.\r\nfunc_e = [DecoratorDef(name=Name(\"fancy\")),\r\n FunctionDef(name=Name(\"pants\")),\r\n Return(Str(\"Hello World!\"))\r\n]\r\n\r\ndoc.create_lineage(func_e)\r\n\r\ndoc.output()\r\n```\r\n\r\n**Output**:\r\n\r\n```python\r\ndef get_a_zero():\r\n return 0\r\n\r\n\r\ndef just_pass():\r\n pass\r\n\r\n\r\ndef so_many_args(a1, a2, *args):\r\n return \"Not enough time\"\r\n\r\n\r\ndef so_many_kwargs(a1=val, **kwargs):\r\n return\r\n\r\n\r\n@fancy()\r\ndef pants():\r\n return \"Hello World!\"\r\n```\r\n\r\nHere is an example that generates an extremely rough flask Blueprint from a swagger () yml doc\r\n\r\n``` python\r\nfrom yaml import load\r\nfrom sourcerer import Document, FunctionDef, DecoratorDef, Return, Str, Name, Call, Assignment, Attribute\r\nfrom sys import argv\r\n\r\n# Create a document to put our code in\r\ndoc = Document()\r\n\r\n# Open our yml file and read it in\r\napi = load(open(argv[1], 'r').read())\r\n\r\nblueprint = Name(api['basePath'])\r\n\r\nbp = Assignment(blueprint,\r\n Call(name=\"Blueprint\",\r\n arg_names=[Str(blueprint), '__name__'],\r\n kwarg_pairs={'template_folder': Str('templates')}))\r\n\r\ndoc.add_child(bp)\r\n\r\nfor path in api['paths']:\r\n route = [DecoratorDef(name=Attribute(caller_list=[blueprint], name=Name('route')),\r\n arg_names=[Str(path)]), # A decorator: @routename(\"mypath\")\r\n FunctionDef(name=Name(path)), # A function: def routename():\r\n Return()] # A return statement: return\r\n\r\n doc.create_lineage(route) # Cascade these objects into the main document scope\r\n # ...\r\n # @routename(\"mypath\")\r\n # def routename():\r\n # return\r\n # ...\r\n\r\ndoc.output() # Send output to standard out (output to file optional)\r\n\r\n####################\r\n# Without inline comments:\r\n##\r\n\r\nfrom yaml import load\r\nfrom sourcerer import Document, FunctionDef, DecoratorDef, Return, Str, Name, Call, Assignment, Attribute\r\nfrom sys import argv\r\n\r\ndoc = Document()\r\n\r\napi = load(open(argv[1], 'r').read())\r\n\r\nblueprint = Name(api['basePath'])\r\n\r\nbp = Assignment(blueprint,\r\n Call(name=\"Blueprint\",\r\n arg_names=[Str(blueprint), '__name__'],\r\n kwarg_pairs={'template_folder': Str('templates')}))\r\ndoc.add_child(bp)\r\n\r\nfor path in api['paths']:\r\n route = [DecoratorDef(name=Attribute(caller_list=[blueprint], name=Name('route')),\r\n arg_names=[Str(path)]),\r\n FunctionDef(name=Name(path)),\r\n Return()]\r\n doc.create_lineage(route)\r\n\r\ndoc.output()\r\n```\r\n\r\n**Output:**\r\n\r\n```python\r\nv1 = Blueprint(\"v1\", __name__, template_folder=\"templates\")\r\n\r\n\r\n@v1.route(\"/products\")\r\ndef products():\r\n return\r\n\r\n\r\n@v1.route(\"/estimates/price\")\r\ndef estimatesprice():\r\n return\r\n\r\n\r\n@v1.route(\"/history\")\r\ndef history():\r\n return\r\n\r\n\r\n@v1.route(\"/me\")\r\ndef me():\r\n return\r\n\r\n\r\n@v1.route(\"/estimates/time\")\r\ndef estimatestime():\r\n return\r\n```\r\n\r\n## Technologies\r\n\r\n* YAPF formatted output to produce pep8 compliant code\r\n\r\n\r\n## Upcoming Features\r\n\r\n### Generate code from Spellbooks\r\n\r\nSource code can also be generated by ingesting and parsing a config document (ex. yaml, json, xml\u2026), known as a Spellbook. Spellbooks can be parsed into source code be defining a schema, called a Syntax Map.\r\n\r\n#### Example Spellbook (YAML):\r\n\r\n```YAML\r\nfunctions:\r\n func1:\r\n args: ['thing1', 'thing2']\r\n kwargs: {\"key1\": \"val1\"}\r\n varargs: false\r\n keywords: false\r\n ret:\r\n value:\r\n true\r\n```\r\n\r\n#### Example Syntax Map to parse this Spellbook:\r\n\r\n\r\n```python\r\n# Without inline comments\r\n{\"functions\": {'type': FunctionDef,\r\n 'key': 'name',\r\n 'value_map': {'args': 'arg_names',\r\n 'kwargs': 'kwarg_pairs',\r\n 'varargs': 'varargs',\r\n 'keywords': 'keywords'},\r\n 'children':{'ret':'return'}},\r\n \"return\": {'type': Return,\r\n 'value_map': {'value':'val'}}\r\n}\r\n\r\n# With inline comments\r\n{\"functions\": {'type': FunctionDef, # Each top level entry under functions is a FunctionDef\r\n 'key': 'name', # The functions key (func1) is the value to the name argument for the FunctionDef\r\n 'value_map': {'args': 'arg_names', # Define what args are called in the markups schema\r\n 'kwargs': 'kwarg_pairs',\r\n 'varargs': 'varargs',\r\n 'keywords': 'keywords'},\r\n 'children':{'ret':'return'}}, # When top-level objects are seen their values will be\r\n # pared as well, building a new object from the mapping\r\n # they specify and then appended to this object\r\n \"return\": {'type': Return,\r\n 'value_map': {'value':'val'}}\r\n}\r\n```\r\n\r\n#### Building a Syntax Map for a Spellbook:\r\n\r\nYour Syntax Maps top-level keys define what your Spellbook top-level sections are containing. The values of your Syntax Map top-level keys are dictionaries defining how to handle the contents of your Spellbook sections.\r\n\r\nIn the given example, the only top-level Spellbook section is \u2018functions\u2019. In the Syntax Map, the \u2018functions\u2019 key\u2019s value says several things:\r\n\r\n1. For each child node encountered, create a new FunctionObj (defined by \u2018type\u2019)\r\n2. The key defining each child node is the \u2018name\u2019 argument for the FunctionObj\r\n3. The sub-keys of the child node are properties of the FunctionObj. The values of those sub-keys are can be one of two things:\r\n - If the value is in the value map, it is an argument to FunctionObj\r\n - If the value is in the children map, it should be placed into the scope of the FunctionObj. The value will be looked up in the Syntax Map top-level to see if it can be be instantiated into a new sourcerer object.\r\n\r\n#### The Syntax Map schema should consist of:\r\n\r\n- type (required): The class name to instantiate\r\n- key (required): what the key for the node represents\r\n- value\\_map (required): map properties to arguments to the class\r\n- children: values that should be instantiated and placed into the current nodes child scope\r\n\r\n#### Using a Syntax Map and Spellbook to generate your source:\r\n\r\nBased on the example Syntax Map and the Example YAML, the following will write the resulting source code to stardard out\r\n\r\n```python\r\nfrom sourcerer import YAMLProcessor\r\n\r\ngen = YAMLProcessor()\r\ngen.load('sample_data/sample.yml')\r\ngen.output()\r\n```\r\n\r\n\r\n\r\n\r\nHistory\r\n-------\r\n\r\n0.0.3 (2015-04-15)\r\n---------------------", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/LISTERINE/sourcerer", "keywords": "sourcerer", "license": "Apache2", "maintainer": "", "maintainer_email": "", "name": "sourcerer", "package_url": "https://pypi.org/project/sourcerer/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/sourcerer/", "project_urls": { "Homepage": "https://github.com/LISTERINE/sourcerer" }, "release_url": "https://pypi.org/project/sourcerer/1.0b10/", "requires_dist": null, "requires_python": null, "summary": "Library to programatically genrate python source code", "version": "1.0b10" }, "last_serial": 2820790, "releases": { "1.0b1": [ { "comment_text": "", "digests": { "md5": "9a3822332bbc9c5b9d2ca81f8117d033", "sha256": "9438a6f92f7d31110d91015711fd4adb6564da805f9ca8267e7aaf63ee2305f8" }, "downloads": -1, "filename": "sourcerer-1.0b5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9a3822332bbc9c5b9d2ca81f8117d033", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 17982, "upload_time": "2016-09-06T22:18:39", "url": "https://files.pythonhosted.org/packages/17/61/8936d1f56c45709a70b7bd69e64b21de913368444e0f89ce1fb94b26a0ea/sourcerer-1.0b5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8888f5566af1f9a672c7984f9d0d96fd", "sha256": "64585c23b77850578547e6c21191f37f9d17420910c6229008950f693085677a" }, "downloads": -1, "filename": "sourcerer-1.0b5.tar.gz", "has_sig": false, "md5_digest": "8888f5566af1f9a672c7984f9d0d96fd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25102, "upload_time": "2016-09-06T22:19:07", "url": "https://files.pythonhosted.org/packages/9d/1b/9d3a39778c58672360c817e1d4267c8b2e50f5a9d6cff6ee977bd4a14c7b/sourcerer-1.0b5.tar.gz" } ], "1.0b10": [ { "comment_text": "", "digests": { "md5": "86ab2c9a23389281ea1af417a2f00385", "sha256": "f9b9dceebcc8d10205eb5667a5d8d2a684b8d17cf5bf63e855be8b72c51fbb4d" }, "downloads": -1, "filename": "sourcerer-1.0b10-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "86ab2c9a23389281ea1af417a2f00385", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 17961, "upload_time": "2017-04-21T18:16:03", "url": "https://files.pythonhosted.org/packages/bc/bc/e5321cb83b3d4a365ac09b9f81da8acbc159aa005f390b1539a5458a60ed/sourcerer-1.0b10-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "caaf6840d03c0b4dfcd90bc3e958d738", "sha256": "904bc5d1cbd3051e76ac92df0614272cb31a0fc98243fc71681598b4c64078ed" }, "downloads": -1, "filename": "sourcerer-1.0b10.tar.gz", "has_sig": false, "md5_digest": "caaf6840d03c0b4dfcd90bc3e958d738", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26556, "upload_time": "2017-04-21T18:16:15", "url": "https://files.pythonhosted.org/packages/29/4f/3d3b84464e48b80e912fd62d1e5681fe8dfc06ad2ccfe4602539835f3d9d/sourcerer-1.0b10.tar.gz" } ], "1.0b7": [ { "comment_text": "", "digests": { "md5": "8a2bd065f6354562266536638c268ae5", "sha256": "181dd582b5e7e568d4d8ad8d8d467106dfa918faf3748084a303ae41a980c838" }, "downloads": -1, "filename": "sourcerer-1.0b7-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8a2bd065f6354562266536638c268ae5", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 18054, "upload_time": "2016-09-21T19:28:11", "url": "https://files.pythonhosted.org/packages/70/c4/f803ad59c3ed86ccdf7d1c7b0a7ddfecca7cd0b54895c674dabbac94498d/sourcerer-1.0b7-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a8da234f6d304ce3742715b1dc131371", "sha256": "eddc8a7079e78a759fac463127be3c7b5210470056f1da33face971d52afc408" }, "downloads": -1, "filename": "sourcerer-1.0b7.tar.gz", "has_sig": false, "md5_digest": "a8da234f6d304ce3742715b1dc131371", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25656, "upload_time": "2016-09-21T19:28:27", "url": "https://files.pythonhosted.org/packages/79/eb/260056e6505af701c74918e4800181f11c032c82e14239d66d774d1ab318/sourcerer-1.0b7.tar.gz" } ], "1.0b8": [ { "comment_text": "", "digests": { "md5": "f7cd7f931d448129dc9bc6bb2b87f76c", "sha256": "98704775a49376de110341d89dde5adc6570037042c9ddb7b4aa606bd69e3ff2" }, "downloads": -1, "filename": "sourcerer-1.0b8_fixed-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f7cd7f931d448129dc9bc6bb2b87f76c", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 16945, "upload_time": "2017-04-20T15:38:32", "url": "https://files.pythonhosted.org/packages/cf/15/26acce6ae1b346db7b821e98d00c98b426a4a1fca513fc90d030804619a2/sourcerer-1.0b8_fixed-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "af7ea9c69fdeec513d10e00e340caf7e", "sha256": "7ef5ff2cb0d19ff3da13c12529cdcbabc0bca43c0d6e0291b7d0e92668a83f02" }, "downloads": -1, "filename": "sourcerer-1.0b8_fixed.tar.gz", "has_sig": false, "md5_digest": "af7ea9c69fdeec513d10e00e340caf7e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25347, "upload_time": "2017-04-20T15:38:53", "url": "https://files.pythonhosted.org/packages/a2/f3/90d5e2923995c8e3980f0c64da9f09b2a82be7d3509463c71383ccdf568f/sourcerer-1.0b8_fixed.tar.gz" } ], "1.0b9": [ { "comment_text": "", "digests": { "md5": "79a0d9dc3669103ab613efdcaac06213", "sha256": "70d2c4361a7b7249b019240f6d4d0e99fed5979ce4ed4d6b9942561e0bf56120" }, "downloads": -1, "filename": "sourcerer-1.0b9_fixed-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "79a0d9dc3669103ab613efdcaac06213", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 17758, "upload_time": "2017-04-20T15:41:07", "url": "https://files.pythonhosted.org/packages/03/d4/99ddad3c9256ba3ec062d3219b3f9362c631bd37289491f2c1bd0be9fcd5/sourcerer-1.0b9_fixed-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0e180791f486681851a045435cd84435", "sha256": "dd68ea39e7b5da985721c1d659c766e77c6689f68c4875ad22cacbffdf304609" }, "downloads": -1, "filename": "sourcerer-1.0b9_fixed.tar.gz", "has_sig": false, "md5_digest": "0e180791f486681851a045435cd84435", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26318, "upload_time": "2017-04-20T15:41:28", "url": "https://files.pythonhosted.org/packages/0f/4c/7687440960e35cb953ad83fdb447dfc7252962b14190315de4709d554a97/sourcerer-1.0b9_fixed.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "86ab2c9a23389281ea1af417a2f00385", "sha256": "f9b9dceebcc8d10205eb5667a5d8d2a684b8d17cf5bf63e855be8b72c51fbb4d" }, "downloads": -1, "filename": "sourcerer-1.0b10-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "86ab2c9a23389281ea1af417a2f00385", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 17961, "upload_time": "2017-04-21T18:16:03", "url": "https://files.pythonhosted.org/packages/bc/bc/e5321cb83b3d4a365ac09b9f81da8acbc159aa005f390b1539a5458a60ed/sourcerer-1.0b10-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "caaf6840d03c0b4dfcd90bc3e958d738", "sha256": "904bc5d1cbd3051e76ac92df0614272cb31a0fc98243fc71681598b4c64078ed" }, "downloads": -1, "filename": "sourcerer-1.0b10.tar.gz", "has_sig": false, "md5_digest": "caaf6840d03c0b4dfcd90bc3e958d738", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26556, "upload_time": "2017-04-21T18:16:15", "url": "https://files.pythonhosted.org/packages/29/4f/3d3b84464e48b80e912fd62d1e5681fe8dfc06ad2ccfe4602539835f3d9d/sourcerer-1.0b10.tar.gz" } ] }