Xqt submitted this change.

View Change

Approvals: Xqt: Verified; Looks good to me, approved
[PWB8] Drop Python 3.5 dependencies

- update requirements
- remove version warning
- remove Python 3.5 code variants
- remove win32_unicode.py
- update documentation

Bug: T301908
Change-Id: I3a5183ca82e2c6595cfe0a9b9490319604330731
---
M .appveyor.yml
M dev-requirements.txt
M docs/api_ref/pywikibot.userinterfaces.rst
M docs/index.rst
M mypy.ini
M pywikibot/README.rst
M pywikibot/__init__.py
M pywikibot/scripts/generate_user_files.py
M pywikibot/specialbots/_upload.py
M pywikibot/throttle.py
M pywikibot/tools/collections.py
M pywikibot/userinterfaces/gui.py
M pywikibot/userinterfaces/terminal_interface_win32.py
D pywikibot/userinterfaces/win32_unicode.py
M requirements.txt
M setup.py
M tests/eventstreams_tests.py
M tests/utils.py
18 files changed, 41 insertions(+), 468 deletions(-)

diff --git a/.appveyor.yml b/.appveyor.yml
index 3d1cc5c..48e05d7 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -22,7 +22,6 @@

# Appveyor pre-installs these versions onto build machines

-
- PYTHON: "C:\\Python36-x64"
PYTHON_VERSION: "3.6.x"
PYTHON_ARCH: "64"
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 94a3ad4..a90a4b5 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -2,9 +2,8 @@
#

pytest >= 5.3
-pytest-cov >= 2.11.1, < 3.0.0;python_version<"3.6"
-pytest-cov >= 3.0.0;python_version>="3.10"
-pytest-cov >= 2.11.1;python_version>="3.6" and python_version<"3.10"
+pytest-cov >= 3.0.0; python_version>="3.10"
+pytest-cov >= 2.11.1; python_version<"3.10"
pytest-timeout
pytest-runner
pytest-subtests >= 0.3.2
@@ -14,13 +13,9 @@
# httpbin 0.7 fails with werkzeug 2.1.0/1 (T305124)
werkzeug>=0.15.5, <2.1.0

-# T293440: pytest-httpbin needs cffi >=1.0.0
-# but Python 3.5 needs cffi < 1.15 which is not taken into account
-cffi >= 1.0.0, < 1.15.0 ;python_version=="3.5"
pytest-httpbin

pydocstyle>=4.0.0
-flake8==3.9.2; python_version < "3.6"
flake8>=5.0.2; python_version >= "3.6"
flake8-docstrings>=0.2.6
flake8-isort;python_version>="3.6"
diff --git a/docs/api_ref/pywikibot.userinterfaces.rst b/docs/api_ref/pywikibot.userinterfaces.rst
index bb1240b..576e61e 100644
--- a/docs/api_ref/pywikibot.userinterfaces.rst
+++ b/docs/api_ref/pywikibot.userinterfaces.rst
@@ -51,9 +51,3 @@

.. automodule:: userinterfaces.transliteration
:synopsis: Module to transliterate text
-
-:mod:`win32\_unicode` --- Unicode Interface for Python 3.5
-----------------------------------------------------------
-
-.. automodule:: userinterfaces.win32_unicode
- :synopsis: Unicode support for stdout, stderr and argv with Python 3.5.
diff --git a/docs/index.rst b/docs/index.rst
index e78b4bb..3a84893 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,8 +19,8 @@
whether you have Python installed and to find its version, just type
``python`` at the CMD or shell prompt.

-Python 3.5.3 or higher is currently required to run the bot, but Python 3.6
-or higher is recommended. Python 3.5 support will be dropped with Pywikibot 8.
+Python 3.6.0 or higher is currently required to run the bot, but Python 3.7
+or higher is recommended. Python 3.6 support will be dropped with Pywikibot 9.

Pywikibot and this documentation are licensed under the
:ref:`MIT license`;
diff --git a/mypy.ini b/mypy.ini
index 34102e5..4a36827 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -1,5 +1,5 @@
[mypy]
-python_version = 3.5
+python_version = 3.6
check_untyped_defs = true
disallow_any_generics = true
disallow_incomplete_defs = true
diff --git a/pywikibot/README.rst b/pywikibot/README.rst
index f1cbab1..21f1f54 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.3 <https://www.python.org/downloads/>`_
+You need to have at least Python version `3.6.0 <https://www.python.org/downloads/>`_
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 a9f2a56..a8e8889 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -68,7 +68,7 @@
)
from pywikibot.site import APISite, BaseSite, DataSite
from pywikibot.time import Timestamp
-from pywikibot.tools import normalize_username, PYTHON_VERSION
+from pywikibot.tools import normalize_username


ItemPageStrNoneType = Union[str, 'ItemPage', None]
@@ -95,15 +95,6 @@
argvu = [] # type: List[str]


-if PYTHON_VERSION < (3, 6):
- warn("""
-Python {version} will be dropped with release 8.0 soon.
-It is recommended to use Python 3.6 or above.
-See T301908 for further information.
-""".format(version=sys.version.split(maxsplit=1)[0]),
- FutureWarning) # adjust this line no in utils.execute()
-
-
class Coordinate(_WbRepresentation):

"""Class for handling and storing Coordinates."""
diff --git a/pywikibot/scripts/generate_user_files.py b/pywikibot/scripts/generate_user_files.py
index 443aa82..5882a80 100755
--- a/pywikibot/scripts/generate_user_files.py
+++ b/pywikibot/scripts/generate_user_files.py
@@ -231,9 +231,6 @@
ConfigSection = namedtuple('ConfigSection', 'head, info, section')

config_path = Path(__file__).resolve().parents[1].joinpath('config.py')
- if PYTHON_VERSION < (3, 6):
- config_path = str(config_path)
-
with codecs.open(config_path, 'r', 'utf-8') as config_f:
config_file = config_f.read()

diff --git a/pywikibot/specialbots/_upload.py b/pywikibot/specialbots/_upload.py
index 16e38e7..0764746 100644
--- a/pywikibot/specialbots/_upload.py
+++ b/pywikibot/specialbots/_upload.py
@@ -135,7 +135,7 @@
else:
headers = {}

- with open(str(path), 'ab') as fd: # T272345: Python 3.5 needs str
+ with open(path, 'ab') as fd:
os.lseek(handle, file_len, 0)
try:
response = http.fetch(file_url, stream=True,
diff --git a/pywikibot/throttle.py b/pywikibot/throttle.py
index 9df3846..1ac0cf7 100644
--- a/pywikibot/throttle.py
+++ b/pywikibot/throttle.py
@@ -10,18 +10,12 @@
import time
from collections import Counter, namedtuple
from contextlib import suppress
+from hashlib import blake2b
from typing import Optional, Union

import pywikibot
from pywikibot import config
-from pywikibot.tools import PYTHON_VERSION, deprecated
-
-
-if PYTHON_VERSION < (3, 6):
- from hashlib import md5
- blake2b = None
-else:
- from hashlib import blake2b
+from pywikibot.tools import deprecated


FORMAT_LINE = '{module_id} {pid} {time} {site}\n'
@@ -103,11 +97,8 @@
if module is None:
module = pywikibot.calledModuleName()
module = module.encode()
- if blake2b:
- hashobj = blake2b(module, digest_size=2)
- else:
- hashobj = md5(module)
- return hashobj.hexdigest()[:4] # slice for Python 3.5
+ hashobj = blake2b(module, digest_size=2)
+ return hashobj.hexdigest()

def _read_file(self, raise_exc: bool = False):
"""Yield process entries from file."""
diff --git a/pywikibot/tools/collections.py b/pywikibot/tools/collections.py
index a4cd8a3..af9460a 100644
--- a/pywikibot/tools/collections.py
+++ b/pywikibot/tools/collections.py
@@ -7,14 +7,7 @@
import collections

from abc import abstractmethod, ABC
-from collections.abc import (
- Container,
- Generator,
- Iterable,
- Iterator,
- Mapping,
- Sized,
-)
+from collections.abc import Collection, Generator, Iterator, Mapping
from contextlib import suppress
from itertools import chain
from typing import Any
@@ -32,8 +25,7 @@
)


-# Collection is not provided with Python 3.5; use Container, Iterable, Sized
-class SizedKeyCollection(Container, Iterable, Sized):
+class SizedKeyCollection(Collection):

"""Structure to hold values where the key is given by the value itself.

diff --git a/pywikibot/userinterfaces/gui.py b/pywikibot/userinterfaces/gui.py
index 395b06f..1dea42b 100644
--- a/pywikibot/userinterfaces/gui.py
+++ b/pywikibot/userinterfaces/gui.py
@@ -12,6 +12,11 @@
# Distributed under the terms of the MIT license.
#
import tkinter
+from idlelib import replace as ReplaceDialog
+from idlelib import search as SearchDialog
+from idlelib.config import idleConf
+from idlelib.configdialog import ConfigDialog
+from idlelib.multicall import MultiCallCreator
from tkinter import simpledialog as tkSimpleDialog
from tkinter.scrolledtext import ScrolledText
from typing import Optional
@@ -22,20 +27,6 @@
from pywikibot.tools import PYTHON_VERSION


-# T164163: Fix idlelib import in Python 3.6
-if PYTHON_VERSION >= (3, 6):
- from idlelib import replace as ReplaceDialog
- from idlelib import search as SearchDialog
- from idlelib.config import idleConf
- from idlelib.configdialog import ConfigDialog
- from idlelib.multicall import MultiCallCreator
-else:
- from idlelib import ReplaceDialog, SearchDialog
- from idlelib.configDialog import ConfigDialog
- from idlelib.configHandler import idleConf
- from idlelib.MultiCall import MultiCallCreator
-
-
class TextEditor(ScrolledText):

"""A text widget with some editing enhancements.
@@ -562,15 +553,6 @@
@staticmethod
def get_image(photo, width, height):
"""Take the BytesIO object and build an imageTK thumbnail."""
- if PYTHON_VERSION < (3, 6):
- # vulnerability found in Pillow<8.1.1
- from sys import version
- raise RuntimeError(
- 'This script requires Python 3.6+ for GUI support.\n'
- '{version} is not supported. Please update your Python.'
- .format(version=version.split(maxsplit=1)[0])
- )
-
try:
from PIL import Image, ImageTk
except ImportError:
diff --git a/pywikibot/userinterfaces/terminal_interface_win32.py b/pywikibot/userinterfaces/terminal_interface_win32.py
index c3a3454..4b25740 100644
--- a/pywikibot/userinterfaces/terminal_interface_win32.py
+++ b/pywikibot/userinterfaces/terminal_interface_win32.py
@@ -6,7 +6,6 @@
#
import ctypes

-from pywikibot.tools import PYTHON_VERSION
from pywikibot.userinterfaces import terminal_interface_base


@@ -35,19 +34,6 @@

"""User interface for Win32 terminals."""

- def __init__(self) -> None:
- """Initializer."""
- super().__init__()
- # issue1602 solved in Python 3.6
- if PYTHON_VERSION == (3, 5): # pragma: no cover
- from pywikibot.userinterfaces import win32_unicode
- stdin, stdout, stderr, argv = win32_unicode.get_unicode_console()
- self.stdin = stdin
- self.stdout = stdout
- self.stderr = stderr
- self.argv = argv
- self.encoding = 'utf-8'
-
def support_color(self, target_stream):
"""Return whether the target stream supports actually color."""
return target_stream.isatty()
diff --git a/pywikibot/userinterfaces/win32_unicode.py b/pywikibot/userinterfaces/win32_unicode.py
deleted file mode 100644
index a135878..0000000
--- a/pywikibot/userinterfaces/win32_unicode.py
+++ /dev/null
@@ -1,335 +0,0 @@
-"""Unicode support for stdout, stderr and argv with Python 3.5.
-
-.. deprecated:: 7.1
- will be removed with Pywikibot 8 when Python 3.5 support is dropped.
-"""
-#
-# (C) Pywikibot team, 2012-2022
-#
-##############################################
-# Support for unicode in Windows cmd.exe
-# Posted on Stack Overflow [1], available under CC-BY-SA 3.0 [2]
-#
-# Question: "Windows cmd encoding change causes Python crash" [3] by Alex [4],
-# Answered [5] by David-Sarah Hopwood [6].
-#
-# [1] https://stackoverflow.com
-# [2] https://creativecommons.org/licenses/by-sa/3.0/
-# [3] https://stackoverflow.com/questions/878972
-# [4] https://stackoverflow.com/users/85185
-# [5] https://stackoverflow.com/a/3259271/118671
-# [6] https://stackoverflow.com/users/393146
-#
-################################################
-#
-# Licensed under both CC-BY-SA and the MIT license.
-#
-################################################
-import sys
-from contextlib import suppress
-from ctypes import Structure, byref
-from ctypes import c_void_p as LPVOID
-from ctypes import create_unicode_buffer, sizeof
-from io import IOBase, UnsupportedOperation
-from typing import IO
-
-from pywikibot.backports import List, Tuple
-
-
-OSWIN32 = (sys.platform == 'win32')
-
-stdin = sys.stdin
-stdout = sys.stdout
-stderr = sys.stderr
-argv = sys.argv
-
-original_stderr = sys.stderr
-
-if OSWIN32:
- from ctypes import POINTER, WINFUNCTYPE, WinError, windll
- from ctypes.wintypes import (
- BOOL,
- DWORD,
- HANDLE,
- LPWSTR,
- SHORT,
- UINT,
- ULONG,
- WCHAR,
- )
-
-try:
- ReadConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPVOID, DWORD, POINTER(DWORD),
- LPVOID)(('ReadConsoleW', windll.kernel32))
- WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD),
- LPVOID)(('WriteConsoleW', windll.kernel32))
-except NameError:
- ReadConsoleW = WriteConsoleW = None
-
-
-class UnicodeInput(IOBase):
-
- """Unicode terminal input class."""
-
- def __init__(self, hConsole, name, bufsize: int = 1024) -> None:
- """Initialize the input stream."""
- self._hConsole = hConsole
- self.bufsize = bufsize
- self.buffer = create_unicode_buffer(bufsize)
- self.name = name
- self.encoding = 'utf-8'
-
- def readline(self):
- """Read one line from the input."""
- maxnum = DWORD(self.bufsize - 1)
- numrecv = DWORD(0)
- result = ReadConsoleW(self._hConsole, self.buffer, maxnum,
- byref(numrecv), None)
- if not result:
- raise Exception('stdin failure')
- return self.buffer.value[:numrecv.value]
-
-
-class UnicodeOutput(IOBase):
-
- """Unicode terminal output class."""
-
- def __init__(self, hConsole, stream, fileno, name) -> None:
- """Initialize the output stream."""
- self._hConsole = hConsole
- self._stream = stream
- self._fileno = fileno
- self.softspace = False
- self.mode = 'w'
- self.encoding = 'utf-8'
- self.name = name
- self.flush()
-
- def fileno(self):
- """Return the fileno."""
- return self._fileno
-
- def flush(self):
- """Flush the stream."""
- if self._hConsole is None:
- try:
- self._stream.flush()
- except Exception as e:
- _complain('{}.flush: {!r} from {!r}'
- .format(self.name, e, self._stream))
- raise
-
- def write(self, text):
- """Write the text to the output."""
- try:
- if self._hConsole is None:
- self._stream.write(text)
- else:
- if not isinstance(text, str):
- text = bytes(text).decode('utf-8')
- remaining = len(text)
- while remaining > 0:
- n = DWORD(0)
- # There is a shorter-than-documented limitation on the
- # length of the string passed to WriteConsoleW (see
- # <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232>.
- retval = WriteConsoleW(self._hConsole, text,
- min(remaining, 10000),
- byref(n), None)
- if 0 in (retval, n.value):
- msg = 'WriteConsoleW returned {!r}, n.value = {!r}' \
- .format(retval, n.value)
- raise OSError(msg)
- remaining -= n.value
- if remaining == 0:
- break
- text = text[n.value:]
- except Exception as e:
- _complain('{}.write: {!r}'.format(self.name, e))
- raise
-
- def writelines(self, lines):
- """Write a list of lines by using write."""
- try:
- for line in lines:
- self.write(line)
- except Exception as e:
- _complain('{}.writelines: {!r}'.format(self.name, e))
- raise
-
- def isatty(self):
- """Return True if the stream is interactive."""
- return self._hConsole is not None
-
-
-def old_fileno(std_name):
- """Return the fileno or None if that doesn't work."""
- # some environments like IDLE don't support the fileno operation
- # handle those like std streams which don't have fileno at all
- std = getattr(sys, 'std{}'.format(std_name))
- if hasattr(std, 'fileno'):
- with suppress(UnsupportedOperation):
- return std.fileno()
- return None
-
-
-# If any exception occurs in this code, try to print it on stderr,
-# which makes for frustrating debugging if stderr is directed to our wrapper.
-# So be paranoid about catching errors and reporting them to original_stderr,
-# so that we can at least see them.
-def _complain(message) -> None:
- print(isinstance(message, str) and message or repr(message),
- file=original_stderr)
-
-
-def force_truetype_console(h_stdout) -> None:
- """Force the console to use a TrueType font (Vista+)."""
- TMPF_TRUETYPE = 0x04
- LF_FACESIZE = 32
-
- class COORD(Structure):
- _fields_ = [('X', SHORT),
- ('Y', SHORT)]
-
- class CONSOLE_FONT_INFOEX(Structure):
- _fields_ = [('cbSize', ULONG),
- ('nFont', DWORD),
- ('dwFontSize', COORD),
- ('FontFamily', UINT),
- ('FontWeight', UINT),
- ('FaceName', WCHAR * LF_FACESIZE)]
-
- try:
- GetCurrentConsoleFontEx = WINFUNCTYPE(
- BOOL,
- HANDLE, # hConsoleOutput
- BOOL, # bMaximumWindow
- POINTER(CONSOLE_FONT_INFOEX), # lpConsoleCurrentFontEx
- )(('GetCurrentConsoleFontEx', windll.kernel32))
-
- SetCurrentConsoleFontEx = WINFUNCTYPE(
- BOOL,
- HANDLE, # hConsoleOutput
- BOOL, # bMaximumWindow
- POINTER(CONSOLE_FONT_INFOEX), # lpConsoleCurrentFontEx
- )(('SetCurrentConsoleFontEx', windll.kernel32))
- except AttributeError:
- # pre Windows Vista. Return without doing anything.
- return
-
- current_font = CONSOLE_FONT_INFOEX()
- current_font.cbSize = sizeof(CONSOLE_FONT_INFOEX)
-
- if not GetCurrentConsoleFontEx(h_stdout, True, byref(current_font)):
- WinError()
-
- truetype_font = (current_font.FontFamily & TMPF_TRUETYPE)
-
- if not truetype_font:
- new_font = CONSOLE_FONT_INFOEX()
- new_font.cbSize = sizeof(CONSOLE_FONT_INFOEX)
- new_font.FaceName = 'Lucida Console'
-
- if not SetCurrentConsoleFontEx(h_stdout, True, byref(new_font)):
- WinError()
-
-
-def get_unicode_console() -> Tuple[IO, IO, IO, List[str]]:
- """
- Get Unicode console objects.
-
- :return: stdin, stdout, stderr, argv
- """
- # Make Unicode console output work independently of the current code page.
- # This also fixes https://bugs.python.org/issue1602
- # Credit to Michael Kaplan
- # http://blogs.msdn.com/b/michkap/archive/2010/04/07/9989346.aspx
- # and TZOmegaTZIOY
- # https://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462
-
- global stdin, stdout, stderr
-
- if not OSWIN32:
- return stdin, stdout, stderr, argv
-
- try:
- # <https://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
- # HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
- # returns INVALID_HANDLE_VALUE, NULL, or a valid handle
- #
- # <https://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx>
- # DWORD WINAPI GetFileType(DWORD hFile);
- #
- # <https://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx>
- # BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);
-
- GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(('GetStdHandle',
- windll.kernel32))
- STD_INPUT_HANDLE = DWORD(-10)
- STD_OUTPUT_HANDLE = DWORD(-11)
- STD_ERROR_HANDLE = DWORD(-12)
- GetFileType = WINFUNCTYPE(DWORD, DWORD)(('GetFileType',
- windll.kernel32))
- FILE_TYPE_CHAR = 0x0002
- FILE_TYPE_REMOTE = 0x8000
- GetConsoleMode = (WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))
- (('GetConsoleMode', windll.kernel32)))
- INVALID_HANDLE_VALUE = DWORD(-1).value
-
- def not_a_console(handle):
- """Return whether the handle is not to a console."""
- if handle == INVALID_HANDLE_VALUE or handle is None:
- return True
- return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
- or GetConsoleMode(handle, byref(DWORD())) == 0)
-
- old_stdin_fileno = old_fileno('in')
- old_stdout_fileno = old_fileno('out')
- old_stderr_fileno = old_fileno('err')
-
- STDIN_FILENO = 0
- STDOUT_FILENO = 1
- STDERR_FILENO = 2
- real_stdin = (old_stdin_fileno == STDIN_FILENO)
- real_stdout = (old_stdout_fileno == STDOUT_FILENO)
- real_stderr = (old_stderr_fileno == STDERR_FILENO)
-
- if real_stdin:
- hStdin = GetStdHandle(STD_INPUT_HANDLE)
- if not_a_console(hStdin):
- real_stdin = False
-
- if real_stdout:
- hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
- force_truetype_console(hStdout)
- if not_a_console(hStdout):
- real_stdout = False
-
- if real_stderr:
- hStderr = GetStdHandle(STD_ERROR_HANDLE)
- force_truetype_console(hStderr)
- if not_a_console(hStderr):
- real_stderr = False
-
- if real_stdout or real_stderr:
- if real_stdin:
- stdin = UnicodeInput(hStdin, name='<Unicode console stdin>')
-
- if real_stdout:
- stdout = UnicodeOutput(hStdout, sys.stdout, STDOUT_FILENO,
- '<Unicode console stdout>')
- else:
- stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno,
- '<Unicode redirected stdout>')
-
- if real_stderr:
- stderr = UnicodeOutput(hStderr, sys.stderr, STDERR_FILENO,
- '<Unicode console stderr>')
- else:
- stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno,
- '<Unicode redirected stderr>')
- except Exception as e:
- _complain('exception {!r} while fixing up sys.stdout and sys.stderr'
- .format(e))
-
- return stdin, stdout, stderr, argv
diff --git a/requirements.txt b/requirements.txt
index 10eddfb..862c1cf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,13 +18,11 @@
# $ awk -F '[#>=]' '{print $1}' requirements.txt | xargs apt-cache search

# mandatory dependencies, others are optional
-requests>=2.20.1, < 2.26.0; python_version < '3.6'
-requests>=2.20.1, < 2.28.0; python_version >= '3.6' and python_version < '3.7'
+requests>=2.20.1, < 2.28.0; python_version < '3.7'
requests>=2.20.1; python_version >= '3.7'
setuptools>=48.0.0 ; python_version >= '3.10'
setuptools>=38.5.2 ; python_version >= '3.7' and python_version < '3.10'
-setuptools>=20.8.1, <59.7.0 ; python_version >= '3.6' and python_version < '3.7'
-setuptools>=20.8.1, !=50.0.0, <51.0.0 ; python_version < '3.6'
+setuptools>=20.8.1, <59.7.0 ; python_version < '3.7'

# MediaWiki markup parser
# mwparserfromhell is default, wikitextparser can be used instead
@@ -44,15 +42,15 @@
python-stdnum >= 1.17

# GUI
-Pillow >= 8.1.1 ; python_version >= '3.6'
+Pillow >= 8.1.1

# core pagegenerators
google >= 1.7
sseclient >= 0.0.18,< 0.0.23

# The mysql generator in pagegenerators depends on PyMySQL
-PyMySQL >= 0.7.11, < 1.0.0 ; python_version < '3.6'
-PyMySQL >= 1.0.0 ; python_version >= '3.6'
+# toolforge uses 0.9.3
+PyMySQL >= 0.9.3

# core HTML comparison parser in diff module
beautifulsoup4
diff --git a/setup.py b/setup.py
index fe66a45..0f646a1 100755
--- a/setup.py
+++ b/setup.py
@@ -38,7 +38,7 @@
Pywikibot is not available on:
{version}

-This version of Pywikibot only supports Python 3.5.3+.
+This version of Pywikibot only supports Python 3.6+.
"""

try:
@@ -49,7 +49,7 @@

def python_is_supported() -> bool:
"""Check that Python is supported."""
- return sys.version_info[:3] >= (3, 5, 3)
+ return sys.version_info[:3] >= (3, 6)


if not python_is_supported(): # pragma: no cover
@@ -65,19 +65,15 @@
'Google': ['google>=1.7'],
'memento': ['memento_client==0.6.1'],
'mwparserfromhell': ['mwparserfromhell>=0.5.0'],
- 'wikitextparser': ['wikitextparser>=0.47.5; python_version < "3.6"',
- 'wikitextparser>=0.47.0; python_version >= "3.6"'],
- 'mysql': ['PyMySQL >= 0.7.11, < 1.0.0 ; python_version < "3.6"',
- 'PyMySQL >= 1.0.0 ; python_version >= "3.6"'],
- 'Tkinter': [ # vulnerability found in Pillow<8.1.1
- 'Pillow>=8.1.1;python_version>="3.6"',
- ],
+ 'wikitextparser': ['wikitextparser>=0.47.0'],
+ 'mysql': ['PyMySQL >= 0.9.3'], # toolforge
+ # vulnerability found in Pillow<8.1.1 but toolforge uses 5.4.1
+ 'Tkinter': ['Pillow>=8.1.1'],
'mwoauth': ['mwoauth!=0.3.1,>=0.2.4'],
'html': ['BeautifulSoup4'],
'http': ['fake_useragent'],
'flake8': [ # Due to incompatibilities between packages the order matters.
- 'flake8==3.9.2,<5.0.0; python_version < "3.6"',
- 'flake8>=5.0.2; python_version >= "3.6"',
+ 'flake8>=5.0.2',
'darglint',
'pydocstyle>=4.0.0',
'flake8-bugbear!=21.4.1,!=21.11.28',
@@ -112,16 +108,12 @@
# ------- setup install_requires ------- #
# packages which are mandatory
dependencies = [
- 'requests>=2.20.1, <2.26.0; python_version < "3.6"',
- 'requests>=2.20.1, <2.28.0; '
- 'python_version >= "3.6" and python_version < "3.7"',
+ 'requests>=2.20.1, <2.28.0; python_version < "3.7"',
'requests>=2.20.1; python_version>="3.7"',
# PEP 440
'setuptools>=48.0.0 ; python_version >= "3.10"',
'setuptools>=38.5.2 ; python_version >= "3.7" and python_version < "3.10"',
- 'setuptools>=20.8.1, <59.7.0 '
- '; python_version >= "3.6" and python_version < "3.7"',
- 'setuptools>=20.8.1, !=50.0.0, <51.0.0 ; python_version < "3.6"',
+ 'setuptools>=20.8.1, <59.7.0 ; python_version < "3.7"',
]
# in addition either mwparserfromhell or wikitextparser is required

@@ -277,7 +269,7 @@
# zip_safe
install_requires=dependencies,
extras_require=extra_deps,
- python_requires='>=3.5.3',
+ python_requires='>=3.6',
# namespace_packages
test_suite='tests.collector',
tests_require=test_deps,
@@ -363,7 +355,6 @@
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
- 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
diff --git a/tests/eventstreams_tests.py b/tests/eventstreams_tests.py
index 873bfc7..bafe316 100755
--- a/tests/eventstreams_tests.py
+++ b/tests/eventstreams_tests.py
@@ -13,7 +13,6 @@
from pywikibot import config, Site
from pywikibot.comms.eventstreams import EventSource, EventStreams
from pywikibot.family import WikimediaFamily
-from pywikibot.tools import PYTHON_VERSION

from tests.aspects import DefaultSiteTestCase, TestCase, require_modules
from tests.utils import skipping
@@ -45,10 +44,9 @@
self.assertEqual(e._url, e.sse_kwargs.get('url'))
self.assertIsNone(e._total)
self.assertIsNone(e._streams)
- if PYTHON_VERSION >= (3, 6):
- self.assertEqual(repr(e),
- "EventStreams(url='{}')"
- .format(self.sites[key]['hostname']))
+ self.assertEqual(repr(e),
+ "EventStreams(url='{}')"
+ .format(self.sites[key]['hostname']))

def test_url_from_site(self, key):
"""Test EventStreams with url from site."""
@@ -61,12 +59,10 @@
self.assertEqual(e._url, e.sse_kwargs.get('url'))
self.assertIsNone(e._total)
self.assertEqual(e._streams, streams)
- if PYTHON_VERSION >= (3, 6):
- site_repr = 'site={}, '.format(
- repr(site)) if site != Site() else ''
- self.assertEqual(repr(e),
- "EventStreams({}streams='{}')"
- .format(site_repr, streams))
+ site_repr = 'site={}, '.format(repr(site)) if site != Site() else ''
+ self.assertEqual(repr(e),
+ "EventStreams({}streams='{}')"
+ .format(site_repr, streams))


@mock.patch('pywikibot.comms.eventstreams.EventSource', new=mock.MagicMock())
diff --git a/tests/utils.py b/tests/utils.py
index 5245dcc..e9031dc 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -21,7 +21,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

@@ -450,9 +449,6 @@

:param command: executable to run and arguments to use
"""
- if PYTHON_VERSION < (3, 6):
- command.insert(1, '-W ignore::FutureWarning:pywikibot:104')
-
env = os.environ.copy()

# Prevent output by test package; e.g. 'max_retries reduced from x to y'

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

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I3a5183ca82e2c6595cfe0a9b9490319604330731
Gerrit-Change-Number: 834550
Gerrit-PatchSet: 6
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged