jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/985373 )

Change subject: replace collections.namedtuple with typing.NamedTuple
......................................................................

replace collections.namedtuple with typing.NamedTuple

Change-Id: I1802458320777ba0aaa7e59d406ca3358981eed8
---
M pywikibot/textlib.py
M scripts/blockpageschecker.py
M pywikibot/pagegenerators/_filters.py
M pywikibot/throttle.py
M pywikibot/scripts/generate_user_files.py
M pywikibot/site/_apisite.py
6 files changed, 98 insertions(+), 48 deletions(-)

Approvals:
  Xqt: Looks good to me, approved
  jenkins-bot: Verified




diff --git a/pywikibot/pagegenerators/_filters.py 
b/pywikibot/pagegenerators/_filters.py
index 16af382..500bc12 100644
--- a/pywikibot/pagegenerators/_filters.py
+++ b/pywikibot/pagegenerators/_filters.py
@@ -8,9 +8,8 @@

 import datetime
 import re
-from collections import namedtuple
 from functools import partial
-from typing import TYPE_CHECKING, Union
+from typing import TYPE_CHECKING, NamedTuple, Union

 import pywikibot
 from pywikibot import config
@@ -362,6 +361,12 @@
 RegexBodyFilterPageGenerator = RegexFilter.contentfilter


+class _Edit(NamedTuple):
+    do_edit: datetime.datetime
+    edit_start: datetime.datetime
+    edit_end: datetime.datetime
+
+
 def EdittimeFilterPageGenerator(
     generator: Iterable[pywikibot.page.Page],
     last_edit_start: datetime.datetime | None = None,
@@ -380,9 +385,7 @@
     :param first_edit_end: Only yield pages first edited before this time
     :param show_filtered: Output a message for each page not yielded
     """
-    Edit = namedtuple('Edit', ['do_edit', 'edit_start', 'edit_end'])
-
-    def to_be_yielded(edit: Edit,
+    def to_be_yielded(edit: _Edit,
                       page: pywikibot.page.Page,
                       rev: pywikibot.page.Revision,
                       show_filtered: bool) -> bool:
@@ -407,13 +410,13 @@

         return True

-    latest_edit = Edit(last_edit_start or last_edit_end,
-                       last_edit_start or datetime.datetime.min,
-                       last_edit_end or datetime.datetime.max)
+    latest_edit = _Edit(last_edit_start or last_edit_end,
+                        last_edit_start or datetime.datetime.min,
+                        last_edit_end or datetime.datetime.max)

-    first_edit = Edit(first_edit_start or first_edit_end,
-                      first_edit_start or datetime.datetime.min,
-                      first_edit_end or datetime.datetime.max)
+    first_edit = _Edit(first_edit_start or first_edit_end,
+                       first_edit_start or datetime.datetime.min,
+                       first_edit_end or datetime.datetime.max)

     for page in generator or []:
         yield_for_last = to_be_yielded(latest_edit, page,
diff --git a/pywikibot/scripts/generate_user_files.py 
b/pywikibot/scripts/generate_user_files.py
index 440a5c2..6e03aae 100755
--- a/pywikibot/scripts/generate_user_files.py
+++ b/pywikibot/scripts/generate_user_files.py
@@ -18,9 +18,9 @@
 import os
 import re
 import sys
-from collections import namedtuple
 from pathlib import Path
 from textwrap import fill
+from typing import NamedTuple

 from pywikibot.backports import Callable
 from pywikibot.scripts import _import_with_no_user_config
@@ -228,7 +228,10 @@
 {botpasswords}"""


-ConfigSection = namedtuple('ConfigSection', 'head, info, section')
+class _ConfigSection(NamedTuple):
+    head: str
+    info: str
+    section: str


 def parse_sections() -> list:
@@ -237,7 +240,7 @@
     config.py will be in the pywikibot/ directory whereas
     generate_user_files script is in pywikibot/scripts.

-    :return: a list of ConfigSection named tuples.
+    :return: a list of _ConfigSection named tuples.
     """
     data = []

@@ -255,7 +258,7 @@

     for section, head, comment in result:
         info = ' '.join(text.strip('# ') for text in comment.splitlines())
-        data.append(ConfigSection(head, info, section))
+        data.append(_ConfigSection(head, info, section))
     return data

 
@@ -290,7 +293,7 @@


 def input_sections(variant: str,
-                   sections: list[ConfigSection],
+                   sections: list[_ConfigSection],
                    skip: Callable | None = None,
                    force: bool = False,
                    default: str = 'n') -> None:
@@ -339,10 +342,16 @@
     return copies


+class _UserItem(NamedTuple):
+    family: str
+    code: str
+    name: str
+
+
 def create_user_config(
-    main_family,
-    main_code,
-    main_username,
+    main_family: str,
+    main_code: str,
+    main_username: str,
     force: bool = False
 ):
     """
@@ -353,14 +362,13 @@
     _fnc = os.path.join(base_dir, USER_BASENAME)
     _fncpass = os.path.join(base_dir, PASS_BASENAME)

-    useritem = namedtuple('useritem', 'family, code, name')
     userlist = []
     if force and not config.verbose_output:
         if main_username:
-            userlist = [useritem(main_family, main_code, main_username)]
+            userlist = [_UserItem(main_family, main_code, main_username)]
     else:
         while True:
-            userlist += [useritem(*get_site_and_lang(
+            userlist += [_UserItem(*get_site_and_lang(
                 main_family, main_code, main_username, force=force))]
             if not pywikibot.input_yn('Do you want to add any other projects?',
                                       force=force,
diff --git a/pywikibot/site/_apisite.py b/pywikibot/site/_apisite.py
index 3c46cad..380811b 100644
--- a/pywikibot/site/_apisite.py
+++ b/pywikibot/site/_apisite.py
@@ -10,10 +10,10 @@
 import re
 import time
 import typing
-from collections import OrderedDict, defaultdict, namedtuple
+from collections import OrderedDict, defaultdict
 from contextlib import suppress
 from textwrap import fill
-from typing import TYPE_CHECKING, Any, TypeVar, Union
+from typing import TYPE_CHECKING, Any, NamedTuple, TypeVar, Union

 import pywikibot
 from pywikibot import login
@@ -93,6 +93,11 @@
 _RequestWrapperT = TypeVar('_RequestWrapperT', bound='api._RequestWrapper')


+class _OnErrorExc(NamedTuple):
+    exception: Exception
+    on_new_page: bool | None
+
+
 class APISite(
     BaseSite,
     EchoMixin,
@@ -2173,8 +2178,6 @@

         return False

-    OnErrorExc = namedtuple('OnErrorExc', 'exception on_new_page')
-
     # catalog of merge history errors for use in error messages
     _mh_errors = {
         'noapiwrite': 'API editing not enabled on {site} wiki',
@@ -2283,7 +2286,7 @@
             raise Error('mergehistory: unexpected response')

     # catalog of move errors for use in error messages
-    _mv_errors: dict[str, str | OnErrorExc] = {
+    _mv_errors: dict[str, str | _OnErrorExc] = {
         'noapiwrite': 'API editing not enabled on {site} wiki',
         'writeapidenied':
             'User {user} is not authorized to edit on {site} wiki',
@@ -2298,13 +2301,13 @@
         'immobilenamespace':
             'Pages in {oldnamespace} namespace cannot be moved on {site} '
             'wiki',
-        'articleexists': OnErrorExc(exception=ArticleExistsConflictError,
-                                    on_new_page=True),
-        # "protectedpage" can happen in both directions.
-        'protectedpage': OnErrorExc(exception=LockedPageError,
-                                    on_new_page=None),
-        'protectedtitle': OnErrorExc(exception=LockedNoPageError,
+        'articleexists': _OnErrorExc(exception=ArticleExistsConflictError,
                                      on_new_page=True),
+        # "protectedpage" can happen in both directions.
+        'protectedpage': _OnErrorExc(exception=LockedPageError,
+                                     on_new_page=None),
+        'protectedtitle': _OnErrorExc(exception=LockedNoPageError,
+                                      on_new_page=True),
         'nonfilenamespace':
             'Cannot move a file to {newnamespace} namespace on {site} '
             'wiki',
diff --git a/pywikibot/textlib.py b/pywikibot/textlib.py
index 0c5f80e..b6a0d45 100644
--- a/pywikibot/textlib.py
+++ b/pywikibot/textlib.py
@@ -8,7 +8,7 @@

 import itertools
 import re
-from collections import OrderedDict, namedtuple
+from collections import OrderedDict
 from collections.abc import Sequence
 from contextlib import suppress
 from html.parser import HTMLParser
@@ -940,7 +940,11 @@
 HEAD_PATTERN = re.compile(r'(={1,6}).+\1', re.DOTALL)
 TITLE_PATTERN = re.compile("'{3}([^']+)'{3}")

-_Heading = namedtuple('_Heading', ('text', 'start', 'end'))
+
+class _Heading(NamedTuple):
+    text: str
+    start: int
+    end: int


 class Section(NamedTuple):
@@ -1947,11 +1951,20 @@

 TIMEGROUPS = ('time', 'tzinfo', 'year', 'month', 'day', 'hour', 'minute')

-#: Hold precompiled timestamp patterns for :class:`TimeStripper`.
-#: Order of TimeStripperPatterns is important to avoid mismatch when searching.
-#:
-#: .. versionadded:: 8.0
-TimeStripperPatterns = namedtuple('TimeStripperPatterns', TIMEGROUPS[:-2])
+
+class TimeStripperPatterns(NamedTuple):
+    """Hold precompiled timestamp patterns for :class:`TimeStripper`.
+
+    Attribute order is important to avoid mismatch when searching.
+
+    .. versionadded:: 8.0
+    """
+
+    time: Pattern[str]
+    tzinfo: Pattern[str]
+    year: Pattern[str]
+    month: Pattern[str]
+    day: Pattern[str]


 class TimeStripper:
diff --git a/pywikibot/throttle.py b/pywikibot/throttle.py
index 3944d27..ec0cfba 100644
--- a/pywikibot/throttle.py
+++ b/pywikibot/throttle.py
@@ -10,9 +10,10 @@
 import math
 import threading
 import time
-from collections import Counter, namedtuple
+from collections import Counter
 from contextlib import suppress
 from hashlib import blake2b
+from typing import NamedTuple

 import pywikibot
 from pywikibot import config
@@ -21,7 +22,6 @@


 FORMAT_LINE = '{module_id} {pid} {time} {site}\n'
-ProcEntry = namedtuple('ProcEntry', ['module_id', 'pid', 'time', 'site'])

 pid: bool | int = False
 """global process identifier
@@ -32,6 +32,15 @@
 """


+class ProcEntry(NamedTuple):
+    """ProcEntry namedtuple."""
+
+    module_id: str
+    pid: int
+    time: int
+    site: str
+
+
 class Throttle:

     """Control rate of access to wiki server.
diff --git a/scripts/blockpageschecker.py b/scripts/blockpageschecker.py
index 9aa4f2c..438cbc8 100755
--- a/scripts/blockpageschecker.py
+++ b/scripts/blockpageschecker.py
@@ -52,8 +52,8 @@

 import re
 import webbrowser
-from collections import namedtuple
 from itertools import chain
+from typing import NamedTuple

 import pywikibot
 from pywikibot import i18n, pagegenerators
@@ -169,7 +169,12 @@
 project_inserted = ['ar', 'cs', 'fr', 'it', 'ja', 'pt', 'sr', 'ur', 'zh']

 # END PREFERENCES
-ParsedTemplate = namedtuple('ParsedTemplate', 'blocktype, regex, msgtype')
+
+
+class _ParsedTemplate(NamedTuple):
+    blocktype: str
+    regex: str
+    msgtype: str


 class CheckerBot(ConfigParserBot, ExistingPageBot, SingleSiteBot):
@@ -260,25 +265,25 @@
                 for catch_regex in template:
                     result_catch = re.findall(catch_regex, text)
                     if result_catch:
-                        return ParsedTemplate(
+                        return _ParsedTemplate(
                             results[index], catch_regex, 'modifying')
 
             if tsmp and ttmp and ttp != ttmp and tsp != tsmp:
                 for catch_regex in ttmp:
                     result_catch = re.findall(catch_regex, text)
                     if result_catch:
-                        return ParsedTemplate(
+                        return _ParsedTemplate(
                             'sysop-move', catch_regex, 'modifying')

                 for catch_regex in tsmp:
                     result_catch = re.findall(catch_regex, text)
                     if result_catch:
-                        return ParsedTemplate(
+                        return _ParsedTemplate(
                             'autoconfirmed-move', catch_regex, 'modifying')

             # If editable means that we have no regex, won't change anything
             # with this regex
-            return ParsedTemplate('editable', r'\A', 'adding')
+            return _ParsedTemplate('editable', r'\A', 'adding')

         tsp = i18n.translate(self.site, template_semi_protection)
         ttp = i18n.translate(self.site, template_total_protection)

--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/985373
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: I1802458320777ba0aaa7e59d406ca3358981eed8
Gerrit-Change-Number: 985373
Gerrit-PatchSet: 3
Gerrit-Owner: JJMC89 <[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