'Retrain autotaggers'

def _retrain(self, tags=None):

    (session, config, idx) = (self.session, self.session.config, self._idx())
    tags = (tags or [asb.match_tag for asb in autotag_configs(config)])
    tids = [config.get_tag(t)._key for t in tags if t]
    session.ui.mark(_('Retraining    SpamBayes    autotaggers'))
    if (not config.real_hasattr('autotag')):
        config.real_setattr('autotag', {})
    no_trash = [('-in:%s' % t._key) for t in config.get_tags(type='trash')]
    interest = {}
    for ttype in ('replied', 'read', 'tagged'):
        interest[ttype] = set()
        for tag in config.get_tags(type=ttype):
            interest[ttype] |= idx.search(session, ([('in:%s' % tag.slug)] + no_trash)).as_set()
        session.ui.notify((_('Have    %d    interesting    %s    messages') % (len(interest[ttype]), ttype)))
    (retrained, unreadable) = ([], [])
    count_all = 0
    for at_config in autotag_configs(config):
        at_tag = config.get_tag(at_config.match_tag)
        if (at_tag and (at_tag._key in tids)):
            session.ui.mark(('Retraining:    %s' % at_tag.name))
            yn = [(set(), set(), ('in:%s' % at_tag.slug), True), (set(), set(), ('-in:%s' % at_tag.slug), False)]
            for (tset, mset, srch, which) in yn:
                mset |= idx.search(session, ([srch] + no_trash)).as_set()
            interesting = []
            for etagid in at_config.exclude_tags:
                etag = config.get_tag(etagid)
                if (etag._key not in interest):
                    srch = ([('in:%s' % etag._key)] + no_trash)
                    interest[etag._key] = idx.search(session, srch).as_set()
                interesting.append(etag._key)
            interesting.extend(['replied', 'read', 'tagged', None])
            for ttype in interesting:
                for (tset, mset, srch, which) in yn:
                    full_size = int((at_config.corpus_size * (0.33 if which else 0.67)))
                    want = min((full_size // len(interesting)), max(0, (full_size - len(tset))))
                    if ((full_size > len(tset)) and (not ttype)):
                        want = (full_size - len(tset))
                    if want:
                        if ttype:
                            adding = sorted(list((mset & interest[ttype])))
                        else:
                            adding = sorted(list(mset))
                        adding = set(list(reversed(adding))[:want])
                        tset |= adding
                        mset -= adding
            atagger = config.load_auto_tagger(at_config)
            atagger.reset(at_config)
            for (tset, mset, srch, which) in yn:
                count = 0
                for msg_idx in sorted(list(tset)):
                    try:
                        e = Email(idx, msg_idx)
                        count += 1
                        count_all += 1
                        session.ui.mark((_('Reading    %s    (%d/%d,    %s=%s)') % (e.msg_mid(), count, len(tset), at_tag.name, which)))
                        atagger.learn(at_config, e.get_msg(), self._get_keywords(e), which)
                        play_nice_with_threads()
                        if mailpile.util.QUITTING:
                            return self._error('Aborted')
                    except (IndexError, TypeError, ValueError, OSError, IOError):
                        if ('autotag' in session.config.sys.debug):
                            import traceback
                            traceback.print_exc()
                        unreadable.append(msg_idx)
                        session.ui.warning((_('Failed    to    process    message    at    =%s') % b36(msg_idx)))
            config.save_auto_tagger(at_config)
            retrained.append(at_tag.name)
    message = (_('Retrained    SpamBayes    auto-tagging    for    %s') % ',    '.join(retrained))
    session.ui.mark(message)
    return self._success(message, result={'retrained': retrained, 'unreadable': unreadable, 'read_messages': count_all})
