Source code for save_the_change.util

# -*- coding: utf-8 -*-

from __future__ import division, absolute_import, print_function, unicode_literals

from datetime import date, time, datetime, timedelta, tzinfo
from decimal import Decimal
from uuid import UUID

from django.utils import six


#: A :class:`set` listing known immutable types.
IMMUTABLE_TYPES = set((
	type(None), bool, float, complex, Decimal,
	six.text_type, six.binary_type, tuple, frozenset,
	date, time, datetime, timedelta, tzinfo,
	UUID
) + six.integer_types + six.string_types)

#: A :class:`set` listing known immutable types that are infinitely
#: recursively iterable.
INFINITELY_ITERABLE_IMMUTABLE_TYPES = set(
	(six.text_type, six.binary_type) + six.string_types
)


class DoesNotExist:
	"""Indicates when an attribute does not exist on an object."""
	pass


[docs]def is_mutable(obj): """ Checks if given object is likely mutable. :param obj: object to check. We check that the object is itself a known immutable type, and then attempt to recursively check any objects within it. Strings are special cased to prevent us getting stuck in an infinite loop. :return: :const:`True` if the object is likely mutable, :const:`False` if it definitely is not. :rtype: :obj:`bool` """ if type(obj) not in IMMUTABLE_TYPES: return True elif type(obj) not in INFINITELY_ITERABLE_IMMUTABLE_TYPES: try: for sub_obj in iter(obj): if is_mutable(sub_obj): return True except TypeError: pass return False