I am writing some python 3 bioinformatics software and was wondering about the best way to write it in an OOP format. I am pretty sure a lot of my classes are violating the SRP principle, but I'm not entirely sure of how to refactor them (partly because they are quite small).
For example, I have a ProcessedInput
class for processing a user input and standardising it for downstream analysis. Presumably this violates the SRP as it would need changes if any of the processing steps needed to change. However, as each step is just a single function, I'm not sure it makes sense to make each one it's own class (FileReader
, FileScraper
, etc). I could pull the methods out into functions and make a standalone function with whats currently contained in the innit
method, but I like having all the functions in the same class as they're all related.
I've used this somewhat procedural class setup in a few classes, so I'd be interested in knowing if it's bad practice. Perhaps it's best to make smaller defined classes - or maybe that's too much abstraction that overly complicates the code?
Thanks! Tim
class ProcessedInput:
def __init__(self, filepath, accession, ignore_pseudo, target_regions):
if filepath != None and accession == None:
self.records = self.read_genbank(filepath)
elif filepath == None and accession != None:
self.records = self.scrape_genbank(5, accession)
else:
raise ValueError(f'Input not recognised - either filepath ({filepath}) or accession ({accession}) must be None')
self.accession = accession
self.filepath = filepath
self.proteins = self.collect_proteins(self.records,
ignore_pseudo)
if target_regions != None:
self.user_specified_proteins = self.filter_proteins(self.proteins,
target_regions)
else:
self.user_specified_proteins = self.proteins
self.record_flags = self.find_flag(self.user_specified_proteins,
flags = ['locus_tag', 'protein_id'])
def read_genbank_file(self, path):
#read path to file object
return file
def scrape_genbank_file(self, number_of_attempts, accession):
#scrape file from public database, handle scrape fail with exception
#read scraped response to file object (same as read_file output)
return file
def collect_proteins(self, file, ignore_pseudo):
#parse file to get proteins of interest for downstream processing - ignore pseudo proteins if desired
return proteins
def filter_proteins(self, proteins, target_regions):
#filter collected proteins to those in specific region of query (e.g. first half of genome)
return filtered_proteins
def find_flag(self, proteins, flags_to_test):
#each protein is associated with metadata, and I need to pick a
#persistent id from that metadata to use as a general protein identifier.
#This tests each flag in flags_to_test to confirm the flag is a field in
#every protein's metadata, and all values associated with the flag are unique
return flags