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

Commits:

26 changed files:

Changes:

  • gajim/application.py
    ... ... @@ -36,7 +36,6 @@
    36 36
     import time
    
    37 37
     import sys
    
    38 38
     from datetime import datetime
    
    39
    -from pathlib import Path
    
    40 39
     from urllib.parse import unquote
    
    41 40
     
    
    42 41
     from nbxmpp.namespaces import Namespace
    
    ... ... @@ -384,7 +383,7 @@ def warn_with_traceback(message, category, filename, lineno,
    384 383
     
    
    385 384
         @staticmethod
    
    386 385
         def _redirect_output():
    
    387
    -        debug_folder = Path(configpaths.get('DEBUG'))
    
    386
    +        debug_folder = configpaths.get('DEBUG')
    
    388 387
             date = datetime.today().strftime('%d%m%Y-%H%M%S')
    
    389 388
             filename = '%s-debug.log' % date
    
    390 389
             fd = open(debug_folder / filename, 'a')
    
    ... ... @@ -392,7 +391,7 @@ def _redirect_output():
    392 391
     
    
    393 392
         @staticmethod
    
    394 393
         def _cleanup_debug_logs():
    
    395
    -        debug_folder = Path(configpaths.get('DEBUG'))
    
    394
    +        debug_folder = configpaths.get('DEBUG')
    
    396 395
             debug_files = list(debug_folder.glob('*-debug.log*'))
    
    397 396
             now = time.time()
    
    398 397
             for file in debug_files:
    

  • gajim/common/app.py
    ... ... @@ -34,7 +34,6 @@
    34 34
     import sys
    
    35 35
     import logging
    
    36 36
     import uuid
    
    37
    -from pathlib import Path
    
    38 37
     from collections import namedtuple
    
    39 38
     from collections import defaultdict
    
    40 39
     
    
    ... ... @@ -631,7 +630,7 @@ def load_css_config():
    631 630
         css_config = CSSConfig()
    
    632 631
     
    
    633 632
     def set_debug_mode(enable: bool) -> None:
    
    634
    -    debug_folder = Path(configpaths.get('DEBUG'))
    
    633
    +    debug_folder = configpaths.get('DEBUG')
    
    635 634
         debug_enabled = debug_folder / 'debug-enabled'
    
    636 635
         if enable:
    
    637 636
             debug_enabled.touch()
    
    ... ... @@ -640,7 +639,7 @@ def set_debug_mode(enable: bool) -> None:
    640 639
                 debug_enabled.unlink()
    
    641 640
     
    
    642 641
     def get_debug_mode() -> bool:
    
    643
    -    debug_folder = Path(configpaths.get('DEBUG'))
    
    642
    +    debug_folder = configpaths.get('DEBUG')
    
    644 643
         debug_enabled = debug_folder / 'debug-enabled'
    
    645 644
         return debug_enabled.exists()
    
    646 645
     
    
    ... ... @@ -648,7 +647,7 @@ def get_stored_bob_data(algo_hash: str) -> Optional[bytes]:
    648 647
         try:
    
    649 648
             return bob_cache[algo_hash]
    
    650 649
         except KeyError:
    
    651
    -        filepath = Path(configpaths.get('BOB')) / algo_hash
    
    650
    +        filepath = configpaths.get('BOB') / algo_hash
    
    652 651
             if filepath.exists():
    
    653 652
                 with open(str(filepath), 'r+b') as file:
    
    654 653
                     data = file.read()
    

  • gajim/common/cert_store.py
    ... ... @@ -14,7 +14,6 @@
    14 14
     
    
    15 15
     
    
    16 16
     import logging
    
    17
    -from pathlib import Path
    
    18 17
     
    
    19 18
     from gi.repository import GLib
    
    20 19
     from gi.repository import Gio
    
    ... ... @@ -30,7 +29,7 @@
    30 29
     
    
    31 30
     class CertificateStore:
    
    32 31
         def __init__(self):
    
    33
    -        self._path = Path(configpaths.get('CERT_STORE'))
    
    32
    +        self._path = configpaths.get('CERT_STORE')
    
    34 33
             self._certs = []
    
    35 34
     
    
    36 35
             self._load_certificates()
    

  • gajim/common/configpaths.py
    ... ... @@ -38,7 +38,7 @@
    38 38
     from gajim.common.types import PathTuple
    
    39 39
     
    
    40 40
     
    
    41
    -def get(key: str) -> str:
    
    41
    +def get(key: str) -> Path:
    
    42 42
         return _paths[key]
    
    43 43
     
    
    44 44
     
    
    ... ... @@ -50,7 +50,7 @@ def get_plugin_dirs() -> List[Path]:
    50 50
                 Path(_paths['PLUGINS_USER'])]
    
    51 51
     
    
    52 52
     
    
    53
    -def get_paths(type_: PathType) -> Generator[str, None, None]:
    
    53
    +def get_paths(type_: PathType) -> Generator[Path, None, None]:
    
    54 54
         for key, value in _paths.items():
    
    55 55
             path_type = value[2]
    
    56 56
             if type_ != path_type:
    
    ... ... @@ -71,7 +71,7 @@ def set_profile(profile: str) -> None:
    71 71
     
    
    72 72
     
    
    73 73
     def set_config_root(config_root: str) -> None:
    
    74
    -    _paths.custom_config_root = str(Path(config_root).resolve())
    
    74
    +    _paths.custom_config_root = Path(config_root).resolve()
    
    75 75
     
    
    76 76
     
    
    77 77
     def init() -> None:
    
    ... ... @@ -80,24 +80,21 @@ def init() -> None:
    80 80
     
    
    81 81
     def create_paths() -> None:
    
    82 82
         for path in get_paths(PathType.FOLDER):
    
    83
    -        if not isinstance(path, Path):
    
    84
    -            path_ = Path(path)
    
    85
    -
    
    86
    -        if path_.is_file():
    
    87
    -            print(_('%s is a file but it should be a directory') % path_)
    
    83
    +        if path.is_file():
    
    84
    +            print(_('%s is a file but it should be a directory') % path)
    
    88 85
                 print(_('Gajim will now exit'))
    
    89 86
                 sys.exit()
    
    90 87
     
    
    91
    -        if not path_.exists():
    
    92
    -            for parent_path in reversed(path_.parents):
    
    88
    +        if not path.exists():
    
    89
    +            for parent_path in reversed(path.parents):
    
    93 90
                     # Create all parent folders
    
    94 91
                     # don't use mkdir(parent=True), as it ignores `mode`
    
    95 92
                     # when creating the parents
    
    96 93
                     if not parent_path.exists():
    
    97 94
                         print(('creating %s directory') % parent_path)
    
    98 95
                         parent_path.mkdir(mode=0o700)
    
    99
    -            print(('creating %s directory') % path_)
    
    100
    -            path_.mkdir(mode=0o700)
    
    96
    +            print(('creating %s directory') % path)
    
    97
    +            path.mkdir(mode=0o700)
    
    101 98
     
    
    102 99
     
    
    103 100
     class ConfigPaths:
    
    ... ... @@ -105,67 +102,66 @@ def __init__(self) -> None:
    105 102
             self._paths = {}  # type: Dict[str, PathTuple]
    
    106 103
             self.profile = ''
    
    107 104
             self.profile_separation = False
    
    108
    -        self.custom_config_root = None  # type: Optional[str]
    
    105
    +        self.custom_config_root = None  # type: Optional[Path]
    
    109 106
     
    
    110 107
             if os.name == 'nt':
    
    111 108
                 try:
    
    112 109
                     # Documents and Settings\[User Name]\Application Data\Gajim
    
    113 110
                     self.config_root = self.cache_root = self.data_root = \
    
    114
    -                        os.path.join(os.environ['appdata'], 'Gajim')
    
    111
    +                        Path(os.environ['appdata']) / 'Gajim'
    
    115 112
                 except KeyError:
    
    116 113
                     # win9x, in cwd
    
    117
    -                self.config_root = self.cache_root = self.data_root = '.'
    
    114
    +                self.config_root = self.cache_root = self.data_root = Path('.')
    
    118 115
             else:
    
    119
    -            self.config_root = os.path.join(GLib.get_user_config_dir(),
    
    120
    -                                            'gajim')
    
    121
    -            self.cache_root = os.path.join(GLib.get_user_cache_dir(), 'gajim')
    
    122
    -            self.data_root = os.path.join(GLib.get_user_data_dir(), 'gajim')
    
    116
    +            self.config_root = Path(GLib.get_user_config_dir()) / 'gajim'
    
    117
    +            self.cache_root = Path(GLib.get_user_cache_dir()) / 'gajim'
    
    118
    +            self.data_root = Path(GLib.get_user_data_dir()) / 'gajim'
    
    123 119
     
    
    124 120
             import pkg_resources
    
    125
    -        basedir = pkg_resources.resource_filename("gajim", ".")
    
    121
    +        basedir = Path(pkg_resources.resource_filename("gajim", "."))
    
    126 122
     
    
    127 123
             source_paths = [
    
    128
    -            ('DATA', os.path.join(basedir, 'data')),
    
    129
    -            ('STYLE', os.path.join(basedir, 'data', 'style')),
    
    130
    -            ('EMOTICONS', os.path.join(basedir, 'data', 'emoticons')),
    
    131
    -            ('GUI', os.path.join(basedir, 'data', 'gui')),
    
    132
    -            ('ICONS', os.path.join(basedir, 'data', 'icons')),
    
    133
    -            ('HOME', os.path.expanduser('~')),
    
    134
    -            ('PLUGINS_BASE', os.path.join(basedir, 'data', 'plugins')),
    
    124
    +            ('DATA', basedir / 'data'),
    
    125
    +            ('STYLE', basedir / 'data' / 'style'),
    
    126
    +            ('EMOTICONS', basedir / 'data' / 'emoticons'),
    
    127
    +            ('GUI', basedir / 'data' / 'gui'),
    
    128
    +            ('ICONS', basedir / 'data' / 'icons'),
    
    129
    +            ('HOME', Path.home()),
    
    130
    +            ('PLUGINS_BASE', basedir / 'data' / 'plugins'),
    
    135 131
             ]
    
    136 132
     
    
    137 133
             for path in source_paths:
    
    138 134
                 self.add(*path)
    
    139 135
     
    
    140
    -    def __getitem__(self, key: str) -> str:
    
    136
    +    def __getitem__(self, key: str) -> Path:
    
    141 137
             location, path, _ = self._paths[key]
    
    142 138
             if location == PathLocation.CONFIG:
    
    143
    -            return os.path.join(self.config_root, path)
    
    139
    +            return self.config_root / path
    
    144 140
             if location == PathLocation.CACHE:
    
    145
    -            return os.path.join(self.cache_root, path)
    
    141
    +            return self.cache_root / path
    
    146 142
             if location == PathLocation.DATA:
    
    147
    -            return os.path.join(self.data_root, path)
    
    143
    +            return self.data_root / path
    
    148 144
             return path
    
    149 145
     
    
    150 146
         def items(self) -> Generator[Tuple[str, PathTuple], None, None]:
    
    151 147
             for key, value in self._paths.items():
    
    152 148
                 yield (key, value)
    
    153 149
     
    
    154
    -    def _prepare(self, path: str, unique: bool) -> str:
    
    150
    +    def _prepare(self, path: Path, unique: bool) -> Path:
    
    155 151
             if os.name == 'nt':
    
    156
    -            path = path.capitalize()
    
    152
    +            path = Path(str(path).capitalize())
    
    157 153
             if self.profile:
    
    158 154
                 if unique or self.profile_separation:
    
    159
    -                return '%s.%s' % (path, self.profile)
    
    155
    +                return Path(f'{path}.{self.profile}')
    
    160 156
             return path
    
    161 157
     
    
    162 158
         def add(self,
    
    163 159
                 name: str,
    
    164
    -            path: str,
    
    160
    +            path: Path,
    
    165 161
                 location: PathLocation = None,
    
    166 162
                 path_type: PathType = None,
    
    167 163
                 unique: bool = False) -> None:
    
    168
    -        if path and location is not None:
    
    164
    +        if location is not None:
    
    169 165
                 path = self._prepare(path, unique)
    
    170 166
             self._paths[name] = (location, path, path_type)
    
    171 167
     
    
    ... ... @@ -175,10 +171,10 @@ def init(self):
    175 171
                 self.cache_root = self.data_root = self.custom_config_root
    
    176 172
     
    
    177 173
             user_dir_paths = [
    
    178
    -            ('TMP', tempfile.gettempdir()),
    
    179
    -            ('MY_CONFIG', '', PathLocation.CONFIG, PathType.FOLDER),
    
    180
    -            ('MY_CACHE', '', PathLocation.CACHE, PathType.FOLDER),
    
    181
    -            ('MY_DATA', '', PathLocation.DATA, PathType.FOLDER),
    
    174
    +            ('TMP', Path(tempfile.gettempdir())),
    
    175
    +            ('MY_CONFIG', Path(), PathLocation.CONFIG, PathType.FOLDER),
    
    176
    +            ('MY_CACHE', Path(), PathLocation.CACHE, PathType.FOLDER),
    
    177
    +            ('MY_DATA', Path(), PathLocation.DATA, PathType.FOLDER),
    
    182 178
             ]
    
    183 179
     
    
    184 180
             for path in user_dir_paths:
    

  • gajim/common/helpers.py
    ... ... @@ -51,6 +51,7 @@
    51 51
     from urllib.parse import unquote
    
    52 52
     from encodings.punycode import punycode_encode
    
    53 53
     from functools import wraps
    
    54
    +from pathlib import Path
    
    54 55
     from packaging.version import Version as V
    
    55 56
     
    
    56 57
     from nbxmpp.namespaces import Namespace
    
    ... ... @@ -447,18 +448,18 @@ def check_soundfile_path(file_, dirs=None):
    447 448
                                          (eg: ~/.gajim/sounds/, DATADIR/sounds...).
    
    448 449
         :return      the path to file or None if it doesn't exists.
    
    449 450
         """
    
    451
    +    if not file_:
    
    452
    +        return None
    
    453
    +    if Path(file_).exists():
    
    454
    +        return Path(file_)
    
    455
    +
    
    450 456
         if dirs is None:
    
    451 457
             dirs = [configpaths.get('MY_DATA'),
    
    452 458
                     configpaths.get('DATA')]
    
    453 459
     
    
    454
    -    if not file_:
    
    455
    -        return None
    
    456
    -    if os.path.exists(file_):
    
    457
    -        return file_
    
    458
    -
    
    459 460
         for dir_ in dirs:
    
    460
    -        dir_ = os.path.join(dir_, 'sounds', file_)
    
    461
    -        if os.path.exists(dir_):
    
    461
    +        dir_ = dir_ / 'sounds' / file_
    
    462
    +        if dir_.exists():
    
    462 463
                 return dir_
    
    463 464
         return None
    
    464 465
     
    
    ... ... @@ -482,11 +483,12 @@ def strip_soundfile_path(file_, dirs=None, abs_=True):
    482 483
             dirs = [configpaths.get('MY_DATA'),
    
    483 484
                     configpaths.get('DATA')]
    
    484 485
     
    
    485
    -    name = os.path.basename(file_)
    
    486
    +    file_ = Path(file_)
    
    487
    +    name = file_.name
    
    486 488
         for dir_ in dirs:
    
    487
    -        dir_ = os.path.join(dir_, 'sounds', name)
    
    489
    +        dir_ = dir_ / 'sounds' / name
    
    488 490
             if abs_:
    
    489
    -            dir_ = os.path.abspath(dir_)
    
    491
    +            dir_ = dir_.absolute()
    
    490 492
             if file_ == dir_:
    
    491 493
                 return name
    
    492 494
         return file_
    
    ... ... @@ -496,6 +498,7 @@ def play_sound_file(path_to_soundfile):
    496 498
         if path_to_soundfile is None:
    
    497 499
             return
    
    498 500
     
    
    501
    +    path_to_soundfile = str(path_to_soundfile)
    
    499 502
         if sys.platform == 'win32':
    
    500 503
             import winsound
    
    501 504
             try:
    
    ... ... @@ -854,25 +857,19 @@ def version_condition(current_version, required_version):
    854 857
         return True
    
    855 858
     
    
    856 859
     def get_available_emoticon_themes():
    
    857
    -    emoticons_themes = ['font']
    
    858 860
         files = []
    
    859
    -    dir_iterator = os.scandir(configpaths.get('EMOTICONS'))
    
    860
    -    for folder in dir_iterator:
    
    861
    +    for folder in configpaths.get('EMOTICONS').iterdir():
    
    861 862
             if not folder.is_dir():
    
    862 863
                 continue
    
    863
    -        file_iterator = os.scandir(folder.path)
    
    864
    -        for theme in file_iterator:
    
    865
    -            if theme.is_file():
    
    866
    -                files.append(theme.name)
    
    867
    -
    
    868
    -    if os.path.isdir(configpaths.get('MY_EMOTS')):
    
    869
    -        files += os.listdir(configpaths.get('MY_EMOTS'))
    
    870
    -
    
    871
    -    for file in files:
    
    872
    -        if file.endswith('.png'):
    
    873
    -            emoticons_themes.append(file[:-4])
    
    874
    -    emoticons_themes.sort()
    
    875
    -    return emoticons_themes
    
    864
    +        files += [theme for theme in folder.iterdir() if theme.is_file()]
    
    865
    +
    
    866
    +    my_emots = configpaths.get('MY_EMOTS')
    
    867
    +    if my_emots.is_dir():
    
    868
    +        files += list(my_emots.iterdir())
    
    869
    +
    
    870
    +    emoticons_themes = ['font']
    
    871
    +    emoticons_themes += [file.stem for file in files if file.suffix == '.png']
    
    872
    +    return sorted(emoticons_themes)
    
    876 873
     
    
    877 874
     def call_counter(func):
    
    878 875
         def helper(self, restart=False):
    

  • gajim/common/jingle_content.py
    ... ... @@ -19,8 +19,6 @@
    19 19
     from typing import Any  # pylint: disable=unused-import
    
    20 20
     from typing import Dict  # pylint: disable=unused-import
    
    21 21
     
    
    22
    -import os
    
    23
    -
    
    24 22
     import nbxmpp
    
    25 23
     from nbxmpp.namespaces import Namespace
    
    26 24
     
    
    ... ... @@ -227,8 +225,8 @@ def _fill_content(self, content):
    227 225
             if self.use_security:
    
    228 226
                 security = nbxmpp.simplexml.Node(
    
    229 227
                     tag=Namespace.JINGLE_XTLS + ' security')
    
    230
    -            certpath = os.path.join(
    
    231
    -                configpaths.get('MY_CERT'), SELF_SIGNED_CERTIFICATE) + '.cert'
    
    228
    +            certpath = configpaths.get('MY_CERT') / (SELF_SIGNED_CERTIFICATE
    
    229
    +                                                     + '.cert')
    
    232 230
                 cert = load_cert_file(certpath)
    
    233 231
                 if cert:
    
    234 232
                     digest_algo = (cert.get_signature_algorithm()
    

  • gajim/common/jingle_ft.py
    ... ... @@ -18,7 +18,6 @@
    18 18
     
    
    19 19
     import hashlib
    
    20 20
     import logging
    
    21
    -import os
    
    22 21
     import threading
    
    23 22
     from enum import IntEnum, unique
    
    24 23
     
    
    ... ... @@ -119,10 +118,10 @@ def __init__(self, session, transport=None, file_props=None,
    119 118
                 State.CAND_SENT_AND_RECEIVED : StateCandSentAndRecv(self)
    
    120 119
             }
    
    121 120
     
    
    122
    -        cert_name = os.path.join(configpaths.get('MY_CERT'),
    
    123
    -                                 jingle_xtls.SELF_SIGNED_CERTIFICATE)
    
    124
    -        if not (os.path.exists(cert_name + '.cert')
    
    125
    -                and os.path.exists(cert_name + '.pkey')):
    
    121
    +        cert_name = (configpaths.get('MY_CERT') /
    
    122
    +                     jingle_xtls.SELF_SIGNED_CERTIFICATE)
    
    123
    +        if not (cert_name.with_suffix('.cert').exists()
    
    124
    +                and cert_name.with_suffix('.pkey').exists()):
    
    126 125
                 jingle_xtls.make_certs(cert_name, 'gajim')
    
    127 126
     
    
    128 127
         def __state_changed(self, nextstate, args=None):
    

  • gajim/common/jingle_xtls.py
    ... ... @@ -13,7 +13,7 @@
    13 13
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14 14
     
    
    15 15
     import logging
    
    16
    -import os
    
    16
    +from pathlib import Path
    
    17 17
     
    
    18 18
     from OpenSSL import SSL, crypto
    
    19 19
     
    
    ... ... @@ -52,7 +52,7 @@ def load_cert_file(cert_path, cert_store=None):
    52 52
         """
    
    53 53
         This is almost identical to the one in nbxmpp.tls_nb
    
    54 54
         """
    
    55
    -    if not os.path.isfile(cert_path):
    
    55
    +    if not cert_path.is_file():
    
    56 56
             return None
    
    57 57
         try:
    
    58 58
             f = open(cert_path)
    
    ... ... @@ -100,22 +100,22 @@ def get_context(fingerprint, verify_cb=None, remote_jid=None):
    100 100
         elif fingerprint == 'client':
    
    101 101
             ctx.set_verify(SSL.VERIFY_PEER, verify_cb or default_callback)
    
    102 102
     
    
    103
    -    cert_name = os.path.join(configpaths.get('MY_CERT'), SELF_SIGNED_CERTIFICATE)
    
    104
    -    ctx.use_privatekey_file((cert_name + '.pkey').encode('utf-8'))
    
    105
    -    ctx.use_certificate_file((cert_name + '.cert').encode('utf-8'))
    
    103
    +    cert_name = configpaths.get('MY_CERT') / SELF_SIGNED_CERTIFICATE
    
    104
    +    ctx.use_privatekey_file(str(cert_name.with_suffix('.pkey')).encode('utf-8'))
    
    105
    +    ctx.use_certificate_file(str(cert_name.with_suffix('.cert')).encode('utf-8'))
    
    106 106
     
    
    107 107
         # Try to load Diffie-Hellman parameters.
    
    108 108
         # First try user DH parameters, if this fails load the default DH parameters
    
    109
    -    dh_params_name = os.path.join(configpaths.get('MY_CERT'), DH_PARAMS)
    
    109
    +    dh_params_name = configpaths.get('MY_CERT') / DH_PARAMS
    
    110 110
         try:
    
    111 111
             with open(dh_params_name, "r"):
    
    112 112
                 ctx.load_tmp_dh(dh_params_name.encode('utf-8'))
    
    113 113
         except FileNotFoundError as err:
    
    114
    -        default_dh_params_name = os.path.join(configpaths.get('DATA'),
    
    115
    -                                              'other', DEFAULT_DH_PARAMS)
    
    114
    +        default_dh_params_name = (configpaths.get('DATA') / 'other' /
    
    115
    +                                  DEFAULT_DH_PARAMS)
    
    116 116
             try:
    
    117 117
                 with open(default_dh_params_name, "r"):
    
    118
    -                ctx.load_tmp_dh(default_dh_params_name.encode('utf-8'))
    
    118
    +                ctx.load_tmp_dh(str(default_dh_params_name).encode('utf-8'))
    
    119 119
             except FileNotFoundError as err:
    
    120 120
                 log.error('Unable to load default DH parameter file: %s, %s',
    
    121 121
                           default_dh_params_name, err)
    
    ... ... @@ -123,9 +123,9 @@ def get_context(fingerprint, verify_cb=None, remote_jid=None):
    123 123
     
    
    124 124
         if remote_jid:
    
    125 125
             store = ctx.get_cert_store()
    
    126
    -        path = os.path.join(os.path.expanduser(configpaths.get('MY_PEER_CERTS')),
    
    127
    -                            remote_jid) + '.cert'
    
    128
    -        if os.path.exists(path):
    
    126
    +        path = configpaths.get('MY_PEER_CERTS').expanduser() / (remote_jid
    
    127
    +                                                                + '.cert')
    
    128
    +        if path.exists():
    
    129 129
                 load_cert_file(path, cert_store=store)
    
    130 130
                 log.debug('certificate file %s loaded fingerprint %s',
    
    131 131
                           path, fingerprint)
    
    ... ... @@ -140,8 +140,8 @@ def read_cert(certpath):
    140 140
         return certificate
    
    141 141
     
    
    142 142
     def send_cert(con, jid_from, sid):
    
    143
    -    certpath = os.path.join(configpaths.get('MY_CERT'), SELF_SIGNED_CERTIFICATE) + \
    
    144
    -        '.cert'
    
    143
    +    certpath = configpaths.get('MY_CERT') / (SELF_SIGNED_CERTIFICATE
    
    144
    +                                             + '.cert')
    
    145 145
         certificate = read_cert(certpath)
    
    146 146
         iq = nbxmpp.Iq('result', to=jid_from)
    
    147 147
         iq.setAttr('id', sid)
    
    ... ... @@ -159,8 +159,7 @@ def send_cert(con, jid_from, sid):
    159 159
     
    
    160 160
     def handle_new_cert(con, obj, jid_from):
    
    161 161
         jid = app.get_jid_without_resource(jid_from)
    
    162
    -    certpath = os.path.join(os.path.expanduser(configpaths.get('MY_PEER_CERTS')), jid)
    
    163
    -    certpath += '.cert'
    
    162
    +    certpath = configpaths.get('MY_PEER_CERTS').expanduser() / (jid + '.cert')
    
    164 163
     
    
    165 164
         id_ = obj.getAttr('id')
    
    166 165
     
    
    ... ... @@ -177,9 +176,8 @@ def handle_new_cert(con, obj, jid_from):
    177 176
         approve_pending_content(id_)
    
    178 177
     
    
    179 178
     def check_cert(jid, fingerprint):
    
    180
    -    certpath = os.path.join(os.path.expanduser(configpaths.get('MY_PEER_CERTS')), jid)
    
    181
    -    certpath += '.cert'
    
    182
    -    if os.path.exists(certpath):
    
    179
    +    certpath = configpaths.get('MY_PEER_CERTS').expanduser() / (jid + '.cert')
    
    180
    +    if certpath.exists():
    
    183 181
             cert = load_cert_file(certpath)
    
    184 182
             if cert:
    
    185 183
                 digest_algo = cert.get_signature_algorithm().decode('utf-8')\
    
    ... ... @@ -273,12 +271,12 @@ def make_certs(filepath, CN):
    273 271
         key = createKeyPair(TYPE_RSA, 4096)
    
    274 272
         req = createCertRequest(key, CN=CN)
    
    275 273
         cert = createCertificate(req, req, key, 0, 0, 60*60*24*365*5) # five years
    
    276
    -    with open(filepath + '.pkey', 'wb') as f:
    
    277
    -        os.chmod(filepath + '.pkey', 0o600)
    
    274
    +    with open(filepath.with_suffix('.pkey'), 'wb') as f:
    
    275
    +        filepath.with_suffix('.pkey').chmod(0o600)
    
    278 276
             f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
    
    279
    -    with open(filepath + '.cert', 'wb') as f:
    
    277
    +    with open(filepath.with_suffix('.cert'), 'wb') as f:
    
    280 278
             f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
    
    281 279
     
    
    282 280
     
    
    283 281
     if __name__ == '__main__':
    
    284
    -    make_certs('./selfcert', 'gajim')
    282
    +    make_certs(Path('selfcert'), 'gajim')

  • gajim/common/modules/bits_of_binary.py
    ... ... @@ -17,7 +17,6 @@
    17 17
     import logging
    
    18 18
     import hashlib
    
    19 19
     from base64 import b64decode
    
    20
    -from pathlib import Path
    
    21 20
     
    
    22 21
     import nbxmpp
    
    23 22
     from nbxmpp.namespaces import Namespace
    
    ... ... @@ -133,7 +132,7 @@ def parse_bob_data(stanza):
    133 132
             log.warning('No data found: %s', stanza)
    
    134 133
             return None
    
    135 134
     
    
    136
    -    filepath = Path(configpaths.get('BOB')) / algo_hash
    
    135
    +    filepath = configpaths.get('BOB') / algo_hash
    
    137 136
         if algo_hash in app.bob_cache or filepath.exists():
    
    138 137
             log.info('BoB data already cached')
    
    139 138
             return None
    
    ... ... @@ -182,7 +181,7 @@ def store_bob_data(bob_data):
    182 181
     
    
    183 182
         algo_hash = '%s+%s' % (bob_data.algo, bob_data.hash_)
    
    184 183
     
    
    185
    -    filepath = Path(configpaths.get('BOB')) / algo_hash
    
    184
    +    filepath = configpaths.get('BOB') / algo_hash
    
    186 185
         if algo_hash in app.bob_cache or filepath.exists():
    
    187 186
             log.info('BoB data already cached')
    
    188 187
             return None
    

  • gajim/common/settings.py
    ... ... @@ -170,7 +170,7 @@ def _namedtuple_factory(cursor: Any, row: Any) -> Any:
    170 170
             return namedtuple("Row", fields)(*row)
    
    171 171
     
    
    172 172
         def _connect_database(self) -> None:
    
    173
    -        path = Path(configpaths.get('SETTINGS'))
    
    173
    +        path = configpaths.get('SETTINGS')
    
    174 174
             if path.is_dir():
    
    175 175
                 log.error('%s is a directory but should be a file', path)
    
    176 176
                 sys.exit()
    
    ... ... @@ -237,7 +237,7 @@ def _migrate(self) -> None:
    237 237
             pass
    
    238 238
     
    
    239 239
         def _migrate_old_config(self) -> None:
    
    240
    -        config_file = Path(configpaths.get('CONFIG_FILE'))
    
    240
    +        config_file = configpaths.get('CONFIG_FILE')
    
    241 241
             if not config_file.exists():
    
    242 242
                 return
    
    243 243
     
    

  • gajim/common/storage/archive.py
    ... ... @@ -27,7 +27,6 @@
    27 27
     import json
    
    28 28
     import logging
    
    29 29
     import sqlite3 as sqlite
    
    30
    -from pathlib import Path
    
    31 30
     from collections import namedtuple
    
    32 31
     
    
    33 32
     from gajim.common import app
    
    ... ... @@ -93,7 +92,7 @@ class MessageArchiveStorage(SqliteStorage):
    93 92
         def __init__(self):
    
    94 93
             SqliteStorage.__init__(self,
    
    95 94
                                    log,
    
    96
    -                               Path(configpaths.get('LOG_DB')),
    
    95
    +                               configpaths.get('LOG_DB'),
    
    97 96
                                    ARCHIVE_SQL_STATEMENT)
    
    98 97
     
    
    99 98
             self._jid_ids = {}
    

  • gajim/common/storage/cache.py
    ... ... @@ -16,7 +16,6 @@
    16 16
     import time
    
    17 17
     import sqlite3
    
    18 18
     import logging
    
    19
    -from pathlib import Path
    
    20 19
     from collections import namedtuple
    
    21 20
     
    
    22 21
     from gajim.common import configpaths
    
    ... ... @@ -56,7 +55,7 @@ class CacheStorage(SqliteStorage):
    56 55
         def __init__(self):
    
    57 56
             SqliteStorage.__init__(self,
    
    58 57
                                    log,
    
    59
    -                               Path(configpaths.get('CACHE_DB')),
    
    58
    +                               configpaths.get('CACHE_DB'),
    
    60 59
                                    CACHE_SQL_STATEMENT)
    
    61 60
     
    
    62 61
             self._entity_caps_cache = {}
    

  • gajim/common/types.py
    ... ... @@ -22,6 +22,7 @@
    22 22
     from typing import Union
    
    23 23
     from typing import TYPE_CHECKING
    
    24 24
     
    
    25
    +from pathlib import Path
    
    25 26
     import nbxmpp
    
    26 27
     
    
    27 28
     from gajim.common.const import PathType, PathLocation
    
    ... ... @@ -53,7 +54,7 @@
    53 54
     PEPHandlersDict = Dict[str, List[PEPNotifyCallback]]
    
    54 55
     
    
    55 56
     # Configpaths
    
    56
    -PathTuple = Tuple[Optional[PathLocation], str, Optional[PathType]]
    
    57
    +PathTuple = Tuple[Optional[PathLocation], Path, Optional[PathType]]
    
    57 58
     
    
    58 59
     # Plugins
    
    59 60
     PluginExtensionPoints = Dict[str, Tuple[Optional[Callable[..., None]],
    

  • gajim/gtk/account_wizard.py
    ... ... @@ -13,7 +13,6 @@
    13 13
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14 14
     
    
    15 15
     import logging
    
    16
    -from pathlib import Path
    
    17 16
     
    
    18 17
     from gi.repository import Gdk
    
    19 18
     from gi.repository import GLib
    
    ... ... @@ -559,7 +558,7 @@ def _on_signup(self, *args):
    559 558
     
    
    560 559
         def _create_server_completion(self):
    
    561 560
             # Parse servers.json
    
    562
    -        file_path = Path(configpaths.get('DATA')) / 'other' / 'servers.json'
    
    561
    +        file_path = configpaths.get('DATA') / 'other' / 'servers.json'
    
    563 562
             self._servers = helpers.load_json(file_path, 'servers', [])
    
    564 563
     
    
    565 564
             # Create a separate model for the address entry, because it will
    
    ... ... @@ -658,7 +657,7 @@ def focus(self):
    658 657
     
    
    659 658
         def _create_server_completion(self):
    
    660 659
             # Parse servers.json
    
    661
    -        file_path = Path(configpaths.get('DATA')) / 'other' / 'servers.json'
    
    660
    +        file_path = configpaths.get('DATA') / 'other' / 'servers.json'
    
    662 661
             servers = helpers.load_json(file_path, 'servers', [])
    
    663 662
     
    
    664 663
             # Create servers_model for comboboxes and entries
    

  • gajim/gtk/avatar.py
    ... ... @@ -12,7 +12,6 @@
    12 12
     # You should have received a copy of the GNU General Public License
    
    13 13
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14 14
     
    
    15
    -import os
    
    16 15
     import logging
    
    17 16
     import hashlib
    
    18 17
     from math import pi
    
    ... ... @@ -295,7 +294,7 @@ def save_avatar(data):
    295 294
                 return None
    
    296 295
     
    
    297 296
             sha = hashlib.sha1(data).hexdigest()
    
    298
    -        path = os.path.join(configpaths.get('AVATAR'), sha)
    
    297
    +        path = configpaths.get('AVATAR') / sha
    
    299 298
             try:
    
    300 299
                 with open(path, 'wb') as output_file:
    
    301 300
                     output_file.write(data)
    
    ... ... @@ -306,8 +305,8 @@ def save_avatar(data):
    306 305
     
    
    307 306
         @staticmethod
    
    308 307
         def get_avatar_path(filename):
    
    309
    -        path = os.path.join(configpaths.get('AVATAR'), filename)
    
    310
    -        if not os.path.isfile(path):
    
    308
    +        path = configpaths.get('AVATAR') / filename
    
    309
    +        if not path.is_file():
    
    311 310
                 return None
    
    312 311
             return path
    
    313 312
     
    

  • gajim/gtk/css_config.py
    ... ... @@ -17,7 +17,6 @@
    17 17
     
    
    18 18
     import math
    
    19 19
     import logging
    
    20
    -from pathlib import Path
    
    21 20
     
    
    22 21
     from gi.repository import Gtk
    
    23 22
     from gi.repository import Gdk
    
    ... ... @@ -148,7 +147,7 @@ def _load_css(self):
    148 147
                                          CSSPriority.DEFAULT_THEME_DARK)
    
    149 148
     
    
    150 149
         def _load_css_from_file(self, filename, priority):
    
    151
    -        path = Path(configpaths.get('STYLE')) / filename
    
    150
    +        path = configpaths.get('STYLE') / filename
    
    152 151
             try:
    
    153 152
                 with open(path, "r") as file_:
    
    154 153
                     css = file_.read()
    
    ... ... @@ -180,7 +179,7 @@ def _pango_to_css_weight(number):
    180 179
             return int(math.ceil(number / 100.0)) * 100
    
    181 180
     
    
    182 181
         def _gather_available_themes(self):
    
    183
    -        files = Path(configpaths.get('MY_THEME')).iterdir()
    
    182
    +        files = configpaths.get('MY_THEME').iterdir()
    
    184 183
             self.themes = [file.stem for file in files if file.suffix == '.css']
    
    185 184
             if 'default' in self.themes:
    
    186 185
                 # Ignore user created themes that are named 'default'
    
    ... ... @@ -191,8 +190,8 @@ def get_theme_path(self, theme, user=True):
    191 190
                 theme = 'default-dark'
    
    192 191
     
    
    193 192
             if user:
    
    194
    -            return Path(configpaths.get('MY_THEME')) / f'{theme}.css'
    
    195
    -        return Path(configpaths.get('STYLE')) / f'{theme}.css'
    
    193
    +            return configpaths.get('MY_THEME') / f'{theme}.css'
    
    194
    +        return configpaths.get('STYLE') / f'{theme}.css'
    
    196 195
     
    
    197 196
         def _determine_theme_path(self):
    
    198 197
             # Gets the path of the currently active theme.
    

  • gajim/gtk/emoji_chooser.py
    ... ... @@ -14,7 +14,6 @@
    14 14
     
    
    15 15
     import logging
    
    16 16
     import weakref
    
    17
    -from pathlib import Path
    
    18 17
     from collections import OrderedDict
    
    19 18
     
    
    20 19
     from gi.repository import Gtk
    
    ... ... @@ -312,12 +311,12 @@ def _get_emoji_theme_path(theme):
    312 311
             if theme == 'font':
    
    313 312
                 return 'font'
    
    314 313
     
    
    315
    -        base_path = Path(configpaths.get('EMOTICONS'))
    
    314
    +        base_path = configpaths.get('EMOTICONS')
    
    316 315
             emoticons_data_path = base_path / theme / f'{theme}.png'
    
    317 316
             if emoticons_data_path.exists():
    
    318 317
                 return emoticons_data_path
    
    319 318
     
    
    320
    -        emoticons_user_path = Path(configpaths.get('MY_EMOTS')) / f'{theme}.png'
    
    319
    +        emoticons_user_path = configpaths.get('MY_EMOTS') / f'{theme}.png'
    
    321 320
             if emoticons_user_path.exists():
    
    322 321
                 return emoticons_user_path
    
    323 322
     
    

  • gajim/gtk/exception.py
    ... ... @@ -23,7 +23,6 @@
    23 23
     import threading
    
    24 24
     import webbrowser
    
    25 25
     import platform
    
    26
    -from pathlib import Path
    
    27 26
     from io import StringIO
    
    28 27
     from urllib.parse import urlencode
    
    29 28
     
    
    ... ... @@ -69,7 +68,7 @@ def _hook(type_, value, tb):
    69 68
     
    
    70 69
     class ExceptionDialog():
    
    71 70
         def __init__(self, type_, value, tb):
    
    72
    -        path = Path(configpaths.get('GUI')) / 'exception_dialog.ui'
    
    71
    +        path = configpaths.get('GUI') / 'exception_dialog.ui'
    
    73 72
             self._ui = get_builder(path.resolve())
    
    74 73
             self._ui.connect_signals(self)
    
    75 74
     
    

  • gajim/gtk/manage_sounds.py
    ... ... @@ -107,7 +107,7 @@ def _on_cursor_changed(self, treeview):
    107 107
             if path_to_snd_file is None:
    
    108 108
                 self._ui.filechooser.unselect_all()
    
    109 109
             else:
    
    110
    -            self._ui.filechooser.set_filename(path_to_snd_file)
    
    110
    +            self._ui.filechooser.set_filename(str(path_to_snd_file))
    
    111 111
     
    
    112 112
         def _on_file_set(self, button):
    
    113 113
             model, iter_ = self._ui.sounds_treeview.get_selection().get_selected()
    
    ... ... @@ -118,7 +118,7 @@ def _on_file_set(self, button):
    118 118
             path_to_snd_file = strip_soundfile_path(filename)
    
    119 119
     
    
    120 120
             # set new path to sounds_model
    
    121
    -        model[iter_][2] = path_to_snd_file
    
    121
    +        model[iter_][2] = str(path_to_snd_file)
    
    122 122
             # set the sound to enabled
    
    123 123
             model[iter_][0] = True
    
    124 124
     
    

  • gajim/gtk/util.py
    ... ... @@ -28,7 +28,6 @@
    28 28
     import functools
    
    29 29
     from importlib import import_module
    
    30 30
     import xml.etree.ElementTree as ET
    
    31
    -from pathlib import Path
    
    32 31
     from functools import wraps
    
    33 32
     from functools import lru_cache
    
    34 33
     
    
    ... ... @@ -177,7 +176,7 @@ def __init__(self,
    177 176
         @staticmethod
    
    178 177
         @functools.lru_cache(maxsize=None)
    
    179 178
         def _load_string_from_filename(filename, gettext_):
    
    180
    -        file_path = str(Path(configpaths.get('GUI')) / filename)
    
    179
    +        file_path = str(configpaths.get('GUI') / filename)
    
    181 180
     
    
    182 181
             if sys.platform == "win32":
    
    183 182
                 # This is a workaround for non working translation on Windows
    
    ... ... @@ -266,7 +265,7 @@ def get_icon_name(name: str,
    266 265
     
    
    267 266
     
    
    268 267
     def load_user_iconsets():
    
    269
    -    iconsets_path = Path(configpaths.get('MY_ICONSETS'))
    
    268
    +    iconsets_path = configpaths.get('MY_ICONSETS')
    
    270 269
         if not iconsets_path.exists():
    
    271 270
             return
    
    272 271
     
    
    ... ... @@ -282,7 +281,7 @@ def get_available_iconsets():
    282 281
         for iconset in GajimIconSet:
    
    283 282
             iconsets.append(iconset.value)
    
    284 283
     
    
    285
    -    iconsets_path = Path(configpaths.get('MY_ICONSETS'))
    
    284
    +    iconsets_path = configpaths.get('MY_ICONSETS')
    
    286 285
         if not iconsets_path.exists():
    
    287 286
             return iconsets
    
    288 287
     
    

  • gajim/history_manager.py
    ... ... @@ -30,7 +30,6 @@
    30 30
     import time
    
    31 31
     import getopt
    
    32 32
     import sqlite3
    
    33
    -from pathlib import Path
    
    34 33
     from enum import IntEnum, unique
    
    35 34
     
    
    36 35
     import gi
    
    ... ... @@ -109,7 +108,7 @@ class Column(IntEnum):
    109 108
     
    
    110 109
     class HistoryManager:
    
    111 110
         def __init__(self):
    
    112
    -        log_db_path = Path(configpaths.get('LOG_DB'))
    
    111
    +        log_db_path = configpaths.get('LOG_DB')
    
    113 112
             if not log_db_path.exists():
    
    114 113
                 ErrorDialog(_('Cannot find history logs database'),
    
    115 114
                             _('%s does not exist.') % log_db_path)
    

  • gajim/plugins/gajimplugin.py
    ... ... @@ -210,8 +210,8 @@ def deactivate(self):
    210 210
     class GajimPluginConfig():
    
    211 211
         def __init__(self, plugin):
    
    212 212
             self.plugin = plugin
    
    213
    -        self.FILE_PATH = os.path.join(
    
    214
    -            configpaths.get('PLUGINS_CONFIG_DIR'), self.plugin.short_name)
    
    213
    +        self.FILE_PATH = (configpaths.get('PLUGINS_CONFIG_DIR') /
    
    214
    +                          self.plugin.short_name)
    
    215 215
             self.data = {}
    
    216 216
     
    
    217 217
         def __getitem__(self, key):
    
    ... ... @@ -243,18 +243,18 @@ def items(self):
    243 243
             return self.data.items()
    
    244 244
     
    
    245 245
         def save(self):
    
    246
    -        fd = open(self.FILE_PATH, 'wb')
    
    247
    -        pickle.dump(self.data, fd)
    
    248
    -        fd.close()
    
    246
    +        with open(self.FILE_PATH, 'wb') as fd:
    
    247
    +            pickle.dump(self.data, fd)
    
    249 248
     
    
    250 249
         def load(self):
    
    251
    -        if os.path.isfile(self.FILE_PATH):
    
    252
    -            fd = open(self.FILE_PATH, 'rb')
    
    250
    +        if not self.FILE_PATH.is_file():
    
    251
    +            self.data = {}
    
    252
    +            self.save()
    
    253
    +            return
    
    254
    +        with open(self.FILE_PATH, 'rb') as fd:
    
    253 255
                 try:
    
    254 256
                     self.data = pickle.load(fd)
    
    255
    -                fd.close()
    
    256 257
                 except Exception:
    
    257
    -                fd.close()
    
    258 258
                     try:
    
    259 259
                         import shelve
    
    260 260
                         s = shelve.open(self.FILE_PATH)
    
    ... ... @@ -276,9 +276,6 @@ def load(self):
    276 276
                         os.rename(self.FILE_PATH, self.FILE_PATH + '.bak')
    
    277 277
                         self.data = {}
    
    278 278
                         self.save()
    
    279
    -        else:
    
    280
    -            self.data = {}
    
    281
    -            self.save()
    
    282 279
     
    
    283 280
     
    
    284 281
     class GajimPluginException(Exception):
    

  • gajim/plugins/helpers.py
    ... ... @@ -27,7 +27,6 @@
    27 27
     
    
    28 28
     import logging
    
    29 29
     import functools
    
    30
    -from pathlib import Path
    
    31 30
     
    
    32 31
     from gajim.common import configpaths
    
    33 32
     from gajim.plugins import plugins_i18n
    
    ... ... @@ -126,8 +125,8 @@ def get_builder(file_name: str, widgets: List[str] = None) -> Builder:
    126 125
     
    
    127 126
     
    
    128 127
     def is_shipped_plugin(path):
    
    129
    -    base = Path(configpaths.get('PLUGINS_BASE'))
    
    128
    +    base = configpaths.get('PLUGINS_BASE')
    
    130 129
         if not base.exists():
    
    131 130
             return False
    
    132
    -    plugin_parent = Path(path).parent
    
    131
    +    plugin_parent = path.parent
    
    133 132
         return base.samefile(plugin_parent)

  • gajim/plugins/pluginmanager.py
    ... ... @@ -241,10 +241,10 @@ def update_plugins(self, replace=True, activate=False, plugin_name=None):
    241 241
             dl_dir = configpaths.get('PLUGINS_DOWNLOAD')
    
    242 242
             to_update = [plugin_name] if plugin_name else next(os.walk(dl_dir))[1]
    
    243 243
             for directory in to_update:
    
    244
    -            src_dir = os.path.join(dl_dir, directory)
    
    245
    -            dst_dir = os.path.join(user_dir, directory)
    
    244
    +            src_dir = dl_dir / directory
    
    245
    +            dst_dir = user_dir / directory
    
    246 246
                 try:
    
    247
    -                if os.path.exists(dst_dir):
    
    247
    +                if dst_dir.exists():
    
    248 248
                         if not replace:
    
    249 249
                             continue
    
    250 250
                         self.delete_plugin_files(dst_dir)
    
    ... ... @@ -701,7 +701,7 @@ def install_from_zip(self, zip_filename, overwrite=None):
    701 701
                 raise PluginsystemError(_('Archive is malformed'))
    
    702 702
     
    
    703 703
             plugin_name = dirs[0]
    
    704
    -        user_dir = Path(configpaths.get('PLUGINS_USER'))
    
    704
    +        user_dir = configpaths.get('PLUGINS_USER')
    
    705 705
             plugin_path = user_dir / plugin_name
    
    706 706
     
    
    707 707
             if plugin_path.exists():
    
    ... ... @@ -742,7 +742,7 @@ def uninstall_plugin(self, plugin):
    742 742
             self.remove_plugin(plugin)
    
    743 743
             self.delete_plugin_files(plugin.__path__)
    
    744 744
             if not is_shipped_plugin(Path(plugin.__path__)):
    
    745
    -            path = Path(configpaths.get('PLUGINS_BASE')) / plugin.short_name
    
    745
    +            path = configpaths.get('PLUGINS_BASE') / plugin.short_name
    
    746 746
                 if path.exists():
    
    747 747
                     self.delete_plugin_files(str(path))
    
    748 748
     
    

  • gajim/plugins/plugins_i18n.py
    ... ... @@ -22,7 +22,7 @@
    22 22
     
    
    23 23
     DOMAIN = 'gajim_plugins'
    
    24 24
     try:
    
    25
    -    plugin_user_dir = Path(configpaths.get('PLUGINS_USER'))
    
    25
    +    plugin_user_dir = configpaths.get('PLUGINS_USER')
    
    26 26
     except KeyError:
    
    27 27
         # This allows to import the module for tests
    
    28 28
         print('No plugin translation path available')
    

  • gajim/vcard.py
    ... ... @@ -25,7 +25,6 @@
    25 25
     # You should have received a copy of the GNU General Public License
    
    26 26
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    27 27
     
    
    28
    -import os
    
    29 28
     import logging
    
    30 29
     
    
    31 30
     from gi.repository import Gtk
    
    ... ... @@ -89,11 +88,11 @@ def __init__(self, contact, account, gc_contact=None):
    89 88
                 self.real_resource = contact.resource
    
    90 89
     
    
    91 90
             puny_jid = helpers.sanitize_filename(contact.jid)
    
    92
    -        local_avatar_basepath = os.path.join(configpaths.get('AVATAR'), puny_jid) + \
    
    93
    -                '_local'
    
    91
    +        local_avatar_basepath = configpaths.get('AVATAR') / (puny_jid +
    
    92
    +                                                             '_local')
    
    94 93
             for extension in ('.png', '.jpeg'):
    
    95
    -            local_avatar_path = local_avatar_basepath + extension
    
    96
    -            if os.path.isfile(local_avatar_path):
    
    94
    +            local_avatar_path = local_avatar_basepath.with_suffix(extension)
    
    95
    +            if local_avatar_path.is_file():
    
    97 96
                     image = self.xml.get_object('custom_avatar_image')
    
    98 97
                     image.set_from_file(local_avatar_path)
    
    99 98
                     image.show()