Skip to content

Commit de5ab4d

Browse files
committed
More generally cleanup temp dirs
1 parent d64dcea commit de5ab4d

File tree

1 file changed

+26
-17
lines changed

1 file changed

+26
-17
lines changed

shiny/_app.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -217,24 +217,33 @@ def __init__(
217217
)
218218

219219
def __del__(self) -> None:
220+
deps = self._registered_dependencies.values()
221+
self._cleanup_temp_source_dirs(list(deps))
222+
223+
@staticmethod
224+
def _cleanup_temp_source_dirs(deps: list[HTMLDependency]) -> None:
225+
# include_css()/include_js() create temporary directories to hold files that
226+
# persist across user sessions, but also need to be cleaned up at some point,
227+
# and Python (unlike R) does not cleanup tempdirs on process exit. So, our next
228+
# best option is to clean them up when the App object is deleted. It's not
229+
# perfect (the App object might be deleted while the process is still running,
230+
# and there might be multiple App objects using the same UI). However, it still
231+
# seems worth doing since that is such a hypothetical edge case. More generally,
232+
# if _any_ HTMLDependency with a source directory that is a _subdirectory_ of
233+
# the (system-wide) temp directory, we should remove it.
220234
current_temp_dir = os.path.realpath(tempfile.gettempdir())
221-
222-
# Ignoring a type hint on source["subdir"] because all of our user-created dependencies
223-
# must have a "subdir" source, but the HTMLDependency type allows for other variations.
224-
user_dependencies: list[str] = [
225-
v.source["subdir"] # type: ignore
226-
for k, v in self._registered_dependencies.items()
227-
if k.startswith("include-")
228-
]
229-
230-
for item in user_dependencies:
231-
# Only remove the item if it exists and it is in the current temp directory
232-
if (
233-
os.path.exists(item)
234-
and os.path.commonprefix([os.path.realpath(item), current_temp_dir])
235-
== current_temp_dir
236-
):
237-
shutil.rmtree(item)
235+
for dep in deps:
236+
src = dep.source_path_map()["source"]
237+
if not src:
238+
continue
239+
src = os.path.realpath(src)
240+
if not os.path.exists(src):
241+
continue
242+
if src == current_temp_dir:
243+
continue
244+
common = os.path.commonprefix([src, current_temp_dir])
245+
if common == current_temp_dir:
246+
shutil.rmtree(src)
238247

239248
def init_starlette_app(self) -> starlette.applications.Starlette:
240249
routes: list[starlette.routing.BaseRoute] = [

0 commit comments

Comments
 (0)