Xqt submitted this change.

View Change

Approvals: jenkins-bot: Verified Xqt: Looks good to me, approved
[IMPR] make logging interface consistent

- all interface is like msg. *args, **kwargs and all parameters
are the same; all parameters of Python logging utility functions
are supported
- introduce layer argument for all logging methods as proposed
- rename text parameter to msg like in python.logging
- all arguments except msg are keyword arguments, all positional
arguments are dropped
- cleanup deprecated postitional arguments
- only use decoder if bytes is given with msg
- update frame due to deprecated_args decorators
- only update extra parameter if required but do not override the
given content
- rename tb in exception with exc_info to be sync with Python
logging.exception
- all Pywikibot logger output functions are similar to Python
logging function with few differences:
- no parameter has to be given with output and stdout; this enables
to print an empty line previously done with pywikibot.output('')
- if no parameter is given with exception(), the error message is
computed from sys.exc_info. If a parameter is given with exception,
it works like error() function. This is different with Python
logging exception where 'exc_info' is set to True which prints
the traceback by default.
- rename output function to info to be in sync with Python logging.info
but keep the output function for backward compatibility
- update usage of these functions
- update ui tests

Bug: T85620
Change-Id: I17759dd9f2f31ee4efa84f6b390b20998a63f188
---
M pwb.py
M pywikibot/__init__.py
M pywikibot/cosmetic_changes.py
M pywikibot/logging.py
M pywikibot/pagegenerators.py
M scripts/archivebot.py
M scripts/category.py
M scripts/checkimages.py
M scripts/dataextend.py
M scripts/download_dump.py
M scripts/interwiki.py
M scripts/maintenance/cache.py
M scripts/maintenance/colors.py
M scripts/replicate_wiki.py
M scripts/solve_disambiguation.py
M tests/aspects.py
M tests/ui_tests.py
17 files changed, 277 insertions(+), 216 deletions(-)

diff --git a/pwb.py b/pwb.py
index 6fddcec..3c46597 100755
--- a/pwb.py
+++ b/pwb.py
@@ -291,7 +291,7 @@

def find_alternates(filename, script_paths):
"""Search for similar filenames in the given script paths."""
- from pywikibot import config, input_choice, output
+ from pywikibot import config, input_choice, info
from pywikibot.bot import QuitKeyboardInterrupt, ShowingListOption

assert config.pwb_close_matches > 0, \
@@ -323,10 +323,10 @@
if len(similar_scripts) == 1:
script = similar_scripts[0]
wait_time = config.pwb_autostart_waittime
- output('NOTE: Starting the most similar script '
- '<<lightyellow>>{}.py<<default>>\n'
- ' in {} seconds; type CTRL-C to stop.'
- .format(script, wait_time))
+ info('NOTE: Starting the most similar script '
+ '<<lightyellow>>{}.py<<default>>\n'
+ ' in {} seconds; type CTRL-C to stop.'
+ .format(script, wait_time))
try:
sleep(wait_time) # Wait a bit to let it be cancelled
except KeyboardInterrupt:
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py
index 54780d2..b94b610 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -60,6 +60,7 @@
debug,
error,
exception,
+ info,
log,
output,
stdout,
@@ -78,12 +79,12 @@
'__version__',
'Bot', 'calledModuleName', 'Category', 'Claim', 'Coordinate', 'critical',
'CurrentPageBot', 'debug', 'error', 'exception', 'FilePage', 'handle_args',
- 'html2unicode', 'input', 'input_choice', 'input_yn', 'ItemPage',
- 'LexemeForm', 'LexemePage', 'LexemeSense', 'Link',
- 'log', 'MediaInfo', 'output', 'Page', 'PropertyPage', 'showDiff',
- 'show_help', 'Site', 'SiteLink', 'stdout', 'Timestamp', 'translate', 'ui',
- 'url2unicode', 'User', 'warning', 'WbGeoShape', 'WbMonolingualText',
- 'WbQuantity', 'WbTabularData', 'WbTime', 'WbUnknown', 'WikidataBot',
+ 'html2unicode', 'info', 'input', 'input_choice', 'input_yn', 'ItemPage',
+ 'LexemeForm', 'LexemePage', 'LexemeSense', 'Link', 'log', 'MediaInfo',
+ 'output', 'Page', 'PropertyPage', 'showDiff', 'show_help', 'Site',
+ 'SiteLink', 'stdout', 'Timestamp', 'translate', 'ui', 'url2unicode',
+ 'User', 'warning', 'WbGeoShape', 'WbMonolingualText', 'WbQuantity',
+ 'WbTabularData', 'WbTime', 'WbUnknown', 'WikidataBot',
)

# argvu is set by pywikibot.bot when it's imported
diff --git a/pywikibot/cosmetic_changes.py b/pywikibot/cosmetic_changes.py
index 09f12dc..522f153 100644
--- a/pywikibot/cosmetic_changes.py
+++ b/pywikibot/cosmetic_changes.py
@@ -283,7 +283,7 @@
if self.ignore == CANCEL.METHOD:
pywikibot.warning('Unable to perform "{}" on "{}"!'
.format(method.__name__, self.title))
- pywikibot.exception(e)
+ pywikibot.error(e)
else:
raise
return text if result is None else result
@@ -302,7 +302,7 @@
if self.ignore == CANCEL.PAGE:
pywikibot.warning('Skipped "{}", because an error occurred.'
.format(self.title))
- pywikibot.exception(e)
+ pywikibot.error(e)
return False
raise
else:
diff --git a/pywikibot/logging.py b/pywikibot/logging.py
index 1eaa02a..5399d03 100644
--- a/pywikibot/logging.py
+++ b/pywikibot/logging.py
@@ -1,21 +1,21 @@
"""User output/logging functions.

-Six output functions are defined. Each requires a string argument
+Six output functions are defined. Each requires a ``msg`` argument
All of these functions generate a message to the log file if
logging is enabled (`-log` or `-debug` command line arguments).

-The functions :func:`output()`, :func:`stdout()`, :func:`warning()` and
-:func:`error()` all display a message to the user through the logger
-object; the only difference is the priority level, which can be used by
-the application layer to alter the display. The :func:`stdout()`
-function should be used only for data that is the "result" of a script,
-as opposed to information messages to the user.
+The functions :func:`info` (alias :func:`output`), :func:`stdout`,
+:func:`warning` and :func:`error` all display a message to the user
+through the logger object; the only difference is the priority level,
+which can be used by the application layer to alter the display. The
+:func:`stdout` function should be used only for data that is the
+"result" of a script, as opposed to information messages to the user.

-The function :func:`log()` by default does not display a message to the
+The function :func:`log` by default does not display a message to the
user, but this can be altered by using the `-verbose` command line
option.

-The function :func:`debug()` only logs its messages, they are never
+The function :func:`debug` only logs its messages, they are never
displayed on the user console. :func:`debug()` takes a required second
argument, which is a string indicating the debugging layer.
"""
@@ -30,16 +30,17 @@

# logging levels
from logging import CRITICAL, DEBUG, ERROR, INFO, WARNING
-from typing import Any, Optional, Union
+from typing import Any

from pywikibot.backports import Callable, List
-
+from pywikibot.tools import deprecated_args, issue_deprecation_warning

STDOUT = 16 #:
VERBOSE = 18 #:
INPUT = 25 #:
"""Three additional logging levels which are implemented beside
-`CRITICAL`, `DEBUG`, `ERROR`, `INFO` and `WARNING`.
+:const:`CRITICAL`, :const:`DEBUG`, :const:`ERROR`, :const:`INFO` and
+:const:`WARNING`.

.. seealso:: :python:`Python Logging Levels<logging.html#logging-levels>`
"""
@@ -65,212 +66,266 @@
_init_routines[:] = [] # the global variable is used with slice operator


-def logoutput(text: object, decoder: Optional[str] = None,
- newline: bool = True, _level: int = INFO, _logger: str = '',
+# Note: The frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def logoutput(msg: Any,
+ *args: Any,
+ level: int = INFO,
**kwargs: Any) -> None:
"""Format output and send to the logging module.

Helper function used by all the user-output convenience functions.
It can be used to implement your own high-level output function with
- a different lgging level.
- """
- if _logger:
- logger = logging.getLogger('pywiki.' + _logger)
- else:
- logger = logging.getLogger('pywiki')
+ a different logging level.

+ `msg` can contain special sequences to create colored output. These
+ consist of the color name in angle bracket, e. g. <<lightpurple>>.
+ <<default>> resets the color.
+
+ Other keyword arguments are passed unchanged to the logger; so far,
+ the only argument that is useful is ``exc_info=True``, which causes
+ the log message to include an exception traceback.
+
+ :param msg: The message to be printed.
+ :param args: Not used yet; prevents positinal arguments except `msg`.
+ :param level: The logging level; supported by :func:`logoutput` only.
+ :keyword newline: If newline is True (default), a line feed will be
+ added after printing the msg.
+ :type newline: bool
+ :keyword layer: Suffix of the logger name separated by dot. By
+ default no suffix is used.
+ :type layer: str
+ :keyword decoder: If msg is bytes, this decoder is used to deccode.
+ Default is 'utf-8', fallback is 'iso8859-1'
+ :type decoder: str
+ :param kwargs: For the other keyword arguments refer
+ :python:`Logger.debug()<library/logging.html#logging.Logger.debug>`
+ and :pyhow:`logging-cookbook`
+ """
# invoke any init routines
if _init_routines:
_init()

- # frame 0 is logoutput() in this module,
- # frame 1 is the convenience function (output(), etc.)
- # frame 2 is whatever called the convenience function
- frame = sys._getframe(2)
+ # cleanup positional args
+ if level == ERROR:
+ keys = ('decoder', 'newline', 'exc_info')
+ elif level == DEBUG:
+ keys = ('layer', 'decoder', 'newline')
+ else:
+ keys = ('decoder', 'newline')
+ for i, arg in enumerate(args):
+ key = keys[i]
+ issue_deprecation_warning(
+ 'Positional argument {} ({})'.format(i + 1, arg),
+ 'keyword argument "{}={}"'.format(key, arg),
+ since='7.2.0')
+ if key in kwargs:
+ warning('{!r} is given as keyword argument {!r} already; ignoring '
+ '{!r}'.format(key, arg, kwargs[key]))
+ else:
+ kwargs[key] = arg

+ # frame 0 is logoutput() in this module,
+ # frame 1 is the deprecation wrapper of this function
+ # frame 2 is the convenience function (output(), etc.)
+ # frame 3 is the deprecation wrapper the convenience function
+ # frame 4 is whatever called the convenience function
+ newline = kwargs.pop('newline', True)
+ frame = sys._getframe(4)
module = os.path.basename(frame.f_code.co_filename)
context = {'caller_name': frame.f_code.co_name,
'caller_file': module,
'caller_line': frame.f_lineno,
'newline': ('\n' if newline else '')}
+ context.update(kwargs.pop('extra', {}))

- if isinstance(text, str):
- decoded_text = text
- elif isinstance(text, bytes):
- if decoder:
- decoded_text = text.decode(decoder)
- else:
- try:
- decoded_text = text.decode('utf-8')
- except UnicodeDecodeError:
- decoded_text = text.decode('iso8859-1')
- else:
- # looks like text is a non-text object.
- # Maybe it has a __str__ builtin ?
- # (allows to print Page, Site...)
- decoded_text = str(text)
+ decoder = kwargs.pop('decoder', 'utf-8')
+ if isinstance(msg, bytes):
+ try:
+ msg = msg.decode(decoder)
+ except UnicodeDecodeError:
+ msg = msg.decode('iso8859-1')

- logger.log(_level, decoded_text, extra=context, **kwargs)
+ layer = kwargs.pop('layer', '')
+ logger = logging.getLogger(('pywiki.' + layer).strip('.'))
+ logger.log(level, msg, extra=context, **kwargs)


-def output(text: object, decoder: Optional[str] = None, newline: bool = True,
- **kwargs: Any) -> None:
- """Output a message to the user via the userinterface.
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def info(msg: Any = '', *args: Any, **kwargs: Any) -> None:
+ """Output a message to the user with level :const:`INFO`.

- Works like print, but uses the encoding used by the user's console
- (console_encoding in the configuration file) instead of ASCII.
+ ``msg`` will be sent to stderr via :mod:`pywikibot.userinterfaces`.
+ It may be omitted and a newline is printed in that case.
+ The arguments are interpreted as for :func:`logoutput`.

- If decoder is None, text should be a unicode string. Otherwise it
- should be encoded in the given encoding.
+ .. versionadded:: 7.2
+ was renamed from :func:`output`.

- If newline is True, a line feed will be added after printing the text.
-
- text can contain special sequences to create colored output. These
- consist of the color name in angle bracket, e. g. <<lightpurple>>.
- <<default>> resets the color.
-
- Other keyword arguments are passed unchanged to the logger; so far, the
- only argument that is useful is "exc_info=True", which causes the
- log message to include an exception traceback.
+ .. seealso::
+ :python:`Logger.info()<library/logging.html#logging.Logger.info>`
"""
- logoutput(text, decoder, newline, INFO, **kwargs)
+ logoutput(msg, *args, **kwargs)


-def stdout(text: object, decoder: Optional[str] = None, newline: bool = True,
- **kwargs: Any) -> None:
- """Output script results to the user via the userinterface.
+output = info
+"""Synomym for :func:`info` for backward compatibility. The arguments
+are interpreted as for :func:`logoutput`.

- The text will be sent to standard output, so that it can be piped to
- another process. All other text will be sent to stderr.
- See: https://en.wikipedia.org/wiki/Pipeline_%28Unix%29
-
- :param text: the message printed via stdout logger to the user.
- :param decoder: If None, text should be a unicode string else it should
- be encoded in the given encoding.
- :param newline: If True, a line feed will be added after printing the text.
- :param kwargs: The keyword arguments can be found in the python doc:
- :pyhow:`logging-cookbook`
- """
- logoutput(text, decoder, newline, STDOUT, **kwargs)
+.. versionchanged:: 7.2
+ was renamed to :func:`info`; `text`was renamed to `msg`; `msg`
+ paramerer may be omitted; only keyword arguments are allowed except
+ for `msg`.
+.. seealso::
+ :python:`Logger.info()<library/logging.html#logging.Logger.info>`
+"""


-def warning(text: object, decoder: Optional[str] = None,
- newline: bool = True, **kwargs: Any) -> None:
- """Output a warning message to the user via the userinterface.
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def stdout(msg: Any = '', *args: Any, **kwargs: Any) -> None:
+ """Output script results to the user with level :const:`STDOUT`.

- :param text: the message the user wants to display.
- :param decoder: If None, text should be a unicode string else it
- should be encoded in the given encoding.
- :param newline: If True, a line feed will be added after printing the text.
- :param kwargs: The keyword arguments can be found in the python doc:
- :pyhow:`logging-cookbook`
- """
- logoutput(text, decoder, newline, WARNING, **kwargs)
+ ``msg`` will be sent to standard output (stdout) via
+ :mod:`pywikibot.userinterfaces`, so that it can be piped to another
+ process. All other functions will sent to stderr.
+ `msg` may be omitted and a newline is printed in that case.

-
-def error(text: object, decoder: Optional[str] = None, newline: bool = True,
- **kwargs: Any) -> None:
- """Output an error message to the user via the userinterface.
-
- :param text: the message containing the error which occurred.
- :param decoder: If None, text should be a unicode string else it should
- be encoded in the given encoding.
- :param newline: If True, a line feed will be added after printing the text.
- :param kwargs: The keyword arguments can be found in the python doc:
- :pyhow:`logging-cookbook`
- """
- logoutput(text, decoder, newline, ERROR, **kwargs)
-
-
-def log(text: object, decoder: Optional[str] = None, newline: bool = True,
- **kwargs: Any) -> None:
- """Output a record to the log file.
-
- :param text: the message which is to be logged to the log file.
- :param decoder: If None, text should be a unicode string else it should
- be encoded in the given encoding.
- :param newline: If True, a line feed will be added after printing the text.
- :param kwargs: The keyword arguments can be found in the python doc:
- :pyhow:`logging-cookbook`
- """
- logoutput(text, decoder, newline, VERBOSE, **kwargs)
-
-
-def critical(text: object, decoder: Optional[str] = None, newline: bool = True,
- **kwargs: Any) -> None:
- """Output a critical record to the user via the userinterface.
-
- :param text: the critical message which is to be displayed to the user.
- :param decoder: If None, text should be a unicode string else it should
- be encoded in the given encoding.
- :param newline: If True, a line feed will be added after printing the text.
- :param kwargs: The keyword arguments can be found in the python doc:
- :pyhow:`logging-cookbook`
- """
- logoutput(text, decoder, newline, CRITICAL, **kwargs)
-
-
-def debug(text: object, layer: str = '', decoder: Optional[str] = None,
- newline: bool = True, **kwargs: Any) -> None:
- """Output a debug record to the log file.
+ The arguments are interpreted as for :func:`logoutput`.

.. versionchanged:: 7.2
- `layer` parameter is optional.
-
- :param text: the message of the debug record to be logged to the log file.
- :param layer: dot-separated logger suffix to record this message
- upon. If not given only 'pywiki' is used as logger name.
- :param decoder: If None, text should be a unicode string else it should
- be encoded in the given encoding.
- :param newline: If True, a line feed will be added after printing the text.
- :param kwargs: The keyword arguments can be found in the python doc:
- :pyhow:`logging-cookbook`
+ `text`was renamed to `msg`; `msg` paramerer may be omitted;
+ only keyword arguments are allowed except for `msg`.
+ .. seealso::
+ - :python:`Logger.log()<library/logging.html#logging.Logger.log>`
+ - https://en.wikipedia.org/wiki/Pipeline_%28Unix%29
"""
- logoutput(text, decoder, newline, DEBUG, layer, **kwargs)
+ logoutput(msg, *args, level=STDOUT, **kwargs)


-def exception(
- msg: Union[Exception, str, None] = None,
- decoder: Optional[str] = None,
- newline: bool = True,
- tb: bool = False,
- **kwargs: Any
-) -> None:
- """Output an error traceback to the user via the userinterface.
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def warning(msg: Any, *args: Any, **kwargs: Any) -> None:
+ """Output a warning message to the user with level :const:`WARNING`.
+
+ ``msg`` will be sent to stderr via :mod:`pywikibot.userinterfaces`.
+ The arguments are interpreted as for :func:`logoutput`.
+
+ .. versionchanged:: 7.2
+ `text`was renamed to `msg`; only keyword arguments are allowed
+ except for `msg`.
+ .. seealso::
+ :python:`Logger.warning()<library/logging.html#logging.Logger.warning>`
+ """
+ logoutput(msg, *args, level=WARNING, **kwargs)
+
+
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def error(msg: Any, *args: Any, **kwargs: Any) -> None:
+ """Output an error message to the user with level :const:`ERROR`.
+
+ ``msg`` will be sent to stderr via :mod:`pywikibot.userinterfaces`.
+ The arguments are interpreted as for :func:`logoutput`.
+
+ .. versionchanged:: 7.2
+ `text`was renamed to `msg`; only keyword arguments are allowed
+ except for `msg`.
+ .. seealso::
+ :python:`Logger.error()<library/logging.html#logging.Logger.error>`
+ """
+ logoutput(msg, *args, level=ERROR, **kwargs)
+
+
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def log(msg: Any, *args: Any, **kwargs: Any) -> None:
+ """Output a record to the log file with level :const:`VERBOSE`.
+
+ The arguments are interpreted as for :func:`logoutput`.
+
+ .. versionchanged:: 7.2
+ `text`was renamed to `msg`; only keyword arguments are allowed
+ except for `msg`.
+ .. seealso::
+ :python:`Logger.log()<library/logging.html#logging.Logger.log>`
+ """
+ logoutput(msg, *args, level=VERBOSE, **kwargs)
+
+
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def critical(msg: Any, *args: Any, **kwargs: Any) -> None:
+ """Output a critical record to the user with level :const:`CRITICAL`.
+
+ ``msg`` will be sent to stderr via :mod:`pywikibot.userinterfaces`.
+ The arguments are interpreted as for :func:`logoutput`.
+
+ .. versionchanged:: 7.2
+ `text`was renamed to `msg`; only keyword arguments are allowed
+ except for `msg`.
+ .. seealso::
+ :python:`Logger.critical()
+ <library/logging.html#logging.Logger.critical>`
+ """
+ logoutput(msg, *args, level=CRITICAL, **kwargs)
+
+
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(text='msg') # since 7.2
+def debug(msg: Any, *args: Any, **kwargs: Any) -> None:
+ """Output a debug record to the log file with level :const:`DEBUG`.
+
+ The arguments are interpreted as for :func:`logoutput`.
+
+ .. versionchanged:: 7.2
+ `layer` parameter is optional; `text`was renamed to `msg`;
+ only keyword arguments are allowed except for `msg`.
+ .. seealso::
+ :python:`Logger.debug()<library/logging.html#logging.Logger.debug>`
+ """
+ logoutput(msg, *args, level=DEBUG, **kwargs)
+
+
+# Note: The logoutput frame must be updated if this decorator is removed
+@deprecated_args(tb='exc_info') # since 7.2
+def exception(msg: Any = None, *args: Any, **kwargs: Any) -> None:
+ """Output an error traceback to the user with level :const:`ERROR`.

Use directly after an 'except' statement::

...
except Exception:
- pywikibot.exception()
+ pywikibot.exception('exc_info'=True)
...

or alternatively::

...
except Exception as e:
- pywikibot.exception(e)
+ pywikibot.exception(e, 'exc_info'=True)
...

+ Without `exc_info` parameter this function works like :func:`error`
+ except that the `msg` parameter may be omitted.
This function should only be called from an Exception handler.
+ ``msg`` will be sent to stderr via :mod:`pywikibot.userinterfaces`.
+ The arguments are interpreted as for :func:`logoutput`.

- :param msg: If not None, contains the description of the exception
- that occurred.
- :param decoder: If None, text should be a unicode string else it should
- be encoded in the given encoding.
- :param newline: If True, a line feed will be added after printing the text.
- :param kwargs: The keyword arguments can be found in the python doc:
- :pyhow:`logging-cookbook`
- :param tb: Set to True in order to output traceback also.
+ .. versionchanged:: 7.2
+ only keyword arguments are allowed except for `msg`;
+ `exc_info` keyword is to be used instead of `tb`.
+ .. seealso::
+ :python:`Logger.exception()
+ <library/logging.html#logging.Logger.exception>`
+
+ The arguments are interpreted as for :meth:`output`.
"""
- if isinstance(msg, BaseException):
- if tb:
- kwargs['exc_info'] = 1
- else:
- exc_info = sys.exc_info()
- msg = '{}: {}'.format(repr(exc_info[1]).split('(')[0],
- str(exc_info[1]).strip())
- if tb:
- kwargs['exc_info'] = exc_info
+ if msg is None:
+ exc_type, value, _tb = sys.exc_info()
+ msg = str(value)
+ if not kwargs.get('exc_info', False):
+ msg += ' ({})'.format(exc_type.__name__)
assert msg is not None
- logoutput(msg, decoder, newline, ERROR, **kwargs)
+ error(msg, *args, **kwargs)
diff --git a/pywikibot/pagegenerators.py b/pywikibot/pagegenerators.py
index 50160b1..796cecf 100644
--- a/pywikibot/pagegenerators.py
+++ b/pywikibot/pagegenerators.py
@@ -1422,7 +1422,7 @@
pywikibot.warning('LogeventsPageGenerator: '
'failed to load page for {!r}; skipping'
.format(entry.data))
- pywikibot.exception(e)
+ pywikibot.error(e)


def NewpagesPageGenerator(site: OPT_SITE_TYPE = None,
@@ -1752,7 +1752,7 @@
namespaces = site.namespaces.resolve(namespaces)
except KeyError as e:
pywikibot.log('Failed resolving namespaces:')
- pywikibot.exception(e)
+ pywikibot.error(e)
raise

return (page for page in generator if page.namespace() in namespaces)
@@ -2707,7 +2707,7 @@
try:
import google
except ImportError:
- pywikibot.error('ERROR: generator GoogleSearchPageGenerator '
+ pywikibot.error('generator GoogleSearchPageGenerator '
"depends on package 'google'.\n"
'To install, please run: pip install google.')
sys.exit(1)
diff --git a/scripts/archivebot.py b/scripts/archivebot.py
index 13d362d..1ba136b 100755
--- a/scripts/archivebot.py
+++ b/scripts/archivebot.py
@@ -910,9 +910,8 @@
pywikibot.error('Missing or malformed template in page {}: {}'
.format(pg, e))
except Exception:
- pywikibot.error('Error occurred while processing page {}'
- .format(pg))
- pywikibot.exception(tb=True)
+ pywikibot.exception('Error occurred while processing page {}'
+ .format(pg), exc_info=True)


if __name__ == '__main__':
diff --git a/scripts/category.py b/scripts/category.py
index 0119536..5a7e12b 100755
--- a/scripts/category.py
+++ b/scripts/category.py
@@ -1114,8 +1114,7 @@
pywikibot.output(line)

# show the title of the page where the link was found.
- pywikibot.output('')
- pywikibot.output('>>> <<lightpurple>>{}<<default>> <<<'
+ pywikibot.output('\n>>> <<lightpurple>>{}<<default>> <<<'
.format(member.title()))

# determine a reasonable amount of context.
@@ -1151,8 +1150,7 @@
key=methodcaller('title'))

# show categories as possible choices with numbers
- pywikibot.output('')
-
+ pywikibot.output()
supercat_option = CatIntegerOption(0, len(supercatlist), 'u')
if not supercatlist:
pywikibot.output('This category has no supercategories.')
@@ -1171,7 +1169,7 @@
subcat_option.list_categories(cat_list)

# show possible options for the user
- pywikibot.output('')
+ pywikibot.output()
options = (supercat_option,
subcat_option,
StandardOption(
@@ -1248,7 +1246,7 @@

def treat(self, page) -> None:
"""Process page."""
- pywikibot.output('')
+ pywikibot.output()
self.move_to_category(page, self.cat, self.cat)


@@ -1343,7 +1341,7 @@
cat = pywikibot.Category(self.site, self.cat_title)
pywikibot.output('Generating tree...', newline=False)
tree = self.treeview(cat)
- pywikibot.output('')
+ pywikibot.output()
if self.filename:
pywikibot.output('Saving results in ' + self.filename)
with codecs.open(self.filename, 'a', 'utf-8') as f:
diff --git a/scripts/checkimages.py b/scripts/checkimages.py
index a929f54..0c9430e 100755
--- a/scripts/checkimages.py
+++ b/scripts/checkimages.py
@@ -745,7 +745,7 @@
self.num_notify[self.talk_page.title()] -= 1
err = None
if err:
- pywikibot.exception(err)
+ pywikibot.error(err)
pywikibot.output('Skipping saving talk page {}'
.format(self.talk_page))

@@ -1351,9 +1351,9 @@
pywikibot.output('Skipping {}...'.format(self.image_name))
self.skip_list.append(self.image_name)
if skip_number == 1:
- pywikibot.output('')
+ pywikibot.output()
return True
- pywikibot.output('')
+ pywikibot.output()
return False

@staticmethod
diff --git a/scripts/dataextend.py b/scripts/dataextend.py
index f8ee391..5f916df 100644
--- a/scripts/dataextend.py
+++ b/scripts/dataextend.py
@@ -1290,7 +1290,7 @@
if not self.url and not self.sparqlquery:
return
newclaims = []
- pywikibot.output('')
+ pywikibot.output()
pagerequest = None
if not self.skipfirst:
try:
@@ -1638,7 +1638,7 @@
if result:
newclaims.append((prop, result, self))

- pywikibot.output('')
+ pywikibot.output()
for (function, prop) in [
(self.findcoords, 'coordinates'),
]:
diff --git a/scripts/download_dump.py b/scripts/download_dump.py
index 66626d8..4a7b6cf 100755
--- a/scripts/download_dump.py
+++ b/scripts/download_dump.py
@@ -133,7 +133,7 @@
parts = 50
display_string = ''

- pywikibot.output('')
+ pywikibot.output()
for data in response.iter_content(100 * 1024):
result_file.write(data)

@@ -156,7 +156,7 @@
- len(display_string.rstrip()))

pywikibot.output(display_string, newline=False)
- pywikibot.output('')
+ pywikibot.output()

# Rename the temporary file to the target file
# if the download completes successfully
diff --git a/scripts/interwiki.py b/scripts/interwiki.py
index 9eb1dfd..d6473b0 100755
--- a/scripts/interwiki.py
+++ b/scripts/interwiki.py
@@ -1823,7 +1823,7 @@
page, linkedPage))

except OSError:
- pywikibot.output('ERROR: could not report backlinks')
+ pywikibot.error('could not report backlinks')


class InterwikiBot:
diff --git a/scripts/maintenance/cache.py b/scripts/maintenance/cache.py
index 512a818..cb24d54 100755
--- a/scripts/maintenance/cache.py
+++ b/scripts/maintenance/cache.py
@@ -268,7 +268,7 @@
except ValueError as e:
pywikibot.error('Failed loading {}'.format(
entry._cachefile_path()))
- pywikibot.exception(e, tb=True)
+ pywikibot.exception(e, exc_info=True)
continue

if use_accesstime is None:
@@ -294,7 +294,7 @@
pywikibot.error('Problems loading {} with key {}, {!r}'
.format(entry.filename, entry.key,
entry._parsed_key))
- pywikibot.exception(e, tb=True)
+ pywikibot.exception(e, exc_info=True)
continue

if func is None or func(entry):
diff --git a/scripts/maintenance/colors.py b/scripts/maintenance/colors.py
index 9a0434d..2f4543b 100755
--- a/scripts/maintenance/colors.py
+++ b/scripts/maintenance/colors.py
@@ -37,7 +37,7 @@
line = '{} {}'.format(bg_col.ljust(max_len_bc_color), line)
pywikibot.output(line)

- pywikibot.output('')
+ pywikibot.output()


if __name__ == '__main__':
diff --git a/scripts/replicate_wiki.py b/scripts/replicate_wiki.py
index f4e2478..18735fa 100755
--- a/scripts/replicate_wiki.py
+++ b/scripts/replicate_wiki.py
@@ -94,7 +94,7 @@
for s in self.sites:
s.login()
pywikibot.output(str(s), newline=False)
- pywikibot.output('')
+ pywikibot.output()

def check_sysops(self) -> None:
"""Check if sysops are the same on all wikis."""
@@ -145,9 +145,8 @@
pywikibot.output('Bizarre NoPageError that we are '
'just going to ignore')
except IsRedirectPageError:
- pywikibot.output(
- 'error: Redirectpage - todo: handle gracefully')
- pywikibot.output('')
+ pywikibot.error('Redirectpage - todo: handle gracefully')
+ pywikibot.output()

def generate_overviews(self) -> None:
"""Create page on wikis with overview of bot results."""
diff --git a/scripts/solve_disambiguation.py b/scripts/solve_disambiguation.py
index 63e3e2e..5e3d8a4 100755
--- a/scripts/solve_disambiguation.py
+++ b/scripts/solve_disambiguation.py
@@ -1084,7 +1084,7 @@
else:
pywikibot.output('\nThe following changes have been made:\n')
pywikibot.showDiff(original_text, text)
- pywikibot.output('')
+ pywikibot.output()
# save the page
self.setSummaryMessage(disamb_page, new_targets,
unlink_counter, dn)
diff --git a/tests/aspects.py b/tests/aspects.py
index c93da45..b2b8af8 100644
--- a/tests/aspects.py
+++ b/tests/aspects.py
@@ -467,9 +467,9 @@
'HTTP status: {} - {}'.format(
r.status_code, HTTPStatus(r.status_code).phrase))
except Exception as e:
- pywikibot.error('{}: accessing {} caused exception:'
- .format(cls.__name__, hostname))
- pywikibot.exception(e, tb=True)
+ pywikibot.exception('{}: accessing {} caused exception:'
+ .format(cls.__name__, hostname),
+ exc_info=True)

cls._checked_hostnames[hostname] = e
raise unittest.SkipTest(
diff --git a/tests/ui_tests.py b/tests/ui_tests.py
index cab4146..6df6054 100755
--- a/tests/ui_tests.py
+++ b/tests/ui_tests.py
@@ -160,17 +160,26 @@
pywikibot.exception('exception')
self.assertEqual(self.strout.getvalue(), '')
self.assertEqual(self.strerr.getvalue(),
- 'ERROR: TestExceptionError: Testing Exception\n')
+ 'ERROR: exception\n')
+
+ def test_exception_empty(self):
+ try:
+ raise TestExceptionError('Testing Exception')
+ except TestExceptionError:
+ pywikibot.exception()
+ self.assertEqual(self.strout.getvalue(), '')
+ self.assertEqual(self.strerr.getvalue(),
+ 'ERROR: Testing Exception (TestExceptionError)\n')

def test_exception_tb(self):
try:
raise TestExceptionError('Testing Exception')
except TestExceptionError:
- pywikibot.exception('exception', tb=True)
+ pywikibot.exception(exc_info=True)
self.assertEqual(self.strout.getvalue(), '')
stderrlines = self.strerr.getvalue().split('\n')
self.assertEqual(stderrlines[0],
- 'ERROR: TestExceptionError: Testing Exception')
+ 'ERROR: Testing Exception')
self.assertEqual(stderrlines[1], 'Traceback (most recent call last):')
self.assertEqual(stderrlines[3],
" raise TestExceptionError('Testing Exception')")

To view, visit change 630209. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I17759dd9f2f31ee4efa84f6b390b20998a63f188
Gerrit-Change-Number: 630209
Gerrit-PatchSet: 13
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: JJMC89 <JJMC89.Wikimedia@gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw@arctus.nl>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged