diff --git a/src/flake8/plugins/finder.py b/src/flake8/plugins/finder.py index fb87d0d..9e9e3af 100644 --- a/src/flake8/plugins/finder.py +++ b/src/flake8/plugins/finder.py @@ -179,6 +179,8 @@ def _flake8_plugins( def _find_importlib_plugins() -> Generator[Plugin, None, None]: + # some misconfigured pythons (RHEL) have things on `sys.path` twice + seen = set() for dist in importlib_metadata.distributions(): # assigned to prevent continual reparsing eps = dist.entry_points @@ -190,6 +192,11 @@ def _find_importlib_plugins() -> Generator[Plugin, None, None]: # assigned to prevent continual reparsing meta = dist.metadata + if meta["name"] in seen: + continue + else: + seen.add(meta["name"]) + if meta["name"] in BANNED_PLUGINS: LOG.warning( "%s plugin is obsolete in flake8>=%s", diff --git a/tests/unit/plugins/finder_test.py b/tests/unit/plugins/finder_test.py index 3c11c64..63f8156 100644 --- a/tests/unit/plugins/finder_test.py +++ b/tests/unit/plugins/finder_test.py @@ -361,6 +361,23 @@ unrelated = unrelated:main ] +def test_duplicate_dists(flake8_dist): + # some poorly packaged pythons put lib and lib64 on sys.path resulting in + # duplicates from `importlib.metadata.distributions` + with mock.patch.object( + importlib_metadata, + "distributions", + return_value=[ + flake8_dist, + flake8_dist, + ], + ): + ret = list(finder._find_importlib_plugins()) + + # we should not have duplicates + assert len(ret) == len(set(ret)) + + def test_find_local_plugins_nothing(): cfg = configparser.RawConfigParser() assert set(finder._find_local_plugins(cfg)) == set()