Skip to content

fix: preserve wrapped method metadata in require_authentication#244

Merged
Olen merged 2 commits into
mainfrom
fix/wraps-decorator
May 14, 2026
Merged

fix: preserve wrapped method metadata in require_authentication#244
Olen merged 2 commits into
mainfrom
fix/wraps-decorator

Conversation

@Olen
Copy link
Copy Markdown
Owner

@Olen Olen commented May 14, 2026

The bug

You're right — the function-level docstrings on https://olen.github.io/Spond/spond/spond.html are wrong, but the cause isn't in the docstrings themselves. The `require_authentication` decorator was missing `@functools.wraps(func)`, so every method it decorated lost its metadata:

```python

before

@staticmethod
def require_authentication(func: Callable):
async def wrapper(self, *args, **kwargs):
...
return wrapper
```

Without `functools.wraps`, `Spond.get_profile` was internally just a copy of `wrapper`. `inspect.signature` saw `(self, *args, **kwargs)`. `inspect.getdoc` saw nothing (or the wrapper's docstring leaked through, depending on Python's exact resolution). pdoc reads both, so every decorated method on the live site rendered as:

```
async def get_profile(self, *args, **kwargs):
# source: the wrapper's body, not get_profile's
```

instead of:

```
async def get_profile(self) -> JSONDict:
"""Retrieve the authenticated user's profile.

The profile dict includes at least the user's \`id\`, \`firstName\`, and
\`lastName\`...
"""

```

All my docstring work from #237 / #241 landed in source but pdoc never saw it for decorated methods.

The fix

Two lines: `import functools` + `@functools.wraps(func)` on the inner wrapper. After this fix, decorated methods expose their real signatures and docstrings:

```
get_profile(self) -> 'JSONDict'
→ Retrieve the authenticated user's profile.
get_posts(self, group_id: 'str | None' = None, max_posts: 'int' = 20, ...
→ Retrieve posts from group walls.
get_events(self, group_id: 'str | None' = None, subgroup_id: 'str | None' = None, ...
→ Retrieve events visible to the authenticated user.
```

Regression tests

New `TestRequireAuthenticationDecorator` class with three tests that each fail if `functools.wraps` is removed:

  • `test_decorator_preserves_signature` — `get_posts` exposes its real parameter list, not `*args, **kwargs`.
  • `test_decorator_preserves_docstring` — `get_profile` exposes its real docstring, not the wrapper's.
  • `test_decorator_preserves_name` — `get_events.name` is `"get_events"`, not `"wrapper"`.

Why this only surfaced now

Before #241 expanded the docstrings, all decorated methods had thin one-line docstrings. The wrapper's "leaked" appearance was less obvious because the user-facing docs were already terse. After #241 dropped substantial docstrings on each method, the bug became loud: I had carefully written content for, say, `get_events`, and pdoc kept showing a generic `(self, *args, **kwargs)` shim instead.

Test plan

🤖 Generated with Claude Code

Olen added 2 commits May 14, 2026 16:28
…ator

`require_authentication` was missing `@functools.wraps(func)` on its
inner `wrapper`, so every decorated method (most of `Spond.*`) lost
its `__name__`, `__doc__`, `__qualname__`, `__wrapped__`, and real
signature.

The effect on the published pdoc site was severe: every decorated
method rendered as `async def get_xxx(self, *args, **kwargs):` with
the decorator's source listing inline, instead of the method's real
signature and docstring. The recently-expanded docstrings (#237/#241)
existed in source but were never read by `inspect`-based tooling.

Fix:

- Import `functools`.
- Apply `@functools.wraps(func)` to the inner `wrapper`.

Regression tests in a new `TestRequireAuthenticationDecorator` class
lock in the three properties that need to survive: signature,
docstring, and `__name__`. Each would fail without `functools.wraps`.
@Olen Olen requested a review from Copilot May 14, 2026 14:29
@Olen Olen added the updateme Automatically update PR from main label May 14, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds @functools.wraps(func) to the require_authentication decorator so wrapped async methods retain their original signature, name, and docstring. This restores correct rendering on the pdoc-generated GitHub Pages site and improves IDE/inspect introspection.

Changes:

  • Import functools and apply @functools.wraps(func) to the inner wrapper in require_authentication.
  • Add a new TestRequireAuthenticationDecorator test class covering signature, docstring, and __name__ preservation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
spond/base.py Add functools import and @functools.wraps(func) on the require_authentication wrapper.
tests/test_spond.py Add three regression tests asserting the decorator preserves signature, docstring, and name.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Olen Olen merged commit db25ad7 into main May 14, 2026
11 checks passed
@Olen Olen deleted the fix/wraps-decorator branch May 14, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

updateme Automatically update PR from main

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants