Merge pull request #16933 from martenson/merge231in

merge release_23.1 into dev
This commit is contained in:
Marius van den Beek
2023-10-27 12:40:58 +02:00
committed by GitHub
17 changed files with 280 additions and 86 deletions
@@ -65,7 +65,12 @@ const workflow = computed(() => {
});
const workflowStep = computed(() => {
if ("workflow_step_id" in props.invocationMessage && workflow.value) {
if (
"workflow_step_id" in props.invocationMessage &&
props.invocationMessage.workflow_step_id !== undefined &&
props.invocationMessage.workflow_step_id !== null &&
workflow.value
) {
return workflow.value.steps[props.invocationMessage.workflow_step_id];
}
return undefined;
@@ -149,10 +154,14 @@ const infoString = computed(() => {
invocationMessage.workflow_step_id + 1
} is a conditional step and the result of the when expression is not a boolean type.`;
} else if (reason === "unexpected_failure") {
if (invocationMessage.details) {
return `${failFragment} an unexpected failure occurred: '${invocationMessage.details}'`;
let atStep = "";
if (invocationMessage.workflow_step_id !== null && invocationMessage.workflow_step_id !== undefined) {
atStep = ` at step ${invocationMessage.workflow_step_id + 1}`;
}
return `${failFragment} an unexpected failure occurred.`;
if (invocationMessage.details) {
return `${failFragment} an unexpected failure occurred${atStep}: '${invocationMessage.details}'`;
}
return `${failFragment} an unexpected failure occurred${atStep}.`;
} else if (reason === "workflow_output_not_found") {
return `Defined workflow output '${invocationMessage.output_name}' was not found in step ${
invocationMessage.workflow_step_id + 1
@@ -77,7 +77,7 @@ export interface GenericInvocationFailureCollectionFailedEncodedDatabaseIdField
/**
* HistoryDatasetCollectionAssociation ID that relates to failure.
*/
hdca_id?: string;
hdca_id: string;
/**
* Workflow step id of step that caused failure.
*/
@@ -92,7 +92,7 @@ export interface GenericInvocationFailureCollectionFailedInt {
/**
* HistoryDatasetCollectionAssociation ID that relates to failure.
*/
hdca_id?: number;
hdca_id: number;
/**
* Workflow step id of step that caused failure.
*/
@@ -159,7 +159,7 @@ export interface GenericInvocationFailureJobFailedEncodedDatabaseIdField {
/**
* Job ID that relates to failure.
*/
job_id?: string;
job_id: string;
/**
* Workflow step id of step that caused failure.
*/
@@ -174,7 +174,7 @@ export interface GenericInvocationFailureJobFailedInt {
/**
* Job ID that relates to failure.
*/
job_id?: number;
job_id: number;
/**
* Workflow step id of step that caused failure.
*/
@@ -232,6 +232,10 @@ export interface GenericInvocationUnexpectedFailureEncodedDatabaseIdField {
* May contains details to help troubleshoot this problem.
*/
details?: string;
/**
* Workflow step id of step that failed.
*/
workflow_step_id?: number;
}
export interface GenericInvocationUnexpectedFailureInt {
reason: "unexpected_failure";
@@ -239,4 +243,8 @@ export interface GenericInvocationUnexpectedFailureInt {
* May contains details to help troubleshoot this problem.
*/
details?: string;
/**
* Workflow step id of step that failed.
*/
workflow_step_id?: number;
}
+8 -7
View File
@@ -600,13 +600,14 @@ class Registry:
return self.datatypes_by_extension.get(ext, None)
def change_datatype(self, data, ext):
data.extension = ext
# call init_meta and copy metadata from itself. The datatype
# being converted *to* will handle any metadata copying and
# initialization.
if data.has_data():
data.set_size()
data.init_meta(copy_from=data)
if data.extension != ext:
data.extension = ext
# call init_meta and copy metadata from itself. The datatype
# being converted *to* will handle any metadata copying and
# initialization.
if data.has_data():
data.set_size()
data.init_meta(copy_from=data)
return data
def load_datatype_converters(self, toolbox, use_cached=False):
+10
View File
@@ -151,6 +151,16 @@ class ToolInputsNotReadyException(MessageException):
error_code = error_codes_by_name["TOOL_INPUTS_NOT_READY"]
class ToolInputsNotOKException(MessageException):
def __init__(self, err_msg=None, type="info", *, src: str, id: int, **extra_error_info):
super().__init__(err_msg, type, **extra_error_info)
self.src = src
self.id = id
status_code = 400
error_code = error_codes_by_name["TOOL_INPUTS_NOT_OK"]
class RealUserRequiredException(MessageException):
status_code = 400
error_code = error_codes_by_name["REAL_USER_REQUIRED"]
+5
View File
@@ -94,6 +94,11 @@
"code": 400016,
"message": "Only real users can make this request."
},
{
"name": "TOOL_INPUTS_NOT_OK",
"code": 400017,
"message": "Tool inputs not in required OK state."
},
{
"name": "USER_AUTHENTICATION_FAILED",
"code": 401001,
+4
View File
@@ -1198,12 +1198,16 @@ class DefaultJobDispatcher:
except KeyError:
log.error(f"({job_wrapper.job_id}) Invalid job runner: {runner_name}")
job_wrapper.fail(DEFAULT_JOB_RUNNER_FAILURE_MESSAGE)
return None
if get_task_runner and job_wrapper.can_split() and runner.runner_name != "PulsarJobRunner":
return self.job_runners["tasks"]
return runner
def put(self, job_wrapper):
runner = self.get_job_runner(job_wrapper, get_task_runner=True)
if runner is None:
# Something went wrong, we've already failed the job wrapper
return
if isinstance(job_wrapper, TaskWrapper):
# DBTODO Refactor
log.debug(f"({job_wrapper.job_id}) Dispatching task {job_wrapper.task_id} to task runner")
+1 -1
View File
@@ -448,7 +448,7 @@ def set_metadata_portable(
object_store_update_actions.append(
partial(push_if_necessary, object_store, dataset, external_filename)
)
object_store_update_actions.append(partial(reset_external_filename, dataset))
object_store_update_actions.append(partial(reset_external_filename, dataset))
object_store_update_actions.append(partial(dataset.set_total_size))
object_store_update_actions.append(partial(export_store.add_dataset, dataset))
if dataset_instance_id not in unnamed_id_to_path:
+12 -1
View File
@@ -605,7 +605,18 @@ class FileParameter(MetadataParameter):
if isinstance(value, int):
return session.get(galaxy.model.MetadataFile, value)
else:
return session.execute(select(galaxy.model.MetadataFile).filter_by(uuid=value)).scalar_one()
wrapped_value = session.execute(
select(galaxy.model.MetadataFile).filter_by(uuid=value)
).scalar_one_or_none()
if wrapped_value:
return wrapped_value
else:
# If we've simultaneously copied the dataset and we've changed the datatype on the
# copy we may not have committed the MetadataFile yet, so we need to commit the session.
# TODO: It would be great if we can avoid the commit in the future.
with transaction(session):
session.commit()
return session.execute(select(galaxy.model.MetadataFile).filter_by(uuid=value)).scalar_one_or_none()
def make_copy(self, value, target_context: MetadataCollection, source_context):
session = target_context._object_session(target_context.parent)
+5 -1
View File
@@ -51,7 +51,10 @@ class StepOrderIndexGetter(GetterDict):
# Fetch the order_index when serializing for the API,
# which makes much more sense when pointing to steps.
if key == "workflow_step_id":
return self._obj.workflow_step.order_index
if self._obj.workflow_step:
return self._obj.workflow_step.order_index
else:
return default
elif key == "dependent_workflow_step_id":
if self._obj.dependent_workflow_step_id:
return self._obj.dependent_workflow_step.order_index
@@ -132,6 +135,7 @@ class GenericInvocationFailureWhenNotBoolean(InvocationFailureMessageBase[Databa
class GenericInvocationUnexpectedFailure(InvocationMessageBase, Generic[DatabaseIdT]):
reason: Literal[FailureReason.unexpected_failure]
details: Optional[str] = Field(None, description="May contains details to help troubleshoot this problem.")
workflow_step_id: Optional[int] = Field(None, description="Workflow step id of step that failed.")
class GenericInvocationWarning(InvocationMessageBase, Generic[DatabaseIdT]):
+20 -13
View File
@@ -39,7 +39,10 @@ from galaxy import (
exceptions,
model,
)
from galaxy.exceptions import ToolInputsNotReadyException
from galaxy.exceptions import (
ToolInputsNotOKException,
ToolInputsNotReadyException,
)
from galaxy.job_execution import output_collect
from galaxy.metadata import get_metadata_compute_strategy
from galaxy.model import (
@@ -2875,7 +2878,7 @@ class ExpressionTool(Tool):
copy_object = input_dataset
break
if copy_object is None:
raise Exception("Failed to find dataset output.")
raise exceptions.MessageException("Failed to find dataset output.")
out_data[key].copy_from(copy_object)
def parse_environment_variables(self, tool_source):
@@ -3217,8 +3220,10 @@ class DatabaseOperationTool(Tool):
if self.require_dataset_ok:
if state != model.Dataset.states.OK:
raise ValueError(
f"Tool requires inputs to be in valid state, but dataset {input_dataset} is in state '{input_dataset.state}'"
raise ToolInputsNotOKException(
f"Tool requires inputs to be in valid state, but dataset {input_dataset} is in state '{input_dataset.state}'",
src="hda",
id=input_dataset.id,
)
for input_dataset in input_datasets.values():
@@ -3347,7 +3352,7 @@ class ExtractDatasetCollectionTool(DatabaseOperationTool):
elif how == "by_index":
extracted_element = collection[int(incoming["which"]["index"])]
else:
raise Exception("Invalid tool parameters.")
raise exceptions.MessageException("Invalid tool parameters.")
extracted = extracted_element.element_object
extracted_o = extracted.copy(
copy_tags=extracted.tags, new_name=extracted_element.element_identifier, flush=False
@@ -3387,7 +3392,9 @@ class MergeCollectionTool(DatabaseOperationTool):
if element_identifier not in identifiers_map:
identifiers_map[element_identifier] = []
elif dupl_actions == "fail":
raise Exception(f"Duplicate collection element identifiers found for [{element_identifier}]")
raise exceptions.MessageException(
f"Duplicate collection element identifiers found for [{element_identifier}]"
)
identifiers_map[element_identifier].append(input_num)
for copy, input_list in enumerate(input_lists):
@@ -3579,12 +3586,12 @@ class SortTool(DatabaseOperationTool):
except KeyError:
hdca_history_name = f"{hdca.hid}: {hdca.name}"
message = f"List of element identifiers does not match element identifiers in collection '{hdca_history_name}'"
raise Exception(message)
raise exceptions.MessageException(message)
else:
message = f"Number of lines must match number of list elements ({len(elements)}), but file has {data_lines} lines"
raise Exception(message)
raise exceptions.MessageException(message)
else:
raise Exception(f"Unknown sort_type '{sorttype}'")
raise exceptions.MessageException(f"Unknown sort_type '{sorttype}'")
if presort_elements is not None:
sorted_elements = [x[1] for x in sorted(presort_elements, key=lambda x: x[0])]
@@ -3616,7 +3623,7 @@ class RelabelFromFileTool(DatabaseOperationTool):
def add_copied_value_to_new_elements(new_label, dce_object):
new_label = new_label.strip()
if new_label in new_elements:
raise Exception(
raise exceptions.MessageException(
f"New identifier [{new_label}] appears twice in resulting collection, these values must be unique."
)
if getattr(dce_object, "history_content_type", None) == "dataset":
@@ -3629,7 +3636,7 @@ class RelabelFromFileTool(DatabaseOperationTool):
with open(new_labels_path) as fh:
new_labels = fh.readlines(1024 * 1000000)
if strict and len(hdca.collection.elements) != len(new_labels):
raise Exception("Relabel mapping file contains incorrect number of identifiers")
raise exceptions.MessageException("Relabel mapping file contains incorrect number of identifiers")
if how_type == "tabular":
# We have a tabular file, where the first column is an existing element identifier,
# and the second column is the new element identifier.
@@ -3641,7 +3648,7 @@ class RelabelFromFileTool(DatabaseOperationTool):
default = None if strict else element_identifier
new_label = new_labels_dict.get(element_identifier, default)
if not new_label:
raise Exception(f"Failed to find new label for identifier [{element_identifier}]")
raise exceptions.MessageException(f"Failed to find new label for identifier [{element_identifier}]")
add_copied_value_to_new_elements(new_label, dce_object)
else:
# If new_labels_dataset_assoc is not a two-column tabular dataset we label with the current line of the dataset
@@ -3650,7 +3657,7 @@ class RelabelFromFileTool(DatabaseOperationTool):
add_copied_value_to_new_elements(new_labels[i], dce_object)
for key in new_elements.keys():
if not re.match(r"^[\w\- \.,]+$", key):
raise Exception(f"Invalid new collection identifier [{key}]")
raise exceptions.MessageException(f"Invalid new collection identifier [{key}]")
self._add_datasets_to_history(history, new_elements.values())
output_collections.create_collection(
next(iter(self.outputs.values())), "output", elements=new_elements, propagate_hda_tags=False
+12 -8
View File
@@ -19,6 +19,7 @@ from typing import (
from boltons.iterutils import remap
from galaxy import model
from galaxy.exceptions import ToolInputsNotOKException
from galaxy.model.base import transaction
from galaxy.model.dataset_collections.matching import MatchingCollections
from galaxy.model.dataset_collections.structure import (
@@ -143,14 +144,17 @@ def execute(
if check_inputs_ready:
for params in execution_tracker.param_combinations:
# This will throw an exception if the tool is not ready.
check_inputs_ready(
tool,
trans,
params,
history,
execution_cache=execution_cache,
collection_info=collection_info,
)
try:
check_inputs_ready(
tool,
trans,
params,
history,
execution_cache=execution_cache,
collection_info=collection_info,
)
except ToolInputsNotOKException as e:
execution_tracker.record_error(e)
execution_tracker.ensure_implicit_collections_populated(history, mapping_params.param_template)
job_count = len(execution_tracker.param_combinations)
@@ -490,6 +490,10 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
history_is_current = history_to_view == trans.history
else:
history_to_view = trans.history
if not history_to_view:
raise exceptions.RequestParameterMissingException(
"No 'id' parameter provided for history, and user does not have a current history."
)
user_is_owner = True
history_is_current = True
+10
View File
@@ -2314,6 +2314,16 @@ class ToolModule(WorkflowModule):
if execution_tracker.execution_errors:
# TODO: formalize into InvocationFailure ?
message = f"Failed to create {len(execution_tracker.execution_errors)} job(s) for workflow step {step.order_index + 1}: {str(execution_tracker.execution_errors[0])}"
for error in execution_tracker.execution_errors:
# try first to raise a structured invocation error message
if isinstance(error, exceptions.ToolInputsNotOKException) and error.src == "hda":
raise FailWorkflowEvaluation(
why=InvocationFailureDatasetFailed(
reason=FailureReason.dataset_failed,
hda_id=error.id,
workflow_step_id=step.id,
)
)
raise exceptions.MessageException(message)
return complete
+9 -1
View File
@@ -240,12 +240,20 @@ class WorkflowInvoker:
except modules.DelayedWorkflowEvaluation as de:
step_delayed = delayed_steps = True
self.progress.mark_step_outputs_delayed(step, why=de.why)
except Exception:
except Exception as e:
log.exception(
"Failed to schedule %s, problem occurred on %s.",
self.workflow_invocation.workflow.log_str(),
step.log_str(),
)
if isinstance(e, MessageException):
# This is the highest level at which we can inject the step id
# to provide some more context to the exception.
raise modules.FailWorkflowEvaluation(
why=InvocationUnexpectedFailure(
reason=FailureReason.unexpected_failure, details=str(e), workflow_step_id=step.id
)
)
raise
if not step_delayed:
+72
View File
@@ -4060,6 +4060,78 @@ outputs:
assert "workflow_step_id" in message
assert message["output_name"] == "does_not_exist"
@skip_without_tool("__APPLY_RULES__")
@skip_without_tool("job_properties")
def test_workflow_failed_input_not_ok(self, history_id):
summary = self._run_workflow(
"""
class: GalaxyWorkflow
steps:
job_props:
tool_id: job_properties
state:
thebool: true
failbool: true
apply:
tool_id: __APPLY_RULES__
in:
input: job_props/list_output
state:
rules:
rules:
- type: add_column_metadata
value: identifier0
mapping:
- type: list_identifiers
columns: [0]
""",
history_id=history_id,
assert_ok=False,
wait=True,
)
invocation_details = self.workflow_populator.get_invocation(summary.invocation_id, step_details=True)
assert invocation_details["state"] == "failed"
assert len(invocation_details["messages"]) == 1
message = invocation_details["messages"][0]
assert message["reason"] == "dataset_failed"
assert message["workflow_step_id"] == 1
@skip_without_tool("__RELABEL_FROM_FILE__")
def test_workflow_failed_with_message_exception(self, history_id):
summary = self._run_workflow(
"""
class: GalaxyWorkflow
inputs:
input_collection:
collection_type: list
type: collection
relabel_file:
type: data
steps:
relabel:
tool_id: __RELABEL_FROM_FILE__
in:
input: input_collection
how|labels: relabel_file
test_data:
input_collection:
collection_type: "list:list"
relabel_file:
value: 1.bed
type: File
""",
history_id=history_id,
assert_ok=False,
wait=True,
)
invocation_details = self.workflow_populator.get_invocation(summary.invocation_id, step_details=True)
assert invocation_details["state"] == "failed"
assert len(invocation_details["messages"]) == 1
message = invocation_details["messages"][0]
assert message["reason"] == "unexpected_failure"
assert message["workflow_step_id"] == 2
assert "Invalid new collection identifier" in message["details"]
@skip_without_tool("identifier_multiple")
def test_invocation_map_over(self, history_id):
summary = self._run_workflow(
@@ -30,6 +30,7 @@ from typing import (
from requests import Response
from galaxy.tool_util.verify.test_data import TestDataResolver
from galaxy.util.unittest import TestCase
from galaxy_test.base.api_util import TEST_USER
from galaxy_test.base.constants import (
@@ -75,17 +76,19 @@ class BaseUploadContentConfigurationInstance(integration_util.IntegrationInstanc
response = self.dataset_populator.fetch(payload, assert_ok=assert_ok, wait=wait)
return response
def _write_file(self, dir_path: str, content: str, filename: str = "test") -> str:
"""Helper for writing ftp/server dir files."""
self._ensure_directory(dir_path)
path = os.path.join(dir_path, filename)
with open(path, "w") as f:
f.write(content)
return path
def _ensure_directory(self, path: str) -> None:
if not os.path.exists(path):
os.makedirs(path)
def _write_file(dir_path: str, content: str, filename: str = "test") -> str:
"""Helper for writing ftp/server dir files."""
_ensure_directory(dir_path)
path = os.path.join(dir_path, filename)
with open(path, "w") as f:
f.write(content)
return path
def _ensure_directory(path: str) -> None:
if not os.path.exists(path):
os.makedirs(path)
class BaseUploadContentConfigurationTestCase(BaseUploadContentConfigurationInstance, TestCase):
@@ -190,6 +193,42 @@ class TestNonAdminsCannotPasteFilePath(BaseUploadContentConfigurationTestCase):
assert os.path.exists(path)
def fetch_link_data_only(
library_populator: LibraryPopulator, dataset_populator: DatasetPopulator, test_data_resolver: TestDataResolver
):
history_id, library, destination = library_populator.setup_fetch_to_folder("fetch_and_link")
bed_test_data_path = test_data_resolver.get_filename("4.bed")
assert os.path.exists(bed_test_data_path)
items = [{"src": "path", "path": bed_test_data_path, "info": "my cool bed", "link_data_only": True}]
targets = [{"destination": destination, "items": items}]
payload = {
"history_id": history_id, # TODO: Shouldn't be needed :(
"targets": targets,
}
dataset_populator.fetch(payload)
dataset = library_populator.get_library_contents_with_path(library["id"], "/4.bed")
assert dataset["file_size"] == 61, dataset
assert dataset["file_name"] == bed_test_data_path, dataset
assert os.path.exists(bed_test_data_path)
def link_data_only(server_dir: str, library_populator: LibraryPopulator) -> None:
content = "hello world\n"
dir_path = os.path.join(server_dir, "lib1")
file_path = _write_file(dir_path, content)
library = library_populator.new_private_library("serverdirupload")
# upload $GALAXY_ROOT/test-data/library
payload, files = library_populator.create_dataset_request(
library, upload_option="upload_directory", server_dir="lib1", link_data=True
)
response = library_populator.raw_library_contents_create(library["id"], payload, files=files)
assert response.status_code == 200, response.json()
dataset = response.json()[0]
ok_dataset = library_populator.wait_on_library_dataset(library["id"], dataset["id"])
assert ok_dataset["file_size"] == 12, ok_dataset
assert ok_dataset["file_name"] == file_path, ok_dataset
class TestAdminsCanPasteFilePaths(BaseUploadContentConfigurationTestCase):
require_admin_user = True
@@ -506,9 +545,9 @@ class TestEnableFtpPurgeUploadConfiguration(BaseFtpUploadConfigurationTestCase):
class TestAdvancedFtpUploadFetch(BaseFtpUploadConfigurationTestCase):
def test_fetch_ftp_directory(self, history_id: str) -> None:
dir_path = self._get_user_ftp_path()
self._write_file(os.path.join(dir_path, "subdir"), "content 1", filename="1")
self._write_file(os.path.join(dir_path, "subdir"), "content 22", filename="2")
self._write_file(os.path.join(dir_path, "subdir"), "content 333", filename="3")
_write_file(os.path.join(dir_path, "subdir"), "content 1", filename="1")
_write_file(os.path.join(dir_path, "subdir"), "content 22", filename="2")
_write_file(os.path.join(dir_path, "subdir"), "content 333", filename="3")
target = {
"destination": {"type": "hdca"},
"elements_from": "directory",
@@ -525,9 +564,9 @@ class TestAdvancedFtpUploadFetch(BaseFtpUploadConfigurationTestCase):
def test_fetch_nested_elements_from(self, history_id: str) -> None:
dir_path = self._get_user_ftp_path()
self._write_file(os.path.join(dir_path, "subdir1"), "content 1", filename="1")
self._write_file(os.path.join(dir_path, "subdir1"), "content 22", filename="2")
self._write_file(os.path.join(dir_path, "subdir2"), "content 333", filename="3")
_write_file(os.path.join(dir_path, "subdir1"), "content 1", filename="1")
_write_file(os.path.join(dir_path, "subdir1"), "content 22", filename="2")
_write_file(os.path.join(dir_path, "subdir2"), "content 333", filename="3")
elements = [
{
"name": "subdirel1",
@@ -667,7 +706,7 @@ class TestUploadOptionsFtpUploadConfiguration(BaseFtpUploadConfigurationTestCase
shutil.copyfile(input_path, os.path.join(target_dir, test_data_path))
def _write_user_ftp_file(self, path: str, content: str) -> str:
return self._write_file(os.path.join(self.ftp_dir(), TEST_USER), content, filename=path)
return _write_file(os.path.join(self.ftp_dir(), TEST_USER), content, filename=path)
class TestServerDirectoryOffByDefault(BaseUploadContentConfigurationTestCase):
@@ -721,20 +760,7 @@ class TestServerDirectoryValidUsage(BaseUploadContentConfigurationTestCase):
assert library_dataset["file_size"] == 12, library_dataset
def test_link_data_only(self) -> None:
content = "hello world\n"
dir_path = os.path.join(self.server_dir(), "lib1")
file_path = self._write_file(dir_path, content)
library = self.library_populator.new_private_library("serverdirupload")
# upload $GALAXY_ROOT/test-data/library
payload, files = self.library_populator.create_dataset_request(
library, upload_option="upload_directory", server_dir="lib1", link_data=True
)
response = self.library_populator.raw_library_contents_create(library["id"], payload, files=files)
assert response.status_code == 200, response.json()
dataset = response.json()[0]
ok_dataset = self.library_populator.wait_on_library_dataset(library["id"], dataset["id"])
assert ok_dataset["file_size"] == 12, ok_dataset
assert ok_dataset["file_name"] == file_path, ok_dataset
link_data_only(self.server_dir(), self.library_populator)
@classmethod
def server_dir(cls) -> str:
@@ -813,20 +839,7 @@ class TestFetchByPath(BaseUploadContentConfigurationTestCase):
assert os.path.exists(bed_test_data_path)
def test_fetch_link_data_only(self) -> None:
history_id, library, destination = self.library_populator.setup_fetch_to_folder("fetch_and_link")
bed_test_data_path = self.test_data_resolver.get_filename("4.bed")
assert os.path.exists(bed_test_data_path)
items = [{"src": "path", "path": bed_test_data_path, "info": "my cool bed", "link_data_only": True}]
targets = [{"destination": destination, "items": items}]
payload = {
"history_id": history_id, # TODO: Shouldn't be needed :(
"targets": targets,
}
self.dataset_populator.fetch(payload)
dataset = self.library_populator.get_library_contents_with_path(library["id"], "/4.bed")
assert dataset["file_size"] == 61, dataset
assert dataset["file_name"] == bed_test_data_path, dataset
assert os.path.exists(bed_test_data_path)
fetch_link_data_only(self.library_populator, self.dataset_populator, self.test_data_resolver)
def test_fetch_recursive_archive(self) -> None:
history_id, library, destination = self.library_populator.setup_fetch_to_folder("recursive_archive")
@@ -948,3 +961,26 @@ class TestDirectoryAndCompressedTypes(BaseUploadContentConfigurationTestCase):
history_id=history_id,
)
self.dataset_populator.wait_for_job(response["jobs"][0]["id"])
class TestLinkDataUploadExtendedMetadata(BaseUploadContentConfigurationTestCase):
require_admin_user = True
@classmethod
def handle_galaxy_config_kwds(cls, config) -> None:
super().handle_galaxy_config_kwds(config)
config["allow_path_paste"] = True
config["metadata_strategy"] = "extended"
server_dir = cls.server_dir()
os.makedirs(server_dir)
config["library_import_dir"] = server_dir
@classmethod
def server_dir(cls) -> str:
return cls.temp_config_dir("server")
def test_fetch_link_data_only(self) -> None:
fetch_link_data_only(self.library_populator, self.dataset_populator, self.test_data_resolver)
def test_link_data_only(self) -> None:
link_data_only(self.server_dir(), self.library_populator)
+2 -1
View File
@@ -41,7 +41,8 @@ def main():
# grep comments
grep_comments = ["grep", "^#"]
exit_code = subprocess.call(grep_comments, stdout=output_fh)
exit_code = subprocess.call(grep_comments, stdin=input_fh, stdout=output_fh)
input_fh.seek(0)
if exit_code not in [0, 1]:
stop_err("Searching for comment lines failed")