Skip to content

Commit 8e530f1

Browse files
committed
Tool Landing API...
1 parent 3aa3bec commit 8e530f1

File tree

13 files changed

+500
-22
lines changed

13 files changed

+500
-22
lines changed

client/src/api/schema/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7832,7 +7832,7 @@ export interface components {
78327832
* @default false
78337833
*/
78347834
public: boolean;
7835-
request_state?: components["schemas"]["DataLandingRequestState"];
7835+
request_state: components["schemas"]["DataLandingRequestState"];
78367836
};
78377837
/** CreateEntryPayload */
78387838
CreateEntryPayload: {

lib/galaxy/managers/landing.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,21 @@
2929
WorkflowLandingRequest,
3030
)
3131
from galaxy.security.idencoding import IdEncodingHelper
32-
from galaxy.structured_app import StructuredApp
32+
from galaxy.structured_app import (
33+
MinimalManagerApp,
34+
StructuredApp,
35+
)
36+
from galaxy.tool_util.parameters import (
37+
landing_decode,
38+
LandingRequestInternalToolState,
39+
LandingRequestToolState,
40+
)
3341
from galaxy.util import safe_str_cmp
3442
from .context import ProvidesUserContext
43+
from .tools import (
44+
get_tool_from_toolbox,
45+
ToolRunReference,
46+
)
3547

3648
LandingRequestModel = Union[ToolLandingRequestModel, WorkflowLandingRequestModel]
3749

@@ -43,16 +55,37 @@ def __init__(
4355
sa_session: galaxy_scoped_session,
4456
security: IdEncodingHelper,
4557
workflow_contents_manager: WorkflowContentsManager,
58+
app: MinimalManagerApp,
4659
):
4760
self.sa_session = sa_session
4861
self.security = security
4962
self.workflow_contents_manager = workflow_contents_manager
63+
self.app = app
5064

5165
def create_tool_landing_request(self, payload: CreateToolLandingRequestPayload, user_id=None) -> ToolLandingRequest:
66+
tool_id = payload.tool_id
67+
tool_version = payload.tool_version
68+
request_state = payload.request_state
69+
70+
ref = ToolRunReference(tool_id=tool_id, tool_version=tool_version, tool_uuid=None)
71+
tool = get_tool_from_toolbox(self.app.toolbox, ref)
72+
landing_request_state = LandingRequestToolState(request_state or {})
73+
# Okay this is a hack until tool request API commit is merged, tools don't yet have a parameter
74+
# schema - so we can't do this properly.
75+
if hasattr(tool, "parameters"):
76+
internal_landing_request_state = landing_decode(landing_request_state, tool, self.security.decode_id)
77+
else:
78+
assert tool.id == "__DATA_FETCH__"
79+
# we have validated the payload as part of the API request
80+
# nothing else to decode ideally so just swap to internal model state object
81+
internal_landing_request_state = LandingRequestInternalToolState(
82+
input_state=landing_request_state.input_state
83+
)
84+
5285
model = ToolLandingRequestModel()
53-
model.tool_id = payload.tool_id
54-
model.tool_version = payload.tool_version
55-
model.request_state = payload.request_state
86+
model.tool_id = tool_id
87+
model.tool_version = tool_version
88+
model.request_state = internal_landing_request_state.input_state
5689
model.uuid = uuid4()
5790
model.client_secret = payload.client_secret
5891
model.public = payload.public

lib/galaxy/model/store/discover.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -985,10 +985,10 @@ def replace_request_syntax_sugar(obj):
985985
# item...
986986
new_hashes = []
987987
for key in HASH_NAME_MAP.keys():
988-
if key in obj:
988+
if key in obj and obj[key] is not None:
989989
new_hashes.append({"hash_function": key, "hash_value": obj[key]})
990990
del obj[key]
991-
if key.lower() in obj:
991+
if key.lower() in obj and obj[key.lower()] is not None:
992992
new_hashes.append({"hash_function": key, "hash_value": obj[key.lower()]})
993993
del obj[key.lower()]
994994
# hack around pydantic stick a None in here for data fetch models.

lib/galaxy/schema/fetch_data.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
Field,
1414
field_validator,
1515
Json,
16+
TypeAdapter,
1617
)
1718
from typing_extensions import (
1819
Literal,
@@ -205,7 +206,9 @@ class CompositeItems(FetchBaseModel):
205206

206207

207208
class NestedElement(BaseDataElement):
208-
elements: list[Union["AnyElement", "NestedElement"]] = Field(..., alias="elements")
209+
elements: list[Union["AnyElement", "NestedElement"]] = Field(
210+
..., validation_alias=AliasChoices("elements", "items")
211+
)
209212

210213

211214
AnyElement = Annotated[
@@ -287,6 +290,9 @@ def targets_string_to_json(cls, v):
287290
]
288291

289292

293+
TargetsAdapter = TypeAdapter(Targets)
294+
295+
290296
class FetchDataPayload(BaseDataPayload):
291297
targets: Targets
292298

@@ -301,10 +307,8 @@ class DataLandingRequestState(Model):
301307

302308
# Vaguely matches the schema.schema.ToolLandingState but we don't allow data_fetch to be called directly
303309
# via the tool API so we have a more specific model here.
304-
class DataLandingPayload(Model):
305-
tool_id: str
306-
tool_version: Optional[str] = None
307-
request_state: DataLandingRequestState = None
310+
class CreateDataLandingPayload(Model):
311+
request_state: DataLandingRequestState
308312
client_secret: Optional[str] = None
309313
public: bool = False
310314

lib/galaxy/tool_util/client/landing.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,18 @@
2424

2525

2626
def load_default_catalog():
27-
catalog_yaml = resource_string(__name__, "landing_catalog.sample.yml")
27+
name = __name__
28+
if __name__ == "__main__":
29+
name = "galaxy.tool_util.client.landing"
30+
catalog_yaml = resource_string(name, "landing_library.catalog.yml")
2831
return yaml.safe_load(catalog_yaml)
2932

3033

3134
@dataclass
3235
class Request:
3336
template_id: str
3437
catalog: str
38+
public: bool
3539
client_secret: Optional[str]
3640
galaxy_url: str
3741

@@ -56,9 +60,16 @@ def generate_claim_url(request: Request) -> Response:
5660
else:
5761
catalog = load_default_catalog()
5862
template = catalog[template_id]
59-
template_type = "tool" if "tool_id" in template else "workflow"
63+
if "tool_id" in template:
64+
template_type = "tool"
65+
elif "workflow_id" in template:
66+
template_type = "workflow"
67+
else:
68+
template_type = "data"
6069
if client_secret:
6170
template["client_secret"] = client_secret
71+
if request.public:
72+
template["public"] = True
6273

6374
landing_request_url = f"{galaxy_url}/api/{template_type}_landings"
6475
raw_response = requests.post(
@@ -70,7 +81,8 @@ def generate_claim_url(request: Request) -> Response:
7081
except Exception:
7182
raise Exception("Request failed: %s", raw_response.text)
7283
response = raw_response.json()
73-
url = f"{galaxy_url}/{template_type}_landings/{response['uuid']}"
84+
response_type = "workflow" if template_type == "workflow" else "tool"
85+
url = f"{galaxy_url}/{response_type}_landings/{response['uuid']}"
7486
if client_secret:
7587
url = url + f"?secret={client_secret}"
7688
return Response(url)
@@ -100,6 +112,14 @@ def arg_parser() -> argparse.ArgumentParser:
100112
default=None,
101113
help="An optional client secret to verify the request against, set to __GEN__ to generate one at random for this request.",
102114
)
115+
parser.add_argument(
116+
"-p",
117+
"--public",
118+
dest="public",
119+
default=False,
120+
action="store_true",
121+
help="Declare the landing as public.",
122+
)
103123
return parser
104124

105125

@@ -111,6 +131,7 @@ def main(argv=None) -> None:
111131
request = Request(
112132
args.template_id,
113133
args.catalog,
134+
args.public,
114135
args.secret,
115136
args.galaxy_url,
116137
)

0 commit comments

Comments
 (0)