Alex S.H. Lin has submitted this change and it was merged.
Change subject: [PEP8] changes, remove obsolete imports, code improvements
......................................................................
[PEP8] changes, remove obsolete imports, code improvements
Change-Id: I450e8ec7b81b4c353e9f4216ee6c5903089e8913
---
M imagecopy_self.py
1 file changed, 399 insertions(+), 360 deletions(-)
Approvals:
Alex S.H. Lin: Verified; Looks good to me, approved
diff --git a/imagecopy_self.py b/imagecopy_self.py
index 26765c7..cf0c810 100644
--- a/imagecopy_self.py
+++ b/imagecopy_self.py
@@ -44,57 +44,58 @@
# (C) Multichill 2008
#
# English Wikipedia specific bot by:
-# (C) Multichill 2010
+# (C) Multichill 2010-2012
#
-# (C) Pywikipedia bot team, 2003-2011
+# (C) Pywikibot team, 2010-2013
#
# Distributed under the terms of the MIT license.
#
-__version__='$Id$'
+__version__ = '$Id$'
#
from Tkinter import *
-import os, sys, re, codecs
-import urllib, httplib, urllib2
+import sys
+import re
+import codecs
import webbrowser
-from Queue import Queue
-import time, threading
-import wikipedia as pywikibot
-import config, socket
-import pagegenerators, add_text
-import imagerecat
+import threading
from datetime import datetime
+
+import wikipedia as pywikibot
+import pagegenerators
+import add_text
+import imagerecat
from upload import *
from image import *
from pywikibot import i18n
-NL=''
+NL = ''
nowCommonsTemplate = {
- 'de' : u'{{NowCommons|%s}}',
- 'en' :
u'{{NowCommons|1=File:%s|date=~~~~~|reviewer={{subst:REVISIONUSER}}}}',
- 'lb' : u'{{Elo op Commons|%s}}',
- 'nds-nl' : u'{{NoenCommons|1=File:%s}}',
- 'shared' :
u'{{NowCommons|1=File:%s|date=~~~~~|reviewer={{subst:REVISIONUSER}}}}',
+ 'de': u'{{NowCommons|%s}}',
+ 'en':
u'{{NowCommons|1=File:%s|date=~~~~~|reviewer={{subst:REVISIONUSER}}}}',
+ 'lb': u'{{Elo op Commons|%s}}',
+ 'nds-nl': u'{{NoenCommons|1=File:%s}}',
+ 'shared':
u'{{NowCommons|1=File:%s|date=~~~~~|reviewer={{subst:REVISIONUSER}}}}',
}
moveToCommonsTemplate = {
- 'de' : [u'NowCommons', u'NC', u'NCT',
u'Nowcommons'],
- 'en' : [u'Commons ok', u'Copy to Wikimedia Commons',
u'Move to commons', u'Movetocommons', u'To commons', u'Copy to
Wikimedia Commons by BotMultichill'],
- 'lb' : [u'Move to commons'],
- 'nds-nl' : [u'Noar Commons', u'VNC'],
- 'shared' : [u'Move'],
+ 'de': [u'NowCommons', u'NC', u'NCT',
u'Nowcommons'],
+ 'en': [u'Commons ok', u'Copy to Wikimedia Commons',
u'Move to commons', u'Movetocommons', u'To commons', u'Copy to
Wikimedia Commons by BotMultichill'],
+ 'lb': [u'Move to commons'],
+ 'nds-nl': [u'Noar Commons', u'VNC'],
+ 'shared': [u'Move'],
}
skipTemplates = {
- 'de' : [u'Löschprüfung',
- u'NoCommons',
- u'NowCommons',
- u'NowCommons/Mängel',
- u'NowCommons-Überprüft',
- u'Wappenrecht',
- ],
- 'en' :[u'Db-f1',
+ 'de': [u'Löschprüfung',
+ u'NoCommons',
+ u'NowCommons',
+ u'NowCommons/Mängel',
+ u'NowCommons-Überprüft',
+ u'Wappenrecht',
+ ],
+ 'en': [u'Db-f1',
u'Db-f2',
u'Db-f3',
u'Db-f7',
@@ -127,148 +128,164 @@
u'PUI',
u'Pui',
u'Ffd',
- u'PD-user', # Only the self templates are supported for now.
+ u'PD-user', # Only the self templates are supported for now.
u'Ticket Scan',
u'Non-free 2D art',
u'Non-free 3D art',
u'Non-free architectural work',
u'Non-free fair use in',
],
- 'lb' : [u'Läschen',
- ],
- 'nds-nl' : [u'Allinnig Wikipedie',
- u'Bepark',
- u'Gienidee',
- u'NoenCommons',
- u'NowCommons',
- ],
- 'shared' : [u''],
- }
+ 'lb': [u'Läschen',
+ ],
+ 'nds-nl': [u'Allinnig Wikipedie',
+ u'Bepark',
+ u'Gienidee',
+ u'NoenCommons',
+ u'NowCommons',
+ ],
+ 'shared': [u''],
+}
licenseTemplates = {
- 'de' :
[(u'\{\{Bild-CC-by-sa/3\.0/de\}\}[\s\r\n]*\{\{Bild-CC-by-sa/3\.0\}\}[\s\r\n]*\{\{Bild-GFDL-Neu\}\}',
u'{{Self|Cc-by-sa-3.0-de|Cc-by-sa-3.0|GFDL|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{Bild-GFDL\}\}[\s\r\n]*\{\{Bild-CC-by-sa/(\d\.\d)\}\}',
u'{{Self|GFDL|Cc-by-sa-3.0-migrated|Cc-by-sa-\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{Bild-GFDL\}\}',
u'{{Self|GFDL|Cc-by-sa-3.0-migrated|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{Bild-CC-by-sa/(\d\.\d)\}\}',
u'{{Self|Cc-by-sa-\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{Bild-CC-by-sa/(\d\.\d)/de\}\}',
u'{{Self|Cc-by-sa-\\1-de|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{Bild-CC-by/(\d\.\d)\}\}',
u'{{Self|Cc-by-\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{Bild-CC-by/(\d\.\d)/de\}\}',
u'{{Self|Cc-by-\\1-de|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
-
- ],
- 'en' : [(u'\{\{(self|self2)\|([^\}]+)\}\}',
u'{{Self|\\2|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{(GFDL-self|GFDL-self-no-disclaimers)\|([^\}]+)\}\}',
u'{{Self|GFDL|\\2|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{GFDL-self-with-disclaimers\|([^\}]+)\}\}',
u'{{Self|GFDL-with-disclaimers|\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{PD-self(\|date=[^\}]+)?\}\}',
u'{{PD-user-w|%(lang)s|%(family)s|%(author)s}}'),
- (u'\{\{Multilicense replacing
placeholder(\|[^\}\|=]+=[^\}\|]+)*(?P<migration>\|[^\}\|=]+=[^\}\|]+)(\|[^\}\|=]+=[^\}\|]+)*\}\}',
u'{{Self|GFDL|Cc-by-sa-2.5,2.0,1.0\\g<migration>|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- (u'\{\{Multilicense replacing placeholder new(\|class=[^\}]+)?\}\}',
u'{{Self|GFDL|Cc-by-sa-3.0,2.5,2.0,1.0|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- ],
- 'lb' : [(u'\{\{(self|self2)\|([^\}]+)\}\}',
u'{{Self|\\2|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
- ],
- 'nds-nl' : [(u'\{\{PD-eigenwark\}\}',
u'{{PD-user-w|%(lang)s|%(family)s|%(author)s}}'),
- ],
- 'shared' : [(u'\{\{(self|self2)\|([^\}]+)\}\}',
u'{{Self|\\2|author=%(author)s at old wikivoyage shared}}'),
- ],
- }
+ 'de':
[(u'\{\{Bild-CC-by-sa/3\.0/de\}\}[\s\r\n]*\{\{Bild-CC-by-sa/3\.0\}\}[\s\r\n]*\{\{Bild-GFDL-Neu\}\}',
+
u'{{Self|Cc-by-sa-3.0-de|Cc-by-sa-3.0|GFDL|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{Bild-GFDL\}\}[\s\r\n]*\{\{Bild-CC-by-sa/(\d\.\d)\}\}',
+
u'{{Self|GFDL|Cc-by-sa-3.0-migrated|Cc-by-sa-\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{Bild-GFDL\}\}',
+
u'{{Self|GFDL|Cc-by-sa-3.0-migrated|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{Bild-CC-by-sa/(\d\.\d)\}\}',
+ u'{{Self|Cc-by-sa-\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{Bild-CC-by-sa/(\d\.\d)/de\}\}',
+ u'{{Self|Cc-by-sa-\\1-de|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{Bild-CC-by/(\d\.\d)\}\}',
+ u'{{Self|Cc-by-\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{Bild-CC-by/(\d\.\d)/de\}\}',
+ u'{{Self|Cc-by-\\1-de|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ ],
+ 'en': [(u'\{\{(self|self2)\|([^\}]+)\}\}',
+ u'{{Self|\\2|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{(GFDL-self|GFDL-self-no-disclaimers)\|([^\}]+)\}\}',
+ u'{{Self|GFDL|\\2|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{GFDL-self-with-disclaimers\|([^\}]+)\}\}',
+
u'{{Self|GFDL-with-disclaimers|\\1|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{PD-self(\|date=[^\}]+)?\}\}',
+ u'{{PD-user-w|%(lang)s|%(family)s|%(author)s}}'),
+ (u'\{\{Multilicense replacing
placeholder(\|[^\}\|=]+=[^\}\|]+)*(?P<migration>\|[^\}\|=]+=[^\}\|]+)(\|[^\}\|=]+=[^\}\|]+)*\}\}',
+
u'{{Self|GFDL|Cc-by-sa-2.5,2.0,1.0\\g<migration>|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ (u'\{\{Multilicense replacing placeholder new(\|class=[^\}]+)?\}\}',
+
u'{{Self|GFDL|Cc-by-sa-3.0,2.5,2.0,1.0|author=[[:%(lang)s:User:%(author)s|%(author)s]]
at [http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ ],
+ 'lb': [(u'\{\{(self|self2)\|([^\}]+)\}\}',
u'{{Self|\\2|author=[[:%(lang)s:User:%(author)s|%(author)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]}}'),
+ ],
+ 'nds-nl': [(u'\{\{PD-eigenwark\}\}',
u'{{PD-user-w|%(lang)s|%(family)s|%(author)s}}'),
+ ],
+ 'shared': [(u'\{\{(self|self2)\|([^\}]+)\}\}',
u'{{Self|\\2|author=%(author)s at old wikivoyage shared}}'),
+ ],
+}
sourceGarbage = {
- 'de' : [u'==\s*Beschreibung,\sQuelle\s*==',
- u'==\s*Beschrieving\s*==',
- u'==\s*\[\[Wikipedia:Lizenzvorlagen für Bilder\|Lizenz\]\]\s*==',
- ],
+ 'de': [u'==\s*Beschreibung,\sQuelle\s*==',
+ u'==\s*Beschrieving\s*==',
+ u'==\s*\[\[Wikipedia:Lizenzvorlagen für Bilder\|Lizenz\]\]\s*==',
+ ],
'en': [u'==\s*Description\s*==',
u'==\s*Summary\s*==',
u'==\s*Licensing:?\s*==',
- u'\{\{(Copy to Wikimedia Commons|Move to Commons|Move to commons|Move to
Wikimedia Commons|Copy to commons|Mtc|MtC|MTC|CWC|CtWC|CTWC|Ctwc|Tocommons|Copy to
Commons|To Commons|Movetocommons|Move to Wikimedia commons|Move-to-commons|Commons
ok|ToCommons|To commons|MoveToCommons|Copy to wikimedia commons|Upload to
commons|CopyToCommons|Copytocommons|MITC|MovetoCommons|Do move to Commons|Orphan
image)(\|[^\}]+)?\}\}'
+ u'\{\{'
+ u'(Copy to Wikimedia Commons|Move to Commons|Move to commons|'
+ u'Move to Wikimedia Commons|Copy to commons|Mtc|MtC|MTC|CWC|CtWC|'
+ u'CTWC|Ctwc|Tocommons|Copy to Commons|To Commons|Movetocommons|'
+ u'Move to Wikimedia commons|Move-to-commons|Commons ok|ToCommons|'
+ u'To commons|MoveToCommons|Copy to wikimedia commons|'
+ u'Upload to commons|CopyToCommons|Copytocommons|MITC|MovetoCommons|'
+ u'Do move to Commons|Orphan image)'
+ u'(\|[^\}]+)?\}\}'
],
- 'lb' : [u'==\s*Résumé\s*==',
- u'==\s*Lizenz:\s*==',
- ],
- 'nds-nl' : [
- u'==\s*Licentie\s*==',
+ 'lb': [u'==\s*Résumé\s*==',
+ u'==\s*Lizenz:\s*==',
+ ],
+ 'nds-nl': [u'==\s*Licentie\s*==',
u'\{\{DEFAULTSORT:\{\{PAGENAME\}\}\}\}',
],
- 'shared' : [u'==\s*Beschreibung,\sQuelle\s*==',
- u'==\s*Licensing:?\s*==',
- ],
- }
+ 'shared': [u'==\s*Beschreibung,\sQuelle\s*==',
+ u'==\s*Licensing:?\s*==',
+ ],
+}
informationTemplate = {
- 'de' : 'Information',
- 'en' : 'Information',
- 'nds-nl' : 'Information',
- 'shared' : 'Information',
- }
+ 'de': 'Information',
+ 'en': 'Information',
+ 'nds-nl': 'Information',
+ 'shared': 'Information',
+}
informationFields = {
- 'de' : {
- u'anmerkungen' : u'remarks', #FIXME: More flexible
- u'beschreibung' : u'description',
- u'quelle' : u'source',
- u'datum' : u'date',
- u'urheber' : u'author',
- u'permission' : u'permission',
- u'andere Versione' : u'other versions',
- },
- 'en' : {
- u'location' : u'remarks',
- u'description' : u'description',
- u'source' : u'source',
- u'date' : u'date',
- u'author' : u'author',
- u'permission' : u'permission',
- u'other versions' : u'other versions',
- },
- 'nds-nl' : {
- u'location' : u'remarks',
- u'description' : u'description',
- u'source' : u'source',
- u'date' : u'date',
- u'author' : u'author',
- u'permission' : u'permission',
- u'other versions' : u'other versions',
- },
- 'shared' : {
- u'description' : u'description',
- u'source' : u'source',
- u'date' : u'date',
- u'author' : u'author',
- u'permission' : u'permission',
- u'other versions' : u'other versions',
- },
- }
-
+ 'de': {
+ u'anmerkungen': u'remarks', # FIXME: More flexible
+ u'beschreibung': u'description',
+ u'quelle': u'source',
+ u'datum': u'date',
+ u'urheber': u'author',
+ u'permission': u'permission',
+ u'andere Versione': u'other versions',
+ },
+ 'en': {
+ u'location': u'remarks',
+ u'description': u'description',
+ u'source': u'source',
+ u'date': u'date',
+ u'author': u'author',
+ u'permission': u'permission',
+ u'other versions': u'other versions',
+ },
+ 'nds-nl': {
+ u'location': u'remarks',
+ u'description': u'description',
+ u'source': u'source',
+ u'date': u'date',
+ u'author': u'author',
+ u'permission': u'permission',
+ u'other versions': u'other versions',
+ },
+ 'shared': {
+ u'description': u'description',
+ u'source': u'source',
+ u'date': u'date',
+ u'author': u'author',
+ u'permission': u'permission',
+ u'other versions': u'other versions',
+ },
+}
def supportedSite():
- '''
+ """
Check if this site is supported
- '''
- site=pywikibot.getSite()
- lang=site.language()
+ """
+ site = pywikibot.getSite()
+ lang = site.language()
- lists = [nowCommonsTemplate,
- moveToCommonsTemplate,
- skipTemplates,
- licenseTemplates,
- sourceGarbage,
- ]
-
+ lists = [
+ nowCommonsTemplate,
+ moveToCommonsTemplate,
+ skipTemplates,
+ licenseTemplates,
+ sourceGarbage,
+ ]
for l in lists:
if not l.get(lang):
return False
-
return True
+
class imageFetcher(threading.Thread):
- '''
- Tries to fetch information for all images in the generator
- '''
- def __init__ ( self, pagegenerator, prefetchQueue):
+ """ Tries to fetch information for all images in the generator
"""
+ def __init__(self, pagegenerator, prefetchQueue):
self.pagegenerator = pagegenerator
self.prefetchQueue = prefetchQueue
imagerecat.initLists()
- threading.Thread.__init__ ( self )
+ threading.Thread.__init__(self)
def run(self):
for page in self.pagegenerator:
@@ -278,9 +295,9 @@
return True
def processImage(self, page):
- '''
+ """
Work on a single image
- '''
+ """
if page.exists() and (page.namespace() == 6) and \
(not page.isRedirectPage()):
imagepage = pywikibot.ImagePage(page.site(), page.title())
@@ -306,10 +323,11 @@
self.prefetchQueue.put(self.getNewFields(imagepage))
def doiskip(self, imagepage):
- '''
+ """
Skip this image or not.
Returns True if the image is on the skip list, otherwise False
- '''
+
+ """
for template in imagepage.templates():
if template in skipTemplates[imagepage.site().language()]:
pywikibot.output(
@@ -318,34 +336,35 @@
return False
def getNewFields(self, imagepage):
- '''
- Build a new description based on the imagepage
- '''
- if u'{{Information' in imagepage.get() or u'{{information' in
imagepage.get():
- (description, date, source, author, permission, other_versions) =
self.getNewFieldsFromInformation(imagepage)
+ """ Build a new description based on the imagepage
"""
+ if u'{{Information' in imagepage.get() or \
+ u'{{information' in imagepage.get():
+ (description, date, source, author, permission,
+ other_versions) = self.getNewFieldsFromInformation(imagepage)
else:
- (description, date, source, author) =
self.getNewFieldsFromFreetext(imagepage)
+ (description, date, source,
+ author) = self.getNewFieldsFromFreetext(imagepage)
permission = u''
other_versions = u''
licensetemplate = self.getNewLicensetemplate(imagepage)
categories = self.getNewCategories(imagepage)
- return {u'imagepage' : imagepage,
- u'filename' : imagepage.title(withNamespace=False),
- u'description' : description,
- u'date' : date,
- u'source' : source,
- u'author' : author,
- u'permission' : permission,
- u'other_versions' : other_versions,
- u'licensetemplate' : licensetemplate,
- u'categories' : categories,
- u'skip' : False}
+ return {u'imagepage': imagepage,
+ u'filename': imagepage.title(withNamespace=False),
+ u'description': description,
+ u'date': date,
+ u'source': source,
+ u'author': author,
+ u'permission': permission,
+ u'other_versions': other_versions,
+ u'licensetemplate': licensetemplate,
+ u'categories': categories,
+ u'skip': False}
def getNewFieldsFromInformation(self, imagepage):
- '''
+ """
Try to extract fields from the current information template for the new
information template.
- '''
+ """
#fields = [u'location', u'description', u'source',
u'date', u'author', u'permission', u'other versions']
#FIXME: The implementation for German has to be checked for the
"strange" fields
@@ -358,13 +377,14 @@
other_versions = u''
contents = {}
- for key, value in informationFields.get(imagepage.site().language()).items():
- contents[value]=u''
+ for key, value in informationFields.get(
+ imagepage.site().language()).items():
+ contents[value] = u''
templates = imagepage.templatesWithParams()
for (template, params) in templates:
- if template==u'Information':
+ if template == u'Information':
for param in params:
#Split at =
(field, sep, value) = param.partition(u'=')
@@ -379,47 +399,58 @@
# Description
# FIXME: Add {{<lang>|<original text>}} if <lang is valid at
Commons
- if not contents[u'description']==u'':
- description = self.convertLinks(contents[u'description'],
imagepage.site())
- if contents.get(u'remarks') and not
contents[u'remarks']==u'':
- if description==u'':
- description = self.convertLinks(contents[u'remarks'],
imagepage.site())
+ if contents[u'description']:
+ description = self.convertLinks(contents[u'description'],
+ imagepage.site())
+ if contents.get(u'remarks') and contents[u'remarks']:
+ if description == u'':
+ description = self.convertLinks(contents[u'remarks'],
+ imagepage.site())
else:
- description = description + u'<BR/>\n' +
self.convertLinks(contents[u'remarks'], imagepage.site())
+ description += u'<BR/>\n' + self.convertLinks(
+ contents[u'remarks'], imagepage.site())
# Source
- source = self.getSource(imagepage,
source=self.convertLinks(contents[u'source'], imagepage.site()))
+ source = self.getSource(imagepage,
+ source=self.convertLinks(contents[u'source'],
+ imagepage.site()))
# Date
- if not contents[u'date']==u'':
+ if contents[u'date']:
date = contents[u'date']
else:
date = self.getUploadDate(imagepage)
# Author
- if not (contents[u'author']==u'' or
contents[u'author']==self.getAuthor(imagepage)):
+ if not (contents[u'author'] == u'' or
+ contents[u'author'] == self.getAuthor(imagepage)):
author = self.convertLinks(contents[u'author'], imagepage.site())
else:
author = self.getAuthorText(imagepage)
# Permission
# Still have to filter out crap like "see below" or "yes"
- if not contents[u'permission']==u'':
+ if contents[u'permission']:
# Strip of the license temlate if it's in the permission section
for (regex, repl) in licenseTemplates[imagepage.site().language()]:
- contents[u'permission'] = re.sub(regex, u'',
contents[u'permission'], flags=re.IGNORECASE)
- permission = self.convertLinks(contents[u'permission'],
imagepage.site())
+ contents[u'permission'] = re.sub(regex, u'',
+ contents[u'permission'],
+ flags=re.IGNORECASE)
+ permission = self.convertLinks(contents[u'permission'],
+ imagepage.site())
# Other_versions
- if not contents[u'other versions']==u'':
- other_versions = self.convertLinks(contents[u'other versions'],
imagepage.site())
+ if contents[u'other versions']:
+ other_versions = self.convertLinks(contents[u'other versions'],
+ imagepage.site())
return (description, date, source, author, permission, other_versions)
def getNewFieldsFromFreetext(self, imagepage):
- '''
+ """
Try to extract fields from free text for the new information template.
- '''
+
+ """
text = imagepage.get()
#text = re.sub(u'== Summary ==', u'', text, re.IGNORECASE)
#text = re.sub(u'== Licensing ==', u'', text, re.IGNORECASE)
@@ -440,100 +471,103 @@
return (description, date, source, author)
def getUploadDate(self, imagepage):
- '''
- Get the original upload date to put in the date field of the new information
template. If we really have nothing better.
- '''
+ """
+ Get the original upload date to put in the date field of the new
+ information template. If we really have nothing better.
+
+ """
uploadtime = imagepage.getFileVersionHistory()[-1][0]
uploadDatetime = datetime.strptime(uploadtime, u'%Y-%m-%dT%H:%M:%SZ')
return u'{{Date|' + str(uploadDatetime.year) + u'|' +
str(uploadDatetime.month) + u'|' + str(uploadDatetime.day) + u'}} (original
upload date)'
def getSource(self, imagepage, source=u''):
- '''
+ """
Get the text to put in the source field of the new information template.
- '''
+
+ """
site = imagepage.site()
lang = site.language()
family = site.family.name
- if source==u'':
- source=u'{{Own}}'
+ if source == u'':
+ source = u'{{Own}}'
- return source.strip() + u'<BR />Transferred from
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]' % {u'lang' : lang,
u'family' : family}
+ return source.strip() + u'<BR />Transferred from
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]' \
+ % {u'lang': lang, u'family': family}
def getAuthorText(self, imagepage):
- '''
- Get the original uploader to put in the author field of the new information
template.
- '''
+ """
+ Get the original uploader to put in the author field of the new
+ information template.
+
+ """
site = imagepage.site()
lang = site.language()
family = site.family.name
firstuploader = self.getAuthor(imagepage)
- return u'[[:%(lang)s:User:%(firstuploader)s|%(firstuploader)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]' % {u'lang' : lang,
u'family' : family , u'firstuploader' : firstuploader}
+ return (u'[[:%(lang)s:User:%(firstuploader)s|%(firstuploader)s]] at
[http://%(lang)s.%(family)s.org %(lang)s.%(family)s]'
+ % {u'lang': lang, u'family': family,
+ u'firstuploader': firstuploader})
def getAuthor(self, imagepage):
- '''
- Get the first uploader.
- '''
+ """ Get the first uploader. """
return imagepage.getFileVersionHistory()[-1][1].strip()
def convertLinks(self, text, sourceSite):
- '''
- Convert links from the current wiki to Commons.
- '''
+ """ Convert links from the current wiki to Commons.
"""
lang = sourceSite.language()
family = sourceSite.family.name
- conversions =[(u'\[\[([^\[\]\|]+)\|([^\[\]\|]+)\]\]',
u'[[:%(lang)s:\\1|\\2]]'),
- (u'\[\[([^\[\]\|]+)\]\]',
u'[[:%(lang)s:\\1|\\1]]'),
- ]
-
+ conversions = [
+ (u'\[\[([^\[\]\|]+)\|([^\[\]\|]+)\]\]',
u'[[:%(lang)s:\\1|\\2]]'),
+ (u'\[\[([^\[\]\|]+)\]\]', u'[[:%(lang)s:\\1|\\1]]'),
+ ]
for (regex, replacement) in conversions:
- text = re.sub(regex, replacement % {u'lang' : lang,
u'family' : family}, text)
-
+ text = re.sub(regex, replacement % {u'lang': lang,
+ u'family': family}, text)
return text
def getNewLicensetemplate(self, imagepage):
- '''
- Get a license template to put on the image to be uploaded
- '''
+ """ Get a license template to put on the image to be uploaded
"""
text = imagepage.get()
-
site = imagepage.site()
lang = site.language()
family = site.family.name
-
result = u''
-
- for (regex, replacement) in licenseTemplates[imagepage.site().language()]:
+ for (regex,
+ replacement) in licenseTemplates[imagepage.site().language()]:
match = re.search(regex, text, flags=re.IGNORECASE)
if match:
- result = re.sub(regex, replacement, match.group(0), flags=re.IGNORECASE)
- return result % {u'author' : self.getAuthor(imagepage),
- u'lang' : lang,
- u'family' : family}
-
+ result = re.sub(regex, replacement, match.group(0),
+ flags=re.IGNORECASE)
+ return result % {u'author': self.getAuthor(imagepage),
+ u'lang': lang,
+ u'family': family}
return result
def getNewCategories(self, imagepage):
- '''
+ """
Get a categories for the image
Dont forget to filter
- '''
+
+ """
result = u''
- (commonshelperCats, usage, galleries) =
imagerecat.getCommonshelperCats(imagepage)
+ (commonshelperCats, usage,
+ galleries) = imagerecat.getCommonshelperCats(imagepage)
newcats = imagerecat.applyAllFilters(commonshelperCats)
for newcat in newcats:
- result = result + u'[[Category:' + newcat + u']] '
+ result += u'[[Category:' + newcat + u']] '
return result
+
class userInteraction(threading.Thread):
- '''
+ """
Prompt all images to the user.
- '''
- def __init__ ( self, prefetchQueue, uploadQueue):
+ """
+ def __init__(self, prefetchQueue, uploadQueue):
self.prefetchQueue = prefetchQueue
self.uploadQueue = uploadQueue
self.autonomous = False
- threading.Thread.__init__ ( self )
+ threading.Thread.__init__(self)
def run(self):
while True:
@@ -547,36 +581,39 @@
return True
def setAutonomous(self):
- '''
- Don't do any user interaction.
- '''
+ """ Don't do any user interaction. """
self.autonomous = True
return
def processImage(self, fields):
- '''
- Work on a single image
- '''
+ """ Work on a single image """
if self.autonomous:
- # Check if the image already exists. Do nothing if the name is already
taken.
- CommonsPage=pywikibot.Page(pywikibot.getSite('commons',
'commons'), u'File:' + fields.get('filename'))
+ # Check if the image already exists. Do nothing if the name is
+ # already taken.
+ CommonsPage = pywikibot.Page(pywikibot.getSite('commons',
+ 'commons'),
+ u'File:' +
fields.get('filename'))
if CommonsPage.exists():
return False
else:
while True:
# Do the Tkdialog to accept/reject and change te name
- fields=Tkdialog(fields).getnewmetadata()
+ fields = Tkdialog(fields).getnewmetadata()
if fields.get('skip'):
- pywikibot.output(u'Skipping %s : User pressed skip.' %
fields.get('imagepage').title())
+ pywikibot.output(u'Skipping %s : User pressed skip.'
+ % fields.get('imagepage').title())
return False
# Check if the image already exists
- CommonsPage=pywikibot.Page(pywikibot.getSite('commons',
'commons'), u'File:' + fields.get('filename'))
+ CommonsPage = pywikibot.Page(pywikibot.getSite('commons',
+ 'commons'),
+ u'File:' +
fields.get('filename'))
if not CommonsPage.exists():
break
else:
- pywikibot.output('Image already exists, pick another name or skip
this image')
+ pywikibot.output('Image already exists, pick another name '
+ 'or skip this image')
# We dont overwrite images, pick another name, go to the start of the
loop
# Put the fields in the queue to be uploaded
@@ -584,11 +621,13 @@
class Tkdialog:
- def __init__(self, fields): #imagepage, description, date, source, author,
licensetemplate, categories):
- self.root=Tk()
+
+ def __init__(self, fields): # imagepage, description, date, source, author,
licensetemplate, categories):
+ self.root = Tk()
#"%dx%d%+d%+d" % (width, height, xoffset, yoffset)
- #Always appear the same size and in the bottom-left corner
- #FIXME : Base this on the screen size or make it possible for the user to
configure this
+ # Always appear the same size and in the bottom-left corner
+ # FIXME : Base this on the screen size or make it possible for the user
+ # to configure this
# Get all the relevant fields
self.imagepage = fields.get('imagepage')
@@ -609,10 +648,10 @@
self.root.geometry("1500x400+100-100")
self.root.title(self.filename)
- self.url=self.imagepage.permalink()
- self.scrollbar=Scrollbar(self.root, orient=VERTICAL)
+ self.url = self.imagepage.permalink()
+ self.scrollbar = Scrollbar(self.root, orient=VERTICAL)
- self.old_description=Text(self.root)
+ self.old_description = Text(self.root)
self.old_description.insert(END, self.imagepage.get().encode('utf-8'))
self.old_description.config(state=DISABLED, height=8, width=140, padx=0, pady=0,
wrap=WORD, yscrollcommand=self.scrollbar.set)
@@ -646,7 +685,7 @@
self.information_licensetemplate = Entry(self.root)
self.information_categories = Entry(self.root)
- self.field_width=120
+ self.field_width = 120
self.filename_field.config(width=self.field_width)
self.information_description.config(width=self.field_width)
@@ -658,7 +697,6 @@
self.information_licensetemplate.config(width=self.field_width)
self.information_categories.config(width=self.field_width)
-
self.filename_field.insert(0, self.filename)
self.information_description.insert(0, self.description)
self.information_date.insert(0, self.date)
@@ -669,10 +707,10 @@
self.information_licensetemplate.insert(0, self.licensetemplate)
self.information_categories.insert(0, self.categories)
- self.browserButton=Button(self.root, text='View in browser',
- command=self.openInBrowser)
- self.skipButton=Button(self.root, text="Skip", command=self.skipFile)
- self.okButton=Button(self.root, text="OK", command=self.okFile)
+ self.browserButton = Button(self.root, text='View in browser',
+ command=self.openInBrowser)
+ self.skipButton = Button(self.root, text="Skip",
command=self.skipFile)
+ self.okButton = Button(self.root, text="OK", command=self.okFile)
##Start grid
self.old_description_label.grid(row=0, column=0, columnspan=3)
@@ -709,75 +747,66 @@
self.browserButton.grid(row=12, column=1, rowspan=2)
def okFile(self):
- '''
- The user pressed the OK button.
- '''
- self.filename=self.filename_field.get()
- self.description=self.information_description.get()
- self.date=self.information_date.get()
- self.source=self.information_source.get()
- self.author=self.information_author.get()
- self.permission=self.information_permission.get()
- self.other_versions=self.information_other_versions.get()
- self.licensetemplate=self.information_licensetemplate.get()
- self.categories=self.information_categories.get()
+ """ The user pressed the OK button. """
+ self.filename = self.filename_field.get()
+ self.description = self.information_description.get()
+ self.date = self.information_date.get()
+ self.source = self.information_source.get()
+ self.author = self.information_author.get()
+ self.permission = self.information_permission.get()
+ self.other_versions = self.information_other_versions.get()
+ self.licensetemplate = self.information_licensetemplate.get()
+ self.categories = self.information_categories.get()
self.root.destroy()
def skipFile(self):
- '''
- The user pressed the Skip button.
- '''
- self.skip=1
+ """ The user pressed the Skip button. """
+ self.skip = 1
self.root.destroy()
def openInBrowser(self):
- '''
- The user pressed the View in browser button.
- '''
+ """ The user pressed the View in browser button.
"""
webbrowser.open(self.url)
def add2autoskip(self):
- '''
- The user pressed the Add to AutoSkip button.
- '''
- templateid=int(self.templatelist.curselection()[0])
- template=self.templatelist.get(templateid)
- toadd=codecs.open(archivo, 'a', 'utf-8')
- toadd.write('{{'+template)
+ """ The user pressed the Add to AutoSkip button.
"""
+ templateid = int(self.templatelist.curselection()[0])
+ template = self.templatelist.get(templateid)
+ toadd = codecs.open(archivo, 'a', 'utf-8')
+ toadd.write('{{' + template)
toadd.close()
self.skipFile()
def getnewmetadata(self):
- '''
+ """
Activate the dialog and return the new name and if the image is skipped.
- '''
+
+ """
self.root.mainloop()
- return {u'imagepage' : self.imagepage,
- u'filename' : self.filename,
- u'description' : self.description,
- u'date' : self.date,
- u'source' : self.source,
- u'author' : self.author,
- u'permission' : self.permission,
- u'other_versions' : self.other_versions,
- u'licensetemplate' : self.licensetemplate,
- u'categories' : self.categories,
- u'skip' : self.skip}
+ return {u'imagepage': self.imagepage,
+ u'filename': self.filename,
+ u'description': self.description,
+ u'date': self.date,
+ u'source': self.source,
+ u'author': self.author,
+ u'permission': self.permission,
+ u'other_versions': self.other_versions,
+ u'licensetemplate': self.licensetemplate,
+ u'categories': self.categories,
+ u'skip': self.skip}
class uploader(threading.Thread):
- '''
- Upload all images
- '''
- def __init__ ( self, uploadQueue):
+ """ Upload all images """
+ def __init__(self, uploadQueue):
self.uploadQueue = uploadQueue
self.checktemplate = True
- threading.Thread.__init__ ( self )
+ threading.Thread.__init__(self)
def run(self):
- while True: #Change later
+ while True: # Change later
fields = self.uploadQueue.get()
if fields:
self.processImage(fields)
@@ -786,29 +815,26 @@
return True
def nochecktemplate(self):
- '''
- Don't want to add {{BotMoveToCommons}}
- '''
+ """ Don't want to add {{BotMoveToCommons}} """
self.checktemplate = False
return
def processImage(self, fields):
- '''
- Work on a single image
- '''
+ """ Work on a single image """
cid = self.buildNewImageDescription(fields)
pywikibot.output(cid)
- bot = UploadRobot(url=fields.get('imagepage').fileUrl(), description=cid,
useFilename=fields.get('filename'), keepFilename=True, verifyDescription=False,
ignoreWarning = True, targetSite = pywikibot.getSite('commons',
'commons'))
+ bot = UploadRobot(url=fields.get('imagepage').fileUrl(),
+ description=cid, useFilename=fields.get('filename'),
+ keepFilename=True, verifyDescription=False,
+ ignoreWarning=True,
+ targetSite=pywikibot.getSite('commons',
'commons'))
bot.run()
self.tagNowcommons(fields.get('imagepage'),
fields.get('filename'))
self.replaceUsage(fields.get('imagepage'),
fields.get('filename'))
-
def buildNewImageDescription(self, fields):
- '''
- Build a new information template
- '''
+ """ Build a new information template """
site = fields.get('imagepage').site()
lang = site.language()
@@ -816,31 +842,34 @@
cid = u''
if self.checktemplate:
- cid = cid +
u'\n{{BotMoveToCommons|%(lang)s.%(family)s|year={{subst:CURRENTYEAR}}|month={{subst:CURRENTMONTHNAME}}|day={{subst:CURRENTDAY}}}}\n'
% {u'lang' : lang, u'family' : family}
- cid = cid + u'== {{int:filedesc}} ==\n'
- cid = cid + u'{{Information\n'
- cid = cid + u'|description=%(description)s\n' % fields
- cid = cid + u'|date=%(date)s\n' % fields
- cid = cid + u'|source=%(source)s\n' % fields
- cid = cid + u'|author=%(author)s\n' % fields
- cid = cid + u'|permission=%(permission)s\n' % fields
- cid = cid + u'|other_versions=%(other_versions)s\n' % fields
- cid = cid + u'}}\n'
- cid = cid + u'== {{int:license}} ==\n'
- cid = cid + u'%(licensetemplate)s\n' % fields
- cid = cid + u'\n'
- cid = cid + self.getOriginalUploadLog(fields.get('imagepage'))
- cid = cid + u'__NOTOC__\n'
- if fields.get('categories').strip()==u'':
+ cid +=
u'\n{{BotMoveToCommons|%(lang)s.%(family)s|year={{subst:CURRENTYEAR}}|month={{subst:CURRENTMONTHNAME}}|day={{subst:CURRENTDAY}}}}\n'
\
+ % {u'lang': lang, u'family': family}
+ cid += u'== {{int:filedesc}} ==\n'
+ cid += u'{{Information\n'
+ cid += u'|description=%(description)s\n' % fields
+ cid += u'|date=%(date)s\n' % fields
+ cid += u'|source=%(source)s\n' % fields
+ cid += u'|author=%(author)s\n' % fields
+ cid += u'|permission=%(permission)s\n' % fields
+ cid += u'|other_versions=%(other_versions)s\n' % fields
+ cid += u'}}\n'
+ cid += u'== {{int:license}} ==\n'
+ cid += u'%(licensetemplate)s\n' % fields
+ cid += u'\n'
+ cid += self.getOriginalUploadLog(fields.get('imagepage'))
+ cid += u'__NOTOC__\n'
+ if fields.get('categories').strip() == u'':
cid = cid + u'{{Subst:Unc}}'
else:
cid = cid + u'%(categories)s\n' % fields
return cid
def getOriginalUploadLog(self, imagepage):
- '''
- Get the original upload log to put at the bottom of the image description page at
Commons.
- '''
+ """
+ Get the original upload log to put at the bottom of the image
+ description page at Commons.
+
+ """
filehistory = imagepage.getFileVersionHistory()
filehistory.reverse()
@@ -848,62 +877,69 @@
lang = site.language()
family = site.family.name
- sourceimage =
imagepage.site().get_address(imagepage.title()).replace(u'&redirect=no&useskin=monobook',
u'')
+ sourceimage = imagepage.site().get_address(
+ imagepage.title()).replace(u'&redirect=no&useskin=monobook',
u'')
result = u'== {{Original upload log}} ==\n'
- result = result + u'The original description page is/was
[http://%(lang)s.%(family)s.org%(sourceimage)s here]. All following user names refer to
%(lang)s.%(family)s.\n' % {u'lang' : lang, u'family' : family ,
u'sourceimage' : sourceimage}
+ result += (u'The original description page is/was
[http://%(lang)s.%(family)s.org%(sourceimage)s here]. All following user names refer to
%(lang)s.%(family)s.\n'
+ % {u'lang': lang, u'family': family,
+ u'sourceimage': sourceimage})
for (timestamp, username, resolution, size, comment) in filehistory:
- date = datetime.strptime(timestamp,
u'%Y-%m-%dT%H:%M:%SZ').strftime('%Y-%m-%d %H:%M')
- result = result + u'* %(date)s
[[:%(lang)s:user:%(username)s|%(username)s]] %(resolution)s (%(size)s bytes)
\'\'<nowiki>%(comment)s</nowiki>\'\'\n' % {
- u'lang' : lang,
- u'family' : family ,
- u'date' : date,
- u'username' : username,
+ date = datetime.strptime(
+ timestamp, u'%Y-%m-%dT%H:%M:%SZ').strftime('%Y-%m-%d
%H:%M')
+ result += u'* %(date)s [[:%(lang)s:user:%(username)s|%(username)s]]
%(resolution)s (%(size)s bytes)
\'\'<nowiki>%(comment)s</nowiki>\'\'\n' % {
+ u'lang': lang,
+ u'family': family,
+ u'date': date,
+ u'username': username,
u'resolution': resolution,
u'size': size,
- u'comment' : comment}
+ u'comment': comment}
return result
def tagNowcommons(self, imagepage, filename):
- '''
- Tagged the imag which has been moved to Commons for deletion.
- '''
- if pywikibot.Page(pywikibot.getSite('commons', 'commons'),
u'File:' + filename).exists():
- #Get a fresh copy, force to get the page so we dont run into edit conflicts
- imtxt=imagepage.get(force=True)
+ """ Tagged the imag which has been moved to Commons for deletion.
"""
+ if pywikibot.Page(pywikibot.getSite('commons', 'commons'),
+ u'File:' + filename).exists():
+ # Get a fresh copy, force to get the page so we dont run into edit
+ # conflicts
+ imtxt = imagepage.get(force=True)
- #Remove the move to commons templates
+ # Remove the move to commons templates
if imagepage.site().language() in moveToCommonsTemplate:
for moveTemplate in moveToCommonsTemplate[imagepage.site().language()]:
- imtxt = re.sub(u'(?i)\{\{' + moveTemplate +
u'[^\}]*\}\}', u'', imtxt)
+ imtxt = re.sub(u'(?i)\{\{' + moveTemplate +
+ u'[^\}]*\}\}', u'', imtxt)
- #add {{NowCommons}}
+ # add {{NowCommons}}
if imagepage.site().language() in nowCommonsTemplate:
- addTemplate = nowCommonsTemplate[imagepage.site().language()] % filename
+ addTemplate = nowCommonsTemplate[
+ imagepage.site().language()] % filename
else:
addTemplate = nowCommonsTemplate['_default'] % filename
- commentText = i18n.twtranslate(imagepage.site(),
- 'commons-file-now-available',
- {'localfile':
imagepage.title(withNamespace=False),
- 'commonsfile': filename})
+ commentText = i18n.twtranslate(
+ imagepage.site(), 'commons-file-now-available',
+ {'localfile': imagepage.title(withNamespace=False),
+ 'commonsfile': filename})
pywikibot.showDiff(imagepage.get(), imtxt + addTemplate)
- imagepage.put(imtxt + addTemplate, comment = commentText)
+ imagepage.put(imtxt + addTemplate, comment=commentText)
def replaceUsage(self, imagepage, filename):
- '''
+ """
If the image is uploaded under a different name, replace all usage.
- '''
+
+ """
if imagepage.title(withNamespace=False) != filename:
gen = pagegenerators.FileLinksGenerator(imagepage)
preloadingGen = pagegenerators.PreloadingGenerator(gen)
- moveSummary = i18n.twtranslate(imagepage.site(),
- 'commons-file-moved',
- {'localfile':
imagepage.title(withNamespace=False),
- 'commonsfile': filename})
+ moveSummary = i18n.twtranslate(
+ imagepage.site(), 'commons-file-moved',
+ {'localfile': imagepage.title(withNamespace=False),
+ 'commonsfile': filename})
imagebot = ImageRobot(generator=preloadingGen,
oldImage=imagepage.title(withNamespace=False),
@@ -918,7 +954,7 @@
pywikibot.warning(u'This bot is still full of bugs')
pywikibot.warning(u'Use at your own risk!')
- generator = None;
+ generator = None
autonomous = False
checkTemplate = True
@@ -939,7 +975,8 @@
generator = genFactory.getCombinedGenerator()
if not generator:
- raise add_text.NoEnoughData('You have to specify the generator you want to
use for the script!')
+ raise add_text.NoEnoughData(
+ 'You have to specify the generator you want to use for the script!')
pregenerator = pagegenerators.PreloadingGenerator(generator)
@@ -950,16 +987,18 @@
userInteractionThread = userInteraction(prefetchQueue, uploadQueue)
uploaderThread = uploader(uploadQueue)
- imageFetcherThread.daemon=False
- userInteractionThread.daemon=False
- uploaderThread.daemon=False
+ imageFetcherThread.daemon = False
+ userInteractionThread.daemon = False
+ uploaderThread.daemon = False
if autonomous:
- pywikibot.output(u'Bot is running in autonomous mode. There will be no user
interaction.')
+ pywikibot.output(u'Bot is running in autonomous mode. There will be no '
+ u'user interaction.')
userInteractionThread.setAutonomous()
if not checkTemplate:
- pywikibot.output(u'No check template will be added to the uploaded
files.')
+ pywikibot.output(u'No check template will be added to the uploaded '
+ u'files.')
uploaderThread.nochecktemplate()
fetchDone = imageFetcherThread.start()
--
To view, visit
https://gerrit.wikimedia.org/r/103555
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I450e8ec7b81b4c353e9f4216ee6c5903089e8913
Gerrit-PatchSet: 3
Gerrit-Project: pywikibot/compat
Gerrit-Branch: master
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Alex S.H. Lin <alexsh(a)mail2000.com.tw>
Gerrit-Reviewer: DrTrigon <dr.trigon(a)surfeu.ch>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Multichill <maarten(a)mdammers.nl>
Gerrit-Reviewer: jenkins-bot