From c18257bd5da1133064bbf79b105394c491c47f84 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Tue, 9 Jul 2024 19:24:51 -0400 Subject: [PATCH] Remove dependency on site_packages It is deprecated and the note says to move away when Python 3.7 is dropped. Seems like now ;) --- conftest.py | 12 +++++++++--- install_dev_repos.py | 2 +- requirements/main.yml | 2 ++ setup.py | 3 ++- spyder/app/find_plugins.py | 27 +++++++++++++++------------ spyder/plugins/completion/plugin.py | 13 ++++++++++--- spyder/utils/programs.py | 6 +++--- spyder/utils/tests/test_programs.py | 2 +- 8 files changed, 43 insertions(+), 24 deletions(-) diff --git a/conftest.py b/conftest.py index 20c11c96886..741908e81a3 100644 --- a/conftest.py +++ b/conftest.py @@ -115,11 +115,17 @@ def reset_conf_before_test(): # Restore completion clients default settings, since they # don't have default values on the configuration. - from pkg_resources import iter_entry_points + + # See compatibility note on `group` keyword: + # https://docs.python.org/3/library/importlib.metadata.html#entry-points + if sys.version_info < (3, 10): # pragma: no cover + from importlib_metadata import entry_points + else: # pragma: no cover + from importlib.metadata import entry_points provider_configurations = {} - for entry_point in iter_entry_points(COMPLETION_ENTRYPOINT): - Provider = entry_point.resolve() + for entry_point in entry_points(group=COMPLETION_ENTRYPOINT): + Provider = entry_point.load() provider_name = Provider.COMPLETION_PROVIDER_NAME (provider_conf_version, diff --git a/install_dev_repos.py b/install_dev_repos.py index 56e2db1d242..c676bed1836 100755 --- a/install_dev_repos.py +++ b/install_dev_repos.py @@ -15,7 +15,7 @@ from pathlib import Path from subprocess import check_output -from importlib_metadata import PackageNotFoundError, distribution +from importlib.metadata import PackageNotFoundError, distribution from packaging.requirements import Requirement # Remove current/script directory from sys.path[0] if added by the Python invocation, diff --git a/requirements/main.yml b/requirements/main.yml index 92bd4974a24..6dd26168c7d 100644 --- a/requirements/main.yml +++ b/requirements/main.yml @@ -43,3 +43,5 @@ dependencies: - textdistance >=4.2.0 - three-merge >=0.1.1 - watchdog >=0.10.3 + # Need at least some compatibility with python 3.10 features + - importlib-metadata >=4.6.0 diff --git a/setup.py b/setup.py index 51f7b5f5d98..dccc321e541 100644 --- a/setup.py +++ b/setup.py @@ -246,7 +246,8 @@ def run(self): 'spyder-kernels>=2.5.2,<2.6.0', 'textdistance>=4.2.0', 'three-merge>=0.1.1', - 'watchdog>=0.10.3' + 'watchdog>=0.10.3', + 'importlib_metadata>=4.8.3;python_version<"3.10"', ] # Loosen constraints to ensure dev versions still work diff --git a/spyder/app/find_plugins.py b/spyder/app/find_plugins.py index 0bc8c4377f7..0d6c088d8e7 100644 --- a/spyder/app/find_plugins.py +++ b/spyder/app/find_plugins.py @@ -7,11 +7,17 @@ Plugin dependency solver. """ +import sys import importlib import logging import traceback -import pkg_resources +# See compatibility note on `group` keyword: +# https://docs.python.org/3/library/importlib.metadata.html#entry-points +if sys.version_info < (3, 10): # pragma: no cover + from importlib_metadata import entry_points +else: # pragma: no cover + from importlib.metadata import entry_points from spyder.api.exceptions import SpyderAPIError from spyder.api.plugins import Plugins @@ -28,16 +34,15 @@ def find_internal_plugins(): """ internal_plugins = {} - entry_points = list(pkg_resources.iter_entry_points("spyder.plugins")) internal_names = get_class_values(Plugins) - for entry_point in entry_points: + for entry_point in entry_points(group="spyder.plugins"): name = entry_point.name if name not in internal_names: continue - class_name = entry_point.attrs[0] - mod = importlib.import_module(entry_point.module_name) + class_name = entry_point.attr + mod = importlib.import_module(entry_point.module) plugin_class = getattr(mod, class_name, None) internal_plugins[name] = plugin_class @@ -56,21 +61,19 @@ def find_external_plugins(): Find available external plugins based on setuptools entry points. """ internal_names = get_class_values(Plugins) - plugins = list(pkg_resources.iter_entry_points("spyder.plugins")) external_plugins = {} - for entry_point in plugins: + for entry_point in entry_points(group="spyder.plugins"): name = entry_point.name if name not in internal_names: try: - class_name = entry_point.attrs[0] - mod = importlib.import_module(entry_point.module_name) + class_name = entry_point.attr + mod = importlib.import_module(entry_point.module) plugin_class = getattr(mod, class_name, None) # To display in dependencies dialog. - plugin_class._spyder_module_name = entry_point.module_name - plugin_class._spyder_package_name = ( - entry_point.dist.project_name) + plugin_class._spyder_module_name = entry_point.module + plugin_class._spyder_package_name = entry_point.dist.name plugin_class._spyder_version = entry_point.dist.version external_plugins[name] = plugin_class diff --git a/spyder/plugins/completion/plugin.py b/spyder/plugins/completion/plugin.py index 99bc8caa41f..0a3a67a55a2 100644 --- a/spyder/plugins/completion/plugin.py +++ b/spyder/plugins/completion/plugin.py @@ -12,6 +12,7 @@ """ # Standard library imports +import sys import functools import inspect import logging @@ -19,9 +20,15 @@ from typing import List, Union import weakref +# See compatibility note on `group` keyword: +# https://docs.python.org/3/library/importlib.metadata.html#entry-points +if sys.version_info < (3, 10): # pragma: no cover + from importlib_metadata import entry_points +else: # pragma: no cover + from importlib.metadata import entry_points + # Third-party imports from packaging.version import parse -from pkg_resources import iter_entry_points from qtpy.QtCore import QMutex, QMutexLocker, QTimer, Slot, Signal # Local imports @@ -234,7 +241,7 @@ def __init__(self, parent, configuration=None): # Find and instantiate all completion providers registered via # entrypoints - for entry_point in iter_entry_points(COMPLETION_ENTRYPOINT): + for entry_point in entry_points(group=COMPLETION_ENTRYPOINT): try: # This absolutely ensures that the Kite provider won't be # loaded. For instance, it can happen when you have an older @@ -243,7 +250,7 @@ def __init__(self, parent, configuration=None): if 'kite' in entry_point.name: continue logger.debug(f'Loading entry point: {entry_point}') - Provider = entry_point.resolve() + Provider = entry_point.load() self._instantiate_and_register_provider(Provider) except Exception as e: logger.warning('Failed to load completion provider from entry ' diff --git a/spyder/utils/programs.py b/spyder/utils/programs.py index cd1a99a73f7..1d10a6084bb 100644 --- a/spyder/utils/programs.py +++ b/spyder/utils/programs.py @@ -24,7 +24,6 @@ # Third party imports from packaging.version import parse -import pkg_resources import psutil # Local imports @@ -849,9 +848,10 @@ def get_package_version(package_name): # When support for Python 3.7 and below is dropped, this can be replaced # with the built-in importlib.metadata.version try: - ver = pkg_resources.get_distribution(package_name).version + from importlib_metadata import version + ver = version(package_name) return ver - except pkg_resources.DistributionNotFound: + except PackageNotFoundError: return None diff --git a/spyder/utils/tests/test_programs.py b/spyder/utils/tests/test_programs.py index 5c78b0ef2a7..439c77b940f 100644 --- a/spyder/utils/tests/test_programs.py +++ b/spyder/utils/tests/test_programs.py @@ -287,7 +287,7 @@ def test_open_files_with_application(tmp_path): def test_get_package_version(): - # Primarily a test of pkg_resources/setuptools being installed properly + # Primarily a test of importlib.metadata being installed properly assert get_package_version('IPython') assert get_package_version('python_lsp_black')