Skip to content

[utils] preserve method metadata in apply_forward_hook - #13803

Merged
sayakpaul merged 4 commits into
huggingface:mainfrom
javierdejesusda:fix/apply-forward-hook-preserves-metadata
Oct 14, 2026
Merged

sayakpaul merged 4 commits into
huggingface:mainfrom
javierdejesusda:fix/apply-forward-hook-preserves-metadata

Conversation

@javierdejesusda

@javierdejesusda javierdejesusda commented May 24, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #6575

apply_forward_hook returns an inner wrapper that doesn't use functools.wraps. When accelerate 0.17 or newer is installed, every method it decorates (37 files in src/diffusers/ use it, mostly on encode/decode) loses its __name__ and __doc__, has no __wrapped__, and reports the signature (self, *args, **kwargs). inspect.signature, help() and doc-builder all see wrapper, so with accelerate installed doc-builder's autodoc renders AutoencoderKL.encode/decode as wrapper(*args, **kwargs), with no docstring and a source link to accelerate_utils.py.

The hosted v0.39.0 docs still show them that way. The v0.40.0 and main docs render them correctly because #14131 moved the doc build to doc-builder's light install, which doesn't install accelerate, so the decorator returns the method unchanged there. apply_forward_hook on main still doesn't use functools.wraps.

This adds @functools.wraps(method) to wrapper. An accelerate pre_forward hook still fires on encode/decode calls, same as on main.

With accelerate installed:

# main
AutoencoderKL.decode.__name__                 == "wrapper"
AutoencoderKL.decode.__doc__                  is None
hasattr(AutoencoderKL.decode, "__wrapped__")  == False
inspect.signature(AutoencoderKL.decode)       == (self, *args, **kwargs)

# this PR
AutoencoderKL.decode.__name__                 == "decode"
AutoencoderKL.decode.__doc__                  starts with "Decode a batch of images."
hasattr(AutoencoderKL.decode, "__wrapped__")  == True
inspect.signature(AutoencoderKL.decode)       == (self, z: torch.FloatTensor, return_dict: bool = True, generator=None) -> DecoderOutput | torch.FloatTensor

Coordination: in #6575, stevhliu linked the @apply_forward_hook line above AutoencoderKL.decode and wrote "I think the line here may be giving the doc-builder some hiccups when parsing the file, but I'm not entirely sure." On this PR, his review said "nice, thanks for this!" and left the call on whether to keep the test to sayakpaul.

Tests

TestApplyForwardHook in tests/others/test_utils.py checks that a decorated function keeps its __name__ and __doc__. It only catches a missing functools.wraps when accelerate is installed: without accelerate, apply_forward_hook returns the function unchanged and the test passes with or without the fix. The "Fast tests for PRs" workflow installs accelerate and runs tests/others.

Run with Python 3.11, torch 2.8.0 and accelerate 1.15.0:

$ pytest tests/others/test_utils.py::TestApplyForwardHook    # main (916a5791e) with only this test added
E       AssertionError: assert 'wrapper' == 'example'
1 failed

$ pytest tests/others/test_utils.py::TestApplyForwardHook    # this branch
1 passed

$ pytest tests/others/test_utils.py
25 passed, 1 skipped

$ pytest -n 4 tests/models/autoencoders/test_models_autoencoder_kl.py tests/models/autoencoders/test_models_consistency_decoder_vae.py tests/models/autoencoders/test_models_vq.py tests/models/autoencoders/test_models_autoencoder_tiny.py tests/models/autoencoders/test_models_asymmetric_autoencoder_kl.py tests/hooks/test_hooks.py tests/hooks/test_group_offloading.py
113 passed, 206 skipped    # same counts on main

$ make quality
All checks passed!
2138 files already formatted

Claude was used to review this change.

Who can review?

@stevhliu @sayakpaul

Add @functools.wraps to the inner wrapper so it inherits __name__,
__doc__, __module__ and the signature of the wrapped method. Without
this, methods decorated with @apply_forward_hook (e.g. AutoencoderKL's
encode and decode) lose their docstring and signature, so doc-builder
cannot render them through the [[autodoc]] directive and they show up
as "wrapper" with a generic (*args, **kwargs) signature on the live
API docs. The same affects VQModel, ConsistencyDecoderVAE and the
other autoencoders that use the decorator.

Add regression tests asserting that the wrapped method exposes the
right metadata (name, docstring, signature including default values,
__wrapped__) and that the underlying offload hook still fires through
the wrapper.

Fixes huggingface#6575
@javierdejesusda
javierdejesusda force-pushed the fix/apply-forward-hook-preserves-metadata branch from 9d4632e to fbdae29 Compare May 24, 2026 23:23
@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@stevhliu stevhliu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice, thanks for this! imo seems a bit much to add a test for this simple fix, but i'll defer to @sayakpaul on whether we need to include this

@javierdejesusda

Copy link
Copy Markdown
Contributor Author

Happy to defer on the test. I only added it because the #6575 breakage was silent: call-time behaviour was always fine, it only showed up in inspect.signature/doc-builder, so a functional test wouldn't catch a regression if functools.wraps gets dropped later. That said, it's a 2-line fix, so I'm happy to keep it as-is, trim it to a single minimal assertion, or drop it entirely, whatever you and @sayakpaul prefer.

@javierdejesusda

Copy link
Copy Markdown
Contributor Author

@sayakpaul I've updated the branch with main and trimmed the test down to a single minimal check (the wrapped method keeps its __name__ and __doc__), as @stevhliu suggested. Ready for review whenever you have a moment.

@javierdejesusda

Copy link
Copy Markdown
Contributor Author

@sayakpaul I merged main again to fix the conflict in tests/others/test_utils.py (#14792 added a test class in the same spot, so I kept both) and corrected the description. The test is still the trimmed single check from before, after stevhliu's note that a test seemed a bit much for this fix. Happy to drop it if you'd prefer.

@sayakpaul
sayakpaul merged commit 08d6977 into huggingface:main Oct 14, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing methods of AutoencoderKL in online docs

4 participants