Source code for alchy.utils

"""Generic utility functions used in package.

..
    >>> from alchy.utils import *
"""

import re
from collections import Iterable

from sqlalchemy import Column

from ._compat import string_types, iteritems


__all__ = [
    'is_sequence',
    'has_primary_key',
    'camelcase_to_underscore',
    'iterflatten',
    'flatten'
]


[docs]def is_sequence(obj): """Test if `obj` is an iterable but not ``dict`` or ``str``. Mainly used to determine if `obj` can be treated like a ``list`` for iteration purposes. """ return (isinstance(obj, Iterable) and not isinstance(obj, string_types) and not isinstance(obj, dict))
[docs]def has_primary_key(metadict): """Check if meta class' dict object has a primary key defined.""" return any(column.primary_key for attr, column in iteritems(metadict) if isinstance(column, Column))
[docs]def camelcase_to_underscore(string): """Convert string from ``CamelCase`` to ``under_score``.""" return (re.sub('((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))', r'_\1', string) .lower())
[docs]def iterflatten(items): """Return iterator which flattens list/tuple of lists/tuples:: >>> to_flatten = [1, [2,3], [4, [5, [6]], 7], 8] >>> assert list(iterflatten(to_flatten)) == [1,2,3,4,5,6,7,8] """ for item in items: if isinstance(item, (list, tuple)): for itm in iterflatten(item): yield itm else: yield item
[docs]def flatten(items): """Return flattened list of a list/tuple of lists/tuples:: >>> assert flatten([1, [2,3], [4, [5, [6]], 7], 8]) == [1,2,3,4,5,6,7,8] """ return list(iterflatten(items))
def iterunique(items): """Return iterator to find unique list while preserving the order.""" seen = [] for item in items: if item not in seen: seen.append(item) yield item def unique(items): """Return unique list while preserving the order. >>> assert unique([1, 2, 3, 1, 2, 3, 4]) == [1, 2, 3, 4] """ return list(iterunique(items)) def mapper_class(relation): """Return mapper class given an ORM relation attribute.""" return relation.property.mapper.class_ def get_mapper_class(model, field): """Return mapper class given ORM model and field string.""" return mapper_class(getattr(model, field)) def merge_declarative_args(base_classes, config_key): """Given a list of base classes, merge declarative args identified by `config_key` into a single configuration object. """ configs = [getattr(base, config_key, None) for base in reversed(base_classes)] args = [] kargs = {} for obj in configs: if not obj: continue if callable(obj): obj = obj() if isinstance(obj, dict): kargs.update(obj) elif isinstance(obj[-1], dict): # Configuration object has a dict at the end so we assume the # passed in format was [item0, item1, ..., dict0]. args += obj[:-1] kargs.update(obj[-1]) else: args += obj # Make args unique in case base classes duplicated items. args = unique(args) return (args, kargs)