<commit_before>from functools import partial, wraps

from pipetools.debug import get_name, set_name, repr_args


class Pipe(object):
    """
    Pipe-style combinator.

    Example::

        p = pipe | F | G | H

        p(x) == H(G(F(x)))

    """
    def __init__(self, func=None):
        self.func = func
        self.__name__ = 'Pipe'

    def __str__(self):
        return get_name(self.func)

    __repr__ = __str__

    @staticmethod
    def compose(first, second):
        name = lambda: '{0} | {1}'.format(get_name(first), get_name(second))

        def composite(*args, **kwargs):
            return second(first(*args, **kwargs))
        return set_name(name, composite)

    @classmethod
    def bind(cls, first, second):
        return cls(
            first if second is None else
            second if first is None else
            cls.compose(first, second))

    def __or__(self, next_func):
        return self.bind(self.func, prepare_function_for_pipe(next_func))

    def __ror__(self, prev_func):
        return self.bind(prepare_function_for_pipe(prev_func), self.func)

    def __lt__(self, thing):
        return self.func(thing) if self.func else thing

    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

    def __get__(self, instance, owner):
        return partial(self, instance) if instance else self


pipe = Pipe()


class Maybe(Pipe):

    @staticmethod
    def compose(first, second):
        name = lambda: '{0} ?| {1}'.format(get_name(first), get_name(second))

        def composite(*args, **kwargs):
            result = first(*args, **kwargs)
            return None if result is None else second(result)
        return set_name(name, composite)

    def __call__(self, *args, **kwargs):
        if len(args) == 1 and args[0] is None and not kwargs:
            return None
        return self.func(*args, **kwargs)

    def __lt__(self, thing):
        return (
            None if thing is None else
            self.func(thing) if self.func else
            thing)

maybe = Maybe()


def prepare_function_for_pipe(thing):
    if isinstance(thing, XObject):
        return ~thing
    if isinstance(thing, tuple):
        return xpartial(*thing)
    if isinstance(thing, basestring):
        return StringFormatter(thing)
    if callable(thing):
        return thing
    raise ValueError('Cannot pipe %s' % thing)


def StringFormatter(template):

    f = unicode(template).format

    def format(content):
        if isinstance(content, dict):
            return f(**content)
        if _iterable(content):
            return f(*content)
        return f(content)

    return set_name(lambda: "format('%s')" % template[:20], format)


def _iterable(obj):
    return (hasattr(obj, '__iter__')
        or hasattr(obj, '__getitem__')
        and not isinstance(obj, basestring))


class XObject(object):

    def __init__(self, func=None):
        self._func = func
        set_name(lambda: get_name(func) if func else 'X', self)

    def __repr__(self):
        return get_name(self)

    def __invert__(self):
        return self._func or set_name('X', lambda x: x)

    def bind(self, name, func):
        set_name(name, func)
        return XObject((self._func | func) if self._func else (pipe | func))

    def __call__(self, *args, **kwargs):
        name = lambda: 'X(%s)' % repr_args(*args, **kwargs)<commit_msg>fixed checking if objects are iterable<commit_after>from collections import Iterable
from functools import partial, wraps

from pipetools.debug import get_name, set_name, repr_args


class Pipe(object):
    """
    Pipe-style combinator.

    Example::

        p = pipe | F | G | H

        p(x) == H(G(F(x)))

    """
    def __init__(self, func=None):
        self.func = func
        self.__name__ = 'Pipe'

    def __str__(self):
        return get_name(self.func)

    __repr__ = __str__

    @staticmethod
    def compose(first, second):
        name = lambda: '{0} | {1}'.format(get_name(first), get_name(second))

        def composite(*args, **kwargs):
            return second(first(*args, **kwargs))
        return set_name(name, composite)

    @classmethod
    def bind(cls, first, second):
        return cls(
            first if second is None else
            second if first is None else
            cls.compose(first, second))

    def __or__(self, next_func):
        return self.bind(self.func, prepare_function_for_pipe(next_func))

    def __ror__(self, prev_func):
        return self.bind(prepare_function_for_pipe(prev_func), self.func)

    def __lt__(self, thing):
        return self.func(thing) if self.func else thing

    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

    def __get__(self, instance, owner):
        return partial(self, instance) if instance else self


pipe = Pipe()


class Maybe(Pipe):

    @staticmethod
    def compose(first, second):
        name = lambda: '{0} ?| {1}'.format(get_name(first), get_name(second))

        def composite(*args, **kwargs):
            result = first(*args, **kwargs)
            return None if result is None else second(result)
        return set_name(name, composite)

    def __call__(self, *args, **kwargs):
        if len(args) == 1 and args[0] is None and not kwargs:
            return None
        return self.func(*args, **kwargs)

    def __lt__(self, thing):
        return (
            None if thing is None else
            self.func(thing) if self.func else
            thing)

maybe = Maybe()


def prepare_function_for_pipe(thing):
    if isinstance(thing, XObject):
        return ~thing
    if isinstance(thing, tuple):
        return xpartial(*thing)
    if isinstance(thing, basestring):
        return StringFormatter(thing)
    if callable(thing):
        return thing
    raise ValueError('Cannot pipe %s' % thing)


def StringFormatter(template):

    f = unicode(template).format

    def format(content):
        if isinstance(content, dict):
            return f(**content)
        if _iterable(content):
            return f(*content)
        return f(content)

    return set_name(lambda: "format('%s')" % template[:20], format)


def _iterable(obj):
    "Iterable but not a string"
    return isinstance(obj, Iterable) and not isinstance(obj, basestring)


class XObject(object):

    def __init__(self, func=None):
        self._func = func
        set_name(lambda: get_name(func) if func else 'X', self)

    def __repr__(self):
        return get_name(self)

    def __invert__(self):
        return self._func or set_name('X', lambda x: x)

    def bind(self, name, func):
        set_name(name, func)
        return XObject((self._func | func) if self._func else (pipe | func))

    def __call__(self, *args, **kwargs):
        name = lambda: 'X(%s)' % repr_args(*args, **kwargs)
{'fraction_non_alphanumeric': 0.11669106881405564, 'fraction_numerical': 0.002342606149341142, 'mean_word_length': 2.595263157894737, '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': '7084326', 'n_tokens_mistral': 2109, 'n_tokens_neox': 2027, 'n_words': 590}