class TracListing(Container): """Content class for trac listing""" implements(ITracListing) def __init__(self, id=None, **kwargs): super(TracListing, self).__init__(id, **kwargs) # manage an index of parent-to-child, int parent ticket id key # to PersistentList of int ticket id value: self._children = IOBTree() # indexes for score and reward-ratio values: self._scores = IIBTree() # int (ticket#) -> int (sum/score) self._reward = IOBTree() # int (ticket#) -> float (ratio) def index_parent_child(self, parent, child=None): if ITracTicket.providedBy(parent): parent = parent.getId() if ITracTicket.providedBy(child): child = child.getId() parent = int(parent) child = int(child) if child else None self._children[parent] = self._children.get(parent, PersistentList()) if child is not None: self._children[parent].append(child) def _adapter(self): if getattr(self, '_v_trac_adapter', None) is None: self._v_trac_adapter = TracTickets(self) # adapt once return self._v_trac_adapter def select(self, query): return self._adapter().select(query) def _add(self, ticket_number, adapter=None): adapter = adapter or self._adapter() # generated id from title will be str(ticket_number), we # then change the title in sync after creation. content = createContentInContainer( self, portal_type='uu.trac.ticket', title=unicode(ticket_number), ) content.sync() # check for and recursively add child tickets: childq = 'parent=~#%s' % ticket_number children = adapter.select(childq) for child_id in children: self._add(child_id, adapter) def sync(self): adapter = self._adapter() self._children = IOBTree() # reset all parent/child refs q = 'status!=closed' for number in adapter.select(q): if str(number) not in self.objectIds(): if number in (self.visible_tickets or []): self._add(number, adapter) else: self.get(str(number)).sync() def children_for(self, ticket_number): return list(self._children.get(int(ticket_number), [])) def result(self, reward=False): """ Return sorted listing of tuples with ticket number, score. If reward is True, use reward-ratio instead of score. """ keyfn = lambda t: t[1] # sort function, on score, not ticket _sorted = lambda l: sorted(l, key=keyfn, reverse=True) _visible = lambda t: t[0] in self.visible_tickets if reward: return _sorted(filter(_visible, self._reward.items())) return _sorted(filter(_visible, self._scores.items())) def index(self, ticket): if not ITracTicket.providedBy(ticket): ticket = self.get(int(ticket)) tid = int(ticket.getId()) parent = ticket.parent if parent: self.index_parent_child(parent, tid) self._scores[tid] = ticket.score() self._reward[tid] = ticket.reward_ratio()
class BooleanIndex(UnIndex): """Index for booleans self._index = set([documentId1, documentId2]) self._unindex = {documentId:[True/False]} False doesn't have actual entries in _index. """ meta_type = "BooleanIndex" manage_options = ( { 'label': 'Settings', 'action': 'manage_main' }, { 'label': 'Browse', 'action': 'manage_browse' }, ) query_options = ["query"] manage = manage_main = DTMLFile('dtml/manageBooleanIndex', globals()) manage_main._setName('manage_main') manage_browse = DTMLFile('../dtml/browseIndex', globals()) def clear(self): self._length = BTrees.Length.Length() self._index = IITreeSet() self._unindex = IIBTree() def insertForwardIndexEntry(self, entry, documentId): """If True, insert directly into treeset """ if entry: self._index.insert(documentId) self._length.change(1) def removeForwardIndexEntry(self, entry, documentId): """Take the entry provided and remove any reference to documentId in its entry in the index. """ try: if entry: self._index.remove(documentId) self._length.change(-1) except ConflictError: raise except Exception: LOG.exception( '%s: unindex_object could not remove ' 'documentId %s from index %s. This ' 'should not happen.' % (self.__class__.__name__, str(documentId), str(self.id))) def _index_object(self, documentId, obj, threshold=None, attr=''): """ index and object 'obj' with integer id 'documentId'""" returnStatus = 0 # First we need to see if there's anything interesting to look at datum = self._get_object_datum(obj, attr) # Make it boolean, int as an optimization if datum is not _marker: datum = int(bool(datum)) # We don't want to do anything that we don't have to here, so we'll # check to see if the new and existing information is the same. oldDatum = self._unindex.get(documentId, _marker) if datum != oldDatum: if oldDatum is not _marker: self.removeForwardIndexEntry(oldDatum, documentId) if datum is _marker: try: del self._unindex[documentId] except ConflictError: raise except Exception: LOG.error('Should not happen: oldDatum was there, now ' 'its not, for document with id %s' % documentId) if datum is not _marker: if datum: self.insertForwardIndexEntry(datum, documentId) self._unindex[documentId] = datum returnStatus = 1 return returnStatus def _apply_index(self, request, resultset=None): record = parseIndexRequest(request, self.id, self.query_options) if record.keys is None: return None index = self._index for key in record.keys: if key: # If True, check index return (intersection(index, resultset), (self.id, )) else: # Otherwise, remove from resultset or _unindex if resultset is None: return (union(difference(self._unindex, index), IISet([])), (self.id, )) else: return (difference(resultset, index), (self.id, )) return (IISet(), (self.id, )) def indexSize(self): """Return distinct values, as an optimization we always claim 2.""" return 2 def items(self): items = [] for v, k in self._unindex.items(): if isinstance(v, int): v = IISet((v, )) items.append((k, v)) return items