jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/632462 )
Change subject: [tests] Enable tests for parser_function_count.py
......................................................................
[tests] Enable tests for parser_function_count.py
Change-Id: I976ce2927a0ec3456c8fdfcb64f0f48749c757d1
---
M scripts/parser_function_count.py
M tests/script_tests.py
2 files changed, 3 insertions(+), 1 deletion(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/scripts/parser_function_count.py b/scripts/parser_function_count.py
index 7293e5d..db2856f 100644
--- a/scripts/parser_function_count.py
+++ b/scripts/parser_function_count.py
@@ -116,7 +116,7 @@
@property
def generator(self):
"""Generator."""
- gen = self.site.allpages(start=self.option.start,
+ gen = self.site.allpages(start=self.opt.start,
namespace=10, filterredir=False)
if self.site.doc_subpage:
gen = pagegenerators.RegexFilterPageGenerator(
diff --git a/tests/script_tests.py b/tests/script_tests.py
index d2ba2a3..b15062e 100644
--- a/tests/script_tests.py
+++ b/tests/script_tests.py
@@ -101,6 +101,7 @@
'revertbot',
'noreferences',
'nowcommons',
+ 'parser_function_count',
'patrol',
'shell',
'standardize_interwiki',
@@ -127,6 +128,7 @@
'imageharvest': 'From what URL should I get the images',
'login': 'Logged in on ',
'pagefromfile': 'Please enter the file name',
+ 'parser_function_count': 'Hold on, this will need some time.',
'replace': 'Press Enter to use this automatic message',
'replicate_wiki':
'error: the following arguments are required: destination',
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/632462
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I976ce2927a0ec3456c8fdfcb64f0f48749c757d1
Gerrit-Change-Number: 632462
Gerrit-PatchSet: 1
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/631982 )
Change subject: [IMPR] use functools.singledispatch for two date functions
......................................................................
[IMPR] use functools.singledispatch for two date functions
use functools.singledispatch for two date.multi and date.dh
to decrease code complexity
Change-Id: Idc8fc0dcf54b8b4755e76584bade9496eba6a53d
---
M pywikibot/date.py
1 file changed, 60 insertions(+), 53 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/date.py b/pywikibot/date.py
index 360099e..8b8d908 100644
--- a/pywikibot/date.py
+++ b/pywikibot/date.py
@@ -11,6 +11,7 @@
from collections import defaultdict
from contextlib import suppress
+from functools import singledispatch
from string import digits as _decimalDigits # noqa: N812
from pywikibot import Site
@@ -42,7 +43,8 @@
snglValsFormats = ['CurrEvents']
-def multi(value, tuplst):
+@singledispatch
+def multi(value: int, tuplst):
"""
Run multiple pattern checks for the same entry.
@@ -52,24 +54,25 @@
first to encode/decode a single value (e.g. simpleInt), second is a
predicate function with an integer parameter that returns true or false.
When the 2nd function evaluates to true, the 1st function is used.
-
"""
- if isinstance(value, str):
- # Try all functions, and test result against predicates
- for func, pred in tuplst:
- try:
- res = func(value)
- except ValueError:
- continue
- if pred(res):
- return res
- else:
- # Find a predicate that gives true for this int value, and run a
- # function
- for func, pred in tuplst:
- if pred(value):
- return func(value)
+ # Find a predicate that gives true for this int value, and run a
+ # function
+ for func, pred in tuplst:
+ if pred(value):
+ return func(value)
+ raise ValueError('could not find a matching function')
+
+(a)multi.register(str)
+def _(value: str, tuplst):
+ # Try all functions, and test result against predicates
+ for func, pred in tuplst:
+ try:
+ res = func(value)
+ except ValueError:
+ continue
+ if pred(res):
+ return res
raise ValueError('could not find a matching function')
@@ -406,7 +409,8 @@
return _escPtrnCache2[pattern]
-def dh(value, pattern, encf, decf, filter=None):
+@singledispatch
+def dh(value: int, pattern, encf, decf, filter=None):
"""Function to help with year parsing.
Usually it will be used as a lambda call in a map::
@@ -433,46 +437,49 @@
"""
compPattern, strPattern, decoders = escapePattern2(pattern)
- if isinstance(value, str):
- m = compPattern.match(value)
- if m:
- # decode each found value using provided decoder
- values = [decoder[2](m.group(i + 1))
- for i, decoder in enumerate(decoders)]
- decValue = decf(values)
+ # Encode an integer value into a textual form.
+ # This will be called from outside as well as recursivelly to verify
+ # parsed value
+ if filter and not filter(value):
+ raise ValueError('value {} is not allowed'.format(value))
- assert not isinstance(decValue, str), \
- 'Decoder must not return a string!'
+ params = encf(value)
- # recursive call to re-encode and see if we get the original
- # (may through filter exception)
- if value == dh(decValue, pattern, encf, decf, filter):
- return decValue
-
- raise ValueError("reverse encoding didn't match")
+ if isinstance(params, (tuple, list)):
+ assert len(params) == len(decoders), (
+ 'parameter count ({0}) does not match decoder count ({1})'
+ .format(len(params), len(decoders)))
+ # convert integer parameters into their textual representation
+ params = tuple(_make_parameter(decoders[i], param)
+ for i, param in enumerate(params))
+ return strPattern % params
else:
- # Encode an integer value into a textual form.
- # This will be called from outside as well as recursivelly to verify
- # parsed value
- if filter and not filter(value):
- raise ValueError('value {} is not allowed'.format(value))
+ assert len(decoders) == 1, (
+ 'A single parameter does not match {0} decoders.'
+ .format(len(decoders)))
+ # convert integer parameter into its textual representation
+ return strPattern % _make_parameter(decoders[0], params)
- params = encf(value)
- if isinstance(params, (tuple, list)):
- assert len(params) == len(decoders), (
- 'parameter count ({0}) does not match decoder count ({1})'
- .format(len(params), len(decoders)))
- # convert integer parameters into their textual representation
- params = tuple(_make_parameter(decoders[i], param)
- for i, param in enumerate(params))
- return strPattern % params
- else:
- assert len(decoders) == 1, (
- 'A single parameter does not match {0} decoders.'
- .format(len(decoders)))
- # convert integer parameter into its textual representation
- return strPattern % _make_parameter(decoders[0], params)
+(a)dh.register(str)
+def _(value: str, pattern, encf, decf, filter=None):
+ compPattern, strPattern, decoders = escapePattern2(pattern)
+ m = compPattern.match(value)
+ if m:
+ # decode each found value using provided decoder
+ values = [decoder[2](m.group(i + 1))
+ for i, decoder in enumerate(decoders)]
+ decValue = decf(values)
+
+ assert not isinstance(decValue, str), \
+ 'Decoder must not return a string!'
+
+ # recursive call to re-encode and see if we get the original
+ # (may through filter exception)
+ if value == dh(decValue, pattern, encf, decf, filter):
+ return decValue
+
+ raise ValueError("reverse encoding didn't match")
def _make_parameter(decoder, param):
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/631982
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Idc8fc0dcf54b8b4755e76584bade9496eba6a53d
Gerrit-Change-Number: 631982
Gerrit-PatchSet: 8
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: JJMC89 <JJMC89.Wikimedia(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/181724 )
Change subject: Porting parser_function_count.py from compat to core/scripts
......................................................................
Porting parser_function_count.py from compat to core/scripts
- Added parsefunctioncount.py in core/scripts/ as part of
Pywikibot:Compat to Core migration.
- use SingleSiteBot, ExistingPageBot, NoRedirectPageBot classes
- use collections.Counter to hold the result
- Use magicwords for variable declaration via siteinfo.
- Use doc_subpages infrastructure of core
Bug: T66878
Change-Id: I28aafa2aa2928b9585fc825523dfc17fb808e4f9
---
M docs/scripts/scripts.rst
M scripts/README.rst
A scripts/parser_function_count.py
3 files changed, 225 insertions(+), 1 deletion(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/docs/scripts/scripts.rst b/docs/scripts/scripts.rst
index 088b454..ba353c7 100644
--- a/docs/scripts/scripts.rst
+++ b/docs/scripts/scripts.rst
@@ -271,6 +271,11 @@
.. automodule:: scripts.pagefromfile
+scripts.parser\_function\_count script
+--------------------------------------
+
+.. automodule:: scripts.parser_function_count
+
scripts.patrol script
---------------------
diff --git a/scripts/README.rst b/scripts/README.rst
index b51e4fb..402ef5b 100644
--- a/scripts/README.rst
+++ b/scripts/README.rst
@@ -167,7 +167,10 @@
| | number of pages to be put on the wiki. |
+------------------------+---------------------------------------------------------+
| #pageimport.py | Import pages from a certain wiki to another. |
- +------------------------+---------------------------------------------------------+
+ +------------------------+--+------------------------------------------------------+
+ | parser_function_count.py | Find expensive templates that are subject to be |
+ | | converted to Lua. |
+ +------------------------+--+------------------------------------------------------+
| patrol.py | Obtains a list pages and marks the edits as patrolled |
| | based on a whitelist. |
+------------------------+---------------------------------------------------------+
diff --git a/scripts/parser_function_count.py b/scripts/parser_function_count.py
new file mode 100644
index 0000000..7293e5d
--- /dev/null
+++ b/scripts/parser_function_count.py
@@ -0,0 +1,216 @@
+# -*- coding: utf-8 -*-
+"""
+Used to find expensive templates that are subject to be converted to Lua.
+
+It counts parser functions and then orders templates by number of these
+and uploads the first n titles or alternatively templates having count()>n.
+
+Parameters:
+
+-start Will start from the given title (it does not have to exist).
+ Parameter may be given as "-start" or "-start:title".
+ Defaults to '!'.
+
+-first Returns the first n results in decreasing order of number
+ of hits (or without ordering if used with -nosort)
+ Parameter may be given as "-first" or "-first:n".
+
+-atleast Returns templates with at least n hits.
+ Parameter may be given as "-atleast" or "-atleast:n".
+
+-nosort Keeps the original order of templates. Default behaviour is
+ to sort them by decreasing order of count(parserfunctions).
+
+-save Saves the results. The file is in the form you may upload it
+ to a wikipage. May be given as "-save:<filename>".
+ If it exists, titles will be appended.
+
+-upload Specify a page in your wiki where results will be uploaded.
+ Parameter may be given as "-upload" or "-upload:title".
+ Say good-bye to previous content if existed.
+
+Precedence of evaluation: results are first sorted in decreasing order of
+templates, unless nosort is switched on. Then first n templates are taken if
+first is specified, and at last atleast is evaluated. If nosort and first are
+used together, the program will stop at the nth hit without scanning the rest
+of the template namespace. This may be used to run it in more sessions
+(continue with -start next time).
+
+First is strict. That means if results #90-120 have the same number of parser
+functions and you specify -first:100, only the first 100 will be listed (even
+if atleast is used as well).
+
+Should you specify neither first nor atleast, all templates using parser
+functions will be listed.
+"""
+#
+# (C) Pywikibot team, 2013-2020
+#
+# Distributed under the terms of the MIT license.
+#
+# Todo:
+# * Using xml and xmlstart
+# * Using categories
+# * Error handling for uploading (anyway, that's the last action, it's only
+# for the beauty of the program, does not effect anything).
+
+import codecs
+import re
+
+from collections import Counter
+
+import pywikibot
+
+from pywikibot.bot import ExistingPageBot, NoRedirectPageBot, SingleSiteBot
+from pywikibot import pagegenerators
+
+
+class ParserFunctionCountBot(SingleSiteBot,
+ ExistingPageBot, NoRedirectPageBot):
+
+ """Bot class used for obtaining Parser function Count."""
+
+ def __init__(self, **kwargs):
+ """Initializer."""
+ self.available_options.update({
+ 'atleast': None,
+ 'first': None,
+ 'nosort': False,
+ 'save': None,
+ 'start': '!',
+ 'upload': None,
+ })
+ super().__init__(**kwargs)
+
+ editcomment = {
+ # This will be used for uploading the list to your wiki.
+ 'en':
+ 'Bot: uploading list of templates having too many parser '
+ 'functions',
+ 'hu':
+ 'A túl sok parserfüggvényt használó sablonok listájának '
+ 'feltöltése',
+ }
+
+ # Limitations for result:
+ if self.opt.first:
+ try:
+ self.opt.first = int(self.opt.first)
+ if self.opt.first < 1:
+ self.opt.first = None
+ except ValueError:
+ self.opt.first = None
+
+ if self.opt.atleast:
+ try:
+ self.opt.atleast = int(self.opt.atleast)
+ # 1 has no effect, don't waste resources.
+ if self.opt.atleast < 2:
+ self.opt.atleast = None
+ except ValueError:
+ self.opt.atleast = None
+
+ lang = self.site.lang
+ self.summary = editcomment.get(lang, editcomment['en'])
+
+ @property
+ def generator(self):
+ """Generator."""
+ gen = self.site.allpages(start=self.option.start,
+ namespace=10, filterredir=False)
+ if self.site.doc_subpage:
+ gen = pagegenerators.RegexFilterPageGenerator(
+ gen, self.site.doc_subpage, quantifier='none')
+ return gen
+
+ def setup(self):
+ """Setup magic words, regex and result counter."""
+ pywikibot.output('Hold on, this will need some time. '
+ 'You will be notified by 50 templates.')
+ magicwords = []
+ for magic_word in self.site.siteinfo['magicwords']:
+ magicwords += magic_word['aliases']
+ self.regex = re.compile(r'#({}):'.format('|'.join(magicwords)), re.I)
+ self.results = Counter()
+
+ def treat(self, page):
+ """Process a single template."""
+ title = page.title()
+ if (self._treat_counter + 1) % 50 == 0:
+ # Don't let the poor user panic in front of a black screen.
+ pywikibot.output('{}th template is being processed: {}'
+ .format(self._treat_counter + 1, title))
+
+ text = page.text
+ functions = self.regex.findall(text)
+ if functions and (self.opt.atleast is None
+ or self.opt.atleast <= len(functions)):
+ self.results[title] = len(functions)
+
+ if self.opt.nosort and self.opt.first \
+ and len(self.results) >= self.opt.first:
+ self.stop()
+
+ def teardown(self):
+ """Final processing."""
+ resultlist = '\n'.join(
+ '# [[{result[0]}]] ({result[1]})'
+ .format(result=result)
+ for result in self.results.most_common(self.opt.first))
+ pywikibot.output(resultlist)
+ pywikibot.output('{} templates were found.'.format(len(self.results)))
+
+ # File operations:
+ if self.opt.save:
+ # This opens in strict error mode, that means bot will stop
+ # on encoding errors with ValueError.
+ # See http://docs.python.org/library/codecs.html#codecs.open
+ try:
+ with codecs.open(
+ self.opt.save, encoding='utf-8', mode='a') as f:
+ f.write(resultlist)
+ except OSError:
+ pywikibot.exception()
+
+ if self.opt.upload:
+ page = pywikibot.Page(self.site, self.opt.upload)
+ self.userPut(page, page.text, resultlist,
+ ignore_save_related_errors=True,
+ summary=self.summary)
+
+
+def main(*args):
+ """Process command line arguments and invoke ParserFunctionCountBot."""
+ local_args = pywikibot.handle_args(*args)
+ options = {}
+
+ # Parse command line arguments
+ for arg in local_args:
+ opt, _, value = arg.partition(':')
+ if not opt.startswith('-'):
+ continue
+ opt = opt[1:]
+ if opt == 'start':
+ options[opt] = value or pywikibot.input(
+ 'From which title do you want to continue?')
+ elif opt == 'save':
+ options[opt] = value or pywikibot.input(
+ 'Please enter the filename:')
+ elif opt == 'upload':
+ options[opt] = value or pywikibot.input(
+ 'Please enter the pagename:')
+ elif opt == 'first':
+ options[opt] = value or pywikibot.input(
+ 'Please enter the max. number of templates to display:')
+ elif opt == 'atleast':
+ options[opt] = value or pywikibot.input(
+ 'Please enter the min. number of functions to display:')
+ elif opt == 'nosort':
+ options[opt] = True
+
+ bot = ParserFunctionCountBot(**options)
+ bot.run()
+
+
+if __name__ == '__main__':
+ main()
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/181724
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I28aafa2aa2928b9585fc825523dfc17fb808e4f9
Gerrit-Change-Number: 181724
Gerrit-PatchSet: 22
Gerrit-Owner: Prianka <priyankajayaswal025(a)gmail.com>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Liuxinyu970226 <541329866(a)qq.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: Mpaa <mpaa.wiki(a)gmail.com>
Gerrit-Reviewer: Prianka <priyankajayaswal025(a)gmail.com>
Gerrit-Reviewer: Prod <prodigion(a)hotmail.com>
Gerrit-Reviewer: Ricordisamoa <ricordisamoa(a)disroot.org>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/632438 )
Change subject: [bugfix] Fix for opt.update to prevent deprecation warning
......................................................................
[bugfix] Fix for opt.update to prevent deprecation warning
Change-Id: Ibefe2426a1b0d8b5ae965def17ca77b726a000f0
---
M pywikibot/bot.py
1 file changed, 1 insertion(+), 1 deletion(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/bot.py b/pywikibot/bot.py
index 9857f13..079e987 100644
--- a/pywikibot/bot.py
+++ b/pywikibot/bot.py
@@ -1054,7 +1054,7 @@
# self.options contains the options overridden from defaults
self._options = {opt: options[opt]
for opt in received_options & valid_options}
- self.opt.update(self.options)
+ self.opt.update(self._options)
for opt in received_options - valid_options:
pywikibot.warning('{} is not a valid option. It was ignored.'
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/632438
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ibefe2426a1b0d8b5ae965def17ca77b726a000f0
Gerrit-Change-Number: 632438
Gerrit-PatchSet: 1
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/618928 )
Change subject: [IMPR] Improvements for OptionHandler
......................................................................
[IMPR] Improvements for OptionHandler
- get Bot options by Bot.opt.option attribute or Bot.opt[option] as well
- deprecate availableOptions in favour of available_options due to
naming convention
- deprecate setOptions in favour of set_options due to naming convention
- deprecate getOption in favour of the new implementation
- deprecate options attibute
- Update specialbots and basic.py as first step
Change-Id: I94e3fcb299e779aab7834b8feb042dfc4d6a0b9e
---
M pywikibot/bot.py
M pywikibot/specialbots/_unlink.py
M pywikibot/specialbots/_upload.py
M scripts/basic.py
4 files changed, 90 insertions(+), 56 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/bot.py b/pywikibot/bot.py
index 619f6a6..4f59108 100644
--- a/pywikibot/bot.py
+++ b/pywikibot/bot.py
@@ -23,7 +23,7 @@
scripts.ini configuration file. That file consists of sections, led by a
C{[section]} header and followed by C{option: value} or C{option=value}
entries. The section is the script name without .py suffix. All options
- identified must be predefined in availableOptions dictionary.
+ identified must be predefined in available_options dictionary.
* L{Bot}: The previous base class which should be avoided. This class is mainly
used for bots which work with wikibase or together with an image repository.
@@ -126,6 +126,7 @@
deprecated, deprecate_arg, deprecated_args, issue_deprecation_warning,
)
from pywikibot.tools._logging import LoggingFormatter, RotatingFileHandler
+from pywikibot.tools import classproperty
from pywikibot.tools.formatter import color_format
@@ -980,6 +981,24 @@
i18n.input('pywikibot-enter-finished-browser')
+class _OptionDict(dict):
+
+ """The option dict which holds the options of OptionHandler."""
+
+ def __init__(self, classname, options):
+ self.classname = classname
+ super().__init__(options)
+
+ def __missing__(self, key):
+ raise pywikibot.Error("'{}' is not a valid option for {}."
+ .format(key, self.classname))
+ __getattr__ = dict.__getitem__
+
+
+_DEPRECATION_MSG = 'Optionhandler.opt.option attribute ' \
+ 'or Optionhandler.opt[option] item'
+
+
class OptionHandler:
"""Class to get and set options."""
@@ -989,46 +1008,64 @@
# The values are the default values
# Overwrite this in subclasses!
- availableOptions = {} # type: Dict[str, Any]
+ available_options = {} # type: Dict[str, Any]
def __init__(self, **kwargs):
"""
- Only accept options defined in availableOptions.
+ Only accept options defined in available_options.
@param kwargs: bot options
"""
- self.setOptions(**kwargs)
+ self.set_options(**kwargs)
+ @classproperty
+ @deprecated('available_options', since='20201006')
+ def availableOptions(cls):
+ """DEPRECATED. Available_options class property."""
+ return cls.available_options
+
+ @deprecated('set_options', since='20201006')
def setOptions(self, **kwargs):
- """
- Set the instance options.
+ """DEPRECATED. Set the instance options."""
+ self.set_options(**kwargs)
- @param kwargs: options
- """
- valid_options = set(self.availableOptions)
- received_options = set(kwargs)
+ def set_options(self, **options):
+ """Set the instance options."""
+ valid_options = set(self.available_options)
+ received_options = set(options)
- # contains the options overridden from defaults
- self.options = {
- opt: kwargs[opt] for opt in received_options & valid_options}
+ # self.opt contains all available options including defaults
+ self.opt = _OptionDict(self.__class__.__name__, self.available_options)
+ # self.options contains the options overridden from defaults
+ self._options = {opt: options[opt]
+ for opt in received_options & valid_options}
+ self.opt.update(self.options)
for opt in received_options - valid_options:
- pywikibot.warning('%s is not a valid option. It was ignored.'
- % opt)
+ pywikibot.warning('{} is not a valid option. It was ignored.'
+ .format(opt))
+ @deprecated(_DEPRECATION_MSG, since='20201006')
def getOption(self, option):
- """
- Get the current value of an option.
+ """DEPRECATED. Get the current value of an option.
- @param option: key defined in OptionHandler.availableOptions
+ @param option: key defined in OptionHandler.available_options
@raise pywikibot.exceptions.Error: No valid option is given with
option parameter
"""
- try:
- return self.options.get(option, self.availableOptions[option])
- except KeyError:
- raise pywikibot.Error("'{0}' is not a valid option for {1}."
- .format(option, self.__class__.__name__))
+ return self.opt[option]
+
+ @property
+ @deprecated(_DEPRECATION_MSG, since='20201006', future_warning=True)
+ def options(self):
+ """DEPRECATED. Return changed options."""
+ return self._options
+
+ @options.setter
+ @deprecated(_DEPRECATION_MSG, since='20201006', future_warning=True)
+ def options(self, options):
+ """DEPRECATED. Return changed options."""
+ self.set_options(**options)
class BaseBot(OptionHandler):
@@ -1051,7 +1088,7 @@
# The values are the default values
# Extend this in subclasses!
- availableOptions = {
+ available_options = {
'always': False, # By default ask for confirmation when putting a page
}
@@ -1059,7 +1096,7 @@
def __init__(self, **kwargs):
"""
- Only accept options defined in availableOptions.
+ Only accept options defined in available_options.
@param kwargs: bot options
"""
@@ -1103,7 +1140,7 @@
def user_confirm(self, question):
"""Obtain user response if bot option 'always' not enabled."""
- if self.getOption('always'):
+ if self.opt.always:
return True
choice = pywikibot.input_choice(question,
@@ -1188,7 +1225,7 @@
if not self.user_confirm('Do you want to accept these changes?'):
return False
- if 'asynchronous' not in kwargs and self.getOption('always'):
+ if 'asynchronous' not in kwargs and self.opt.always:
kwargs['asynchronous'] = True
ignore_save_related_errors = kwargs.pop('ignore_save_related_errors',
@@ -1574,7 +1611,7 @@
"""A bot class that can read options from scripts.ini file.
- All options must be predefined in availableOptions dictionary. The type
+ All options must be predefined in available_options dictionary. The type
of these options is responsible for the correct interpretation of the
options type given by the .ini file. They can be interpreted as bool,
int, float or str (default). The settings file may be like:
@@ -1588,22 +1625,22 @@
The option values are interpreted in this order::
- - availableOptions default setting
+ - available_options default setting
- script.ini options settings
- command line arguments
"""
INI = 'scripts.ini'
- def setOptions(self, **kwargs):
+ def set_options(self, **kwargs):
"""Read settings from scripts.ini file."""
conf = configparser.ConfigParser(inline_comment_prefixes=[';'])
section = calledModuleName()
if (conf.read(self.INI) == [self.INI] and conf.has_section(section)):
pywikibot.output('Reading settings from {} file.'.format(self.INI))
- args = {}
- for option, value in self.availableOptions.items():
+ options = {}
+ for option, value in self.available_options.items():
if not conf.has_option(section, option):
continue
# use a convenience parser method, default to get()
@@ -1613,15 +1650,15 @@
method = getattr(conf, 'getboolean')
else:
method = getattr(conf, 'get' + value_type, default)
- args[option] = method(section, option)
- for opt in set(conf.options(section)) - set(args):
+ options[option] = method(section, option)
+ for opt in set(conf.options(section)) - set(options):
pywikibot.warning(
'"{}" is not a valid option. It was ignored.'.format(opt))
- args.update(kwargs)
+ options.update(kwargs)
else:
- args = kwargs
+ options = kwargs
- super().setOptions(**args)
+ super().set_options(**options)
class CurrentPageBot(BaseBot):
@@ -1798,7 +1835,7 @@
@ivar create_missing_item: If True, new items will be created if the
current page doesn't have one. Subclasses should override this in the
- initializer with a bool value or using self.getOption.
+ initializer with a bool value or using self.opt attribute.
@type create_missing_item: bool
"""
diff --git a/pywikibot/specialbots/_unlink.py b/pywikibot/specialbots/_unlink.py
index ce5afe9..abd2e1d 100644
--- a/pywikibot/specialbots/_unlink.py
+++ b/pywikibot/specialbots/_unlink.py
@@ -9,8 +9,6 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
from pywikibot.bot import (
AlwaysChoice, AutomaticTWSummaryBot, ChoiceException, ExistingPageBot,
InteractiveReplace, NoRedirectPageBot, UnhandledAnswer,
@@ -25,7 +23,7 @@
def __init__(self):
"""Initializer."""
- super(EditReplacement, self).__init__('edit', 'e')
+ super().__init__('edit', 'e')
self.stop = True
@@ -35,10 +33,10 @@
def __init__(self, bot):
"""Create default settings."""
- super(InteractiveUnlink, self).__init__(
- old_link=bot.pageToUnlink, new_link=False, default='u')
+ super().__init__(old_link=bot.pageToUnlink,
+ new_link=False, default='u')
self._always = AlwaysChoice(self, 'unlink all pages', 'a')
- self._always.always = bot.getOption('always')
+ self._always.always = bot.opt.always
self.additional_choices = [
AlwaysChoice(self, 'unlink all on page', 'p'),
self._always, EditReplacement()]
@@ -48,7 +46,7 @@
def handle_answer(self, choice):
"""Handle choice and store in bot's options."""
- answer = super(InteractiveUnlink, self).handle_answer(choice)
+ answer = super().handle_answer(choice)
self._bot.options['always'] = self._always.always
return answer
@@ -59,12 +57,12 @@
def __init__(self, **kwargs):
"""Redirect all parameters and add namespace as an available option."""
- self.availableOptions.update({
+ self.available_options.update({
'namespaces': [],
# Which namespaces should be processed?
# default to [] which means all namespaces will be processed
})
- super(BaseUnlinkBot, self).__init__(**kwargs)
+ super().__init__(**kwargs)
def _create_callback(self):
"""Create a new callback instance for replace_links."""
diff --git a/pywikibot/specialbots/_upload.py b/pywikibot/specialbots/_upload.py
index 7db395a..b842ff8 100644
--- a/pywikibot/specialbots/_upload.py
+++ b/pywikibot/specialbots/_upload.py
@@ -81,8 +81,8 @@
@type always: bool
"""
super().__init__(**kwargs)
- always = self.getOption('always')
- if (always and ignore_warning is not True and aborts is not True):
+ always = self.opt.always
+ if always and ignore_warning is not True and aborts is not True:
raise ValueError('When always is set to True, either '
'ignore_warning or aborts must be set to True.')
if always and not description:
@@ -218,7 +218,7 @@
pywikibot.warning('file_url is not given. '
'Set to self.url by default.')
- always = self.getOption('always')
+ always = self.opt.always
# Isolate the pure name
filename = file_url
# Filename may be either a URL or a local file path
diff --git a/scripts/basic.py b/scripts/basic.py
index e5df728..8d14573 100755
--- a/scripts/basic.py
+++ b/scripts/basic.py
@@ -77,7 +77,7 @@
"""
# Add your own options to the bot and set their defaults
# -always option is predefined by BaseBot class
- self.availableOptions.update({
+ self.available_options.update({
'replace': False, # delete old text and write the new text
'summary': None, # your own bot summary
'text': 'Test', # add this text from option. 'Test' is default
@@ -86,7 +86,6 @@
# call initializer of the super class
super().__init__(site=True, **kwargs)
-
# assign the generator to the bot
self.generator = generator
@@ -103,13 +102,13 @@
# Retrieve your private option
# Use your own text or use the default 'Test'
- text_to_add = self.getOption('text')
+ text_to_add = self.opt.text
- if self.getOption('replace'):
+ if self.opt.replace:
# replace the page text
text = text_to_add
- elif self.getOption('top'):
+ elif self.opt.top:
# put text on top
text = text_to_add + text
@@ -119,7 +118,7 @@
# if summary option is None, it takes the default i18n summary from
# i18n subdirectory with summary_key as summary key.
- self.put_current(text, summary=self.getOption('summary'))
+ self.put_current(text, summary=self.opt.summary)
def main(*args) -> None:
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/618928
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I94e3fcb299e779aab7834b8feb042dfc4d6a0b9e
Gerrit-Change-Number: 618928
Gerrit-PatchSet: 8
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: D3r1ck01 <xsavitar.wiki(a)aol.com>
Gerrit-Reviewer: Hazard-SJ <hazardsjwiki(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <Ladsgroup(a)gmail.com>
Gerrit-Reviewer: Mpaa <mpaa.wiki(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: Zhuyifei1999 <zhuyifei1999(a)gmail.com>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged