From f577022b0f6407079759cd99b71b432d6a864313 Mon Sep 17 00:00:00 2001 From: agavriil Date: Wed, 19 Aug 2026 17:57:08 +0200 Subject: [PATCH 1/3] fixed arguments --- src/foldtree/pyfoldtree.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/foldtree/pyfoldtree.py b/src/foldtree/pyfoldtree.py index fe82d08..ece6df4 100644 --- a/src/foldtree/pyfoldtree.py +++ b/src/foldtree/pyfoldtree.py @@ -49,7 +49,7 @@ def structblob2tree(input_folder, outfolder, overwrite = False, alnres = foldseek2tree.runFoldseek_allvall_EZsearch(input_folder , outfolder + 'res.m8', foldseekpath = foldseekpath) if core == True: - corecut.extract_core( alnres , resdf+'.core.csv', hitthresh = .8 ,minthresh = .6, corefolder = input_folder+'core_structs/' , structfolder = input_folder ) + corecut.extract_core( alnres , outfolder+'.core.csv', hitthresh = .8 ,minthresh = .6, corefolder = input_folder+'core_structs/' , structfolder = input_folder ) if os.path.exists(outfolder + 'res.m8') and overwrite == False: print('found foldseek core output, skipping foldseek') alnres = outfolder + 'core.res.m8' @@ -92,29 +92,29 @@ def structblob2tree(input_folder, outfolder, overwrite = False, trees[k] = out_tree return alnres, trees -if __name__ == '__main__': +def main(): parser = argparse.ArgumentParser(description='run foldtree pipeline for a folder of pdb files') parser.add_argument('struct_dir', help='path to folder with pdb files') parser.add_argument('output_dir', help='output directory') - parser.add_argument('--corecut', help='cut the core of the proteins and realign') + parser.add_argument('--corecut', action='store_true', help='cut the core of the proteins and realign') parser.add_argument('--kernel', choices = ['lddt', 'fident', 'tmalign' ] , default = 'fident', help='this is the comparison metric used to build the tree') parser.add_argument('--fastmepath', default='fastme', help='path to fastme binary') parser.add_argument('--quicktreepath', default='quicktree', help='path to quicktree binary') - parser.add_argument('--foldseekpath', default='../foldseek/foldseek', help='path to foldseek binary') + parser.add_argument('--foldseekpath', default='foldseek', help='path to foldseek binary') parser.add_argument('--delta', default=0.0001, help='small number to replace negative branch lengths with') parser.add_argument('--correction', help='use the -ln correction for the distance matrix') parser.add_argument('--overwrite', help='overwrite existing foldseek output') - parser.add_argument( 'hittresh', default = .8, help='threshold for finding the boundaries of the core') - parser.add_argument( 'minthresh', default = .6, help='threshold if the core is not found') + parser.add_argument( '--hittresh', default = .8, help='threshold for finding the boundaries of the core') + parser.add_argument( '--minthresh', default = .6, help='threshold if the core is not found') args = parser.parse_args() - if not all([args.positional1, args.positional2]): + if not all([args.struct_dir, args.output_dir]): parser.error("Positional arguments are required.") flag_dict = {} - flag_dict['corecut'] = True if args.corecut else False + flag_dict['core'] = args.corecut flag_dict['hittresh'] = args.hittresh flag_dict['minthresh'] = args.minthresh flag_dict['correction'] = True if args.correction else False @@ -129,4 +129,5 @@ def structblob2tree(input_folder, outfolder, overwrite = False, print('Done!') - +if __name__ == '__main__': + main() From abd33dc8d43231dd2eb765f9940a5c0c6eeb45e5 Mon Sep 17 00:00:00 2001 From: agavriil Date: Thu, 20 Aug 2026 11:35:40 +0200 Subject: [PATCH 2/3] tried minimal fixes for pyfoldtree --- src/foldtree/corecut.py | 6 +++--- src/foldtree/pyfoldtree.py | 27 ++++++++++++++++++--------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/foldtree/corecut.py b/src/foldtree/corecut.py index daf6199..38c2a25 100644 --- a/src/foldtree/corecut.py +++ b/src/foldtree/corecut.py @@ -22,8 +22,8 @@ def extract_core(resdf , outfile, hitthresh = .8 ,minthresh = .6, corefolder = """ - #read all results - folder =''.join([ sub + '/' for sub in resdf.split('/')[:-1] ]) + # read all results + folder = os.path.dirname(resdf) print(folder) resdf = pd.read_table(resdf, header = None) resdf.columns = 'query,target,fident,alnlen,mismatch,gapopen,qstart,qend,tstart,tend,evalue,bits,lddt,lddtfull,alntmscore'.split(',') @@ -75,7 +75,7 @@ def extract_core(resdf , outfile, hitthresh = .8 ,minthresh = .6, corefolder = if '/' in q: qfile = qfile.split('/')[-1] - struct = parser.get_structure(q.split('.')[0], folder+structfolder+qfile ) + struct = parser.get_structure(q.split('.')[0], os.path.join(structfolder, qfile)) #zero based indexing... struct_core = Bio.PDB.Dice.extract( struct ,'A' , hits[q]['min']+1 , hits[q]['max']+1 ,folder+corefolder+qfile ) diff --git a/src/foldtree/pyfoldtree.py b/src/foldtree/pyfoldtree.py index ece6df4..a05a506 100644 --- a/src/foldtree/pyfoldtree.py +++ b/src/foldtree/pyfoldtree.py @@ -10,6 +10,7 @@ import numpy as np import pandas as pd import os +import shutil def structblob2tree(input_folder, outfolder, overwrite = False, fastmepath = 'fastme', quicktreepath = 'quicktree' , @@ -41,20 +42,28 @@ def structblob2tree(input_folder, outfolder, overwrite = False, kernel to use, either 'fident', 'lddt' or 'alntmscore' ''' + if shutil.which(fastmepath) is None: + raise RuntimeError( + f"FastME executable '{fastmepath}' was not found. " + "FastME is required to run pyfoldtree. " + "Install it or provide its location with --fastmepath." + ) + os.makedirs(outfolder, exist_ok=True) + #check if the foldseek output is already there - if os.path.exists(outfolder + 'res.m8') and overwrite == False: + if os.path.exists(os.path.join(outfolder, 'res.m8')) and overwrite == False: print('found foldseek output, skipping foldseek') - alnres = outfolder + 'res.m8' + alnres = os.path.join(outfolder, 'res.m8') else: - alnres = foldseek2tree.runFoldseek_allvall_EZsearch(input_folder , outfolder + 'res.m8', foldseekpath = foldseekpath) + alnres = foldseek2tree.runFoldseek_allvall_EZsearch(input_folder , os.path.join(outfolder, 'res.m8'), foldseekpath = foldseekpath) if core == True: corecut.extract_core( alnres , outfolder+'.core.csv', hitthresh = .8 ,minthresh = .6, corefolder = input_folder+'core_structs/' , structfolder = input_folder ) - if os.path.exists(outfolder + 'res.m8') and overwrite == False: + if os.path.exists(os.path.join(outfolder, 'core.res.m8')) and overwrite == False: print('found foldseek core output, skipping foldseek') - alnres = outfolder + 'core.res.m8' + alnres = os.path.join(outfolder, 'core.res.m8') else: - alnres = foldseek2tree.runFoldseek_allvall_EZsearch(input_folder , outfolder + 'core.res.m8', foldseekpath = foldseekpath) + alnres = foldseek2tree.runFoldseek_allvall_EZsearch(input_folder , os.path.join(outfolder, 'core.res.m8'), foldseekpath = foldseekpath) res = pd.read_table(alnres , header = None ) res[0] = res[0].map(lambda x :x.replace('.pdb', '')) @@ -85,10 +94,10 @@ def structblob2tree(input_folder, outfolder, overwrite = False, else: factor = 1 matrices[k] = Tajima_dist(matrices[k], factor = factor) - np.save( input_folder + k + '_distmat.npy' , matrices[k]) - distmat_txt = foldseek2tree.distmat_to_txt( ids , matrices[k] , outfolder + k + '_distmat.txt' ) + np.save(os.path.join(input_folder, k + '_distmat.npy'), matrices[k]) + distmat_txt = foldseek2tree.distmat_to_txt( ids , matrices[k] , os.path.join(outfolder, k + '_distmat.txt')) out_tree = foldseek2tree.runFastme( fastmepath = fastmepath , clusterfile = distmat_txt ) - out_tree = foldseek2tree.postprocess(out_tree, input_folder + 'structblob_tree.nwk' , delta = delta) + out_tree = foldseek2tree.postprocess(out_tree, os.path.join(input_folder, 'structblob_tree.nwk') , delta = delta) trees[k] = out_tree return alnres, trees From dbdeda8dd67beaf7a85bc82b6e8b59ce08a01088 Mon Sep 17 00:00:00 2001 From: agavriil Date: Thu, 20 Aug 2026 12:05:44 +0200 Subject: [PATCH 3/3] fixed correction and Tajima_dist call --- src/foldtree/pyfoldtree.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/foldtree/pyfoldtree.py b/src/foldtree/pyfoldtree.py index a05a506..14068a5 100644 --- a/src/foldtree/pyfoldtree.py +++ b/src/foldtree/pyfoldtree.py @@ -16,7 +16,7 @@ def structblob2tree(input_folder, outfolder, overwrite = False, fastmepath = 'fastme', quicktreepath = 'quicktree' , foldseekpath = 'foldseek' , delta = 0.0001 , correction = False , kernel = 'fident' , core = False - , hittresh = .8 , minthresh = .6): + , hitthresh = .8 , minthresh = .6): ''' run fold tree pipeline for a folder of pdb files @@ -58,7 +58,7 @@ def structblob2tree(input_folder, outfolder, overwrite = False, alnres = foldseek2tree.runFoldseek_allvall_EZsearch(input_folder , os.path.join(outfolder, 'res.m8'), foldseekpath = foldseekpath) if core == True: - corecut.extract_core( alnres , outfolder+'.core.csv', hitthresh = .8 ,minthresh = .6, corefolder = input_folder+'core_structs/' , structfolder = input_folder ) + corecut.extract_core( alnres , outfolder+'.core.csv', hitthresh = hitthresh ,minthresh = minthresh, corefolder = input_folder+'core_structs/' , structfolder = input_folder ) if os.path.exists(os.path.join(outfolder, 'core.res.m8')) and overwrite == False: print('found foldseek core output, skipping foldseek') alnres = os.path.join(outfolder, 'core.res.m8') @@ -93,7 +93,7 @@ def structblob2tree(input_folder, outfolder, overwrite = False, factor = .93 else: factor = 1 - matrices[k] = Tajima_dist(matrices[k], factor = factor) + matrices[k] = foldseek2tree.Tajima_dist(matrices[k], bfactor = factor) np.save(os.path.join(input_folder, k + '_distmat.npy'), matrices[k]) distmat_txt = foldseek2tree.distmat_to_txt( ids , matrices[k] , os.path.join(outfolder, k + '_distmat.txt')) out_tree = foldseek2tree.runFastme( fastmepath = fastmepath , clusterfile = distmat_txt ) @@ -113,9 +113,9 @@ def main(): parser.add_argument('--quicktreepath', default='quicktree', help='path to quicktree binary') parser.add_argument('--foldseekpath', default='foldseek', help='path to foldseek binary') parser.add_argument('--delta', default=0.0001, help='small number to replace negative branch lengths with') - parser.add_argument('--correction', help='use the -ln correction for the distance matrix') + parser.add_argument('--correction', action='store_true', help='use the -ln correction for the distance matrix') parser.add_argument('--overwrite', help='overwrite existing foldseek output') - parser.add_argument( '--hittresh', default = .8, help='threshold for finding the boundaries of the core') + parser.add_argument( '--hitthresh', default = .8, help='threshold for finding the boundaries of the core') parser.add_argument( '--minthresh', default = .6, help='threshold if the core is not found') args = parser.parse_args() @@ -124,7 +124,7 @@ def main(): parser.error("Positional arguments are required.") flag_dict = {} flag_dict['core'] = args.corecut - flag_dict['hittresh'] = args.hittresh + flag_dict['hitthresh'] = args.hitthresh flag_dict['minthresh'] = args.minthresh flag_dict['correction'] = True if args.correction else False flag_dict['overwrite'] = True if args.overwrite else False