import importlib.util import sys from pathlib import Path from flask import Flask, render_template_string from werkzeug.middleware.dispatcher import DispatcherMiddleware from werkzeug.serving import run_simple root = Flask(__name__) @root.route("/") def index(): apps = [ d.name for d in Path(__file__).parent.iterdir() if d.is_dir() and (d / "app.py").exists() ] items = "".join( f'' f'\u203a' f'
{a.replace("_", " ").replace("-", " ").title()}
' f'
/{a}
' f"
" for i, a in enumerate(sorted(apps)) ) return render_template_string(f""" Tools

Tools

Flask applications

{items}
""") def load_sub_apps(): mounts = {} base = Path(__file__).parent for app_dir in sorted(base.iterdir()): app_file = app_dir / "app.py" if not app_dir.is_dir() or not app_file.exists(): continue spec = importlib.util.spec_from_file_location(app_dir.name, app_file) mod = importlib.util.module_from_spec(spec) sys.modules[app_dir.name] = ( mod # must be registered before exec so Flask(__name__) resolves root_path correctly ) spec.loader.exec_module(mod) mounts[f"/{app_dir.name}"] = mod.app print(f" mounted /{app_dir.name}") return mounts application = DispatcherMiddleware(root, load_sub_apps()) if __name__ == "__main__": run_simple("0.0.0.0", 8080, application, use_reloader=False)