Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove non-version metadata hack #1268

Merged
merged 3 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.d/1268.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
All packaging metadata except from `__version__` and `__version_info__` has been removed from the `attr` and `attrs` modules (for example, `attrs.__url__`).

Please use [`importlib.metadata`](https://docs.python.org/3/library/importlib.metadata.html) or [*importlib_metadata*](https://pypi.org/project/importlib-metadata/) instead.
45 changes: 6 additions & 39 deletions src/attr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,54 +79,21 @@ def _make_getattr(mod_name: str) -> Callable:
"""

def __getattr__(name: str) -> str:
dunder_to_metadata = {
"__title__": "Name",
"__copyright__": "",
"__version__": "version",
"__version_info__": "version",
"__description__": "summary",
"__uri__": "",
"__url__": "",
"__author__": "",
"__email__": "",
"__license__": "license",
}
if name not in dunder_to_metadata:
if name not in ("__version__", "__version_info__"):
msg = f"module {mod_name} has no attribute {name}"
raise AttributeError(msg)

import sys
import warnings

if sys.version_info < (3, 8):
from importlib_metadata import metadata
else:
try:
from importlib.metadata import metadata

if name not in ("__version__", "__version_info__"):
warnings.warn(
f"Accessing {mod_name}.{name} is deprecated and will be "
"removed in a future release. Use importlib.metadata directly "
"to query for attrs's packaging metadata.",
DeprecationWarning,
stacklevel=2,
)
except ImportError:
from importlib_metadata import metadata

meta = metadata("attrs")
if name == "__license__":
return "MIT"
if name == "__copyright__":
return "Copyright (c) 2015 Hynek Schlawack"
if name in ("__uri__", "__url__"):
return meta["Project-URL"].split(" ", 1)[-1]

if name == "__version_info__":
return VersionInfo._from_version_string(meta["version"])
if name == "__author__":
return meta["Author-email"].rsplit(" ", 1)[0]
if name == "__email__":
return meta["Author-email"].rsplit("<", 1)[1][:-1]

return meta[dunder_to_metadata[name]]
return meta["version"]

return __getattr__

Expand Down
85 changes: 0 additions & 85 deletions tests/test_packaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,6 @@ def _mod(request):


class TestLegacyMetadataHack:
def test_title(self, mod):
"""
__title__ returns attrs.
"""
with pytest.deprecated_call() as ws:
assert "attrs" == mod.__title__

assert (
f"Accessing {mod.__name__}.__title__ is deprecated"
in ws.list[0].message.args[0]
)

def test_copyright(self, mod):
"""
__copyright__ returns the correct blurp.
"""
with pytest.deprecated_call() as ws:
assert "Copyright (c) 2015 Hynek Schlawack" == mod.__copyright__

assert (
f"Accessing {mod.__name__}.__copyright__ is deprecated"
in ws.list[0].message.args[0]
)

def test_version(self, mod, recwarn):
"""
__version__ returns the correct version and doesn't warn.
Expand All @@ -52,67 +28,6 @@ def test_version(self, mod, recwarn):

assert [] == recwarn.list

def test_description(self, mod):
"""
__description__ returns the correct description.
"""
with pytest.deprecated_call() as ws:
assert "Classes Without Boilerplate" == mod.__description__

assert (
f"Accessing {mod.__name__}.__description__ is deprecated"
in ws.list[0].message.args[0]
)

@pytest.mark.parametrize("name", ["__uri__", "__url__"])
def test_uri(self, mod, name):
"""
__uri__ & __url__ returns the correct project URL.
"""
with pytest.deprecated_call() as ws:
assert "https://www.attrs.org/" == getattr(mod, name)

assert (
f"Accessing {mod.__name__}.{name} is deprecated"
in ws.list[0].message.args[0]
)

def test_author(self, mod):
"""
__author__ returns Hynek.
"""
with pytest.deprecated_call() as ws:
assert "Hynek Schlawack" == mod.__author__

assert (
f"Accessing {mod.__name__}.__author__ is deprecated"
in ws.list[0].message.args[0]
)

def test_email(self, mod):
"""
__email__ returns Hynek's email address.
"""
with pytest.deprecated_call() as ws:
assert "hs@ox.cx" == mod.__email__

assert (
f"Accessing {mod.__name__}.__email__ is deprecated"
in ws.list[0].message.args[0]
)

def test_license(self, mod):
"""
__license__ returns MIT.
"""
with pytest.deprecated_call() as ws:
assert "MIT" == mod.__license__

assert (
f"Accessing {mod.__name__}.__license__ is deprecated"
in ws.list[0].message.args[0]
)

def test_does_not_exist(self, mod):
"""
Asking for unsupported dunders raises an AttributeError.
Expand Down