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
xsd, docs, and test for sort_by (discover_datasets) #9684
Conversation
a98c123
to
38e05f2
Compare
38e05f2
to
020326a
Compare
seems ready |
<tests> | ||
<test> | ||
<param name="input1" value="tinywga.fam" /> | ||
<output_collection name="collection_numeric_name" type="list" count="11"/> |
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.
Don't you want to ascertain the new sort order ? You can list <element/>
items here
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.
That's true, but I did not expect the order of the elements is relevant. Lets try.
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.
Test currently do not check for the order, but only if the elements contained in the test definition are produced by the test:
def verify_elements(element_objects, element_tests): |
This would be (quite) easy to change, but
- the test definition is a dict and dictionary order can only be used for python >= 3.7
- dictionary order would always be lexicographic as defined for strings
- it seems that the dictionary order is lost in the
get_tool_tests
function called heretool_test_dicts = tool_test_dicts or galaxy_interactor.get_tool_tests(tool_id, tool_version=tool_version)
Seems difficult.
Spontaneous ideas
- sort the test elements in verify_elements as given by
sort_by
- leave it as is and consider the test just checking for bugs
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.
- the test definition is a dict and dictionary order can only be used for python >= 3.7
3.6, it was made official in 3.7
- dictionary order would always be lexicographic as defined for strings
this should be by insertion order on newer python's, right ?
Anyway, I agree this is not as straightforward. Maybe add a in the test, and then we can reconsider once sort order is guaranteed or we decide to write an API test, which could also assert this.
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.
3.6, it was made official in 3.7
true
this should be by insertion order on newer python's, right ?
also true, my mistake
Anyway, I agree this is not as straightforward. Maybe add a in the test, and then we can reconsider once sort order is guaranteed or we decide to write an API test, which could also assert this.
Still I have the urge to understand this :) Somewehere here:
def get_tool_tests(self, tool_id, tool_version=None): |
the order seems to get lost. Any suggestions where I could dig?
3a5d621
to
7543b91
Compare
Got it. Problem seems to be that galaxy/lib/galaxy/web/framework/decorators.py Line 323 in 7543b91
galaxy/lib/galaxy/web/framework/decorators.py Line 297 in 7543b91
Curious if this causes tests to fail... One could add a tests with wrong element order ... ? We should add docs here if this gets accepted https://docs.galaxyproject.org/en/master/dev/schema.html#tool-tests-test-output-collection |
@@ -326,7 +326,7 @@ def format_return_as_json(rval, jsonp_callback=None, pretty=False): | |||
|
|||
Use `pretty=True` to return pretty printed json. | |||
""" | |||
dumps_kwargs = dict(indent=4, sort_keys=True) if pretty else {} | |||
dumps_kwargs = dict(indent=4) if pretty else {} |
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 should do this until we sunset python 3.5. You could add the index of the element here and then sort the test elements where needed. Do you maybe want to just add the xsd changes in for 20.05 ?
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.
Your are probably right -- even if it seems safe in most places where format_return_as_json
is used (pretty is either set to False
or set to True
only in debug mode).
The only place where its True
is here:
return format_return_as_json(ret_dict, pretty=True) |
An alternative might be to add another parameter (e.g. sort_keys=False
) to format_return_as_json
. Tell me your preference and I will go ahead :)
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'd go with the xsd changes only, but if you want to dig deeper I think that adding the index of the element to the test definition seems more solid to me.
Done :) Also changed the text of the Exception to something like:
before the complete dict for the tool generated collection elements was dumped .. For me there was never any information of interest except for the IDs. Do you think this is OK. |
Still, for |
template = "Failed to find identifier [%s] for testing, tool generated collection elements [%s]" | ||
message = template % (element_identifier, element_objects) | ||
if element is None: | ||
template = "Failed to find identifier '%s' of test collection %s in the tool generated collection elements %s (at the correct position)" |
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.
Isn't the corrent position
i
?
Is the correct position the index of the iteration over sorted_test_ids ?
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.
and wouldn't this mean you can simplify the logic to
for element_index, expected_element_identifier in enumerate(sorted_test_ids):
assert element_objects[element_index]["element_identifier"] == expected_element_identifier
?
(You could add some length handling for missing elements)
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.
No, the test is just checking if the elements listed in the test occur in the same order in the generated elements.
Thereby the tool author does not need to list all elements (which might be very many).
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.
Alright, then how about this:
for element_index, expected_element_identifier in enumerate(sorted_test_ids):
if expected_element_identifier is None:
break
assert element_objects[element_index]["element_identifier"] == expected_element_identifier
That way it's clear at which position the test data differs, and I think the logic is a bit easier to follow ?
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 see why this should work :( ..
The None
entries from here:
sorted_test_ids = [None] * len(element_tests) |
should all be overwritten by the actual identifiers. I only use [None] * len(element_tests)
to initialize a list of the needed length.
I extended the test in order to clarify what I meant. The tool new generates 10 elements, but the test only uses three of them to verify the sorting order. The number of generated elements is tested with the count
attribute.
Formally spoken we test if the list of elements in the test is a subsequence of the generated elements.
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.
what is element_tests ? Is that not the list of specified tests?
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.
Its a dict
, looking like this
{'1': [None, {'assert_list': [{'attributes': {'expression': '^.*$'}, 'children': [], 'tag': 'has_text_matching'}], 'checksum': None, 'compare': 'diff', 'decompress': False, 'delta': 10000, 'delta_frac': None, 'element_index': 0, 'elements': {}, 'extra_files': [], 'lines_diff': 0, 'md5': None, 'metadata': {}, 'primary_datasets': {}, 'sort': False}], '10': [None, {'assert_list': [{'attributes': {'expression': '^.*$'}, 'children': [], 'tag': 'has_text_matching'}], 'checksum': None, 'compare': 'diff', 'decompress': False, 'delta': 10000, 'delta_frac': None, 'element_index': 2, 'elements': {}, 'extra_files': [], 'lines_diff': 0, 'md5': None, 'metadata': {}, 'primary_datasets': {}, 'sort': False}], '2': [None, {'assert_list': [{'attributes': {'expression': '^.*$'}, 'children': [], 'tag': 'has_text_matching'}], 'checksum': None, 'compare': 'diff', 'decompress': False, 'delta': 10000, 'delta_frac': None, 'element_index': 1, 'elements': {}, 'extra_files': [], 'lines_diff': 0, 'md5': None, 'metadata': {}, 'primary_datasets': {}, 'sort': False}]}
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.
Maybe calling it element_index is a bad idea if it isn't expected to match the actual element index. Something like expected_order_index maybe would be better?
I don't really have the throughput to deal with this, but maybe this change requiring the order to match should be hidden behind a profile version tag for the tool? If there wasn't a ton of tool breakage maybe it is not worth the effort, I will just update Planemo regardless.
- order of sort_comp and sort_by was wrong for sort_by in collections - sort_by was missing for data output - adds a test (though we can't check the generated order .. I manually tested with `planemo serve`)
by adding an element_index attribute to the element attributes. background: test collection elements were sorted alphabetically because: 1 they are stored in a dict which is unsorted in py<3.6 2 galaxy.web.framework.format_return_as_json dumps this dict to json with sort_keys=True (at least in debug mode which affects planemo t) dropping 2 would be sufficient for py>=3.6, since the test collection elements would be stored in insertion order in the dict.
2f72455
to
8b94088
Compare
create more elements, but still list only 3 in the test
That's definitely a nice improvement, thanks a lot @bernt-matthias! |
element_attrib = dict(element.attrib) | ||
identifier = element_attrib.pop('name', None) | ||
if identifier is None: | ||
raise Exception("Test primary dataset does not have a 'identifier'") | ||
element_tests[identifier] = __parse_test_attributes(element, element_attrib, parse_elements=True) | ||
element_tests[identifier][1]["element_index"] = idx |
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 breaks YAML parsing because the general interface assumes this is here but only the XML parser adds it. This would break CWL tools, YAML tools, and Galaxy workflows (this last one breaks Planemo CI after this was published). So I'm going to refactor this addition into TestCollectionOutputDef - it will just make sure this is populated there. I hope that makes sense.
I think my issues are addressed in https://github.com/galaxyproject/galaxy/pull/10434/files. What do y'all think about that approach? Sorry for not catching this sooner. |
Since
planemo lint
failed so far for this attribute we can be quite sure that this was never used (in a tool)planemo serve
)follow up on #9674