# Path: snowballing/collection_helpers.py
# def consume_key(collection, key, use_key):
#     """Consume key from collection based on use_key"""
#     if use_key is True:
#         return consume(collection, key)
#     elif use_key:
#         return consume(collection, use_key)
#     else:
#         return collection.get(key)
# 
# def oset(self, obj, key, value, cvar=None):
#     setattr(obj, (cvar or self.cvar)[key], value)
# 
# def odel(self, obj, key, cvar=None):
#     del obj[(cvar or self.cvar)[key]]
# 
# def ohas(self, obj, key, cvar=None):
#     return hasattr(obj, (cvar or self.cvar)[key])
# 
# def dset(self, collection, key, value, cvar=None):
#     collection[(cvar or self.cvar)[key]] = value
# 
# Path: snowballing/utils.py
# def compare_str(first, second):
#     """Compare strings and return matching ratio
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> compare_str('abcd', 'abed')
#         0.75
#     """
#     return difflib.SequenceMatcher(None, first, second).ratio()
# 
# def match_any(string, regexes):
#     """Check if string matches any regex in list
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> match_any("a", ["b", "c"])
#         False
#         >>> match_any("a", ["b", "c", "a"])
#         True
#         >>> match_any("_a", ["b", "c", "a"])
#         False
#         >>> match_any("_a", ["b", "c", "a", "_.*"])
#         True
#     """
#     if len(regexes) >= 100:
#         return any(re.match(regex + "$", string) for regex in regexes)
#     else:
#         combined = "({})".format(")|(".join(regex + "$" for regex in regexes))
#         return bool(re.match(combined, string))


import re
from string import ascii_lowercase
from .collection_helpers import consume_key, oset, odel, ohas, dset
from .utils import compare_str, match_any
    from .operations import work_by_varname
    from .operations import find_work_by_info
    from .models import Site
        from . import config
    from snowballing import config, models
        >>> class A: pass
        >>> obj = A()
        >>> obj.attr = 'x'
        >>> obj.attr2 = 'y'
        >>> obj._ignored = 'z'
        >>> print(generate_title(obj, prepend=""))
        attr: x
        attr2: y
        >>> print(generate_title(obj, prepend="", ignore={"_.*", "attr"}))
        attr2: y
    """
    result = "\n".join(
        "{}: {}".format(attr, str(value))
        for attr, value in obj.__dict__.items()
        if not match_any(attr, ignore)
        if value is not None
    )
    return prepend + result if result else ""


def update_models(old_category=None):
    for (cls_name, category, *_) in config.CLASSES:
        if not hasattr(models, cls_name):
            attrs = {}
            dset(attrs, "category", category)
            setattr(models, cls_name, type(cls_name, (models.Work,), attrs))
        else:
            obj = getattr(models, cls_name)
            if old_category is not None and hasattr(obj, old_category):
                delattr(obj, old_category)

# Path: snowballing/collection_helpers.py
# def consume_key(collection, key, use_key):
#     """Consume key from collection based on use_key"""
#     if use_key is True:
#         return consume(collection, key)
#     elif use_key:
#         return consume(collection, use_key)
#     else:
#         return collection.get(key)
# 
# def oset(self, obj, key, value, cvar=None):
#     setattr(obj, (cvar or self.cvar)[key], value)
# 
# def odel(self, obj, key, cvar=None):
#     del obj[(cvar or self.cvar)[key]]
# 
# def ohas(self, obj, key, cvar=None):
#     return hasattr(obj, (cvar or self.cvar)[key])
# 
# def dset(self, collection, key, value, cvar=None):
#     collection[(cvar or self.cvar)[key]] = value
# 
# Path: snowballing/utils.py
# def compare_str(first, second):
#     """Compare strings and return matching ratio
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> compare_str('abcd', 'abed')
#         0.75
#     """
#     return difflib.SequenceMatcher(None, first, second).ratio()
# 
# def match_any(string, regexes):
#     """Check if string matches any regex in list
# 
#     Doctest:
# 
#     .. doctest::
# 
#         >>> match_any("a", ["b", "c"])
#         False
#         >>> match_any("a", ["b", "c", "a"])
#         True
#         >>> match_any("_a", ["b", "c", "a"])
#         False
#         >>> match_any("_a", ["b", "c", "a", "_.*"])
#         True
#     """
#     if len(regexes) >= 100:
#         return any(re.match(regex + "$", string) for regex in regexes)
#     else:
#         combined = "({})".format(")|(".join(regex + "$" for regex in regexes))
#         return bool(re.match(combined, string))


# Path: snowballing/config_helpers.py
import re
from string import ascii_lowercase
from .collection_helpers import consume_key, oset, odel, ohas, dset
from .utils import compare_str, match_any
    from .operations import work_by_varname
    from .operations import find_work_by_info
    from .models import Site
        from . import config
    from snowballing import config, models

        >>> class A: pass
        >>> obj = A()
        >>> obj.attr = 'x'
        >>> obj.attr2 = 'y'
        >>> obj._ignored = 'z'
        >>> print(generate_title(obj, prepend=""))
        attr: x
        attr2: y
        >>> print(generate_title(obj, prepend="", ignore={"_.*", "attr"}))
        attr2: y
    """
    result = "\n".join(
        "{}: {}".format(attr, str(value))
        for attr, value in obj.__dict__.items()
        if not match_any(attr, ignore)
        if value is not None
    )
    return prepend + result if result else ""


def update_models(old_category=None):
    for (cls_name, category, *_) in config.CLASSES:
        if not hasattr(models, cls_name):
            attrs = {}
            dset(attrs, "category", category)
            setattr(models, cls_name, type(cls_name, (models.Work,), attrs))
        else:
            obj = getattr(models, cls_name)
            if old_category is not None and hasattr(obj, old_category):
                delattr(obj, old_category)

            oset(obj, "category", category)