Skip to content

Commit 95654e0

Browse files
committed
Deprecate construction of Distribution and subclasses without implementing abstract methods. Fixes #422.
1 parent 6ebb1f9 commit 95654e0

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

importlib_metadata/__init__.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,26 @@ def __repr__(self):
348348
return f'<FileHash mode: {self.mode} value: {self.value}>'
349349

350350

351-
class Distribution(metaclass=abc.ABCMeta):
351+
class DeprecatedNonAbstract:
352+
def __new__(cls, *args, **kwargs):
353+
all_names = {
354+
name for subclass in inspect.getmro(cls) for name in vars(subclass)
355+
}
356+
abstract = {
357+
name
358+
for name in all_names
359+
if getattr(getattr(cls, name), '__isabstractmethod__', False)
360+
}
361+
if abstract:
362+
warnings.warn(
363+
f"Unimplemented abstract methods {abstract}",
364+
DeprecationWarning,
365+
stacklevel=2,
366+
)
367+
return super().__new__(cls)
368+
369+
370+
class Distribution(DeprecatedNonAbstract):
352371
"""A Python distribution package."""
353372

354373
@abc.abstractmethod

tests/_context.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import contextlib
2+
3+
4+
# from jaraco.context 4.3
5+
class suppress(contextlib.suppress, contextlib.ContextDecorator):
6+
"""
7+
A version of contextlib.suppress with decorator support.
8+
9+
>>> @suppress(KeyError)
10+
... def key_error():
11+
... {}['']
12+
>>> key_error()
13+
"""

tests/test_main.py

+13
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import re
22
import pickle
33
import unittest
4+
import warnings
45
import importlib
56
import importlib_metadata
7+
import contextlib
68
import itertools
79
import pyfakefs.fake_filesystem_unittest as ffs
810

911
from . import fixtures
12+
from ._context import suppress
1013
from importlib_metadata import (
1114
Distribution,
1215
EntryPoint,
@@ -20,6 +23,13 @@
2023
)
2124

2225

26+
@contextlib.contextmanager
27+
def suppress_known_deprecation():
28+
with warnings.catch_warnings(record=True) as ctx:
29+
warnings.simplefilter('default', category=DeprecationWarning)
30+
yield ctx
31+
32+
2333
class BasicTests(fixtures.DistInfoPkg, unittest.TestCase):
2434
version_pattern = r'\d+\.\d+(\.\d)?'
2535

@@ -44,6 +54,9 @@ def test_package_not_found_mentions_metadata(self):
4454

4555
assert "metadata" in str(ctx.exception)
4656

57+
# expected to fail until ABC is enforced
58+
@suppress(AssertionError)
59+
@suppress_known_deprecation()
4760
def test_abc_enforced(self):
4861
with self.assertRaises(TypeError):
4962
type('DistributionSubclass', (Distribution,), {})()

0 commit comments

Comments
 (0)