0

I have a bunch of long pyqt scripts, in which the original author wrote code like this

from PyQt4.QtGui import *
from PyQt4.QtCore import *
...

Is there a smart or quick way to change the code to

from PyQt4 import QtGui,QtCore
...

and also prefix every pyqt class with module name? eg change QDialog to QtGui.QDialog, with sublime editor or pycharm ? or any other editor?

I read about one can add custom fixers to 2to3 script, and repurpose that tool for this, but that doesn't seem a simple task. Or build ast tree and do the replace by yourself ( sounds more complex and maybe it is reinventing the wheel ). Or should I just write regex replace script and just parse all the .py files ? ( sounds unsafe )

edit: I read the original question, it seems my question is a subset of it, finally I used a hacky solution, since I knew the code I want to fix is pyqt.

bad_file = '/path/to/bad_file'
import re

from PyQt4 import QtCore,QtGui

QtCore_mappings = [x for x in dir(QtCore) if '_' not in x]
QtGui_mappings = [x for x in dir(QtGui) if '_' not in x]

mappings = {'QtCore':QtCore_mappings,'QtGui':QtGui_mappings }

cache={}


def find_class_long_name(c):
    for k,v in mappings.iteritems():
        if c in v:
            return '%s.%s' % (k,c)
    else:
        return None

with open(bad_file) as f:
    code = f.read()

    all_classes =  re.findall(r'\bQ[A-Z]\w*\b', code)
    all_classes=set(all_classes)

    for c in all_classes:
        new_c = find_class_long_name(c)
        if new_c:
            print '%s ---> %s' % (c, new_c)
            code=re.sub(r'\b%s\b' %c,new_c,code)
        else:
            print 'skipped:',c

        # write code to new file

update 2: I think I can just replace the module import lines without changing the code

def find_module(c):
    for k,v in mappings.iteritems():
        if c in v:
            return k
    else:
        return None

with open(bad_file) as f:
    code = f.read()
    # print code

    all_classes =  re.findall(r'\bQ[A-Z]\w*\b', code)
    all_classes=set(all_classes)

    for c in all_classes:
        c_module = find_module(c)
        if c_module:
            cache[c_module].append(c)
        else:
            print 'skipped:',c

    cmd = ''
    for k,v in cache.iteritems():
        if cache[k]:
            cmd+='from %s import (%s)' % (k, ', '.join(sorted(cache[k])))
            cmd+='\n'

    print 'new import:\n'
    print cmd
Shuman
  • 3,914
  • 8
  • 42
  • 65
  • If I may ask. How many `from x import *` are we talking about? –  Oct 27 '16 at 18:21
  • In several hundreds of files, the problem is in the code, every usage of PyQt classes does not have `QtGui.` or `QtCore.` as a prefix – Shuman Oct 27 '16 at 18:23
  • That is a problem. Maybe you can think about running `pylint` once you replace everything to get a list of import errors and then add it to `from x import y, z`? –  Oct 27 '16 at 18:26

0 Answers0