{ "info": { "author": "Mike Pagel", "author_email": "mike@mpagel.de", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development", "Topic :: Software Development :: Libraries" ], "description": "pymultigen - Multi-file frontend for single-file code generators\n================================================================\n\n.. image:: https://travis-ci.org/moltob/pymultigen.svg?branch=master\n :target: https://travis-ci.org/moltob/pymultigen\n\n.. image:: https://badge.fury.io/py/pymultigen.svg\n :target: https://badge.fury.io/py/pymultigen\n\n.. image:: https://coveralls.io/repos/github/moltob/pymultigen/badge.svg?branch=master\n :target: https://coveralls.io/github/moltob/pymultigen?branch=master\n\n.. image:: https://img.shields.io/badge/License-MIT-yellow.svg\n :target: https://opensource.org/licenses/MIT\n\n.. image:: https://img.shields.io/badge/contributions-welcome-brightgreen.svg\n\nThis small library adds multi-file management on top of one or more existing single-file code\ngenerators.\n\n.. contents:: :depth: 2\n\nWhy would I need pymultigen?\n----------------------------\n\nCode generators like `Mako `_ or `Jinja `_\nare great and can be used to generate just about any kind of textual output from templates with a\nnice template language. They are very mature and battle-proven. However, most of those generators\nhave their origin in the web application domain. The typical usecase is to dynamically render a\nsingle HTTP response (most of the time an HTML page) from one or more templates. *One* HTML page.\n\nIf you want to use these generators in other scenarious, e.g. to generate code or reports, but not\nto *one* but to *multiple* files in different folders, pymultigen can help. It simply adds an easy\nto configure file and folder management layer on top of one or more existing code generators.\n\nInstallation\n------------\n\npymultigen comes in form or a regular Python distribution and can be installed from Github or PyPI\nwith a simple:\n\n.. code-block:: shell\n\n $ pip install pymultigen\n\nThe library works with any version of Python >= 3.3.\n\nUsage\n-----\n\nThe overall concept of pymultigen is simple:\n\n* A ``Generator`` class controls the overall generation workflow. The most important method it\n implements is ``generate(model, folder)``. This is the single method called by *users* of the\n created multi-file generator.\n* The ``Generator`` has a static list of ``Task`` objects. Each ``Task`` describes a step executed\n at generation time.\n* One ``Task`` is responsible for translating a specific set of elements in the input model to one\n output file in the output folder. The input set can be chosen arbitrarily, often this is the list\n of a certain model element type (e.g. instance of a ``Table`` class in a relational model from\n which SQL statements should be generated).\n\nUsing pymultigen means therefore to create one ``Generator`` class for your new generator and one or\nmore ``Task`` classes, one for each type of output artifact. If you are using a template-based code\ngenerator under the hood, you usually will have one ``Task`` per output template.\n\nBefore you start, you need to check, whether pymultigen already has an integration for your\nsingle-file code generator built-in. Currently, the following integrations are available:\n\n* Jinja2\n\nIf you want to use another generation engine, you can easily add support yourself (the current\nJinja2 integration consists of less than 20 lines of code). If you've done so, please consider\ngiving back to the community. Your contribution is welcome! Please see below for instructions how to\nextend pymultigen with a new integration.\n\nUsing the Jinja2 integration\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYou may want to check out `pyecoregen `_, a code generator\nfrom `pyecore `_-based models to Python classes. It is a\nconcrete Jinja2-based code generator built with pymultigen.\n\nJinja2 is a template-based text generator. Writing a file-generator with Jinja therefore involves\nwriting a template for each type of output file. In pymultigen you will then implement a ``Task``\nclass per output file type, i.e. per Jinja template.\n\nThe general form of such a ``Task`` looks like this:\n\n.. code-block:: python\n\n class MyTask(multigen.jinja.JinjaTask):\n\n # Name of template file used by this task.\n template_name = 'name-of-template.tpl'\n\n def filtered_elements(self, model):\n \"\"\"Return iterator based over elements in model that are passed to template.\"\"\"\n\n def relative_path_for_element(self, element):\n \"\"\"Returns relative file path receiving the generator output for given element.\"\"\"\n\nThe workflow engine will initially call ``filtered_elements``. This method is expected to return an\ninterator over model elements for which a single file needs to be generated. *Model* is meant here\nin an abstract way: It may be an instance of a formal metamodel, but it could be any Python object,\nlike a dictionaries or lists. The contained elements being iterated over are accessible from within\na template as ``element``.\n\nOnce Jinja has produced a textual result it must be written to file. This is where\n``relative_path_for_element`` comes into play. For a given element that was filtered from the model\nbefore, it returns the corresponding filepath. Note that this path is interpreted to be relative to\nthe top-level output path of the overall generation (see below). If subfolders are mentioned here,\nthey are created on demand.\n\nOne of more tasks classes like this must then be registered with a top-level generator. Just like\nbefore, a new ``Generator`` class is derived from the appropriate base class:\n\n.. code-block:: python\n\n class MyGenerator(multigen.jinja.JinjaGenerator):\n\n # List of task objects to be processed by this generator.\n tasks = [\n MyTask(),\n ]\n\n # Root path where Jinja templates are found.\n templates_path = os.path.join(\n os.path.abspath(os.path.dirname(__file__)),\n 'templates'\n )\n\n def create_environment(self, **kwargs):\n \"\"\"Create Jinja2 environment.\"\"\"\n environment = super().create_environment(**kwargs)\n # Do any customization of environment here, or delete this method.\n return environment\n\nThe base class implementation of {{create_environment}} passes {{templates_path}} to the created\nenvironment object to allow Jinja to find the template names specified in a ``Tasks``'s\n``template_name``. By overriding this method you can extend the environment, e.g. to add filters and\ntests. Of course you can also completely replace the implementation, e.g. to change the way how\ntemplates how looked up.\n\nThe example above simply instantiates the new ``Task`` class. Here you can optionally pass a\nformatter function, that is then applied to the output of Jinja. Formatters are simple string\ntransformations, some of which are built-in in the ``formatters.py`` module. If you actually are\nwriting a Python code generator you may want to clean up the generated code according to pep8,\nsimply pass the appropriate formatter during task instantiation:\n\n.. code-block:: python\n\n class MyGeneratorWithPep8(multigen.jinja.JinjaGenerator):\n\n # List of task objects to be processed by this generator.\n tasks = [\n MyTask(formatter=multigen.formatter.format_autopep8),\n ]\n\n ...\n\nExtending pymultigen\n--------------------\n\nContributions welcome!\n\nBelow the most typical extension scenarios are described. Note that in theory pymultigen can be used\nwith *any* code that produces text, not just a templating engine. Take a look at the class hierarchy\nin ``generator.py`` to get more insights or drop me a note if this is something you plan to do.\n\nFormatters\n~~~~~~~~~~\n\nWriting a new formatter is trivial: Simply create a function that transforms an input string into\nthe nicely formatted output string. If you want to get your formatter added to pymultigen, please\nmake sure that:\n\n* New dependencies (like autopep8 in the existing pep8 formatter) are only imported in the\n formatting function. This way user only pay for what they use.\n* Please write unittests and add your possible dependencies to the ``tests_require`` argument in\n ``setup.py``.\n\nThere is not much more to it.\n\nTemplating engine\n~~~~~~~~~~~~~~~~~\n\nFor a live sample, look at the Jinja2 integration in ``jinja.py``. For your templating engine ``X``,\nyou probably have to write small ``Generator`` and ``Task`` base classes like this:\n\n.. code-block:: python\n\n class XGenerator(TemplateGenerator):\n\n def __init__(self, environment=None, **kwargs):\n super().__init__(**kwargs)\n # Add any attributes to the generator that are static with respect to a full generation\n # run (over all files), like a Jinja2 environment.\n ...\n\n\n class XTask(TemplateFileTask):\n\n def generate_file(self, element, filepath):\n \"\"\"Actual generation of element.\"\"\"\n\nEach element that is iterated over from the input model is eventually passed to the tasks's\n``generate_file`` method. Here simply call you template engine to produce the output string. You\nalso want to apply the optional formatter before writing the string to disk. This is how the Jinja\ntask does it:\n\n.. code-block:: python\n\n def generate_file(self, element, filepath):\n template = self.environment.get_template(self.template_name)\n context = self.create_template_context(element=element)\n\n with open(filepath, 'wt') as file:\n file.write(self.formatter(template.render(**context)))\n\nThe implementation shows two more things:\n\n* The template to be used is retrieved from an ``environment`` that is specific to the template\n engine. Such an environment is usually passed down from the ``Generator`` class to the ``Task``.\n* ``create_template_context`` is a function implemented in base class ``TemplateTask``. It\n implements the very common case of dictionaries being used as template context objects. Of course\n you can override this if it doesn't match your engine.\n\n\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/moltob/pymultigen", "keywords": "code generator jinja multi-file", "license": "MIT License", "maintainer": "", "maintainer_email": "", "name": "pymultigen", "package_url": "https://pypi.org/project/pymultigen/", "platform": "", "project_url": "https://pypi.org/project/pymultigen/", "project_urls": { "Homepage": "https://github.com/moltob/pymultigen" }, "release_url": "https://pypi.org/project/pymultigen/0.2.0/", "requires_dist": null, "requires_python": "", "summary": "Multi-file frontend for single-file code generators.", "version": "0.2.0" }, "last_serial": 3125458, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "77557db616188327e9ca141bd3925a98", "sha256": "b1c37f85db7a8ebf76b9ebfa60f85b6c50d5962607bbee7d7eaeaa263e55c1a9" }, "downloads": -1, "filename": "pymultigen-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "77557db616188327e9ca141bd3925a98", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 5515, "upload_time": "2017-05-23T19:03:03", "url": "https://files.pythonhosted.org/packages/e5/7c/040aad71db88a7c50a0d3d8cef2ba279a9271d4d4df05f6acf7fd4edc426/pymultigen-0.0.1-py3-none-any.whl" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "6bbcde513b0123dd9a21477699845652", "sha256": "b38def3ea691682f7f9f1bd118d05e8491ad31a9c403809f2f920bab86426b68" }, "downloads": -1, "filename": "pymultigen-0.0.2.tar.gz", "has_sig": false, "md5_digest": "6bbcde513b0123dd9a21477699845652", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3619, "upload_time": "2017-05-23T19:51:25", "url": "https://files.pythonhosted.org/packages/59/81/7d808ee38e1807ab7666ab9461ffe465897a637f76dd4ec987d71219c476/pymultigen-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "f592cfaf9f10ba00ca917141769c66c9", "sha256": "60bbe3c25bd677a8329ca7ac0c50b1b239218713ea0f98e344250b3e364f94e8" }, "downloads": -1, "filename": "pymultigen-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "f592cfaf9f10ba00ca917141769c66c9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5693, "upload_time": "2017-05-23T20:00:37", "url": "https://files.pythonhosted.org/packages/85/d3/36514277314fb680d8cc718e7d2334afd41ec92c90b5db58be6c4269f418/pymultigen-0.0.3-py3-none-any.whl" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "b1cdaa1f7327cacdf9226296854d1a07", "sha256": "f0a46ae944ec62e07ecb9f2260859cff72e23862d75e3eff7b76af4e9683346f" }, "downloads": -1, "filename": "pymultigen-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "b1cdaa1f7327cacdf9226296854d1a07", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12026, "upload_time": "2017-05-25T15:00:19", "url": "https://files.pythonhosted.org/packages/a3/3b/d16f922b9446298a188867c5dbf60a3bbdd0fc1c53e791ce0b63e8cb86c9/pymultigen-0.1.1-py3-none-any.whl" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "fa330d4747182cf73a21a5ef0669a62d", "sha256": "b84b8d7227354ba7373db3ea04b0ecc4c87fffc3e980be447c0d0b4428b6f492" }, "downloads": -1, "filename": "pymultigen-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "fa330d4747182cf73a21a5ef0669a62d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12255, "upload_time": "2017-08-26T18:48:44", "url": "https://files.pythonhosted.org/packages/23/d5/07571f86a39e8a99e573a1864646d8615614fd10225e0c894c67102123f9/pymultigen-0.2.0-py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "fa330d4747182cf73a21a5ef0669a62d", "sha256": "b84b8d7227354ba7373db3ea04b0ecc4c87fffc3e980be447c0d0b4428b6f492" }, "downloads": -1, "filename": "pymultigen-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "fa330d4747182cf73a21a5ef0669a62d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12255, "upload_time": "2017-08-26T18:48:44", "url": "https://files.pythonhosted.org/packages/23/d5/07571f86a39e8a99e573a1864646d8615614fd10225e0c894c67102123f9/pymultigen-0.2.0-py3-none-any.whl" } ] }