diff --git a/lib/galaxy/datatypes/data.py b/lib/galaxy/datatypes/data.py index 308e691a02cc..05f5adbad6bf 100644 --- a/lib/galaxy/datatypes/data.py +++ b/lib/galaxy/datatypes/data.py @@ -484,16 +484,17 @@ def _serve_file_download(self, headers, data, trans, to_ext, file_size, **kwd): def _serve_binary_file_contents_as_text(self, trans, data, headers, file_size, max_peek_size): headers["content-type"] = "text/html" - return ( - trans.fill_template_mako( - "/dataset/binary_file.mako", - data=data, - file_contents=open(data.get_file_name(), "rb").read(max_peek_size), - file_size=util.nice_size(file_size), - truncated=file_size > max_peek_size, - ), - headers, - ) + with open(data.get_file_name(), "rb") as fh: + return ( + trans.fill_template_mako( + "/dataset/binary_file.mako", + data=data, + file_contents=fh.read(max_peek_size), + file_size=util.nice_size(file_size), + truncated=file_size > max_peek_size, + ), + headers, + ) def _serve_file_contents(self, trans, data, headers, preview, file_size, max_peek_size): from galaxy.datatypes import images @@ -502,16 +503,17 @@ def _serve_file_contents(self, trans, data, headers, preview, file_size, max_pee if not preview or isinstance(data.datatype, images.Image) or file_size < max_peek_size: return self._yield_user_file_content(trans, data, data.get_file_name(), headers), headers - # preview large text file - headers["content-type"] = "text/html" - return ( - trans.fill_template_mako( - "/dataset/large_file.mako", - truncated_data=open(data.get_file_name(), "rb").read(max_peek_size), - data=data, - ), - headers, - ) + with compression_utils.get_fileobj(data.get_file_name(), "rb") as fh: + # preview large text file + headers["content-type"] = "text/html" + return ( + trans.fill_template_mako( + "/dataset/large_file.mako", + truncated_data=fh.read(max_peek_size), + data=data, + ), + headers, + ) def display_data( self, diff --git a/lib/galaxy/datatypes/tabular.py b/lib/galaxy/datatypes/tabular.py index db9ef1293294..fab0b5893334 100644 --- a/lib/galaxy/datatypes/tabular.py +++ b/lib/galaxy/datatypes/tabular.py @@ -197,14 +197,15 @@ def display_data( return open(dataset.get_file_name(), mode="rb"), headers else: headers["content-type"] = "text/html" - return ( - trans.fill_template_mako( - "/dataset/large_file.mako", - truncated_data=open(dataset.get_file_name()).read(max_peek_size), - data=dataset, - ), - headers, - ) + with compression_utils.get_fileobj(dataset.get_file_name(), "rb") as fh: + return ( + trans.fill_template_mako( + "/dataset/large_file.mako", + truncated_data=fh.read(max_peek_size), + data=dataset, + ), + headers, + ) else: column_names = "null" if dataset.metadata.column_names: diff --git a/lib/galaxy/managers/hdas.py b/lib/galaxy/managers/hdas.py index 8eefb8434753..f69a20c6cc4c 100644 --- a/lib/galaxy/managers/hdas.py +++ b/lib/galaxy/managers/hdas.py @@ -311,7 +311,10 @@ def text_data(self, hda, preview=True): truncated = preview and os.stat(file_path).st_size > MAX_PEEK_SIZE with get_fileobj(file_path) as fh: - hda_data = fh.read(MAX_PEEK_SIZE) + try: + hda_data = fh.read(MAX_PEEK_SIZE) + except UnicodeDecodeError: + raise exceptions.RequestParameterInvalidException("Cannot generate text preview for dataset.") return truncated, hda_data # .... annotatable diff --git a/lib/galaxy/managers/users.py b/lib/galaxy/managers/users.py index 226bbcf7e0f9..6e50241ab3d9 100644 --- a/lib/galaxy/managers/users.py +++ b/lib/galaxy/managers/users.py @@ -611,8 +611,9 @@ def send_reset_email(self, trans, payload, **kwd): except Exception as e: log.debug(body) return f"Failed to submit email. Please contact the administrator: {util.unicodify(e)}" - else: - return "Failed to produce password reset token. User not found." + if not reset_user: + log.warning(f"Failed to produce password reset token. User with email '{email}' not found.") + return None def get_reset_token(self, trans, email): reset_user = get_user_by_email(trans.sa_session, email, self.app.model.User) diff --git a/lib/galaxy/tool_util/biotools/source.py b/lib/galaxy/tool_util/biotools/source.py index 6f101abcbee5..f5fcc54041c5 100644 --- a/lib/galaxy/tool_util/biotools/source.py +++ b/lib/galaxy/tool_util/biotools/source.py @@ -55,12 +55,13 @@ def __init__(self, cache=None): def _raw_get_metadata(self, biotools_reference) -> Optional[str]: api_url = f"https://bio.tools/api/tool/{biotools_reference}?format=json" - req = requests.get(api_url, timeout=DEFAULT_SOCKET_TIMEOUT) - req.encoding = req.apparent_encoding - if req.status_code == 404: - return None - else: + try: + req = requests.get(api_url, timeout=DEFAULT_SOCKET_TIMEOUT) + req.raise_for_status() + req.encoding = req.apparent_encoding return req.text + except Exception: + return None def get_biotools_metadata(self, biotools_reference: str) -> Optional[BiotoolsEntry]: createfunc = functools.partial(self._raw_get_metadata, biotools_reference) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index ebdad3e37aed..8d243cb88014 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2053,7 +2053,8 @@ def src_id_to_item( item = sa_session.get(src_to_class[value["src"]], decoded_id) except KeyError: raise ValueError(f"Unknown input source {value['src']} passed to job submission API.") - assert item + if not item: + raise ValueError("Invalid input id passed to job submission API.") item.extra_params = {k: v for k, v in value.items() if k not in ("src", "id")} return item diff --git a/lib/galaxy/web/framework/middleware/statsd.py b/lib/galaxy/web/framework/middleware/statsd.py index 1b017f715651..d817569f3d8e 100644 --- a/lib/galaxy/web/framework/middleware/statsd.py +++ b/lib/galaxy/web/framework/middleware/statsd.py @@ -28,8 +28,13 @@ def __call__(self, environ, start_response): start_time = time.time() req = self.application(environ, start_response) dt = int((time.time() - start_time) * 1000) - page = environ.get("controller_action_key", None) or environ.get("PATH_INFO", "NOPATH").strip("/").replace( - "/", "." + page = ( + environ.get("controller_action_key", None) + or environ.get("PATH_INFO", "NOPATH") + .strip("/") + .replace("/", ".") + .encode("ascii", errors="replace") + .decode() ) self.galaxy_stasd_client.timing(page, dt) try: diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py index 8e476f0db3b4..b0cb5ae5fe69 100644 --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -342,7 +342,7 @@ def reset_password(self, trans, payload=None, **kwd): payload = payload or {} if message := self.user_manager.send_reset_email(trans, payload): return self.message_exception(trans, message) - return {"message": "Reset link has been sent to your email."} + return {"message": "If an account exists for this email address a confirmation email will be dispatched."} def __get_redirect_url(self, redirect): if not redirect or redirect == "None": diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py index 0ad9f46d5c16..d0eb5025d5c4 100644 --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -746,7 +746,8 @@ def get_all_outputs(self, data_only=False): # This can happen when importing workflows with missing tools. # We can't raise an exception here, as that would prevent loading # the workflow. - log.error( + # This is also listed when opening such a workflow in the workflow editor. + log.warning( f"Workflow output '{workflow_output['output_name']}' defined, but not listed among data outputs" ) continue diff --git a/test/integration/objectstore/_purged_handling.py b/test/integration/objectstore/_purged_handling.py index 1437f6742ae5..097a9f922360 100644 --- a/test/integration/objectstore/_purged_handling.py +++ b/test/integration/objectstore/_purged_handling.py @@ -9,7 +9,7 @@ def purge_while_job_running(dataset_populator: DatasetPopulator, extra_sleep=0): response = dataset_populator.run_tool( "all_output_types", inputs={ - "sleep_param": 5, + "sleep_param": 5 + extra_sleep, }, history_id=history_id, ) diff --git a/test/integration/test_extended_metadata.py b/test/integration/test_extended_metadata.py index d267ed01c418..50c21940cfba 100644 --- a/test/integration/test_extended_metadata.py +++ b/test/integration/test_extended_metadata.py @@ -100,7 +100,7 @@ def test_fetch_data_library(self): def test_purge_while_job_running(self): # pass extra_sleep, since templating the command line will fail if the output # is deleted before remote_tool_eval runs. - purge_while_job_running(self.dataset_populator, extra_sleep=4) + purge_while_job_running(self.dataset_populator, extra_sleep=10) class TestExtendedMetadataDeferredIntegration(integration_util.IntegrationTestCase): diff --git a/test/unit/app/managers/test_UserManager.py b/test/unit/app/managers/test_UserManager.py index b8286838d103..8bd1807c50c1 100644 --- a/test/unit/app/managers/test_UserManager.py +++ b/test/unit/app/managers/test_UserManager.py @@ -240,7 +240,7 @@ def test_reset_email_user_deleted(self): self.user_manager.delete(user) assert user.deleted is True message = self.user_manager.send_reset_email(self.trans, {"email": user_email}) - assert message == "Failed to produce password reset token. User not found." + assert message is None def test_get_user_by_identity(self): # return None if username/email not found