Skip to content

Commit c520161

Browse files
committed
Merge branch 'main' into drop_fn_session_param
* main: Bump version to 0.7.1.9000 Fix input_task_button for modules (#1108) Bump version to 0.7.1 Test input task button and extended task decorator (#1099) Add remaining examples for express API reference (#1093) test: Add `make playwright-debug` to help debug playwright tests (#1097) Make input_selectize work correctly within a module (#1091) Update types to allow `navset_*` functions to accept `MetadataNode` args (#1094) Update changelog Update express.ui.hold() to accept any type of object (#1089)
2 parents 5a4f8e2 + fb8b587 commit c520161

File tree

122 files changed

+2454
-549
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+2454
-549
lines changed

CHANGELOG.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88

9-
## [UNRELEASED]
9+
## [UNRELEASED] - YYYY-MM-DD
10+
11+
### Bug fixes
12+
13+
* Fixed `input_task_button` not working in a Shiny module. (#1108)
14+
15+
16+
## [0.7.1] - 2024-02-05
17+
18+
### Bug fixes
1019

1120
* Fixed `render.download` not working in Express. (#1085)
1221

22+
* `express.ui.hold()` can now accept any type of object, instead of just `TagChild` objects. (#1089)
23+
24+
* Fixed an issue where `input_selectize` would not initialize correctly when created within a Shiny module. (#1091)
25+
1326

1427
## [0.7.0] - 2024-01-25
1528

@@ -56,12 +69,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5669
* `shiny.render.transformer.OutputRendererSync`
5770
* `shiny.render.transformer.OutputRendererAsync`
5871

59-
6072
### Other changes
6173

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

77+
6578
## [0.6.1.1] - 2023-12-22
6679

6780
### Bug fixes

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ playwright-deploys: install-playwright install-rsconnect ## end-to-end tests on
104104
playwright-examples: install-playwright ## end-to-end tests on examples with playwright
105105
pytest tests/playwright/examples/$(SUB_FILE)
106106

107+
playwright-debug: install-playwright ## All end-to-end tests, chrome only, headed
108+
pytest -c tests/playwright/playwright-pytest.ini tests/playwright/$(SUB_FILE)
109+
107110
testrail-junit: install-playwright install-trcli ## end-to-end tests with playwright and generate junit report
108111
pytest tests/playwright/shiny/$(SUB_FILE) --junitxml=report.xml
109112

docs/_quartodoc-core.yml

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -328,58 +328,6 @@ quartodoc:
328328
- types.SilentException
329329
- types.SilentCancelOutputException
330330
- types.SafeException
331-
- title: Shiny Express
332-
desc: Functions for Shiny Express applications
333-
contents:
334-
- kind: page
335-
path: ContextManagerComponents
336-
summary:
337-
name: "Context manager components"
338-
desc: ""
339-
flatten: true
340-
contents:
341-
- express.ui.sidebar
342-
- express.ui.layout_sidebar
343-
- express.ui.layout_column_wrap
344-
- express.ui.layout_columns
345-
- express.ui.card
346-
- express.ui.accordion
347-
- express.ui.accordion_panel
348-
- express.ui.nav_panel
349-
- express.ui.nav_control
350-
- express.ui.nav_menu
351-
- express.ui.navset_bar
352-
- express.ui.navset_card_pill
353-
- express.ui.navset_card_tab
354-
- express.ui.navset_card_underline
355-
- express.ui.navset_hidden
356-
- express.ui.navset_pill
357-
- express.ui.navset_pill_list
358-
- express.ui.navset_tab
359-
- express.ui.navset_underline
360-
- express.ui.value_box
361-
- express.ui.panel_title
362-
- express.ui.panel_well
363-
- express.ui.panel_conditional
364-
- express.ui.panel_fixed
365-
- express.ui.panel_absolute
366-
- kind: page
367-
path: PageFunctions
368-
summary:
369-
name: "Page functions"
370-
desc: ""
371-
flatten: true
372-
contents:
373-
- express.ui.page_opts
374-
- kind: page
375-
path: DisplayFunctions
376-
summary:
377-
name: "Display functions"
378-
desc: ""
379-
flatten: true
380-
contents:
381-
- express.ui.hold
382-
- express.expressify
383331
- title: Deprecated
384332
desc: ""
385333
contents:

docs/_renderer.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,6 @@ def read_file(file: str | Path, root_dir: str | Path | None = None) -> FileConte
271271

272272

273273
def check_if_missing_expected_example(el, converted):
274-
if os.environ.get("SHINY_MODE", "core") == "express":
275-
# TODO: remove once we are done porting express examples
276-
return
277-
278274
if re.search(r"(^|\n)#{2,6} Examples\n", converted):
279275
# Manually added examples are fine
280276
return
@@ -287,7 +283,12 @@ def is_no_ex_decorator(x):
287283
if x == "no_example()":
288284
return True
289285

290-
return x == f'no_example("{os.environ.get("SHINY_MODE", "core")}")'
286+
no_ex_decorators = [
287+
f'no_example("{os.environ.get("SHINY_MODE", "core")}")',
288+
f"no_example('{os.environ.get('SHINY_MODE', 'core')}')",
289+
]
290+
291+
return x in no_ex_decorators
291292

292293
if hasattr(el, "decorators") and any(
293294
[is_no_ex_decorator(d.value.canonical_name) for d in el.decorators]
@@ -304,8 +305,7 @@ def is_no_ex_decorator(x):
304305
# In practice, this covers methods of exported classes (class still needs ex)
305306
return
306307

307-
# TODO: Remove shiny.express from no_req_examples when we have examples ready
308-
no_req_examples = ["shiny.express", "shiny.experimental"]
308+
no_req_examples = ["shiny.experimental"]
309309
if any([el.target_path.startswith(mod) for mod in no_req_examples]):
310310
return
311311

pytest.ini

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,3 @@ testpaths=tests/pytest/
44
; ; Debug version of options
55
; addopts = --strict-markers --durations=6 --durations-min=5.0 --browser chromium --numprocesses auto --video=retain-on-failure -vv
66
addopts = --strict-markers --durations=6 --durations-min=5.0 --browser webkit --browser firefox --browser chromium --numprocesses auto
7-
markers =
8-
examples: Suite of tests to validate that examples do not produce errors (deselect with '-m "not examples"')
9-
integrationtest: Suite of tests that check deploys and integration with other services (deselect with '-m "not integrationtest"')

shiny/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""A package for building reactive web applications."""
22

3-
__version__ = "0.7.0.9000"
3+
__version__ = "0.7.1.9000"
44

55
from ._shinyenv import is_pyodide as _is_pyodide
66

shiny/_docstring.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ def _(func: F) -> F:
138138
app_file_name = app_file or "app.py"
139139
try:
140140
example_file = app_choose_core_or_express(
141-
os.path.join(example_dir, app_file_name)
141+
os.path.join(example_dir, app_file_name),
142+
mode="express" if "shiny/express/" in func_dir else None,
142143
)
143144
except ExampleNotFoundException as e:
144145
file = "shiny/" + func_dir.split("shiny/")[1]
@@ -248,10 +249,17 @@ def __init__(
248249
super().__init__(file_names, dir, "express")
249250

250251

251-
def app_choose_core_or_express(app_path: Optional[str] = None) -> str:
252+
def app_choose_core_or_express(
253+
app_path: Optional[str] = None,
254+
mode: Optional[Literal["express", "core"]] = None,
255+
) -> str:
252256
app_path = app_path or "app.py"
253257

254-
if os.environ.get("SHINY_MODE") == "express":
258+
if mode is None:
259+
mode_env = os.environ.get("SHINY_MODE", "core")
260+
mode = "express" if mode_env == "express" else "core"
261+
262+
if mode == "express":
255263
if is_express_app(app_path):
256264
return app_path
257265

shiny/api-examples/Renderer/app-core.py

Lines changed: 10 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,21 @@
11
from __future__ import annotations
22

3-
from typing import Literal, Optional
3+
# Import the custom renderer implementations
4+
from renderers import render_capitalize, render_upper
45

56
from shiny import App, Inputs, ui
6-
from shiny.render.renderer import Renderer, ValueFn
7-
8-
#######
9-
# Start of package author code
10-
#######
11-
12-
13-
class render_capitalize(Renderer[str]):
14-
# The documentation for the class will be displayed when the user hovers over the
15-
# decorator when **no** parenthesis are used. Ex: `@render_capitalize`
16-
# If no documentation is supplied to the `__init__()` method, then this
17-
# documentation will be displayed when parenthesis are used on the decorator.
18-
"""
19-
Render capitalize class documentation goes here.
20-
"""
21-
22-
to_case: Literal["upper", "lower", "ignore"]
23-
"""
24-
The case to render the value in.
25-
"""
26-
placeholder: bool
27-
"""
28-
Whether to render a placeholder value. (Defaults to `True`)
29-
"""
30-
31-
def auto_output_ui(self):
32-
"""
33-
Express UI for the renderer
34-
"""
35-
return ui.output_text_verbatim(self.output_name, placeholder=self.placeholder)
36-
37-
def __init__(
38-
self,
39-
_fn: Optional[ValueFn[str]] = None,
40-
*,
41-
to_case: Literal["upper", "lower", "ignore"] = "upper",
42-
placeholder: bool = True,
43-
) -> None:
44-
# If a different set of documentation is supplied to the `__init__` method,
45-
# then this documentation will be displayed when parenthesis are used on the decorator.
46-
# Ex: `@render_capitalize()`
47-
"""
48-
Render capitalize documentation goes here.
49-
50-
It is a good idea to talk about parameters here!
51-
52-
Parameters
53-
----------
54-
to_case
55-
The case to render the value. (`"upper"`)
56-
57-
Options:
58-
- `"upper"`: Render the value in upper case.
59-
- `"lower"`: Render the value in lower case.
60-
- `"ignore"`: Do not alter the case of the value.
61-
62-
placeholder
63-
Whether to render a placeholder value. (`True`)
64-
"""
65-
# Do not pass params
66-
super().__init__(_fn)
67-
self.to_case = to_case
68-
69-
async def render(self) -> str | None:
70-
value = await self.fn()
71-
if value is None:
72-
# If `None` is returned, then do not render anything.
73-
return None
74-
75-
ret = str(value)
76-
if self.to_case == "upper":
77-
return ret.upper()
78-
if self.to_case == "lower":
79-
return ret.lower()
80-
if self.to_case == "ignore":
81-
return ret
82-
raise ValueError(f"Invalid value for `to_case`: {self.to_case}")
83-
84-
85-
class render_upper(Renderer[str]):
86-
"""
87-
Minimal capitalize string transformation renderer.
88-
89-
No parameters are supplied to this renderer. This allows us to skip the `__init__()`
90-
method and `__init__()` documentation. If you hover over this decorator with and
91-
without parenthesis, you will see this documentation in both situations.
92-
93-
Note: This renderer is equivalent to `render_capitalize(to="upper")`.
94-
"""
95-
96-
def auto_output_ui(self):
97-
"""
98-
Express UI for the renderer
99-
"""
100-
return ui.output_text_verbatim(self.output_name, placeholder=True)
101-
102-
async def transform(self, value: str) -> str:
103-
"""
104-
Transform the value to upper case.
105-
106-
This method is shorthand for the default `render()` method. It is useful to
107-
transform non-`None` values. (Any `None` value returned by the app author will
108-
be forwarded to the browser.)
109-
110-
Parameters
111-
----------
112-
value
113-
The a non-`None` value to transform.
114-
115-
Returns
116-
-------
117-
str
118-
The transformed value. (Must be a subset of `Jsonifiable`.)
119-
"""
120-
121-
return str(value).upper()
122-
123-
124-
#######
125-
# End of package author code
126-
#######
127-
128-
129-
#######
130-
# Start of app author code
131-
#######
132-
133-
134-
def text_row(id: str, label: str):
135-
return ui.tags.tr(
136-
ui.tags.td(f"{label}:"),
137-
ui.tags.td(ui.output_text_verbatim(id, placeholder=True)),
138-
)
139-
return ui.row(
140-
ui.column(6, f"{id}:"),
141-
ui.column(6, ui.output_text_verbatim(id, placeholder=True)),
142-
)
143-
1447

1458
app_ui = ui.page_fluid(
1469
ui.h1("Capitalization renderer"),
14710
ui.input_text("caption", "Caption:", "Data summary"),
148-
ui.tags.table(
149-
text_row("upper", "@render_upper"),
150-
text_row("upper_with_paren", "@render_upper()"),
151-
#
152-
text_row("cap_upper", "@render_capitalize"),
153-
text_row("cap_lower", "@render_capitalize(to='lower')"),
154-
),
11+
"@render_upper: ",
12+
ui.output_text_verbatim("upper", placeholder=True),
13+
"@render_upper(): ",
14+
ui.output_text_verbatim("upper_with_paren", placeholder=True),
15+
"@render_capitalize: ",
16+
ui.output_text_verbatim("cap_upper", placeholder=True),
17+
"@render_capitalize(to='lower'): ",
18+
ui.output_text_verbatim("cap_lower", placeholder=True),
15519
)
15620

15721

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Import the custom renderer implementations
2+
from renderers import render_capitalize, render_upper
3+
4+
from shiny.express import input, ui
5+
6+
ui.h1("Capitalization renderer")
7+
ui.input_text("caption", "Caption:", "Data summary")
8+
9+
"@render_upper:"
10+
11+
12+
# Hovering over `@render_upper` will display the class documentation
13+
@render_upper
14+
def upper():
15+
return input.caption()
16+
17+
18+
"@render_upper():"
19+
20+
21+
# Hovering over `@render_upper` will display the class documentation as there is no
22+
# `__init__()` documentation
23+
@render_upper()
24+
def upper_with_paren():
25+
return input.caption()
26+
27+
28+
"@render_capitalize:"
29+
30+
31+
# Hovering over `@render_capitalize` will display the class documentation
32+
@render_capitalize
33+
def cap_upper():
34+
return input.caption()
35+
36+
37+
"@render_capitalize(to='lower'): "
38+
39+
40+
# Hovering over `@render_capitalize` will display the `__init__()` documentation
41+
@render_capitalize(to_case="lower")
42+
def cap_lower():
43+
return input.caption()

0 commit comments

Comments
 (0)