fix: Validate that reactive and render decorated functions have no required parameters#2200
Merged
schloerke merged 6 commits intoposit-dev:mainfrom Mar 26, 2026
Merged
Conversation
…quired parameters Add runtime validation to @reactive.calc, @reactive.effect, and @render.* decorators that raises TypeError when the decorated function has required parameters. Reactive and render functions should take no arguments. Closes posit-dev#1819 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
schloerke
requested changes
Mar 26, 2026
Collaborator
schloerke
left a comment
There was a problem hiding this comment.
@mvanhorn Thank you (and Claude)! 😅
Request:
- If default parameters are supplied, could we also display a "anti-pattern" warning?
- This will help steer users away from adding parameters that will never be leveraged... Or to wrap their functions in lambda to clearly define the contract.
- In the future, we could turn it into an error. 1 year?
- Add a CHANGELOG.md entry
Add a UserWarning in validate_no_params when functions have parameters with default values, since Shiny never supplies arguments to reactive or render decorated functions. Also add comprehensive unit tests for validate_no_params covering all logic paths (skip_names, var args, error/warning messages) and a CHANGELOG entry. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a `stacklevel` keyword argument so callers with deeper call stacks can point warnings at the correct user code frame. Also add a `_shiny_params_validated` flag on validated functions to prevent duplicate warnings when decorators are stacked (e.g., @reactive.poll internally uses @reactive.calc via @functools.wraps). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass stacklevel=5 from Calc_.__init__ and Effect_.__init__ so
warnings point to user code, not internal create_calc/create_effect.
- Pass stacklevel=5 from Renderer.__call__ to account for the extra
frame through subclass __init__ -> super().__init__ -> self(_fn).
- Use f"render.{type(self).__name__}" so error/warning messages say
@render.text instead of @text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend validate_no_params coverage to all decorators that expect zero-argument functions: - reactive.poll (in wrapper) - reactive.file_reader (in wrapper) - reactive.event (in decorator) - render.download (in __call__, which overrides Renderer.__call__ and bypasses the base class validation) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…edup - Stacklevel tests for all 7 callsites verifying warnings point to the correct user file - Render prefix tests for error and warning messages - fn.__name__ in warning suggestion text - Validation tests (reject/accept/warn) for reactive.event, reactive.poll, reactive.file_reader, and render.download - Stacked decorator tests verifying exactly one warning when @calc/@effect is combined with @event, and when @poll/@file_reader internally chains through @reactive.calc Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Collaborator
|
** Implementing my requests. Yay Claude |
Collaborator
|
Thank you, @mvanhorn ! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds runtime validation to
@reactive.calc,@reactive.effect, and@render.*decorators to raise a clearTypeErrorwhen the decorated function has required parameters. These decorators expect zero-argument functions.Why this matters
Users who forget to remove parameters from their decorated functions get confusing runtime errors later (e.g., missing argument errors during reactive flush). This validation catches the mistake at decoration time with a clear message like:
@reactive.calc expected a function with no required parameters, but my_func() has required parameter(s): x, y.Per #1819, this is a common mistake for users who don't enable type checking.
Changes
shiny/_utils.py: Addedvalidate_no_params(fn, decorator_name)utility usinginspect.signature(). Accepts functions with*args,**kwargs, or default-valued parameters.shiny/reactive/_reactives.py: Added validation toCalc_.__init__andEffect_.__init__shiny/render/renderer/_renderer.py: Added validation toRenderer.__call__tests/pytest/test_reactives.py: 6 tests covering calc/effect with required params, no params, and default paramstests/pytest/test_renderer.py: 3 tests covering render.text with the same patternsTesting
Added 9 unit tests. Run with
pytest tests/pytest/test_reactives.py tests/pytest/test_renderer.py.Fixes #1819
This contribution was developed with AI assistance (Claude Code).