#! /usr/bin/env python import sys import re import os import shutil from subprocess import Popen, PIPE, STDOUT from tempfile import mkstemp from optparse import OptionParser class FileFormat: PHYLIP, NEXUS, UNKNOWN = range(3) DEFAULT_PAUP = "paup" class Logger: def debug(self, m): if options.noisy: print >>sys.stderr, m def warn(self, m): if not options.quiet: print >>sys.stderr, m _LOG = Logger() def diagnose_format(filename): f = open(filename, "rU") try: firstLine = f.readline() phylip_header = re.compile(r"^\s*\d+\s+\d+\s*$") if phylip_header.match(firstLine): _LOG.debug(filename + " appears to be PHYLIP.") return FileFormat.PHYLIP nexus_header = re.compile(r"^\#NEXUS", re.I) if nexus_header.match(firstLine): _LOG.debug(filename + " appears to be NEXUS.") return FileFormat.NEXUS _LOG.debug(filename + " format could not be diagnosed.") return FileFormat.UNKNOWN finally: f.close() def phylip_to_nexus(filename): _LOG.debug("Converting " + filename + "to NEXUS using PAUP.") paup_command = options.paup or DEFAULT_PAUP shell = bool(options.paup is None) paup_proc = Popen(paup_command, stdin=PIPE, stdout=PIPE, stderr=STDOUT, shell=True) if options.filename: outfn = options.filename else: outstream, outfn = mkstemp() try: try: o, e = paup_proc.communicate("ToNEXUS fromfile=%s format=phylip tofile=%s replace;\n" % (filename, outfn)) _LOG.debug(o) except OSError: sys.exit("Conversion failed, make sure that a valid path to paup is" " given (with a -p or --paup= option). \nTried to execute " "PAUP with the invocation \"%s\"." % paup_command) if not options.filename: nexus = open(outfn, "rU") try: c = nexus.read() sys.stdout.write(c) finally: nexus.close() finally: if not options.filename: _LOG.debug("removing " + outfn) os.remove(outfn) def unknown_to_nexus(filename): _LOG.debug("Treating unknown file " + filename + " as if it were NEXUS") nexus_to_nexus(filename) def nexus_to_nexus(filename): if options.filename: shutil.copyfile(filename, options.filename) else: nexus = open(filename, "rU") try: sys.stderr.write(nexus.read()) finally: nexus.close() parser = OptionParser() parser.add_option("-f", "--file", dest="filename", help="NEXUS file to write", metavar="FILE") parser.add_option("-p", "--paup", dest="paup", help="path to PAUP -- required if PAUP* is not on you path as \"%s\" and you wish to perform some conversions (e.g. a PHYLIP to NEXUS conversion)" % DEFAULT_PAUP, metavar="FILE") parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False, help="suppress warnings") parser.add_option("-n", "--noisy", action="store_true", dest="noisy", default=False, help="print status messages to stderr") (options, args) = parser.parse_args() if len(args) != 1: sys.exit("Expecting a file to convert to NEXUS") if options.filename and os.path.exists(options.filename): _LOG.warn(options.filename + " will be replaced") converter = { FileFormat.PHYLIP : phylip_to_nexus, FileFormat.NEXUS : nexus_to_nexus, FileFormat.UNKNOWN: unknown_to_nexus, } for infile_name in args: format = diagnose_format(infile_name) convFunc = converter[format] convFunc(infile_name)