1 from collections import namedtuple
3 from ...util import ordered
6 Revert = namedtuple("Revert", ['reverting', 'reverteds', 'reverted_to'])
8 Represents a revert event. This class behaves like
9 :class:`collections.namedtuple`. Note that the datatypes of `reverting`,
10 `reverteds` and `reverted_to` is not specified since those types will depend
11 on the revision data provided during revert detection.
15 The reverting revision data : `mixed`
17 The reverted revision data (ordered chronologically) : list( `mixed` )
19 The reverted-to revision data : `mixed`
23 class Detector(ordered.HistoricalMap):
25 Detects revert events in a stream of revisions (to the same page) based on
26 matching checksums. To detect reverts, construct an instance of this class and call
27 :meth:`process` in chronological order (``direction == "newer"``).
29 See `<https://meta.wikimedia.org/wiki/R:Identity_revert>`_
33 a positive integer indicating the maximum revision distance that a revert can span.
36 >>> from mw.lib import reverts
37 >>> detector = reverts.Detector()
39 >>> detector.process("aaa", {'rev_id': 1})
40 >>> detector.process("bbb", {'rev_id': 2})
41 >>> detector.process("aaa", {'rev_id': 3})
42 Revert(reverting={'rev_id': 3}, reverteds=[{'rev_id': 2}], reverted_to={'rev_id': 1})
43 >>> detector.process("ccc", {'rev_id': 4})
47 def __init__(self, radius=defaults.RADIUS):
51 a positive integer indicating the maximum revision distance that a revert can span.
54 raise TypeError("invalid radius. Expected a positive integer.")
55 super().__init__(maxlen=radius + 1)
57 def process(self, checksum, revision=None):
59 Process a new revision and detect a revert if it occurred. Note that
60 you can pass whatever you like as `revision` and it will be returned in
61 the case that a revert occurs.
65 Any identity-machable string-based hash of revision content
67 Revision meta data. Note that any data will just be returned in the
71 a :class:`~mw.lib.reverts.Revert` if one occured or `None`
75 if checksum in self: # potential revert
77 reverteds = list(self.up_to(checksum))
79 if len(reverteds) > 0: # If no reverted revisions, this is a noop
80 revert = Revert(revision, reverteds, self[checksum])
82 self.insert(checksum, revision)