jenkins-bot has submitted this change and it was merged.
Change subject: Make protect.py more wiki-agnostic
......................................................................
Make protect.py more wiki-agnostic
- Removed most harcoded protection level and types
- Applies protection levels only if the make sense depending on
Page.applicable_protections().
- The ProtectionRobot class extends pywikibot.Bot
- 'protections' dict replaces 'edit', 'move' and 'create'
- the 'always' switch is now a standard option
- Clarified "-unprotect" option and added "-default[:<level>]"
If a protection type (e.g. "edit") is not defined, it
chooses by default "sysop". "-default" overwrites this and
"-unprotect" acts like "-default:none". Only "-default"
will change only the explicitily set protection types.
- Fixed in Page.protect() that prompt only defaults to True if
protections was None ("deprecated mode")
Bug: 55057 - implicitly enable the 'upload'-type protection
Change-Id: I41146fa0c161a242834ab0b1fe2954c7b89d7fd1
---
M pywikibot/page.py
M scripts/protect.py
2 files changed, 152 insertions(+), 109 deletions(-)
Approvals:
John Vandenberg: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/page.py b/pywikibot/page.py
index 969d02b..7108a2b 100644
--- a/pywikibot/page.py
+++ b/pywikibot/page.py
@@ -1583,7 +1583,7 @@
@deprecate_arg("throttle", None)
def protect(self, edit=False, move=False, create=None, upload=None,
- unprotect=False, reason=None, prompt=True, protections=None,
+ unprotect=False, reason=None, prompt=None, protections=None,
**kwargs):
"""(Un)protect a wiki page. Requires administrator status.
@@ -1596,7 +1596,8 @@
@type protections: dict
@param reason: Reason for the action
@type reason: basestring
- @param prompt: Whether to ask user for confirmation
+ @param prompt: Whether to ask user for confirmation (deprecated).
+ Defaults to protections is None
@type prompt: bool
"""
def deprecated(value, arg_name):
@@ -1637,6 +1638,8 @@
protections = dict(
[(p_type, "") for p_type in self.applicable_protections()])
answer = 'y'
+ if called_using_deprecated_arg and prompt is None:
+ prompt = True
if prompt:
pywikibot.bot.warning(u'"prompt" argument of protect() is '
'deprecated')
diff --git a/scripts/protect.py b/scripts/protect.py
index d7a55b1..256d76b 100644
--- a/scripts/protect.py
+++ b/scripts/protect.py
@@ -1,41 +1,43 @@
# -*- coding: utf-8 -*-
"""
This script can be used to protect and unprotect pages en masse.
+
Of course, you will need an admin account on the relevant wiki.
-
-
These command line parameters can be used to specify which pages to work on:
¶ms;
Furthermore, the following command line parameters are supported:
--always: Don't prompt to protect pages, just do it.
+-always Don't prompt to protect pages, just do it.
--summary: Supply a custom edit summary.
+-summary: Supply a custom edit summary. Tries to generate summary from
+ the page selector. If no summary is supplied or couldn't
+ determine one from the selector it'll ask for one.
--unprotect: Actually unprotect pages instead of protecting
+-unprotect Acts like "default:none"
--edit:PROTECTION_LEVEL Set edit protection level to PROTECTION_LEVEL
+-default: Sets the default protection level (default 'sysop'). If no
+ level is defined it doesn't change unspecified levels.
--move:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL
+-[type]:[level] Set [type] protection level to [level]
-## Without support ##
-## -create:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL ##
+Usual values for [level] are: sysop, autoconfirmed, none; further levels may be
+provided by some wikis.
-Values for PROTECTION_LEVEL are: sysop, autoconfirmed, none.
-If an operation parameter (edit, move or create) is not specified, default
-protection level is 'sysop' (or 'none' if -unprotect).
+For all protection types (edit, move, etc.) it chooses the default protection
+level. This is "sysop" or "none" if -unprotect was selected. If multiple
+-unprotect or -default are used, only the last occurence is applied.
Usage: python protect.py <OPTIONS>
Examples:
-Protect everything in the category "To protect" prompting.
- python protect.py -cat:"To protect" -always
+Protect everything in the category 'To protect' prompting.
+ python protect.py -cat:'To protect'
-Unprotect all pages listed in text file "unprotect.txt" without prompting.
- python protect.py -file:unprotect.txt -unprotect
+Unprotect all pages listed in text file 'unprotect.txt' without prompting.
+ python protect.py -file:unprotect.txt -unprotect -always
"""
#
@@ -50,8 +52,7 @@
#
import pywikibot
-from pywikibot import i18n
-from pywikibot import pagegenerators
+from pywikibot import i18n, pagegenerators, Bot
# This is required for the text that is shown when you run this script
# with the parameter -help.
@@ -60,141 +61,180 @@
}
-class ProtectionRobot:
+class ProtectionRobot(Bot):
+
""" This bot allows protection of pages en masse. """
- def __init__(self, generator, summary, always=False, unprotect=False,
- edit='sysop', move='sysop', create='sysop'):
+ def __init__(self, generator, protections, **kwargs):
"""
- Arguments:
- * generator - A page generator.
- * always - Protect without prompting?
- * edit, move, create - protection level for these operations
- * unprotect - unprotect pages (and ignore edit, move, create
params)
+ Create a new ProtectionRobot.
+ @param generator: the page generator
+ @type generator: generator
+ @param protections: protections as a dict with "type": "level"
+ @type protections: dict
+ @param kwargs: additional arguments directly feed to Bot.__init__()
"""
+ self.availableOptions.update({
+ 'summary': None,
+ })
+ super(ProtectionRobot, self).__init__(**kwargs)
self.generator = generator
- self.summary = summary
- self.prompt = not always
- self.unprotect = unprotect
- self.edit = edit
- self.move = move
+ self.protections = protections
def run(self):
- """ Start the bot's action.
- Loop through everything in the page generator and (un)protect it.
+ """Start the bot's action.
+ Loop through everything in the page generator and apply the
+ protections.
"""
for page in self.generator:
pywikibot.output(u'Processing page %s' % page.title())
- page.protect(unprotect=self.unprotect, reason=self.summary,
- prompt=self.prompt, edit=self.edit, move=self.move)
+ if not self.getOption('always'):
+ choice = pywikibot.inputChoice(
+ u'Do you want to change the protection level of %s?'
+ % page.title(asLink=True, forceInterwiki=True),
+ ['yes', 'No', 'all'],
+ ['y', 'N', 'a'],
+ 'n')
+ if choice == 'n':
+ continue
+ elif choice == 'a':
+ self.option['always'] = True
+ applicable = page.applicable_protections()
+ protections = dict(
+ [prot for prot in self.protections if prot[0] in applicable])
+ page.protect(reason=self.getOption('summary'),
+ protections=protections)
-def choiceProtectionLevel(operation, default, protectionLevels):
- """ Asks a valid protection level for "operation".
- Returns the protection level chosen by user.
+def check_protection_level(operation, level, levels, default=None):
+ """Check if the protection level is valid or asks if necessary.
+ @return a valid protection level
+ @rtype string
"""
- default = default[0]
- firstChar = map(lambda level: level[0], protectionLevels)
- choiceChar = pywikibot.inputChoice('Choice a protection level to %s:'
- % operation,
- protectionLevels, firstChar,
- default=default)
- for level in protectionLevels:
- if level.startswith(choiceChar):
- return level
+ if level not in levels:
+ first_char = []
+ default_char = None
+ num = 1
+ for level in levels:
+ for c in level:
+ if c not in first_char:
+ first_char.append(c)
+ break
+ else:
+ first_char.append(unicode(num))
+ num += 1
+ if level == default:
+ default_char = first_char[-1]
+ choice = pywikibot.inputChoice('Choice a protection level to %s:'
+ % operation, levels, first_char,
+ default=default_char)
+
+ return levels[first_char.index(choice)]
+ else:
+ return level
def main(*args):
- protectionLevels = ['sysop', 'autoconfirmed', 'none']
-
- # This factory is responsible for processing command line arguments
- # that are also used by other scripts and that determine on which pages
- # to work on.
- pageName = ''
- summary = None
- always = False
+ options = {}
+ message_properties = {}
generator = None
- edit = ''
- move = ''
- defaultProtection = 'sysop'
+ protections = {}
+ default_level = 'sysop'
+ default_summaries = {
+ 'cat': 'category',
+ 'links': 'links',
+ 'ref': 'ref',
+ 'imageused': 'images',
+ 'file': 'simple',
+ }
# read command line parameters
local_args = pywikibot.handleArgs(*args)
genFactory = pagegenerators.GeneratorFactory()
- mysite = pywikibot.Site()
+ site = pywikibot.Site()
+ protection_levels = set(site.protection_levels())
+ protection_types = site.protection_types()
+ if '' in protection_levels:
+ protection_levels.remove('')
+ protection_levels.add('none')
for arg in local_args:
if arg == '-always':
- always = True
+ options['always'] = True
elif arg.startswith('-summary'):
if len(arg) == len('-summary'):
- summary = pywikibot.input(u'Enter a reason for the
protection:')
+ # fill dummy value to prevent automatic generation
+ options['summary'] = None
else:
- summary = arg[len('-summary:'):]
+ options['summary'] = arg[len('-summary:'):]
elif arg.startswith('-images'):
pywikibot.output('\n\03{lightred}-image option is deprecated. '
'Please use -imagelinks instead.\03{default}\n')
local_args.append('-imagelinks' + arg[7:])
elif arg.startswith('-unprotect'):
- defaultProtection = 'none'
- elif arg.startswith('-edit'):
- edit = arg[len('-edit:'):]
- if edit not in protectionLevels:
- edit = choiceProtectionLevel(
- 'edit', defaultProtection, protectionLevels)
- elif arg.startswith('-move'):
- move = arg[len('-move:'):]
- if move not in protectionLevels:
- move = choiceProtectionLevel(
- 'move', defaultProtection, protectionLevels)
- elif arg.startswith('-create'):
- create = arg[len('-create:'):]
- if create not in protectionLevels:
- create = choiceProtectionLevel(
- 'create', defaultProtection, protectionLevels)
+ default_level = 'none'
+ elif arg.startswith('-default'):
+ if len(arg) == len('-default'):
+ default_level = None
+ else:
+ default_level = arg[len('-default:'):]
else:
- genFactory.handleArg(arg)
- found = arg.find(':') + 1
- if found:
- pageName = arg[found:]
+ is_p_type = False
+ if arg.startswith('-'):
+ delimiter = arg.find(':')
+ if delimiter > 0:
+ p_type = arg[1:delimiter]
+ level = arg[delimiter + 1:]
+ if p_type in protection_types:
+ protections[p_type] = level
+ is_p_type = True
+ if not is_p_type:
+ if not genFactory.handleArg(arg):
+ raise ValueError('Unknown parameter "{}"'.format(arg))
+ found = arg.find(':') + 1
+ if found:
+ message_properties.update({'cat': arg[found:],
+ 'page': arg[found:]})
- if not summary:
- if pageName:
- if arg.startswith('cat') or arg.startswith('subcats'):
- summary = i18n.twtranslate(mysite, 'protect-category',
- {'cat': pageName})
- elif arg.startswith('links'):
- summary = i18n.twtranslate(mysite, 'protect-links',
- {'page': pageName})
- elif arg.startswith('ref'):
- summary = i18n.twtranslate(mysite, 'protect-ref',
- {'page': pageName})
- elif arg.startswith('imageused'):
- summary = i18n.twtranslate(mysite, 'protect-images',
- {'page': pageName})
- elif arg.startswith('file'):
- summary = i18n.twtranslate(mysite, 'protect-simple')
+ if 'summary' not in options:
+ generator_type = arg[1:found] if found > 0 else arg[1:]
+ if generator_type in default_summaries:
+ message_type = default_summaries[generator_type]
+ if message_type == 'simple' or message_properties:
+ options['summary'] = i18n.twtranslate(
+ site, 'protect-{}'.format(message_type),
+ message_properties)
generator = genFactory.getCombinedGenerator()
# We are just protecting pages, so we have no need of using a preloading
# page generator to actually get the text of those pages.
if generator:
- if summary is None:
- summary = pywikibot.input(u'Enter a reason for the %sprotection:'
- % ['', 'un'][protectionLevels == 'none'])
- if not edit:
- edit = defaultProtection
- if not move:
- move = defaultProtection
- bot = ProtectionRobot(generator, summary, always, edit=edit, move=move)
+ if default_level:
+ default_level = check_protection_level('Default level',
+ default_level,
+ protection_levels)
+ # set the default value for all
+ # None (not the string 'none') will be ignored by Site.protect()
+ combined_protections = dict([
+ (p_type, default_level) for p_type in protection_types])
+ for p_type, level in protections.items():
+ level = check_protection_level(p_type, level, protection_levels,
+ default_level)
+ if level == 'none':
+ level = ''
+ combined_protections[p_type] = level
+ if not options.get('summary'):
+ options['summary'] = pywikibot.input(
+ u'Enter a reason for the protection change:')
+ bot = ProtectionRobot(generator, combined_protections, **options)
bot.run()
else:
# Show help text from the top of this file
pywikibot.showHelp()
-if __name__ == "__main__":
+if __name__ == '__main__':
main()
--
To view, visit https://gerrit.wikimedia.org/r/149501
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I41146fa0c161a242834ab0b1fe2954c7b89d7fd1
Gerrit-PatchSet: 7
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Ricordisamoa <[email protected]>
Gerrit-Reviewer: John Vandenberg <[email protected]>
Gerrit-Reviewer: Ladsgroup <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Merlijn van Deen <[email protected]>
Gerrit-Reviewer: Multichill <[email protected]>
Gerrit-Reviewer: Ricordisamoa <[email protected]>
Gerrit-Reviewer: Russell Blau <[email protected]>
Gerrit-Reviewer: XZise <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
Pywikibot-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/pywikibot-commits