Skip to content

Commit

Permalink
Merge pull request #22244 from hmaarrfk/no_pkg_resources
Browse files Browse the repository at this point in the history
PR: Remove dependency on `pkg_resources` and use `importlib-metadata` instead
  • Loading branch information
ccordoba12 authored Jul 24, 2024
2 parents 5c23422 + 84af373 commit b610229
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 37 deletions.
1 change: 1 addition & 0 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies:
- cloudpickle >=0.5.0
- cookiecutter >=1.6.0
- diff-match-patch >=20181111
- importlib-metadata >=4.6.0
- intervaltree >=3.0.2
- ipython >=8.13.0,<9.0.0,!=8.17.1
- jedi >=0.17.2,<0.20.0
Expand Down
13 changes: 9 additions & 4 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,18 @@ def reset_conf_before_test():
from spyder.plugins.completion.api import COMPLETION_ENTRYPOINT
from spyder.plugins.completion.plugin import CompletionPlugin

# 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

# Restore completion clients default settings, since they
# don't have default values on the configuration.
from pkg_resources import iter_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,
Expand Down
2 changes: 1 addition & 1 deletion install_dev_repos.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 0 additions & 5 deletions installers/macOS/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@
ModuleNotFoundError: No module named 'keyring.backends.chainer'
ModuleNotFoundError: No module named 'keyring.backends.libsecret'
ModuleNotFoundError: No module named 'keyring.backends.macOS'
pkg_resources:
ImportError: The 'more_itertools' package is required; normally this is
bundled with this package so if you get this warning, consult the
packager of your distribution.
pygments:
ModuleNotFoundError: No module named 'pygments.formatters.latex'
pylint_venv:
Expand All @@ -45,7 +41,6 @@
PACKAGES = [
'blackd',
'keyring',
'pkg_resources',
'pygments',
'pylint_venv',
'pyls_spyder',
Expand Down
2 changes: 2 additions & 0 deletions requirements/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ dependencies:
- cloudpickle >=0.5.0
- cookiecutter >=1.6.0
- diff-match-patch >=20181111
# Need at least some compatibility with python 3.10 features
- importlib-metadata >=4.6.0
- intervaltree >=3.0.2
- ipython >=8.13.0,<9.0.0,!=8.17.1
- jedi >=0.17.2,<0.20.0
Expand Down
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ def run(self):
'cloudpickle>=0.5.0',
'cookiecutter>=1.6.0',
'diff-match-patch>=20181111',
# While this is only required for python <3.10, it is safe enough to
# install in all cases and helps the tests to pass.
'importlib-metadata>=4.6.0',
'intervaltree>=3.0.2',
'ipython>=8.12.2,<8.13.0; python_version=="3.8"',
'ipython>=8.13.0,<9.0.0,!=8.17.1; python_version>"3.8"',
Expand Down Expand Up @@ -246,7 +249,7 @@ 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',
]

# Loosen constraints to ensure dev versions still work
Expand Down
29 changes: 16 additions & 13 deletions spyder/app/find_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@
Plugin dependency solver.
"""

import sys
import importlib
import logging
import traceback

import pkg_resources

from spyder.api.exceptions import SpyderAPIError
from spyder.api.plugins import Plugins
from spyder.api.utils import get_class_values
from spyder.config.base import STDERR

# 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


logger = logging.getLogger(__name__)

Expand All @@ -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

Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions spyder/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
CLOUDPICKLE_REQVER = '>=0.5.0'
COOKIECUTTER_REQVER = '>=1.6.0'
DIFF_MATCH_PATCH_REQVER = '>=20181111'
IMPORTLIB_METADATA_REQVER = '>=4.6.0'
# None for pynsist install for now
# (check way to add dist.info/egg.info from packages without wheels available)
INTERVALTREE_REQVER = None if is_pynsist() else '>=3.0.2'
Expand Down Expand Up @@ -121,6 +122,10 @@
'package_name': "diff-match-patch",
'features': _("Compute text file diff changes during edition"),
'required_version': DIFF_MATCH_PATCH_REQVER},
{'modname': 'importlib_metadata',
'package_name': 'importlib-metadata',
'features': _('Access the metadata for a Python package'),
'required_version': IMPORTLIB_METADATA_REQVER},
{'modname': "intervaltree",
'package_name': "intervaltree",
'features': _("Compute folding range nesting levels"),
Expand Down
13 changes: 10 additions & 3 deletions spyder/plugins/completion/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"""

# Standard library imports
import sys
import functools
import inspect
import logging
Expand All @@ -21,7 +22,6 @@

# 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
Expand All @@ -37,6 +37,13 @@
from spyder.plugins.completion.confpage import CompletionConfigPage
from spyder.plugins.completion.container import CompletionContainer

# 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


logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -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
Expand All @@ -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 '
Expand Down
14 changes: 5 additions & 9 deletions spyder/utils/programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@

# Standard library imports
from ast import literal_eval
from getpass import getuser
from textwrap import dedent
import glob
from getpass import getuser
import importlib
from importlib.metadata import PackageNotFoundError, version as package_version
import itertools
import os
import os.path as osp
import re
import subprocess
import sys
import tempfile
from textwrap import dedent
import threading
import time

# Third party imports
from packaging.version import parse
import pkg_resources
import psutil

# Local imports
Expand Down Expand Up @@ -845,13 +845,9 @@ def get_module_version(module_name):

def get_package_version(package_name):
"""Return package version or None if version can't be retrieved."""

# 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
return ver
except pkg_resources.DistributionNotFound:
return package_version(package_name)
except PackageNotFoundError:
return None


Expand Down
2 changes: 1 addition & 1 deletion spyder/utils/tests/test_programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down

0 comments on commit b610229

Please sign in to comment.