diff --git a/CHEWBBACA/AlleleCall/allele_call.py b/CHEWBBACA/AlleleCall/allele_call.py index 7b2ee065..0673e64b 100644 --- a/CHEWBBACA/AlleleCall/allele_call.py +++ b/CHEWBBACA/AlleleCall/allele_call.py @@ -2762,7 +2762,7 @@ def main(input_file, loci_list, schema_directory, output_directory, # Get list of loci in the schema schema_loci = fo.pickle_loader(fo.join_paths(schema_directory, - [ct.LOCI_LIST_FILE])) + [ct.GENE_LIST_BASENAME])) schema_loci_paths = [fo.join_paths(schema_directory, [file]) for file in schema_loci] @@ -2847,8 +2847,8 @@ def main(input_file, loci_list, schema_directory, output_directory, mo.function_helper, config['CPU cores'], show_progress=False) - novel_alleles_count = sum(len(v) for v in novel_alleles) novel_alleles = im.merge_dictionaries(novel_alleles) + novel_alleles_count = sum(len(v) for k, v in novel_alleles.items()) print(f'Assigned identifiers to {novel_alleles_count} new alleles.') updated_files = {} @@ -3009,9 +3009,9 @@ def main(input_file, loci_list, schema_directory, output_directory, classification_labels) print(f'Classified a total of {total_cds} CDSs.') - class_counts_header = [f'{c:^8}' for c in ct.ALLELECALL_CLASSIFICATIONS] + class_counts_header = [f'{c:^8}' for c in ct.ALLELECALL_CLASSIFICATIONS[:-1]] class_counts_header = ' '.join(class_counts_header) - class_counts_values = [f'{global_counts.get(c, 0):^8}' for c in ct.ALLELECALL_CLASSIFICATIONS] + class_counts_values = [f'{global_counts.get(c, 0):^8}' for c in ct.ALLELECALL_CLASSIFICATIONS[:-1]] class_counts_values = ' '.join(class_counts_values) print('='*len(class_counts_header)) print(class_counts_header) @@ -3020,8 +3020,8 @@ def main(input_file, loci_list, schema_directory, output_directory, print('='*len(class_counts_header)) if no_inferred is False and config['Mode'] != 1 and len(novel_alleles) > 0: - print('Added {0} novel alleles to the schema.'.format(sum(added2))) - print('Added {0} representative alleles to the schema.'.format(added[1])) + print('Added {0} new alleles to the schema.'.format(sum(added2))) + print('Added {0} new representative alleles to the schema.'.format(added[1])) elif no_inferred is True: print('User passed "--no-inferred". No alleles added to the schema.') elif len(novel_alleles) == 0: diff --git a/CHEWBBACA/CHEWBBACA_NS/download_schema.py b/CHEWBBACA/CHEWBBACA_NS/download_schema.py index 2b1fb892..f52f9a80 100755 --- a/CHEWBBACA/CHEWBBACA_NS/download_schema.py +++ b/CHEWBBACA/CHEWBBACA_NS/download_schema.py @@ -531,18 +531,10 @@ def main(species_id, schema_id, download_folder, cpu_cores, fo.remove_files(ns_files) # Write hidden schema config file - del(schema_params_dict['Schema_lock']) - schema_config = pv.write_schema_config(schema_params_dict['bsr'], - ptf_hash, - schema_params_dict['translation_table'], - schema_params_dict['minimum_locus_length'], + schema_params_dict['ptf_path'] = ptf_hash + schema_params_dict['window_size'] = schema_params_dict.get('window_size', None) + schema_config = pv.write_schema_config(schema_params_dict, schema_params_dict['chewBBACA_version'], - schema_params_dict['size_threshold'], - schema_params_dict['word_size'], - schema_params_dict.get('window_size', None), # add window size to chewie-NS - schema_params_dict['cluster_sim'], - schema_params_dict['representative_filter'], - schema_params_dict['intraCluster_filter'], schema_path) # Create ns_config file diff --git a/CHEWBBACA/CHEWBBACA_NS/synchronize_schema.py b/CHEWBBACA/CHEWBBACA_NS/synchronize_schema.py index 3d602022..99bfd011 100755 --- a/CHEWBBACA/CHEWBBACA_NS/synchronize_schema.py +++ b/CHEWBBACA/CHEWBBACA_NS/synchronize_schema.py @@ -761,7 +761,7 @@ def main(schema_directory, cpu_cores, nomenclature_server, headers_post_bytes['Authorization'] = token headers_post_bytes['user_id'] = user_id - schema_params = pv.read_configs(schema_directory, '.schema_config') + schema_params = pv.read_configs(schema_directory, ct.SCHEMA_CONFIG_BASENAME) # verify that local configs have a single value per parameter if all([len(schema_params[k]) == 1 @@ -819,7 +819,7 @@ def main(schema_directory, cpu_cores, nomenclature_server, ''.format(count, len(loci_alleles))) # Get schema files from genes list file - genes_list = fo.join_paths(schema_directory, ['.genes_list']) + genes_list = fo.join_paths(schema_directory, [ct.GENE_LIST_BASENAME]) genes = fo.pickle_loader(genes_list) # update loci structure diff --git a/CHEWBBACA/CHEWBBACA_NS/upload_schema.py b/CHEWBBACA/CHEWBBACA_NS/upload_schema.py index dc045172..cad2400c 100755 --- a/CHEWBBACA/CHEWBBACA_NS/upload_schema.py +++ b/CHEWBBACA/CHEWBBACA_NS/upload_schema.py @@ -969,7 +969,7 @@ def main(schema_directory, species_id, schema_name, loci_prefix, print('Local schema: {0}'.format(schema_directory)) # Get schema files from genes list file - genes_list = os.path.join(schema_directory, '.genes_list') + genes_list = fo.join_paths(schema_directory, [ct.GENE_LIST_BASENAME]) genes = fo.pickle_loader(genes_list) fasta_paths = [os.path.join(schema_directory, file) for file in genes] fasta_paths.sort() @@ -993,7 +993,7 @@ def main(schema_directory, species_id, schema_name, loci_prefix, # Verify schema config print('Verifying schema configs...') # Load schema config file - configs = pv.read_configs(schema_directory, '.schema_config') + configs = pv.read_configs(schema_directory, ct.SCHEMA_CONFIG_BASENAME) # Validate arguments values schema_ptfs = configs['prodigal_training_file'] diff --git a/CHEWBBACA/SchemaEvaluator/evaluate_schema.py b/CHEWBBACA/SchemaEvaluator/evaluate_schema.py index 8ccc95ff..d9d4fd30 100644 --- a/CHEWBBACA/SchemaEvaluator/evaluate_schema.py +++ b/CHEWBBACA/SchemaEvaluator/evaluate_schema.py @@ -577,7 +577,7 @@ def main(schema_directory, output_directory, genes_list, annotations, for file in schema_files} # Check if the schema was created with chewBBACA - config_file = os.path.join(schema_directory, ".schema_config") + config_file = fo.join_paths(schema_directory, [ct.SCHEMA_CONFIG_BASENAME]) if os.path.exists(config_file): # get the schema configs with open(config_file, "rb") as cf: diff --git a/CHEWBBACA/UniprotFinder/annotate_schema.py b/CHEWBBACA/UniprotFinder/annotate_schema.py index 8106375c..8f58e55b 100755 --- a/CHEWBBACA/UniprotFinder/annotate_schema.py +++ b/CHEWBBACA/UniprotFinder/annotate_schema.py @@ -386,7 +386,7 @@ def main(schema_directory, output_directory, genes_list, protein_table, else: # Search for annotations through the SPARQL endpoint print('\nQuerying UniProt\'s SPARQL endpoint...') - config_file = fo.join_paths(schema_directory, ['.schema_config']) + config_file = fo.join_paths(schema_directory, [ct.SCHEMA_CONFIG_BASENAME]) if os.path.isfile(config_file) is True: config = fo.pickle_loader(config_file) translation_table = config.get('translation_table', [11])[0] diff --git a/CHEWBBACA/chewBBACA.py b/CHEWBBACA/chewBBACA.py index de8f13c9..4caad25b 100755 --- a/CHEWBBACA/chewBBACA.py +++ b/CHEWBBACA/chewBBACA.py @@ -5,6 +5,8 @@ ------- This is the main script of the chewBBACA suite. +It parses the options and arguments provided through the command +line and calls the specified module. """ @@ -97,8 +99,7 @@ def msg(name=None): 'create a schema. Module documentation available at ' 'https://chewbbaca.readthedocs.io/en/latest/user/modules/CreateSchema.html') - parser.add_argument('CreateSchema', nargs='+', - help='') + parser.add_argument('CreateSchema', nargs='+', help='') parser.add_argument('-i', '--input-files', nargs='?', type=str, required=True, dest='input_files', @@ -186,11 +187,10 @@ def msg(name=None): args = parser.parse_args() del args.CreateSchema - # Check if ptf exists + # Check if PTF exists if args.ptf_path is not None: - ptf_exists = os.path.isfile(args.ptf_path) - if ptf_exists is False: - sys.exit('Invalid path for Prodigal training file.') + if os.path.isfile(args.ptf_path) is False: + sys.exit(ct.INVALID_PTF_PATH) # Create output directory created = fo.create_directory(args.output_directory) @@ -219,12 +219,9 @@ def msg(name=None): ptf_hash = fo.hash_file(args.ptf_path, hashlib.blake2b()) # Write schema config file - schema_config = pv.write_schema_config(args.blast_score_ratio, ptf_hash, - args.translation_table, ct.MSL_MIN, - version, args.size_threshold, - args.word_size, args.window_size, - args.clustering_sim, args.representative_filter, - args.intra_filter, schema_dir) + args.minimum_length = ct.MSL_MIN + args.ptf_path = ptf_hash + schema_config = pv.write_schema_config(vars(args), version, schema_dir) # Create the file with the list of genes/loci pv.write_gene_list(schema_dir) @@ -450,7 +447,7 @@ def msg(name=None): if 'short' not in schema_files or len(fo.filter_by_extension(schema_files, ['.fasta'])[0]) == 0: sys.exit(ct.SCHEMA_INVALID_PATH) - config_file = os.path.join(args.schema_directory, '.schema_config') + config_file = os.path.join(args.schema_directory, ct.SCHEMA_CONFIG_BASENAME) # Legacy schemas do not have config file # Tell users to adapt with PrepExternalSchema module if os.path.isfile(config_file) is False: @@ -557,8 +554,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('SchemaEvaluator', nargs='+', - help='Evaluates a set of loci.') + parser.add_argument('SchemaEvaluator', nargs='+', help='') parser.add_argument('-g', '--schema-directory', type=str, required=True, dest='schema_directory', @@ -669,12 +665,11 @@ def msg(name=None): return usage_msg parser = argparse.ArgumentParser(prog='AlleleCallEvaluator', - description='', + description='Evaluates allele calling results.', usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('AlleleCallEvaluator', nargs='+', - help='Evaluates allele calling results.') + parser.add_argument('AlleleCallEvaluator', nargs='+', help='') parser.add_argument('-i', '--input-files', type=str, required=True, dest='input_files', @@ -774,8 +769,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('ExtractCgMLST', nargs='+', - help='') + parser.add_argument('ExtractCgMLST', nargs='+', help='') parser.add_argument('-i', '--input-file', type=str, required=True, dest='input_file', @@ -840,9 +834,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('RemoveGenes', nargs='+', - help='Remove loci from a matrix with allelic ' - 'profiles.') + parser.add_argument('RemoveGenes', nargs='+', help='') parser.add_argument('-i', '--input-file', type=str, required=True, dest='input_file', @@ -890,8 +882,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('JoinProfiles', nargs='+', - help='') + parser.add_argument('JoinProfiles', nargs='+', help='') parser.add_argument('-p', '--profiles', nargs='+', type=str, required=True, dest='profiles', @@ -942,27 +933,21 @@ def msg(name=None): return usage_msg parser = argparse.ArgumentParser(prog='PrepExternalSchema', - description='Enables the ' - 'adaptation of external ' - 'schemas so that the loci ' - 'and alleles present in ' - 'those schemas can be used ' - 'with chewBBACA. During ' - 'the process, alleles that ' - 'do not correspond to a ' - 'complete CDS or that cannot ' - 'be translated are discarded ' - 'from the final schema. One ' - 'or more alleles of each ' - 'gene/locus will be chosen ' - 'as representatives and ' - 'included in the "short" ' - 'directory.', + description='Enables the adaptation of external ' + 'schemas so that the loci and alleles ' + 'present in those schemas can be used ' + 'with chewBBACA. During the process, ' + 'alleles that do not correspond to a ' + 'complete CDS or that cannot be ' + 'translated are discarded from the ' + 'final schema. One or more alleles of ' + 'each gene/locus will be chosen as ' + 'representatives and included in the ' + '"short" directory.', usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('PrepExternalSchema', nargs='+', - help='') + parser.add_argument('PrepExternalSchema', nargs='+', help='') parser.add_argument('-g', '--schema-directory', type=str, required=True, dest='schema_directory', @@ -1041,11 +1026,10 @@ def msg(name=None): args = parser.parse_args() del args.PrepExternalSchema - # Check if ptf exists + # Check if PTF exists if args.ptf_path is not None: - ptf_exists = os.path.isfile(args.ptf_path) - if ptf_exists is False: - sys.exit('Invalid path for Prodigal training file.') + if os.path.isfile(args.ptf_path) is False: + sys.exit(ct.INVALID_PTF_PATH) # Define output paths schema_path = os.path.abspath(args.output_directory) @@ -1101,12 +1085,13 @@ def msg(name=None): print('Copied Prodigal training file to schema directory.') # Write schema config file - schema_config = pv.write_schema_config(args.blast_score_ratio, ptf_hash, - args.translation_table, args.minimum_length, - version, args.size_threshold, ct.WORD_SIZE_DEFAULT, - ct.WINDOW_SIZE_DEFAULT, ct.CLUSTERING_SIMILARITY_DEFAULT, - ct.REPRESENTATIVE_FILTER_DEFAULT, ct.INTRA_CLUSTER_DEFAULT, - schema_path) + args.ptf_path = ptf_hash + args.word_size = ct.WORD_SIZE_DEFAULT + args.window_size = ct.WINDOW_SIZE_DEFAULT + args.clustering_sim = ct.CLUSTERING_SIMILARITY_DEFAULT + args.representative_filter = ct.REPRESENTATIVE_FILTER_DEFAULT + args.intra_filter = ct.INTRA_CLUSTER_DEFAULT + schema_config = pv.write_schema_config(vars(args), version, schema_path) # Create hidden file with list of loci genes_list_file = pv.write_gene_list(schema_path) @@ -1156,8 +1141,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('UniprotFinder', nargs='+', - help='') + parser.add_argument('UniprotFinder', nargs='+', help='') parser.add_argument('-g', '--schema-directory', type=str, required=True, dest='schema_directory', @@ -1264,8 +1248,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('DownloadSchema', nargs='+', - help='') + parser.add_argument('DownloadSchema', nargs='+', help='') parser.add_argument('-sp', '--species-id', type=str, required=True, dest='species_id', @@ -1289,9 +1272,7 @@ def msg(name=None): '(will be redefined to a lower value ' 'if it is equal to or exceeds the total' 'number of available CPU cores/threads). ' - 'This value is only used if local sequences ' - 'are aligned against reference proteomes with ' - 'BLASTp. This value is only used if it is ' + 'This value is only used if it is ' 'necessary to construct the schema locally.') parser.add_argument('--ns', '--nomenclature-server', type=pv.validate_ns_url, @@ -1362,8 +1343,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('LoadSchema', nargs='+', - help='') + parser.add_argument('LoadSchema', nargs='+', help='') parser.add_argument('-i', '--schema-directory', type=str, required=True, dest='schema_directory', @@ -1465,8 +1445,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('SyncSchema', nargs='+', - help='') + parser.add_argument('SyncSchema', nargs='+', help='') parser.add_argument('-sc', '--schema-directory', type=str, required=True, dest='schema_directory', @@ -1550,8 +1529,7 @@ def msg(name=None): usage=msg(), formatter_class=ModifiedHelpFormatter) - parser.add_argument('NSStats', nargs='+', - help='') + parser.add_argument('NSStats', nargs='+', help='') parser.add_argument('-m', '--mode', type=str, required=True, dest='mode', @@ -1626,8 +1604,8 @@ def main(): 'and schemas in Chewie-NS.', run_stats_requests]} - matches = ["--v", "-v", "-version", "--version"] - if len(sys.argv) > 1 and any(m in sys.argv[1] for m in matches): + version_triggers = ['-v', '--v', '-version', '--version'] + if len(sys.argv) > 1 and sys.argv[1] in version_triggers: # Print version and exit print('chewBBACA version: {0}'.format(version)) sys.exit(0) @@ -1639,8 +1617,9 @@ def main(): print('Contacts: {0}\n'.format(ct.contacts)) # Display help message if selected process is not valid - if len(sys.argv) == 1 or sys.argv[1] not in functions_info: - print('USAGE: chewBBACA.py [module] -h \n') + help_triggers = ['-h', '--h', '-help', '--help'] + if len(sys.argv) == 1 or sys.argv[1] not in functions_info or sys.argv[1] in help_triggers: + print('USAGE: chewBBACA.py [module] -h, --help\n') print('Select one of the following modules :\n') for f in functions_info: print('{0}: {1}'.format(f, functions_info[f][0])) @@ -1649,6 +1628,10 @@ def main(): # Check python version python_version = pv.validate_python_version() + # Trigger module help message if no arguments are provided + if len(sys.argv) == 2 and sys.argv[1] in functions_info: + sys.argv.append('-h') + process = sys.argv[1] functions_info[process][1]() diff --git a/CHEWBBACA/utils/constants.py b/CHEWBBACA/utils/constants.py index ebc05e38..a7be52e8 100755 --- a/CHEWBBACA/utils/constants.py +++ b/CHEWBBACA/utils/constants.py @@ -183,6 +183,8 @@ NOVEL_BASENAME = 'novel_alleles.fasta' CDS_COORDINATES_BASENAME = 'cds_coordinates.tsv' INVALID_CDS_BASENAME = 'invalid_cds.txt' +SCHEMA_CONFIG_BASENAME = '.schema_config' +GENE_LIST_BASENAME = '.genes_list' # Header for TSV file with loci stats LOCI_STATS_HEADER = ('Locus\tEXC\tINF\tPLOT3\tPLOT5\tLOTSC\tNIPH\t' 'NIPHEM\tALM\tASM\tPAMA\tLNF\tTotal_CDS') @@ -232,8 +234,6 @@ GENOME_LIST = 'listGenomes2Call.txt' LOCI_LIST = 'listGenes2Call.txt' -LOCI_LIST_FILE = '.genes_list' - # Maximum number of allele hashes per pre-computed file HASH_TABLE_MAXIMUM_ALLELES = 200000 @@ -481,3 +481,6 @@ # PTF is missing from schema's directory LOADSCHEMA_MISSING_PTF = ('Please ensure that the schema\'s directory includes the ' 'Prodigal training file used to create the schema.') + +# Path for PTF does not exist +INVALID_PTF_PATH = 'Invalid path for Prodigal training file.' diff --git a/CHEWBBACA/utils/parameters_validation.py b/CHEWBBACA/utils/parameters_validation.py index 09448a7d..e6dd3dd4 100644 --- a/CHEWBBACA/utils/parameters_validation.py +++ b/CHEWBBACA/utils/parameters_validation.py @@ -744,14 +744,14 @@ def validate_ptf_path(ptf_path, schema_directory): if file.endswith('.trn')] if len(schema_ptfs) > 1: sys.exit('Found more than one Prodigal training ' - 'file in schema directory.\nPlease maintain ' + 'file in the schema directory.\nPlease maintain ' 'only the training file used in the schema ' 'creation process.') elif len(schema_ptfs) == 1: if schema_ptfs[0] is not None: ptf_path = os.path.join(schema_directory, schema_ptfs[0]) else: - print('There is no Prodigal training file in schema\'s ' + print('There is no Prodigal training file in the schema ' 'directory.') ptf_path = None else: @@ -1004,56 +1004,24 @@ def write_gene_list(schema_dir): # Loci FASTA files must end with '.fasta' extension schema_files = os.listdir(schema_dir) loci_files, _ = fo.filter_by_extension(schema_files, ['.fasta']) - output_file = fo.join_paths(schema_dir, ['.genes_list']) + output_file = fo.join_paths(schema_dir, [ct.GENE_LIST_BASENAME]) fo.pickle_dumper(loci_files, output_file) return [os.path.isfile(output_file), output_file] -def write_schema_config(blast_score_ratio, ptf_hash, translation_table, - minimum_sequence_length, chewie_version, size_threshold, - word_size, window_size, clustering_sim, representative_filter, - intra_filter, output_directory): - """ Writes chewBBACA's parameters values used to create +def write_schema_config(args, chewie_version, output_directory): + """ Writes chewBBACA's parameter values used to create a schema to a file. Parameters ---------- - blast_score_ratio : float - BLAST Score Ratio value used to create the - schema. - ptf_hash : str - BLAKE2 hash of the Prodigal training file - content. - translation_table : int - Genetic code used to predict and translate - coding sequences. - minimum_sequence_length : int - Minimum sequence length, sequences with a - length value lower than this value are not - included in the schema. + args : dict + Dictionary with the parameter values to store in the + schema config file. chewie_version : str Version of the chewBBACA suite used to create the schema. - size_threshold : float - Sequence size variation percentage threshold, - new alleles cannot have a length value that - deviates +/- than this value in relation to the - locus's representative sequence. - word_size : int - Word/k value used to cluster protein sequences - during schema creation and allele calling. - clustering_sim : float - Proportion of k-mers/minimizers that two proteins - need to have in common to be clustered together. - representative_filter : float - Proportion of k-mers/minimizers that a clustered - protein has to have in common with the representative - protein of the cluster to be considered the same gene. - intra_filter : float - Proportion of k-mers/minimizers that clustered - proteins have to have in common to be considered - of the same gene. output_directory : str Path to the output directory where the file with schema parameters values will be created. @@ -1066,22 +1034,27 @@ def write_schema_config(blast_score_ratio, ptf_hash, translation_table, is the path to the created file. """ - size_threshold = None if size_threshold in [None, 'None'] else float(size_threshold) + # Deal with multiple names for the same parameter + size_threshold = None if args['size_threshold'] in [None, 'None'] else float(args['size_threshold']) + bsr = float(args.get('blast_score_ratio')) if 'blast_score_ratio' in args else float(args['bsr']) + minimum_locus_length = int(args.get('minimum_length')) if 'minimum_length' in args else int(args['minimum_locus_length']) + cluster_sim = args.get('clustering_sim') if 'clustering_sim' in args else args['cluster_sim'] + intraCluster_filter = args.get('intra_filter') if 'intra_filter' in args else args['intraCluster_filter'] params = {} - params['bsr'] = [float(blast_score_ratio)] - params['prodigal_training_file'] = [ptf_hash] - params['translation_table'] = [int(translation_table)] - params['minimum_locus_length'] = [int(minimum_sequence_length)] + params['bsr'] = [bsr] + params['prodigal_training_file'] = [args['ptf_path']] + params['translation_table'] = [int(args['translation_table'])] + params['minimum_locus_length'] = [minimum_locus_length] params['chewBBACA_version'] = [chewie_version] params['size_threshold'] = [size_threshold] - params['word_size'] = [word_size] - params['window_size'] = [window_size] - params['cluster_sim'] = [clustering_sim] - params['representative_filter'] = [representative_filter] - params['intraCluster_filter'] = [intra_filter] + params['word_size'] = [args['word_size']] + params['window_size'] = [args['window_size']] + params['cluster_sim'] = [cluster_sim] + params['representative_filter'] = [args['representative_filter']] + params['intraCluster_filter'] = [intraCluster_filter] - config_file = os.path.join(output_directory, '.schema_config') + config_file = os.path.join(output_directory, ct.SCHEMA_CONFIG_BASENAME) fo.pickle_dumper(params, config_file) return [os.path.isfile(config_file), config_file]