<commit_before>"""
Basic Template system for project skeleton.

skeleton is similar to the template part of PasteScript but 
without any dependencies; it should also be compatible with Python 3.

However in this early phase of development, it only target python 2.5+,
and tests require Mock.
"""

import codecs
import datetime
import logging
import os
import re
import shutil
import sys

from skeleton.utils import get_loggger, get_file_mode, vars_to_optparser, prompt


log = get_loggger(__name__)


class Skeleton(dict):
    """
    Skeleton Class.
    
    It should have a `src` attribute set to the path to the skeleton folder
    (relative to the class module) and a list of variables, the `vars` 
    attribute, the skeleton template files require. The variable should be an 
    object with name and full_description attribute, and a prompt method than 
    prompt the user for the variable value and return it. You can use 
    `skeleton.Var`.
    
    By default a template file ends with "_tmpl" (see the `template_suffix` 
    attribute), is UTF-8 encoded (`file_encoding` attribute) and will be 
    formatted by Python 2.6+ string Formatter.
    
    You can set an alternative formatter by overwriting the `template_formatter`
    method. It takes for argument the template to parse and self for
    variable mapping.
    """
    src = None
    vars = []
    required_skeletons = []
    template_suffix = '_tmpl'
    file_encoding = 'UTF-8'
    run_dry = False

    def __init__(self, *arg, **kw):
        super(Skeleton, self).__init__(*arg, **kw)

        self._required_skeletons = []
        for skel_class in self.required_skeletons:
            skel = skel_class(*arg, **kw)
            self.update(skel)
            self._required_skeletons.append(skel)

        # Set global variables
        self['Year'] = datetime.datetime.utcnow().year

        # Set defaults
        self._defaults = dict([
            (var.name, var.default,)
                for var in self.vars if var.default is not None
                ])

    def update(self, *args, **kw):
        """
        Add or update entries in the skeleton
        
        See dict.update()
        """
        for skel in self._required_skeletons:
            skel.update(*args, **kw)
        super(Skeleton, self).update(*args, **kw)

    def __setitem__(self, key, value):
        """
        Add or update an entry in the skeleton
        """
        for skel in self._required_skeletons:
            skel.__setitem__(key, value)
        super(Skeleton, self).__setitem__(key, value)

    def get(self, variable_name, default=None):
        """
        Get the set variable value or its default or the given default
        """
        default = self._defaults.get(variable_name, default)
        return super(Skeleton, self).get(variable_name, default)

    @property
    def skel_dir(self):
        """
        return the path (absolute path or relative to the current working
        directory).
        """
        if self.src is None:
            raise AttributeError(
                "The src attribute of the %s Skeleton is not set" %
                self.__class__.__name__
                )

        mod = sys.modules[self.__class__.__module__]
        mod_dir = os.path.dirname(mod.__file__)
        skel_path = os.path.join(mod_dir, self.src)

        if not os.path.exists(skel_path):
            raise AttributeError("No skeleton at %r" % skel_path)
        return skel_path

    def check_vars(self):
        """
        Raise a KeyError if any required variable is missing.
        """
        for skel in self._required_skeletons:
            skel.check_vars()
            self.update(skel)

        for var in self.vars:
            if var.name not in self and var.name not in self._defaults:
                raise KeyError("Variable %r not set." % var.name)

    def get_missing_variables(self):
        """
        Prompt user for any missing variable 
        (even the ones with a default value).
        """
        for skel in self._required_skeletons:
            skel.get_missing_variables()
            self.update(skel)

        for var in self.vars:
            if var.name not in self:
                self[var.name] = var.prompt()
            else:
                log.debug("Varaiable %r already set", var.name)

    def write(self, dst_dir):
        """
        Apply skeleton to dst_dir.
        
        Copy files and folders from the src folder to the dst_dir. If dst_dir 
        doesn't exist, it will be created.
        
        The file name are formatted by the template formatter so that file
        names can do dynamically generated. Make sure that any special charters
        for the formatters are escaped.
        
        If the file name ends by "_tmpl" its content will be formatted by the
        template formatter.
        
        Raises:
        - KeyError if a variable is missing and doesn't have a default.
        - IOError if it cannot read the skeleton files, or cannot create
          files and folder.
        """
        for skel in self._required_skeletons:
            skel.write(dst_dir)
            self.update(skel)

        log.info(
            "Rendering %s skeleton at %r...",
            self.__class__.__name__,
            dst_dir)

        self.check_vars()

        if not os.path.exists(dst_dir):
            self._mkdir(dst_dir)

        skel_dir = self.skel_dir
        skel_dir_len = len(skel_dir)
        log.debug("Getting skeleton from %r" % skel_dir)

        for dir_path, dir_names, file_names in os.walk(skel_dir):
            rel_dir_path = dir_path[skel_dir_len:].lstrip(r'\/')<commit_msg>required skeleton get passed the run_dry flag<commit_after>"""
Basic Template system for project skeleton.

skeleton is similar to the template part of PasteScript but 
without any dependencies; it should also be compatible with Python 3.

However in this early phase of development, it only target python 2.5+,
and tests require Mock.
"""

import codecs
import datetime
import logging
import os
import re
import shutil
import sys

from skeleton.utils import get_loggger, get_file_mode, vars_to_optparser, prompt


log = get_loggger(__name__)


class Skeleton(dict):
    """
    Skeleton Class.
    
    It should have a `src` attribute set to the path to the skeleton folder
    (relative to the class module) and a list of variables, the `vars` 
    attribute, the skeleton template files require. The variable should be an 
    object with name and full_description attribute, and a prompt method than 
    prompt the user for the variable value and return it. You can use 
    `skeleton.Var`.
    
    By default a template file ends with "_tmpl" (see the `template_suffix` 
    attribute), is UTF-8 encoded (`file_encoding` attribute) and will be 
    formatted by Python 2.6+ string Formatter.
    
    You can set an alternative formatter by overwriting the `template_formatter`
    method. It takes for argument the template to parse and self for
    variable mapping.
    """
    src = None
    vars = []
    required_skeletons = []
    template_suffix = '_tmpl'
    file_encoding = 'UTF-8'
    run_dry = False

    def __init__(self, *arg, **kw):
        super(Skeleton, self).__init__(*arg, **kw)

        self._required_skeletons = []
        for skel_class in self.required_skeletons:
            skel = skel_class(*arg, **kw)
            self.update(skel)
            self._required_skeletons.append(skel)

        # Set global variables
        self['Year'] = datetime.datetime.utcnow().year

        # Set defaults
        self._defaults = dict([
            (var.name, var.default,)
                for var in self.vars if var.default is not None
                ])

    def update(self, *args, **kw):
        """
        Add or update entries in the skeleton
        
        See dict.update()
        """
        for skel in self._required_skeletons:
            skel.update(*args, **kw)
        super(Skeleton, self).update(*args, **kw)

    def __setitem__(self, key, value):
        """
        Add or update an entry in the skeleton
        """
        for skel in self._required_skeletons:
            skel.__setitem__(key, value)
        super(Skeleton, self).__setitem__(key, value)

    def get(self, variable_name, default=None):
        """
        Get the set variable value or its default or the given default
        """
        default = self._defaults.get(variable_name, default)
        return super(Skeleton, self).get(variable_name, default)

    @property
    def skel_dir(self):
        """
        return the path (absolute path or relative to the current working
        directory).
        """
        if self.src is None:
            raise AttributeError(
                "The src attribute of the %s Skeleton is not set" %
                self.__class__.__name__
                )

        mod = sys.modules[self.__class__.__module__]
        mod_dir = os.path.dirname(mod.__file__)
        skel_path = os.path.join(mod_dir, self.src)

        if not os.path.exists(skel_path):
            raise AttributeError("No skeleton at %r" % skel_path)
        return skel_path

    def check_vars(self):
        """
        Raise a KeyError if any required variable is missing.
        """
        for skel in self._required_skeletons:
            skel.check_vars()
            self.update(skel)

        for var in self.vars:
            if var.name not in self and var.name not in self._defaults:
                raise KeyError("Variable %r not set." % var.name)

    def get_missing_variables(self):
        """
        Prompt user for any missing variable 
        (even the ones with a default value).
        """
        for skel in self._required_skeletons:
            skel.get_missing_variables()
            self.update(skel)

        for var in self.vars:
            if var.name not in self:
                self[var.name] = var.prompt()
            else:
                log.debug("Varaiable %r already set", var.name)

    def write(self, dst_dir):
        """
        Apply skeleton to dst_dir.
        
        Copy files and folders from the src folder to the dst_dir. If dst_dir 
        doesn't exist, it will be created.
        
        The file name are formatted by the template formatter so that file
        names can do dynamically generated. Make sure that any special charters
        for the formatters are escaped.
        
        If the file name ends by "_tmpl" its content will be formatted by the
        template formatter.
        
        Raises:
        - KeyError if a variable is missing and doesn't have a default.
        - IOError if it cannot read the skeleton files, or cannot create
          files and folder.
        """
        for skel in self._required_skeletons:
            skel.run_dry = self.run_dry
            skel.write(dst_dir)
            self.update(skel)

        log.info(
            "Rendering %s skeleton at %r...",
            self.__class__.__name__,
            dst_dir)

        self.check_vars()

        if not os.path.exists(dst_dir):
            self._mkdir(dst_dir)

        skel_dir = self.skel_dir
        skel_dir_len = len(skel_dir)
        log.debug("Getting skeleton from %r" % skel_dir)

        for dir_path, dir_names, file_names in os.walk(skel_dir):
            rel_dir_path = dir_path[skel_dir_len:].lstrip(r'\/')
{'fraction_non_alphanumeric': 0.07849500087703912, 'fraction_numerical': 0.0012278547623223997, 'mean_word_length': 2.0719288793103448, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '769427', 'n_tokens_mistral': 3279, 'n_tokens_neox': 3104, 'n_words': 1117}