posit-dev / posit-dev/py-shinylive
`_find_packages_in_requirements()` silently strips extras, so `shiny[theme]` never bundles libsass
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 56
- Forks
- 6
- Avg merge
- 3m
- Merged PRs (30d)
- 1
Description
Summary
_find_packages_in_requirements() (shinylive/_deps.py:608) strips extras from a requirement line, so shiny[theme] is recorded as plain shiny. The packages the extra asks for are therefore never copied into the published assets, and the app fails at runtime with a 404 — even though the wheels are bundled with Shinylive and would have worked.
The failure is silent at build time: nothing warns, and the export/render succeeds.
Reproduction
>>> from shinylive._deps import _find_packages_in_requirements
>>> _find_packages_in_requirements("shiny[theme]")
['shiny']
>>> _find_packages_in_requirements("libsass")
['libsass']
The offending line is the version-suffix regex, which treats [theme] as trailing junk:
pkg_name = re.sub(r"([a-zA-Z0-9._-]+)(.*)", r"\1", line).strip()
End-to-end, with requirements.txt = shiny[theme] and an app that builds a customized ui.Theme():
preload error: The following error occurred while loading libsass: Failed to fetch
preload error: ... ruamel.yaml ... pydantic ... annotated-types ... pydantic_core: Failed to fetch
ImportError: The 'libsass' package is required to compile custom themes.
Switching the same file to a bare libsass fixes it: the wheel is copied, 0 console errors, app runs.
Why this is worth fixing rather than documenting around
The two halves of Shinylive disagree about extras:
- The runtime installer handles them correctly.
_install_requirements_from_dir()inshinylive/src/hooks/usePyodide.tsxexplicitly resolves extras against the already-installed dist's metadata — its own source comment uses this very case as the worked example:# Convert requires records : 'libsass>=0.23.0; extra == "theme"'. - The build-time asset copier does not. So the installer dutifully tries to install what the extra asks for, and every fetch 404s because those wheels were never published next to the app.
shiny[theme] is not a hypothetical spelling — it is what Shiny's own ui.Theme docstring instructs users to install:
Note: Compiling custom themes requires the libsass package, which is not installed by default with Shiny. Use
pip install libsassorpip install "shiny[theme]"to install it.
So a user who follows the documentation into a Shinylive app gets a broken app with no build-time signal. We just hit this in the Shiny for Python docs site: posit-dev/py-shiny#2386 / posit-dev/py-shiny#2387 had to pin a bare libsass instead of the nicer shiny[theme] specifically to work around this.
Scope
Both consumers of find_package_deps() are affected, since both go through this parser:
shinylive_app_resources()(_deps.py:350) — the Quarto extension'sapp-resourcespath, used by Quarto sites.shinylive export(_export.py:99).
Suggested fix
Options, roughly in increasing order of effort:
- Fail loudly. At minimum, don't silently drop the extra — warn (or error) when a requirement carries one, so the problem surfaces at build time instead of in the user's browser. This alone would have saved the debugging round-trip.
- Parse properly. Replace the regex with
packaging.requirements.Requirement, which gives.nameand.extrasdirectly and also handles markers/specifiers correctly. - Resolve the extras. For a package present in the assets dir, read
Provides-Extra/Requires-Distfrom the wheel'sMETADATAand add each selected extra's requirements to the dependency set — mirroring whatusePyodide.tsxalready does at runtime. Note the pyodide lock'sdependswon't help here: it lists runtime deps only, not extras.
Even (1) + (2) would be a real improvement; (3) makes shiny[theme] work as users reasonably expect.
Related: #4 (wheel not bundled unless explicitly imported) and #17 (only inspect requirements.txt packages for dependencies) — same general area of "what gets bundled", different trigger.
Environment
shinylivePython package 0.8.11, web assets 0.10.14- Verified against
main(shinylive/_deps.pyis byte-identical there today)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in shinylive/_deps.py at _find_packages_in_requirements() and trace its callers in shinylive_app_resources() and shinylive/_export.py. Compare the parser’s behavior with extras handling in shinylive/src/hooks/usePyodide.tsx, then run the existing dependency or export checks if available. Done means requirements such as shiny[theme] are handled deliberately at build time, with selected extra dependencies bundled or the limitation reported clearly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100