<commit_before>from argparse import Namespace
from contextlib import contextmanager
from pkg_resources import get_distribution, DistributionNotFound
import errno
import logging
import os
from random import SystemRandom
import string

import yaml

from ._compat import which


import_module = __import__

logger = logging.getLogger('passpie')
handler = logging.StreamHandler()
formatter = logging.Formatter(
    '%(name)s::%(levelname)s::%(module)s::%(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)


def genpass(length=32, special="_-#|+="):
    """generates a password with random chararcters
    """
    chars = special + string.ascii_letters + string.digits + " "
    return "".join(SystemRandom().choice(chars) for _ in range(length))


@contextmanager
def mkdir_open(path, mode="r"):
    try:
        dir_path = os.path.dirname(path)
        os.makedirs(dir_path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(dir_path):
            pass
        else:
            raise
    with open(path, mode) as fd:
        yield fd


def get_version():
    try:
        _dist = get_distribution('passpie')
        dist_loc = os.path.normcase(_dist.location)
        here = os.path.normcase(__file__)
        if not here.startswith(os.path.join(dist_loc, 'passpie')):
            raise DistributionNotFound
    except DistributionNotFound:
        return 'Please install this project with setup.py or pip'
    else:
        return _dist.version


def load_config(default_config, user_config_path):
    try:
        with open(user_config_path) as config_file:
            config_content = config_file.read()
    except IOError as e:
        logging.debug('Not a valid path for config {}'.format(e))
        return Namespace(**default_config)

    try:
        user_config = yaml.load(config_content)
        default_config.update(user_config)
    except yaml.scanner.ScannerError as e:
        logging.debug('Malformed user configuration file {}'.format(e))
        return Namespace(**default_config)

    config = Namespace(**default_config)
    return config


def ensure_dependencies():
    try:
        assert which('gpg') or which('gpg2')
    except AssertionError:
        raise RuntimeError('GnuPG not installed. https://www.gnupg.org/')


def reverse_enumerate(seq):
    return [e for e in zip(reversed(range(len(list(seq)))), list(seq))]<commit_msg>Add tempdir context manager to utils<commit_after>from argparse import Namespace
from contextlib import contextmanager
from functools import wraps
from pkg_resources import get_distribution, DistributionNotFound
from random import SystemRandom
import errno
import logging
import os
import shutil
import string
import tempfile

import yaml

from ._compat import which


import_module = __import__

logger = logging.getLogger('passpie')
handler = logging.StreamHandler()
formatter = logging.Formatter(
    '%(name)s::%(levelname)s::%(module)s::%(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)


def genpass(length=32, special="_-#|+="):
    """generates a password with random chararcters
    """
    chars = special + string.ascii_letters + string.digits + " "
    return "".join(SystemRandom().choice(chars) for _ in range(length))


@contextmanager
def mkdir_open(path, mode="r"):
    try:
        dir_path = os.path.dirname(path)
        os.makedirs(dir_path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(dir_path):
            pass
        else:
            raise
    with open(path, mode) as fd:
        yield fd


def get_version():
    try:
        _dist = get_distribution('passpie')
        dist_loc = os.path.normcase(_dist.location)
        here = os.path.normcase(__file__)
        if not here.startswith(os.path.join(dist_loc, 'passpie')):
            raise DistributionNotFound
    except DistributionNotFound:
        return 'Please install this project with setup.py or pip'
    else:
        return _dist.version


def load_config(default_config, user_config_path):
    try:
        with open(user_config_path) as config_file:
            config_content = config_file.read()
    except IOError as e:
        logging.debug('Not a valid path for config {}'.format(e))
        return Namespace(**default_config)

    try:
        user_config = yaml.load(config_content)
        default_config.update(user_config)
    except yaml.scanner.ScannerError as e:
        logging.debug('Malformed user configuration file {}'.format(e))
        return Namespace(**default_config)

    config = Namespace(**default_config)
    return config


def ensure_dependencies():
    try:
        assert which('gpg') or which('gpg2')
    except AssertionError:
        raise RuntimeError('GnuPG not installed. https://www.gnupg.org/')


def reverse_enumerate(seq):
    return [e for e in zip(reversed(range(len(list(seq)))), list(seq))]


@contextmanager
def tempdir():
    path = tempfile.mkdtemp()
    yield path
    if os.path.exists(path):
        shutil.rmtree(path)


def logged(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        text = '{} called with args: {}, kwargs: {}'.format(
            func.__name__, args, kwargs)
        logger.debug(text)
        return func(*args, **kwargs)
    return wrapper
{'fraction_non_alphanumeric': 0.10623818525519849, 'fraction_numerical': 0.0011342155009451795, 'mean_word_length': 3.3086319218241043, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, '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': '3256974', 'n_tokens_mistral': 1604, 'n_tokens_neox': 1544, 'n_words': 405}