jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1351448?usp=email )

Change subject: Build strings from joined fragments
......................................................................

Build strings from joined fragments

Collect replacement, date-pattern and displayed-list fragments before
joining them. Avoid repeatedly copying the accumulated string on Python
implementations without concatenation optimizations.

Preserve output order, whitespace and replacement-group handling.

Change-Id: Ia2cfa782412c78382d322b7c5baa7b01c51a3d6a
---
M pywikibot/bot_choice.py
M pywikibot/date.py
M pywikibot/pagegenerators/_factory.py
M pywikibot/textlib.py
4 files changed, 38 insertions(+), 39 deletions(-)

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




diff --git a/pywikibot/bot_choice.py b/pywikibot/bot_choice.py
index 4951f27..46ca97b 100644
--- a/pywikibot/bot_choice.py
+++ b/pywikibot/bot_choice.py
@@ -533,15 +533,15 @@
     @property
     def out(self) -> str:
         """Output text of the enumerated list."""
-        text = ''
+        text_parts = []
         if self.pre is not None:
-            text = self.pre + '\n'
+            text_parts.append(self.pre + '\n')
         width = len(str(self.maximum))
-        for i, item in enumerate(self._list, self.minimum):
-            text += f'{i:>{width}} - {item}\n'
+        text_parts.extend(f'{i:>{width}} - {item}\n'
+                          for i, item in enumerate(self._list, self.minimum))
         if self.post is not None:
-            text += self.post + '\n'
-        return text
+            text_parts.append(self.post + '\n')
+        return ''.join(text_parts)


 class MultipleChoiceList(ListOption):
diff --git a/pywikibot/date.py b/pywikibot/date.py
index 56bcab0..b9f0ecb 100644
--- a/pywikibot/date.py
+++ b/pywikibot/date.py
@@ -404,37 +404,35 @@
     compiled regex object and a list of digit decoders.
     """
     @singledispatch
-    def decode(dec: decoder_type, subpattern: str, newpattern: str,
-               strpattern: str) -> tuple[str, str]:
+    def decode(dec: decoder_type, subpattern: str) -> tuple[str, str]:

         if len(subpattern) == 3:
             # enforce mandatory field size
-            newpattern += f'([{dec[0]}]{{{subpattern[1]}}})'
+            newpattern = f'([{dec[0]}]{{{subpattern[1]}}})'
             # add the number of required digits as the last (4th)
             # part of the tuple
             decoders.append((*dec, int(s[1])))
         else:
-            newpattern += f'([{dec[0]}]+)'
+            newpattern = f'([{dec[0]}]+)'
             decoders.append(dec)

-        # All encoders produce a string for strpattern.
+        # All encoders produce a string for the format placeholder.
         # This causes problem with the zero padding.
         # Need to rethink

-        return newpattern, strpattern + '%s'
+        return newpattern, '%s'

     @decode.register(str)
-    def _(dec: str, subpattern: str, newpattern: str,
-          strpattern: str) -> tuple[str, str]:
+    def _(dec: str, subpattern: str) -> tuple[str, str]:
         # Special case for strings that are replaced instead of decoded
-        # Keep the original text for strPattern
+        # Keep the original text for the format placeholder
         assert len(subpattern) < 3, (
             f'Invalid pattern {pattern}: Cannot use zero padding size '
             f'in {subpattern}!')
-        return newpattern + re.escape(dec), strpattern + subpattern
+        return re.escape(dec), subpattern

-    newPattern = ''  # match starts at the beginning of the string
-    strPattern = ''
+    regex_parts = []  # match starts at the beginning of the string
+    string_parts = []
     decoders: list[decoder_type] = []
     for s in _reParameters.split(pattern):
         if s is None:
@@ -444,14 +442,15 @@
                 and (len(s) == 2 or s[1] in _decimalDigits)):
             # Must match a "%2d" or "%d" style
             dec = _digitDecoders[s[-1]]
-            newPattern, strPattern = decode(dec, s, newPattern, strPattern)
+            regex_part, string_part = decode(dec, s)
         else:
-            newPattern += re.escape(s)
-            strPattern += s
+            regex_part, string_part = re.escape(s), s
+        regex_parts.append(regex_part)
+        string_parts.append(string_part)

-    newPattern += '$'  # end of the string
-    compiledPattern = re.compile(newPattern)
-    return compiledPattern, strPattern, decoders
+    regex_parts.append('$')  # end of the string
+    compiledPattern = re.compile(''.join(regex_parts))
+    return compiledPattern, ''.join(string_parts), decoders


 @singledispatch
diff --git a/pywikibot/pagegenerators/_factory.py 
b/pywikibot/pagegenerators/_factory.py
index 740c6b1..31439be 100644
--- a/pywikibot/pagegenerators/_factory.py
+++ b/pywikibot/pagegenerators/_factory.py
@@ -502,12 +502,11 @@
                                       ) -> None:
             _i = ' ' * 4
             _2i = 2 * _i
-            txt = 'Available categories of lint errors:\n'
+            text_parts = ['Available categories of lint errors:\n']
             for prio, _list in cats.items():
-                txt += f'{_i}{prio}\n'
-                txt += ''.join(
-                    f'{_2i}{c}\n' for c in _list)
-            pywikibot.info(txt)
+                text_parts.append(f'{_i}{prio}\n')
+                text_parts.extend(f'{_2i}{c}\n' for c in _list)
+            pywikibot.info(''.join(text_parts))

         if cat == 'show':  # Display categories of lint errors.
             show_available_categories(cats)
@@ -536,12 +535,12 @@
                                                    'limit')

             max_w = max(len(p) for p in pages[::2]) + 4
-            txt = 'Available special pages:\n'
-            for a, b in zip_longest(pages[::2], pages[1::2], fillvalue=''):
-                txt += f'    {a:<{max_w}}{b}\n'
-            txt += ('\nMaximum number of pages to return is {max} '
-                    '({highmax} for bots).\n'.format_map(limit))
-            pywikibot.info(txt)
+            text_parts = ['Available special pages:\n']
+            text_parts.extend(f'    {a:<{max_w}}{b}\n' for a, b in zip_longest(
+                pages[::2], pages[1::2], fillvalue=''))
+            text_parts.append('\nMaximum number of pages to return is {max} '
+                              '({highmax} for bots).\n'.format_map(limit))
+            pywikibot.info(''.join(text_parts))
             sys.exit(0)

         return self.site.querypage(value)
diff --git a/pywikibot/textlib.py b/pywikibot/textlib.py
index 71c05b2..2b6fe7c 100644
--- a/pywikibot/textlib.py
+++ b/pywikibot/textlib.py
@@ -470,7 +470,7 @@
             # On the other hand, this approach does not work because it
             # can't handle lookahead or lookbehind (see bug T123185).
             # So we have to process the group references manually.
-            replacement = ''
+            replacement_parts = []

             group_regex = re.compile(r'\\(\d+)|\\g<(.+?)>')
             last = 0
@@ -480,13 +480,14 @@
                     group_id = int(group_id)

                 try:
-                    replacement += new[last:group_match.start()]
-                    replacement += match[group_id] or ''
+                    replacement_parts.append(new[last:group_match.start()])
+                    replacement_parts.append(match[group_id] or '')
                 except IndexError:
                     raise IndexError(f'Invalid group reference: {group_id}\n'
                                      f'Groups found: {match.groups()}')
                 last = group_match.end()
-            replacement += new[last:]
+            replacement_parts.append(new[last:])
+            replacement = ''.join(replacement_parts)

         text = text[:match_start] + replacement + text[match.end():]


--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1351448?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ia2cfa782412c78382d322b7c5baa7b01c51a3d6a
Gerrit-Change-Number: 1351448
Gerrit-PatchSet: 1
Gerrit-Owner: Mahveotm <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to