<commit_before>import collections
from datetime import datetime, timedelta
import re

from pyxp import *
from pyxp.client import *
from pygmi import *
from pygmi.util import prop

__all__ = ('wmii', 'Tags', 'Tag', 'Area', 'Frame', 'Client',
           'Button', 'Colors', 'Color', 'Toggle', 'Always', 'Never')

spacere = re.compile(r'\s')

class utf8(object):
    def __str__(self):
        return unicode(self).encode('utf-8')

@apply
class Toggle(utf8):
    def __unicode__(self):
        return unicode(self.__class__.__name__)
@apply
class Always(Toggle.__class__):
    pass
@apply
class Never(Toggle.__class__):
    pass

def constrain(min, max, val):
    if val < min:
        return min
    if val > max:
        return max
    return val

class Ctl(object):
    """
    An abstract class to represent the 'ctl' files of the wmii filesystem.
    Instances act as live, writable dictionaries of the settings represented
    in the file.

    Abstract roperty ctl_path: The path to the file represented by this
            control.
    Property ctl_hasid: When true, the first line of the represented
            file is treated as an id, rather than a key-value pair. In this
            case, the value is available via the 'id' property.
    Property ctl_types: A dict mapping named dictionary keys to two valued
            tuples, each containing a decoder and encoder function for the
            property's plain text value.
    """
    sentinel = {}
    ctl_types = {}
    ctl_hasid = False

    def __eq__(self, other):
        if self.ctl_hasid and isinstance(other, Ctl) and other.ctl_hasid:
            return self.id == other.id
        return False

    def __init__(self):
        self.cache = {}

    def ctl(self, *args):
        """
        Arguments are joined by ascii spaces and written to the ctl file.
        """
        client.awrite(self.ctl_path, ' '.join(args))

    def __getitem__(self, key):
        for line in self.ctl_lines():
            key_, rest = line.split(' ', 1)
            if key_ == key:
                if key in self.ctl_types:
                    return self.ctl_types[key][0](rest)
                return rest
        raise KeyError()
    def __hasitem__(self, key):
        return key in self.keys()
    def __setitem__(self, key, val):
        assert '\n' not in key
        self.cache[key] = val
        if key in self.ctl_types:
            if self.ctl_types[key][1] is None:
                raise NotImplementedError('%s: %s is not writable' % (self.ctl_path, key))
            val = self.ctl_types[key][1](val)
        self.ctl(key, val)

    def get(self, key, default=sentinel):
        """
        Gets the instance's dictionary value for 'key'. If the key doesn't
        exist, 'default' is returned. If 'default' isn't provided and the key
        doesn't exist, a KeyError is raised.<commit_msg>[pygmi] Make sure Ctl#ctl strings are unicode before joining them. Fixes issue #194.<commit_after>import collections
from datetime import datetime, timedelta
import re

from pyxp import *
from pyxp.client import *
from pygmi import *
from pygmi.util import prop

__all__ = ('wmii', 'Tags', 'Tag', 'Area', 'Frame', 'Client',
           'Button', 'Colors', 'Color', 'Toggle', 'Always', 'Never')

spacere = re.compile(r'\s')

class utf8(object):
    def __str__(self):
        return unicode(self).encode('utf-8')

@apply
class Toggle(utf8):
    def __unicode__(self):
        return unicode(self.__class__.__name__)
@apply
class Always(Toggle.__class__):
    pass
@apply
class Never(Toggle.__class__):
    pass

def constrain(min, max, val):
    if val < min:
        return min
    if val > max:
        return max
    return val

class Ctl(object):
    """
    An abstract class to represent the 'ctl' files of the wmii filesystem.
    Instances act as live, writable dictionaries of the settings represented
    in the file.

    Abstract roperty ctl_path: The path to the file represented by this
            control.
    Property ctl_hasid: When true, the first line of the represented
            file is treated as an id, rather than a key-value pair. In this
            case, the value is available via the 'id' property.
    Property ctl_types: A dict mapping named dictionary keys to two valued
            tuples, each containing a decoder and encoder function for the
            property's plain text value.
    """
    sentinel = {}
    ctl_types = {}
    ctl_hasid = False

    def __eq__(self, other):
        if self.ctl_hasid and isinstance(other, Ctl) and other.ctl_hasid:
            return self.id == other.id
        return False

    def __init__(self):
        self.cache = {}

    def ctl(self, *args):
        """
        Arguments are joined by ascii spaces and written to the ctl file.
        """
        client.awrite(self.ctl_path, u' '.join(map(unicode, args)))

    def __getitem__(self, key):
        for line in self.ctl_lines():
            key_, rest = line.split(' ', 1)
            if key_ == key:
                if key in self.ctl_types:
                    return self.ctl_types[key][0](rest)
                return rest
        raise KeyError()
    def __hasitem__(self, key):
        return key in self.keys()
    def __setitem__(self, key, val):
        assert '\n' not in key
        self.cache[key] = val
        if key in self.ctl_types:
            if self.ctl_types[key][1] is None:
                raise NotImplementedError('%s: %s is not writable' % (self.ctl_path, key))
            val = self.ctl_types[key][1](val)
        self.ctl(key, val)

    def get(self, key, default=sentinel):
        """
        Gets the instance's dictionary value for 'key'. If the key doesn't
        exist, 'default' is returned. If 'default' isn't provided and the key
        doesn't exist, a KeyError is raised.
{'fraction_non_alphanumeric': 0.09862306368330465, 'fraction_numerical': 0.002925989672977625, 'mean_word_length': 2.355080831408776, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '4808208', 'n_tokens_mistral': 1741, 'n_tokens_neox': 1673, 'n_words': 619}