posit-dev / py-shiny

Shiny for Python
https://shiny.posit.co/py/
MIT License
1.29k stars 78 forks source link

include helpers don't work when used twice in the same dir #729

Open jcheng5 opened 1 year ago

jcheng5 commented 1 year ago

From Discord thread: https://discord.com/channels/1109483223987277844/1148651437820231710

Basically, if you use two (or more?) of the include helpers (ui.include_js, ui.include_css, etc.) pointing to files in the same directory, only one of them actually succeeds. The others 404.

shinylive repro link

pieterjanvc commented 5 months ago

Hello,

Any updates on this? I'm facing the same issue and how it can be fixed soon. (the workaround is good for now though, but it took me ages to find this post and spent debugging in vain)

Thanks!

rkaramc commented 1 month ago

Hi, Problem occurs because maybe_copy_files(path, include_files) is dropping the tmpdir before copying the file at path to it.

https://github.com/posit-dev/py-shiny/blob/33c8c79b7edf28f2e0d1d1e2b6051eed084d15ad/shiny/ui/_include_helpers.py#L215-L216 https://github.com/posit-dev/py-shiny/blob/33c8c79b7edf28f2e0d1d1e2b6051eed084d15ad/shiny/ui/_include_helpers.py#L228-L230

Related issue at https://github.com/posit-dev/py-shiny/issues/1427#issuecomment-2133065164_. @Konkrad fixed it by placing each file in its own directory.

I fixed the issue by placing the files all in a single directory, but then calling ui.include_js(path, method="link_files") for each file. Here, the multiple calls to include_js are redundant, as the directory and it's children are copied multiple times. However, this redundancy is necessary to create the script tags for each file to be included.

My initial approach was to patch maybe_copy_file to comment out the call to shutil.rmtree on line 230. Worked fine, but this seemed to be over-kill! A better approach may be to rm only the file being included. Or to allow a list of files to be sent to include_js.

Hope this helps!

rkaramc commented 1 month ago

Update to the above... another approach...

I added a __init__.js to the js directory - all it contains are import statements for each of the other js files. Then called ui.include_js("js/__init__.py", method="link_files"). So there is only one call to ui.include_js, and the js directory and it's files are not being rmtree'ed and copied over repeatedly.