Skip to content

Commit c2f32b7

Browse files
deeleeramonegithub-actions[bot]dependabot[bot]
authored
[Release] pywry-v2.0.4 (#78)
* chore(sync): merge main into develop (#66) * update sbom workflow * Release/pywry 2.0.1 (#41) * patch release * missed file in commit * Fix SBOM step * Fix pip install command for dependencies * Prepare Python package artifacts for PyPI publishing Add step to prepare Python package artifacts for publishing. --------- Co-authored-by: deeleeramone <> * Release/pywry 2.0.2 (#56) * chore(sync): merge main into develop (#43) * update sbom workflow * Release/pywry 2.0.1 (#41) * patch release * missed file in commit * Fix SBOM step * Fix pip install command for dependencies * Prepare Python package artifacts for PyPI publishing Add step to prepare Python package artifacts for publishing. --------- Co-authored-by: deeleeramone <> --------- Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * chore(lockfiles): refresh uv.lock and package-lock.json * build(deps): bump python-multipart (#45) Bumps the uv group with 1 update in the /pywry directory: [python-multipart](https://github.com/Kludex/python-multipart). Updates `python-multipart` from 0.0.26 to 0.0.27 - [Release notes](https://github.com/Kludex/python-multipart/releases) - [Changelog](https://github.com/Kludex/python-multipart/blob/main/CHANGELOG.md) - [Commits](Kludex/python-multipart@0.0.26...0.0.27) --- updated-dependencies: - dependency-name: python-multipart dependency-version: 0.0.27 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump langchain-core (#46) Bumps the uv group with 1 update in the /pywry directory: [langchain-core](https://github.com/langchain-ai/langchain). Updates `langchain-core` from 1.3.2 to 1.3.3 - [Release notes](https://github.com/langchain-ai/langchain/releases) - [Commits](langchain-ai/langchain@langchain-core==1.3.2...langchain-core==1.3.3) --- updated-dependencies: - dependency-name: langchain-core dependency-version: 1.3.3 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): update pydantic requirement in /pywry/docs (#47) Updates the requirements on [pydantic](https://github.com/pydantic/pydantic) to permit the latest version. - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/v2.13.4/HISTORY.md) - [Commits](pydantic/pydantic@v2.13.3...v2.13.4) --- updated-dependencies: - dependency-name: pydantic dependency-version: 2.13.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): update pydantic-settings requirement in /pywry/docs (#48) Updates the requirements on [pydantic-settings](https://github.com/pydantic/pydantic-settings) to permit the latest version. - [Release notes](https://github.com/pydantic/pydantic-settings/releases) - [Commits](pydantic/pydantic-settings@v2.14.0...v2.14.1) --- updated-dependencies: - dependency-name: pydantic-settings dependency-version: 2.14.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump pydantic from 2.13.3 to 2.13.4 in /pywry (#49) Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.13.3 to 2.13.4. - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/v2.13.4/HISTORY.md) - [Commits](pydantic/pydantic@v2.13.3...v2.13.4) --- updated-dependencies: - dependency-name: pydantic dependency-version: 2.13.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump agent-client-protocol in /pywry (#50) Bumps [agent-client-protocol](https://github.com/agentclientprotocol/python-sdk) from 0.9.0 to 0.10.0. - [Release notes](https://github.com/agentclientprotocol/python-sdk/releases) - [Commits](agentclientprotocol/python-sdk@0.9.0...0.10.0) --- updated-dependencies: - dependency-name: agent-client-protocol dependency-version: 0.10.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump pydantic-settings from 2.14.0 to 2.14.1 in /pywry (#51) Bumps [pydantic-settings](https://github.com/pydantic/pydantic-settings) from 2.14.0 to 2.14.1. - [Release notes](https://github.com/pydantic/pydantic-settings/releases) - [Commits](pydantic/pydantic-settings@v2.14.0...v2.14.1) --- updated-dependencies: - dependency-name: pydantic-settings dependency-version: 2.14.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump openai from 2.33.0 to 2.36.0 in /pywry (#52) Bumps [openai](https://github.com/openai/openai-python) from 2.33.0 to 2.36.0. - [Release notes](https://github.com/openai/openai-python/releases) - [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md) - [Commits](openai/openai-python@v2.33.0...v2.36.0) --- updated-dependencies: - dependency-name: openai dependency-version: 2.36.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump cryptography from 47.0.0 to 48.0.0 in /pywry (#53) Bumps [cryptography](https://github.com/pyca/cryptography) from 47.0.0 to 48.0.0. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](pyca/cryptography@47.0.0...48.0.0) --- updated-dependencies: - dependency-name: cryptography dependency-version: 48.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump urllib3 in /pywry in the uv group across 1 directory (#54) Bumps the uv group with 1 update in the /pywry directory: [urllib3](https://github.com/urllib3/urllib3). Updates `urllib3` from 2.6.3 to 2.7.0 - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](urllib3/urllib3@2.6.3...2.7.0) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.7.0 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * Bugfix/chat handler (#55) * fix chart handler getting swallowed * version bump * claude marketplace version * claude marketplace version * claude changelog --------- Co-authored-by: deeleeramone <> * chore(lockfiles): refresh uv.lock and package-lock.json --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: deeleeramone <> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): update pydantic-settings requirement in /pywry/docs (#58) Updates the requirements on [pydantic-settings](https://github.com/pydantic/pydantic-settings) to permit the latest version. - [Release notes](https://github.com/pydantic/pydantic-settings/releases) - [Commits](pydantic/pydantic-settings@v2.14.0...v2.14.1) --- updated-dependencies: - dependency-name: pydantic-settings dependency-version: 2.14.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump authlib from 1.7.1 to 1.7.2 in /pywry (#59) Bumps [authlib](https://github.com/authlib/authlib) from 1.7.1 to 1.7.2. - [Release notes](https://github.com/authlib/authlib/releases) - [Commits](authlib/authlib@1.7.1...v1.7.2) --- updated-dependencies: - dependency-name: authlib dependency-version: 1.7.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump uvicorn from 0.46.0 to 0.47.0 in /pywry (#60) Bumps [uvicorn](https://github.com/Kludex/uvicorn) from 0.46.0 to 0.47.0. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](Kludex/uvicorn@0.46.0...0.47.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.47.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump anthropic from 0.97.0 to 0.102.0 in /pywry (#61) Bumps [anthropic](https://github.com/anthropics/anthropic-sdk-python) from 0.97.0 to 0.102.0. - [Release notes](https://github.com/anthropics/anthropic-sdk-python/releases) - [Changelog](https://github.com/anthropics/anthropic-sdk-python/blob/main/CHANGELOG.md) - [Commits](anthropics/anthropic-sdk-python@v0.97.0...v0.102.0) --- updated-dependencies: - dependency-name: anthropic dependency-version: 0.102.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * fix flakey test * fix flakey test * build(deps-dev): bump fastmcp from 3.2.4 to 3.3.1 in /pywry (#62) Bumps [fastmcp](https://github.com/PrefectHQ/fastmcp) from 3.2.4 to 3.3.1. - [Release notes](https://github.com/PrefectHQ/fastmcp/releases) - [Changelog](https://github.com/PrefectHQ/fastmcp/blob/main/docs/changelog.mdx) - [Commits](PrefectHQ/fastmcp@v3.2.4...v3.3.1) --- updated-dependencies: - dependency-name: fastmcp dependency-version: 3.3.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump the uv group across 1 directory with 3 updates (#65) Bumps the uv group with 3 updates in the /pywry directory: [idna](https://github.com/kjd/idna), [langsmith](https://github.com/langchain-ai/langsmith-sdk) and [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions). Updates `idna` from 3.13 to 3.15 - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.md) - [Commits](kjd/idna@v3.13...v3.15) Updates `langsmith` from 0.7.36 to 0.8.0 - [Release notes](https://github.com/langchain-ai/langsmith-sdk/releases) - [Commits](langchain-ai/langsmith-sdk@v0.7.36...v0.8.0) Updates `pymdown-extensions` from 10.21.2 to 10.21.3 - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](facelessuser/pymdown-extensions@10.21.2...10.21.3) --- updated-dependencies: - dependency-name: idna dependency-version: '3.15' dependency-type: indirect dependency-group: uv - dependency-name: langsmith dependency-version: 0.8.0 dependency-type: indirect dependency-group: uv - dependency-name: pymdown-extensions dependency-version: 10.21.3 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump ty from 0.0.34 to 0.0.40 in /pywry (#67) Bumps [ty](https://github.com/astral-sh/ty) from 0.0.34 to 0.0.40. - [Release notes](https://github.com/astral-sh/ty/releases) - [Changelog](https://github.com/astral-sh/ty/blob/main/CHANGELOG.md) - [Commits](astral-sh/ty@0.0.34...0.0.40) --- updated-dependencies: - dependency-name: ty dependency-version: 0.0.39 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump fastapi from 0.136.1 to 0.136.3 in /pywry (#68) Bumps [fastapi](https://github.com/fastapi/fastapi) from 0.136.1 to 0.136.3. - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](fastapi/fastapi@0.136.1...0.136.3) --- updated-dependencies: - dependency-name: fastapi dependency-version: 0.136.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump ruff from 0.15.12 to 0.15.14 in /pywry (#69) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.12 to 0.15.14. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.12...0.15.14) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.14 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps): bump starlette in /pywry in the uv group across 1 directory (#75) Bumps the uv group with 1 update in the /pywry directory: [starlette](https://github.com/Kludex/starlette). Updates `starlette` from 1.0.0 to 1.0.1 - [Release notes](https://github.com/Kludex/starlette/releases) - [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md) - [Commits](Kludex/starlette@1.0.0...1.0.1) --- updated-dependencies: - dependency-name: starlette dependency-version: 1.0.1 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump pytest-asyncio from 1.3.0 to 1.4.0 in /pywry (#74) Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 1.3.0 to 1.4.0. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](pytest-dev/pytest-asyncio@v1.3.0...v1.4.0) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-version: 1.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> * build(deps-dev): bump ruff from 0.15.14 to 0.15.15 in /pywry (#73) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.14 to 0.15.15. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.14...0.15.15) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.15 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump uvicorn from 0.47.0 to 0.48.0 in /pywry (#72) Bumps [uvicorn](https://github.com/Kludex/uvicorn) from 0.47.0 to 0.48.0. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](Kludex/uvicorn@0.47.0...0.48.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.48.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump openai from 2.36.0 to 2.40.0 in /pywry (#70) Bumps [openai](https://github.com/openai/openai-python) from 2.36.0 to 2.40.0. - [Release notes](https://github.com/openai/openai-python/releases) - [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md) - [Commits](openai/openai-python@v2.36.0...v2.40.0) --- updated-dependencies: - dependency-name: openai dependency-version: 2.40.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump tornado in /pywry in the uv group across 1 directory (#76) Bumps the uv group with 1 update in the /pywry directory: [tornado](https://github.com/tornadoweb/tornado). Updates `tornado` from 6.5.5 to 6.5.6 - [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst) - [Commits](tornadoweb/tornado@v6.5.5...v6.5.6) --- updated-dependencies: - dependency-name: tornado dependency-version: 6.5.6 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix missing tv inline mixin (#77) Co-authored-by: deeleeramone <> * chore(lockfiles): refresh uv.lock and package-lock.json * label positional * chore(lockfiles): refresh uv.lock and package-lock.json --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: deeleeramone <>
1 parent c9d6322 commit c2f32b7

9 files changed

Lines changed: 528 additions & 145 deletions

File tree

claude/scripts/build_distributions.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,7 @@ def _build_cowork_plugin() -> Path:
121121
plugin = json.loads(plugin_json_path.read_text(encoding="utf-8"))
122122
if not plugin["description"].endswith(COWORK_DESCRIPTION_SUFFIX):
123123
plugin["description"] += COWORK_DESCRIPTION_SUFFIX
124-
plugin_json_path.write_text(
125-
json.dumps(plugin, indent=2) + "\n", encoding="utf-8"
126-
)
124+
plugin_json_path.write_text(json.dumps(plugin, indent=2) + "\n", encoding="utf-8")
127125

128126
out = DIST / "pywry-cowork.plugin"
129127
_zip_directory(workdir, out)
@@ -140,9 +138,7 @@ def _build_desktop_extension() -> Path:
140138
def _summarize(path: Path) -> None:
141139
size = path.stat().st_size
142140
if size > SIZE_LIMIT_BYTES:
143-
raise RuntimeError(
144-
f"{path.name} is {size:,} bytes — exceeds the 50 MB limit"
145-
)
141+
raise RuntimeError(f"{path.name} is {size:,} bytes — exceeds the 50 MB limit")
146142
with zipfile.ZipFile(path) as zf:
147143
files = zf.namelist()
148144
rel = path.relative_to(REPO_ROOT)

pywry/docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ mkdocs-section-index>=0.3.12
1414

1515
# Needed for building docs (dependencies of pywry)
1616
pydantic>=2.13.4
17-
pydantic-settings>=2.14.0
17+
pydantic-settings>=2.14.1

pywry/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "pywry"
3-
version = "2.0.2"
3+
version = "2.0.4"
44
description = "A lightweight and blazingly fast, cross-platform, WebView rendering engine and desktop UI toolkit for Python. Batteries included."
55
authors = [{ name = "PyWry", email = "pywry2@gmail.com" }]
66
license = { text = "Apache 2.0" }

pywry/pywry/inline.py

Lines changed: 214 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
_UNSET,
4242
_Unset,
4343
)
44+
from .tvchart.mixin import TVChartStateMixin
4445
from .toolbar import Toolbar, get_toolbar_script, wrap_content_with_toolbars
4546
from .widget_protocol import BaseWidget # noqa: TC001
4647

@@ -1667,7 +1668,7 @@ async def get_widget_html_async(widget_id: str) -> str | None:
16671668
return await _state.get_widget_html_async(widget_id)
16681669

16691670

1670-
class InlineWidget(GridStateMixin, PlotlyStateMixin, ToolbarStateMixin):
1671+
class InlineWidget(GridStateMixin, PlotlyStateMixin, TVChartStateMixin, ToolbarStateMixin):
16711672
"""Base inline widget that renders via FastAPI server and IFrame.
16721673
16731674
Implements BaseWidget protocol for unified API across rendering backends.
@@ -1822,7 +1823,10 @@ def open_in_browser(self) -> None:
18221823
webbrowser.open(self.url)
18231824

18241825
def on(
1825-
self, event_type: str, callback: Callable[[dict[str, Any], str, str], Any]
1826+
self,
1827+
event_type: str,
1828+
callback: Callable[[dict[str, Any], str, str], Any],
1829+
label: str | None = None,
18261830
) -> InlineWidget:
18271831
"""Register a callback for events from JavaScript.
18281832
@@ -1832,6 +1836,9 @@ def on(
18321836
Event name (e.g., 'plotly:click', 'toggle', 'grid:cell-click').
18331837
callback : Callable[[dict[str, Any], str, str], Any]
18341838
Handler function receiving (data, event_type, label).
1839+
label : str or None, optional
1840+
Ignored for inline widgets (accepted for API compatibility with
1841+
``PyWry.on()``).
18351842
18361843
Returns
18371844
-------
@@ -3773,6 +3780,186 @@ def _preload_chart_data(user_id: str = "default") -> dict[str, str]:
37733780
return preload
37743781

37753782

3783+
def generate_tvchart_html(
3784+
chart_html: str,
3785+
config_payload: str,
3786+
chart_id: str,
3787+
widget_id: str,
3788+
title: str = "Chart",
3789+
theme: ThemeLiteral | None = None,
3790+
toolbars: list[dict[str, Any] | Toolbar] | None = None,
3791+
modals: list[dict[str, Any] | Modal] | None = None,
3792+
inline_css: str = "",
3793+
full_document: bool = True,
3794+
token: str | None = None,
3795+
) -> str:
3796+
"""Generate HTML for a TradingView Lightweight Chart.
3797+
3798+
Parameters
3799+
----------
3800+
chart_html : str
3801+
The chart container ``<div>`` (and any toolbar/modal markup).
3802+
config_payload : str
3803+
JSON string with ``chartOptions``, ``series``, ``storage``, etc.
3804+
chart_id : str
3805+
DOM id of the chart container element.
3806+
widget_id : str
3807+
Unique widget identifier (used by the pywry bridge).
3808+
title : str
3809+
Page title.
3810+
theme : 'dark' or 'light', optional
3811+
Color theme.
3812+
toolbars : list, optional
3813+
Toolbar configurations.
3814+
modals : list, optional
3815+
Modal configurations.
3816+
inline_css : str
3817+
Extra CSS to inject.
3818+
full_document : bool
3819+
If True, return complete HTML document; if False, content fragment only.
3820+
token : str or None
3821+
Widget auth token for the pywry bridge.
3822+
3823+
Returns
3824+
-------
3825+
str
3826+
"""
3827+
from .assets import (
3828+
get_pywry_css,
3829+
get_scrollbar_js,
3830+
get_toast_css,
3831+
get_tvchart_defaults_js,
3832+
get_tvchart_js,
3833+
)
3834+
from .modal import wrap_content_with_modals
3835+
from .notebook import _wrap_content_with_toolbars
3836+
3837+
if theme is None:
3838+
theme = _get_default_theme()
3839+
3840+
tvchart_js = get_tvchart_js()
3841+
tvchart_script = f"<script>{tvchart_js}</script>" if tvchart_js else ""
3842+
tvchart_defaults = get_tvchart_defaults_js()
3843+
tvchart_defaults_script = f"<script>{tvchart_defaults}</script>" if tvchart_defaults else ""
3844+
3845+
# Chart init script — waits for LightweightCharts then renders
3846+
chart_init_script = f"""<script>
3847+
(function() {{
3848+
function initChart() {{
3849+
if (typeof LightweightCharts === 'undefined') {{
3850+
setTimeout(initChart, 50);
3851+
return;
3852+
}}
3853+
var payload = {config_payload};
3854+
var container = document.getElementById('{chart_id}');
3855+
if (!container) {{
3856+
setTimeout(initChart, 50);
3857+
return;
3858+
}}
3859+
if (window.PYWRY_TVCHART_RENDER) {{
3860+
window.PYWRY_TVCHART_RENDER('{chart_id}', container, payload);
3861+
}} else if (window.PYWRY_TVCHART_CREATE) {{
3862+
window.PYWRY_TVCHART_CREATE('{chart_id}', container, payload);
3863+
}}
3864+
}}
3865+
initChart();
3866+
}})();
3867+
</script>"""
3868+
3869+
if not full_document:
3870+
# Content fragment for anywidget — caller handles wrapping
3871+
wrapped = _wrap_content_with_toolbars(chart_html, toolbars)
3872+
if modals:
3873+
modal_html, modal_scripts = wrap_content_with_modals("", modals)
3874+
wrapped = f"{wrapped}{modal_html}{modal_scripts}"
3875+
return f"{wrapped}\n{chart_init_script}"
3876+
3877+
# Full document for IFrame / browser mode
3878+
pywry_css = get_pywry_css()
3879+
pywry_style = f"<style>{pywry_css}</style>" if pywry_css else ""
3880+
toast_css = get_toast_css()
3881+
toast_style = f"<style>{toast_css}</style>" if toast_css else ""
3882+
scrollbar_js = get_scrollbar_js()
3883+
scrollbar_script = f"<script>{scrollbar_js}</script>" if scrollbar_js else ""
3884+
inline_style = f"<style>{inline_css}</style>" if inline_css else ""
3885+
3886+
if theme == "dark":
3887+
widget_theme_class = "pywry-theme-dark"
3888+
elif theme == "system":
3889+
widget_theme_class = "pywry-theme-system"
3890+
else:
3891+
widget_theme_class = "pywry-theme-light"
3892+
3893+
# Build widget content with toolbars
3894+
widget_content = wrap_content_with_toolbars(chart_html, toolbars)
3895+
3896+
# Inject modals
3897+
modal_block = ""
3898+
if modals:
3899+
modal_html, modal_scripts = wrap_content_with_modals("", modals)
3900+
modal_block = f"{modal_html}{modal_scripts}"
3901+
3902+
return f"""<!DOCTYPE html>
3903+
<html class="{theme}">
3904+
<head>
3905+
<meta charset="utf-8">
3906+
<title>{title}</title>
3907+
{tvchart_script}
3908+
{tvchart_defaults_script}
3909+
{pywry_style}
3910+
{toast_style}
3911+
{inline_style}
3912+
{scrollbar_script}
3913+
<style>
3914+
html, body {{
3915+
margin: 0;
3916+
padding: 0;
3917+
width: 100%;
3918+
height: 100%;
3919+
overflow: hidden;
3920+
background: var(--pywry-bg-primary);
3921+
}}
3922+
.pywry-widget {{
3923+
--pywry-widget-width: 100%;
3924+
--pywry-widget-height: 100%;
3925+
width: 100%;
3926+
height: 100%;
3927+
display: flex;
3928+
flex-direction: column;
3929+
border: none;
3930+
border-radius: 0;
3931+
box-sizing: border-box;
3932+
background-color: var(--pywry-bg-primary);
3933+
}}
3934+
.pywry-toolbar {{
3935+
border: none;
3936+
}}
3937+
.pywry-content {{
3938+
flex: 1;
3939+
min-height: 0;
3940+
box-sizing: border-box;
3941+
overflow: hidden;
3942+
}}
3943+
.pywry-tvchart-container {{
3944+
flex: 1;
3945+
min-height: 0;
3946+
width: 100%;
3947+
height: 100%;
3948+
box-sizing: border-box;
3949+
}}
3950+
</style>
3951+
</head>
3952+
<body>
3953+
<div class="pywry-widget pywry-custom-scrollbar {widget_theme_class}">
3954+
{widget_content}
3955+
</div>
3956+
{modal_block}
3957+
{_get_pywry_bridge_js(widget_id, token)}
3958+
{chart_init_script}
3959+
</body>
3960+
</html>"""
3961+
3962+
37763963
def show_tvchart(
37773964
data: Any = None,
37783965
callbacks: dict[str, Callable[..., Any]] | None = None,
@@ -3845,10 +4032,8 @@ def show_tvchart(
38454032
import json as _json
38464033
import uuid as _uuid
38474034

3848-
from .modal import wrap_content_with_modals
3849-
from .notebook import _wrap_content_with_toolbars
4035+
from .notebook import create_tvchart_widget
38504036
from .runtime import is_headless
3851-
from .widget import HAS_ANYWIDGET, PyWryTVChartWidget
38524037

38534038
if theme is None:
38544039
theme = _get_default_theme()
@@ -3930,25 +4115,21 @@ def show_tvchart(
39304115

39314116
chart_html = f'<div id="{chart_id}" class="pywry-tvchart-container"></div>'
39324117

3933-
# Inject toolbars
3934-
chart_html = _wrap_content_with_toolbars(chart_html, toolbars)
3935-
3936-
# Inject modals
3937-
if modals:
3938-
modal_html, modal_scripts = wrap_content_with_modals("", modals)
3939-
chart_html = f"{chart_html}{modal_html}{modal_scripts}"
3940-
3941-
if HAS_ANYWIDGET and not open_browser and not is_headless():
3942-
widget = PyWryTVChartWidget(
3943-
content=chart_html,
3944-
chart_config=config_payload,
3945-
theme=theme,
3946-
width=width,
3947-
height=f"{height}px",
3948-
chart_id=chart_id,
3949-
)
3950-
else:
3951-
widget = PyWryTVChartWidget(content=chart_html)
4118+
# Create widget using auto-backend selection
4119+
# Force InlineWidget (IFrame) for BROWSER mode since it has open_in_browser()
4120+
widget = create_tvchart_widget(
4121+
chart_html=chart_html,
4122+
config_payload=config_payload,
4123+
chart_id=chart_id,
4124+
widget_id=widget_id,
4125+
title=title,
4126+
theme=theme,
4127+
width=width,
4128+
height=height,
4129+
toolbars=toolbars,
4130+
modals=modals,
4131+
force_iframe=open_browser,
4132+
)
39524133

39534134
if callbacks:
39544135
for event_type, callback in callbacks.items():
@@ -3960,14 +4141,17 @@ def show_tvchart(
39604141
wire_storage(user_id="default")
39614142

39624143
if provider is not None:
3963-
widget._wire_datafeed_provider(provider)
4144+
wire_datafeed = getattr(widget, "_wire_datafeed_provider", None)
4145+
if callable(wire_datafeed):
4146+
wire_datafeed(provider)
39644147

4148+
# Display
39654149
if is_headless():
39664150
pass
4151+
elif open_browser:
4152+
open_fn = getattr(widget, "open_in_browser", None)
4153+
if callable(open_fn):
4154+
open_fn()
39674155
else:
3968-
open_in_browser = getattr(widget, "open_in_browser", None)
3969-
if open_browser and callable(open_in_browser):
3970-
open_in_browser()
3971-
else:
3972-
widget.display()
4156+
widget.display()
39734157
return widget

0 commit comments

Comments
 (0)