Use workflow-style payload in data landing request

Makes it considerably easier for sites that support data landing and
workflow requests, and it's also easier to read and validate.

Closes https://github.com/galaxyproject/galaxy/issues/21097
This commit is contained in:
mvdbeek
2025-10-19 09:33:32 +02:00
parent fcbaf24d69
commit 4fca48e924
10 changed files with 455 additions and 192 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ export type DatasetStorageDetails = components["schemas"]["DatasetStorageDetails
export type DatasetCollectionAttributes = components["schemas"]["DatasetCollectionAttributesResult"];
export type ConcreteObjectStoreModel = components["schemas"]["ConcreteObjectStoreModel"];
export type MessageException = components["schemas"]["MessageExceptionModel"];
export type DatasetHash = components["schemas"]["DatasetHash"];
export type DatasetHash = components["schemas"]["DatasetHash-Output"];
export type DatasetSource = components["schemas"]["DatasetSource"];
export type DatasetTransform = components["schemas"]["DatasetSourceTransform"];
export type StoreExportPayload = components["schemas"]["StoreExportPayload"];
+1 -1
View File
@@ -308,7 +308,7 @@ export function canMutateHistory(history: AnyHistory): boolean {
return !history.purged && !history.archived;
}
export type DatasetHash = components["schemas"]["DatasetHash"];
export type DatasetHash = components["schemas"]["DatasetHash-Output"];
export type DatasetSource = components["schemas"]["DatasetSource"];
export type DatasetTransform = components["schemas"]["DatasetSourceTransform"];
+155 -15
View File
@@ -7400,6 +7400,75 @@ export interface components {
/** Item Ids */
item_ids: string[];
};
/** CollectionElementCollectionRequestUri */
CollectionElementCollectionRequestUri: {
/**
* Class
* @constant
*/
class: "Collection";
/** Collection Type */
collection_type: string;
/** Elements */
elements: (
| components["schemas"]["CollectionElementCollectionRequestUri"]
| components["schemas"]["CollectionElementDataRequestUri"]
)[];
/**
* Identifier
* @description A unique identifier for this element within the collection.
*/
identifier: string;
};
/** CollectionElementDataRequestUri */
CollectionElementDataRequestUri: {
/**
* Class
* @constant
*/
class: "File";
/** Created From Basename */
created_from_basename?: string | null;
/**
* Dbkey
* @default ?
*/
dbkey: string;
/**
* Deferred
* @default false
*/
deferred: boolean;
/** Ext */
ext: string;
/** Hashes */
hashes?: components["schemas"]["DatasetHash-Input"][] | null;
/**
* Identifier
* @description A unique identifier for this element within the collection.
*/
identifier: string;
/** Info */
info?: string | null;
/** Location */
location: string;
/** Name */
name?: string | null;
/**
* Space To Tab
* @default false
*/
space_to_tab: boolean;
/** Src */
src?: null;
/** Tags */
tags?: string[] | null;
/**
* To Posix Lines
* @default false
*/
to_posix_lines: boolean;
};
/** CollectionElementIdentifier */
CollectionElementIdentifier: {
/**
@@ -7976,7 +8045,11 @@ export interface components {
* @default false
*/
public: boolean;
request_state: components["schemas"]["DataLandingRequestState"];
/** Request State */
request_state: (
| components["schemas"]["FileRequestUri"]
| components["schemas"]["DataRequestCollectionUri"]
)[];
};
/** CreateEntryPayload */
CreateEntryPayload: {
@@ -9510,17 +9583,6 @@ export interface components {
* @enum {string}
*/
DataItemSourceType: "hda" | "ldda" | "hdca" | "dce" | "dc";
/** DataLandingRequestState */
DataLandingRequestState: {
/** Targets */
targets: (
| components["schemas"]["DataElementsTarget"]
| components["schemas"]["HdcaDataItemsTarget"]
| components["schemas"]["DataElementsFromTarget"]
| components["schemas"]["HdcaDataItemsFromTarget"]
| components["schemas"]["FtpImportTarget"]
)[];
};
/** DataParameterModel */
DataParameterModel: {
/**
@@ -9589,6 +9651,30 @@ export interface components {
*/
type: "data";
};
/** DataRequestCollectionUri */
DataRequestCollectionUri: {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
class: "Collection";
/** Collection Type */
collection_type: string;
/**
* Deferred
* @default false
*/
deferred: boolean;
/** Elements */
elements: (
| components["schemas"]["CollectionElementCollectionRequestUri"]
| components["schemas"]["CollectionElementDataRequestUri"]
)[];
/** Name */
name?: string | null;
/** Src */
src?: null;
};
/** DatasetAssociationRoles */
DatasetAssociationRoles: {
/**
@@ -9666,7 +9752,17 @@ export interface components {
*/
DatasetExtraFiles: components["schemas"]["ExtraFileEntry"][];
/** DatasetHash */
DatasetHash: {
"DatasetHash-Input": {
/**
* Hash Function
* @enum {string}
*/
hash_function: "MD5" | "SHA-1" | "SHA-256" | "SHA-512";
/** Hash Value */
hash_value: string;
};
/** DatasetHash */
"DatasetHash-Output": {
/**
* Extra Files Path
* @description The path to the extra files used to generate the hash.
@@ -11378,6 +11474,50 @@ export interface components {
/** visible */
visible: boolean;
};
/** FileRequestUri */
FileRequestUri: {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
class: "File";
/** Created From Basename */
created_from_basename?: string | null;
/**
* Dbkey
* @default ?
*/
dbkey: string;
/**
* Deferred
* @default false
*/
deferred: boolean;
/** Ext */
ext: string;
/** Hashes */
hashes?: components["schemas"]["DatasetHash-Input"][] | null;
/** Info */
info?: string | null;
/** Location */
location: string;
/** Name */
name?: string | null;
/**
* Space To Tab
* @default false
*/
space_to_tab: boolean;
/** Src */
src?: null;
/** Tags */
tags?: string[] | null;
/**
* To Posix Lines
* @default false
*/
to_posix_lines: boolean;
};
/** FileSourceTemplateSummaries */
FileSourceTemplateSummaries: components["schemas"]["FileSourceTemplateSummary"][];
/** FileSourceTemplateSummary */
@@ -12218,7 +12358,7 @@ export interface components {
* Hashes
* @description The list of hashes associated with this dataset.
*/
hashes?: components["schemas"]["DatasetHash"][] | null;
hashes?: components["schemas"]["DatasetHash-Output"][] | null;
/**
* HDA or LDDA
* @description Whether this dataset belongs to a history (HDA) or a library (LDDA).
@@ -12479,7 +12619,7 @@ export interface components {
* Hashes
* @description The list of hashes associated with this dataset.
*/
hashes: components["schemas"]["DatasetHash"][];
hashes: components["schemas"]["DatasetHash-Output"][];
/**
* HDA or LDDA
* @description Whether this dataset belongs to a history (HDA) or a library (LDDA).
+5 -3
View File
@@ -27,6 +27,7 @@ from galaxy.schema.schema import (
)
from galaxy.schema.terms import HelpTerms
from galaxy.schema.types import CoercedStringType
from galaxy.tool_util_models.parameters import FileOrCollectionRequest
from galaxy.util.hash_util import HashFunctionNames
HELP_TERMS = HelpTerms()
@@ -303,14 +304,15 @@ class FetchDataFormPayload(BaseDataPayload):
targets: Union[Json[Targets], Targets]
class DataLandingRequestState(Model):
targets: Targets
FileOrCollectionRequests = list[FileOrCollectionRequest]
FileOrCollectionRequestsAdapter = TypeAdapter(FileOrCollectionRequests)
# Vaguely matches the schema.schema.ToolLandingState but we don't allow data_fetch to be called directly
# via the tool API so we have a more specific model here.
class CreateDataLandingPayload(Model):
request_state: DataLandingRequestState
request_state: FileOrCollectionRequests
client_secret: Optional[str] = None
public: bool = False
origin: Optional[HttpUrl] = None
+1 -1
View File
@@ -79,7 +79,7 @@ def generate_claim_url(request: Request) -> Response:
try:
raw_response.raise_for_status()
except Exception:
raise Exception("Request failed: %s", raw_response.text)
raise Exception("Request failed: %s", raw_response.json())
response = raw_response.json()
response_type = "workflow" if template_type == "workflow" else "tool"
url = f"{galaxy_url}/{response_type}_landings/{response['uuid']}"
@@ -21,207 +21,229 @@ int_workflow:
int_input: 8
upload:
request_state:
targets:
- destination: {type: "hdas"}
items:
- src: url
name: "Reference information"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "txt"
- src: url
name: "Reference sequence"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
- src: url
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq.gz"
- destination: {type: "hdca"}
- class: File
name: Reference information
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "txt"
- class: File
name: Reference sequence
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
- class: File
name: Read 1
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq.gz"
- class: Collection
collection_type: list
name: "my collection"
items:
- src: url
name: "sample1"
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
elements:
- class: File
name: sample1
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: sample2
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: sample3
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- destination: {type: "hdca"}
- class: Collection
collection_type: list:paired
name: "The List of Dataset Pairs"
items:
- name: sample1
items:
- src: url
elements:
- class: Collection
collection_type: paired
name: sample1
elements:
- class: File
name: forward
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: reverse
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- name: sample2
items:
- src: url
class: Collection
collection_type: paired
elements:
- class: File
name: forward
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: reverse
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- destination: {type: "hdca"}
- class: Collection
collection_type: list:list:paired
name: "Nested List of Dataset Pairs"
items:
- name: treatment1
items:
- name: replicate1
items:
- src: url
elements:
- class: Collection
collection_type: list:paired
name: treatment1
elements:
- class: Collection
collection_type: paired
name: replicate1
elements:
- class: File
name: forward
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: reverse
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- name: replicate2
items:
- src: url
- class: Collection
collection_type: paired
name: replicate2
elements:
- class: File
name: forward
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: reverse
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- name: treatment2
items:
- name: replicate1
items:
- src: url
- class: Collection
collection_type: list:paired
name: treatment2
elements:
- class: Collection
collection_type: paired
name: replicate1
elements:
- class: File
name: forward
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: reverse
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- name: replicate2
items:
- src: url
- class: Collection
collection_type: paired
name: replicate2
elements:
- class: File
name: forward
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- src: url
- class: File
name: reverse
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
- destination: {type: "hdas"}
items:
- src: url
name: "sample1.fasta"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
tags: ['name:sample1']
- src: url
name: "sample2.fasta"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
tags: ['name:sample2']
- destination: {type: "hdas"}
items:
- src: url
name: "sample1.fastq"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment1', 'group:replicate:replicate1']
- src: url
name: "sample2.fastq"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment1', 'group:replicate:replicate2']
- src: url
name: "sample3.fastq"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment2', 'group:replicate:replicate1']
- src: url
name: "sample4.fastq"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment2', 'group:replicate:replicate2']
- destination: {type: "hdas"}
items:
- src: url
name: "Convert spaces and not newlines"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "txt"
space_to_tab: true
to_posix_lines: false
- src: url
name: "Convert newlines and not spaces"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
space_to_tab: false
to_posix_lines: true
- src: url
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq.gz"
- destination: {type: "hdas"}
items:
- src: url
name: "Reference information"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "txt"
dbkey: hg19
- src: url
name: "Reference sequence"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
dbkey: hg19
- src: url
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq.gz"
- destination: {type: "hdca"}
- class: File
name: "sample1.fasta"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
tags: ['name:sample1']
- class: File
name: "sample2.fasta"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
tags: ['name:sample2']
- class: File
name: "sample1.fastq"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment1', 'group:replicate:replicate1']
- class: File
name: "sample2.fastq"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment1', 'group:replicate:replicate2']
- class: File
name: "sample2.fastq"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment1', 'group:replicate:replicate2']
- class: File
name: "sample3.fastq"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment1', 'group:replicate:replicate2']
- class: File
name: "sample3.fastq"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment2', 'group:replicate:replicate1']
- class: File
name: "sample4.fastq"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq"
tags: ['group:treatment:treatment2', 'group:replicate:replicate2']
- class: File
name: "Convert spaces and not newlines"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "txt"
space_to_tab: true
to_posix_lines: false
- class: File
name: "Convert newlines and not spaces"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
space_to_tab: false
to_posix_lines: true
- class: File
name: "Reference genome"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fastq.gz"
- class: File
name: "Reference information"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "txt"
dbkey: hg19
- class: File
name: "Reference sequence"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "fasta"
dbkey: hg19
- class: File
name: "Reference annotation"
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "gff"
dbkey: hg19
- class: Collection
collection_type: paired:paired
name: "esoteric collection type"
items:
- name: "forward"
items:
- src: url
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
elements:
- class: Collection
collection_type: paired
name: "forward"
elements:
- class: File
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
name: "forward"
items:
- src: url
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
- class: File
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
name: "reverse"
- name: "reverse"
items:
- src: url
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
- class: Collection
collection_type: paired
name: "reverse"
elements:
- class: File
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
name: "forward"
items:
- src: url
url: "base64://eyJ0c3JjIjogInRlc3QifQ=="
- class: File
location: "base64://eyJ0c3JjIjogInRlc3QifQ=="
ext: "txt"
name: "reverse"
upload_one:
request_state:
targets:
- destination: {type: "hdas"}
items:
- src: url
- class: Collection
collection_type: list
name: "my collection"
elements:
- class: File
name: "Reference information"
url: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
location: "base64://eyJ0ZXN0IjogInRlc3QifQ=="
ext: "txt"
+13 -2
View File
@@ -19,6 +19,7 @@ from typing import (
from pydantic import (
AfterValidator,
AliasChoices,
AnyUrl,
BaseModel,
ConfigDict,
@@ -403,6 +404,7 @@ class BaseDataRequest(StrictModel):
deferred: StrictBool = False
created_from_basename: Optional[StrictStr] = None
info: Optional[StrictStr] = None
tags: Optional[List[str]] = None
hashes: Optional[List[DatasetHash]] = None
space_to_tab: bool = False
to_posix_lines: bool = False
@@ -440,12 +442,20 @@ class FileRequestUri(BaseDataRequest):
class CollectionElementDataRequestUri(FileRequestUri):
class_: Literal["File"] = Field(..., alias="class")
identifier: StrictStr
identifier: StrictStr = Field(
...,
description="A unique identifier for this element within the collection.",
validation_alias=AliasChoices("identifier", "name"),
)
class CollectionElementCollectionRequestUri(StrictModel):
class_: Literal["Collection"] = Field(..., alias="class")
identifier: StrictStr
identifier: StrictStr = Field(
...,
description="A unique identifier for this element within the collection.",
validation_alias=AliasChoices("identifier", "name"),
)
collection_type: StrictStr
elements: List[
Annotated[
@@ -485,6 +495,7 @@ _DataRequest = Annotated[
DataRequest: Type = cast(Type, _DataRequest)
DataOrCollectionRequest = Union[_DataRequest, FileRequestUri, DataRequestCollectionUri, DataRequestHdca]
FileOrCollectionRequest = Annotated[Union[FileRequestUri, DataRequestCollectionUri], Field(discriminator="class_")]
DataRequestHda.model_rebuild()
DataRequestLd.model_rebuild()
@@ -34,6 +34,9 @@ def validate_and_normalize_targets(trans, payload, set_internal_fields=True):
as needed for each upload.
"""
targets = payload.get("targets", [])
landing_uuid = payload.get("landing_uuid")
if landing_uuid:
payload["landing_uuid"] = str(landing_uuid)
for target in targets:
destination = get_required_item(target, "destination", "Each target must specify a 'destination'")
+93 -3
View File
@@ -37,13 +37,26 @@ from galaxy.model import (
from galaxy.schema.credentials import CredentialsContext
from galaxy.schema.fetch_data import (
CreateDataLandingPayload,
DataElementsTarget,
FetchDataFormPayload,
FetchDataPayload,
FilesPayload,
HdaDestination,
HdcaDataItemsTarget,
HdcaDestination,
NestedElement,
TargetsAdapter,
UrlDataElement,
)
from galaxy.schema.schema import CreateToolLandingRequestPayload
from galaxy.security.idencoding import IdEncodingHelper
from galaxy.tool_util_models.parameters import (
CollectionElementCollectionRequestUri,
CollectionElementDataRequestUri,
DataRequestCollectionUri,
DataRequestUri,
FileRequestUri,
)
from galaxy.tools import Tool
from galaxy.tools.search import ToolBoxSearch
from galaxy.util.path import safe_contains
@@ -88,6 +101,82 @@ def validate_tool_for_running(trans: ProvidesHistoryContext, tool_ref: ToolRunRe
return tool
def data_landing_payload_to_fetch_targets(data_landing_payload: CreateDataLandingPayload):
"""Convert a CreateDataLandingPayload with DataOrCollectionRequest format to FetchDataPayload with Targets format.
This function transforms data/collection requests (used in workflow landing and data request payloads) into the fetch API's target format.
"""
targets: list[Union[DataElementsTarget, HdcaDataItemsTarget]] = []
for request_item in data_landing_payload.request_state:
if isinstance(request_item, (DataRequestUri, FileRequestUri)):
# Convert single file/URL request to a DataElementsTarget
element = UrlDataElement(
src="url",
url=str(request_item.url),
ext=request_item.ext,
dbkey=request_item.dbkey,
name=request_item.name,
deferred=request_item.deferred,
info=request_item.info,
tags=request_item.tags,
space_to_tab=request_item.space_to_tab,
to_posix_lines=request_item.to_posix_lines,
created_from_basename=request_item.created_from_basename,
)
targets.append(
DataElementsTarget(
destination=HdaDestination(type="hdas"),
elements=[element],
)
)
elif isinstance(request_item, DataRequestCollectionUri):
# Convert collection request to HdcaDataItemsTarget
def convert_collection_element(elem):
"""Convert a collection element (file or nested collection) recursively."""
if isinstance(elem, CollectionElementDataRequestUri):
# This is a file element
return UrlDataElement(
src="url",
url=str(elem.url),
ext=elem.ext,
dbkey=elem.dbkey,
name=elem.identifier,
deferred=elem.deferred,
info=elem.info,
tags=elem.tags,
space_to_tab=elem.space_to_tab,
to_posix_lines=elem.to_posix_lines,
created_from_basename=elem.created_from_basename,
)
elif isinstance(elem, CollectionElementCollectionRequestUri):
# This is a nested collection element
# Recursively convert its elements
nested_elements = [convert_collection_element(nested_elem) for nested_elem in elem.elements]
return NestedElement(
name=elem.identifier,
elements=nested_elements,
collection_type=elem.collection_type,
)
else:
raise ValueError(f"Unknown collection element type: {type(elem)}")
elements = [convert_collection_element(elem) for elem in request_item.elements]
targets.append(
HdcaDataItemsTarget(
destination=HdcaDestination(type="hdca"),
elements=elements,
collection_type=request_item.collection_type,
name=request_item.name,
)
)
return [target.model_dump(mode="json", exclude_unset=True) for target in TargetsAdapter.validate_python(targets)]
class ToolsService(ServiceBase):
def __init__(
self,
@@ -107,12 +196,13 @@ class ToolsService(ServiceBase):
data_landing_payload: CreateDataLandingPayload,
) -> CreateToolLandingRequestPayload:
request_version = "1"
payload = data_landing_payload.model_dump(exclude_unset=True)["request_state"]
payload = {"targets": data_landing_payload_to_fetch_targets(data_landing_payload)}
validate_and_normalize_targets(trans, payload, set_internal_fields=False)
validated_back_to_model = TargetsAdapter.validate_python(payload["targets"])
request_state = {
"request_version": request_version,
"request_json": {"targets": TargetsAdapter.dump_python(validated_back_to_model, exclude_unset=True)},
"request_json": {
"targets": payload["targets"],
},
"file_count": "0",
}
return CreateToolLandingRequestPayload(
+8 -13
View File
@@ -7,7 +7,7 @@ from pydantic import HttpUrl
from galaxy.schema.fetch_data import (
CreateDataLandingPayload,
DataLandingRequestState,
FileOrCollectionRequestsAdapter,
)
from galaxy.schema.schema import (
CreateToolLandingRequestPayload,
@@ -65,19 +65,14 @@ class TestLandingApi(ApiTestCase):
assert "Input should be a valid integer" in response.text
def test_data_landing(self):
data_landing_request_state = DataLandingRequestState(
targets=[
data_landing_request_state = FileOrCollectionRequestsAdapter.validate_python(
[
{
"destination": {"type": "hdas"},
"items": [
{
"src": "url",
"url": "base64://eyJ0ZXN0IjogInRlc3QifQ==", # base64 encoded {"test": "test"}
"ext": "txt",
"deferred": False,
}
],
}
"class": "File",
"location": "base64://eyJ0ZXN0IjogInRlc3QifQ==", # base64 encoded {"test": "test"}
"filetype": "txt",
"deferred": False,
},
],
)
payload = CreateDataLandingPayload(request_state=data_landing_request_state, public=True)