<commit_before>import logging
from .base import DependentGenerator


__all__ = ['IndependentGeneratorMeta', 'ClonedGenerator']

logger = logging.getLogger('tohu')


class TohuCloneError(Exception):
    """
    Custom exception for errors related to cloned generators.
    """


class ClonedGenerator(DependentGenerator):

    def __init__(self, parent):
        self.parent = parent
        self.gen = parent._spawn()

    def __repr__(self):
        return f'<ClonedGenerator: id={id(self)}, parent={self.parent} >'

    # def clone(self):
    #     return ClonedGenerator(self.parent)

    def _spawn_and_reattach_parent(self, new_parent):
        logger.debug(f'Spawning cloned generator {self} and re-attaching to new parent {new_parent}')
        return ClonedGenerator(new_parent)

    def __next__(self):
        return next(self.gen)

    def reset(self, seed=None):
        logger.debug(f'Ignoring reset() on cloned generator {self}')

    def reset_dependent_generator(self, seed):
        logger.debug(f'Resetting cloned generator {self} (seed={seed})')
        self.gen.reset(seed)


def attach_new_init_method(cls):
    """
    Replace the existing cls.__init__() method with a new one which
    also initialises the _dependent_generators attribute to an empty list.
    """

    orig_init = cls.__init__

    def new_init(self, *args, **kwargs):
        self._dependent_generators = []
        orig_init(self, *args, **kwargs)

    cls.__init__ = new_init


def attach_new_reset_method(cls):
    """
    Replace existing cls.reset() method with a new one which also
    calls reset() on any clones.
    """
    orig_reset = cls.reset

    def new_reset(self, seed=None):
        orig_reset(self, seed)
        for c in self._dependent_generators:
            c.reset_dependent_generator(seed)
        return self

    cls.reset = new_reset


def attach_make_clone_method(cls):

    def make_clone(self):
        c = ClonedGenerator(parent=self)
        self.register_clone(c)
        return c

    cls.clone = make_clone


def attach_register_clone_method(cls):

    def register_clone(self, clone):
        """
        Register
        """
        assert isinstance(clone, ClonedGenerator), f"Not a cloned generator: {clone}"
        self._dependent_generators.append(clone)

    cls.register_clone = register_clone


class IndependentGeneratorMeta(type):

    def __new__(metacls, cg_name, bases, clsdict):
        new_cls = super(IndependentGeneratorMeta, metacls).__new__(metacls, cg_name, bases, clsdict)

        attach_new_init_method(new_cls)
        attach_new_reset_method(new_cls)
        attach_make_clone_method(new_cls)
        attach_register_clone_method(new_cls)

        return new_cls<commit_msg>Add debugging message<commit_after>import logging
from .base import DependentGenerator


__all__ = ['IndependentGeneratorMeta', 'ClonedGenerator']

logger = logging.getLogger('tohu')


class TohuCloneError(Exception):
    """
    Custom exception for errors related to cloned generators.
    """


class ClonedGenerator(DependentGenerator):

    def __init__(self, parent):
        self.parent = parent
        self.gen = parent._spawn()

    def __repr__(self):
        return f'<ClonedGenerator: id={id(self)}, parent={self.parent} >'

    # def clone(self):
    #     return ClonedGenerator(self.parent)

    def _spawn_and_reattach_parent(self, new_parent):
        logger.debug(f'Spawning cloned generator {self} and re-attaching to new parent {new_parent}')
        return ClonedGenerator(new_parent)

    def __next__(self):
        return next(self.gen)

    def reset(self, seed=None):
        logger.debug(f'Ignoring reset() on cloned generator {self}')

    def reset_dependent_generator(self, seed):
        logger.debug(f'Resetting cloned generator {self} (seed={seed})')
        self.gen.reset(seed)


def attach_new_init_method(cls):
    """
    Replace the existing cls.__init__() method with a new one which
    also initialises the _dependent_generators attribute to an empty list.
    """

    orig_init = cls.__init__

    def new_init(self, *args, **kwargs):
        self._dependent_generators = []
        orig_init(self, *args, **kwargs)

    cls.__init__ = new_init


def attach_new_reset_method(cls):
    """
    Replace existing cls.reset() method with a new one which also
    calls reset() on any clones.
    """
    orig_reset = cls.reset

    def new_reset(self, seed=None):
        orig_reset(self, seed)
        for c in self._dependent_generators:
            c.reset_dependent_generator(seed)
        return self

    cls.reset = new_reset


def attach_make_clone_method(cls):

    def make_clone(self):
        c = ClonedGenerator(parent=self)
        logger.debug(f"Cloning generator {self} (new clone: {c})")
        self.register_clone(c)
        return c

    cls.clone = make_clone


def attach_register_clone_method(cls):

    def register_clone(self, clone):
        """
        Register
        """
        assert isinstance(clone, ClonedGenerator), f"Not a cloned generator: {clone}"
        self._dependent_generators.append(clone)

    cls.register_clone = register_clone


class IndependentGeneratorMeta(type):

    def __new__(metacls, cg_name, bases, clsdict):
        new_cls = super(IndependentGeneratorMeta, metacls).__new__(metacls, cg_name, bases, clsdict)

        attach_new_init_method(new_cls)
        attach_new_reset_method(new_cls)
        attach_make_clone_method(new_cls)
        attach_register_clone_method(new_cls)

        return new_cls
{'fraction_non_alphanumeric': 0.09687330562082053, 'fraction_numerical': 0.0, 'mean_word_length': 3.250384024577573, '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': '2920543', 'n_tokens_mistral': 1710, 'n_tokens_neox': 1646, 'n_words': 387}