From b648c60dd460011ee241b050305ddb02c33077be Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 18 Apr 2024 12:37:45 -0400 Subject: [PATCH 01/20] Add a link to histories list in history import message for situations where you import without a history visible (e.g. published page view) --- client/src/components/History/HistoryView.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/components/History/HistoryView.vue b/client/src/components/History/HistoryView.vue index 103909b0a9f7..e185e7517147 100644 --- a/client/src/components/History/HistoryView.vue +++ b/client/src/components/History/HistoryView.vue @@ -25,7 +25,9 @@ - History imported and set to your active history. + + History imported and is now your active history. View here. + Date: Thu, 18 Apr 2024 17:51:13 -0400 Subject: [PATCH 02/20] Rename method, add comment to explain side effects --- lib/galaxy/model/tags.py | 13 ++++++++++--- test/unit/app/managers/test_TagHandler.py | 11 +++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/model/tags.py b/lib/galaxy/model/tags.py index a62051b79eef..eefc252f919c 100644 --- a/lib/galaxy/model/tags.py +++ b/lib/galaxy/model/tags.py @@ -294,8 +294,15 @@ def get_tag_by_name(self, tag_name): return self.sa_session.scalars(select(galaxy.model.Tag).filter_by(name=tag_name.lower()).limit(1)).first() return None - def _create_tag(self, tag_str: str): - """Create a Tag object from a tag string.""" + def _create_tags(self, tag_str: str): + """ + Create or retrieve one of more Tag objects from a tag string. If there are multiple + hierarchical tags in the tag string, the string will be split along `self.hierarchy_separator` chars. + A Tag instance will be created for each non-empty prefix. If a prefix corresponds to the + name of an existing tag, that tag will be retrieved; otherwise, a new Tag object will be created. + For example, for the tag string `a.b.c` 3 Tag isntances will be created: `a`, `a.b`, `a.b.c`. + Return the last tag created (`a.b.c`). + """ tag_hierarchy = tag_str.split(self.hierarchy_separator) tag_prefix = "" parent_tag = None @@ -344,7 +351,7 @@ def _get_or_create_tag(self, tag_str): tag = self.get_tag_by_name(scrubbed_tag_str) # Create tag if necessary. if tag is None: - tag = self._create_tag(scrubbed_tag_str) + tag = self._create_tags(scrubbed_tag_str) return tag def _get_item_tag_assoc(self, user, item, tag_name): diff --git a/test/unit/app/managers/test_TagHandler.py b/test/unit/app/managers/test_TagHandler.py index 97b476c0e715..f249e4dfa63d 100644 --- a/test/unit/app/managers/test_TagHandler.py +++ b/test/unit/app/managers/test_TagHandler.py @@ -112,3 +112,14 @@ def test_item_has_tag(self): # Tag assert self.tag_handler.item_has_tag(self.user, item=hda, tag=hda.tags[0].tag) assert not self.tag_handler.item_has_tag(self.user, item=hda, tag="tag2") + + def test_get_name_value_pair(self): + """Test different combinations of tag and name/value delimiters via parse_tags().""" + assert self.tag_handler.parse_tags("a") == [("a", None)] + assert self.tag_handler.parse_tags("a.b") == [("a.b", None)] + assert self.tag_handler.parse_tags("a.b:c") == [("a.b", "c")] + assert self.tag_handler.parse_tags("a.b:c.d") == [("a.b", "c.d")] + assert self.tag_handler.parse_tags("a.b:c.d:e.f") == [("a.b", "c.d:e.f")] + assert self.tag_handler.parse_tags("a.b:c.d:e.f.") == [("a.b", "c.d:e.f.")] + assert self.tag_handler.parse_tags("a.b:c.d:e.f:") == [("a.b", "c.d:e.f:")] + assert self.tag_handler.parse_tags("a.b:c.d:e.f:::") == [("a.b", "c.d:e.f:::")] From b356b0cca3b658fcda62e19c6d99886e4c194ca8 Mon Sep 17 00:00:00 2001 From: John Davis Date: Thu, 18 Apr 2024 18:29:43 -0400 Subject: [PATCH 03/20] Factor out tag pattern into a const --- lib/galaxy/schema/schema.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 34fe24988095..853148272753 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -66,6 +66,8 @@ OptionalNumberT = Annotated[Optional[Union[int, float]], Field(None)] +TAG_ITEM_PATTERN = r"^([^\s.:])+(.[^\s.:]+)*(:[^\s.:]+)?$" + class DatasetState(str, Enum): NEW = "new" @@ -527,7 +529,7 @@ class HistoryContentSource(str, Enum): DatasetCollectionInstanceType = Literal["history", "library"] -TagItem = Annotated[str, Field(..., pattern=r"^([^\s.:])+(.[^\s.:]+)*(:[^\s.:]+)?$")] +TagItem = Annotated[str, Field(..., pattern=TAG_ITEM_PATTERN)] class TagCollection(RootModel): From 972f91824163047b9d25d5d1abd9812f3b410a63 Mon Sep 17 00:00:00 2001 From: John Davis Date: Thu, 18 Apr 2024 18:31:45 -0400 Subject: [PATCH 04/20] Add unit test (failing) for tag string regex --- test/unit/schema/test_schema.py | 46 ++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/test/unit/schema/test_schema.py b/test/unit/schema/test_schema.py index 570469ed6fc2..e139a52544c4 100644 --- a/test/unit/schema/test_schema.py +++ b/test/unit/schema/test_schema.py @@ -1,8 +1,12 @@ +import re from uuid import uuid4 from pydantic import BaseModel -from galaxy.schema.schema import DatasetStateField +from galaxy.schema.schema import ( + DatasetStateField, + TAG_ITEM_PATTERN, +) from galaxy.schema.tasks import ( GenerateInvocationDownload, RequestUser, @@ -34,3 +38,43 @@ class StateModel(BaseModel): def test_dataset_state_coercion(): assert StateModel(state="ok").state == "ok" assert StateModel(state="deleted").state == "discarded" + + +class TestTagPattern: + + def test_valid(self): + tag_strings = [ + "a", + "aa", + "aa.aa", + "aa.aa.aa", + "~!@#$%^&*()_+`-=[]{};'\",./<>?", + "a.b:c", + "a.b:c.d:e.f", + "a.b:c.d:e..f", + "a.b:c.d:e.f:g", + "a.b:c.d:e.f::g", + "a.b:c.d:e.f::g:h", + "a::a", # leading colon for tag value + "a:.a", # leading period for tag value + "a:a:", # training colon OK for tag value + "a:a.", # training period OK for tag value + ] + for t in tag_strings: + assert re.match(TAG_ITEM_PATTERN, t) + + def test_invalid(self): + tag_strings = [ + " a", # leading space for tag name + ":a", # leading colon for tag name + ".a", # leading period for tag name + "a ", # trailing space for tag name + "a a", # space inside tag name + "a: a", # leading space for tag value + "a:a a", # space inside tag value + "a:", # trailing colon for tag name + "a.", # trailing period for tag name + "a:b ", # trailing space for tag value + ] + for t in tag_strings: + assert not re.match(TAG_ITEM_PATTERN, t) From 7ec131156eb5ac635e90bd644201ae3f2f9503a7 Mon Sep 17 00:00:00 2001 From: John Davis Date: Thu, 18 Apr 2024 18:34:01 -0400 Subject: [PATCH 05/20] Add unit test to verify spllitting tag string into name/value --- test/unit/app/managers/test_TagHandler.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/unit/app/managers/test_TagHandler.py b/test/unit/app/managers/test_TagHandler.py index f249e4dfa63d..7f0e3ad21ce8 100644 --- a/test/unit/app/managers/test_TagHandler.py +++ b/test/unit/app/managers/test_TagHandler.py @@ -114,12 +114,13 @@ def test_item_has_tag(self): assert not self.tag_handler.item_has_tag(self.user, item=hda, tag="tag2") def test_get_name_value_pair(self): - """Test different combinations of tag and name/value delimiters via parse_tags().""" + """Verify that parsing a single tag string correctly splits it into name/value pairs.""" assert self.tag_handler.parse_tags("a") == [("a", None)] assert self.tag_handler.parse_tags("a.b") == [("a.b", None)] assert self.tag_handler.parse_tags("a.b:c") == [("a.b", "c")] assert self.tag_handler.parse_tags("a.b:c.d") == [("a.b", "c.d")] assert self.tag_handler.parse_tags("a.b:c.d:e.f") == [("a.b", "c.d:e.f")] assert self.tag_handler.parse_tags("a.b:c.d:e.f.") == [("a.b", "c.d:e.f.")] + assert self.tag_handler.parse_tags("a.b:c.d:e.f..") == [("a.b", "c.d:e.f..")] assert self.tag_handler.parse_tags("a.b:c.d:e.f:") == [("a.b", "c.d:e.f:")] - assert self.tag_handler.parse_tags("a.b:c.d:e.f:::") == [("a.b", "c.d:e.f:::")] + assert self.tag_handler.parse_tags("a.b:c.d:e.f::") == [("a.b", "c.d:e.f::")] From c31bccf712ff206f4679bde52da2969779fff0b3 Mon Sep 17 00:00:00 2001 From: John Davis Date: Thu, 18 Apr 2024 19:05:06 -0400 Subject: [PATCH 06/20] Fix regex pattern --- lib/galaxy/schema/schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 853148272753..277bb82f481e 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -66,7 +66,7 @@ OptionalNumberT = Annotated[Optional[Union[int, float]], Field(None)] -TAG_ITEM_PATTERN = r"^([^\s.:])+(.[^\s.:]+)*(:[^\s.:]+)?$" +TAG_ITEM_PATTERN = r"^([^\s.:])+(\.[^\s.:]+)*(:\S+)?$" class DatasetState(str, Enum): From ee64fc414daa5b807c2d3305e600f3b75a72fe98 Mon Sep 17 00:00:00 2001 From: John Davis Date: Thu, 18 Apr 2024 21:45:39 -0400 Subject: [PATCH 07/20] Update client valid tag regex --- client/src/components/Tags/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Tags/model.js b/client/src/components/Tags/model.js index ced4f9896553..43dbc05d74ee 100644 --- a/client/src/components/Tags/model.js +++ b/client/src/components/Tags/model.js @@ -7,7 +7,7 @@ import { keyedColorScheme } from "utils/color"; // Valid tag regex. The basic format here is a tag name with optional subtags // separated by a period, and then an optional value after a colon. -export const VALID_TAG_RE = /^([^\s.:])+(.[^\s.:]+)*(:[^\s.:]+)?$/; +export const VALID_TAG_RE = /^([^\s.:])+(\.[^\s.:]+)*(:\S+)?$/; export class TagModel { /** From e32b9aa60840666daef36140476f67dfd5bde33e Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Fri, 19 Apr 2024 10:16:32 +0200 Subject: [PATCH 08/20] Fix test_get_tags_histories_content test The calling code expects that this creates a dataset, but instead this used to create dataset collection. --- lib/galaxy_test/api/test_item_tags.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/galaxy_test/api/test_item_tags.py b/lib/galaxy_test/api/test_item_tags.py index 3b9527f7b37f..025c3504c012 100644 --- a/lib/galaxy_test/api/test_item_tags.py +++ b/lib/galaxy_test/api/test_item_tags.py @@ -135,9 +135,9 @@ def _create_valid_tag(self, prefix: str): return response def _create_history_contents(self, history_id): - history_content_id = self.dataset_collection_populator.create_list_in_history( - history_id, contents=["test_dataset"], direct_upload=True, wait=True - ).json()["outputs"][0]["id"] + history_content_id = self.dataset_populator.new_dataset( + history_id, contents="test_dataset", direct_upload=True, wait=True + )["id"] return history_content_id def _create_history(self): From e765e66925505f5dfb6c1348079cfdbd7dea7e4f Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 19 Apr 2024 13:29:02 +0200 Subject: [PATCH 09/20] Handle PyFilesystem2 errors more gracefully --- lib/galaxy/files/sources/_pyfilesystem2.py | 34 +++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/galaxy/files/sources/_pyfilesystem2.py b/lib/galaxy/files/sources/_pyfilesystem2.py index 3336f72a2165..e604a6c8f75f 100644 --- a/lib/galaxy/files/sources/_pyfilesystem2.py +++ b/lib/galaxy/files/sources/_pyfilesystem2.py @@ -12,9 +12,11 @@ ) import fs +import fs.errors from fs.base import FS from typing_extensions import Unpack +from galaxy.exceptions import MessageException from . import ( BaseFilesSource, FilesSourceOptions, @@ -42,19 +44,25 @@ def _open_fs(self, user_context=None, opts: Optional[FilesSourceOptions] = None) def _list(self, path="/", recursive=False, user_context=None, opts: Optional[FilesSourceOptions] = None): """Return dictionary of 'Directory's and 'File's.""" - - with self._open_fs(user_context=user_context, opts=opts) as h: - if recursive: - res: List[Dict[str, Any]] = [] - for p, dirs, files in h.walk(path): - to_dict = functools.partial(self._resource_info_to_dict, p) - res.extend(map(to_dict, dirs)) - res.extend(map(to_dict, files)) - return res - else: - res = h.scandir(path, namespaces=["details"]) - to_dict = functools.partial(self._resource_info_to_dict, path) - return list(map(to_dict, res)) + try: + with self._open_fs(user_context=user_context, opts=opts) as h: + if recursive: + res: List[Dict[str, Any]] = [] + for p, dirs, files in h.walk(path): + to_dict = functools.partial(self._resource_info_to_dict, p) + res.extend(map(to_dict, dirs)) + res.extend(map(to_dict, files)) + return res + else: + res = h.scandir(path, namespaces=["details"]) + to_dict = functools.partial(self._resource_info_to_dict, path) + return list(map(to_dict, res)) + except fs.errors.PermissionDenied as e: + raise MessageException( + f"Permission Denied. Reason: {e}. Please check your credentials in your preferences for {self.label}." + ) + except fs.errors.FSError as e: + raise MessageException(f"Problem listing file source path {path}. Reason: {e}") from e def _realize_to(self, source_path, native_path, user_context=None, opts: Optional[FilesSourceOptions] = None): with open(native_path, "wb") as write_file: From 0bbb982cae3af878c3ff52673dfb7b1c8588d433 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 19 Apr 2024 13:31:30 +0200 Subject: [PATCH 10/20] Handle errors creating new entries more gracefully --- lib/galaxy/files/sources/_rdm.py | 4 ++-- lib/galaxy/managers/remote_files.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/files/sources/_rdm.py b/lib/galaxy/files/sources/_rdm.py index 14f7e9e1daa0..7d9a97d2fb5f 100644 --- a/lib/galaxy/files/sources/_rdm.py +++ b/lib/galaxy/files/sources/_rdm.py @@ -7,7 +7,7 @@ from typing_extensions import Unpack -from galaxy.exceptions import AuthenticationRequired +from galaxy.exceptions import MessageException from galaxy.files import ProvidesUserFileSourcesUserContext from galaxy.files.sources import ( BaseFilesSource, @@ -199,7 +199,7 @@ def get_authorization_token(self, user_context: OptionalUserContext) -> str: effective_props = self._serialization_props(user_context) token = effective_props.get("token") if not token: - raise AuthenticationRequired( + raise MessageException( f"Please provide a personal access token in your user's preferences for '{self.label}'" ) return token diff --git a/lib/galaxy/managers/remote_files.py b/lib/galaxy/managers/remote_files.py index 06980dac8580..985dd4980dbd 100644 --- a/lib/galaxy/managers/remote_files.py +++ b/lib/galaxy/managers/remote_files.py @@ -162,6 +162,9 @@ def create_entry(self, user_ctx: ProvidesUserContext, entry_data: CreateEntryPay file_source = file_source_path.file_source try: result = file_source.create_entry(entry_data.dict(), user_context=user_file_source_context) + except exceptions.MessageException: + log.warning(f"Problem creating entry {entry_data.name} in file source {entry_data.target}", exc_info=True) + raise except Exception: message = f"Problem creating entry {entry_data.name} in file source {entry_data.target}" log.warning(message, exc_info=True) From 91bf0c69aa8440f7df932320727581512160d2ea Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 19 Apr 2024 13:32:24 +0200 Subject: [PATCH 11/20] Handle Dropbox special case --- lib/galaxy/files/sources/dropbox.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/files/sources/dropbox.py b/lib/galaxy/files/sources/dropbox.py index 880834411d5a..865338da2bbd 100644 --- a/lib/galaxy/files/sources/dropbox.py +++ b/lib/galaxy/files/sources/dropbox.py @@ -8,6 +8,7 @@ Union, ) +from galaxy.exceptions import MessageException from . import ( FilesSourceOptions, FilesSourceProperties, @@ -27,8 +28,17 @@ def _open_fs(self, user_context=None, opts: Optional[FilesSourceOptions] = None) if "accessToken" in props: props["access_token"] = props.pop("accessToken") - handle = DropboxFS(**{**props, **extra_props}) - return handle + try: + handle = DropboxFS(**{**props, **extra_props}) + return handle + except Exception as e: + # This plugin might raise dropbox.dropbox_client.BadInputException + # which is not a subclass of fs.errors.FSError + if "OAuth2" in str(e): + raise MessageException( + f"Permission Denied. Reason: {e}. Please check your credentials in your preferences for {self.label}." + ) + raise MessageException(f"Error connecting to Dropbox. Reason: {e}") __all__ = ("DropboxFilesSource",) From 53f5b5fd1f1e2a059413cbb16206731f189d014e Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 19 Apr 2024 13:44:08 +0200 Subject: [PATCH 12/20] Use less cryptic error when unexpected error --- lib/galaxy/managers/remote_files.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/managers/remote_files.py b/lib/galaxy/managers/remote_files.py index 985dd4980dbd..2be2274dbc70 100644 --- a/lib/galaxy/managers/remote_files.py +++ b/lib/galaxy/managers/remote_files.py @@ -9,6 +9,7 @@ from galaxy import exceptions from galaxy.files import ( ConfiguredFileSources, + FileSourcePath, ProvidesUserFileSourcesUserContext, ) from galaxy.files.sources import ( @@ -94,10 +95,10 @@ def index( opts=opts, ) except exceptions.MessageException: - log.warning(f"Problem listing file source path {file_source_path}", exc_info=True) + log.warning(self._get_error_message(file_source_path), exc_info=True) raise except Exception: - message = f"Problem listing file source path {file_source_path}" + message = self._get_error_message(file_source_path) log.warning(message, exc_info=True) raise exceptions.InternalServerError(message) if format == RemoteFilesFormat.flat: @@ -131,6 +132,9 @@ def index( return index + def _get_error_message(self, file_source_path: FileSourcePath) -> str: + return f"Problem listing file source path {file_source_path.file_source.get_uri_root()}{file_source_path.path}" + def get_files_source_plugins( self, user_context: ProvidesUserContext, From b32480c95cef2cf5ff9609ea71e08a3ece7f3579 Mon Sep 17 00:00:00 2001 From: John Davis Date: Fri, 19 Apr 2024 09:46:48 -0400 Subject: [PATCH 13/20] Update lib/galaxy/model/tags.py Co-authored-by: Dannon --- lib/galaxy/model/tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/model/tags.py b/lib/galaxy/model/tags.py index eefc252f919c..8772a10900a4 100644 --- a/lib/galaxy/model/tags.py +++ b/lib/galaxy/model/tags.py @@ -296,7 +296,7 @@ def get_tag_by_name(self, tag_name): def _create_tags(self, tag_str: str): """ - Create or retrieve one of more Tag objects from a tag string. If there are multiple + Create or retrieve one or more Tag objects from a tag string. If there are multiple hierarchical tags in the tag string, the string will be split along `self.hierarchy_separator` chars. A Tag instance will be created for each non-empty prefix. If a prefix corresponds to the name of an existing tag, that tag will be retrieved; otherwise, a new Tag object will be created. From 645ff002ecf5bdc0e057f245712f4c9a9ebb1647 Mon Sep 17 00:00:00 2001 From: John Davis Date: Fri, 19 Apr 2024 09:47:00 -0400 Subject: [PATCH 14/20] Update lib/galaxy/model/tags.py Co-authored-by: Dannon --- lib/galaxy/model/tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/model/tags.py b/lib/galaxy/model/tags.py index 8772a10900a4..a642a4a5a34a 100644 --- a/lib/galaxy/model/tags.py +++ b/lib/galaxy/model/tags.py @@ -300,7 +300,7 @@ def _create_tags(self, tag_str: str): hierarchical tags in the tag string, the string will be split along `self.hierarchy_separator` chars. A Tag instance will be created for each non-empty prefix. If a prefix corresponds to the name of an existing tag, that tag will be retrieved; otherwise, a new Tag object will be created. - For example, for the tag string `a.b.c` 3 Tag isntances will be created: `a`, `a.b`, `a.b.c`. + For example, for the tag string `a.b.c` 3 Tag instances will be created: `a`, `a.b`, `a.b.c`. Return the last tag created (`a.b.c`). """ tag_hierarchy = tag_str.split(self.hierarchy_separator) From b5a93f0ef7ea55a501f941812c5a54422a65e970 Mon Sep 17 00:00:00 2001 From: John Davis Date: Fri, 19 Apr 2024 09:47:11 -0400 Subject: [PATCH 15/20] Update lib/galaxy/model/tags.py Co-authored-by: Dannon --- lib/galaxy/model/tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/model/tags.py b/lib/galaxy/model/tags.py index a642a4a5a34a..15abfb6ab967 100644 --- a/lib/galaxy/model/tags.py +++ b/lib/galaxy/model/tags.py @@ -351,7 +351,7 @@ def _get_or_create_tag(self, tag_str): tag = self.get_tag_by_name(scrubbed_tag_str) # Create tag if necessary. if tag is None: - tag = self._create_tags(scrubbed_tag_str) + tag = self._create_tag(scrubbed_tag_str) return tag def _get_item_tag_assoc(self, user, item, tag_name): From b798109589a6e0b3cd5492d021f9c3ad825a97f5 Mon Sep 17 00:00:00 2001 From: John Davis Date: Fri, 19 Apr 2024 09:47:18 -0400 Subject: [PATCH 16/20] Update lib/galaxy/model/tags.py Co-authored-by: Dannon --- lib/galaxy/model/tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/model/tags.py b/lib/galaxy/model/tags.py index 15abfb6ab967..22e7ae63ef75 100644 --- a/lib/galaxy/model/tags.py +++ b/lib/galaxy/model/tags.py @@ -294,7 +294,7 @@ def get_tag_by_name(self, tag_name): return self.sa_session.scalars(select(galaxy.model.Tag).filter_by(name=tag_name.lower()).limit(1)).first() return None - def _create_tags(self, tag_str: str): + def _create_tag(self, tag_str: str): """ Create or retrieve one or more Tag objects from a tag string. If there are multiple hierarchical tags in the tag string, the string will be split along `self.hierarchy_separator` chars. From 90bb4c93341e972955e757bff4db72ee0bdc62c9 Mon Sep 17 00:00:00 2001 From: John Davis Date: Fri, 19 Apr 2024 09:47:31 -0400 Subject: [PATCH 17/20] Update test/unit/schema/test_schema.py Co-authored-by: Dannon --- test/unit/schema/test_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/schema/test_schema.py b/test/unit/schema/test_schema.py index e139a52544c4..69d7660c20d4 100644 --- a/test/unit/schema/test_schema.py +++ b/test/unit/schema/test_schema.py @@ -57,7 +57,7 @@ def test_valid(self): "a.b:c.d:e.f::g:h", "a::a", # leading colon for tag value "a:.a", # leading period for tag value - "a:a:", # training colon OK for tag value + "a:a:", # trailing colon OK for tag value "a:a.", # training period OK for tag value ] for t in tag_strings: From ac8338f64df9f6c527222dfb045fd010c00f787f Mon Sep 17 00:00:00 2001 From: John Davis Date: Fri, 19 Apr 2024 09:47:38 -0400 Subject: [PATCH 18/20] Update test/unit/schema/test_schema.py Co-authored-by: Dannon --- test/unit/schema/test_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/schema/test_schema.py b/test/unit/schema/test_schema.py index 69d7660c20d4..21b37096d131 100644 --- a/test/unit/schema/test_schema.py +++ b/test/unit/schema/test_schema.py @@ -58,7 +58,7 @@ def test_valid(self): "a::a", # leading colon for tag value "a:.a", # leading period for tag value "a:a:", # trailing colon OK for tag value - "a:a.", # training period OK for tag value + "a:a.", # trailing period OK for tag value ] for t in tag_strings: assert re.match(TAG_ITEM_PATTERN, t) From 0d1c41f0cc27ff4338e71283563d35e4cff16c54 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:36:51 +0200 Subject: [PATCH 19/20] Prefer AuthenticationRequired for credential issues --- lib/galaxy/files/sources/_pyfilesystem2.py | 7 +++++-- lib/galaxy/files/sources/_rdm.py | 4 ++-- lib/galaxy/files/sources/dropbox.py | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/galaxy/files/sources/_pyfilesystem2.py b/lib/galaxy/files/sources/_pyfilesystem2.py index e604a6c8f75f..efdb5ac79ca8 100644 --- a/lib/galaxy/files/sources/_pyfilesystem2.py +++ b/lib/galaxy/files/sources/_pyfilesystem2.py @@ -16,7 +16,10 @@ from fs.base import FS from typing_extensions import Unpack -from galaxy.exceptions import MessageException +from galaxy.exceptions import ( + AuthenticationRequired, + MessageException, +) from . import ( BaseFilesSource, FilesSourceOptions, @@ -58,7 +61,7 @@ def _list(self, path="/", recursive=False, user_context=None, opts: Optional[Fil to_dict = functools.partial(self._resource_info_to_dict, path) return list(map(to_dict, res)) except fs.errors.PermissionDenied as e: - raise MessageException( + raise AuthenticationRequired( f"Permission Denied. Reason: {e}. Please check your credentials in your preferences for {self.label}." ) except fs.errors.FSError as e: diff --git a/lib/galaxy/files/sources/_rdm.py b/lib/galaxy/files/sources/_rdm.py index 7d9a97d2fb5f..14f7e9e1daa0 100644 --- a/lib/galaxy/files/sources/_rdm.py +++ b/lib/galaxy/files/sources/_rdm.py @@ -7,7 +7,7 @@ from typing_extensions import Unpack -from galaxy.exceptions import MessageException +from galaxy.exceptions import AuthenticationRequired from galaxy.files import ProvidesUserFileSourcesUserContext from galaxy.files.sources import ( BaseFilesSource, @@ -199,7 +199,7 @@ def get_authorization_token(self, user_context: OptionalUserContext) -> str: effective_props = self._serialization_props(user_context) token = effective_props.get("token") if not token: - raise MessageException( + raise AuthenticationRequired( f"Please provide a personal access token in your user's preferences for '{self.label}'" ) return token diff --git a/lib/galaxy/files/sources/dropbox.py b/lib/galaxy/files/sources/dropbox.py index 865338da2bbd..70c994e3e2e4 100644 --- a/lib/galaxy/files/sources/dropbox.py +++ b/lib/galaxy/files/sources/dropbox.py @@ -8,7 +8,10 @@ Union, ) -from galaxy.exceptions import MessageException +from galaxy.exceptions import ( + AuthenticationRequired, + MessageException, +) from . import ( FilesSourceOptions, FilesSourceProperties, @@ -35,7 +38,7 @@ def _open_fs(self, user_context=None, opts: Optional[FilesSourceOptions] = None) # This plugin might raise dropbox.dropbox_client.BadInputException # which is not a subclass of fs.errors.FSError if "OAuth2" in str(e): - raise MessageException( + raise AuthenticationRequired( f"Permission Denied. Reason: {e}. Please check your credentials in your preferences for {self.label}." ) raise MessageException(f"Error connecting to Dropbox. Reason: {e}") From 47f2ca6994a596cd6eb0d4d7708abfcd86b18340 Mon Sep 17 00:00:00 2001 From: Alexander OSTROVSKY Date: Wed, 28 Feb 2024 15:06:31 -0600 Subject: [PATCH 20/20] add colabfold tar file datatype --- lib/galaxy/config/sample/datatypes_conf.xml.sample | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/galaxy/config/sample/datatypes_conf.xml.sample b/lib/galaxy/config/sample/datatypes_conf.xml.sample index ee92a9da6bad..96be00d60aa7 100644 --- a/lib/galaxy/config/sample/datatypes_conf.xml.sample +++ b/lib/galaxy/config/sample/datatypes_conf.xml.sample @@ -377,6 +377,7 @@ +