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

Changes needed to support info and search methods on roman_datamodels #997

Closed
wants to merge 2 commits into from

Conversation

perrygreenfield
Copy link
Contributor

Since roman_datamodels has nodes that are dict and list like, but not actually dicts and lists, the asdf info and search machinery will not work with them. These changes allow use of any Mapping and MutableSequence classes in their place, allowing the functionality to extend to roman_datamodels.

One test fails, but seems unrelated to this.

Not sure how to handles supposed changes to asdf-standard.

And I see my editor has done some PEP 8 reformatting. Sigh.

@perrygreenfield perrygreenfield requested a review from eslavich May 20, 2021 20:49
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.

The asdf-standard diff is what's causing the test to fail and can be fixed like this:

git checkout master -- asdf-standard
git commit -m "Revert change to asdf-standard pointer"

@@ -365,11 +370,11 @@ def _handle_immutable_sequence(node, json_id):
return result

def _handle_children(node, json_id):
if isinstance(node, dict):
if isinstance(node, Mapping):
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not safe to change this to match any Mapping or MutableSequence, since walk_and_modify relies on being able to construct a new instance of the container with no arguments. For example, a tree containing an equivalency fails because Equivalency.__init__ has a required argument:

import asdf
from astropy.units import equivalencies

tree = {"equiv": equivalencies.spectral()}
asdf.treeutil.walk_and_modify(tree, lambda n: n)
TypeError: __init__() missing 1 required positional argument: 'equiv_list'

@@ -82,8 +83,9 @@ def from_root_node(cls, root_identifier, root_node):
next_nodes = []

for parent, identifier, node in current_nodes:
if (isinstance(node, dict) or isinstance(node, list) or isinstance(node, tuple)) and id(node) in seen:
info = _NodeInfo(parent, identifier, node, current_depth, recursive=True)
if (isinstance(node, Mapping) or isinstance(node, MutableSequence) or isinstance(node, tuple)) and id(node) in seen:
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm starting to have some reservations about crawling all subclasses of Mapping and MutableSequence. I assume we're skipping Sequence here because that would match strings -- are there other types that will end up being similarly inconvenient to have split into separate nodes in the info display?

What do you think about having the user or the extension opt in each traversable class? On an extension that might look something like:

class SomeExtension:
  traversable_types = [
    "roman_datamodels.stnode.DNode",
    "roman_datamodels.stnode.LNode",
  ]

Copy link
Contributor

Choose a reason for hiding this comment

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

Alternatively we could create a marker interface, something like:

class AsdfTraversable:
  pass

and include that among DNode and LNode's parent classes:

from asdf.extension import AsdfTraversable

class DNode(UserList, AsdfTraversable):
  # blah blah

I like that better from an implementation point of view, but an extension author wouldn't be able to mark classes that they don't control.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Belatedly, I don't see that as a problem normally. It's needed here since we are building a tree of objects, and if someone else has a similar need, they can use a similar solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I try to sweep the cobwebs away on this one. Is there any reason that DNode and LNode shouldn't automatically be traversed?

As for other possibly traversable objects, we could have such objects provide a method to return whatever structure they think appropriate for their contents. Any reason not to let them control that completely? The transversing code checks for the presence of such a method, and if it exists, calls it. Should there be reference objects within that also support that interface, they can also be called, recursively. I suppose we could use this for DNode and LNodes as a uniform interface.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the idea of a method, __asdf_traverse__?

Copy link
Contributor

@eslavich eslavich Jan 11, 2022

Choose a reason for hiding this comment

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

But how to handle classes that are implemented by a 3rd party and not necessarily modifiable by asdf developers or the extension author?

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, I'll give it a try. That seems like a good name. I was going to go with __asdf_the_doors_open_so_come_in_and_look_around__ but that might be a hair too long.

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 suppose I should close this and open a new PR. What should I base it off of given all the changes going on?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As for 3rd party classes that don't implement it, tough. They don't want to be introspected, would be the simple answer. Otherwise we could implement a registry of some sort that knows about them and has code to deal with that. But not for this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I recommend branching off of master so that we can release this sooner in a 2.x version.

@ddavis-stsci
Copy link

Hey Perry, is this modification something that might help with the Roman data_models and validation meeting for Thursday. Should we try and discuss this as well?

@perrygreenfield
Copy link
Contributor Author

I'm not sure it helps in the issues that Paul raised. But I prefer Ed's solution to this issue. Normally these utilities stop at anything that is turned into a special object, and since the whole data model is a special object, they will stay opaque to these tools unless we indicate that it should dig deeper.

@perrygreenfield
Copy link
Contributor Author

This has been superseded by #1052

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

Successfully merging this pull request may close these issues.

3 participants