<commit_before>#!/usr/local/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function
import inspect
import sys
import glob
import re

__doc__ = """
Basic usage
-----------
Most of the methods of ConfigParser (https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser)
should be usable in a relatively obvious way, however, ``dkconfig`` tries to
give you some sane defaults to make your life easier, e.g. it will create
files/headers/keys that don't exist::

    /tst> ll
    /tst> dkconfig foo.ini set header key value
    /tst> cat foo.ini
    [header]
    key = value

Sections can be added::

    /tst> dkconfig foo.ini add_section header2
    /tst> cat foo.ini
    [header]
    key = value

    [header2]

re-adding them is a no-op (and doesn't throw an exception)::

    /tst> dkconfig foo.ini add_section header2
    /tst> cat foo.ini
    [header]
    key = value

    [header2]

the values command pretty prints the keys and values::

    /tst> dkconfig foo.ini values
    key => value

the ``dos`` command will output the key/values as dos ``set`` commands::

    /tst> dkconfig foo.ini dos
    set "KEY=value"
    /tst> dkconfig foo.ini dos > tmp.bat && tmp.bat
    /tst> echo %KEY%
    value

the ``bash`` command does the same for bash::

    /tst> dkconfig foo.ini bash
    export KEY="value"

You can read values directly into dos variables in the regular convuluted way::

    /tst> for /f "delims=" %a in ('dkconfig foo.ini get header key') do @set KEY=%a
    /tst> echo %KEY%
    value

Bash has a more sane syntax for this::

    bash$ export KEY=$(dkconfig foo.ini get header key)
    bash$ echo $KEY
    value

The appropriate error returns are set if a key is missing::

    /tst> dkconfig foo.ini get header missing
    /tst> echo %ERRORLEVEL%
    1

    /tst> dkconfig foo.ini get header key
    value
    /tst> echo %ERRORLEVEL%
    0
"""
try:
    import ConfigParser as configparser
except ImportError:
    import configparser
from contextlib import contextmanager
from lockfile import LockFile


def _printres(val):
    if val is None:
        print("")
        return
    if isinstance(val, list):
        if not val:
            print("")
            return
        first = val[0]
        if isinstance(first, tuple):
            keylen = max(len(k) for k, v in val)
            for item in val:
                print(item[0].ljust(keylen), '=>', item[1])
        else:
            for item in val:
                print(item)
    else:
        print(val)


class Config(configparser.RawConfigParser):
    exit = 0

    def help(self, cmdname=None):
        """List all commands, or help foo to get help on foo.
        """
        cmds = [name for name in dir(self)
                if not name.startswith('_')
                and inspect.ismethod(getattr(self, name))]
        if cmdname is None or cmdname not in cmds:
            return cmds

        firstline = inspect.getsourcelines(getattr(self, cmdname))[0][0]
        docstring = inspect.getdoc(getattr(self, cmdname))
        return firstline.strip() + '\n\n' + docstring

    def add_section(self, section):
        "Silently accept existing sections."
        try:
            # super(Config, self).add_section(section)
            # ConfigParser is an old style class (can't use super)
            configparser.RawConfigParser.add_section(self, section)
        except configparser.DuplicateSectionError:
            pass

    def get(self, section, option):
        "Get an option from a section (returns None if it can't find it)."
        try:
            return configparser.RawConfigParser.get(self, section, option)
        except (configparser.NoSectionError, configparser.NoOptionError):
            self.exit = 1
            return None

    def set(self, section, option, value):
        """Set an option in a section (creates the section if it doesn't exist.
        """
        if not self.has_section(section):
            self.add_section(section)
        return configparser.RawConfigParser.set(self, section, option, value)

    def setlist(self, section, key, *lst):
        if not self.has_section(section):
            self.add_section(section)
        listval = '\n'.join([str(item) for item in lst])
        configparser.RawConfigParser.set(self, section, key, listval)

    def values(self, *sections):
        "Return all values in the config file."
        res = []
        sections = sections or self.sections()
        for sect in sections:
            res += self.items(sect)
        return res

    def dos(self, *sections):
        "Return values as dos set statements."

        def convert_val(v):
            m = re.match(r'\w:(?:/[^/]*)*', v)
            if m:
                # it's a path
                return v.replace('/', '\\')
            return v
            # print("converting:", v, type(v))
            # return re.sub(r'\$(.*)\b', r"%%\1%%", v, re.I)

        return ['set "%s=%s"' % (k.upper(), convert_val(v))
                for k, v in self.values(*sections)]

    def bash(self, *sections):
        "Return values as bash export statements."
        return ['export %s="%s"' % (k.upper(), v) for k, v in self.values(*sections)]


@contextmanager
def parser(fname):
    cp = Config()
    lock = LockFile(fname + '.lock')
    with lock:
        try:
            cp.read(fname)
        except IOError as e:
            # file not found: errno == 2 (it will be created below)
            if e.errno != 2:
                raise
        yield cp
        cp.write(open(fname, 'w'))


def config(filename, command='cat', flags=(), *args):
    "Main entry point for this module."
    if '--debug' in flags:
        print("\n==> CONFIG:", filename, command, args, '\n')
    args = [arg for arg in args if not arg.startswith('-')]<commit_msg>Don't wait forever.<commit_after>#!/usr/local/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function
import inspect
import sys
import glob
import re

__doc__ = """
Basic usage
-----------
Most of the methods of ConfigParser (https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser)
should be usable in a relatively obvious way, however, ``dkconfig`` tries to
give you some sane defaults to make your life easier, e.g. it will create
files/headers/keys that don't exist::

    /tst> ll
    /tst> dkconfig foo.ini set header key value
    /tst> cat foo.ini
    [header]
    key = value

Sections can be added::

    /tst> dkconfig foo.ini add_section header2
    /tst> cat foo.ini
    [header]
    key = value

    [header2]

re-adding them is a no-op (and doesn't throw an exception)::

    /tst> dkconfig foo.ini add_section header2
    /tst> cat foo.ini
    [header]
    key = value

    [header2]

the values command pretty prints the keys and values::

    /tst> dkconfig foo.ini values
    key => value

the ``dos`` command will output the key/values as dos ``set`` commands::

    /tst> dkconfig foo.ini dos
    set "KEY=value"
    /tst> dkconfig foo.ini dos > tmp.bat && tmp.bat
    /tst> echo %KEY%
    value

the ``bash`` command does the same for bash::

    /tst> dkconfig foo.ini bash
    export KEY="value"

You can read values directly into dos variables in the regular convuluted way::

    /tst> for /f "delims=" %a in ('dkconfig foo.ini get header key') do @set KEY=%a
    /tst> echo %KEY%
    value

Bash has a more sane syntax for this::

    bash$ export KEY=$(dkconfig foo.ini get header key)
    bash$ echo $KEY
    value

The appropriate error returns are set if a key is missing::

    /tst> dkconfig foo.ini get header missing
    /tst> echo %ERRORLEVEL%
    1

    /tst> dkconfig foo.ini get header key
    value
    /tst> echo %ERRORLEVEL%
    0
"""
try:
    import ConfigParser as configparser
except ImportError:
    import configparser
from contextlib import contextmanager
from lockfile import LockFile


def _printres(val):
    if val is None:
        print("")
        return
    if isinstance(val, list):
        if not val:
            print("")
            return
        first = val[0]
        if isinstance(first, tuple):
            keylen = max(len(k) for k, v in val)
            for item in val:
                print(item[0].ljust(keylen), '=>', item[1])
        else:
            for item in val:
                print(item)
    else:
        print(val)


class Config(configparser.RawConfigParser):
    exit = 0

    def help(self, cmdname=None):
        """List all commands, or help foo to get help on foo.
        """
        cmds = [name for name in dir(self)
                if not name.startswith('_')
                and inspect.ismethod(getattr(self, name))]
        if cmdname is None or cmdname not in cmds:
            return cmds

        firstline = inspect.getsourcelines(getattr(self, cmdname))[0][0]
        docstring = inspect.getdoc(getattr(self, cmdname))
        return firstline.strip() + '\n\n' + docstring

    def add_section(self, section):
        "Silently accept existing sections."
        try:
            # super(Config, self).add_section(section)
            # ConfigParser is an old style class (can't use super)
            configparser.RawConfigParser.add_section(self, section)
        except configparser.DuplicateSectionError:
            pass

    def get(self, section, option):
        "Get an option from a section (returns None if it can't find it)."
        try:
            return configparser.RawConfigParser.get(self, section, option)
        except (configparser.NoSectionError, configparser.NoOptionError):
            self.exit = 1
            return None

    def set(self, section, option, value):
        """Set an option in a section (creates the section if it doesn't exist.
        """
        if not self.has_section(section):
            self.add_section(section)
        return configparser.RawConfigParser.set(self, section, option, value)

    def setlist(self, section, key, *lst):
        if not self.has_section(section):
            self.add_section(section)
        listval = '\n'.join([str(item) for item in lst])
        configparser.RawConfigParser.set(self, section, key, listval)

    def values(self, *sections):
        "Return all values in the config file."
        res = []
        sections = sections or self.sections()
        for sect in sections:
            res += self.items(sect)
        return res

    def dos(self, *sections):
        "Return values as dos set statements."

        def convert_val(v):
            m = re.match(r'\w:(?:/[^/]*)*', v)
            if m:
                # it's a path
                return v.replace('/', '\\')
            return v
            # print("converting:", v, type(v))
            # return re.sub(r'\$(.*)\b', r"%%\1%%", v, re.I)

        return ['set "%s=%s"' % (k.upper(), convert_val(v))
                for k, v in self.values(*sections)]

    def bash(self, *sections):
        "Return values as bash export statements."
        return ['export %s="%s"' % (k.upper(), v) for k, v in self.values(*sections)]


@contextmanager
def parser(fname):
    cp = Config()
    lock = LockFile(fname + '.lock', timeout=2)
    with lock:
        try:
            cp.read(fname)
        except IOError as e:
            # file not found: errno == 2 (it will be created below)
            if e.errno != 2:
                raise
        yield cp
        cp.write(open(fname, 'w'))


def config(filename, command='cat', flags=(), *args):
    "Main entry point for this module."
    if '--debug' in flags:
        print("\n==> CONFIG:", filename, command, args, '\n')
    args = [arg for arg in args if not arg.startswith('-')]
{'fraction_non_alphanumeric': 0.11478649368502448, 'fraction_numerical': 0.0031789672652289716, 'mean_word_length': 2.221699418765569, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 47, 'https://': 2, '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': '4969983', 'n_tokens_mistral': 3578, 'n_tokens_neox': 3446, 'n_words': 1206}