Skip to content

Commit 7128a35

Browse files
committedFeb 10, 2016
add 2to3 script to migrate (some) PyQt signal/slots to new style
1 parent d11c689 commit 7128a35

File tree

3 files changed

+91
-6
lines changed

3 files changed

+91
-6
lines changed
 

‎scripts/qgis_fixes/__init__.py

Whitespace-only changes.

‎scripts/qgis_fixes/fix_pyqt.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@
297297
"QPoint",
298298
"QPointF",
299299
"QDirIterator",
300+
]),
301+
(None, [
300302
"SIGNAL",
301303
"SLOT",
302304
]),
@@ -397,19 +399,21 @@ def transform_member(self, node, results):
397399
pref = mod_member.prefix
398400
member = results.get("member")
399401

402+
missing = False
403+
400404
# Simple case with only a single member being imported
401405
if member:
402406
# this may be a list of length one, or just a node
403407
if isinstance(member, list):
404408
member = member[0]
405-
new_name = None
409+
new_name = ''
406410
for change in MAPPING[mod_member.value]:
407411
if member.value in change[1]:
408412
new_name = change[0]
409413
break
410414
if new_name:
411415
mod_member.replace(Name(new_name, prefix=pref))
412-
else:
416+
elif new_name == '':
413417
self.cannot_convert(node, "This is an invalid module element")
414418

415419
# Multiple members being imported
@@ -430,14 +434,16 @@ def transform_member(self, node, results):
430434
found = False
431435
for change in MAPPING[mod_member.value]:
432436
if member_name in change[1]:
433-
if change[0] not in mod_dict:
434-
modules.append(change[0])
435-
mod_dict.setdefault(change[0], []).append(member)
437+
if change[0] is not None:
438+
if change[0] not in mod_dict:
439+
modules.append(change[0])
440+
mod_dict.setdefault(change[0], []).append(member)
436441
found = True
437442
if not found:
438443
f = open("/tmp/missing", "a+")
439444
f.write("member %s of %s not found\n" % (member_name, mod_member.value))
440445
f.close()
446+
missing = True
441447

442448
new_nodes = []
443449
indentation = find_indentation(node)
@@ -450,6 +456,7 @@ def handle_name(name, prefix):
450456
name.children[2].clone()]
451457
return [Node(syms.import_as_name, kids)]
452458
return [Name(name.value, prefix=prefix)]
459+
453460
for module in modules:
454461
elts = mod_dict[module]
455462
names = []
@@ -462,13 +469,18 @@ def handle_name(name, prefix):
462469
new.prefix = indentation
463470
new_nodes.append(new)
464471
first = False
472+
465473
if new_nodes:
466474
nodes = []
467475
for new_node in new_nodes[:-1]:
468476
nodes.extend([new_node, Newline()])
469477
nodes.append(new_nodes[-1])
478+
479+
if node.prefix:
480+
nodes[0].prefix = node.prefix
481+
470482
node.replace(nodes)
471-
else:
483+
elif missing:
472484
self.cannot_convert(node, "All module elements are invalid")
473485

474486
def transform_dot(self, node, results):

‎scripts/qgis_fixes/fix_signals.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""Migrate signals from old style to new style
2+
"""
3+
# Author: Juergen E. Fischer
4+
5+
# .connect( sender, signal, receiver, slot )
6+
7+
# Local imports
8+
from lib2to3 import fixer_base, pytree
9+
from lib2to3.fixer_util import Call, Name, Attr, ArgList, Node, syms
10+
11+
import re
12+
13+
14+
class FixSignals(fixer_base.BaseFix):
15+
PATTERN = """
16+
(
17+
power<
18+
any trailer< '.' method=('connect'|'disconnect') >
19+
trailer<
20+
'('
21+
arglist<
22+
sender=any ','
23+
power< 'SIGNAL' trailer< '(' signal=any ')' > > ','
24+
slot=any
25+
>
26+
')'
27+
>
28+
>
29+
|
30+
power<
31+
emitter=any trailer< '.' 'emit' >
32+
trailer<
33+
'('
34+
args=arglist<
35+
power< 'SIGNAL' trailer< '(' signal=any ')' > >
36+
( ',' any )*
37+
>
38+
')'
39+
>
40+
>
41+
)
42+
"""
43+
44+
# def match(self, node):
45+
# res = super(FixSignals, self).match( node )
46+
# r = repr(node)
47+
# if "emit" in r:
48+
# print "yes" if res else "no", ": ", r
49+
# return res
50+
51+
def transform(self, node, results):
52+
signal = results.get("signal").value
53+
signal = re.sub('^["\']([^(]+)(?:\(.*\))?["\']$', '\\1', signal)
54+
55+
if 'emitter' in results:
56+
emitter = results.get("emitter").clone()
57+
emitter.prefix = node.prefix
58+
args = results.get("args").clone()
59+
args.children = args.children[2:]
60+
if args.children:
61+
args.children[0].prefix = ''
62+
res = Node(syms.power, [emitter, Name('.'), Name(signal), Name('.'), Name('emit')] + [ArgList([args])])
63+
else:
64+
sender = results.get("sender").clone()
65+
method = results.get("method")
66+
if isinstance(method, list):
67+
method = method[0]
68+
method = method.clone()
69+
sender.prefix = node.prefix
70+
slot = results.get("slot").clone()
71+
slot.prefix = ""
72+
res = Node(syms.power, [sender, Name('.'), Name(signal), Name('.'), method] + [ArgList([slot])])
73+
return res

1 commit comments

Comments
 (1)

nyalldawson commented on Feb 10, 2016

@nyalldawson
Collaborator

Nice!

FYI for the c++ code we can use clazy to do a similar automatic port.

Please sign in to comment.