Repository: cogent3/cogent3
Pull request #1076 (2022-07-04 07:46:06)

ENH: changed default Composable method name to main
[CHANGED] related to #1075, replaced self.func with
    self.main.

This does not fully address the issue, which will require
defining an abstrcat class and method. The challenge to that is
some choices regarding the assignment to self.main are conditioned
on other parameter values.


Patch:
diff --git a/src/cogent3/app/align.py b/src/cogent3/app/align.py
index 3bb6e6d49..e9248e971 100644
--- a/src/cogent3/app/align.py
+++ b/src/cogent3/app/align.py
@@ -376,9 +376,9 @@ class align_to_ref(ComposableSeq):
             S=S, d=insertion_penalty, e=extension_penalty, return_score=False
         )
         if ref_seq.lower() == "longest":
-            self.func = self.align_to_longest
+            self.main = self.align_to_longest
         else:
-            self.func = self.align_to_named_seq
+            self.main = self.align_to_named_seq
             self._ref_name = ref_seq
 
         self._gap_state = None  # can be character or int, depends on aligner
@@ -515,7 +515,7 @@ class progressive_align(ComposableSeq):
             show_progress=False,
         )
 
-        self.func = self.multiple_align
+        self.main = self.multiple_align
 
     def _build_guide(self, seqs):
         tree = self._make_tree(seqs)
diff --git a/src/cogent3/app/composable.py b/src/cogent3/app/composable.py
index 183894a95..d1eb9cf0a 100644
--- a/src/cogent3/app/composable.py
+++ b/src/cogent3/app/composable.py
@@ -172,7 +172,7 @@ class ComposableType:
 class Composable(ComposableType):
     def __init__(self, **kwargs):
         super(Composable, self).__init__(**kwargs)
-        # self.func = None  # over-ride in subclass
+        # self.main = None  # over-ride in subclass
         self._in = None  # input rules
         self._out = None  # rules receiving output
         # rules operating on result but not part of a chain
@@ -302,7 +302,7 @@ class Composable(ComposableType):
 
         if not val:
             return val
-        result = self._trapped_call(self.func, val, *args, **kwargs)
+        result = self._trapped_call(self.main, val, *args, **kwargs)
         if not result and type(result) != NotCompleted:
             msg = (
                 f"The value {result} equates to False. "
@@ -638,7 +638,7 @@ class _checkpointable(Composable):
             data_path, suffix=suffix, create=create, if_exists=if_exists
         )
         self._callback = name_callback
-        self.func = self.write
+        self.main = self.write
 
         # override the following in subclasses
         self._format = None
@@ -706,7 +706,7 @@ class user_function(Composable):
         self._args = args
         self._kwargs = kwargs
 
-    def func(self, *args, **kwargs):
+    def main(self, *args, **kwargs):
         """
         Parameters
         ----------
diff --git a/src/cogent3/app/dist.py b/src/cogent3/app/dist.py
index a7c53db57..0a940a614 100644
--- a/src/cogent3/app/dist.py
+++ b/src/cogent3/app/dist.py
@@ -100,7 +100,7 @@ class fast_slow_dist(ComposableDistance):
         elif slow_calc:
             self._moltype = slow_calc.moltype
         self._sm = slow_calc
-        self.func = self.calc_distance
+        self.main = self.calc_distance
 
     def _est_dist_pair_slow(self, aln):
         """returns distance between seq pairs in aln"""
diff --git a/src/cogent3/app/evo.py b/src/cogent3/app/evo.py
index 33bb05d4c..a821dc326 100644
--- a/src/cogent3/app/evo.py
+++ b/src/cogent3/app/evo.py
@@ -173,7 +173,7 @@ class model(ComposableModel):
         self._param_rules = param_rules
         self._time_het = deepcopy(time_het)
         self._split_codons = split_codons
-        self.func = self.fit
+        self.main = self.fit
 
     def _configure_lf(self, aln, identifier, initialise=None):
         lf = self._sm.make_likelihood_function(self._tree, **self._lf_args)
@@ -357,7 +357,7 @@ class model_collection(ComposableHypothesis):
             raise ValueError(msg)
 
         self._alts = alternates
-        self.func = self.test_hypothesis
+        self.main = self.test_hypothesis
         self._init_alt = init_alt
         self._sequential = sequential
 
@@ -434,7 +434,7 @@ class bootstrap(ComposableHypothesis):
         self._num_reps = num_reps
         self._verbose = verbose
         self._parallel = parallel
-        self.func = self.run
+        self.main = self.run
 
     def _fit_sim(self, rep_num):
         sim_aln = self._null.simulate_alignment()
@@ -485,7 +485,7 @@ class ancestral_states(ComposableTabular):
             data_types=self._data_types,
         )
         self._formatted_params()
-        self.func = self.recon_ancestor
+        self.main = self.recon_ancestor
 
     def recon_ancestor(self, result):
         """returns a tabular_result of posterior probabilities of ancestral states"""
@@ -516,7 +516,7 @@ class tabulate_stats(ComposableTabular):
             data_types=self._data_types,
         )
         self._formatted_params()
-        self.func = self.extract_stats
+        self.main = self.extract_stats
 
     def extract_stats(self, result):
         """returns Table for all statistics returned by likelihood function
@@ -639,7 +639,7 @@ class natsel_neutral(ComposableHypothesis):
         )
         hyp = hypothesis(null, alt)
 
-        self.func = hyp
+        self.main = hyp
 
 
 class natsel_zhang(ComposableHypothesis):
@@ -798,7 +798,7 @@ class natsel_zhang(ComposableHypothesis):
             upper_omega=upper_omega,
         )
 
-        self.func = self.test_hypothesis
+        self.main = self.test_hypothesis
 
     def _get_alt_from_null(self, null):
         rules = null.lf.get_param_rules()
@@ -964,7 +964,7 @@ class natsel_sitehet(ComposableHypothesis):
             upper_omega=upper_omega,
         )
 
-        self.func = self.test_hypothesis
+        self.main = self.test_hypothesis
 
     def _get_alt_from_null(self, null):
         rules = null.lf.get_param_rules()
@@ -1163,4 +1163,4 @@ class natsel_timehet(ComposableHypothesis):
         )
         hyp = hypothesis(null, alt)
 
-        self.func = hyp
+        self.main = hyp
diff --git a/src/cogent3/app/io.py b/src/cogent3/app/io.py
index ceebad018..c1f448e66 100644
--- a/src/cogent3/app/io.py
+++ b/src/cogent3/app/io.py
@@ -181,7 +181,7 @@ def get_data_store(
 
 class _seq_loader:
     def __init__(self):
-        self.func = self.load
+        self.main = self.load
 
     def load(self, path):
         """returns alignment"""
@@ -310,7 +310,7 @@ class load_tabular(ComposableTabular):
         self._with_title = with_title
         self._with_header = with_header
         self._limit = limit
-        self.func = self.load
+        self.main = self.load
         self.strict = strict
         self.as_type = as_type
 
@@ -539,7 +539,7 @@ class load_json(Composable):
         super(load_json, self).__init__(
             input_types=self._input_types, output_types=self._output_types
         )
-        self.func = self.read
+        self.main = self.read
 
     def read(self, path):
         """returns object deserialised from json at path"""
@@ -581,7 +581,7 @@ class write_json(_checkpointable):
             if_exists=if_exists,
             suffix=suffix,
         )
-        self.func = self.write
+        self.main = self.write
 
     def _set_checkpoint_loader(self):
         self._load_checkpoint = self
@@ -627,7 +627,7 @@ class load_db(Composable):
         super(load_db, self).__init__(
             input_types=self._input_types, output_types=self._output_types
         )
-        self.func = self.read
+        self.main = self.read
 
     def read(self, identifier):
         """returns object deserialised from a TinyDb"""
@@ -673,7 +673,7 @@ class write_db(_checkpointable):
             suffix=suffix,
             writer_class=WritableTinyDbDataStore,
         )
-        self.func = self.write
+        self.main = self.write
 
     def _set_checkpoint_loader(self):
         self._load_checkpoint = self
diff --git a/src/cogent3/app/sample.py b/src/cogent3/app/sample.py
index a95732e4b..afbe0ac6b 100644
--- a/src/cogent3/app/sample.py
+++ b/src/cogent3/app/sample.py
@@ -139,7 +139,7 @@ class omit_degenerates(ComposableAligned):
         self._no_degen = omit_degenerates
         self._allow_gap = not gap_is_degen
         self._motif_length = motif_length
-        self.func = self.filter_degenerates
+        self.main = self.filter_degenerates
 
     def filter_degenerates(self, aln):
         if self.moltype and aln.moltype != self.moltype:
@@ -190,7 +190,7 @@ class omit_gap_pos(ComposableAligned):
         self.moltype = moltype
         self._allowed_frac = allowed_frac
         self._motif_length = motif_length
-        self.func = self.omit
+        self.main = self.omit
 
     def omit(self, aln):
         if self.moltype and aln.moltype != self.moltype:
@@ -259,7 +259,7 @@ class take_codon_positions(ComposableAligned):
                 gc, alphabet=moltype.alphabet, as_indices=True
             )
             self._fourfold_degen_sets = sets
-            self.func = self.take_fourfold_positions
+            self.main = self.take_fourfold_positions
             return
 
         assert (
@@ -269,10 +269,10 @@ class take_codon_positions(ComposableAligned):
         by_index = True if len(positions) == 1 else False
         if by_index:
             positions = positions[0] - 1
-            self.func = self.take_codon_position
+            self.main = self.take_codon_position
         else:
             positions = tuple(p - 1 for p in sorted(positions))
-            self.func = self.take_codon_positions
+            self.main = self.take_codon_positions
 
         self._positions = positions
 
@@ -331,7 +331,7 @@ class take_named_seqs(ComposableSeq):
         self._formatted_params()
         self._names = names
         self._negate = negate
-        self.func = self.take_seqs
+        self.main = self.take_seqs
 
     def take_seqs(self, data):
         try:
@@ -387,7 +387,7 @@ class take_n_seqs(ComposableSeq):
         self._number = number
         self._random = random
         self._fixed_choice = fixed_choice
-        self.func = self.take_seqs
+        self.main = self.take_seqs
 
     def _set_names(self, data):
         """set the names attribute"""
@@ -444,7 +444,7 @@ class min_length(ComposableSeq):
             length = length // motif_length
         self._min_length = length
         self._motif_length = motif_length
-        self.func = self.if_long_enough
+        self.main = self.if_long_enough
         self._subtract_degen = subtract_degen
         if moltype:
             moltype = get_moltype(moltype)
@@ -552,7 +552,7 @@ class fixed_length(ComposableAligned):
         if seed:
             np_random.seed(seed)
 
-        self.func = {False: self.truncated}.get(random, self.sample_positions)
+        self.main = {False: self.truncated}.get(random, self.sample_positions)
 
     def truncated(self, aln):
         if self._moltype and self._moltype != aln.moltype:
@@ -631,7 +631,7 @@ class omit_bad_seqs(ComposableAligned):
         self._quantile = quantile
         self._gap_fraction = gap_fraction
         self._moltype = moltype
-        self.func = self.drop_bad_seqs
+        self.main = self.drop_bad_seqs
 
     def drop_bad_seqs(self, aln):
         if self._moltype and self._moltype != aln.moltype:
@@ -686,11 +686,11 @@ class omit_duplicated(ComposableSeq):
 
         self._mask_degen = mask_degen
         if choose == "longest":
-            self.func = self.choose_longest
+            self.main = self.choose_longest
         elif choose == "random":
-            self.func = self.choose_random
+            self.main = self.choose_random
         else:
-            self.func = self.take_unique
+            self.main = self.take_unique
 
     def choose_longest(self, seqs):
         if self._moltype and self._moltype != seqs.moltype:
@@ -761,7 +761,7 @@ class trim_stop_codons(ComposableSeq):
         )
         self._formatted_params()
         self._gc = gc
-        self.func = self.trim_stops
+        self.main = self.trim_stops
 
     def trim_stops(self, data):
         data = data.trim_stop_codons(gc=self._gc)
diff --git a/src/cogent3/app/translate.py b/src/cogent3/app/translate.py
index e4b2a8ae7..a3fb4224c 100644
--- a/src/cogent3/app/translate.py
+++ b/src/cogent3/app/translate.py
@@ -193,7 +193,7 @@ class select_translatable(ComposableSeq):
         self._gc = get_code(gc)
         self._allow_rc = allow_rc
         self._trim_terminal_stop = trim_terminal_stop
-        self.func = self.get_translatable
+        self.main = self.get_translatable
 
     def get_translatable(self, seqs):
         """returns the translatable sequences from seqs.
@@ -272,7 +272,7 @@ class translate_seqs(ComposableSeq):
         self._moltype = moltype
         self._gc = get_code(gc)
         self._trim_terminal_stop = trim_terminal_stop
-        self.func = self.get_translated
+        self.main = self.get_translated
 
     def get_translated(self, seqs):
         """returns translated sequences"""
diff --git a/src/cogent3/app/tree.py b/src/cogent3/app/tree.py
index 7e566ef20..ed9ffd621 100644
--- a/src/cogent3/app/tree.py
+++ b/src/cogent3/app/tree.py
@@ -55,7 +55,7 @@ class scale_branches(ComposableTree):
 
         self._scalar = scalar
         self._min_length = min_length
-        self.func = self._scale_lengths
+        self.main = self._scale_lengths
 
     def _scale_lengths(self, tree):
         scalar = self._scalar
@@ -97,7 +97,7 @@ class uniformize_tree(ComposableTree):
         self._formatted_params()
         self._root_at = root_at
         self._ordered_names = ordered_names
-        self.func = self._uniformize
+        self.main = self._uniformize
 
     def _uniformize(self, tree):
         if self._root_at == "midpoint":
@@ -135,7 +135,7 @@ class quick_tree(ComposableTree):
             data_types=self._data_types,
         )
         self._formatted_params()
-        self.func = self.quick_tree
+        self.main = self.quick_tree
         self._drop_invalid = drop_invalid
 
     def quick_tree(self, dists):


Test patch:
diff --git a/tests/test_app/test_composable.py b/tests/test_app/test_composable.py
index 692b5e573..82865172d 100644
--- a/tests/test_app/test_composable.py
+++ b/tests/test_app/test_composable.py
@@ -346,7 +346,7 @@ class TestPicklable(TestCase):
         from cogent3.app import io
 
         read = io.load_aligned(moltype="dna")
-        read.func = lambda x: None
+        read.main = lambda x: None
         got = read("somepath.fasta")
         self.assertIsInstance(got, NotCompleted)
         self.assertEqual(got.type, "BUG")