<commit_before>import ast
import os
import sys

from .casts import Boolean, List, Option, Tuple
from .exceptions import UnknownConfiguration
from .loaders import Environment, RecursiveSearch

MAGIC_FRAME_DEPTH = 2


def _caller_path():
    # MAGIC! Get the caller's module path.
    # noinspection PyProtectedMember
    frame = sys._getframe(MAGIC_FRAME_DEPTH)
    path = os.path.dirname(os.path.abspath(frame.f_code.co_filename))
    return path


class Configuration(object):
    # Shortcut for standard casts
    boolean = Boolean()
    list = List()
    tuple = Tuple()
    option = Option
    eval = staticmethod(ast.literal_eval)

    def __init__(self, loaders=None):
        self._recursive_search = None
        if loaders is None:
            self._recursive_search = RecursiveSearch()
            loaders = [
                Environment(),
                self._recursive_search,
            ]

        self.loaders = loaders

    def __repr__(self):
        loaders = ', '.join([repr(l) for l in self.loaders])
        return 'Configuration(loaders=[{}])'.format(loaders)

    def __call__(self, item, cast=lambda v: v, **kwargs):
        if not callable(cast):
            raise TypeError("Cast must be callable")

        if self._recursive_search:
            self._recursive_search.starting_path = _caller_path()

        for loader in self.loaders:
            try:
                return cast(loader[item])
            except KeyError:
                continue

        if 'default' not in kwargs:
            raise UnknownConfiguration("Configuration '{}' not found".format(item))

        return cast(kwargs["default"])<commit_msg>Added an oop friendly repr (#35)<commit_after>import ast
import os
import sys

from .casts import Boolean, List, Option, Tuple
from .exceptions import UnknownConfiguration
from .loaders import Environment, RecursiveSearch

MAGIC_FRAME_DEPTH = 2


def _caller_path():
    # MAGIC! Get the caller's module path.
    # noinspection PyProtectedMember
    frame = sys._getframe(MAGIC_FRAME_DEPTH)
    path = os.path.dirname(os.path.abspath(frame.f_code.co_filename))
    return path


class Configuration(object):
    # Shortcut for standard casts
    boolean = Boolean()
    list = List()
    tuple = Tuple()
    option = Option
    eval = staticmethod(ast.literal_eval)

    def __init__(self, loaders=None):
        self._recursive_search = None
        if loaders is None:
            self._recursive_search = RecursiveSearch()
            loaders = [
                Environment(),
                self._recursive_search,
            ]

        self.loaders = loaders

    def __repr__(self):
        loaders = ', '.join([repr(l) for l in self.loaders])
        return '{}(loaders=[{}])'.format(self.__class__.__name__, loaders)

    def __call__(self, item, cast=lambda v: v, **kwargs):
        if not callable(cast):
            raise TypeError("Cast must be callable")

        if self._recursive_search:
            self._recursive_search.starting_path = _caller_path()

        for loader in self.loaders:
            try:
                return cast(loader[item])
            except KeyError:
                continue

        if 'default' not in kwargs:
            raise UnknownConfiguration("Configuration '{}' not found".format(item))

        return cast(kwargs["default"])
{'fraction_non_alphanumeric': 0.09415292353823089, 'fraction_numerical': 0.0011994002998500749, 'mean_word_length': 2.4713839750260145, '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': '489413', 'n_tokens_mistral': 988, 'n_tokens_neox': 927, 'n_words': 249}