import logging from fastapi import ( Path, Request, Response, ) from galaxy.tool_util.parameters import ( LandingRequestToolState, RequestToolState, TestCaseToolState, ) from galaxy.webapps.galaxy.api import json_schema_response_for_tool_state_model from tool_shed.context import SessionRequestContext from tool_shed.managers.tools import ( parsed_tool_model_cached_for, search, tool_source_for, ) from tool_shed.managers.trs import ( get_tool, service_info, tool_classes, ) from tool_shed.structured_app import ToolShedApp from tool_shed.util.shed_index import build_index from tool_shed_client.schema import ( BuildSearchIndexResponse, ShedParsedTool, ) from tool_shed_client.schema.trs import ( Tool, ToolClass, ToolVersion, ) from tool_shed_client.schema.trs_service_info import Service from . import ( depends, DependsOnTrans, RepositorySearchPageSizeQueryParam, Router, ToolSearchPageQueryParam, ToolsIndexQueryParam, ) log = logging.getLogger(__name__) router = Router(tags=["tools"]) TOOL_ID_PATH_PARAM: str = Path( ..., title="GA4GH TRS Tool ID", description="See also https://ga4gh.github.io/tool-registry-service-schemas/DataModel/#trs-tool-and-trs-tool-version-ids", ) TOOL_VERSION_PATH_PARAM: str = Path( ..., title="Galaxy Tool Wrapper Version", description="The full version string defined on the Galaxy tool wrapper.", ) @router.cbv class FastAPITools: app: ToolShedApp = depends(ToolShedApp) @router.get( "/api/tools", operation_id="tools__index", ) def index( self, q: str = ToolsIndexQueryParam, page: int = ToolSearchPageQueryParam, page_size: int = RepositorySearchPageSizeQueryParam, trans: SessionRequestContext = DependsOnTrans, ): search_results = search(trans, q, page, page_size) return search_results @router.put( "/api/tools/build_search_index", operation_id="tools__build_search_index", require_admin=True, ) def build_search_index(self) -> BuildSearchIndexResponse: """Not part of the stable API, just something to simplify bootstrapping tool sheds, scripting, testing, etc... """ config = self.app.config repos_indexed, tools_indexed = build_index( config.whoosh_index_dir, config.file_path, config.hgweb_config_dir, config.hgweb_repo_prefix, config.database_connection, ) return BuildSearchIndexResponse( repositories_indexed=repos_indexed, tools_indexed=tools_indexed, ) @router.get("/api/ga4gh/trs/v2/service-info", operation_id="tools_trs_service_info") def service_info(self, request: Request) -> Service: return service_info(self.app, request.url) @router.get("/api/ga4gh/trs/v2/toolClasses", operation_id="tools__trs_tool_classes") def tool_classes(self) -> list[ToolClass]: return tool_classes() @router.get( "/api/ga4gh/trs/v2/tools", operation_id="tools__trs_index", ) def trs_index( self, ): # we probably want to be able to query the database at the # tool level and such to do this right? return [] @router.get( "/api/ga4gh/trs/v2/tools/{tool_id}", operation_id="tools__trs_get", ) def trs_get( self, trans: SessionRequestContext = DependsOnTrans, tool_id: str = TOOL_ID_PATH_PARAM, ) -> Tool: return get_tool(trans, tool_id) @router.get( "/api/ga4gh/trs/v2/tools/{tool_id}/versions", operation_id="tools__trs_get_versions", ) def trs_get_versions( self, trans: SessionRequestContext = DependsOnTrans, tool_id: str = TOOL_ID_PATH_PARAM, ) -> list[ToolVersion]: return get_tool(trans, tool_id).versions @router.get( "/api/tools/{tool_id}/versions/{tool_version}", operation_id="tools__parameter_model", summary="Return Galaxy's meta model description of the tool's inputs", ) def show_tool( self, trans: SessionRequestContext = DependsOnTrans, tool_id: str = TOOL_ID_PATH_PARAM, tool_version: str = TOOL_VERSION_PATH_PARAM, ) -> ShedParsedTool: return parsed_tool_model_cached_for(trans, tool_id, tool_version) @router.get( "/api/tools/{tool_id}/versions/{tool_version}/parameter_request_schema", operation_id="tools__parameter_request_schema", summary="Return a JSON schema description of the tool's inputs for the tool request API that will be added to Galaxy at some point", description="The tool request schema includes validation of map/reduce concepts that can be consumed by the tool execution API and not just the request for a single execution.", ) def tool_state_request( self, trans: SessionRequestContext = DependsOnTrans, tool_id: str = TOOL_ID_PATH_PARAM, tool_version: str = TOOL_VERSION_PATH_PARAM, ) -> Response: parsed_tool = parsed_tool_model_cached_for(trans, tool_id, tool_version) return json_schema_response_for_tool_state_model(RequestToolState, parsed_tool.inputs) @router.get( "/api/tools/{tool_id}/versions/{tool_version}/parameter_landing_request_schema", operation_id="tools__parameter_landing_request_schema", summary="Return a JSON schema description of the tool's inputs for the tool landing request API.", ) def tool_state_landing_request( self, trans: SessionRequestContext = DependsOnTrans, tool_id: str = TOOL_ID_PATH_PARAM, tool_version: str = TOOL_VERSION_PATH_PARAM, ) -> Response: parsed_tool = parsed_tool_model_cached_for(trans, tool_id, tool_version) return json_schema_response_for_tool_state_model(LandingRequestToolState, parsed_tool.inputs) @router.get( "/api/tools/{tool_id}/versions/{tool_version}/parameter_test_case_xml_schema", operation_id="tools__parameter_test_case_xml_schema", summary="Return a JSON schema description of the tool's inputs for test case construction.", ) def tool_state_test_case_xml( self, trans: SessionRequestContext = DependsOnTrans, tool_id: str = TOOL_ID_PATH_PARAM, tool_version: str = TOOL_VERSION_PATH_PARAM, ) -> Response: parsed_tool = parsed_tool_model_cached_for(trans, tool_id, tool_version) return json_schema_response_for_tool_state_model(TestCaseToolState, parsed_tool.inputs) @router.get( "/api/tools/{tool_id}/versions/{tool_version}/tool_source", operation_id="tools__tool_source", summary="Return the expanded tool document as a string.", ) def tool_source( self, trans: SessionRequestContext = DependsOnTrans, tool_id: str = TOOL_ID_PATH_PARAM, tool_version: str = TOOL_VERSION_PATH_PARAM, ) -> Response: source, _ = tool_source_for(trans, tool_id, tool_version) return Response( content=source.to_string(), headers={"language": source.language}, )