Templates

pymetacode heavily relies on templates (and uses Jinja as template engine) for performing most of its tasks. The major areas where templates are used are identical to those use cases you encounter in the daily use of the package:

  • creating a new module

  • adding a class to a module

  • adding a function to a module

In each case, not only code stubs are created, but stubs for unit tests as well. Below, the templates for these most important aspects are documented in the form currently contained in the pymetacode package otseöf. Although these templates contain some markup for the Jinja template engine, they should still be rather readable.

Templates for modules

When adding a module to your package, three files are created in their respective (sub)directories:

  • The module in the package source directory (same name as the package)

  • The corresponding test module in the tests directory

  • The reStructuredText file for the API documentation in the docs/api directory

For details, see the pymetacode.coding.ModuleCreator class documentation. Note that the module does not yet have any further content.

The module template

"""
{{ module.name }} module of the {{ package.name }} package.
"""
{% if options.logging %}
import logging


logger = logging.getLogger(__name__)
{% endif %}

The test_module template

import unittest

from {{ package.name }} import {{ module.name }}

The module API documentation template

{{ package.name }}.{{ module.name }} module
======={{ header_extension }}

.. automodule:: {{ package.name }}.{{ module.name }}
    :members:
    :inherited-members:
    :undoc-members:
    :show-inheritance:

Templates for classes

When adding a class to a module, two files are modified and the respective code appended:

  • The class implementation to the module in the package source directory

  • The TestClass implementation in the corresponding test module in the tests directory

As the class template comes with a docstring, and the module API documentation is set such that each class will automatically be documented there (see above), building the documentation will automatically add the class documentation without further ado.

Classes (and corresponding test classes) are always appended to the end of the respective module.

For details, see the pymetacode.coding.ClassCreator class documentation. Note that the module does not yet have any further content.

The class template



class {{ class.name }}:
    """
    One sentence (on one line) describing the class.

    More description comes here...


    Attributes
    ----------
    attr : :class:`None`
        Short description

    Raises
    ------
    exception
        Short description when and why raised


    Examples
    --------
    It is always nice to give some examples how to use the class. Best to do
    that with code examples:

    .. code-block::

        obj = {{ class.name }}()
        ...

    {% if package.version != '0.1' %}
    .. versionadded:: {{ package.version }}
    {% endif %}

    """

    pass

The test_class template



class Test{{ class.name }}(unittest.TestCase):
    def setUp(self):
        self.{{ class.instance }} = {{ module.name }}.{{ class.name }}()

    def test_instantiate_class(self):
        pass

Templates for functions

When adding a function to a module, two files are modified and the respective code appended:

  • The function implementation to the module in the package source directory

  • The TestClass implementation in the corresponding test module in the tests directory

As the function template comes with a docstring, and the module API documentation is set such that each function will automatically be documented there (see above), building the documentation will automatically add the function documentation without further ado.

Functions (and corresponding test classes) are always appended to the end of the respective module.

For details, see the pymetacode.coding.FunctionCreator class documentation. Note that the module does not yet have any further content.

The function template



def {{ function.name }}():
    """
    One sentence (on one line) describing the function.

    More description comes here...

    Parameters
    ----------
    param : :class:`None`
        Short description

    Returns
    -------
    param : :class:`None`
        Short description


    {% if package.version != '0.1' %}
    .. versionadded:: {{ package.version }}
    {% endif %}

    """
    pass

The test_function template



class Test{{ function.name_camelcase }}(unittest.TestCase):
    def test_{{ function.name }}(self):
        pass

Customising templates

While you as a user are free to customise these templates according to your needs, regarding the pattern search and replace options you are pretty much stuck with what is implemented in the respective classes and passed as “context” to the Jinja template engine. As a rule of thumb, the entire configuration is passed as context to each template.