Skip to content
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
2 changes: 2 additions & 0 deletions spond/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
Not intended to be instantiated directly — use a subclass.
"""

import functools
from abc import ABC
from collections.abc import Callable

Expand Down Expand Up @@ -65,6 +66,7 @@ def require_authentication(func: Callable):
client is not yet authenticated. On `AuthenticationError`, closes the
underlying aiohttp session before re-raising."""

@functools.wraps(func)
async def wrapper(self, *args, **kwargs):
if not self.token:
try:
Expand Down
29 changes: 29 additions & 0 deletions tests/test_spond.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,3 +524,32 @@ async def test_login__error_response_raises(self, mock_post) -> None:
with pytest.raises(AuthenticationError):
await s.login()
assert s.token is None


class TestRequireAuthenticationDecorator:
"""The `require_authentication` decorator must preserve the wrapped
method's metadata (signature, docstring, name) so `inspect`-based
tools — pdoc, IDE help, tab completion — see the real method
rather than the wrapper's `(*args, **kwargs)` shim.
"""

def test_decorator_preserves_signature(self) -> None:
"""Decorated methods must expose their real parameter list."""
import inspect

# `get_posts` is decorated and has a distinctive signature
params = list(inspect.signature(Spond.get_posts).parameters)
assert params == ["self", "group_id", "max_posts", "include_comments"]

def test_decorator_preserves_docstring(self) -> None:
"""Decorated methods must expose their own docstring, not the
wrapper's."""
import inspect

doc = inspect.getdoc(Spond.get_profile) or ""
# Wrapper docstring would start with 'Decorator that...' if leaked.
assert "Retrieve the authenticated user's profile." in doc

def test_decorator_preserves_name(self) -> None:
"""`__name__` must be the method's, not 'wrapper'."""
assert Spond.get_events.__name__ == "get_events"