Xqt has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/834550 )

Change subject: [PWB8] Drop Python 3.5 dependencies
......................................................................

[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(-)

Approvals:
  Xqt: Verified; Looks good to me, approved



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 https://gerrit.wikimedia.org/r/c/pywikibot/core/+/834550
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: I3a5183ca82e2c6595cfe0a9b9490319604330731
Gerrit-Change-Number: 834550
Gerrit-PatchSet: 6
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to