Source code for pyscaffold.extensions.cookiecutter

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

Warning:
    *Deprecation Notice* - In the next major release the Cookiecutter extension
    will be extracted into an independent package.
    After PyScaffold v4.0, you will need to explicitly install
    ``pyscaffoldext-cookiecutter`` in your system/virtualenv in order to be
    able to use it.
"""

import argparse

from ..api import Extension
from ..api.helpers import logger, register
from ..warnings import UpdateNotSupported


[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) 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 """ if opts.get("update"): logger.warning(UpdateNotSupported(extension="cookiecutter")) return struct, opts try: from cookiecutter.main import cookiecutter except Exception as e: raise NotInstalled from 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)