diff --git a/docs/conf.py b/docs/conf.py index 90a1da2a..2cd8fb0c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -69,6 +69,4 @@ ('py:class', 'importlib_metadata._meta._T'), # Workaround for #435 ('py:class', '_T'), - # Other workarounds - ('py:class', 'importlib_metadata.DeprecatedNonAbstract'), ] diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index eab73ffe..ed481355 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -12,7 +12,6 @@ import pathlib import operator import textwrap -import warnings import functools import itertools import posixpath @@ -334,27 +333,7 @@ def __repr__(self) -> str: return f'' -class DeprecatedNonAbstract: - # Required until Python 3.14 - def __new__(cls, *args, **kwargs): - all_names = { - name for subclass in inspect.getmro(cls) for name in vars(subclass) - } - abstract = { - name - for name in all_names - if getattr(getattr(cls, name), '__isabstractmethod__', False) - } - if abstract: - warnings.warn( - f"Unimplemented abstract methods {abstract}", - DeprecationWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class Distribution(DeprecatedNonAbstract): +class Distribution(metaclass=abc.ABCMeta): """ An abstract Python distribution package. diff --git a/importlib_metadata/_adapters.py b/importlib_metadata/_adapters.py index 120e43a0..6223263e 100644 --- a/importlib_metadata/_adapters.py +++ b/importlib_metadata/_adapters.py @@ -1,20 +1,8 @@ -import functools -import warnings import re import textwrap import email.message from ._text import FoldedCase -from ._compat import pypy_partial - - -# Do not remove prior to 2024-01-01 or Python 3.14 -_warn = functools.partial( - warnings.warn, - "Implicit None on return values is deprecated and will raise KeyErrors.", - DeprecationWarning, - stacklevel=pypy_partial(2), -) class Message(email.message.Message): @@ -53,12 +41,17 @@ def __iter__(self): def __getitem__(self, item): """ - Warn users that a ``KeyError`` can be expected when a - missing key is supplied. Ref python/importlib_metadata#371. + Override parent behavior to typical dict behavior. + + ``email.message.Message`` will emit None values for missing + keys. Typical mappings, including this ``Message``, will raise + a key error for missing keys. + + Ref python/importlib_metadata#371. """ res = super().__getitem__(item) if res is None: - _warn() + raise KeyError(item) return res def _repair_headers(self): diff --git a/newsfragments/+8256a9d7.removal.rst b/newsfragments/+8256a9d7.removal.rst new file mode 100644 index 00000000..86f61c42 --- /dev/null +++ b/newsfragments/+8256a9d7.removal.rst @@ -0,0 +1 @@ +Removed deprecated support for Distribution subclasses not implementing abstract methods. \ No newline at end of file diff --git a/newsfragments/371.removal.rst b/newsfragments/371.removal.rst new file mode 100644 index 00000000..7aca2d4f --- /dev/null +++ b/newsfragments/371.removal.rst @@ -0,0 +1 @@ +Message.__getitem__ now raises a KeyError on missing keys. \ No newline at end of file diff --git a/tests/test_api.py b/tests/test_api.py index fc20987e..7ce0cd64 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,9 +1,7 @@ import re import textwrap import unittest -import warnings import importlib -import contextlib from . import fixtures from importlib_metadata import ( @@ -18,13 +16,6 @@ ) -@contextlib.contextmanager -def suppress_known_deprecation(): - with warnings.catch_warnings(record=True) as ctx: - warnings.simplefilter('default', category=DeprecationWarning) - yield ctx - - class APITests( fixtures.EggInfoPkg, fixtures.EggInfoPkgPipInstalledNoToplevel, @@ -157,13 +148,13 @@ def test_importlib_metadata_version(self): resolved = version('importlib-metadata') assert re.match(self.version_pattern, resolved) - def test_missing_key_legacy(self): + def test_missing_key(self): """ - Requesting a missing key will still return None, but warn. + Requesting a missing key raises KeyError. """ md = metadata('distinfo-pkg') - with suppress_known_deprecation(): - assert md['does-not-exist'] is None + with self.assertRaises(KeyError): + md['does-not-exist'] def test_get_key(self): """ diff --git a/tests/test_main.py b/tests/test_main.py index 32241c00..f1c12855 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,16 +1,13 @@ import re import pickle import unittest -import warnings import importlib import importlib_metadata -import contextlib from .compat.py39 import os_helper import pyfakefs.fake_filesystem_unittest as ffs from . import fixtures -from ._context import suppress from ._path import Symlink from importlib_metadata import ( Distribution, @@ -25,13 +22,6 @@ ) -@contextlib.contextmanager -def suppress_known_deprecation(): - with warnings.catch_warnings(record=True) as ctx: - warnings.simplefilter('default', category=DeprecationWarning) - yield ctx - - class BasicTests(fixtures.DistInfoPkg, unittest.TestCase): version_pattern = r'\d+\.\d+(\.\d)?' @@ -56,9 +46,6 @@ def test_package_not_found_mentions_metadata(self): assert "metadata" in str(ctx.exception) - # expected to fail until ABC is enforced - @suppress(AssertionError) - @suppress_known_deprecation() def test_abc_enforced(self): with self.assertRaises(TypeError): type('DistributionSubclass', (Distribution,), {})()