From 54cb64292c54b9e8dc2f2ae1a69cb16345b781db Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sat, 27 May 2023 13:46:20 +0100 Subject: [PATCH] Support importlib.metadata entry points for newer python pkg_resources is deprecated and liable to be dropped at some point. --- jedi/plugins/pytest.py | 27 ++++++++++++++++++++++++--- test/test_integration.py | 31 +++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/jedi/plugins/pytest.py b/jedi/plugins/pytest.py index 0f6b320d..06adda44 100644 --- a/jedi/plugins/pytest.py +++ b/jedi/plugins/pytest.py @@ -1,3 +1,5 @@ +import sys +from typing import List from pathlib import Path from parso.tree import search_ancestor @@ -131,15 +133,34 @@ def _is_pytest_func(func_name, decorator_nodes): or any('fixture' in n.get_code() for n in decorator_nodes) -def _find_pytest_plugin_modules(): +def _find_pytest_plugin_modules() -> List[List[str]]: """ Finds pytest plugin modules hooked by setuptools entry points See https://docs.pytest.org/en/stable/how-to/writing_plugins.html#setuptools-entry-points """ - from pkg_resources import iter_entry_points + if sys.version_info >= (3, 8): + from importlib.metadata import entry_points - return [ep.module_name.split(".") for ep in iter_entry_points(group="pytest11")] + if sys.version_info >= (3, 10): + pytest_entry_points = entry_points(group="pytest11") + else: + pytest_entry_points = entry_points().get("pytest11", ()) + + if sys.version_info >= (3, 9): + return [ep.module.split(".") for ep in pytest_entry_points] + else: + # Python 3.8 doesn't have `EntryPoint.module`. Implement equivalent + # to what Python 3.9 does (with additional None check to placate `mypy`) + matches = [ + ep.pattern.match(ep.value) + for ep in pytest_entry_points + ] + return [x.group('module').split(".") for x in matches if x] + + else: + from pkg_resources import iter_entry_points + return [ep.module_name.split(".") for ep in iter_entry_points(group="pytest11")] @inference_state_method_cache() diff --git a/test/test_integration.py b/test/test_integration.py index 2d8e118c..0364c05b 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -1,4 +1,5 @@ import os +import sys from collections import namedtuple import pytest @@ -50,14 +51,32 @@ def test_completion(case, monkeypatch, environment, has_django): pytest_plugin_dir = str(helpers.get_example_dir("pytest_plugin_package")) case._project.added_sys_path = [pytest_plugin_dir] - # ... and mock setuptools entry points to include it + # ... and mock the entry points to include it # see https://docs.pytest.org/en/stable/how-to/writing_plugins.html#setuptools-entry-points - def mock_iter_entry_points(group): - assert group == "pytest11" - EntryPoint = namedtuple("EntryPoint", ["module_name"]) - return [EntryPoint("pytest_plugin.plugin")] + if sys.version_info >= (3, 8): + def mock_entry_points(*, group=None): + import importlib.metadata + entries = [importlib.metadata.EntryPoint( + name=None, + value="pytest_plugin.plugin", + group="pytest11", + )] - monkeypatch.setattr("pkg_resources.iter_entry_points", mock_iter_entry_points) + if sys.version_info >= (3, 10): + assert group == "pytest11" + return entries + else: + assert group is None + return {"pytest11": entries} + + monkeypatch.setattr("importlib.metadata.entry_points", mock_entry_points) + else: + def mock_iter_entry_points(group): + assert group == "pytest11" + EntryPoint = namedtuple("EntryPoint", ["module_name"]) + return [EntryPoint("pytest_plugin.plugin")] + + monkeypatch.setattr("pkg_resources.iter_entry_points", mock_iter_entry_points) repo_root = helpers.root_dir monkeypatch.chdir(os.path.join(repo_root, 'jedi'))