.. _creating_paste_templates: ======================== Creating Paste templates ======================== Introduction ============ `Python Paste `_ is an extremely powerful package that isn't just about WSGI middleware. The related document :ref:`entry_points_and_plugins` demonstrates how to use entry_points to create simple plugins. This document describes how to write just such a plugin for use Paste's project template creation facility and how to add a command to Paste's ``paster`` script. The example task is to create a template for an imaginary content management system. The template is going to produce a project directory structure for a Python package, so we need to be able to specify a package name. Creating The Directory Structure and Templates ============================================== The directory structure for the new project needs to look like this: .. code-block:: text - default_project - +package+ - __init__.py - static - layout - region - renderer - service - layout - __init__.py - region - __init__.py - renderer - __init__.py - setup.py_tmpl - setup.cfg_tmpl - development.ini_tmpl - README.txt_tmpl - ez_setup.py Of course, the actual project's directory structure might look very different. In fact the ``paster create`` command can even be used to generate directory structures which *aren't* project templates --- although this wasn't what it was designed for. When the ``paster create`` command is run, any directories with ``+package+`` in their name will have that portion of the name replaced by a simplified package name and likewise any directories with ``+egg+`` in their name will have that portion replaced by the name of the egg directory, although we don't make use of that feature in this example. All of the files with ``_tmpl`` at the end of their filenames are treated as templates and will have the variables they contain replaced automatically. All other files will remain unchanged. .. note:: The small templating language used with ``paster create`` in files ending in ``_tmpl`` is described in detail in the `Paste util module documentation `_ When specifying a package name it can include capitalisation and ``_`` characters but it should be borne in mind that the actual name of the package will be the *lowercase* package name with the ``_`` characters removed. If the package name contains an ``_``, the egg name will contain a ``_`` character so occasionally the ``+egg+`` name is different to the ``+package+`` name. To avoid difficulty always recommend to users that they stick with package names that contain no ``_`` characters so that the names remain unique when made lowercase. Implementing the Code ===================== Now that the directory structure has been defined, the next step is to implement the commands that will convert this to a ready-to-run project. The template creation commands are implemented by a class derived from ``paste.script.templates.Template``. This is how our example appears: .. code-block:: python from paste.script.templates import Template, var vars = [ var('version', 'Version (like 0.1)'), var('description', 'One-line description of the package'), var('long_description', 'Multi-line description (in reST)'), var('keywords', 'Space-separated keywords/tags'), var('author', 'Author name'), var('author_email', 'Author email'), var('url', 'URL of homepage'), var('license_name', 'License name'), var('zip_safe', 'True/False: if the package can be distributed as a .zip file', default=False), ] class ArtProjectTemplate(Template): _template_dir = 'templates/default_project' summary = 'Art project template' vars = vars The ``vars`` arguments can all be set at run time and will be available to be used as (in this instance) Cheetah template variables in the files which end ``_tmpl``. For example the ``setup.py_tmpl`` file for the ``default_project`` might look like this: .. code-block:: html+mako from setuptools import setup, find_packages version = ${repr(version)|"0.0"} setup(name=${repr(project)}, version=version, description="${description|nothing}", long_description="""\ ${long_description|nothing}""", classifiers=[], keywords=${repr(keywords)|empty}, author=${repr(author)|empty}, author_email=${repr(author_email)|empty}, url=${repr(url)|empty}, license=${repr(license_name)|empty}, packages=find_packages(exclude=['ez_setup']), include_package_data=True, zip_safe=${repr(bool(zip_safe))|False}, install_requires=[ # Extra requirements go here # ], entry_points=""" [paste.app_factory] main=${package}:make_app """, ) .. note: The list of available classifier strings can be obtained from: ``http://www.python.org/pypi?%3Aaction=list_classifiers`` Note how the variables specified in ``vars`` earlier are used to generate the actual ``setup.py`` file. In order to use the new templates they must be hooked up to the ``paster create`` command by means of an entry point. In the ``setup.py`` file of the project (in which created the project template is going to be stored) we need to add the following: .. code-block:: python entry_points=""" [paste.paster_create_template] art_project=art.entry.template:ArtProjectTemplate """, We also need to add ``PasteScript>=1.3`` to the ``install_requires`` line. .. code-block:: python install_requires=["PasteScript>=1.3"], We just need to install the entry points now by running: .. code-block:: bash python setup.py develop We should now be able to see a list of available templates with this command: .. code-block:: bash $ paster create --list-templates .. note:: Windows users will need to add their Python scripts directory to their path or enter the full version of the command, similar to this: .. code-block:: bash C:\Python24\Scripts\paster.exe create --list-templates You should see the following: .. code-block:: text Available templates: art_project: Art project template basic_package: A basic setuptools-enabled package There may be other projects too. Troubleshooting =============== If the Art entries don't show up, check whether it is possible to import the ``template.py`` file because any errors are simply ignored by the paster create command rather than output as a warning. If the code is correct, the issue might be that the entry points data hasn't been updated. Examine the Python ``site-packages`` directory and delete the ``Art.egg-link`` files, any ``Art*.egg`` files or directories and remove any entries for art from ``easy_install.pth`` (replacing ``Art`` with the name chosen for the project of course). Then re-run ``python setup.py develop`` to install the correct information. If problems are still evident, then running the following code will print out a list of all entry points. It might help track the problem down: .. code-block:: python import pkg_resources for x in pkg_resources.iter_group_name(None, None): print x Using the Template =================== Now that the entry point is working, a new project can be created: .. code-block:: bash $ paster create --template=art TestProject Paster will ask lots of questions based on the variables set up in ``vars`` earlier. Pressing ``return`` will cause the default to be used. The final result is a nice project template ready for people to start coding with. Implementing Pylons Templates ============================= If the development context is subject to a frequent need to create lots of Pylons projects, each with a slightly different setup from the standard Pylons defaults then it is probably desirable to create a customised Pylons template to use when generating projects. This can be done in exactly the way described in this document. First, set up a new Python package, perhaps called something like ``CustomPylons`` (obviously, don't use the Pylons name because Pylons itself is already using it). Then check out the Pylons source code and copy the `pylons/templates/default_project `_ directory into the new project as a starting point. The next stage is to add the custom ``vars`` and ``Template`` class and set up the entry points in the ``CustomPylons`` ``setup.py`` file. After those tasks have been completed, it is then possible to create customised templates (ultimately based on the Pylons one) by using the ``CustomPylons`` package.