✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

NameError: 'send_from_directory' is not defined or Runtimeerror: Working outside of application context

Hello,

I’m beginning to wrap my head around flask’s app.app_context(), which I think I might need in the following mwe. What I’m trying to do is to make some files which are provided by the parameter “user_assets_paths” available via @app.route. To achieve this I am using the exec() command, because i need a different function name for each route, otherwise I will get an error saying I am trying to overwrite an existing function.

Inside of the exec()-function, if i don’t import send_from_directory(), i’m getting the NameError. If it’s not imported, I’m getting the RuntimeError.

I’m looking forward to your suggestions on how to achieve what I’m trying to do.

mwe.py:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, State, Output
from pathlib import Path

app = dash.Dash()
app.layout = html.Div(["hello world"])
user_assets_paths = ["."]


def getfile_path_name_extension(directories_or_files: list):
    """
    :param list[str] directories_or_files: A list of directory- or filepaths.  Directories will not be searched for files recursively
    :returns list[tuple] filesplits: file-information splitted into tuples with filepath, filename and fileextension
    """
    directories_or_files = [
        Path(path).absolute() for path in directories_or_files
    ]
    filepaths = set()
    for path in directories_or_files:
        if path.is_file():
            filepaths.add(path)
        else:
            for filepath in [
                path / entry
                for entry in path.glob("*")
                if (path / entry).is_file()
            ]:
                filepaths.add(filepath)
    filesplits = []
    for filepath in filepaths:
        fileextension = "".join(suffix for suffix in filepath.suffixes)
        filename = filepath.stem
        filepath = filepath.parent
        filesplits.append((filepath, filename, fileextension))
    print(filesplits)
    return filesplits


def exec_get_file(iteration):
    func = {}
    exec(
        f"""def get_file{iteration}(filepath, filename, fileextension):
        filename = f"{filename}{fileextension}"
        print(filepath, filename, fileextension)
        try:
            from flask import send_from_directory
            return send_from_directory(filepath, filename)
        except FileNotFoundError:
            abort(404)""",
        func,
    )
    print(func[f"get_file{iteration}"])
    return func[f"get_file{iteration}"]


for iteration, (filepath, filename, fileextension) in enumerate(
    getfile_path_name_extension(user_assets_paths)
):
    app.server.route(
        f"/user_assets/{fileextension.replace('.', '')}/{filename}"
    )(exec_get_file(iteration)(filepath, filename, fileextension))

if __name__ == "__main__":
    app.run_server(debug=True)

Could you elaborate on your usecase? What should the functionality be used for?

I want to abstract as much as possible, since the app is gonna be used by researchers, who might only know python, and don’t have a clue about flask, javascript or css.
The particular use case is that they only need to specify a file and/or folder in which some .js, .css files are located, which overwrite the page template (which is not done in the mwe, but I already implemented this part). The css-file will then be provided by another person which is more knowledgable about webpage-design.