<commit_before><commit_msg>Adding an integration API for externally defined SizedImage subclasses<commit_after>from .datastructures import SizedImage

class AlreadyRegistered(Exception):
    pass

class NotRegistered(Exception):
    pass

class InvalidSizedImageSubclass(Exception):
    pass

class SizedImageRegistry(object):
    """
    A SizedImageRegistry object allows new SizedImage subclasses to be dynamically
    added to all SizedImageFileField instances. New SizedImage subclasses are registered
    with the register() method.
    """

    def __init__(self, name='sizedimage_registry'):
        self._registry = {}  # attr_name -> sizedimage_cls
        self.name = name

    def register(self, attr_name, sizedimage_cls):
        """
        Registers a new SizedImage subclass (`sizedimage_cls`) to be used
        via the attribute (`attr_name`)
        """
        if not issubclass(sizedimage_cls, SizedImage):
            raise InvalidSizedImageSubclass(
                    'Only subclasses of sizedimagefield.datastructures.SizedImage '
                    'may be registered with the SizedImageRegistry')

        if attr_name in self._registry:
            raise AlreadyRegistered('A SizedImage class is already registered to the %s attribute. '
                'If you would like to override this attribute, use the unregister method' % attr_name)
        else:
            self._registry[attr_name] = sizedimage_cls

    def unregister(self, attr_name):
        """
        Unregisters the SizedImage subclass currently assigned to `attr_name`.

        If a SizedImage subclass isn't already registered to `attr_name` NotRegistered will raise.
        """
        if attr_name not in self._registry:
            raise NotRegistered('No SizedImage subclass is registered to %s' % attr_name)
        else:
            del self._registry[attr_name]

sizedimageregistry = SizedImageRegistry()
{'fraction_non_alphanumeric': 0.06530825496342738, 'fraction_numerical': 0.0, 'mean_word_length': 2.956611570247934, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, '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': '4909761', 'n_tokens_mistral': 509, 'n_tokens_neox': 481, 'n_words': 161}