Xqt has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/722879 )
Change subject: [doc] Fix MediaWikiVersion doc string
......................................................................
[doc] Fix MediaWikiVersion doc string
Change-Id: I25c2b9223659327e29c68cd09864ea8514091b62
---
M pywikibot/tools/__init__.py
1 file changed, 1 insertion(+), 1 deletion(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/tools/__init__.py b/pywikibot/tools/__init__.py
index 61ca179..96bd494 100644
--- a/pywikibot/tools/__init__.py
+++ b/pywikibot/tools/__init__.py
@@ -409,7 +409,7 @@
Two versions are equal if their normal version and dev version are equal. A
version is greater if the normal version or dev version is greater. For
- example:
+ example::
1.34 < 1.34.1 < 1.35wmf1 < 1.35alpha < 1.35beta1 < 1.35beta2
< 1.35-rc-1 < 1.35-rc.2 < 1.35
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/722879
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: I25c2b9223659327e29c68cd09864ea8514091b62
Gerrit-Change-Number: 722879
Gerrit-PatchSet: 3
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
Xqt has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/722847 )
Change subject: [doc] Update ROADMAP.rst and CHANGELOG.md
......................................................................
[doc] Update ROADMAP.rst and CHANGELOG.md
Change-Id: I9b6318d2cb87197786d87a03dcd80f1059e36f76
---
M ROADMAP.rst
M scripts/CHANGELOG.md
2 files changed, 34 insertions(+), 9 deletions(-)
Approvals:
Xqt: Verified; Looks good to me, approved
diff --git a/ROADMAP.rst b/ROADMAP.rst
index 78a83cf..715e7f7 100644
--- a/ROADMAP.rst
+++ b/ROADMAP.rst
@@ -1,26 +1,35 @@
Current release changes
^^^^^^^^^^^^^^^^^^^^^^^
+Breaking changes
+----------------
+
* Support of Python 3.5.0 - 3.5.2 has been dropped (T286867)
+Code cleanups
+-------------
+
+* tools.RotatingFileHandler was removed in favour of logging.handlers.RotatingFileHandler
+* tools.DotReadableDict, tools.LazyRegex and tools.DeprecatedRegex classes were removed
+* tools.frozenmap was removed in favour of types.MappingProxyType
+* tools.empty_iterator() was removed in favour of iter(())
+* tools.concat_options() function was removed in favour of bot_choice.Option
+* tools.is_IP was be removed in favour of tools.is_ip_address()
+* textlib.unescape() function was be removed in favour of html.unescape()
+* APISite.deletepage() and APISite.deleteoldimage() methods were removed in favour of APISite.delete()
+* APISite.undeletepage() and APISite.undelete_file_versions() were be removed in favour of APISite.undelete() method
+
+
Deprecations
^^^^^^^^^^^^
* 6.5.0: OutputOption.output() method will be removed in favour of OutputOption.out property
-* 6.5.0: tools.RotatingFileHandler will be removed in favour of logging.handlers.RotatingFileHandler
* 6.4.0: Pywikibot `began using semantic versioning
<https://www.mediawiki.org/wiki/Manual:Pywikibot/Development/Guidelines#Depr…>`_,
all deprecated code will be removed in Pywikibot version 7.0.0.
* 6.2.0: Bot's availableOptions will be removed in favour of available_options
-* 6.2.0: Deprecated tools.is_IP will be removed
* 6.2.0: Usage of pywikibot.config2 is deprecated and will be dropped
* 6.2.0: Exceptions must be imported from exceptions namespace (T280227)
* 6.2.0: Deprecated exception identifiers will be removed (T280227)
-* 6.2.0: empty_iterator will be removed in favour of iter()
-* 6.1.0: tools.frozenmap will be removed in favour of types.MappingProxyType
-* 6.1.0: tools.DotReadableDict will be removed
-* 6.1.0: textlib.unescape() function will be removed in favour of html.unescape()
-* 6.0.1: Site.undeletepage() and Site.undelete_file_versions() will be removed in favour of Site.undelete() method
-* 6.0.1: Site.deletepage() and Site.deleteoldimage() will be removed in favour of Site.delete() method
* 5.0.0: Methods deprecated for 5 years or longer will be removed
diff --git a/scripts/CHANGELOG.md b/scripts/CHANGELOG.md
index 090ede4..f85a12a 100644
--- a/scripts/CHANGELOG.md
+++ b/scripts/CHANGELOG.md
@@ -1,9 +1,25 @@
# Schripts Changelog
+## 7.0.0
+*In development*
+
+### add_text
+* Provide -create and -createonly options (T291354)
+* Deprecated function get_text() was removed in favour of Page.text and BaseBot.skip_page()
+* Deprecated function put_text() was removed in favour of BaseBot.userPut() method
+* Deprecated function add_text() were remove in favour of textlib.add_text()
+
+### newitem
+* Do not pass OtherPageSaveRelatedError silently
+
+### touch
+*Do not pass OtherPageSaveRelatedError silently
+
+
## 6.6.1
*21 September 2021*
-## category
+### category
* Fix -match option
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/722847
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: I9b6318d2cb87197786d87a03dcd80f1059e36f76
Gerrit-Change-Number: 722847
Gerrit-PatchSet: 2
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/721331 )
Change subject: [cleanup] Remove deprecated RotatingFileHandler
......................................................................
[cleanup] Remove deprecated RotatingFileHandler
Change-Id: I581b0380e7117675fb50cf9e514dedce21ecb641
---
M pywikibot/bot.py
M pywikibot/tools/_logging.py
2 files changed, 1 insertion(+), 84 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/bot.py b/pywikibot/bot.py
index 3197e60..5efe486 100644
--- a/pywikibot/bot.py
+++ b/pywikibot/bot.py
@@ -64,7 +64,7 @@
__all__ = (
'CRITICAL', 'ERROR', 'INFO', 'WARNING', 'DEBUG', 'INPUT', 'STDOUT',
'VERBOSE', 'critical', 'debug', 'error', 'exception', 'log', 'warning',
- 'output', 'stdout', 'LoggingFormatter', 'RotatingFileHandler',
+ 'output', 'stdout', 'LoggingFormatter',
'init_handlers', 'writelogheader',
'input', 'input_choice', 'input_yn', 'input_list_choice', 'ui',
'Option', 'StandardOption', 'NestedOption', 'IntegerOption',
@@ -176,7 +176,6 @@
deprecated,
deprecated_args,
issue_deprecation_warning,
- redirect_func,
remove_last_args,
suppress_warnings,
)
@@ -2330,10 +2329,6 @@
set_interface(config.userinterface)
-# Deprecate RotatingFileHandler
-RotatingFileHandler = redirect_func(logging.handlers.RotatingFileHandler,
- since='6.5.0')
-
# NOTE: (T286348)
# Do not use ModuleDeprecationWrapper with this module.
# pywikibot.bot.ui would be wrapped through the ModuleDeprecationWrapper
diff --git a/pywikibot/tools/_logging.py b/pywikibot/tools/_logging.py
index 830b8d9..682f3e2 100644
--- a/pywikibot/tools/_logging.py
+++ b/pywikibot/tools/_logging.py
@@ -5,76 +5,6 @@
# Distributed under the terms of the MIT license.
#
import logging
-import os
-
-from pywikibot.tools import ModuleDeprecationWrapper
-
-
-class _RotatingFileHandler(logging.handlers.RotatingFileHandler):
-
- """DEPRECATED Modified RotatingFileHandler.
-
- Use namer instead. See:
- https://docs.python.org/3/howto/logging-cookbook.html#cookbook-rotator-namer
- """
-
- def doRollover(self):
- """Modified naming system for logging files.
-
- Overwrites the default Rollover renaming by inserting the count
- number between file name root and extension. If backupCount is
- >= 1, the system will successively create new files with the
- same pathname as the base file, but with inserting ".1", ".2"
- etc. in front of the filename suffix. For example, with a
- backupCount of 5 and a base file name of "app.log", you would
- get "app.log", "app.1.log", "app.2.log", ... through to
- "app.5.log". The file being written to is always "app.log" -
- when it gets filled up, it is closed and renamed to "app.1.log",
- and if files "app.1.log", "app.2.log" etc. already exist, then
- they are renamed to "app.2.log", "app.3.log" etc. respectively.
-
- If backupCount is == -1 do not rotate but create new numbered
- filenames. The newest file has the highest number except some
- older numbered files where deleted and the bot was restarted.
- In this case the ordering starts from the lowest available
- (unused) number.
- """
- fmt = '{}.{}{}'
-
- if self.stream:
- self.stream.close()
- self.stream = None
-
- root, ext = os.path.splitext(self.baseFilename)
-
- if self.backupCount > 0:
- for i in range(self.backupCount - 1, 0, -1):
- sfn = self.rotation_filename(fmt.format(root, i, ext))
- dfn = self.rotation_filename(fmt.format(root, i + 1, ext))
- if os.path.exists(sfn):
- if os.path.exists(dfn):
- os.remove(dfn)
- os.rename(sfn, dfn)
- dfn = self.rotation_filename(fmt.format(root, 1, ext))
- if os.path.exists(dfn):
- os.remove(dfn)
- self.rotate(self.baseFilename, dfn)
-
- elif self.backupCount == -1:
- if not hasattr(self, '_last_no'):
- self._last_no = 1
- while True:
- fn = self.rotation_filename(fmt.format(root, self._last_no,
- ext))
- self._last_no += 1
- if not os.path.exists(fn):
- break
- self.rotate(self.baseFilename, fn)
-
- self.mode = 'w'
-
- if not self.delay:
- self.stream = self._open()
class LoggingFormatter(logging.Formatter):
@@ -98,11 +28,3 @@
record.args = (msg,)
return super().format(record).rstrip()
-
-
-wrapper = ModuleDeprecationWrapper(__name__)
-wrapper.add_deprecated_attr(
- 'RotatingFileHandler', _RotatingFileHandler,
- replacement_name=('logging.handlers.RotatingFileHandler '
- 'with your own namer'),
- since='6.5.0')
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/721331
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: I581b0380e7117675fb50cf9e514dedce21ecb641
Gerrit-Change-Number: 721331
Gerrit-PatchSet: 2
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/+/721273 )
Change subject: [cleanup] Remove deleting/undeleting APISite methods
......................................................................
[cleanup] Remove deleting/undeleting APISite methods
Remove deletepage, deleteoldimage, undelete_page, undelete_file_versions
in favour of delete and undelete methods. All are deprecated since 6.0.1.
Change-Id: I966ec6d3b97340eb37b78ceed48eb0c1dfac6dff
---
M pywikibot/site/_apisite.py
1 file changed, 0 insertions(+), 62 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/site/_apisite.py b/pywikibot/site/_apisite.py
index 17ac882..70fc2ad 100644
--- a/pywikibot/site/_apisite.py
+++ b/pywikibot/site/_apisite.py
@@ -2120,38 +2120,6 @@
finally:
self.unlock_page(page)
- @deprecate_arg('summary', 'reason')
- @deprecated('delete()', since='20210330')
- def deletepage(self, page, reason: str):
- """Delete page from the wiki. Requires appropriate privilege level.
-
- :see: https://www.mediawiki.org/wiki/API:Delete
- Page to be deleted can be given either as Page object or as pageid.
-
- :param page: Page to be deleted or its pageid.
- :type page: :py:obj:`pywikibot.page.BasePage` or, for pageid,
- int or str
- :param reason: Deletion reason.
- :raises TypeError, ValueError: page has wrong type/value.
- """
- self.delete(page, reason)
-
- @deprecated('delete() with oldimage keyword parameter', since='20210330')
- def deleteoldimage(self, page, oldimage: str, reason: str):
- """Delete a specific version of a file. Requires appropriate privileges.
-
- :see: https://www.mediawiki.org/wiki/API:Delete
- The oldimage identifier for the specific version of the image must be
- provided.
-
- :param page: Page to be deleted or its pageid
- :type page: FilePage or, in case of pageid, int or str
- :param oldimage: oldimageid of the file version to be deleted.
- :param reason: Deletion reason.
- :raises TypeError, ValueError: page has wrong type/value.
- """
- self.delete(page, reason, oldimage=oldimage)
-
@need_right('undelete')
def undelete(self, page, reason: str, *, revisions=None, fileids=None):
"""Undelete page from the wiki. Requires appropriate privilege level.
@@ -2204,36 +2172,6 @@
finally:
self.unlock_page(page)
- @deprecate_arg('summary', 'reason')
- @deprecated('undelete()', since='20210330')
- def undelete_page(self, page, reason: str, revisions=None):
- """DEPRECATED. Undelete page from the wiki.
-
- :see: https://www.mediawiki.org/wiki/API:Undelete
-
- :param page: Page to be deleted.
- :type page: pywikibot.BasePage
- :param revisions: List of timestamps to restore.
- If None, restores all revisions.
- :type revisions: list
- :param reason: Undeletion reason.
- """
- self.undelete(page, reason, revisions=revisions)
-
- @deprecated('undelete() with fileids parameter', since='20210330')
- def undelete_file_versions(self, page, reason: str, fileids=None):
- """DEPRECATED. Undelete page from the wiki.
-
- :see: https://www.mediawiki.org/wiki/API:Undelete
-
- :param page: Page to be deleted.
- :type page: pywikibot.BasePage
- :param reason: Undeletion reason.
- :param fileids: List of fileids to restore.
- :type fileids: list
- """
- self.undelete(page, reason, fileids=fileids)
-
_protect_errors = {
'noapiwrite': 'API editing not enabled on {site} wiki',
'writeapidenied': 'User {user} not allowed to edit through the API',
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/721273
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: I966ec6d3b97340eb37b78ceed48eb0c1dfac6dff
Gerrit-Change-Number: 721273
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/+/721264 )
Change subject: [py3.5] Drop support for Python 3.5.0 - 3.5.2
......................................................................
[py3.5] Drop support for Python 3.5.0 - 3.5.2
Bug: T286867
Change-Id: I0c9d00d32e6031e0549b0d13d34b4b70fcbb0b86
---
M .appveyor.yml
M ROADMAP.rst
M appveyor_install.ps1
M docs/index.rst
M pywikibot/README.rst
M pywikibot/__init__.py
M pywikibot/backports.py
M setup.py
M tests/utils.py
9 files changed, 13 insertions(+), 28 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/.appveyor.yml b/.appveyor.yml
index 050712d..f5e4a2e 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -15,8 +15,8 @@
# Test the lowest supported release of each major Python version
- - PYTHON: "C:\\Python350-x64"
- PYTHON_VERSION: "3.5.0"
+ - PYTHON: "C:\\Python353-x64"
+ PYTHON_VERSION: "3.5.3"
PYTHON_ARCH: "64"
# Appveyor pre-installs these versions onto build machines
@@ -72,7 +72,7 @@
- git submodule update --init
# Download the Appveyor Python build accessories into subdirectory .\appveyor
- mkdir appveyor
- # Download Python 3.5.0 which isn't pre-installed
+ # Download Python 3.5.3 which isn't pre-installed
- ps: ./appveyor_install.ps1
- python --version
- python -c "import struct; print('PYTHON_ARCH' + chr(58), struct.calcsize('P') << 3)"
diff --git a/ROADMAP.rst b/ROADMAP.rst
index 9104fe8..78a83cf 100644
--- a/ROADMAP.rst
+++ b/ROADMAP.rst
@@ -1,13 +1,12 @@
Current release changes
^^^^^^^^^^^^^^^^^^^^^^^
-* (No changes yet)
+* Support of Python 3.5.0 - 3.5.2 has been dropped (T286867)
Deprecations
^^^^^^^^^^^^
-* 6.6.0: Support of Python 3.5.0 - 3.5.2 will be dropped with Pywikibot 7 (T286867)
* 6.5.0: OutputOption.output() method will be removed in favour of OutputOption.out property
* 6.5.0: tools.RotatingFileHandler will be removed in favour of logging.handlers.RotatingFileHandler
* 6.4.0: Pywikibot `began using semantic versioning
diff --git a/appveyor_install.ps1 b/appveyor_install.ps1
index 01c168e..00c01f4 100644
--- a/appveyor_install.ps1
+++ b/appveyor_install.ps1
@@ -60,7 +60,7 @@
function DownloadPython ($python_version, $platform_suffix) {
$major, $minor, $micro, $prerelease = ParsePythonVersion $python_version
- # Only Python 3.5+ is supported
+ # Only Python 3.5.3+ is supported
$dir = "$major.$minor.$micro"
$ext = "exe"
if ($platform_suffix) {
@@ -126,7 +126,7 @@
function main () {
- if ($env:PYTHON_VERSION -eq "3.5.0") {
+ if ($env:PYTHON_VERSION -eq "3.5.3") {
InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
}
}
diff --git a/docs/index.rst b/docs/index.rst
index ab176ec..b68cb36 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,7 +19,7 @@
whether you have Python installed and to find its version, just type
``python`` at the CMD or shell prompt.
-Python 3.5 or higher is currently required to run the bot, but Python 3.6
+Python 3.5.3 or higher is currently required to run the bot, but Python 3.6
or higher is recommended.
Pywikibot and this documentation are licensed under the
diff --git a/pywikibot/README.rst b/pywikibot/README.rst
index 08b668f..c0b63fb 100644
--- a/pywikibot/README.rst
+++ b/pywikibot/README.rst
@@ -27,7 +27,7 @@
* python-tkinter (optional, used by some experimental GUI stuff)
-You need to have at least Python version `3.5.0 <http://www.python.org/download/>`_
+You need to have at least Python version `3.5.3 <http://www.python.org/download/>`_
or newer installed on your computer to be able to run any of the code in this
package. Please refer the manual at mediawiki for further details and
restrictions.
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py
index 926b280..3d96af8 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -69,7 +69,7 @@
)
from pywikibot.tools import classproperty
from pywikibot.tools import deprecate_arg as _deprecate_arg
-from pywikibot.tools import normalize_username, PYTHON_VERSION
+from pywikibot.tools import normalize_username
from pywikibot.tools.formatter import color_format
@@ -103,15 +103,6 @@
argvu = [] # type: List[str]
-if PYTHON_VERSION < (3, 5, 3):
- warn("""
-Python {version} will be dropped with release 7.0 soon.
-It is recommended to use Python 3.5.3 or above.
-See T286867 for further information.
-""".format(version=sys.version.split(maxsplit=1)[0]),
- FutureWarning) # probably adjust the line no in utils.execute()
-
-
class Timestamp(datetime.datetime):
"""Class for handling MediaWiki timestamps.
diff --git a/pywikibot/backports.py b/pywikibot/backports.py
index 9ae2e7b..e6136fd 100644
--- a/pywikibot/backports.py
+++ b/pywikibot/backports.py
@@ -44,9 +44,7 @@
# typing
-if PYTHON_VERSION < (3, 5, 2):
- from typing import Dict as DefaultDict
-elif PYTHON_VERSION < (3, 9):
+if PYTHON_VERSION < (3, 9):
from typing import DefaultDict # type: ignore[misc]
else:
from collections import ( # type: ignore[misc] # noqa: N812
diff --git a/setup.py b/setup.py
index c81d607..3b2c386 100644
--- a/setup.py
+++ b/setup.py
@@ -42,13 +42,13 @@
Pywikibot is not available on:
{version}
-This version of Pywikibot only supports Python 3.5+.
+This version of Pywikibot only supports Python 3.5.3+.
"""
def python_is_supported():
"""Check that Python is supported."""
- return PYTHON_VERSION >= (3, 5, 0)
+ return PYTHON_VERSION >= (3, 5, 3)
if not python_is_supported(): # pragma: no cover
@@ -248,7 +248,7 @@
maintainer_email=metadata.__maintainer_email__,
license=metadata.__license__,
packages=get_packages(name),
- python_requires='>=3.5.0',
+ python_requires='>=3.5.3',
install_requires=dependencies,
extras_require=extra_deps,
url=metadata.__url__,
diff --git a/tests/utils.py b/tests/utils.py
index a9c6a52..5b4741d 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -20,7 +20,6 @@
from pywikibot.exceptions import APIError
from pywikibot.login import LoginStatus
from pywikibot.site import Namespace
-from pywikibot.tools import PYTHON_VERSION
from tests import _pwb_py
@@ -446,8 +445,6 @@
:param command: executable to run and arguments to use
:type command: list of str
"""
- if PYTHON_VERSION < (3, 5, 3):
- command.insert(1, '-W ignore::FutureWarning:pywikibot:112')
if cryptography_version and cryptography_version < [1, 3, 4]:
command.insert(1, '-W ignore:Old version of cryptography:Warning')
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/721264
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: I0c9d00d32e6031e0549b0d13d34b4b70fcbb0b86
Gerrit-Change-Number: 721264
Gerrit-PatchSet: 5
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/+/710382 )
Change subject: [IMPR] __init__.py type hints
......................................................................
[IMPR] __init__.py type hints
Bug: T286403
Change-Id: I300b0a746bf5b65d6d646cf798740af21898c443
---
M pywikibot/__init__.py
1 file changed, 111 insertions(+), 85 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py
index 926b280..88397c8 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -33,7 +33,14 @@
__version__,
)
from pywikibot._wbtypes import WbRepresentation as _WbRepresentation
-from pywikibot.backports import cache, removesuffix, Dict, List
+from pywikibot.backports import (
+ cache,
+ removesuffix,
+ Callable,
+ Dict,
+ List,
+ Tuple,
+)
from pywikibot.bot import (
Bot,
CurrentPageBot,
@@ -72,6 +79,24 @@
from pywikibot.tools import normalize_username, PYTHON_VERSION
from pywikibot.tools.formatter import color_format
+TO_DECIMAL_TYPE = Union[int, float, str, 'Decimal', None]
+
+# TODO: replace these after T286867
+
+STR_OR_TIMESTAMP = Any # Union[str, 'Timestamp']
+OPT_STR_OR_SITE = Any # Union[str, 'pywikibot.site.BaseSite', None]
+OPT_STR_OR_ITEM_PAGE = Any # Union[str, 'pywikibot.page.ItemPage', None]
+OPT_STR_OR_FAMILY = Any # Union[str, 'pywikibot.family.Family', None]
+
+TIMESTAMP_CLASS = Any # Type['Timestamp']
+COORDINATE_CLASS = Any # Type['Coordinate']
+WB_TIME_CLASS = Any # Type['WbTime']
+WB_QUANTITY_CLASS = Any # Type['WbQuantity']
+WB_MONOLINGUAL_TEXT_CLASS = Any # Type['WbMonolingualText']
+WB_DATA_PAGE_CLASS = Any # Type['_WbDataPage']
+WB_GEO_SHAPE_CLASS = Any # Type['WbGeoShape']
+WB_TABULAR_DATA_CLASS = Any # Type['WbTabularData']
+WB_UNKNOWN_CLASS = Any # Type['WbUnknown']
__all__ = (
'__copyright__', '__description__', '__download_url__', '__license__',
@@ -135,17 +160,17 @@
mediawikiTSFormat = '%Y%m%d%H%M%S'
_ISO8601Format_new = '{0:+05d}-{1:02d}-{2:02d}T{3:02d}:{4:02d}:{5:02d}Z'
- def clone(self):
+ def clone(self) -> datetime.datetime:
"""Clone this instance."""
return self.replace(microsecond=self.microsecond)
@classproperty
- def ISO8601Format(cls):
+ def ISO8601Format(cls: TIMESTAMP_CLASS) -> str:
"""ISO8601 format string class property for compatibility purpose."""
return cls._ISO8601Format()
@classmethod
- def _ISO8601Format(cls, sep: str = 'T') -> str:
+ def _ISO8601Format(cls: TIMESTAMP_CLASS, sep: str = 'T') -> str:
"""ISO8601 format string.
:param sep: one-character separator, placed between the date and time
@@ -155,14 +180,13 @@
return '%Y-%m-%d{}%H:%M:%SZ'.format(sep)
@classmethod
- def fromISOformat(cls, ts, sep: str = 'T'):
+ def fromISOformat(cls: TIMESTAMP_CLASS, ts: STR_OR_TIMESTAMP,
+ sep: str = 'T') -> 'Timestamp':
"""Convert an ISO 8601 timestamp to a Timestamp object.
:param ts: ISO 8601 timestamp or a Timestamp object already
- :type ts: str or Timestamp
:param sep: one-character separator, placed between the date and time
:return: Timestamp object
- :rtype: Timestamp
"""
# If inadvertently passed a Timestamp object, use replace()
# to create a clone.
@@ -171,7 +195,8 @@
return cls.strptime(ts, cls._ISO8601Format(sep))
@classmethod
- def fromtimestampformat(cls, ts):
+ def fromtimestampformat(cls: TIMESTAMP_CLASS, ts: STR_OR_TIMESTAMP
+ ) -> 'Timestamp':
"""Convert a MediaWiki internal timestamp to a Timestamp object."""
# If inadvertently passed a Timestamp object, use replace()
# to create a clone.
@@ -181,7 +206,7 @@
ts += '000'
return cls.strptime(ts, cls.mediawikiTSFormat)
- def isoformat(self, sep='T'):
+ def isoformat(self, sep: str = 'T') -> str: # type: ignore[override]
"""
Convert object to an ISO 8601 timestamp accepted by MediaWiki.
@@ -191,15 +216,15 @@
"""
return self.strftime(self._ISO8601Format(sep))
- def totimestampformat(self):
+ def totimestampformat(self) -> str:
"""Convert object to a MediaWiki internal timestamp."""
return self.strftime(self.mediawikiTSFormat)
- def __str__(self):
+ def __str__(self) -> str:
"""Return a string format recognized by the API."""
return self.isoformat()
- def __add__(self, other):
+ def __add__(self, other: datetime.timedelta) -> 'Timestamp':
"""Perform addition, returning a Timestamp instead of datetime."""
newdt = super().__add__(other)
if isinstance(newdt, datetime.datetime):
@@ -208,7 +233,8 @@
newdt.tzinfo)
return newdt
- def __sub__(self, other):
+ def __sub__(self, other: datetime.timedelta # type: ignore[override]
+ ) -> 'Timestamp':
"""Perform subtraction, returning a Timestamp instead of datetime."""
newdt = super().__sub__(other)
if isinstance(newdt, datetime.datetime):
@@ -225,18 +251,19 @@
_items = ('lat', 'lon', 'entity')
@_deprecate_arg('entity', 'globe_item')
- def __init__(self, lat: float, lon: float, alt=None,
+ def __init__(self, lat: float, lon: float, alt: Optional[float] = None,
precision: Optional[float] = None,
globe: Optional[str] = None, typ: str = '',
name: str = '', dim: Optional[int] = None,
- site: Optional[DataSite] = None, globe_item=None,
- primary: bool = False):
+ site: Optional[DataSite] = None,
+ globe_item: OPT_STR_OR_ITEM_PAGE = None,
+ primary: bool = False) -> None:
"""
Represent a geo coordinate.
:param lat: Latitude
:param lon: Longitude
- :param alt: Altitude? TODO FIXME
+ :param alt: Altitude
:param precision: precision
:param globe: Which globe the point is on
:param typ: The type of coordinate point
@@ -246,7 +273,6 @@
:param globe_item: The Wikibase item for the globe, or the entity URI
of this Wikibase item. Takes precedence over 'globe'
if present.
- :type globe_item: pywikibot.ItemPage or str
:param primary: True for a primary set of coordinates
"""
self.lat = lat
@@ -267,7 +293,7 @@
self.globe = globe
@property
- def entity(self):
+ def entity(self) -> str:
"""Return the entity uri of the globe."""
if not self._entity:
if self.globe not in self.site.globes():
@@ -281,7 +307,7 @@
return self._entity
- def toWikibase(self) -> dict:
+ def toWikibase(self) -> Dict[str, Any]:
"""
Export the data to a JSON object for the Wikibase API.
@@ -297,7 +323,7 @@
}
@classmethod
- def fromWikibase(cls, data: Dict[str, Any],
+ def fromWikibase(cls: COORDINATE_CLASS, data: Dict[str, Any],
site: Optional[DataSite] = None) -> 'Coordinate':
"""
Constructor to create an object from Wikibase's JSON output.
@@ -359,7 +385,7 @@
return self._precision
@precision.setter
- def precision(self, value):
+ def precision(self, value: float) -> None:
self._precision = value
def precisionToDim(self) -> Optional[int]:
@@ -398,7 +424,7 @@
return self._dim
def get_globe_item(self, repo: Optional[DataSite] = None,
- lazy_load: bool = False):
+ lazy_load: bool = False) -> 'ItemPage':
"""
Return the ItemPage corresponding to the globe.
@@ -458,7 +484,7 @@
after: int = 0,
timezone: int = 0,
calendarmodel: Optional[str] = None,
- site: Optional[DataSite] = None):
+ site: Optional[DataSite] = None) -> None:
"""Create a new WbTime object.
The precision can be set by the Wikibase int value (0-14) or by a human
@@ -533,19 +559,20 @@
and precision in self.PRECISION.values()):
self.precision = precision
elif precision in self.PRECISION:
+ assert isinstance(precision, str)
self.precision = self.PRECISION[precision]
else:
raise ValueError('Invalid precision: "{}"'.format(precision))
@classmethod
- def fromTimestr(cls,
+ def fromTimestr(cls: WB_TIME_CLASS,
datetimestr: str,
precision: Union[int, str] = 14,
before: int = 0,
after: int = 0,
timezone: int = 0,
calendarmodel: Optional[str] = None,
- site: Optional[DataSite] = None):
+ site: Optional[DataSite] = None) -> 'WbTime':
"""Create a new WbTime object from a UTC date/time string.
The timestamp differs from ISO 8601 in that:
@@ -565,7 +592,6 @@
:param timezone: Timezone information in minutes.
:param calendarmodel: URI identifying the calendar model
:param site: The Wikibase site
- :rtype: pywikibot.WbTime
"""
match = re.match(r'([-+]?\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)Z',
datetimestr)
@@ -577,15 +603,15 @@
precision, before, after, timezone, calendarmodel, site)
@classmethod
- def fromTimestamp(cls, timestamp, precision: Union[int, str] = 14,
+ def fromTimestamp(cls: WB_TIME_CLASS, timestamp: 'Timestamp',
+ precision: Union[int, str] = 14,
before: int = 0, after: int = 0,
timezone: int = 0, calendarmodel: Optional[str] = None,
- site: Optional[DataSite] = None):
+ site: Optional[DataSite] = None) -> 'WbTime':
"""
Create a new WbTime object from a pywikibot.Timestamp.
:param timestamp: Timestamp
- :type timestamp: pywikibot.Timestamp
:param precision: The unit of the precision of the time.
:param before: Number of units after the given time it could be, if
uncertain. The unit is given by the precision.
@@ -594,7 +620,6 @@
:param timezone: Timezone information in minutes.
:param calendarmodel: URI identifying the calendar model
:param site: The Wikibase site
- :rtype: pywikibot.WbTime
"""
return cls.fromTimestr(timestamp.isoformat(), precision=precision,
before=before, after=after,
@@ -630,7 +655,7 @@
return Timestamp.fromISOformat(
self.toTimestr(force_iso=True).lstrip('+'))
- def toWikibase(self) -> dict:
+ def toWikibase(self) -> Dict[str, Any]:
"""
Convert the data to a JSON object for the Wikibase API.
@@ -647,7 +672,7 @@
@classmethod
@_deprecate_arg('wb', 'data')
- def fromWikibase(cls, data: Dict[str, Any],
+ def fromWikibase(cls: WB_TIME_CLASS, data: Dict[str, Any],
site: Optional[DataSite] = None) -> 'WbTime':
"""
Create a WbTime from the JSON data given by the Wikibase API.
@@ -667,7 +692,7 @@
_items = ('amount', 'upperBound', 'lowerBound', 'unit')
@staticmethod
- def _require_errors(site: DataSite) -> bool:
+ def _require_errors(site: Optional[DataSite]) -> bool:
"""
Check if Wikibase site is so old it requires error bounds to be given.
@@ -683,7 +708,7 @@
return site.mw_version < '1.29.0-wmf.2'
@staticmethod
- def _todecimal(value: str) -> Optional[Decimal]:
+ def _todecimal(value: TO_DECIMAL_TYPE) -> Optional[Decimal]:
"""
Convert a string to a Decimal for use in WbQuantity.
@@ -698,7 +723,7 @@
return Decimal(str(value))
@staticmethod
- def _fromdecimal(value: Decimal) -> Optional[str]:
+ def _fromdecimal(value: Optional[Decimal]) -> Optional[str]:
"""
Convert a Decimal to a string representation suitable for WikiBase.
@@ -706,24 +731,20 @@
:param value: decimal number to convert
"""
- if value is None:
- return None
- return format(value, '+g')
+ return format(value, '+g') if value is not None else None
- def __init__(self, amount, unit=None, error=None,
- site: Optional[DataSite] = None):
+ def __init__(self, amount: TO_DECIMAL_TYPE,
+ unit: OPT_STR_OR_ITEM_PAGE = None,
+ error: Union[TO_DECIMAL_TYPE,
+ Tuple[TO_DECIMAL_TYPE, TO_DECIMAL_TYPE]] = None,
+ site: Optional[DataSite] = None) -> None:
"""
Create a new WbQuantity object.
:param amount: number representing this quantity
- :type amount: str or Decimal. Other types are accepted, and
- converted via str to Decimal.
:param unit: the Wikibase item for the unit or the entity URI of this
Wikibase item.
- :type unit: pywikibot.ItemPage, str or None
:param error: the uncertainty of the amount (e.g. ±1)
- :type error: same as amount, or tuple of two values, where the first
- value is the upper error and the second is the lower error value.
:param site: The Wikibase site
"""
if amount is None:
@@ -742,25 +763,28 @@
self.upperBound = self.lowerBound = None
else:
if error is None:
- upperError = lowerError = Decimal(0)
+ upperError = lowerError = Decimal(0) # type: Optional[Decimal]
elif isinstance(error, tuple):
upperError = self._todecimal(error[0])
lowerError = self._todecimal(error[1])
else:
upperError = lowerError = self._todecimal(error)
+ assert upperError is not None and lowerError is not None
+ assert self.amount is not None
+
self.upperBound = self.amount + upperError
self.lowerBound = self.amount - lowerError
@property
- def unit(self):
+ def unit(self) -> str:
"""Return _unit's entity uri or '1' if _unit is None."""
if isinstance(self._unit, ItemPage):
return self._unit.concept_uri()
return self._unit or '1'
def get_unit_item(self, repo: Optional[DataSite] = None,
- lazy_load: bool = False):
+ lazy_load: bool = False) -> 'ItemPage':
"""
Return the ItemPage corresponding to the unit.
@@ -782,7 +806,7 @@
self._unit = ItemPage.from_entity_uri(repo, self._unit, lazy_load)
return self._unit
- def toWikibase(self) -> dict:
+ def toWikibase(self) -> Dict[str, Any]:
"""
Convert the data to a JSON object for the Wikibase API.
@@ -797,7 +821,7 @@
@classmethod
@_deprecate_arg('wb', 'data')
- def fromWikibase(cls, data: Dict[str, Any],
+ def fromWikibase(cls: WB_QUANTITY_CLASS, data: Dict[str, Any],
site: Optional[DataSite] = None) -> 'WbQuantity':
"""
Create a WbQuantity from the JSON data given by the Wikibase API.
@@ -836,7 +860,7 @@
self.text = text
self.language = language
- def toWikibase(self) -> dict:
+ def toWikibase(self) -> Dict[str, Any]:
"""
Convert the data to a JSON object for the Wikibase API.
@@ -849,7 +873,7 @@
@classmethod
@_deprecate_arg('wb', 'data')
- def fromWikibase(cls, data: Dict[str, Any],
+ def fromWikibase(cls: WB_MONOLINGUAL_TEXT_CLASS, data: Dict[str, Any],
site: Optional[DataSite] = None) -> 'WbMonolingualText':
"""
Create a WbMonolingualText from the JSON data given by Wikibase API.
@@ -872,7 +896,8 @@
_items = ('page', )
@classmethod
- def _get_data_site(cls, repo_site: DataSite) -> APISite:
+ def _get_data_site(cls: WB_DATA_PAGE_CLASS, repo_site: DataSite
+ ) -> APISite:
"""
Return the site serving as a repository for a given data type.
@@ -883,7 +908,8 @@
raise NotImplementedError
@classmethod
- def _get_type_specifics(cls, site: DataSite) -> dict:
+ def _get_type_specifics(cls: WB_DATA_PAGE_CLASS, site: DataSite
+ ) -> Dict[str, Any]:
"""
Return the specifics for a given data type.
@@ -901,15 +927,14 @@
raise NotImplementedError
@staticmethod
- def _validate(page, data_site, ending: str, label: str):
+ def _validate(page: 'Page', data_site: 'BaseSite', ending: str,
+ label: str) -> None:
"""
Validate the provided page against general and type specific rules.
:param page: Page containing the data.
- :type page: pywikibot.Page
:param data_site: The site serving as a repository for the given
data type.
- :type data_site: APISite
:param ending: Required filetype-like ending in page titles.
E.g. '.map'
:param label: Label describing the data type in error messages.
@@ -942,12 +967,11 @@
"Page must be in 'Data:' namespace and end in '{}' "
'for {}.'.format(ending, label))
- def __init__(self, page, site: Optional[DataSite] = None):
+ def __init__(self, page: 'Page', site: Optional[DataSite] = None) -> None:
"""
Create a new _WbDataPage object.
:param page: page containing the data
- :type page: pywikibot.Page
:param site: The Wikibase site
"""
site = site or Site().data_repository()
@@ -956,7 +980,7 @@
specifics['ending'], specifics['label'])
self.page = page
- def __hash__(self):
+ def __hash__(self) -> int:
"""Override super.hash() as toWikibase is a string for _WbDataPage."""
return hash(self.toWikibase())
@@ -969,13 +993,13 @@
return self.page.title()
@classmethod
- def fromWikibase(cls, page_name: str, site: DataSite):
+ def fromWikibase(cls: WB_DATA_PAGE_CLASS, page_name: str,
+ site: Optional[DataSite]) -> '_WbDataPage':
"""
Create a _WbDataPage from the JSON data given by the Wikibase API.
:param page_name: page name from Wikibase value
:param site: The Wikibase site
- :rtype: pywikibot._WbDataPage
"""
# TODO: This method signature does not match our parent class (which
# takes a dictionary argument rather than a string). We should either
@@ -990,7 +1014,7 @@
"""A Wikibase geo-shape representation."""
@classmethod
- def _get_data_site(cls, site: DataSite) -> APISite:
+ def _get_data_site(cls: WB_GEO_SHAPE_CLASS, site: DataSite) -> APISite:
"""
Return the site serving as a geo-shape repository.
@@ -999,7 +1023,8 @@
return site.geo_shape_repository()
@classmethod
- def _get_type_specifics(cls, site: DataSite) -> dict:
+ def _get_type_specifics(cls: WB_GEO_SHAPE_CLASS, site: DataSite
+ ) -> Dict[str, Any]:
"""
Return the specifics for WbGeoShape.
@@ -1017,7 +1042,7 @@
"""A Wikibase tabular-data representation."""
@classmethod
- def _get_data_site(cls, site: DataSite) -> APISite:
+ def _get_data_site(cls: WB_TABULAR_DATA_CLASS, site: DataSite) -> APISite:
"""
Return the site serving as a tabular-data repository.
@@ -1026,7 +1051,8 @@
return site.tabular_data_repository()
@classmethod
- def _get_type_specifics(cls, site: DataSite) -> dict:
+ def _get_type_specifics(cls: WB_TABULAR_DATA_CLASS, site: DataSite
+ ) -> Dict[str, Any]:
"""
Return the specifics for WbTabularData.
@@ -1054,7 +1080,7 @@
_items = ('json',)
- def __init__(self, json):
+ def __init__(self, json: Dict[str, Any]) -> None:
"""
Create a new WbUnknown object.
@@ -1062,7 +1088,7 @@
"""
self.json = json
- def toWikibase(self) -> dict:
+ def toWikibase(self) -> Dict[str, Any]:
"""
Return the JSON object for the Wikibase API.
@@ -1072,7 +1098,7 @@
@classmethod
@_deprecate_arg('json', 'data')
- def fromWikibase(cls, data: Dict[str, Any],
+ def fromWikibase(cls: WB_UNKNOWN_CLASS, data: Dict[str, Any],
site: Optional[DataSite] = None) -> 'WbUnknown':
"""
Create a WbUnknown from the JSON data given by the Wikibase API.
@@ -1083,11 +1109,12 @@
return cls(data)
-_sites = {}
+_sites = {} # type: Dict[str, APISite]
@cache
-def _code_fam_from_url(url: str, name: Optional[str] = None):
+def _code_fam_from_url(url: str, name: Optional[str] = None
+ ) -> Tuple[str, str]:
"""Set url to cache and get code and family from cache.
Site helper method.
@@ -1117,8 +1144,9 @@
@_deprecate_arg('sysop', True)
-def Site(code: Optional[str] = None, fam=None, user: Optional[str] = None, *,
- interface=None,
+def Site(code: Optional[str] = None, fam: OPT_STR_OR_FAMILY = None,
+ user: Optional[str] = None, *,
+ interface: OPT_STR_OR_SITE = None,
url: Optional[str] = None) -> APISite:
"""A factory method to obtain a Site object.
@@ -1167,11 +1195,9 @@
:param code: language code (override config.mylang)
code may also be a sitename like 'wikipedia:test'
:param fam: family name or object (override config.family)
- :type fam: str or pywikibot.family.Family
:param user: bot user name to use on this site (override config.usernames)
:param interface: site class or name of class in :py:obj:`pywikibot.site`
(override config.site_interface)
- :type interface: subclass of :py:obj:`pywikibot.site.BaseSite` or string
:param url: Instead of code and fam, does try to get a Site based on the
URL. Still requires that the family supporting that URL exists.
:raises ValueError: URL and pair of code and family given
@@ -1263,7 +1289,7 @@
link_regex = re.compile(r'\[\[(?P<title>[^\]|[<>{}]*)(\|.*?)?\]\]')
-def showDiff(oldtext, newtext, context=0):
+def showDiff(oldtext: str, newtext: str, context: int = 0) -> None:
"""
Output a string showing the differences between oldtext and newtext.
@@ -1276,7 +1302,7 @@
# Throttle and thread handling
-def sleep(secs):
+def sleep(secs: int) -> None:
"""Suspend execution of the current thread for the given number of seconds.
Drop this process from the throttle log if wait time is greater than
@@ -1287,7 +1313,7 @@
time.sleep(secs)
-def stopme():
+def stopme() -> None:
"""
Drop this process from the throttle log, after pending threads finish.
@@ -1299,7 +1325,7 @@
_flush(False)
-def _flush(stop=True):
+def _flush(stop: bool = True) -> None:
"""
Drop this process from the throttle log, after pending threads finish.
@@ -1310,7 +1336,7 @@
debug('_flush() called', _logger)
- def remaining():
+ def remaining() -> Tuple[int, datetime.timedelta]:
remainingPages = page_put_queue.qsize()
if stop:
# -1 because we added a None element to stop the queue
@@ -1358,7 +1384,7 @@
# Create a separate thread for asynchronous page saves (and other requests)
-def async_manager():
+def async_manager() -> None:
"""Daemon; take requests from the queue and execute them in background."""
while True:
(request, args, kwargs) = page_put_queue.get()
@@ -1370,7 +1396,7 @@
page_put_queue_busy.get()
-def async_request(request, *args, **kwargs):
+def async_request(request: Callable, *args: Any, **kwargs: Any) -> None:
"""Put a request on the queue, and start the daemon if necessary."""
if not _putthread.is_alive():
with page_put_queue.mutex, suppress(AssertionError, RuntimeError):
@@ -1379,9 +1405,9 @@
# queue to hold pending requests
-page_put_queue = Queue(_config.max_queue_size)
+page_put_queue = Queue(_config.max_queue_size) # type: Queue
# queue to signal that async_manager is working on a request. See T147178.
-page_put_queue_busy = Queue(_config.max_queue_size)
+page_put_queue_busy = Queue(_config.max_queue_size) # type: Queue
# set up the background thread
_putthread = threading.Thread(target=async_manager,
name='Put-Thread', # for debugging purposes
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/710382
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: I300b0a746bf5b65d6d646cf798740af21898c443
Gerrit-Change-Number: 710382
Gerrit-PatchSet: 4
Gerrit-Owner: Damian <atagar1(a)gmail.com>
Gerrit-Reviewer: Huji <huji.huji(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged