Philipp Hörist pushed to branch master at gajim / gajim

Commits:

19 changed files:

Changes:

  • gajim/common/jingle_session.py
    ... ... @@ -731,8 +731,7 @@ def __broadcast(self,
    731 731
                 name = content['name']
    
    732 732
                 creator = content['creator']
    
    733 733
                 if (creator, name) not in self.contents:
    
    734
    -                text = 'Content %s (created by %s) does not exist' % (name,
    
    735
    -                                                                      creator)
    
    734
    +                text = f'Content {name} (created by {creator}) does not exist'
    
    736 735
                     self.__send_error(stanza,
    
    737 736
                                       'bad-request',
    
    738 737
                                       text=text,
    
    ... ... @@ -753,7 +752,7 @@ def __on_session_terminate(self,
    753 752
             if reason not in ('success', 'cancel', 'decline'):
    
    754 753
                 self.__dispatch_error(reason, text)
    
    755 754
             if text:
    
    756
    -            text = '%s (%s)' % (reason, text)
    
    755
    +            text = f'{reason} ({text})'
    
    757 756
             else:
    
    758 757
                 # TODO
    
    759 758
                 text = reason
    
    ... ... @@ -828,7 +827,7 @@ def __dispatch_error(self,
    828 827
                              type_: str | None = None
    
    829 828
                              ) -> None:
    
    830 829
             if text:
    
    831
    -            text = '%s (%s)' % (error, text)
    
    830
    +            text = '{error} ({text})'
    
    832 831
             if type_ != 'modify':
    
    833 832
                 self._raise_event('jingle-error-received', reason=text or error)
    
    834 833
     
    
    ... ... @@ -877,7 +876,7 @@ def __send_error(self,
    877 876
                          text: str | None = None,
    
    878 877
                          type_: str | None = None
    
    879 878
                          ) -> None:
    
    880
    -        err_stanza = nbxmpp.Error(stanza, '%s %s' % (Namespace.STANZAS, error))
    
    879
    +        err_stanza = nbxmpp.Error(stanza, f'{Namespace.STANZAS} {error}')
    
    881 880
             err = err_stanza.getTag('error')
    
    882 881
             if type_:
    
    883 882
                 err.setAttr('type', type_)
    

  • gajim/common/modules/base.py
    ... ... @@ -65,9 +65,9 @@ def _set_logger(self, plugin: bool) -> LogAdapter:
    65 65
         def __getattr__(self, key: str) -> Any:
    
    66 66
             if key not in self._nbxmpp_methods:
    
    67 67
                 raise AttributeError(
    
    68
    -                "attribute '%s' is neither part of object '%s' "
    
    69
    -                " nor declared in '_nbxmpp_methods'" % (
    
    70
    -                    key, self.__class__.__name__))
    
    68
    +                f'attribute "{key}" is neither part of object '
    
    69
    +                f'"{self.__class__.__name__}" nor declared in '
    
    70
    +                '"_nbxmpp_methods"')
    
    71 71
     
    
    72 72
             if not app.account_is_connected(self._account):
    
    73 73
                 self._log.warning('Account not connected, can’t use %s', key)
    

  • gajim/common/modules/omemo.py
    ... ... @@ -317,7 +317,7 @@ def _encrypt_file_thread(transfer: HTTPFileTransfer,
    317 317
             transfer.size = len(result.payload)
    
    318 318
             fragment = binascii.hexlify(result.iv + result.key).decode()
    
    319 319
             transfer.set_uri_transform_func(
    
    320
    -            lambda uri: 'aesgcm%s#%s' % (uri[5:], fragment))
    
    320
    +            lambda uri: f'aesgcm{uri[5:]}#{fragment}')
    
    321 321
             transfer.set_encrypted_data(result.payload)
    
    322 322
             GLib.idle_add(callback, transfer)
    
    323 323
     
    

  • gajim/common/preview_helpers.py
    ... ... @@ -391,7 +391,7 @@ def fmt(f: float) -> str:
    391 391
             slon = p_('positive longitude', '%sE') % fmt(lon)
    
    392 392
         else:
    
    393 393
             slon = p_('negative longitude', '%sW') % fmt(-lon)
    
    394
    -    return '%s %s' % (slat, slon)
    
    394
    +    return f'{slat} {slon}'
    
    395 395
     
    
    396 396
     
    
    397 397
     def filename_from_uri(uri: str) -> str:
    

  • gajim/common/settings.py
    ... ... @@ -92,18 +92,18 @@
    92 92
                 settings TEXT
    
    93 93
         );
    
    94 94
     
    
    95
    -    INSERT INTO settings(name, settings) VALUES ('app', '{}');
    
    96
    -    INSERT INTO settings(name, settings) VALUES ('soundevents', '{}');
    
    97
    -    INSERT INTO settings(name, settings) VALUES ('status_presets', '%s');
    
    98
    -    INSERT INTO settings(name, settings) VALUES ('proxies', '%s');
    
    99
    -    INSERT INTO settings(name, settings) VALUES ('plugins', '{}');
    
    100
    -    INSERT INTO settings(name, settings) VALUES ('workspaces', '%s');
    
    101
    -
    
    102
    -    PRAGMA user_version=%s;
    
    103
    -    ''' % (json.dumps(STATUS_PRESET_EXAMPLES),
    
    104
    -           json.dumps(PROXY_EXAMPLES),
    
    105
    -           json.dumps(INITAL_WORKSPACE),
    
    106
    -           CURRENT_USER_VERSION)
    
    95
    +    INSERT INTO settings(name, settings) VALUES ('app', '{{}}');
    
    96
    +    INSERT INTO settings(name, settings) VALUES ('soundevents', '{{}}');
    
    97
    +    INSERT INTO settings(name, settings) VALUES ('status_presets', '{status}');
    
    98
    +    INSERT INTO settings(name, settings) VALUES ('proxies', '{proxies}');
    
    99
    +    INSERT INTO settings(name, settings) VALUES ('plugins', '{{}}');
    
    100
    +    INSERT INTO settings(name, settings) VALUES ('workspaces', '{workspaces}');
    
    101
    +
    
    102
    +    PRAGMA user_version={version};
    
    103
    +    '''.format(status=json.dumps(STATUS_PRESET_EXAMPLES),
    
    104
    +               proxies=json.dumps(PROXY_EXAMPLES),
    
    105
    +               workspaces=json.dumps(INITAL_WORKSPACE),
    
    106
    +               version=CURRENT_USER_VERSION)
    
    107 107
     
    
    108 108
     
    
    109 109
     _SignalCallable = Callable[[Any, str, str | None, JID | None], Any]
    

  • gajim/common/structs.py
    ... ... @@ -106,7 +106,7 @@ def __init__(self,
    106 106
                      ) -> None:
    
    107 107
     
    
    108 108
             if type_ not in ('chat', 'groupchat', 'normal', 'headline'):
    
    109
    -            raise ValueError('Unknown message type: %s' % type_)
    
    109
    +            raise ValueError(f'Unknown message type: {type_}')
    
    110 110
     
    
    111 111
             if not message and chatstate is None and marker is None:
    
    112 112
                 raise ValueError('Trying to send message without content')
    
    ... ... @@ -286,7 +286,7 @@ def _get_type_and_variant_string(self,
    286 286
             if 'JID' in field_type:
    
    287 287
                 return JID, f'{variant_str}s'
    
    288 288
     
    
    289
    -        raise ValueError('unknown type: %s' % field_type)
    
    289
    +        raise ValueError(f'unknown type: {field_type}')
    
    290 290
     
    
    291 291
         def to_variant(self) -> GLib.Variant:
    
    292 292
             __types = {}
    
    ... ... @@ -299,8 +299,7 @@ def to_variant(self) -> GLib.Variant:
    299 299
                     continue
    
    300 300
     
    
    301 301
                 if not isinstance(value, field_t):
    
    302
    -                raise ValueError('invalid type: %s is not a %s' % (value,
    
    303
    -                                                                   field_t))
    
    302
    +                raise ValueError(f'invalid type: {value} is not a {field_t}')
    
    304 303
     
    
    305 304
                 conversion_func = self._type_to_variant_funcs.get(field_t)
    
    306 305
                 if conversion_func is not None:
    
    ... ... @@ -322,6 +321,6 @@ def from_variant(cls: type[_T], variant: GLib.Variant) -> _T:
    322 321
                     value = vdict[field_name]
    
    323 322
                     conversion_func = cls._variant_to_type_funcs.get(value_t_name)
    
    324 323
                     if conversion_func is None:
    
    325
    -                    raise ValueError('no conversion for: %s' % value_t_name)
    
    324
    +                    raise ValueError(f'no conversion for: {value_t_name}')
    
    326 325
                     vdict[field_name] = conversion_func(value)
    
    327 326
             return cls(**vdict)

  • gajim/common/styling.py
    ... ... @@ -185,7 +185,7 @@ def find_byte_index(text: str, index: int):
    185 185
             if index == index_:
    
    186 186
                 return byte_index
    
    187 187
     
    
    188
    -    raise ValueError('index not in string: %s, %s' % (text, index))
    
    188
    +    raise ValueError(f'index not in string: {text}, {index}')
    
    189 189
     
    
    190 190
     
    
    191 191
     def process(text: str | bytes, level: int = 0) -> ParsingResult:
    

  • gajim/common/util/text.py
    ... ... @@ -14,6 +14,8 @@
    14 14
     
    
    15 15
     from __future__ import annotations
    
    16 16
     
    
    17
    +from typing import Literal
    
    18
    +
    
    17 19
     import re
    
    18 20
     
    
    19 21
     from gi.repository import GLib
    
    ... ... @@ -70,3 +72,18 @@ def format_duration(ns: float, total_ns: float) -> str:
    70 72
             return (f'%0{width}d' % i_minutes) + f':{i_seconds:02d}'
    
    71 73
     
    
    72 74
         return f'0:{i_seconds:02d}'
    
    75
    +
    
    76
    +
    
    77
    +def format_sha_bytes(algo: Literal['sha1', 'sha256'], sha_bytes: bytes) -> str:
    
    78
    +    if algo == 'sha1':
    
    79
    +        stop, step = 20, 10
    
    80
    +    elif algo == 'sha256':
    
    81
    +        stop, step = 32, 8
    
    82
    +    else:
    
    83
    +        raise ValueError(f'Unknown algo: {algo}')
    
    84
    +
    
    85
    +    lines: list[str] = []
    
    86
    +    hex_list = [f'{b:02X}' for b in sha_bytes]
    
    87
    +    for pos in range(0, stop, step):
    
    88
    +        lines.append(':'.join(hex_list[pos:pos + step]))
    
    89
    +    return '\n'.join(lines)

  • gajim/gajim.py
    ... ... @@ -40,22 +40,22 @@
    40 40
     
    
    41 41
     def check_version(dep_name: str, current_ver: str, min_ver: str) -> None:
    
    42 42
         if V(current_ver) < V(min_ver):
    
    43
    -        sys.exit('Gajim needs %s >= %s (found %s) to run. '
    
    44
    -                 'Quitting...' % (dep_name, min_ver, current_ver))
    
    43
    +        sys.exit(f'Gajim needs {dep_name} >= {min_ver} '
    
    44
    +                 f'(found {current_ver}) to run. Quitting...')
    
    45 45
     
    
    46 46
     
    
    47 47
     def _check_required_deps() -> None:
    
    48
    -    error_message = 'Gajim needs %s to run. Quitting… (Error: %s)'
    
    48
    +    error_message = 'Gajim needs {lib} to run. Quitting… (Error: {error})'
    
    49 49
     
    
    50 50
         try:
    
    51 51
             import nbxmpp
    
    52 52
         except ImportError as error:
    
    53
    -        sys.exit(error_message % ('python-nbxmpp', error))
    
    53
    +        sys.exit(error_message.format('python-nbxmpp', error))
    
    54 54
     
    
    55 55
         try:
    
    56 56
             import gi
    
    57 57
         except ImportError as error:
    
    58
    -        sys.exit(error_message % ('pygobject', error))
    
    58
    +        sys.exit(error_message.format('pygobject', error))
    
    59 59
     
    
    60 60
         try:
    
    61 61
             gi.require_versions({'GLib': '2.0',
    
    ... ... @@ -66,17 +66,17 @@ def _check_required_deps() -> None:
    66 66
                                  'Pango': '1.0',
    
    67 67
                                  'PangoCairo': '1.0'})
    
    68 68
         except ValueError as error:
    
    69
    -        sys.exit('Missing dependency: %s' % error)
    
    69
    +        sys.exit(f'Missing dependency: {error}')
    
    70 70
     
    
    71 71
         try:
    
    72 72
             import cairo
    
    73 73
         except ImportError as error:
    
    74
    -        sys.exit(error_message % ('pycairo', error))
    
    74
    +        sys.exit(error_message.format('pycairo', error))
    
    75 75
     
    
    76 76
         from gi.repository import Gtk
    
    77
    -    gtk_ver = '%s.%s.%s' % (Gtk.get_major_version(),
    
    78
    -                            Gtk.get_minor_version(),
    
    79
    -                            Gtk.get_micro_version())
    
    77
    +    gtk_ver = '.'.join(map(str, [Gtk.get_major_version(),
    
    78
    +                                 Gtk.get_minor_version(),
    
    79
    +                                 Gtk.get_micro_version()]))
    
    80 80
     
    
    81 81
         from gi.repository import GLib
    
    82 82
         glib_ver = '.'.join(map(str, [GLib.MAJOR_VERSION,
    

  • gajim/gtk/accounts.py
    ... ... @@ -941,9 +941,9 @@ def __init__(self, account: str) -> None:
    941 941
     
    
    942 942
             btbv_label = Gtk.Label()
    
    943 943
             btbv_label.set_xalign(0)
    
    944
    -        markup = '<a href="%s">%s</a>' % (
    
    945
    -            'https://dev.gajim.org/gajim/gajim/-/wikis/help/OMEMO',
    
    946
    -            _('Read more about blind trust'))
    
    944
    +        wiki_url = 'https://dev.gajim.org/gajim/gajim/-/wikis/help/OMEMO'
    
    945
    +        link_text = _('Read more about blind trust')
    
    946
    +        markup = f'<a href="{wiki_url}">{link_text}</a>'
    
    947 947
             btbv_label.set_markup(markup)
    
    948 948
             self.add(btbv_label)
    
    949 949
     
    

  • gajim/gtk/application.py
    ... ... @@ -372,7 +372,7 @@ def _handle_local_options(self,
    372 372
                 # Incorporate profile name into application id
    
    373 373
                 # to have a single app instance for each profile.
    
    374 374
                 profile = profile.get_string()
    
    375
    -            app_id = '%s.%s' % (self.get_application_id(), profile)
    
    375
    +            app_id = f'{self.get_application_id()}.{profile}'
    
    376 376
                 self.set_application_id(app_id)
    
    377 377
                 configpaths.set_profile(profile)
    
    378 378
     
    

  • gajim/gtk/certificate_dialog.py
    ... ... @@ -29,6 +29,7 @@
    29 29
     from gajim.common import app
    
    30 30
     from gajim.common.helpers import get_x509_cert_from_gio_cert
    
    31 31
     from gajim.common.i18n import _
    
    32
    +from gajim.common.util.text import format_sha_bytes
    
    32 33
     
    
    33 34
     from gajim.gtk.builder import get_builder
    
    34 35
     
    
    ... ... @@ -109,13 +110,10 @@ def __init__(self, account: str, certificate: Gio.TlsCertificate) -> None:
    109 110
             self._expires = cert.not_valid_after.strftime('%c %Z')
    
    110 111
     
    
    111 112
             sha1_bytes = cert.fingerprint(hashes.SHA1())
    
    112
    -        sha1 = ':'.join(f'{b:02X}' for b in sha1_bytes)
    
    113
    -        self._sha1 = '%s\n%s' % (sha1[:29], sha1[30:])
    
    113
    +        self._sha1 = format_sha_bytes('sha1', sha1_bytes)
    
    114 114
     
    
    115 115
             sha256_bytes = cert.fingerprint(hashes.SHA256())
    
    116
    -        sha256 = ':'.join(f'{b:02X}' for b in sha256_bytes)
    
    117
    -        self._sha256 = '%s\n%s\n%s\n%s' % (
    
    118
    -            sha256[:23], sha256[24:47], sha256[48:71], sha256[72:])
    
    116
    +        self._sha256 = format_sha_bytes('sha256', sha256_bytes)
    
    119 117
     
    
    120 118
             public_key = cert.public_key()
    
    121 119
             self._pk_algorithm = ''
    

  • gajim/gtk/css_config.py
    ... ... @@ -640,7 +640,7 @@ def refresh(self) -> None:
    640 640
             for index, account in enumerate(accounts):
    
    641 641
                 color = app.settings.get_account_setting(account, 'account_color')
    
    642 642
                 css_class = f'gajim_class_{index}'
    
    643
    -            css += '.%s { background-color: %s }\n' % (css_class, color)
    
    643
    +            css += f'.{css_class} {{ background-color: {color} }}\n'
    
    644 644
                 self._dynamic_dict[account] = css_class
    
    645 645
     
    
    646 646
             self._dynamic_provider.load_from_data(css.encode())
    

  • gajim/gtk/discovery.py
    ... ... @@ -208,7 +208,7 @@ def get_agent_address(jid, node=None):
    208 208
         Get an agent's address for displaying in the GUI
    
    209 209
         '''
    
    210 210
         if node:
    
    211
    -        return '%s@%s' % (node, str(jid))
    
    211
    +        return f'{node}@{str(jid)}'
    
    212 212
         return str(jid)
    
    213 213
     
    
    214 214
     
    
    ... ... @@ -301,7 +301,7 @@ def get_icon(self, identities=None, addr=''):
    301 301
                 service_name = addr.split('.')[0]
    
    302 302
     
    
    303 303
             # Or load it
    
    304
    -        icon_name = 'gajim-agent-%s' % service_name
    
    304
    +        icon_name = f'gajim-agent-{service_name}'
    
    305 305
             if icon_exists(icon_name):
    
    306 306
                 return icon_name
    
    307 307
             return 'gajim-agent-jabber'
    
    ... ... @@ -1139,7 +1139,7 @@ def __init__(self, *args):
    1139 1139
     
    
    1140 1140
         def add_self_line(self):
    
    1141 1141
             addr = get_agent_address(self.jid, self.node)
    
    1142
    -        descr = '<b>%s</b>' % addr
    
    1142
    +        descr = f'<b>{addr}</b>'
    
    1143 1143
             # Guess which kind of service this is
    
    1144 1144
             identities = []
    
    1145 1145
             type_ = app.get_transport_name_from_jid(self.jid,
    
    ... ... @@ -1541,9 +1541,9 @@ def _add_item(self, jid, node, parent_node, item, force):
    1541 1541
             # Row text
    
    1542 1542
             addr = get_agent_address(jid, node)
    
    1543 1543
             if 'name' in item:
    
    1544
    -            descr = '<b>%s</b>\n%s' % (item['name'], addr)
    
    1544
    +            descr = f'<b>{item["name"]}</b>\n{addr}'
    
    1545 1545
             else:
    
    1546
    -            descr = '<b>%s</b>' % addr
    
    1546
    +            descr = f'<b>{addr}</b>'
    
    1547 1547
             # Guess which kind of service this is
    
    1548 1548
             identities = []
    
    1549 1549
             type_ = app.get_transport_name_from_jid(
    
    ... ... @@ -1570,21 +1570,21 @@ def _add_item(self, jid, node, parent_node, item, force):
    1570 1570
         def _update_item(self, iter_, jid, node, item):
    
    1571 1571
             addr = get_agent_address(jid, node)
    
    1572 1572
             if 'name' in item:
    
    1573
    -            descr = '<b>%s</b>\n%s' % (item['name'], addr)
    
    1573
    +            descr = f'<b>{item["name"]}</b>\n{addr}'
    
    1574 1574
             else:
    
    1575
    -            descr = '<b>%s</b>' % addr
    
    1575
    +            descr = f'<b>{addr}</b>'
    
    1576 1576
             self.model[iter_][3] = descr
    
    1577 1577
     
    
    1578 1578
         def _update_info(self, iter_, jid, node, identities, features, data):
    
    1579 1579
             addr = get_agent_address(jid, node)
    
    1580 1580
             if not identities:
    
    1581
    -            descr = '<b>%s</b>' % addr
    
    1581
    +            descr = '<b>{addr}</b>'
    
    1582 1582
             else:
    
    1583 1583
                 name = identities[0].name or ''
    
    1584 1584
                 if name:
    
    1585
    -                descr = '<b>%s</b>\n%s' % (name, addr)
    
    1585
    +                descr = f'<b>{name}</b>\n{addr}'
    
    1586 1586
                 else:
    
    1587
    -                descr = '<b>%s</b>' % addr
    
    1587
    +                descr = f'<b>{addr}</b>'
    
    1588 1588
     
    
    1589 1589
             # Update progress
    
    1590 1590
             self._progress += 1
    

  • gajim/gtk/exception.py
    ... ... @@ -190,13 +190,13 @@ def _request_sentry_endpoint(self) -> None:
    190 190
     
    
    191 191
         def _parse_endpoint(self, request: HTTPRequest) -> str:
    
    192 192
             if not request.is_complete():
    
    193
    -            raise ValueError('Failed to retrieve sentry endpoint: %s %s' % (
    
    194
    -                request.get_status(), request.get_error()))
    
    193
    +            raise ValueError('Failed to retrieve sentry endpoint: '
    
    194
    +                             f'{request.get_status()} {request.get_error()}')
    
    195 195
     
    
    196 196
             try:
    
    197 197
                 data = json.loads(request.get_data())
    
    198 198
             except Exception as error:
    
    199
    -            raise ValueError('Json parsing error: %s' % error)
    
    199
    +            raise ValueError(f'Json parsing error: {error}')
    
    200 200
     
    
    201 201
             endpoint = data.get('sentry_endpoint')
    
    202 202
             if endpoint is None:
    

  • gajim/gtk/groupchat_join.py
    ... ... @@ -142,7 +142,7 @@ def _set_error(self, error: StanzaError) -> None:
    142 142
             if error.condition == 'gone':
    
    143 143
                 reason = error.get_text(get_rfc5646_lang())
    
    144 144
                 if reason:
    
    145
    -                text = '%s:\n%s' % (text, reason)
    
    145
    +                text = f'{text}:\n{reason}'
    
    146 146
             self._show_error_page(text)
    
    147 147
     
    
    148 148
         def _set_error_from_code(self, error_code: str) -> None:
    

  • gajim/gtk/omemo_trust_manager.py
    ... ... @@ -355,7 +355,7 @@ def update(self) -> None:
    355 355
     
    
    356 356
             if not self._row.active:
    
    357 357
                 css_class = 'omemo-inactive-color'
    
    358
    -            tooltip = '%s - %s' % (_('Inactive'), tooltip)
    
    358
    +            tooltip = f'{_("Inactive")} - {tooltip}'
    
    359 359
     
    
    360 360
             image.get_style_context().add_class(css_class)
    
    361 361
             self._css_class = css_class
    

  • gajim/gtk/util.py
    ... ... @@ -323,7 +323,7 @@ def convert_rgba_to_hex(rgba: Gdk.RGBA) -> str:
    323 323
         red = int(rgba.red * 255)
    
    324 324
         green = int(rgba.green * 255)
    
    325 325
         blue = int(rgba.blue * 255)
    
    326
    -    return '#%02x%02x%02x' % (red, green, blue)
    
    326
    +    return f'#{red:02x}{green:02x}{blue:02x}'
    
    327 327
     
    
    328 328
     
    
    329 329
     def convert_rgb_to_hex(rgb_string: str) -> str:
    
    ... ... @@ -428,8 +428,7 @@ def format_location(location: LocationData) -> str:
    428 428
             tag = LOCATION_DATA.get(attr)
    
    429 429
             if tag is None:
    
    430 430
                 continue
    
    431
    -        location_string += '\n<b>%(tag)s</b>: %(text)s' % {
    
    432
    -            'tag': tag.capitalize(), 'text': text}
    
    431
    +        location_string += f'\n<b>{tag.capitalize()}</b>: {text}'
    
    433 432
     
    
    434 433
         return location_string.strip()
    
    435 434
     
    
    ... ... @@ -456,7 +455,7 @@ def format_fingerprint(fingerprint: str) -> str:
    456 455
         wordsize = fplen // 8
    
    457 456
         buf = ''
    
    458 457
         for char in range(0, fplen, wordsize):
    
    459
    -        buf += '{0} '.format(fingerprint[char:char + wordsize])
    
    458
    +        buf += f'{fingerprint[char:char + wordsize]} '
    
    460 459
         buf = textwrap.fill(buf, width=36)
    
    461 460
         return buf.rstrip().upper()
    
    462 461
     
    
    ... ... @@ -670,8 +669,8 @@ def _to_href(match: Match[str]) -> str:
    670 669
             url = match.group()
    
    671 670
             if '://' not in url:
    
    672 671
                 url = 'https://' + url
    
    673
    -        return '<a href="%s"><span foreground="%s">%s</span></a>' % (
    
    674
    -            url, color, match.group())
    
    672
    +        return (f'<a href="{url}"><span foreground="{color}">'
    
    673
    +                f'{match.group()}</span></a>')
    
    675 674
     
    
    676 675
         return URL_REGEX.sub(_to_href, string)
    
    677 676
     
    

  • pyproject.toml
    ... ... @@ -233,8 +233,6 @@ ignore = [
    233 233
       "SIM201", # Use x instead of not x
    
    234 234
       "SIM212", # Use `value if value else ''` instead of `'' if not value else value`
    
    235 235
       "SIM300", # Yoda conditions are discouraged use x instead
    
    236
    -  "UP030",  # Use implicit references for positional format fields
    
    237
    -  "UP031",  # Use format specifiers instead of percent format
    
    238 236
       "UP032",  # Use f-string instead of `format` call
    
    239 237
       "UP034",  # Avoid extraneous parentheses
    
    240 238
       "UP035",  # Import from `collections.abc` instead: `Callable`