diff --git a/lib/importlib_metadata/__init__.py b/lib/importlib_metadata/__init__.py index 32ee3b4d..ed481355 100644 --- a/lib/importlib_metadata/__init__.py +++ b/lib/importlib_metadata/__init__.py @@ -12,14 +12,13 @@ import inspect import pathlib import operator import textwrap -import warnings import functools import itertools import posixpath import collections -from . import _adapters, _meta -from .compat import py39 +from . import _meta +from .compat import py39, py311 from ._collections import FreezableDefaultDict, Pair from ._compat import ( NullFinder, @@ -334,27 +333,7 @@ class FileHash: 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. @@ -461,6 +440,9 @@ class Distribution(DeprecatedNonAbstract): Custom providers may provide the METADATA file or override this property. """ + # deferred for performance (python/cpython#109829) + from . import _adapters + opt_text = ( self.read_text('METADATA') or self.read_text('PKG-INFO') @@ -567,9 +549,8 @@ class Distribution(DeprecatedNonAbstract): return paths = ( - (subdir / name) - .resolve() - .relative_to(self.locate_file('').resolve()) + py311.relative_fix((subdir / name).resolve()) + .relative_to(self.locate_file('').resolve(), walk_up=True) .as_posix() for name in text.splitlines() ) diff --git a/lib/importlib_metadata/_adapters.py b/lib/importlib_metadata/_adapters.py index 120e43a0..6223263e 100644 --- a/lib/importlib_metadata/_adapters.py +++ b/lib/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 @@ class Message(email.message.Message): 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/lib/importlib_metadata/compat/py311.py b/lib/importlib_metadata/compat/py311.py new file mode 100644 index 00000000..3a532743 --- /dev/null +++ b/lib/importlib_metadata/compat/py311.py @@ -0,0 +1,22 @@ +import os +import pathlib +import sys +import types + + +def wrap(path): # pragma: no cover + """ + Workaround for https://github.com/python/cpython/issues/84538 + to add backward compatibility for walk_up=True. + An example affected package is dask-labextension, which uses + jupyter-packaging to install JupyterLab javascript files outside + of site-packages. + """ + + def relative_to(root, *, walk_up=False): + return pathlib.Path(os.path.relpath(path, root)) + + return types.SimpleNamespace(relative_to=relative_to) + + +relative_fix = wrap if sys.version_info < (3, 12) else lambda x: x diff --git a/package/requirements-package.txt b/package/requirements-package.txt index 85f0e61b..2f21fea4 100644 --- a/package/requirements-package.txt +++ b/package/requirements-package.txt @@ -1,5 +1,5 @@ apscheduler==3.10.1 -importlib-metadata==7.1.0 +importlib-metadata==8.0.0 importlib-resources==6.4.0 pyinstaller==6.8.0 pyopenssl==24.1.0 diff --git a/requirements.txt b/requirements.txt index c42251a4..f1593fe6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,7 @@ gntp==1.0.3 html5lib==1.1 httpagentparser==1.9.5 idna==3.7 -importlib-metadata==7.1.0 +importlib-metadata==8.0.0 importlib-resources==6.4.0 git+https://github.com/Tautulli/ipwhois.git@master#egg=ipwhois IPy==1.01