diff --git a/lib/galaxy/dependencies/pinned-requirements.txt b/lib/galaxy/dependencies/pinned-requirements.txt index c1434db0261a..430f6620d443 100644 --- a/lib/galaxy/dependencies/pinned-requirements.txt +++ b/lib/galaxy/dependencies/pinned-requirements.txt @@ -68,7 +68,7 @@ edam-ontology==1.25.2 email-validator==2.3.0 et-xmlfile==2.0.0 exceptiongroup==1.3.0 ; python_full_version < '3.11' -fastapi-slim==0.118.3 +fastapi==0.118.3 filelock==3.19.1 ; python_full_version < '3.10' filelock==3.20.0 ; python_full_version >= '3.10' fissix==24.4.24 @@ -224,7 +224,7 @@ tomli==2.3.0 ; python_full_version < '3.11' tornado==6.5.2 tqdm==4.67.1 tuspy==1.1.0 -tuswsgi==0.5.5 +tuspyserver==4.2.0 typing-extensions==4.15.0 typing-inspection==0.4.2 tzdata==2025.2 diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 16cbf2d9968f..bdcc6815c586 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -8,10 +8,8 @@ import threading import traceback from typing import Optional -from urllib.parse import urljoin from paste import httpexceptions -from tuswsgi import TusMiddleware import galaxy.app import galaxy.datatypes.registry @@ -1084,30 +1082,6 @@ def wrap_in_middleware(app, global_conf, application_stack, **local_conf): from galaxy.web.framework.middleware.translogger import TransLogger app = wrap_if_allowed(app, stack, TransLogger) - # TUS upload middleware - app = wrap_if_allowed( - app, - stack, - TusMiddleware, - kwargs={ - "upload_path": urljoin(f"{application_stack.config.galaxy_url_prefix}/", "api/upload/resumable_upload"), - "tmp_dir": application_stack.config.tus_upload_store or application_stack.config.new_file_path, - "max_size": application_stack.config.maximum_upload_file_size, - }, - ) - # TUS upload middleware for job files.... - app = wrap_if_allowed( - app, - stack, - TusMiddleware, - kwargs={ - "upload_path": urljoin(f"{application_stack.config.galaxy_url_prefix}/", "api/job_files/resumable_upload"), - "tmp_dir": application_stack.config.tus_upload_store_job_files - or application_stack.config.tus_upload_store - or application_stack.config.new_file_path, - "max_size": application_stack.config.maximum_upload_file_size, - }, - ) # X-Forwarded-Host handling app = wrap_if_allowed(app, stack, XForwardedHostMiddleware) # Request ID middleware diff --git a/lib/galaxy/webapps/galaxy/fast_app.py b/lib/galaxy/webapps/galaxy/fast_app.py index fa8ddd6aa072..87c0f7e78d76 100644 --- a/lib/galaxy/webapps/galaxy/fast_app.py +++ b/lib/galaxy/webapps/galaxy/fast_app.py @@ -1,6 +1,7 @@ from typing import ( Any, ) +from urllib.parse import urljoin from a2wsgi import WSGIMiddleware from fastapi import ( @@ -9,6 +10,7 @@ ) from fastapi.openapi.constants import REF_TEMPLATE from starlette.middleware.cors import CORSMiddleware +from tuspyserver import create_tus_router from galaxy.schema.generics import CustomJsonSchema from galaxy.version import VERSION @@ -165,6 +167,23 @@ def get_openapi_schema() -> dict[str, Any]: ) +def include_tus(app: FastAPI, gx_app): + config = gx_app.config + root_path = "" if config.galaxy_url_prefix == "/" else config.galaxy_url_prefix + upload_tus_router = create_tus_router( + prefix=urljoin(root_path, "api/upload/resumable_upload"), + files_dir=config.tus_upload_store or config.new_file_path, + max_size=config.maximum_upload_file_size, + ) + job_files_tus_router = create_tus_router( + prefix=urljoin(root_path, "api/job_files/resumable_upload"), + files_dir=config.tus_upload_store_job_files or config.tus_upload_store or config.new_file_path, + max_size=config.maximum_upload_file_size, + ) + app.include_router(upload_tus_router) + app.include_router(job_files_tus_router) + + def initialize_fast_app(gx_wsgi_webapp, gx_app): root_path = "" if gx_app.config.galaxy_url_prefix == "/" else gx_app.config.galaxy_url_prefix app = get_fastapi_instance(root_path=root_path) @@ -178,6 +197,7 @@ def initialize_fast_app(gx_wsgi_webapp, gx_app): include_legacy_openapi(app, gx_app) wsgi_handler = WSGIMiddleware(gx_wsgi_webapp) gx_app.haltables.append(("WSGI Middleware threadpool", wsgi_handler.executor.shutdown)) + include_tus(app, gx_app) app.mount("/", wsgi_handler) # type: ignore[arg-type] if gx_app.config.galaxy_url_prefix != "/": parent_app = FastAPI() diff --git a/packages/web_apps/setup.cfg b/packages/web_apps/setup.cfg index 759204cf599b..369958790750 100644 --- a/packages/web_apps/setup.cfg +++ b/packages/web_apps/setup.cfg @@ -60,7 +60,7 @@ install_requires = SQLAlchemy>=2.0.37,<2.1,!=2.0.41 starlette starlette-context - tuswsgi + tuspyserver typing-extensions uvicorn uvloop>=0.21.0 diff --git a/pyproject.toml b/pyproject.toml index 1aea3f00e225..217d0baced7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dependencies = [ "docutils!=0.17,!=0.17.1", "dparse", "edam-ontology", - "fastapi-slim>=0.111.0,!=0.119.*,!=0.120.0,!=0.120.1,!=0.120.2", # https://github.com/fastapi/fastapi/pull/13918 + "fastapi>=0.111.0,!=0.119.*,!=0.120.0,!=0.120.1,!=0.120.2", # https://github.com/fastapi/fastapi/pull/13918 "fissix", "fs", "future>=1.0.0", # Python 3.12 support @@ -101,8 +101,8 @@ dependencies = [ "starlette-context", "svgwrite", "tifffile", - "tuswsgi", "typing-extensions", + "tuspyserver", "uvicorn!=0.28.0", # https://github.com/galaxyproject/galaxy/issues/17669 "uvloop>=0.21.0", # Python 3.13 support "WebOb>=1.8.9", # Python 3.13 support