New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix subtle bug in listify function + simplify list munging #16904
Conversation
lib/galaxy/util/__init__.py
Outdated
@@ -1069,7 +1069,7 @@ def listify(item: Any, do_strip: bool = False) -> List: | |||
:rtype: list | |||
:returns: The input as a list | |||
""" | |||
if not item: | |||
if item is None or item == "": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a pretty risky change. Can you move the special casing to munge_filters ? It does change things i.e. when item is 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It surely is counter-intuitive that listify(0)
and listify(False)
return []
, but as Marius says we cannot change the behaviour of this function any more.
We probably need a listify_new
function that does what you were proposing here, and use that in new code / when refactoring.
lib/galaxy/util/__init__.py
Outdated
@@ -1882,3 +1882,14 @@ def enum_values(enum_class): | |||
Values are in member definition order. | |||
""" | |||
return [value.value for value in enum_class.__members__.values()] | |||
|
|||
|
|||
def munge_lists(listA: Any, listB: Any) -> List: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want more functions in util/__init__.py
, which we have to maintain indefinitely as the public api. Apart from that munge_lists
is not a good name and we're not re-using this anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmchilton can you elaborate ?
9f6d319
to
46ab820
Compare
Also, drop _munge_filters and use util function directly.
Move function to managers.base; rename. Do not reuse listify; implement standalone function. Add test case for tuples. (See PR code review for discussion)
46ab820
to
b172849
Compare
I've added a function to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I think this looks good.
The "Test Galaxy packages" failure is related. |
Because the passed argument is not a SA filter, but our own parsed filter, which is a tuple.
This function is indeed a very special case: |
Subtle bug (discovered while upgrading SQLAlchemy syntax.)
The
ModelManager._munge_filters
method is supposed to "combine two lists into a single list" (as per docstring; which is also the right behavior). However, if one of the arguments isNone
and the other argument is not a list, it will return the other argument unchanged. This becomes a problem when one tries to iterate over the returned value, which is not an unlikely scenario:The obvious fix is to replace the existing implementation with a one-liner reusing our existing
listify
util function on both arguments:return listify(listA) + listify(listB)
. However, this exposed a bug: if one of the arguments is an object with the special__bool__
method overridden,listify
may return an empty list - which is the case with SQLAlchemy filters. A filter is a sql expression (e.g.Foo.bar == condition
); so checkingif not my_filter
will simply applynot
to the sql expression and negate it, returningTrue
- and that 's where the code assumes the item asNone
and returns an empty list. Explicitly checking forNone
fixes this.List munging moved to util.
Unit tests included.
How to test the changes?
(Select all options that apply)
License