Turn your functions into composable apps#

Just use the define_app decorator! This generates a wrapper class that has a reference to your function and can then become part of a composed function.

You need two things:

  1. your function

  2. Type hints on the function first argument and the function return type.

Note

At present, your function can have only one required argument.

Supported cogent3 types#

If you function takes or returns cogent3 types, you can use the existing type hints. To see what these are, use the defined_types() function.

from cogent3.app.typing import defined_types

defined_types()
To use a type hint, from cogent3.app import typing
An app which uses one of these hints is compatible with the indicated types.
type hintincludes
AlignedSeqsTypeArrayAlignment, Alignment
UnalignedSeqsTypeSequenceCollection
SeqsCollectionTypeArrayAlignment, SequenceCollection, Alignment
SeqTypeSequence, ProteinWithStopSequence, DnaSequence, RnaSequence, ByteSequence, ProteinSequence
PairwiseDistanceTypeDistanceMatrix
TabularTypeDictArray, DistanceMatrix, Table
TreeTypeTreeNode, PhyloNode
SerialisableTypeSerialisableType
BootstrapResultTypebootstrap_result
HypothesisResultTypehypothesis_result
ModelCollectionResultTypemodel_collection_result
ModelResultTypemodel_result
TabularResultTypetabular_result
GenericResultTypegeneric_result
ResultTypetabular_result, bootstrap_result, generic_result, hypothesis_result, model_result
IdentifierTypeIdentifierType

Note

You don’t have to use cogent3 types, you can also use standard python types.

A simple example#

Let’s make an app that returns the elements of an alignment up to a specified index, with the index being a keyword argument. We now define a decorated function up_to and import the type hints and the decorator.

from cogent3.app.composable import define_app
from cogent3.app.typing import AlignedSeqsType

@define_app
def up_to(val: AlignedSeqsType, index=2) -> AlignedSeqsType:
    return val[:index]

We create an app instance for a specific value of index

first4 = up_to(index=4)
first4
up_to(index=4)

The repr() of the instance indicates the wrapped function and the module it’s in.

You use first4() like all composable apps, e.g.

from cogent3 import make_aligned_seqs

aln = make_aligned_seqs(
    data=dict(a="GCAAGCGTTTAT", b="GCTTTTGTCAAT"), array_align=False, moltype="dna"
)
result = first4(aln)
result
0
aGCAA
b..TT

2 x 4 dna alignment

Renaming sequences#

This time we wrap a method call on a SequenceCollection (and the alignment sub-classes) for renaming sequences. We also illustrate here that to support both aligned and unaligned data types as input/output, we have to include these in the construction of the custom function.

Note

The SerialisableType indicates the data has the ability to be converted to json.

from typing import Union

from cogent3.app.composable import define_app
from cogent3.app.typing import SeqsCollectionType, SerialisableType

T = Union[SeqsCollectionType, SerialisableType]

@define_app
def rename_seqs(seqs: SeqsCollectionType) -> T:
    """upper case names"""
    return seqs.rename_seqs(lambda x: x.upper())

renamer = rename_seqs()
result = renamer(aln)
result
0
AGCAAGCGTTTAT
B..TTTT..CA..

2 x 12 dna alignment

A user app with a different output type#

In this example, we make a function that returns a DistanceMatrix from an alignment.

from cogent3.app.composable import define_app
from cogent3.app.typing import AlignedSeqsType, PairwiseDistanceType

@define_app
def get_dists(aln: AlignedSeqsType, calc="hamming") -> PairwiseDistanceType:
    return aln.distance_matrix(calc=calc, show_progress=False)

percent_dist = get_dists(calc="pdist")
result = percent_dist(aln)
result
namesab
a0.00000.5000
b0.50000.0000