Skip to content

[Bug]: Fail to find function in AST when using decorator to generate function names #2016

@MichielNoback

Description

@MichielNoback

Component

UI (ui.*)

Severity

P2 - Medium (workaround exists)

Shiny Version

shiny=1.4.0

Python Version

python=3.10.18

Minimal Reproducible Example

import faicons as fa
import pandas as pd

from shiny import reactive, render
from shiny.express import ui

class_labels = [('human_animal', "Human/Animal"),
                ('environmental', "Environmental"),
                ('foodstuff', "Foods and Fluids"),
                ('other', "Other")] 

# Add page title 
ui.page_opts(title="Dashboard", fillable=True)

# MAIN PANEL CONTENT
ICONS = {
    "doc": fa.icon_svg("file"),
    "human_animal": fa.icon_svg("user", "regular"),
    "environmental": fa.icon_svg("leaf"),
    "foodstuff": fa.icon_svg("utensils"),
    "other": fa.icon_svg("question"),

}

def extend_name(extension):
    """ Decorator to extend the name of a function with a given extension."""
    def decorator(f):
        f.__name__ = f.__name__ + extension
        return f
    return decorator

with ui.layout_columns(fill=False):
    with ui.value_box(showcase=ICONS["doc"]):
        "Total documents"
        @render.express
        def total_docs():
            150

    for label_name, label_ui in class_labels:
        with ui.value_box(showcase=ICONS[label_name]):
            print(label_name, label_ui)
            label_ui
            @render.express
            @extend_name(f"_{label_name}")
            def docs_label():
                labels = docs_labels()
                if label_name in labels.index:
                    return str(labels[label_name])
                else:
                    return 0

@reactive.calc
def docs_labels():
    return  pd.Series(
        [150, 50, 30, 20],
        index=["human_animal", "environmental", "foodstuff", "other"]
    )

Behavior

When using a decorator to generate unique names for functions within ui.value_box, the app crashes with RuntimeError: Failed to find function 'docs_label_human_animal' in AST. This should never happen, please file an issue!
The piece of code that cause this is this:
@render.express
@extend_name(f"_{label_name}")
def docs_label():
labels = docs_labels()
if label_name in labels.index:
return str(labels[label_name])
else:
return 0

Error Messages (if any)

RuntimeError: Failed to find function 'docs_label_human_animal' in AST. This should never happen, please file an issue!

Environment

MacOS Sanoma 14.5
Chrome Version 137.0.7151.104


Environment:


# This file may be used to create an environment using:
# $ conda create --name <env> --file <this file>
# platform: osx-arm64
# created-by: conda 25.5.0
anyio=4.9.0=pyh29332c3_0
anywidget=0.9.18=pyhd8ed1ab_0
appdirs=1.4.4=pyhd8ed1ab_1
appnope=0.1.2=py310hca03da5_1001
argon2-cffi=25.1.0=pyhd8ed1ab_0
argon2-cffi-bindings=21.2.0=py310h493c2e1_5
arrow=1.3.0=pyhd8ed1ab_1
asgiref=3.8.1=pyhd8ed1ab_1
asttokens=3.0.0=py310hca03da5_0
async-lru=2.0.5=pyh29332c3_0
attrs=25.3.0=pyh71513ae_0
babel=2.17.0=pyhd8ed1ab_0
beautifulsoup4=4.13.4=pyha770c72_0
bleach=6.2.0=pyh29332c3_4
bleach-with-css=6.2.0=h82add2a_4
brotli=1.1.0=hd74edd7_2
brotli-bin=1.1.0=hd74edd7_2
brotli-python=1.0.9=py310h0f1eb42_8
bzip2=1.0.8=h99b78c6_7
ca-certificates=2025.4.26=hbd8a1cb_0
cached-property=1.5.2=hd8ed1ab_1
cached_property=1.5.2=pyha770c72_1
certifi=2025.4.26=pyhd8ed1ab_0
cffi=1.17.1=py310h497396d_0
charset-normalizer=3.4.2=pyhd8ed1ab_0
click=8.2.1=pyh707e725_0
comm=0.2.1=py310hca03da5_0
contourpy=1.0.7=py310h2887b22_0
cycler=0.12.1=pyhd8ed1ab_1
debugpy=1.8.11=py310h313beb8_0
decorator=5.1.1=pyhd3eb1b0_0
defusedxml=0.7.1=pyhd8ed1ab_0
exceptiongroup=1.3.0=pyhd8ed1ab_0
executing=0.8.3=pyhd3eb1b0_0
faicons=0.2.2=pyhd8ed1ab_1
fonttools=4.58.1=py310hc74094e_0
fqdn=1.5.1=pyhd8ed1ab_1
freetype=2.13.3=hce30654_1
h11=0.16.0=pyhd8ed1ab_0
h2=4.2.0=pyhd8ed1ab_0
hpack=4.1.0=pyhd8ed1ab_0
htmltools=0.6.0=pyhd8ed1ab_0
httpcore=1.0.9=pyh29332c3_0
httpx=0.28.1=pyhd8ed1ab_0
hyperframe=6.1.0=pyhd8ed1ab_0
idna=3.10=pyhd8ed1ab_1
importlib-metadata=8.7.0=pyhe01879c_1
importlib-resources=6.5.2=pyhd8ed1ab_0
importlib_resources=6.5.2=pyhd8ed1ab_0
ipykernel=6.29.5=py310hca03da5_1
ipython=8.30.0=py310hca03da5_0
ipywidgets=8.1.7=pyhd8ed1ab_0
isoduration=20.11.0=pyhd8ed1ab_1
jedi=0.19.2=py310hca03da5_0
jinja2=3.1.6=pyhd8ed1ab_0
json5=0.12.0=pyhd8ed1ab_0
jsonpointer=3.0.0=py310hbe9552e_1
jsonschema=4.24.0=pyhd8ed1ab_0
jsonschema-specifications=2025.4.1=pyh29332c3_0
jsonschema-with-format-nongpl=4.24.0=hd8ed1ab_0
jupyter=1.1.1=pyhd8ed1ab_1
jupyter-lsp=2.2.5=pyhe01879c_2
jupyter_client=8.6.3=py310hca03da5_0
jupyter_console=6.6.3=pyhd8ed1ab_1
jupyter_core=5.7.2=py310hca03da5_0
jupyter_events=0.12.0=pyh29332c3_0
jupyter_server=2.16.0=pyhe01879c_0
jupyter_server_terminals=0.5.3=pyhd8ed1ab_1
jupyterlab=4.4.3=pyhd8ed1ab_0
jupyterlab_pygments=0.3.0=pyhd8ed1ab_2
jupyterlab_server=2.27.3=pyhd8ed1ab_1
jupyterlab_widgets=3.0.15=pyhd8ed1ab_0
kiwisolver=1.4.4=py310h2887b22_1
lcms2=2.15=hd835a16_1
lerc=4.0.0=h9a09cb3_0
libblas=3.9.0=20_osxarm64_openblas
libbrotlicommon=1.1.0=hd74edd7_2
libbrotlidec=1.1.0=hd74edd7_2
libbrotlienc=1.1.0=hd74edd7_2
libcblas=3.9.0=20_osxarm64_openblas
libcxx=14.0.6=h848a8c0_0
libdeflate=1.18=h1a8c8d9_0
libexpat=2.7.0=h286801f_0
libffi=3.4.6=h1da3d7d_1
libfreetype=2.13.3=hce30654_1
libfreetype6=2.13.3=h1d14073_1
libgfortran=14.2.0=heb5dd2a_105
libgfortran5=14.2.0=h2c44a93_105
libjpeg-turbo=2.1.5.1=hb547adb_1
liblapack=3.9.0=20_osxarm64_openblas
liblzma=5.8.1=h39f12f2_1
liblzma-devel=5.8.1=h39f12f2_1
libopenblas=0.3.25=openmp_h6c19121_0
libpng=1.6.47=h3783ad8_0
libsodium=1.0.18=h1a28f6b_0
libsqlite=3.50.0=h3f77e49_0
libtiff=4.5.0=h4f7d55c_6
libwebp-base=1.5.0=h2471fea_0
libxcb=1.15=hf346824_0
libzlib=1.3.1=h8359307_2
linkify-it-py=2.0.3=pyhd8ed1ab_1
llvm-openmp=20.1.6=hdb05f8b_0
markdown-it-py=3.0.0=pyhd8ed1ab_1
markupsafe=3.0.2=py310hc74094e_1
matplotlib-base=3.7.1=py310h78c5c2f_0
matplotlib-inline=0.1.6=py310hca03da5_0
mdit-py-plugins=0.4.2=pyhd8ed1ab_1
mdurl=0.1.2=pyhd8ed1ab_1
mistune=3.1.3=pyh29332c3_0
munkres=1.1.4=pyh9f0ad1d_0
narwhals=1.41.0=pyhe01879c_0
nb_conda_kernels=2.5.1=pyh707e725_2
nbclient=0.10.2=pyhd8ed1ab_0
nbconvert-core=7.16.6=pyh29332c3_0
nbformat=5.10.4=pyhd8ed1ab_1
ncurses=6.5=h5e97a16_3
nest-asyncio=1.6.0=py310hca03da5_0
notebook=7.4.3=pyhd8ed1ab_0
notebook-shim=0.2.4=pyhd8ed1ab_1
numpy=1.24.2=py310h3d2048e_0
openjpeg=2.5.0=hbc2ba62_2
openssl=3.5.0=h81ee809_1
orjson=3.10.18=py310h31b3829_1
overrides=7.7.0=pyhd8ed1ab_1
packaging=25.0=pyh29332c3_1
pandas=2.0.0=py310h2b830bf_0
pandocfilters=1.5.0=pyhd8ed1ab_0
parso=0.8.4=py310hca03da5_0
patsy=1.0.1=pyhd8ed1ab_1
pexpect=4.8.0=pyhd3eb1b0_3
pillow=9.5.0=py310h60ecbdf_1
pip=25.1.1=pyh8b19718_0
pkgutil-resolve-name=1.3.10=pyhd8ed1ab_2
platformdirs=4.3.7=py310hca03da5_0
plotly=6.1.2=pyhd8ed1ab_0
pooch=1.8.2=pyhd8ed1ab_1
prometheus_client=0.22.1=pyhd8ed1ab_0
prompt-toolkit=3.0.51=pyha770c72_0
prompt_toolkit=3.0.51=hd8ed1ab_0
psutil=5.9.0=py310h80987f9_1
psygnal=0.13.0=pyhd8ed1ab_0
pthread-stubs=0.4=hd74edd7_1002
ptyprocess=0.7.0=pyhd3eb1b0_2
pure_eval=0.2.2=pyhd3eb1b0_0
pycparser=2.22=pyh29332c3_1
pygments=2.19.1=py310hca03da5_0
pyobjc-core=11.0=py310h4e4eb3c_0
pyobjc-framework-cocoa=11.0=py310h4e4eb3c_0
pyparsing=3.2.3=pyhd8ed1ab_1
pysocks=1.7.1=pyha55dd90_7
python=3.10.18=h6cefb37_0_cpython
python-dateutil=2.9.0post0=py310hca03da5_2
python-fastjsonschema=2.21.1=pyhd8ed1ab_0
python-json-logger=2.0.7=pyhd8ed1ab_0
python-multipart=0.0.20=pyhff2d567_0
python-tzdata=2025.2=pyhd8ed1ab_0
python_abi=3.10=7_cp310
pytz=2025.2=pyhd8ed1ab_0
pyyaml=6.0.2=py310hc74094e_2
pyzmq=26.2.0=py310h313beb8_0
questionary=2.0.1=pyhd8ed1ab_0
readline=8.2=h1d1bf99_2
referencing=0.36.2=pyh29332c3_0
requests=2.32.3=pyhd8ed1ab_1
rfc3339-validator=0.1.4=pyhd8ed1ab_1
rfc3986-validator=0.1.1=pyh9f0ad1d_0
ridgeplot=0.3.2=pyhd8ed1ab_0
rpds-py=0.25.1=py310hb4f9fe2_0
scipy=1.10.1=py310ha0d8a01_2
seaborn=0.13.2=hd8ed1ab_3
seaborn-base=0.13.2=pyhd8ed1ab_3
send2trash=1.8.3=pyh31c8845_1
setuptools=80.9.0=pyhff2d567_0
shiny=1.4.0=pyhd8ed1ab_0
shinywidgets=0.6.2=pyhd8ed1ab_0
six=1.17.0=py310hca03da5_0
sniffio=1.3.1=pyhd8ed1ab_1
soupsieve=2.7=pyhd8ed1ab_0
stack_data=0.2.0=pyhd3eb1b0_0
starlette=0.47.0=pyh82d4cca_0
statsmodels=0.14.4=py310hae04be4_0
terminado=0.18.1=pyh31c8845_0
tinycss2=1.4.0=pyhd8ed1ab_0
tk=8.6.13=h892fb3f_2
tomli=2.2.1=pyhd8ed1ab_1
tornado=6.5.1=py310h80987f9_0
traitlets=5.14.3=py310hca03da5_0
types-python-dateutil=2.9.0.20250516=pyhd8ed1ab_0
typing-extensions=4.14.0=h32cad80_0
typing_extensions=4.14.0=pyhe01879c_0
typing_utils=0.1.0=pyhd8ed1ab_1
tzdata=2025b=h78e105d_0
uc-micro-py=1.0.3=pyhd8ed1ab_1
unicodedata2=16.0.0=py310h078409c_0
uri-template=1.3.0=pyhd8ed1ab_1
urllib3=2.4.0=pyhd8ed1ab_0
uvicorn=0.34.3=pyh31011fe_0
watchfiles=1.0.5=py310hde4708a_0
wcwidth=0.2.13=pyhd8ed1ab_1
webcolors=24.11.1=pyhd8ed1ab_0
webencodings=0.5.1=pyhd8ed1ab_3
websocket-client=1.8.0=pyhd8ed1ab_1
websockets=15.0.1=py310h078409c_0
wheel=0.45.1=pyhd8ed1ab_1
widgetsnbextension=4.0.14=pyhd8ed1ab_0
wrapt=1.17.2=py310h078409c_0
xorg-libxau=1.0.12=h5505292_0
xorg-libxdmcp=1.1.5=hd74edd7_0
xz=5.8.1=h9a6d368_1
xz-gpl-tools=5.8.1=h9a6d368_1
xz-tools=5.8.1=h39f12f2_1
yaml=0.2.5=h3422bc3_2
zeromq=4.3.5=h313beb8_0
zipp=3.22.0=pyhd8ed1ab_0
zstandard=0.23.0=py310h078409c_2
zstd=1.5.7=h6491c7d_2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions