]> code.communitydata.science - rises_declines_wikia_code.git/blob - mediawiki_dump_tools/Mediawiki-Utilities/mw/database/collections/recent_changes.py
Initial commit
[rises_declines_wikia_code.git] / mediawiki_dump_tools / Mediawiki-Utilities / mw / database / collections / recent_changes.py
1 import logging
2 import time
3
4 from ...types import Timestamp
5 from ...util import none_or
6 from .collection import Collection
7
8 logger = logging.getLogger("mw.database.collections.pages")
9
10
11 class RecentChanges(Collection):
12     # (https://www.mediawiki.org/wiki/Manual:Recentchanges_table)
13     TYPES = {
14         'edit': 0,  # edit of existing page
15         'new': 1,  # new page
16         'move': 2,  # Marked as obsolete
17         'log': 3,  # log action (introduced in MediaWiki 1.2)
18         'move_over_redirect': 4,  # Marked as obsolete
19         'external': 5  # An external recent change. Primarily used by Wikidata
20     }
21
22     def listen(self, last=None, types=None, max_wait=5):
23         """
24         Listens to the recent changes table.  Given no parameters, this function
25         will return an iterator over the entire recentchanges table and then
26         continue to "listen" for new changes to come in every 5 seconds.
27
28         :Parameters:
29             last : dict
30                 a recentchanges row to pick up after
31             types : set ( str )
32                 a set of recentchanges types to filter for
33             max_wait : float
34                 the maximum number of seconds to wait between repeated queries
35
36         :Returns:
37             A never-ending iterator over change rows.
38         """
39         while True:
40             if last is not None:
41                 after = last['rc_timestamp']
42                 after_id = last['rc_id']
43             else:
44                 after = None
45                 after_id = None
46
47             start = time.time()
48             rcs = self.query(after=after, after_id=after_id, direction="newer")
49
50             count = 0
51             for rc in rcs:
52                 yield rc
53                 count += 1
54
55             time.sleep(max_wait - (time.time() - start))
56
57     def query(self, before=None, after=None, before_id=None, after_id=None,
58               types=None, direction=None, limit=None):
59         """
60         Queries the ``recentchanges`` table.  See
61         `<https://www.mediawiki.org/wiki/Manual:Recentchanges_table>`_
62
63         :Parameters:
64             before : :class:`mw.Timestamp`
65                 The maximum timestamp
66             after : :class:`mw.Timestamp`
67                 The minimum timestamp
68             before_id : int
69                 The minimum ``rc_id``
70             after_id : int
71                 The maximum ``rc_id``
72             types : set ( str )
73                 Which types of changes to return?
74
75                 * ``edit`` -- Edits to existing pages
76                 * ``new`` -- Edits that create new pages
77                 * ``move`` -- (obsolete)
78                 * ``log`` -- Log actions (introduced in MediaWiki 1.2)
79                 * ``move_over_redirect`` -- (obsolete)
80                 * ``external`` -- An external recent change. Primarily used by Wikidata
81
82             direction : str
83                 "older" or "newer"
84             limit : int
85                 limit the number of records returned
86         """
87         before = none_or(before, Timestamp)
88         after = none_or(after, Timestamp)
89         before_id = none_or(before_id, int)
90         after_id = none_or(after_id, int)
91         types = none_or(types, levels=self.TYPES)
92         direction = none_or(direction, levels=self.DIRECTIONS)
93         limit = none_or(limit, int)
94
95         query = """
96             SELECT * FROM recentchanges
97             WHERE 1
98         """
99         values = []
100
101         if before is not None:
102             query += " AND rc_timestamp < %s "
103             values.append(before.short_format())
104         if after is not None:
105             query += " AND rc_timestamp < %s "
106             values.append(after.short_format())
107         if before_id is not None:
108             query += " AND rc_id < %s "
109             values.append(before_id)
110         if after_id is not None:
111             query += " AND rc_id < %s "
112             values.append(after_id)
113         if types is not None:
114             query += " AND rc_type IN ({0}) ".format(
115                 ",".join(self.TYPES[t] for t in types)
116             )
117
118         if direction is not None:
119             direction = ("ASC " if direction == "newer" else "DESC ")
120             query += " ORDER BY rc_timestamp {0}, rc_id {0}".format(dir)
121
122         if limit is not None:
123             query += " LIMIT %s "
124             values.append(limit)
125
126         cursor.execute(query, values)
127         for row in cursor:
128             yield row

Community Data Science Collective || Want to submit a patch?