posit-dev / posit-dev/py-shiny

feat: Expose missing App attributes in Express via app_opts() and/or an app accessor

Open
#2,195 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.8k
Forks
135
Avg merge
2d 18h
Merged PRs (30d)
21

Description

Problem

Shiny Express apps configure app-level options via app_opts(), but it only covers a subset of what can be set on a shiny.App object in Core mode. Several important App attributes are completely inaccessible from Express:

Attribute Core mode Express app_opts()
static_assets App(...) constructor ✅ supported
bookmark_store App(...) constructor ✅ supported
debug App(...) constructor ✅ supported
sanitize_errors app.sanitize_errors = True ❌ missing
sanitize_error_msg app.sanitize_error_msg = "..." ❌ missing
sanitize_otel_errors app.sanitize_otel_errors = False ❌ missing
lib_prefix app.lib_prefix = "assets/" ❌ missing

In Core mode, an app sets these like:

app = App(app_ui, server)
app.sanitize_errors = True
app.sanitize_otel_errors = False
app.sanitize_error_msg = "Something went wrong."

In Express, there is no equivalent — app_opts() doesn't support any of them and the underlying App object is never exposed to the user.

Proposed Solutions

Option A: Extend app_opts() with all missing attributes

Add the missing parameters to the existing app_opts() function:

app_opts(
    sanitize_errors=True,
    sanitize_otel_errors=False,
    sanitize_error_msg="Something went wrong.",
    lib_prefix="assets/",
)

Pros: Consistent with the existing pattern; all options in one place.
Cons: app_opts() grows with every new App attribute; may lag behind future additions.

Option B: Provide an accessor to the underlying App object

Expose a function (e.g., express.get_app()) that returns the live App instance, allowing direct attribute mutation:

from shiny.express import get_app

get_app().sanitize_errors = True
get_app().sanitize_otel_errors = False

Pros: No need to update app_opts() every time App gains a new attribute; users have full control; mirrors the Core mode experience.
Cons: Requires the App to exist at call time (it's created during create_express_app()); needs careful handling of the execution lifecycle; slightly less discoverable.

Option C: Both — extend app_opts() and add an accessor

Keep app_opts() for the most common options, and add get_app() as an escape hatch for advanced use.

Recommendation

Implement Option C:

  1. Add sanitize_errors, sanitize_otel_errors, and sanitize_error_msg to app_opts() since they're immediately needed and commonly configured.
  2. Add a get_app() (or similar name — current_app(), express_app()?) accessor as an escape hatch so future App attributes don't require app_opts() updates.

The naming of the accessor is worth discussion — options include:

  • express.get_app()
  • express.current_app()
  • express.app() (but could conflict with the app module)

Related

  • shiny/express/_run.pyapp_opts() and AppOpts TypedDict
  • shiny/_app.pyApp class with all mutable attributes
  • examples/req/app.py — Core mode example using app.sanitize_errors = True

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with shiny/express/_run.py, especially app_opts() and the AppOpts TypedDict, then inspect shiny/_app.py for the mutable attributes listed in the issue. Review examples/req/app.py for the Core-mode behavior. Done means selecting and implementing the agreed accessor and/or option design so the missing Express configuration is available, with the lifecycle and API naming resolved.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.