Skip to content

Commit 45afeea

Browse files
authored
Merge branch 'main' into feat/current_output_id
2 parents 4de9a7f + 5653bdb commit 45afeea

File tree

118 files changed

+3543
-2875
lines changed

Some content is hidden

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

118 files changed

+3543
-2875
lines changed

.github/py-shiny/setup/action.yaml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ inputs:
44
python-version:
55
description: 'Python version to use'
66
required: false
7-
default: "3.12"
7+
default: "3.13"
88
runs:
99
using: "composite"
1010
steps:
@@ -39,12 +39,6 @@ runs:
3939
run: |
4040
make ci-install-wheel
4141
42-
- name: Install backports.tarfile
43-
if: ${{ startsWith(inputs.python-version, '3.8') }}
44-
shell: bash
45-
run: |
46-
uv pip install backports.tarfile
47-
4842
- name: Pip list
4943
shell: bash
5044
run: |

.github/workflows/build-docs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
18-
python-version: ["3.12"]
18+
python-version: ["3.13"]
1919
fail-fast: false
2020

2121
steps:

.github/workflows/pytest.yaml

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ jobs:
1717
strategy:
1818
matrix:
1919
# "3.10" must be a string; otherwise it is interpreted as 3.1.
20-
python-version: ["3.12", "3.11", "3.10", "3.9"]
20+
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"]
2121
os: [ubuntu-latest, windows-latest, macOS-latest]
2222
exclude:
23+
- python-version: ${{ github.event.pull_request.draft && '3.12' }}
2324
- python-version: ${{ github.event.pull_request.draft && '3.11' }}
2425
- python-version: ${{ github.event.pull_request.draft && '3.10' }}
2526
- python-version: ${{ github.event.pull_request.draft && '3.9' }}
@@ -73,7 +74,7 @@ jobs:
7374
with:
7475
fetch-depth: 0
7576
- name: "Set up Python 3.10"
76-
uses: actions/setup-python@v4
77+
uses: actions/setup-python@v5
7778
with:
7879
python-version: "3.10"
7980
- name: Install dependencies
@@ -107,18 +108,17 @@ jobs:
107108
runs-on: ubuntu-latest
108109
strategy:
109110
matrix:
110-
python-version: ["3.12", "3.11", "3.10", "3.9"]
111+
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"]
111112
browser: ["chromium", "firefox", "webkit"]
112113
exclude:
114+
- python-version: ${{ github.event.pull_request.draft && '3.12' }}
113115
- python-version: ${{ github.event.pull_request.draft && '3.11' }}
114116
- python-version: ${{ github.event.pull_request.draft && '3.10' }}
115117
- python-version: ${{ github.event.pull_request.draft && '3.9' }}
116118
- browser: ${{ github.event.pull_request.draft && 'firefox' }}
117119
- browser: ${{ github.event.pull_request.draft && 'webkit' }}
118120
# There are many unexplained tests that fail on webkit w/ python 3.8, 3.9
119121
# Given the more recent versions of python work, we will exclude this combination
120-
- browser: "webkit"
121-
python-version: "3.8"
122122
- browser: "webkit"
123123
python-version: "3.9"
124124
fail-fast: false
@@ -157,9 +157,10 @@ jobs:
157157
runs-on: ubuntu-latest
158158
strategy:
159159
matrix:
160-
python-version: ["3.12", "3.11", "3.10", "3.9"]
160+
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"]
161161
browser: ["chromium", "firefox", "webkit"]
162162
exclude:
163+
- python-version: ${{ github.event.pull_request.draft && '3.12' }}
163164
- python-version: ${{ github.event.pull_request.draft && '3.11' }}
164165
- python-version: ${{ github.event.pull_request.draft && '3.10' }}
165166
- python-version: ${{ github.event.pull_request.draft && '3.9' }}
@@ -193,6 +194,17 @@ jobs:
193194
working-directory: examples/brownian/shinymediapipe
194195
run: |
195196
npm ci
197+
- name: Checkout py-shiny-templates repository
198+
uses: actions/checkout@v4
199+
with:
200+
repository: posit-dev/py-shiny-templates
201+
path: py-shiny-templates
202+
203+
- name: Install py-shiny-templates dependencies
204+
if: matrix.python-version != '3.9'
205+
# Scikit-learn 1.7.0+ requires Python 3.10+
206+
run: |
207+
make ci-install-py-shiny-templates-deps
196208
197209
- name: Run example app tests
198210
timeout-minutes: 60
@@ -210,9 +222,10 @@ jobs:
210222
runs-on: ubuntu-latest
211223
strategy:
212224
matrix:
213-
python-version: ["3.12", "3.11", "3.10", "3.9"]
225+
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"]
214226
browser: ["chromium", "firefox", "webkit"]
215227
exclude:
228+
- python-version: ${{ github.event.pull_request.draft && '3.12' }}
216229
- python-version: ${{ github.event.pull_request.draft && '3.11' }}
217230
- python-version: ${{ github.event.pull_request.draft && '3.10' }}
218231
- python-version: ${{ github.event.pull_request.draft && '3.9' }}

CHANGELOG.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### New features
1111

12-
* The `.output_*()` methods of the `ClientData` class (e.g., `session.clientdata.output_height()`) can now be called without an `id` inside a output renderer. (#1978)
12+
* Added support for python 3.13. (#1711)
13+
14+
* `ui.sidebar()` is now interactively resizable. (#2020)
15+
16+
* `ui.update_*()` functions now accept `ui.TagChild` (i.e., HTML) as input to the `label` and `icon` arguments. (#2020)
17+
18+
* The `.output_*()` methods of the `ClientData` class (e.g., `session.clientdata.output_height()`) can now be called without an `id` when called inside a `@render` function. (#1978)
19+
20+
* `playwright.controller.InputActionButton` gains a `expect_icon()` method. As a result, the already existing `expect_label()` no longer includes the icon. (#2020)
1321

1422
### Improvements
1523

24+
* Improved the styling and readability of markdown tables rendered by `ui.Chat()` and `ui.MarkdownStream()`. (#1973)
25+
1626
* `selectize`, `remove_button`, and `options` parameters of `ui.input_select()` have been deprecated; use `ui.input_selectize()` instead. (Thanks, @ErdaradunGaztea!) (#1947)
1727

18-
* Improved the styling and readability of markdown tables rendered by `ui.Chat()` and `ui.MarkdownStream()`. (#1973)
28+
* Added `timeout_secs` parameter to `create_app_fixture` to allow testing apps with longer startup times. (#2033)
1929

2030
### Bug fixes
2131

32+
* Fixed an issue with `ui.Chat()` sometimes wanting to scroll a parent element. (#1996)
33+
2234
* Explicitly call out module usage in UI input bookmark button documentation. (#1983)
2335

2436
* Fix missing session when trying to display an error duing bookmarking. (#1984)
2537

38+
* Fixed `set()` method of `InputSelectize` controller so it clears existing selections before applying new values. (#2024)
39+
2640

2741
## [1.4.0] - 2025-04-08
2842

@@ -50,6 +64,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5064

5165
### Bug fixes
5266

67+
* Fixed issue where apps run in Workbench were unexpectedly crashing. Apps running in Workbench will now have `ws_per_message_deflate=False` enforced. (#2005)
68+
5369
* Fixed an issue where the `<main>` areas of `ui.page_sidebar()` and `ui.page_navbar()` (with a `sidebar`) were made to be a fillable containers even when `fillable=False`. (#1816)
5470

5571
* Fixed an issue where the `.update_user_input()` method on `ui.Chat()` isn't working in shinylive. (#1891)

Makefile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ clean-test: FORCE
5656
rm -fr .pytest_cache
5757
rm -rf typings/
5858

59-
typings/appdirs:
60-
@echo "Creating appdirs stubs"
61-
pyright --createstub appdirs
6259
typings/folium:
6360
@echo "Creating folium stubs"
6461
pyright --createstub folium
@@ -75,7 +72,7 @@ typings/matplotlib/__init__.pyi:
7572
mv typings/python-type-stubs/stubs/matplotlib typings/
7673
rm -rf typings/python-type-stubs
7774

78-
pyright-typings: typings/appdirs typings/folium typings/uvicorn typings/seaborn typings/matplotlib/__init__.pyi
75+
pyright-typings: typings/folium typings/uvicorn typings/seaborn typings/matplotlib/__init__.pyi
7976

8077
check: check-format check-lint check-types check-tests ## check code, style, types, and test (basic CI)
8178
check-fix: format check-lint check-types check-tests ## check and format code, style, types, and test
@@ -223,6 +220,8 @@ install-deps: FORCE ## install dependencies
223220
pip install -e ".[dev,test]" --upgrade
224221
ci-install-deps: FORCE
225222
uv pip install -e ".[dev,test]"
223+
ci-install-py-shiny-templates-deps: FORCE
224+
uv pip install -r py-shiny-templates/requirements.txt
226225

227226
install-docs: FORCE
228227
pip install -e ".[dev,test,doc]"

docs/_quartodoc-testing.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ quartodoc:
2626
contents:
2727
- playwright.controller.InputActionButton
2828
- playwright.controller.InputActionLink
29+
- playwright.controller.InputBookmarkButton
2930
- playwright.controller.InputCheckbox
3031
- playwright.controller.InputCheckboxGroup
3132
- playwright.controller.InputDarkMode
@@ -59,6 +60,7 @@ quartodoc:
5960
- playwright.controller.NavsetTab
6061
- playwright.controller.NavsetUnderline
6162
- playwright.controller.NavPanel
63+
- playwright.controller.PageNavbar
6264
- title: Upload and download
6365
desc: Methods for interacting with Shiny app uploading and downloading controller.
6466
contents:

js/chat/chat.ts

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ interface ChatInputSetInputOptions {
131131
}
132132

133133
class ChatInput extends LightElement {
134-
private _disabled = false;
135-
136134
@property() placeholder = "Enter a message...";
137135
// disabled is reflected manually because `reflect: true` doesn't work with LightElement
138136
@property({ type: Boolean })
@@ -155,6 +153,27 @@ class ChatInput extends LightElement {
155153
this.#onInput();
156154
}
157155

156+
private _disabled = false;
157+
inputVisibleObserver?: IntersectionObserver;
158+
159+
connectedCallback(): void {
160+
super.connectedCallback();
161+
162+
this.inputVisibleObserver = new IntersectionObserver((entries) => {
163+
entries.forEach((entry) => {
164+
if (entry.isIntersecting) this.#updateHeight();
165+
});
166+
});
167+
168+
this.inputVisibleObserver.observe(this);
169+
}
170+
171+
disconnectedCallback(): void {
172+
super.disconnectedCallback();
173+
this.inputVisibleObserver?.disconnect();
174+
this.inputVisibleObserver = undefined;
175+
}
176+
158177
attributeChangedCallback(
159178
name: string,
160179
_old: string | null,
@@ -189,7 +208,7 @@ class ChatInput extends LightElement {
189208
return html`
190209
<textarea
191210
id="${this.id}"
192-
class="form-control textarea-autoresize"
211+
class="form-control"
193212
rows="1"
194213
placeholder="${this.placeholder}"
195214
@keydown=${this.#onKeyDown}
@@ -217,6 +236,7 @@ class ChatInput extends LightElement {
217236
}
218237

219238
#onInput(): void {
239+
this.#updateHeight();
220240
this.button.disabled = this.disabled
221241
? true
222242
: this.value.trim().length === 0;
@@ -247,6 +267,15 @@ class ChatInput extends LightElement {
247267
if (focus) this.textarea.focus();
248268
}
249269

270+
#updateHeight(): void {
271+
const el = this.textarea;
272+
if (el.scrollHeight == 0) {
273+
return;
274+
}
275+
el.style.height = "auto";
276+
el.style.height = `${el.scrollHeight}px`;
277+
}
278+
250279
setInputValue(
251280
value: string,
252281
{ submit = false, focus = false }: ChatInputSetInputOptions = {}
@@ -528,11 +557,19 @@ class ChatContainer extends LightElement {
528557

529558
// ------- Register custom elements and shiny bindings ---------
530559

531-
customElements.define(CHAT_MESSAGE_TAG, ChatMessage);
532-
customElements.define(CHAT_USER_MESSAGE_TAG, ChatUserMessage);
533-
customElements.define(CHAT_MESSAGES_TAG, ChatMessages);
534-
customElements.define(CHAT_INPUT_TAG, ChatInput);
535-
customElements.define(CHAT_CONTAINER_TAG, ChatContainer);
560+
const chatCustomElements = [
561+
{ tag: CHAT_MESSAGE_TAG, component: ChatMessage },
562+
{ tag: CHAT_USER_MESSAGE_TAG, component: ChatUserMessage },
563+
{ tag: CHAT_MESSAGES_TAG, component: ChatMessages },
564+
{ tag: CHAT_INPUT_TAG, component: ChatInput },
565+
{ tag: CHAT_CONTAINER_TAG, component: ChatContainer }
566+
];
567+
568+
chatCustomElements.forEach(({ tag, component }) => {
569+
if (!customElements.get(tag)) {
570+
customElements.define(tag, component);
571+
}
572+
});
536573

537574
window.Shiny.addCustomMessageHandler(
538575
"shinyChatMessage",
@@ -561,3 +598,5 @@ window.Shiny.addCustomMessageHandler(
561598
el.dispatchEvent(evt);
562599
}
563600
);
601+
602+
export { CHAT_CONTAINER_TAG };

js/markdown-stream/markdown-stream.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import ClipboardJS from "clipboard";
66
import hljs from "highlight.js/lib/common";
77
import { Renderer, parse } from "marked";
88

9+
import { CHAT_CONTAINER_TAG } from "../chat/chat";
10+
911
import {
1012
LightElement,
1113
createElement,
@@ -282,6 +284,12 @@ class MarkdownElement extends LightElement {
282284
while (el) {
283285
if (el.scrollHeight > el.clientHeight) return el;
284286
el = el.parentElement;
287+
if (el?.tagName?.toLowerCase() === CHAT_CONTAINER_TAG.toLowerCase()) {
288+
// This ensures that we do not accidentally scroll a parent element of the chat
289+
// container. If the chat container itself is scrollable, a scrollable element
290+
// would already have been identified.
291+
break;
292+
}
285293
}
286294
return null;
287295
}

pyproject.toml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ classifiers = [
2626
"Programming Language :: Python :: 3.10",
2727
"Programming Language :: Python :: 3.11",
2828
"Programming Language :: Python :: 3.12",
29+
"Programming Language :: Python :: 3.13",
2930
]
3031
dependencies = [
3132
"typing-extensions>=4.10.0",
@@ -37,7 +38,7 @@ dependencies = [
3738
"markdown-it-py>=1.1.0",
3839
"mdit-py-plugins>=0.3.0",
3940
"linkify-it-py>=1.0",
40-
"appdirs>=1.4.4",
41+
"platformdirs>=2.1.0",
4142
"asgiref>=3.5.2",
4243
"packaging>=20.9",
4344
"watchfiles>=0.18.0;platform_system!='Emscripten'",
@@ -54,8 +55,8 @@ theme = ["libsass>=0.23.0", "brand_yml>=0.1.0"]
5455
test = [
5556
"pytest>=6.2.4",
5657
"pytest-asyncio>=0.17.2",
57-
"pytest-playwright>=0.3.0",
58-
"playwright>=1.43.0",
58+
"pytest-playwright>=0.5.2",
59+
"playwright>=1.48.0",
5960
"pytest-xdist",
6061
"pytest-timeout",
6162
"pytest-rerunfailures",
@@ -86,7 +87,6 @@ test = [
8687
"faicons",
8788
"ridgeplot",
8889
"great_tables",
89-
"modin[all]",
9090
"polars",
9191
"dask[dataframe]",
9292
"pyarrow",
@@ -113,11 +113,7 @@ dev = [
113113
"anthropic",
114114
"google-generativeai;python_version>='3.9'",
115115
"langchain_core",
116-
# langsmith (needed for langchain_core) versions >= 0.3
117-
# (up to at least 0.3.2 as of 2025-01-29)
118-
# cause an `argparse.ArgumentError` when running `pytest`.
119-
# https://github.com/posit-dev/py-shiny/issues/1829
120-
"langsmith<0.3",
116+
"langsmith>=0.3.4",
121117
"openai",
122118
"ollama",
123119
"chatlas>=0.6.1",

shiny/_datastructures.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ class PriorityQueueFIFO(Generic[T]):
1515
"""
1616

1717
def __init__(self) -> None:
18-
# Using Tuple instead of tuple because in Python 3.8 and earlier, tuple isn't
19-
# generic
2018
self._pq: PriorityQueue[tuple[int, int, T]] = PriorityQueue()
2119
self._counter: int = 0
2220

0 commit comments

Comments
 (0)