From 40a66278a36e8aa202273a3ace073136f744a73c Mon Sep 17 00:00:00 2001 From: Calum Lind Date: Mon, 29 May 2023 12:05:56 +0100 Subject: [PATCH] [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 --- .github/workflows/ci.yml | 3 --- CHANGELOG.md | 6 ++++++ deluge/common.py | 38 +++++++++++++++++++++++--------------- deluge/ui/web/server.py | 3 ++- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adf156e71..82a9fd99a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,9 +7,6 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -env: - SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" - jobs: test-linux: runs-on: ubuntu-20.04 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7de306456..d878a488d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2.2.x (TBA) + +### Breaking changes + +- Python 3.6 support removed (Python >= 3.7) + ## 2.1.1 (2022-07-10) ### Core diff --git a/deluge/common.py b/deluge/common.py index bcee2695f..638fefba5 100644 --- a/deluge/common.py +++ b/deluge/common.py @@ -23,15 +23,21 @@ import tarfile import time from contextlib import closing from datetime import datetime +from importlib import resources from io import BytesIO +from pathlib import Path from urllib.parse import unquote_plus, urljoin from urllib.request import pathname2url -import pkg_resources - from deluge.decorators import deprecated from deluge.error import InvalidPathError +try: + from importlib.metadata import distribution +except ImportError: + from pkg_resources import get_distribution as distribution + + try: import chardet except ImportError: @@ -90,7 +96,7 @@ def get_version(): Returns: str: The version of Deluge. """ - return pkg_resources.get_distribution('Deluge').version + return distribution('Deluge').version 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)) -def resource_filename(module, path): - """Get filesystem path for a resource. +def resource_filename(module: str, path: str) -> str: + """Get filesystem path for a non-python resource. - This function contains a work-around for pkg_resources.resource_filename - not returning the correct path with multiple 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. + Abstracts getting module resource files. Originally created to + workaround pkg_resources.resource_filename limitations with + multiple Deluge packages installed. """ - return pkg_resources.get_distribution('Deluge').get_resource_filename( - pkg_resources._manager, os.path.join(*(module.split('.') + [path])) - ) + path = Path(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): diff --git a/deluge/ui/web/server.py b/deluge/ui/web/server.py index fe563f130..77c1ddf60 100644 --- a/deluge/ui/web/server.py +++ b/deluge/ui/web/server.py @@ -486,7 +486,8 @@ class TopLevel(resource.Resource): self.putChild( b'ui_images', LookupResource( - 'UI_Images', common.resource_filename('deluge.ui.data', 'pixmaps') + 'UI_Images', + common.resource_filename('deluge.ui', os.path.join('data', 'pixmaps')), ), )