11from contextlib import ExitStack
22from collections .abc import Callable
3- from dataclasses import dataclass
3+ from dataclasses import dataclass , field
44from functools import partial
55from math import ceil , log2
66from pathlib import Path
@@ -31,6 +31,9 @@ def nil_search_log(*_: str):
3131
3232@dataclass (frozen = True )
3333class SearchConfig :
34+ # NB: All defaults here are not guaranteed to match the command line
35+ # interface defaults, they are for python interface convience only
36+
3437 # Position args
3538 fasta_filepaths : list [Path ]
3639 fmindex_filepaths : list [Path ]
@@ -39,22 +42,25 @@ class SearchConfig:
3942 kmer_lengths : list [int ]
4043 is_binary_search : bool
4144
42- use_reverse_complement : bool
43- output_directory : Path
45+ use_reverse_complement : bool = True
46+ output_directory : Path = Path . cwd ()
4447
45- include_sequence_ids : list [bytes ]
46- exclude_sequence_ids : list [bytes ]
48+ # NB: Cannot assign mutable default arguments since they would be shared
49+ # between instances so we must use default_factory to create a new list
50+ # for each instance when using a frozen dataclass
51+ include_sequence_ids : list [bytes ] = field (default_factory = list )
52+ exclude_sequence_ids : list [bytes ] = field (default_factory = list )
4753
4854 # Performance arguments
49- num_threads : int
50- kmer_batch_size : int
51- initial_search_length : int
55+ num_threads : int = 1
56+ kmer_batch_size : int = 1000000
57+ initial_search_length : int = 0 # NB: default of none
5258
5359 # Verbosity
5460 # NB: Only used when additional calculations are needed for logging
55- verbose : bool
56- # Logging function
57- log : Callable [[str ], None ]
61+ verbose : bool = False
62+ # Logging function (initialzed based on verbosity)
63+ log : Callable [[str ], None ] = field ( init = False )
5864
5965 @classmethod
6066 def from_args (cls , args ):
@@ -154,11 +160,6 @@ def from_args(cls, args):
154160 [s .encode () for s in
155161 exclude_sequences_arg .split (SEQUENCE_ID_SEPARATOR )]
156162
157- if args .verbose :
158- logging_function = partial (verbose_print , True )
159- else :
160- logging_function = nil_search_log
161-
162163 return cls (
163164 # Position args
164165 fasta_filepaths = fasta_filenames ,
@@ -174,7 +175,6 @@ def from_args(cls, args):
174175 include_sequence_ids = include_sequence_ids ,
175176 exclude_sequence_ids = exclude_sequence_ids ,
176177
177- log = logging_function ,
178178 verbose = args .verbose ,
179179
180180 # Performance arguments
@@ -183,6 +183,16 @@ def from_args(cls, args):
183183 initial_search_length = initial_search_length
184184 )
185185
186+ def __post_init__ (self ):
187+ # Setup logging based on verbosity
188+ if self .verbose :
189+ logging_function = partial (verbose_print , True )
190+ else :
191+ logging_function = nil_search_log
192+
193+ # Set attribute on the object since the dataclass is frozen
194+ object .__setattr__ (self , "log" , logging_function )
195+
186196
187197def write_unique_counts (config : SearchConfig ):
188198
0 commit comments