Pml2py

From PyMOLWiki
Revision as of 10:29, 20 May 2011 by Speleo3 (talk | contribs) (use pymol.parsing module)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This script converts a pml script to a python script.

See pymol-users mailing list (Subject: Convert pml script to Pymol Python script, Fri, 8 Apr 2011).

import sys
from pymol import cmd, parsing

def pml2py(filename, out=sys.stdout):
    '''
DESCRIPTION

    Convert a pml script to python syntax.

USAGE

    pml2py infile [, outfile]

TODO

    comments, aliases, multiple commands in one line
    '''
    def quote(args):
        args = iter(args)
        for arg in args:
            if '=' not in arg:
                prefix = ''
            else:
                prefix, arg = arg.split('=', 1)
                prefix += '='
                arg = arg.lstrip()
            yield prefix + repr(arg)

    if isinstance(out, basestring):
        out = open(out, 'w')

    print >> out, '''
# automatically converted from "%s"
import pymol
from pymol import *
''' % (filename)

    handle = iter(open(filename, 'rU'))
    for line in handle:
        while line.endswith('\\\n'):
            line = line[:-2] + handle.next()

        a = line.split(None, 1)
        if len(a) > 1 and a[0] == '_':
            line = a[1]
            a = line.split(None, 1)

        try:
            name = a[0]
            if name.startswith('/'):
                line = line.lstrip()[1:]
                raise
            name = cmd.kwhash.shortcut.get(name, name)
            kw = cmd.keyword[name]
            assert kw[4] != parsing.PYTHON
            func = kw[0]
        except:
            out.write(line)
            continue
        
        # PyMOL stuff without named python function
        if func.__name__ == '<lambda>' or name.startswith('@'):
            print >> out, 'cmd.do(%s)' % (repr(line.strip()))
            continue

        # code blocks
        if name == 'python':
            for line in handle:
                if line.split() == ['python', 'end']:
                    break
                out.write(line)
            continue
        if name == 'skip':
            for line in handle:
                if line.split() == ['skip', 'end']:
                    break
            continue

        # split args
        tok = ','
        if kw[4] == parsing.MOVIE:
            tok = kw[3]
            split_mx = 1
        else:
            split_mx = kw[4] - parsing.LITERAL
        if len(a) > 1:
            if split_mx == 0:
                args = [a[1]]
            else:
                args = [i.strip() for i in parsing.split(a[1], tok, max(0, split_mx))]
        else:
            args = []

        # old syntax: set property=value
        if kw[4] == parsing.LEGACY and '=' in args[0]:
            args = [i.strip() for i in args[0].split('=', 1)] + args[1:]

        # use 'cmd' module if possible
        try:
            test = getattr(cmd, func.__name__)
            assert func == test
            module = 'cmd'
        except:
            module = func.__module__

        print >> out, '%s.%s(%s)' % (module, func.__name__, ', '.join(quote(args)))

cmd.extend('pml2py', pml2py)

# vi:expandtab:smarttab