Source code for pyscaffold.extensions.cookiecutter

# -*- coding: utf-8 -*-
"""
Extension that integrates cookiecutter templates into PyScaffold.
"""
from __future__ import absolute_import

import argparse

from ..api.helpers import register, logger
from ..api import Extension
from ..contrib.six import raise_from


[docs]class Cookiecutter(Extension): """Additionally apply a Cookiecutter template""" mutually_exclusive = True
[docs] def augment_cli(self, parser): """Add an option to parser that enables the Cookiecutter extension Args: parser (argparse.ArgumentParser): CLI parser object """ parser.add_argument( self.flag, dest=self.name, action=create_cookiecutter_parser(self), metavar="TEMPLATE", help="additionally apply a Cookiecutter template. " "Note that not all templates are suitable for PyScaffold. " "Please refer to the docs for more information.")
[docs] def activate(self, actions): """Register before_create hooks to generate project using Cookiecutter Args: actions (list): list of actions to perform Returns: list: updated list of actions """ # `get_default_options` uses passed options to compute derived ones, # so it is better to prepend actions that modify options. actions = register(actions, enforce_cookiecutter_options, before='get_default_options') # `apply_update_rules` uses CWD information, # so it is better to prepend actions that modify it. actions = register(actions, create_cookiecutter, before='apply_update_rules') return actions
[docs]def create_cookiecutter_parser(obj_ref): """Create a Cookiecutter parser. Args: obj_ref (Extension): object reference to the actual extension Returns: NamespaceParser: parser for namespace cli argument """ class CookiecutterParser(argparse.Action): """Consumes the values provided, but also append the extension function to the extensions list. """ def __call__(self, parser, namespace, values, option_string=None): # First ensure the extension function is stored inside the # 'extensions' attribute: extensions = getattr(namespace, 'extensions', []) extensions.append(obj_ref) setattr(namespace, 'extensions', extensions) # Now the extra parameters can be stored setattr(namespace, self.dest, values) # save the cookiecutter cli argument for later obj_ref.args = values return CookiecutterParser
[docs]def enforce_cookiecutter_options(struct, opts): """Make sure options reflect the cookiecutter usage. Args: struct (dict): project representation as (possibly) nested :obj:`dict`. opts (dict): given options, see :obj:`create_project` for an extensive list. Returns: struct, opts: updated project representation and options """ opts['force'] = True return struct, opts
[docs]def create_cookiecutter(struct, opts): """Create a cookie cutter template Args: struct (dict): project representation as (possibly) nested :obj:`dict`. opts (dict): given options, see :obj:`create_project` for an extensive list. Returns: struct, opts: updated project representation and options """ try: from cookiecutter.main import cookiecutter except Exception as e: raise_from(NotInstalled, e) extra_context = dict(full_name=opts['author'], author=opts['author'], email=opts['email'], project_name=opts['project'], package_name=opts['package'], repo_name=opts['package'], project_short_description=opts['description'], release_date=opts['release_date'], version='unknown', # will be replaced later year=opts['year']) if 'cookiecutter' not in opts: raise MissingTemplate logger.report('run', 'cookiecutter ' + opts['cookiecutter']) if not opts.get('pretend'): cookiecutter(opts['cookiecutter'], no_input=True, extra_context=extra_context) return struct, opts
[docs]class NotInstalled(RuntimeError): """This extension depends on the ``cookiecutter`` package.""" DEFAULT_MESSAGE = ("cookiecutter is not installed, " "run: pip install cookiecutter") def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs): super(NotInstalled, self).__init__(message, *args, **kwargs)
[docs]class MissingTemplate(RuntimeError): """A cookiecutter template (git url) is required.""" DEFAULT_MESSAGE = "missing `cookiecutter` option" def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs): super(MissingTemplate, self).__init__(message, *args, **kwargs)