in src/python/pants/base/hash_utils.py [0:0]
def default(self, o):
if self._is_natively_encodable(o):
# isinstance() checks are expensive, particularly for abstract base classes such as Mapping:
# https://stackoverflow.com/questions/42378726/why-is-checking-isinstancesomething-mapping-so-slow
# This means that, if we let natively encodable types all through, we incur a performance hit, since
# we call this function very often.
# TODO(#7658) Figure out why we call this function so often.
return o
if isinstance(o, Mapping):
# Preserve order to avoid collisions for OrderedDict inputs to json.dumps(). We don't do this
# for general mappings because dicts have an arbitrary key ordering in some versions of python
# 3 (2.7 and 3.6-3.7 are known to have sorted keys, but with different definitions of sorted
# orders across versions, including insertion order). We want unordered dicts to collide if
# they have the same keys, in the same way we special-case sets below. Calling sorted() should
# be very fast if the keys happen to be pre-sorted. Pants options don't support OrderedDict
# inputs, and allowing them creates an ambiguity we don't need to deal with right now. See
# discussion in #6475.
if isinstance(o, OrderedDict):
raise TypeError('{cls} does not support OrderedDict inputs: {val!r}.'
.format(cls=type(self).__name__, val=o))
# TODO(#7082): we can remove the sorted() and OrderedDict when we drop python 2.7 and simply
# ensure we encode the keys/values as we do right here.
ordered_kv_pairs = sorted(o.items(), key=lambda x: x[0])
return OrderedDict(
(self._maybe_encode_dict_key(k), self.default(v))
for k, v in ordered_kv_pairs)
if isinstance(o, Set):
# We disallow OrderedSet (although it is not a stdlib collection) for the same reasons as
# OrderedDict above.
if isinstance(o, OrderedSet):
raise TypeError('{cls} does not support OrderedSet inputs: {val!r}.'
.format(cls=type(self).__name__, val=o))
# Set order is arbitrary in python 3.6 and 3.7, so we need to keep this sorted() call.
return sorted(self.default(i) for i in o)
if isinstance(o, DatatypeMixin):
# datatype objects will intentionally raise in the __iter__ method, but the Iterable abstract
# base class will match any class with any superclass that has the attribute __iter__ in the
# __dict__ (see https://docs.python.org/2/library/abc.html), so we need to check for it
# specially here.
# TODO: determine if the __repr__ should be some abstractmethod on DatatypeMixin!
return self.default(repr(o))
if isinstance(o, Iterable) and not isinstance(o, (bytes, list, str)):
return list(self.default(i) for i in o)
logger.debug("Our custom json encoder {} is trying to hash a primitive type, but has gone through"
"checking every other registered type class before. These checks are expensive,"
"so you should consider registering the type {} within"
"this function ({}.default)".format(type(self).__name__, type(o), type(self).__name__))
return o