Skip to content

Commit

Permalink
Merge branch 'main' into drop_fn_session_param
Browse files Browse the repository at this point in the history
* main: (26 commits)
  api!: Merge RendererBase class into Renderer (#1032)
  chore(render.display): Improve error message (#1020)
  `express.ui.page_opts(title = ...)` now always generates a header (#1016)
  api!: `Renderer.auto_output_ui()` drops `id` arg. Make `RendererBase.output_id` a non-namespaced value. (#1030)
  fix(page_sidebar): Add semicolon to end style declaration (#1027)
  chore: Remove experimental from app (#1028)
  chore: Expose `render.renderer.RendererBaseT` and do not require `| None` when defining Renderer types (#1026)
  bug: Restore legacy renderers while packages transition (#1023)
  Update deploy test apps to use render.code
  Update changelog
  Provide useful message in Express when `input` was not imported (#994)
  Calculate coordinate mapping after drawing figure (#999)
  Remove `express.ui.output_*` functions, add `shiny.express.render` (#1018)
  fix: Do not allow for renderer's to be given to reactive effects (#1017)
  Truncate the requirements.txt file before deploys (#998)
  Update changelog
  Fixes for flake8 (#1012)
  Pin starlette version below 0.35 (#1009)
  Remove shiny express warning
  Cause RecallContextManagers to run when used without `with` (#992)
  ...
  • Loading branch information
schloerke committed Jan 19, 2024
2 parents fbe499d + 96a6279 commit 6e2ca05
Show file tree
Hide file tree
Showing 69 changed files with 1,374 additions and 873 deletions.
28 changes: 24 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [UNRELEASED]

### Breaking Changes

* Closed #938: `page_sidebar()` and `page_navbar()` now use `fillable=False` by default. (#990)

### New features

* Added `@render.download` as a replacement for `@session.download`, which is now deprecated. (#977)

* Added `ui.output_code()`, which is currently an alias for `ui.output_text_verbatim()`. (#997)

* Added `@render.code`, which is an alias for `@render.text`, but in Express mode, it displays the result using `ui.output_code()`. (#997)

### Bug fixes

* CLI command `shiny create`... (#965)
* has added a `-d`/`--dir` flag for saving to a specific output directory
* will raise an error if if will overwrite existing files
* prompt users to install `requirements.txt`

* Fixed `js-react` template build error. (#965)

* Fixed #1007: Plot interaction with plotnine provided incorrect values. (#999)

### Developer features

* Output renderers should now be created with the `shiny.render.renderer.Renderer` class. This class should contain either a `.transform(self, value)` method (common) or a `.render(self)` (rare). These two methods should return something can be converted to JSON. In addition, `.default_ui(self, id)` should be implemented by returning `htmltools.Tag`-like content for use within Shiny Express. To make your own output renderer, please inherit from the `Renderer[IT]` class where `IT` is the type (excluding `None`) required to be returned from the App author. (#964)
* Legacy renderers that will be removed in the near future:
* `shiny.render.RenderFunction`
* `shiny.render.RenderFunctionAsync`
* `shiny.render.transformer.OutputRenderer`
* `shiny.render.transformer.OutputRendererSync`
* `shiny.render.transformer.OutputRendererAsync`

* `shiny.render.RenderFunction` and `shiny.render.RenderFunctionAsync` have been removed. They were deprecated in v0.6.0. Instead, please use `shiny.render.renderer.Renderer`. (#964)

* When transforming values within `shiny.render.transformer.output_transformer` transform function, `shiny.render.transformer.resolve_value_fn` is no longer needed as the value function given to the output transformer is now **always** an asynchronous function. `resolve_value_fn(fn)` method has been deprecated. Please change your code from `value = await resolve_value_fn(_fn)` to `value = await _fn()`. (#964)

* `shiny.render.OutputRendererSync` and `shiny.render.OutputRendererAsync` helper classes have been removed in favor of an updated `shiny.render.OutputRenderer` class. Now, the app's output value function will be transformed into an asynchronous function for simplified, consistent execution behavior. If redesigning your code, instead please create a new renderer that inherits from `shiny.render.renderer.Renderer`. (#964)
### Other changes

* Pinned Starlette to version <0.35.0; versions 0.35.0 and 0.35.1 caused problems when deploying on Posit Connect. (#1009
)

## [0.6.1.1] - 2023-12-22

Expand Down
3 changes: 2 additions & 1 deletion docs/_quartodoc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ quartodoc:
- ui.output_table
- ui.output_data_frame
- ui.output_text
- ui.output_code
- ui.output_text_verbatim
- ui.output_ui
- render.plot
Expand All @@ -176,10 +177,10 @@ quartodoc:
desc: ""
contents:
- render.renderer.Renderer
- render.renderer.RendererBase
- render.renderer.Jsonifiable
- render.renderer.ValueFn
- render.renderer.AsyncValueFn
- render.renderer.RendererT
- title: Reactive programming
desc: ""
contents:
Expand Down
2 changes: 1 addition & 1 deletion examples/annotation-export/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def annotations():
df = df.loc[df["annotation"] != ""]
return df

@session.download(filename="data.csv")
@render.download(filename="data.csv")
def download():
yield annotated_data().to_csv()

Expand Down
2 changes: 1 addition & 1 deletion examples/cpuinfo/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def collect_cpu_samples():
combined_data = combined_data[:, -MAX_SAMPLES:]
cpu_history.set(combined_data)

@reactive.Effect(priority=100)
@reactive.effect(priority=100)
@reactive.event(input.reset)
def reset_history():
cpu_history.set(None)
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ setup_requires =
install_requires =
typing-extensions>=4.0.1
uvicorn>=0.16.0
starlette>=0.17.1
starlette>=0.17.1,<0.35.0
websockets>=10.0
python-multipart
htmltools>=0.5.1
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.6.1.9000"
__version__ = "0.6.1.9006"

from ._shinyenv import is_pyodide as _is_pyodide

Expand Down
4 changes: 2 additions & 2 deletions shiny/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def _step(fut: Optional["asyncio.Future[None]"] = None):
assert fut.done()
try:
fut.result()
except BaseException as e:
except BaseException as e: # noqa: B036
exc = e

if result_future.cancelled():
Expand All @@ -419,7 +419,7 @@ def _step(fut: Optional["asyncio.Future[None]"] = None):
except (KeyboardInterrupt, SystemExit) as e:
result_future.set_exception(e)
raise
except BaseException as e:
except BaseException as e: # noqa: B036
result_future.set_exception(e)
else:
# If we get here, the coro didn't finish. Schedule it for completion.
Expand Down
14 changes: 7 additions & 7 deletions shiny/api-examples/Renderer/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Literal
from typing import Literal, Optional

from shiny import App, Inputs, Outputs, Session, ui
from shiny.render.renderer import Renderer, ValueFn
Expand Down Expand Up @@ -28,15 +28,15 @@ class render_capitalize(Renderer[str]):
Whether to render a placeholder value. (Defaults to `True`)
"""

def default_ui(self, id: str):
def auto_output_ui(self):
"""
Express UI for the renderer
"""
return ui.output_text_verbatim(id, placeholder=self.placeholder)
return ui.output_text_verbatim(self.output_name, placeholder=self.placeholder)

def __init__(
self,
_fn: ValueFn[str | None] | None = None,
_fn: Optional[ValueFn[str]] | None = None,
*,
to_case: Literal["upper", "lower", "ignore"] = "upper",
placeholder: bool = True,
Expand Down Expand Up @@ -68,7 +68,7 @@ def __init__(
self.to_case = to_case

async def render(self) -> str | None:
value = await self.value_fn()
value = await self.fn()
if value is None:
# If `None` is returned, then do not render anything.
return None
Expand All @@ -94,11 +94,11 @@ class render_upper(Renderer[str]):
Note: This renderer is equivalent to `render_capitalize(to="upper")`.
"""

def default_ui(self, id: str):
def auto_output_ui(self):
"""
Express UI for the renderer
"""
return ui.output_text_verbatim(id, placeholder=True)
return ui.output_text_verbatim(self.output_name, placeholder=True)

async def transform(self, value: str) -> str:
"""
Expand Down
13 changes: 7 additions & 6 deletions shiny/api-examples/download/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import matplotlib.pyplot as plt
import numpy as np

from shiny import App, Inputs, Outputs, Session, ui
from shiny import App, Inputs, Outputs, Session, render, ui


def make_example(id: str, label: str, title: str, desc: str, extra: Any = None):
Expand Down Expand Up @@ -77,7 +77,7 @@ def make_example(id: str, label: str, title: str, desc: str, extra: Any = None):


def server(input: Inputs, output: Outputs, session: Session):
@session.download()
@render.download()
def download1():
"""
This is the simplest case. The implementation simply returns the name of a file.
Expand All @@ -88,12 +88,12 @@ def download1():
path = os.path.join(os.path.dirname(__file__), "mtcars.csv")
return path

@session.download(filename="image.png")
@render.download(filename="image.png")
def download2():
"""
Another way to implement a file download is by yielding bytes; either all at
once, like in this case, or by yielding multiple times. When using this
approach, you should pass a filename argument to @session.download, which
approach, you should pass a filename argument to @render.download, which
determines what the browser will name the downloaded file.
"""

Expand All @@ -107,7 +107,7 @@ def download2():
plt.savefig(buf, format="png")
yield buf.getvalue()

@session.download(
@render.download(
filename=lambda: f"新型-{date.today().isoformat()}-{np.random.randint(100,999)}.csv"
)
async def download3():
Expand All @@ -116,7 +116,8 @@ async def download3():
yield "新,1,2\n"
yield "型,4,5\n"

@session.download(id="download4", filename="failuretest.txt")
@output(id="download4")
@render.download(filename="failuretest.txt")
async def _():
yield "hello"
raise Exception("This error was caused intentionally")
Expand Down
9 changes: 4 additions & 5 deletions shiny/api-examples/download_button/app.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import asyncio
import random
from datetime import date

import numpy as np

from shiny import App, Inputs, Outputs, Session, ui
from shiny import App, Inputs, Outputs, Session, render, ui

app_ui = ui.page_fluid(
ui.download_button("downloadData", "Download"),
)


def server(input: Inputs, output: Outputs, session: Session):
@session.download(
filename=lambda: f"新型-{date.today().isoformat()}-{np.random.randint(100,999)}.csv"
@render.download(
filename=lambda: f"新型-{date.today().isoformat()}-{random.randint(100,999)}.csv"
)
async def downloadData():
await asyncio.sleep(0.25)
Expand Down
9 changes: 4 additions & 5 deletions shiny/api-examples/download_link/app.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import asyncio
import random
from datetime import date

import numpy as np

from shiny import App, Inputs, Outputs, Session, ui
from shiny import App, Inputs, Outputs, Session, render, ui

app_ui = ui.page_fluid(
ui.download_link("downloadData", "Download"),
)


def server(input: Inputs, output: Outputs, session: Session):
@session.download(
filename=lambda: f"新型-{date.today().isoformat()}-{np.random.randint(100,999)}.csv"
@render.download(
filename=lambda: f"新型-{date.today().isoformat()}-{random.randint(100,999)}.csv"
)
async def downloadData():
await asyncio.sleep(0.25)
Expand Down
20 changes: 20 additions & 0 deletions shiny/api-examples/input_action_button/app-express.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import matplotlib.pyplot as plt
import numpy as np

from shiny import reactive, render
from shiny.express import input, ui

ui.input_slider("n", "Number of observations", min=0, max=1000, value=500)
ui.input_action_button("go", "Go!", class_="btn-success")


@render.plot(alt="A histogram")
# Use reactive.event() to invalidate the plot only when the button is pressed
# (not when the slider is changed)
@reactive.event(input.go, ignore_none=False)
def plot():
np.random.seed(19680801)
x = 100 + 15 * np.random.randn(input.n())
fig, ax = plt.subplots()
ax.hist(x, bins=30, density=True)
return fig
5 changes: 3 additions & 2 deletions shiny/express/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@
# console.
from ..session import Inputs as _Inputs, Outputs as _Outputs, Session as _Session
from ..session import _utils as _session_utils
from .. import render
from . import ui
from ._is_express import is_express_app
from ._output import ( # noqa: F401
ui_kwargs,
suspend_display,
output_args, # pyright: ignore[reportUnusedImport]
)
from ._run import wrap_express_app
from .display_decorator import display_body


__all__ = (
"render",
"input",
"output",
"session",
"is_express_app",
"ui_kwargs",
"suspend_display",
"wrap_express_app",
"ui",
Expand Down
Loading

0 comments on commit 6e2ca05

Please sign in to comment.