Source code for sgcache.path

import collections


_FieldPathSegment = collections.namedtuple('FieldPathSegment', 'type field')
[docs]class FieldPathSegment(_FieldPathSegment): """One segment of a :class:`FieldPath`. .. attribute:: type The entity type of this segment. .. attribute:: field The field name of this segment. """ def __str__(self): return '%s.%s' % self
[docs]class FieldPath(collections.Sequence): """A path in an API3 filter or return field; a sequence of :class:`FieldPathSegment` objects. :param input: A list of :class:`FieldPathSegment`, or a string. :param root_type: The entity type this field starts at; required if the input is a string. :: >>> path = FieldPath('entity.Shot.sg_sequence.Sequence.code', root_type='Task') >>> str(path) 'entity.Shot.sg_sequence.Sequence.code' >>> str(path[:1]) 'entity' >>> str(path[1:]) 'sg_sequence.Sequence.code' """ def __init__(self, input_, root_type=None): if isinstance(input_, basestring): assert root_type parts = input_.split('.') self.segments = segments = [FieldPathSegment(root_type, parts.pop(0))] while parts: segments.append(FieldPathSegment(parts.pop(0), parts.pop(0))) else: self.segments = input_[:] def __len__(self): return len(self.segments) def __getitem__(self, index): if isinstance(index, slice): return FieldPath(self.segments[index]) else: return self.segments[index]
[docs] def format(self, head=False, tail=True, _cached=True): """Stringify this path. :param bool head: Include the root entity type? :param bool tail: Include the final field name? :: >>> path = FieldPath('entity.Shot.code', root_type='Task') >>> path.format() 'entity.Shot.code' >>> path.format(head=True) 'Task.entity.Shot.code' >>> path.format(tail=False) 'entity.Shot' """ # If this is the very common case, cache it the first time. # Doing this results in cutting down 2/3 of the time to respond to # read queries that return 500 entities. if tail and not head and _cached: try: return self._format_cache except AttributeError: res = self._format_cache = self.format(_cached=False) return res len_ = len(self) if not len_: return '' if len_ == 1: if head and tail: return '%s.%s' % self[0] elif head: return self[0][0] elif tail: return self[0][1] else: raise ValueError('need head or tail when single-element path') parts = [] parts.append(('%s.%s' % self[0]) if head else self[0][1]) if len_ > 1: parts.extend('%s.%s' % x for x in self[1:-1]) parts.append(('%s.%s' % self[-1]) if tail else self[-1][0]) return '.'.join(parts)
def __str__(self): return self.format() def __repr__(self): return '<%s %s>' % (self.__class__.__name__, self)