Skip to content
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

added support for __asdf_traverse__ method to allow custom introspect… #1052

Merged
merged 8 commits into from
Jan 26, 2022

Conversation

perrygreenfield
Copy link
Contributor

This PR allows the asdf info functionality to check tag classes for a method asdf_traverse. If that method exists, then it is called whereupon it should return information that the info method expects. This allows any tag class to present information about its contents to the info method.

The original purpose was to allow Roman data files to be displayed just like JWST files, which previously wasn't possible since the Roman asdf tree uses tag classes unlike the JWST tree. Roman_datamodels has been correspondingly updated to take advantage of this new capability.

Copy link
Contributor

@eslavich eslavich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, that turned out nice and tidy! Can you add a brief section to readthedocs too?

asdf/_display.py Outdated
@@ -1,5 +1,11 @@
"""
Utilities for displaying the content of an ASDF tree.

Normally these tools only will introspect dicts, lists, and primative values
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

primative --> primitive

asdf/_display.py Outdated
@@ -1,5 +1,11 @@
"""
Utilities for displaying the content of an ASDF tree.

Normally these tools only will introspect dicts, lists, and primative values
(with an exception for arrays). However, if the objecct that is generated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

objecct --> object

asdf/_display.py Outdated
@@ -114,6 +125,15 @@ def __init__(
self.recursive = recursive
self.visible = visible
self.children = []
self.tag = tag

def supports_info(node):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is being called as a class method up above, but it's not decorated as such and doesn't have a cls argument. On the other hand, it seems to be working...

asdf/_display.py Outdated
@@ -105,7 +115,8 @@ def from_root_node(cls, root_identifier, root_node):
return root_info

def __init__(
self, parent, identifier, node, depth, recursive=False, visible=True
self, parent, identifier, node, depth, recursive=False, visible=True,
tag=None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this new tag argument?

@perrygreenfield
Copy link
Contributor Author

I believe I addressed the comments

@CagtayFabry
Copy link
Contributor

this functionality is great, looking forward to giving it a try, thanks @perrygreenfield !

Copy link
Contributor

@WilliamJamieson WilliamJamieson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems good to me.

asdf/_display.py Outdated
next_nodes.append((info, child_identifier, child_node))
if cls.supports_info(node):
info.tag = node._tag
for child_identifier, child_node in node.__asdf_traverse__():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something I missed before, if we call get_children on the result of __asdf_traverse__, that will allow __asdf_traverse__ to return a dict and have it processed correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean here, particularly with if we call get_children on the result. Doesn't __asdf_traverse__ return the same kind of result that get_children does? I may be slow this morning. It is Wednesday.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way this is set up currently, the __asdf_traverse__ method must return dict.items() if it wants to provide dict items, and enumerate(list) if it wants to provide list items. If we instead call get_children(__asdf_traverse__()) here, then __asdf_traverse__ can return simple dict or list and have everything work correctly (get_children will take care of calling .items() on the dict and wrapping the list in enumerate).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, now I understand. I didn't realize you wanted to change what __asdf_traverse__ should return, I'll make the corresponding changes. It would be a simpler requirement on the method.

self._tag = "foo"

def __asdf_traverse__(self):
return list({'the_meaning_of_life_the_universe_and_everything': 42,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add get_children above, we can return a dict here


If the object produced by the extension supports a class method
`.__asdf_traverse__` then it can be used by those tools to expose the contents
of the object. That method should accept no arguments and return a list.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention dict here if you decide to support that

Copy link
Contributor

@eslavich eslavich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants