-
Notifications
You must be signed in to change notification settings - Fork 242
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
adds support for registering descriptions and example imports for artifact classes #655
Conversation
ArtifactClassRecords are now returned by PluginManager.get_semantic_types() as these are more descriptive than SemanticTypeRecords. For backward compatibility, ArtifactClassRecords have values semantic_type and type_expression, which are set to the same value upon creation of ArtifactClassRecords during plugin registration.
Plugin.types returns dict of ArtifactClassRecords instead of SemanticTypeRecords as the former are more descriptive.
Plugin.type_formats was renamed Plugin.artifact_classes for clarity, and a Plugin.type_formats property was added for backward compatibility. PluginManager.type_formats was renamed PluginManager.artifact_classes for clarity, and a PluginManager.type_formats property was added for backward compatibility. Both properties return the corresponding artifact_classes variable
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.
Thanks @gregcaporaso, this all looks good to me, but one thing that I think will simplify a lot of the code would be to turn artifact_classes
into a dictionary keyed by semantic type.
Then anywhere you cared about a list, artifact_classes.values()
would be fine, and the rest of the time, you actually are interested in the semantic type for duplicate checking which would be a key.
qiime2/core/testing/plugin.py
Outdated
|
||
to_import = use.init_format('to_import', factory, ext='.hello') | ||
|
||
ints = use.import_from_format('ints', |
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 linter is upset about these, you can delete the variable assignment and the usage example won't care
def factory(): | ||
from qiime2.core.testing.format import IntSequenceFormat | ||
from qiime2.plugin.util import transform | ||
ff = transform([1, 2, 3], to_type=IntSequenceFormat) |
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 is probably the best use of transform
within a plugin
context I've seen. I always forget this function exists.
qiime2/plugin/plugin.py
Outdated
def type_formats(self): | ||
# self.type_formats was replaced with self.artifact_classes - this | ||
# property provides backward compatibility | ||
return self.artifact_classes |
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.
👍
qiime2/plugin/plugin.py
Outdated
examples = {} | ||
|
||
registered_artifact_classes = \ | ||
set(str(e.type_expression) for e in self.artifact_classes) |
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 may be worth storing on the plugin instance as a private member, as otherwise we'll be constructing this set for each registration, resulting in n^2 iterations through self.artifact_classes.
A good option might be to turn types
into a mappingproxy of an internal dict, then you can simply check against self.types
as things are being constructed.
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.
actually instead of self.types
self.artifact_classes
would be fine I think.
qiime2/plugin/plugin.py
Outdated
@@ -79,7 +83,7 @@ def __init__(self, name, version, website, package=None, project_name=None, | |||
self.views = {} | |||
self.type_fragments = {} | |||
self.transformers = {} | |||
self.type_formats = [] | |||
self.artifact_classes = [] |
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 might be better as a dictionary for some of the registration behavior
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.
Good call - thanks for catching that! Made this change and most of my commit responding to your comments is updates to address this.
qiime2/sdk/plugin_manager.py
Outdated
@@ -201,7 +201,7 @@ def _integrate_plugin(self, plugin): | |||
) | |||
|
|||
self.formats[name] = record | |||
self.type_formats.extend(plugin.type_formats) | |||
self.artifact_classes.extend(plugin.artifact_classes) |
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 was missing originally, but we should do a similar check as the other properties to make sure duplicate registrations (across plugins) are forbidden.
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 added this test and validated that it works manually and reports a useful error message (from my test: ValueError: Duplicate semantic type ('PCoAResults') defined in plugins: 'sapienns' and 'types'
). I didn't see where/if this type of functionality was being unit tested, so I didn't add unit tests for it now.
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.
There's no pleasant way to test for this, so eyeballing it is fine with me.
# Evan, ideally we could just lookup semantic_type in | ||
# self.artifact_classes but properties get in the way. Is there a way | ||
# to strip properties so this could be simplified to return | ||
# self.artifact_classes[semantic_type] while catching a KeyError? |
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.
There's not a global helper for this, but there is a .duplicate()
method which allows you to override attributes of a type, so (SomeType % Foo).duplicate(predicate=IntersectionExp())
would accomplish your goal. It's not pretty and it's also not recursive, so any variant fields would need to be recursively duplicated as well.
The behavior below is correct and the above sounds like too much work. So let's ignore this for now.
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.
Just promoting the comment to a TODO, since it's useful context and asks the kind of question which would necessitate some nicer mechanisms than what I described.
Thanks @gregcaporaso! |
Thanks for the reviews @ebolyen! |
Adds support for registering descriptions and import examples for artifact classes. Artifact class is a new term that we're using to refer to semantic types with a registered directory format. Previously these would be registered with
Plugin.register_semantic_type_to_format
, and that is still possible for backward compatibility. These can also now be registered withPlugin.register_artifact_class
, which optionally takes a description and a dict of usage examples.Addresses #649.