Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
f802db2
First pass at creating a renderer generator to handle boilerplate and…
schloerke Jul 13, 2023
7ee4db0
Create test_renderer_gen.py
schloerke Jul 13, 2023
52b77bd
Create e2e test app that tests renderer_gen in sync/async and with/wi…
schloerke Jul 13, 2023
c0264ca
Add missing return statement
schloerke Jul 13, 2023
40a18f1
Ignore duckdb data files
schloerke Jul 13, 2023
db57352
Update TODOs
schloerke Jul 13, 2023
40b6421
Naturally export RenderFunctionMeta
schloerke Jul 13, 2023
4a82f0f
Reduce number of Render classes. Have `RendererMeta` class be supplie…
schloerke Jul 14, 2023
8834255
Require users to use `None` when describing `IT` and `OT`
schloerke Jul 14, 2023
7b8abf7
Do not allow args to be named `_render_fn`. Break up test into many t…
schloerke Jul 14, 2023
87fc09f
Get ParamSpec and Concatenate from typing extensions
schloerke Jul 14, 2023
4f69268
Legacy typing lints
schloerke Jul 14, 2023
be7d0b5
Add TODOs
schloerke Jul 17, 2023
5add579
Merge branch 'main' into renderer_gen
schloerke Jul 24, 2023
b36c893
Rework names; Have the handler function receive the render function f…
schloerke Jul 25, 2023
b45880b
Minimize the number of generic variables in the classes. Add helper c…
schloerke Jul 25, 2023
d3a3b20
temp commit to save thoughts before destroying them. Could not get ov…
schloerke Jul 26, 2023
46c1cc9
Another temp commit in messy state. Using classes as return type to hide
schloerke Jul 28, 2023
7bf7267
Using helper method approach to function and types for the user to ma…
schloerke Jul 28, 2023
3179506
Save state again before we start dropping code in favor of using over…
schloerke Jul 31, 2023
0ab8d4a
Save state again. Lots of code as been chopped and it is a good break…
schloerke Jul 31, 2023
ad1d285
Clean up renderer components. Add some docs (needs more)
schloerke Aug 1, 2023
5c7c418
Rename files
schloerke Aug 1, 2023
4444e71
Docs. Still more docs to come
schloerke Aug 1, 2023
daae487
More docs and an example app
schloerke Aug 2, 2023
d900a17
Add comment about `RendererParams`'s `args` field
schloerke Aug 2, 2023
aa5b897
Add comments explaining `RenderFn` and `HandlerFn`
schloerke Aug 2, 2023
64f8f02
Remove comment
schloerke Aug 2, 2023
e7b64e4
Remove `__doc__` param
schloerke Aug 2, 2023
7a7da17
Make `.meta` property into `._meta()` method
schloerke Aug 2, 2023
b5ecaf3
Drop unnecessary `*_` arg
schloerke Aug 2, 2023
ba43bcf
Make `_is_async` property into `_is_async()` method
schloerke Aug 2, 2023
ff81342
Remove newline escape
schloerke Aug 2, 2023
a2a8c28
Remove unnecessary async wrap
schloerke Aug 2, 2023
df843d0
Update comment about async render_fn function in RendererRun
schloerke Aug 2, 2023
05e93e7
Merger `RendererRun` into `Renderer`. Use ABC to mark some methods as…
schloerke Aug 2, 2023
649ab43
Merge branch 'main' into renderer_gen
schloerke Aug 2, 2023
913b403
better comment about which variables are found during imports
schloerke Aug 2, 2023
c71c530
typing lints
schloerke Aug 2, 2023
ae5c1b7
Implement methods for `RenderFunction` and `RenderFunctionAsync`
schloerke Aug 3, 2023
6fc0980
Docs / comments
schloerke Aug 3, 2023
22ed3bf
Add changelog entry
schloerke Aug 3, 2023
322bb0e
Bump to dev version: 0.5.0.9000
schloerke Aug 3, 2023
4e568a9
Partial code review changes
wch Aug 4, 2023
f5cda40
Add test for having an async handler?
schloerke Aug 7, 2023
cffeafb
Merge branch 'renderer_gen' of https://github.com/rstudio/py-shiny in…
schloerke Aug 7, 2023
5ee0500
Make transformer methods consistent. Make `.impl` into `.__call__`
schloerke Aug 7, 2023
1c2a451
Skip impossible test
schloerke Aug 7, 2023
db66eee
Hide test so that pylance doesn't get confused
schloerke Aug 8, 2023
fc02a24
parentheses and type comment
schloerke Aug 8, 2023
99bf57e
Move transformer methods to `shiny.render.transformer` folder
schloerke Aug 8, 2023
8bb6aa6
Restore `shiny.render.__init__` import structure and import transform…
schloerke Aug 8, 2023
de0f5de
Fix broken imports
schloerke Aug 8, 2023
228650b
Test truely async transformer functions
schloerke Aug 8, 2023
d4015b6
Documentation; Partial: Remove `is_async` from meta info. Supply unca…
schloerke Aug 9, 2023
39afa5c
Mark random port test as flaky
schloerke Aug 9, 2023
caa861e
Cleanup files. Implement `_fn` as `ValueFn[IT]` (not `ValueFnAsync[IT…
schloerke Aug 9, 2023
296e8ff
Add output transformer docs
schloerke Aug 9, 2023
34fb8a8
Merge branch 'main' into renderer_gen
schloerke Aug 9, 2023
0213e98
More documentation. More to go
schloerke Aug 9, 2023
2e7fcb8
doc tweaks
schloerke Aug 10, 2023
9c532d6
Update app.py
schloerke Aug 10, 2023
eb1d454
Update test_output_transformer.py
schloerke Aug 10, 2023
cd939a0
Expose `ValueFn`
schloerke Aug 10, 2023
57afd26
Remove comment about `from __future__ import annotations`
schloerke Aug 10, 2023
4f4ee56
spelling
schloerke Aug 10, 2023
88a75c0
Speed up tests
schloerke Aug 10, 2023
f9486c5
Apply suggestions from code review
schloerke Aug 10, 2023
0505dcd
Merge branch 'renderer_gen' of https://github.com/rstudio/py-shiny in…
schloerke Aug 10, 2023
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [UNRELEASED]

### New features

* Added `shiny.render.renderer_components` decorator to help create new output renderers. (#621)

### Bug fixes

### Other changes


## [0.5.1] - 2023-08-08

### Bug fixes
Expand Down
24 changes: 21 additions & 3 deletions docs/_quartodoc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,24 @@ quartodoc:
- render.data_frame
- render.DataGrid
- render.DataTable
- kind: page
path: OutputRender
flatten: true
summary:
name: "Create rendering outputs"
desc: ""
contents:
- render.transformer.output_transformer
- render.transformer.OutputTransformer
- render.transformer.TransformerMetadata
- render.transformer.TransformerParams
- render.transformer.OutputRenderer
- render.transformer.OutputRendererSync
- render.transformer.OutputRendererAsync
- render.transformer.is_async_callable
- render.transformer.resolve_value_fn
- render.transformer.ValueFn
- render.transformer.TransformFn
- title: Reactive programming
desc: ""
contents:
Expand Down Expand Up @@ -178,7 +196,7 @@ quartodoc:
desc: ""
contents:
- kind: page
path: MiscTypes.html
path: MiscTypes
flatten: true
summary:
name: "Miscellaneous types"
Expand All @@ -192,7 +210,7 @@ quartodoc:
- ui._input_slider.SliderValueArg
- ui._input_slider.SliderStepArg
- kind: page
path: TagTypes.html
path: TagTypes
summary:
name: "Tag types"
desc: ""
Expand All @@ -205,7 +223,7 @@ quartodoc:
- htmltools.TagChild
- htmltools.TagList
- kind: page
path: ExceptionTypes.html
path: ExceptionTypes
summary:
name: "Exception types"
desc: ""
Expand Down
4 changes: 2 additions & 2 deletions e2e/inputs/test_input_checkbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_input_checkbox_kitchen(page: Page, app: ShinyAppProc) -> None:
somevalue.expect_checked(False)
somevalue.expect_width(None)

# TODO-karan test output value
# TODO-karan: test output value

somevalue.set(True)

Expand All @@ -28,4 +28,4 @@ def test_input_checkbox_kitchen(page: Page, app: ShinyAppProc) -> None:
somevalue.toggle()
somevalue.expect_checked(True)

# TODO-karan test output value
# TODO-karan: test output value
105 changes: 105 additions & 0 deletions e2e/server/output_transformer/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from __future__ import annotations

from typing import Optional, overload

from shiny import App, Inputs, Outputs, Session, ui
from shiny.render.transformer import (
TransformerMetadata,
ValueFn,
is_async_callable,
output_transformer,
resolve_value_fn,
)


@output_transformer
async def TestTextTransformer(
_meta: TransformerMetadata,
_fn: ValueFn[str | None],
*,
extra_txt: Optional[str] = None,
) -> str | None:
value = await resolve_value_fn(_fn)
value = str(value)
value += "; "
value += "async" if is_async_callable(_fn) else "sync"
if extra_txt:
value = value + "; " + str(extra_txt)
return value


@overload
def render_test_text(
*, extra_txt: Optional[str] = None
) -> TestTextTransformer.OutputRendererDecorator:
...


@overload
def render_test_text(
_fn: TestTextTransformer.ValueFn,
) -> TestTextTransformer.OutputRenderer:
...


def render_test_text(
_fn: TestTextTransformer.ValueFn | None = None,
*,
extra_txt: Optional[str] = None,
) -> TestTextTransformer.OutputRenderer | TestTextTransformer.OutputRendererDecorator:
return TestTextTransformer(
_fn,
TestTextTransformer.params(extra_txt=extra_txt),
)


app_ui = ui.page_fluid(
ui.code("t1:"),
ui.output_text_verbatim("t1"),
ui.code("t2:"),
ui.output_text_verbatim("t2"),
ui.code("t3:"),
ui.output_text_verbatim("t3"),
ui.code("t4:"),
ui.output_text_verbatim("t4"),
ui.code("t5:"),
ui.output_text_verbatim("t5"),
ui.code("t6:"),
ui.output_text_verbatim("t6"),
)


def server(input: Inputs, output: Outputs, session: Session):
@output
@render_test_text
def t1():
return "t1; no call"
# return "hello"

@output
@render_test_text
async def t2():
return "t2; no call"

@output
@render_test_text()
def t3():
return "t3; call"

@output
@render_test_text()
async def t4():
return "t4; call"

@output
@render_test_text(extra_txt="w/ extra_txt")
def t5():
return "t5; call"

@output
@render_test_text(extra_txt="w/ extra_txt")
async def t6():
return "t6; call"


app = App(app_ui, server)
14 changes: 14 additions & 0 deletions e2e/server/output_transformer/test_output_transformer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from conftest import ShinyAppProc
from controls import OutputTextVerbatim
from playwright.sync_api import Page


def test_output_image_kitchen(page: Page, local_app: ShinyAppProc) -> None:
page.goto(local_app.url)

OutputTextVerbatim(page, "t1").expect_value("t1; no call; sync")
OutputTextVerbatim(page, "t2").expect_value("t2; no call; async")
OutputTextVerbatim(page, "t3").expect_value("t3; call; sync")
OutputTextVerbatim(page, "t4").expect_value("t4; call; async")
OutputTextVerbatim(page, "t5").expect_value("t5; call; sync; w/ extra_txt")
OutputTextVerbatim(page, "t6").expect_value("t6; call; async; w/ extra_txt")
1 change: 0 additions & 1 deletion examples/event/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ def btn() -> int:
def _():
print("@calc() event: ", str(btn()))

@output
@render.ui
@reactive.event(input.btn)
def btn_value():
Expand Down
2 changes: 1 addition & 1 deletion shiny/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""A package for building reactive web applications."""

__version__ = "0.5.1"
__version__ = "0.5.1.9000"

from ._shinyenv import is_pyodide as _is_pyodide

Expand Down
8 changes: 4 additions & 4 deletions shiny/_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ def render_ui():
return render.ui()


def render_plot(*args: Any, **kwargs: Any):
def render_plot(*args: Any, **kwargs: Any): # type: ignore
"""Deprecated. Please use render.plot() instead of render_plot()."""
warn_deprecated("render_plot() is deprecated. Use render.plot() instead.")
return render.plot(*args, **kwargs)
return render.plot(*args, **kwargs) # type: ignore


def render_image(*args: Any, **kwargs: Any):
def render_image(*args: Any, **kwargs: Any): # type: ignore
"""Deprecated. Please use render.image() instead of render_image()."""
warn_deprecated("render_image() is deprecated. Use render.image() instead.")
return render.image(*args, **kwargs)
return render.image(*args, **kwargs) # type: ignore


def event(*args: Any, **kwargs: Any):
Expand Down
22 changes: 19 additions & 3 deletions shiny/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,23 @@ async def fn_async(*args: P.args, **kwargs: P.kwargs) -> T:
return fn_async


# This function should generally be used in this code base instead of
# `iscoroutinefunction()`.
def is_async_callable(
obj: Callable[P, T] | Callable[P, Awaitable[T]]
) -> TypeGuard[Callable[P, Awaitable[T]]]:
"""
Returns True if `obj` is an `async def` function, or if it's an object with a
`__call__` method which is an `async def` function. This function should generally
be used in this code base instead of iscoroutinefunction().
Determine if an object is an async function.

This is a more general version of `inspect.iscoroutinefunction()`, which only works
on functions. This function works on any object that has a `__call__` method, such
as a class instance.

Returns
-------
:
Returns True if `obj` is an `async def` function, or if it's an object with a
`__call__` method which is an `async def` function.
"""
if inspect.iscoroutinefunction(obj):
return True
Expand All @@ -262,6 +272,12 @@ def is_async_callable(
return False


# def not_is_async_callable(
# obj: Callable[P, T] | Callable[P, Awaitable[T]]
# ) -> TypeGuard[Callable[P, T]]:
# return not is_async_callable(obj)


# See https://stackoverflow.com/a/59780868/412655 for an excellent explanation
# of how this stuff works.
# For a more in-depth explanation, see
Expand Down
Loading