Transformers¶
Transformers
are functions for converting Semantic Type objects into other formats that can be consumed by python functions. These transformers are typically defined along with the Semantic Types
for which they are designed, and q2-types
provides a number of common Types
and their transformers. Plugins often define new semantic types and/or transformers that are not covered by these core Types
.
How are transformers used by a plugin?¶
Transformers
are not called directly at any time within a plugin. This process is handled by the QIIME 2 framework, as long as the appropriate transformers
are registered in that plugin. The framework interprets the input Artifact source format and destination format from a plugin
’s registration and functional annotation, respectively. Upon output from a Method, the framework interprets the source format (function output) and the Semantic Type
of the desination Artifact
from the plugin
functional annotation and registration, respectively.
For example, we can see how functional annotations define input and output formats in q2_diversity.beta_phylogenetic
:
def beta_phylogenetic(table: biom.Table, phylogeny: skbio.TreeNode,
metric: str)-> skbio.DistanceMatrix:
This function requires biom.Table
and skbio.TreeNode
objects as input, and produces an skbio.DistanceMatrix
object as output.
We can examine the first few lines of the Method
registration for this function to determine the Semantic Types
of these input and output objects:
plugin.methods.register_function(
function=q2_diversity.beta_phylogenetic,
inputs={'table': FeatureTable[Frequency],
'phylogeny': Phylogeny[Rooted]},
parameters={'metric': Str % Choices(beta.phylogenetic_metrics())},
outputs=[('distance_matrix', DistanceMatrix % Properties('phylogenetic'))],
So we see that the biom.Table
object begins its life as a FeatureTable[Frequency]
artifact, the skbio.TreeNode
comes from a Phylogeny[Rooted]
artifact, and the output skbio.DistanceMatrix
must somehow be coerced to become a DistanceMatrix[phylogenetic]
artifact. How do we possibly handle this? Before you hyperventilate, remember that the QIIME 2 framework does all conversion for you, provided the appropriate ``transformers` have been registered`.
Registering a Transformer¶
To give you an idea how this works, let’s take a look at how an example transformer
is registered in q2-types
:
import skbio
from ..plugin_setup import plugin
from . import LSMatFormat
@plugin.register_transformer
def _1(data: skbio.DistanceMatrix) -> LSMatFormat:
ff = LSMatFormat()
with ff.open() as fh:
data.write(fh, format='lsmat')
return ff
@plugin.register_transformer
def _2(ff: LSMatFormat) -> skbio.DistanceMatrix:
return skbio.DistanceMatrix.read(str(ff), format='lsmat', verify=False)
These transformers define how an skbio.DistanceMatrix
object is transformed into an LSMatFormat
object (the underlying format of the data in a DistanceMatrix[phylogenetic]
artifact, as defined in q2-types).
So QIIME 2 recognizes (in the function annotation) that it has an incoming skbio.DistanceMatrix
, which it transforms (via the registered Transformer
) to LSMatFormat
and packages into a DistanceMatrix[phylogenetic]
artifact (as defined in the Method
registration). Easy as 🎂.