[Common] Replace pkg_resources with importlib for resource path finding

With an existing Deluge package installed on the system errors were
occuring trying to start a development instance in virtualenv.

Fixed by replacing usage of deprecated pkg_resource for finding
non-python data files. Includes fallback for Python 3.7/3.8 but drops
Python 3.6 support.

The plugins are still using pkg_resources since they are distributed as
eggs and importlib extracts those data files differently to
pkg_resources so requires a different solution, either as a file stream
or manually cached when plugins are installed.

Closes: https://github.com/deluge-torrent/deluge/pull/403

Co-authored-by: DjLegolas <djlegolas@protonmail.com>
This commit is contained in:
Calum Lind 2023-05-29 12:05:56 +01:00
commit 40a66278a3
No known key found for this signature in database
GPG key ID: 90597A687B836BA3
4 changed files with 31 additions and 19 deletions

View file

@ -7,9 +7,6 @@ on:
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab
workflow_dispatch: workflow_dispatch:
env:
SETUPTOOLS_ENABLE_FEATURES: "legacy-editable"
jobs: jobs:
test-linux: test-linux:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04

View file

@ -1,5 +1,11 @@
# Changelog # Changelog
## 2.2.x (TBA)
### Breaking changes
- Python 3.6 support removed (Python >= 3.7)
## 2.1.1 (2022-07-10) ## 2.1.1 (2022-07-10)
### Core ### Core

View file

@ -23,15 +23,21 @@ import tarfile
import time import time
from contextlib import closing from contextlib import closing
from datetime import datetime from datetime import datetime
from importlib import resources
from io import BytesIO from io import BytesIO
from pathlib import Path
from urllib.parse import unquote_plus, urljoin from urllib.parse import unquote_plus, urljoin
from urllib.request import pathname2url from urllib.request import pathname2url
import pkg_resources
from deluge.decorators import deprecated from deluge.decorators import deprecated
from deluge.error import InvalidPathError from deluge.error import InvalidPathError
try:
from importlib.metadata import distribution
except ImportError:
from pkg_resources import get_distribution as distribution
try: try:
import chardet import chardet
except ImportError: except ImportError:
@ -90,7 +96,7 @@ def get_version():
Returns: Returns:
str: The version of Deluge. str: The version of Deluge.
""" """
return pkg_resources.get_distribution('Deluge').version return distribution('Deluge').version
def get_default_config_dir(filename=None): def get_default_config_dir(filename=None):
@ -290,20 +296,22 @@ def get_pixmap(fname):
return resource_filename('deluge', os.path.join('ui', 'data', 'pixmaps', fname)) return resource_filename('deluge', os.path.join('ui', 'data', 'pixmaps', fname))
def resource_filename(module, path): def resource_filename(module: str, path: str) -> str:
"""Get filesystem path for a resource. """Get filesystem path for a non-python resource.
This function contains a work-around for pkg_resources.resource_filename Abstracts getting module resource files. Originally created to
not returning the correct path with multiple packages installed. workaround pkg_resources.resource_filename limitations with
multiple Deluge packages installed.
So if there's a second deluge package, installed globally and another in
develop mode somewhere else, while pkg_resources.get_distribution('Deluge')
returns the proper deluge instance, pkg_resources.resource_filename
does not, it returns the first found on the python path, which is wrong.
""" """
return pkg_resources.get_distribution('Deluge').get_resource_filename( path = Path(path)
pkg_resources._manager, os.path.join(*(module.split('.') + [path]))
) try:
with resources.as_file(resources.files(module) / path) as resource_file:
return str(resource_file)
except AttributeError:
# Python <= 3.8
with resources.path(module, path.parts[0]) as resource_file:
return str(resource_file.joinpath(*path.parts[1:]))
def open_file(path, timestamp=None): def open_file(path, timestamp=None):

View file

@ -486,7 +486,8 @@ class TopLevel(resource.Resource):
self.putChild( self.putChild(
b'ui_images', b'ui_images',
LookupResource( LookupResource(
'UI_Images', common.resource_filename('deluge.ui.data', 'pixmaps') 'UI_Images',
common.resource_filename('deluge.ui', os.path.join('data', 'pixmaps')),
), ),
) )