Pml2py

From PyMOLWiki
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).

from __future__ import print_function

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]
    '''
    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)

    class stackiter:
        def __init__(self, collection):
            self.iterator = iter(collection)
            self.stack = []
        def __iter__(self):
            return self
        def next(self):
            if len(self.stack):
                return self.stack.pop()
            return next(self.iterator)
        __next__ = next
        def push(self, v):
            self.stack.append(v)

    basestring = (bytes, unicode) if (bytes is str) else (bytes, str)
    if isinstance(out, basestring):
        out = open(out, 'w')

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

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

        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('cmd.do(%s)' % (repr(line.strip())), file=out)
            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:
            a[1] = parsing.split(a[1], '#', 1)[0] # strip of comment
            if split_mx < 0:
                # strip of additional commands
                a[1:] = parsing.split(a[1], ';', 1)
                if len(a) > 2:
                    handle.push(a[2])
            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:]

        # register alias
        if name == 'alias':
            cmd.alias(*args)

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

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

cmd.extend('pml2py', pml2py)

# vi:expandtab:smarttab