Merge lp:~ogra/xdiagnose/py3port into lp:xdiagnose

Proposed by Oliver Grawert
Status: Merged
Merged at revision: 256
Proposed branch: lp:~ogra/xdiagnose/py3port
Merge into: lp:xdiagnose
Diff against target: 1040 lines (+266/-182)
35 files modified
apport/apport-gpu-error-intel.py (+7/-5)
apport/source_xorg.py (+11/-5)
bin/dpkg-log-summary (+9/-11)
bin/xdiagnose (+3/-1)
bin/xpci (+8/-6)
bin/xrandr-tool (+12/-10)
data/workloads/run_workloads (+3/-1)
debian/changelog (+16/-0)
debian/control (+7/-5)
debian/pycompat (+0/-1)
debian/rules (+17/-1)
run-tests (+1/-1)
setup.py (+1/-1)
tests/test_apport_gpu_hook (+1/-1)
tests/test_diagnostic (+3/-1)
tests/test_grub_file (+3/-1)
tests/test_script_syntax.sh (+5/-3)
tests/test_source_xorg (+1/-1)
xdiagnose/applet.py (+14/-14)
xdiagnose/application.py (+3/-1)
xdiagnose/config_update.py (+12/-10)
xdiagnose/diagnostics.py (+28/-27)
xdiagnose/edid.py (+48/-46)
xdiagnose/errors_treeview.py (+3/-1)
xdiagnose/info.py (+9/-7)
xdiagnose/pci_devices.py (+5/-3)
xdiagnose/utils/dates.py (+6/-4)
xdiagnose/utils/debug.py (+3/-1)
xdiagnose/utils/execute.py (+3/-1)
xdiagnose/utils/math.py (+3/-1)
xdiagnose/utils/option_handler.py (+3/-1)
xdiagnose/utils/paths.py (+4/-2)
xdiagnose/utils/screen.py (+5/-3)
xdiagnose/utils/text.py (+3/-1)
xdiagnose/welcome.py (+6/-4)
To merge this branch: bzr merge lp:~ogra/xdiagnose/py3port
Reviewer Review Type Date Requested Status
Bryce Harrington Approve
Colin Watson (community) Approve
Review via email: mp+109633@code.launchpad.net

Description of the change

this merge carries all program code changes for python3 support, do not merge it standalone without package changes. this branch is kept separate from py3 package fixes for easier reviewing only, packaging adjustments will follow shortly in another merge proposal.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

- for k, r in codes.items():
+ for k, r in list(codes.items()):

This is just 2to3 being conservative; you don't actually need the list() here, since the body of the loop doesn't modify codes.

+ dates = list(dates.keys())
  dates.sort()
  return dates

Simpler: "return sorted(dates)"

+ pkgs = list(dpkg_events.keys())
  pkgs.sort()
  for pkg in pkgs:

"for pkg in sorted(dpkg_events):"

+ print(device.name, device.regex, end=' ')
...

Doesn't this end up writing double spaces sometimes (e.g. in the "NOT SUPPORTED" case)? I'd have been inclined to use end=''.

The rest looks fine to me, although I'd have been inclined to add print_function and absolute_import imports from __future__ as applicable just in case there's a need to revert the #! to /usr/bin/python for some reason.

review: Approve
lp:~ogra/xdiagnose/py3port updated
255. By Oliver Grawert

include required and recommended changes from cjwatson review on merge proposal 109633

256. By Oliver Grawert

adjust packaging bits for python3 support

257. By Oliver Grawert

use python_distutils in debian/rules and actually install from the real builddir, thanks xnox for helping with the fix

258. By Oliver Grawert

fix a remaining porting error with xdiagnose/applet.py (exception handling with multiple args has changed)

Revision history for this message
Bryce Harrington (bryce) wrote :

Changes look good. Once you've verified the test suite is still happy let me know and I'll merge this in.

review: Approve
lp:~ogra/xdiagnose/py3port updated
259. By Oliver Grawert

add dependency on python3-apport, various fixes for testsuite, port testsuite to py3, make lp-lib optional for now

260. By Oliver Grawert

fix apport report handling in apport-gpu-error-intel.py to match the new API that needs binary file handling

261. By Oliver Grawert

xdiagnose/applet.py: fix string handling of subprocess.Popen

Revision history for this message
Oliver Grawert (ogra) wrote :

with the latest changes this branch should now be mergeable, UI and testsuite work fine in a quantal VM here

lp:~ogra/xdiagnose/py3port updated
262. By Oliver Grawert

add changelog reference to bug 1013171

Revision history for this message
Bryce Harrington (bryce) wrote :

When I attempt to debuild -sa -S this branch I get an error on python3-apport:

The following packages have unmet dependencies:
 pbuilder-satisfydepends-dummy : Depends: debhelper (>= 7.0.50~) but it is not going to be installed
                                 Depends: dh-translations but it is not going to be installed
                                 Depends: python3 (>= 3.2) but it is not going to be installed
                                 Depends: python3-all but it is not going to be installed
                                 Depends: intltool but it is not going to be installed
                                 Depends: apport but it is not going to be installed
                                 Depends: python3-apport but it is not installable
                                 Depends: python3-distutils-extra (>= 2.32-2) but it is not going to be installed
E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).

I think that python3-apport might be ok as a package dependency rather than a build dependency since it's just the apport hooks that require it during their execution. But after moving that, there's this error:

dh_auto_clean
Traceback (most recent call last):
  File "setup.py", line 20, in <module>
    import DistUtilsExtra.auto
ImportError: No module named DistUtilsExtra.auto

Which is a bit of a head-scratcher. Maybe dh_auto_clean is calling setup.py as python2 or something?

review: Needs Fixing
lp:~ogra/xdiagnose/py3port updated
263. By Oliver Grawert

eek, what was i thinking, indeed we want to depend (not build-depend) on python-apport (and not python3-apport)

Revision history for this message
Oliver Grawert (ogra) wrote :

sorry, indeed the build-dep was wrong and i'm also not sure why i used python3 in the package name (python-apport is actually the py3 version already), fixed now ...

the build error does not happen for me over here, it is indeed strange

Revision history for this message
Bryce Harrington (bryce) wrote :

Excellent, thanks!

I sorted out the build issue I was seeing. It appears that the package build requires *both* python-distutils-extra and python3-distutils-extra. Not sure why, but unless both are included as build requirements, the package fails in the dh_auto_clean proc. I'm guessing that this is running clean for both python2 and python3, or something like that.

There's still a couple warnings I'm seeing:

   dh_python3 -O--buildsystem=python_distutils
W: dh_python3:181: Python 2.x location detected, please use dh_python2: debian/xdiagnose/usr/lib/python2.7
   dh_python2 -O--buildsystem=python_distutils
W: dh_python2:334: Python 3.x location detected, please use dh_python3: debian/xdiagnose/usr/lib/python3
   dh_usrlocal -O--buildsystem=python_distutils

However I think those are unrelated, and sound possibly innocuous so am going to ignore them for now. But if these sound meaningful to you, I'd love some tips on resolving them.

review: Approve
Revision history for this message
Thomas Kluyver (takluyver) wrote :

Are you sure python-apport is the right thing to depend on? It seems to explicitly depend on Python 2: http://packages.ubuntu.com/quantal/python-apport

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'apport/apport-gpu-error-intel.py'
2--- apport/apport-gpu-error-intel.py 2012-04-13 20:32:36 +0000
3+++ apport/apport-gpu-error-intel.py 2012-06-15 11:25:23 +0000
4@@ -1,4 +1,6 @@
5-#!/usr/bin/python
6+#!/usr/bin/python3
7+
8+from __future__ import absolute_import, print_function, unicode_literals
9
10 import os
11 import os.path
12@@ -153,12 +155,12 @@
13 report_filename = '/var/crash/%s.%s.crash' % (report['Package'], str(nowtime).replace(' ', '_'))
14
15 if '--stdout' in argv:
16- print "# %s" %(report_filename)
17- report.write(sys.stdout)
18+ print("# %s" %(report_filename))
19+ report.write(sys.stdout.buffer)
20 return 0
21
22- report_file = os.fdopen(os.open(report_filename, os.O_WRONLY|os.O_CREAT|os.O_EXCL), 'w')
23- os.chmod(report_filename, 0600)
24+ report_file = os.fdopen(os.open(report_filename, os.O_WRONLY|os.O_CREAT|os.O_EXCL), 'wb')
25+ os.chmod(report_filename, 0o600)
26
27 try:
28 report.write(report_file)
29
30=== modified file 'apport/source_xorg.py'
31--- apport/source_xorg.py 2012-04-13 20:09:26 +0000
32+++ apport/source_xorg.py 2012-06-15 11:25:23 +0000
33@@ -1,4 +1,4 @@
34-#!/usr/bin/python
35+#!/usr/bin/python3
36
37 '''Xorg Apport interface
38
39@@ -14,12 +14,18 @@
40 Testing: APPORT_STAGING="yes"
41 '''
42
43+from __future__ import absolute_import, print_function, unicode_literals
44+
45 import os.path
46 import glob
47 import re
48 import subprocess
49 from apport.hookutils import *
50-from launchpadlib.launchpad import Launchpad
51+
52+try:
53+ from launchpadlib.launchpad import Launchpad
54+except ImportError:
55+ pass
56
57 core_x_packages = [
58 'xorg', 'xorg-server', 'xserver-xorg-core', 'mesa'
59@@ -436,7 +442,7 @@
60 'GconfCompiz')
61
62 # Compiz internal state if compiz crashed
63- if report.get('SourcePackage','Unknown') == "compiz" and report.has_key("ProcStatus"):
64+ if report.get('SourcePackage','Unknown') == "compiz" and "ProcStatus" in report:
65 compiz_pid = 0
66 pid_line = re.search("Pid:\t(.*)\n", report["ProcStatus"])
67 if pid_line:
68@@ -692,7 +698,7 @@
69
70 report = {}
71 if not add_info(report, None):
72- print "Unreportable bug"
73+ print("Unreportable bug")
74 sys.exit(1)
75 for key in report:
76- print '[%s]\n%s' % (key, report[key])
77+ print('[%s]\n%s' % (key, report[key]))
78
79=== modified file 'bin/dpkg-log-summary'
80--- bin/dpkg-log-summary 2012-04-04 21:06:10 +0000
81+++ bin/dpkg-log-summary 2012-06-15 11:25:23 +0000
82@@ -1,8 +1,10 @@
83-#!/usr/bin/env python
84+#!/usr/bin/python3
85
86 # NOTE: Be careful to run this from the same distro version as the upgrade was done on
87 # otherwise, it may not be able to look up the proper packages.
88
89+from __future__ import absolute_import, print_function, unicode_literals
90+
91 import re
92 import os
93 import sys
94@@ -23,9 +25,7 @@
95 continue
96 event_date = datetime.datetime.strptime(m.group(1), "%Y-%m-%d")
97 dates[event_date] = True
98- dates = dates.keys()
99- dates.sort()
100- return dates
101+ return sorted(dates)
102
103 def parse_dpkg(dpkg_text, start_date=None, end_date=None):
104 re_dpkg = re.compile(r'^(\d+-\d+-\d+) (\d\d:\d\d:\d\d) (\w+) (.*)$')
105@@ -113,13 +113,13 @@
106 dpkg_log_filename = args[0]
107
108 if options.verbose:
109- print "Reading from %s" %(dpkg_log_filename)
110+ print("Reading from %s" %(dpkg_log_filename))
111 dpkg_text = loadfile(dpkg_log_filename)
112
113 if options.show_dates:
114 event_dates = parse_dpkg_dates(dpkg_text)
115 for d in event_dates:
116- print d.strftime("%Y-%m-%d")
117+ print(d.strftime("%Y-%m-%d"))
118 sys.exit(0)
119
120 start_date = None
121@@ -130,13 +130,11 @@
122 end_date = datetime.datetime.strptime(options.end_date, "%Y-%m-%d")
123 dpkg_events = parse_dpkg(dpkg_text, start_date, end_date)
124
125- pkgs = dpkg_events.keys()
126- pkgs.sort()
127- for pkg in pkgs:
128+ for pkg in sorted(dpkg_events):
129 indent = ''
130 for event in dpkg_events[pkg]:
131- print "%s%-8s %-30s %-12s %-12s %-30s %-30s" %(indent,
132- event['action'], event['source_package'], event['date'], event['time'], event['old_version'], event['new_version'])
133+ print("%s%-8s %-30s %-12s %-12s %-30s %-30s" %(indent,
134+ event['action'], event['source_package'], event['date'], event['time'], event['old_version'], event['new_version']))
135 indent += ' '
136
137 sys.exit(0)
138
139=== modified file 'bin/xdiagnose'
140--- bin/xdiagnose 2012-05-17 05:13:11 +0000
141+++ bin/xdiagnose 2012-06-15 11:25:23 +0000
142@@ -1,4 +1,4 @@
143-#!/usr/bin/python
144+#!/usr/bin/python3
145 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
146 #
147 # Copyright (C) 2010 Bryce Harrington bryce@canonical.com
148@@ -14,6 +14,8 @@
149 # You should have received a copy of the GNU General Public License along
150 # with this program. If not, see <http://www.gnu.org/licenses/>.
151
152+from __future__ import absolute_import, print_function, unicode_literals
153+
154 import sys
155 import os
156 import logging
157
158=== modified file 'bin/xpci'
159--- bin/xpci 2012-05-17 05:13:11 +0000
160+++ bin/xpci 2012-06-15 11:25:23 +0000
161@@ -1,4 +1,4 @@
162-#!/usr/bin/env python
163+#!/usr/bin/python3
164 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
165 #
166 # Copyright (C) 2012 Bryce Harrington bryce@canonical.com
167@@ -14,6 +14,8 @@
168 # You should have received a copy of the GNU General Public License along
169 # with this program. If not, see <http://www.gnu.org/licenses/>.
170
171+from __future__ import absolute_import, print_function, unicode_literals
172+
173 import sys
174 import os
175
176@@ -48,13 +50,13 @@
177 sys.exit(1)
178 for device in devices:
179 if device:
180- print device.name, device.regex,
181+ print(device.name, device.regex, end='')
182 if device.generation:
183- print device.generation,
184+ print(device.generation, end='')
185 if device.title:
186- print device.title,
187- print ','.join(device.drivers),
188+ print(device.title, end='')
189+ print(','.join(device.drivers), end='')
190 if not device.supported:
191- print " (NOT SUPPORTED)"
192+ print(" (NOT SUPPORTED)")
193
194
195
196=== modified file 'bin/xrandr-tool'
197--- bin/xrandr-tool 2012-04-04 21:06:10 +0000
198+++ bin/xrandr-tool 2012-06-15 11:25:23 +0000
199@@ -1,4 +1,6 @@
200-#!/usr/bin/env python
201+#!/usr/bin/python3
202+
203+from __future__ import absolute_import, print_function, unicode_literals
204
205 import sys
206 import re
207@@ -7,12 +9,12 @@
208 if __name__ == "__main__":
209 # TODO: optparse
210 if len(sys.argv) < 2:
211- print "Usage: xrandr-tool <command>"
212- print
213- print "Commands:"
214- print " outputs"
215- print " current-resolution [output-name]"
216- print " resolutions [output-name]"
217+ print("Usage: xrandr-tool <command>")
218+ print()
219+ print("Commands:")
220+ print(" outputs")
221+ print(" current-resolution [output-name]")
222+ print(" resolutions [output-name]")
223 sys.exit(1)
224
225 command = sys.argv[1]
226@@ -35,7 +37,7 @@
227 if m:
228 current_output_name = m.group(1)
229 if command == "outputs":
230- print current_output_name
231+ print(current_output_name)
232
233 if "resolution" in command:
234 m = re_res.match(line)
235@@ -43,6 +45,6 @@
236 res = m.group(1)
237 if command == "current-resolution":
238 if line.find('*') != -1:
239- print res
240+ print(res)
241 else:
242- print res
243+ print(res)
244
245=== modified file 'data/workloads/run_workloads'
246--- data/workloads/run_workloads 2012-04-04 21:06:10 +0000
247+++ data/workloads/run_workloads 2012-06-15 11:25:23 +0000
248@@ -1,4 +1,6 @@
249-#!/usr/bin/env python
250+#!/usr/bin/python3
251+
252+from __future__ import absolute_import, print_function, unicode_literals
253
254 import sys
255 import apt
256
257=== modified file 'debian/changelog'
258--- debian/changelog 2012-05-19 23:46:45 +0000
259+++ debian/changelog 2012-06-15 11:25:23 +0000
260@@ -1,3 +1,19 @@
261+xdiagnose (2.7) UNRELEASED; urgency=low
262+
263+ * port all program code to new python3 conventions
264+ * adjust shebang lines for all python scripts to use python3
265+ * update debian/rules and control for python3 support
266+ * remove unused debian/pycompat file
267+ * switch test suite to python3
268+ * make test suite skip testing of directories
269+ * add dependency on python3-apport
270+ * make launchpadlib usage optional until it is ported to python3
271+ * adjust apport-gpu-error-intel.py for new apport API
272+ * xdiagnose/applet.py fix string handling of subprocess.Popen
273+ * fixes (LP: #1013171)
274+
275+ -- Oliver Grawert <ogra@ubuntu.com> Mon, 11 Jun 2012 15:21:17 +0200
276+
277 xdiagnose (2.6) quantal; urgency=low
278
279 * Add general.lib to consolidate common bash functions
280
281=== modified file 'debian/control'
282--- debian/control 2012-05-19 23:46:45 +0000
283+++ debian/control 2012-06-15 11:25:23 +0000
284@@ -1,14 +1,15 @@
285 Source: xdiagnose
286 Section: python
287 Priority: extra
288+X-Python3-Version: >= 3.2
289 Build-Depends:
290 debhelper (>= 7.0.50~),
291 dh-translations,
292- python (>= 2.6.6-3~),
293- python-all,
294+ python3 (>= 3.2),
295+ python3-all,
296 intltool,
297 apport,
298- python-distutils-extra (>= 2.28)
299+ python3-distutils-extra (>= 2.32-2)
300 Maintainer: Bryce Harrington <bryce@ubuntu.com>
301 Standards-Version: 3.9.2
302 Homepage: http://wiki.ubuntu.com/X
303@@ -17,9 +18,10 @@
304 Architecture: all
305 Depends:
306 ${misc:Depends},
307- ${python:Depends},
308- python-gi (>= 2.28),
309+ ${python3:Depends},
310+ python3-gi (>= 3.2.0-3),
311 gir1.2-gtk-3.0,
312+ python-apport,
313 intel-gpu-tools
314 Replaces:
315 xserver-xorg-video-intel (<= 2:2.14.0-4ubuntu8),
316
317=== removed file 'debian/pycompat'
318--- debian/pycompat 2010-07-03 00:42:11 +0000
319+++ debian/pycompat 1970-01-01 00:00:00 +0000
320@@ -1,1 +0,0 @@
321-2
322
323=== modified file 'debian/rules'
324--- debian/rules 2012-05-19 23:46:45 +0000
325+++ debian/rules 2012-06-15 11:25:23 +0000
326@@ -1,7 +1,23 @@
327 #!/usr/bin/make -f
328
329 %:
330- dh "$@" --with python2,translations --buildsystem python_distutils
331+ dh "$@" --with python2,python3,translations --buildsystem python_distutils
332+
333+override_dh_auto_clean:
334+ dh_auto_clean
335+ rm -rf build
336+
337+override_dh_auto_build:
338+ dh_auto_build
339+ set -ex; for python in $(shell py3versions -r); do \
340+ $$python setup.py build; \
341+ done
342+
343+override_dh_auto_install:
344+ dh_auto_install
345+ set -ex; for python in $(shell py3versions -r); do \
346+ $$python setup.py install --root=$(CURDIR)/debian/xdiagnose --install-layout=deb; \
347+ done
348
349 override_dh_installinit:
350 dh_installinit --no-start --upstart-only --name failsafe-x
351
352=== modified file 'run-tests'
353--- run-tests 2011-12-12 04:02:35 +0000
354+++ run-tests 2012-06-15 11:25:23 +0000
355@@ -4,7 +4,7 @@
356 echo $t
357 file_type=$(file -b $t)
358 case ${file_type} in
359- *python*) python ${t} ;;
360+ *?ython*) python3 ${t} ;;
361 *Bourne*) bash ${t} ;;
362 *bash*) bash ${t} ;;
363 *perl*) perl ${t} ;;
364
365=== modified file 'setup.py'
366--- setup.py 2012-04-15 17:44:44 +0000
367+++ setup.py 2012-06-15 11:25:23 +0000
368@@ -1,4 +1,4 @@
369-#!/usr/bin/env python
370+#!/usr/bin/python3
371 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
372 #
373 # Copyright (C) 2010-2011 Bryce Harrington bryce@canonical.com
374
375=== modified file 'tests/test_apport_gpu_hook'
376--- tests/test_apport_gpu_hook 2012-04-18 01:07:19 +0000
377+++ tests/test_apport_gpu_hook 2012-06-15 11:25:23 +0000
378@@ -1,7 +1,7 @@
379 #!/usr/bin/bash
380
381 echo "# Testing intel GPU hook..."
382-lines=$(python apport/apport-gpu-error-intel.py --stdout --force| wc -l)
383+lines=$(python3 apport/apport-gpu-error-intel.py --stdout --force| wc -l)
384 retval=$?
385 if [ $retval -ne 0 ]; then
386 echo "ERROR"
387
388=== modified file 'tests/test_diagnostic'
389--- tests/test_diagnostic 2012-04-18 01:07:19 +0000
390+++ tests/test_diagnostic 2012-06-15 11:25:23 +0000
391@@ -1,4 +1,6 @@
392-#!/usr/bin/python
393+#!/usr/bin/python3
394+
395+from __future__ import absolute_import, print_function, unicode_literals
396
397 import sys, os.path
398 sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), "..")))
399
400=== modified file 'tests/test_grub_file'
401--- tests/test_grub_file 2012-04-18 01:07:19 +0000
402+++ tests/test_grub_file 2012-06-15 11:25:23 +0000
403@@ -1,4 +1,6 @@
404-#!/usr/bin/python
405+#!/usr/bin/python3
406+
407+from __future__ import absolute_import, print_function, unicode_literals
408
409 import sys, os.path
410 sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), "..")))
411
412=== modified file 'tests/test_script_syntax.sh'
413--- tests/test_script_syntax.sh 2012-03-17 05:59:07 +0000
414+++ tests/test_script_syntax.sh 2012-06-15 11:25:23 +0000
415@@ -45,13 +45,15 @@
416 perl -c $script >/dev/null 2>&1
417 display_result $? 'perl' ${script}
418 ;;
419- *python*script*)
420- python -m py_compile ${script}
421- display_result $? 'python' ${script}
422+ *?ython*script*)
423+ python3 -m py_compile ${script}
424+ display_result $? 'python3' ${script}
425 if [ -e ${script}c ]; then
426 rm ${script}c
427 fi
428 ;;
429+ *directory*)
430+ ;;
431 *) echo "Unknown script type '${file_type}'"
432 display_result 1 ${script}
433 esac
434
435=== modified file 'tests/test_source_xorg'
436--- tests/test_source_xorg 2012-04-18 01:07:19 +0000
437+++ tests/test_source_xorg 2012-06-15 11:25:23 +0000
438@@ -1,7 +1,7 @@
439 #!/usr/bin/bash
440
441 echo "# Testing apport hook..."
442-lines=$(python apport/source_xorg.py | wc -l)
443+lines=$(python3 apport/source_xorg.py | wc -l)
444 if [ $? -ne 0 ]; then
445 echo "FAIL"
446 exit 1
447
448=== modified file 'xdiagnose/applet.py'
449--- xdiagnose/applet.py 2012-03-22 00:56:31 +0000
450+++ xdiagnose/applet.py 2012-06-15 11:25:23 +0000
451@@ -31,7 +31,7 @@
452 self.is_running = True
453
454 if not os.path.exists(self.__grub_config_filename):
455- print "Error: No %s present" %(self.__grub_config_filename)
456+ print("Error: No %s present" %(self.__grub_config_filename))
457 sys.exit(1)
458
459 Gtk.Window.__init__(self)
460@@ -258,7 +258,7 @@
461 active = widget.get_active()
462 if active == self.__enable_apport:
463 return
464- print "Handling apport enabled"
465+ print("Handling apport enabled")
466
467 if self.has_enable_apport(widget.get_active()):
468 enabled = 1
469@@ -305,9 +305,9 @@
470 errors = []
471
472 # Xorg.0.log errors
473- process = subprocess.Popen(['grep', '(EE)', '/var/log/Xorg.0.log'], stdout=subprocess.PIPE)
474+ process = subprocess.Popen(['grep', '(EE)', '/var/log/Xorg.0.log'], universal_newlines=True)
475 stdout, stderr = process.communicate()
476- for err in stdout.split("\n"):
477+ for err in str(stdout).split("\n"):
478 m = re_jockey_error.match(err)
479 if not m:
480 continue
481@@ -316,9 +316,9 @@
482 errors.append(errmsg)
483
484 # dmesg errors
485- process = subprocess.Popen(['dmesg'], stdout=subprocess.PIPE)
486+ process = subprocess.Popen(['dmesg'], universal_newlines=True)
487 stdout, stderr = process.communicate()
488- for err in stdout.split("\n"):
489+ for err in str(stdout).split("\n"):
490 m = re_dmesg_error.match(err)
491 if not m:
492 continue
493@@ -328,9 +328,9 @@
494
495 # jockey errors
496 if os.path.exists('/var/log/jockey.log'):
497- process = subprocess.Popen(['grep', 'ERROR', '/var/log/jockey.log'], stdout=subprocess.PIPE)
498+ process = subprocess.Popen(['grep', 'ERROR', '/var/log/jockey.log'], universal_newlines=True)
499 stdout, stderr = process.communicate()
500- for err in stdout.split("\n"):
501+ for err in str(stdout).split("\n"):
502 m = re_dmesg_error.match(err)
503 if not m:
504 continue
505@@ -397,14 +397,14 @@
506 bak_path = safe_backup(self.__grub_config_filename)
507 if not bak_path:
508 # TODO: Display error message dialog
509- print "Error: Could not backup file %s. Changes not applied." %(
510- self.__grub_config_filename)
511+ print("Error: Could not backup file %s. Changes not applied." %(
512+ self.__grub_config_filename))
513 return
514- except IOError, err:
515+ except IOError as err:
516 # TODO: Display error message dialog
517- print "Error: Failure creating backup file for %s. Changes not applied." %(
518- self.__grub_config_filename)
519- print err
520+ print("Error: Failure creating backup file for %s. Changes not applied." %(
521+ self.__grub_config_filename))
522+ print(err)
523 return
524
525 # Move new file into place
526
527=== modified file 'xdiagnose/application.py'
528--- xdiagnose/application.py 2012-01-11 16:21:29 +0000
529+++ xdiagnose/application.py 2012-06-15 11:25:23 +0000
530@@ -1,4 +1,6 @@
531-#!/usr/bin/env python
532+#!/usr/bin/python3
533+
534+from __future__ import absolute_import, print_function, unicode_literals
535
536 import gtk
537
538
539=== modified file 'xdiagnose/config_update.py'
540--- xdiagnose/config_update.py 2012-03-17 02:45:04 +0000
541+++ xdiagnose/config_update.py 2012-06-15 11:25:23 +0000
542@@ -1,4 +1,6 @@
543-#!/usr/bin/python
544+#!/usr/bin/python3
545+
546+from __future__ import absolute_import, print_function, unicode_literals
547
548 import re
549 import sys
550@@ -88,21 +90,21 @@
551 '''filename is the input file. fileio is the output stream'''
552 keys = []
553 if override_params:
554- keys = override_params.keys()
555+ keys = list(override_params.keys())
556 if merge_params:
557- keys.extend(merge_params.keys())
558+ keys.extend(list(merge_params.keys()))
559 keys = list(set(keys))
560 keys.sort()
561
562- print filename
563+ print(filename)
564 for line in fileinput.input(filename):
565- print line
566+ print(line)
567 new_line = line
568
569 if merge_params is not None:
570- print "Merging parameters"
571+ print("Merging parameters")
572 for key in merge_params:
573- print " - %s" %(key)
574+ print(" - %s" %(key))
575 p = re.compile("^\s*"+key+"\s*"+delim+"\s*(\"?)(.*)(\"?)")
576 m = p.match(line)
577 if m:
578@@ -112,8 +114,8 @@
579 keys.remove(key)
580
581 if override_params is not None:
582- print "Overriding parameters"
583- for key in override_params.keys():
584+ print("Overriding parameters")
585+ for key in list(override_params.keys()):
586 p = re.compile("^\s*"+key+"\s*"+delim)
587 if p.match(line):
588 new_line = "%s%s%s\n" %(key, delim, override_params[key])
589@@ -124,7 +126,7 @@
590
591 # Handle case of parameters that weren't already present in the file
592 for key in keys:
593- print "Adding key %s" %(key)
594+ print("Adding key %s" %(key))
595 if override_params and key in override_params:
596 fileio.write("%s%s%s\n" %(key, delim, override_params[key]))
597 elif merge_params and key in merge_params:
598
599=== modified file 'xdiagnose/diagnostics.py'
600--- xdiagnose/diagnostics.py 2012-03-17 02:45:04 +0000
601+++ xdiagnose/diagnostics.py 2012-06-15 11:25:23 +0000
602@@ -1,4 +1,4 @@
603-#!/usr/bin/env python
604+#!/usr/bin/python3
605 # -*- coding: utf-8 -*-
606 #
607 # Copyright (C) 2010 Bryce Harrington <bryce@ubuntu.com>
608@@ -22,6 +22,7 @@
609 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
610 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
611
612+from __future__ import absolute_import, print_function, unicode_literals
613
614 class Diagnostic:
615 def __init__(self):
616@@ -36,7 +37,7 @@
617 def backup_xorg_conf(self):
618 # xorg_conf_backup="/etc/X11/xorg.conf-backup-${timestamp}"
619 # cp /etc/X11/xorg.conf ${xorg_conf_backup}
620- print "Your config could not be backed up."
621+ print("Your config could not be backed up.")
622 return False
623
624 def default_config(self):
625@@ -46,8 +47,8 @@
626 # rm /etc/X11/xorg.conf
627 #print "Failure restoring configuration to default."
628 #print "Your config has not been changed."
629- print "Your configuration has been restored to default and"
630- print "your old configuration backed up. Please restart."
631+ print("Your configuration has been restored to default and")
632+ print("your old configuration backed up. Please restart.")
633 return True
634
635 def run_xorgconf(self):
636@@ -55,7 +56,7 @@
637 return False
638
639 # Xorg :99 -configure
640- print "Could not generate a new configuration"
641+ print("Could not generate a new configuration")
642 return False
643
644 def view_xorg_log(self):
645@@ -68,7 +69,7 @@
646
647 def verify_xorgconf(self):
648 # Run Alberto's xorg.conf checker (once it's available in main)
649- print "Sorry, this option is not implemented yet"
650+ print("Sorry, this option is not implemented yet")
651 return False
652
653 def edit_config(self):
654@@ -117,36 +118,36 @@
655
656 def menu(self, level):
657 if level == "0":
658- print "Choice:"
659- print "1. Run in low-graphics mode for just one session"
660- print "2. Reconfigure graphics"
661- print "3. Troubleshoot the error"
662- print "4. Exit to console login"
663+ print("Choice:")
664+ print("1. Run in low-graphics mode for just one session")
665+ print("2. Reconfigure graphics")
666+ print("3. Troubleshoot the error")
667+ print("4. Exit to console login")
668
669 elif level == "1":
670 pass
671
672 elif level == "2":
673- print "Reconfiguration:"
674- print "How would you like to reconfigure your display?"
675- print "2a. Use default (generic) configuration"
676- print "2b. Create new configuration for this hardware"
677- print "2c. Use your backed-up configuration"
678+ print("Reconfiguration:")
679+ print("How would you like to reconfigure your display?")
680+ print("2a. Use default (generic) configuration")
681+ print("2b. Create new configuration for this hardware")
682+ print("2c. Use your backed-up configuration")
683
684 elif level == "3":
685- print "Troubleshooting:"
686- print "What information would you like to review?"
687- print "3a. Review the xserver log file"
688- print "3b. Review the startup errors"
689- print "3c. Edit configuration file"
690- print "3d. Archive configuration and logs"
691+ print("Troubleshooting:")
692+ print("What information would you like to review?")
693+ print("3a. Review the xserver log file")
694+ print("3b. Review the startup errors")
695+ print("3c. Edit configuration file")
696+ print("3d. Archive configuration and logs")
697
698 else:
699- print "xdiagnose walks you through troubleshooting a few common X errors."
700- print
701- print " * Screen blanks when lid is closed, and never comes back"
702- print " * 3D performance is horrible"
703- print " * Maximum resolution is lower than what screen can actually perform"
704+ print("xdiagnose walks you through troubleshooting a few common X errors.")
705+ print()
706+ print(" * Screen blanks when lid is closed, and never comes back")
707+ print(" * 3D performance is horrible")
708+ print(" * Maximum resolution is lower than what screen can actually perform")
709
710 def lid_close_blank(self):
711 # Examine kernel logs to see if there was any evidence of it
712
713=== modified file 'xdiagnose/edid.py'
714--- xdiagnose/edid.py 2012-05-22 19:24:10 +0000
715+++ xdiagnose/edid.py 2012-06-15 11:25:23 +0000
716@@ -1,4 +1,6 @@
717-#!/usr/bin/env python
718+#!/usr/bin/python3
719+
720+from __future__ import absolute_import, print_function, unicode_literals
721
722 import sys, os, re
723
724@@ -25,51 +27,51 @@
725 line = m.group(1)
726 edid += line
727
728-print "%20s %s" %("Header:", edid_bytes(edid,0,7))
729-print "%20s %s" %("Manufacturer:", edid_bytes(edid,8,9))
730-print "%20s %s" %("Product ID code:", edid_bytes(edid,10,11))
731-print "%20s %s" %("Serial Number:", edid_bytes(edid,12,15))
732-print "%20s %s" %("Week of Manufacture:", edid_bytes(edid,16))
733-print "%20s %s" %("Year of Manufactur:", edid_bytes(edid,17))
734-print "%20s %s" %("EDID Version:", edid_bytes(edid,18))
735-print "%20s %s" %("EDID Revision:", edid_bytes(edid,19))
736-
737-print "%20s %s" %("Video input def:", edid_bytes(edid,20))
738-print "%20s %s" %("Max Horiz Image(cm):", edid_bytes(edid,21))
739-print "%20s %s" %("Max Vert Image(cm):", edid_bytes(edid,22))
740-print "%20s %s" %("Gamma:", edid_bytes(edid,23))
741-print "%20s %s" %("Power management:", edid_bytes(edid,24))
742-
743-print "%20s %s" %("Chromaticity:", edid_bytes(edid,25,34))
744-print "%20s %s" %("Timing I:", edid_bytes(edid,35))
745-print "%20s %s" %("Timing II:", edid_bytes(edid,36))
746-print "%20s %s" %("Reserved Timing:", edid_bytes(edid,37))
747-print "%20s %s" %("Standard Timing:", edid_bytes(edid,38,53))
748-print "Descriptor Block 1"
749-print "%20s %s" %("Horiz Active (px):", edid_bytes(edid,56))
750-print "%20s %s" %("Horiz Blanking:", edid_bytes(edid,57))
751-print "%20s %s" %("Horiz high:", edid_bytes(edid,58))
752-print "%20s %s" %("Vert Active:", edid_bytes(edid,59))
753-print "%20s %s" %("Vert Blank:", edid_bytes(edid,60))
754-print "%20s %s" %("Vert high:", edid_bytes(edid,61))
755-print "%20s %s" %("Horz Sync Offset (px):", edid_bytes(edid,62))
756-print "%20s %s" %("Horiz Sync Pulse Width (px):", edid_bytes(edid,63))
757-print "%20s %s" %("Vert Sync (lines):", edid_bytes(edid,64))
758-print "%20s %s" %("high:", edid_bytes(edid,65))
759-print "%20s %s" %("Horiz Image Size (mm):", edid_bytes(edid,66))
760-print "%20s %s" %("Vert Image Size (mm):", edid_bytes(edid,67))
761-print "%20s %s" %("Image Size high:", edid_bytes(edid,68))
762-print "%20s %s" %("Horiz Border:", edid_bytes(edid,69))
763-print "%20s %s" %("Vert Border:", edid_bytes(edid,70))
764-print "%20s %s" %("Interlacing:", edid_bytes(edid,71))
765-print "Descriptor Block 2"
766-print "%20s %s" %("Descriptor Block 2:", edid_bytes(edid,72,89))
767-print "Descriptor Block 3"
768-print "%20s %s" %("Descriptor Block 3:", edid_bytes(edid,90,107))
769-print "Descriptor Block 4"
770-print "%20s %s" %("Descriptor Block 4:", edid_bytes(edid,108,125))
771-print "%20s %s" %("Extension Flag:", edid_bytes(edid,126))
772-print "%20s %s" %("Checksum:", edid_bytes(edid,127))
773+print("%20s %s" %("Header:", edid_bytes(edid,0,7)))
774+print("%20s %s" %("Manufacturer:", edid_bytes(edid,8,9)))
775+print("%20s %s" %("Product ID code:", edid_bytes(edid,10,11)))
776+print("%20s %s" %("Serial Number:", edid_bytes(edid,12,15)))
777+print("%20s %s" %("Week of Manufacture:", edid_bytes(edid,16)))
778+print("%20s %s" %("Year of Manufactur:", edid_bytes(edid,17)))
779+print("%20s %s" %("EDID Version:", edid_bytes(edid,18)))
780+print("%20s %s" %("EDID Revision:", edid_bytes(edid,19)))
781+
782+print("%20s %s" %("Video input def:", edid_bytes(edid,20)))
783+print("%20s %s" %("Max Horiz Image(cm):", edid_bytes(edid,21)))
784+print("%20s %s" %("Max Vert Image(cm):", edid_bytes(edid,22)))
785+print("%20s %s" %("Gamma:", edid_bytes(edid,23)))
786+print("%20s %s" %("Power management:", edid_bytes(edid,24)))
787+
788+print("%20s %s" %("Chromaticity:", edid_bytes(edid,25,34)))
789+print("%20s %s" %("Timing I:", edid_bytes(edid,35)))
790+print("%20s %s" %("Timing II:", edid_bytes(edid,36)))
791+print("%20s %s" %("Reserved Timing:", edid_bytes(edid,37)))
792+print("%20s %s" %("Standard Timing:", edid_bytes(edid,38,53)))
793+print("Descriptor Block 1")
794+print("%20s %s" %("Horiz Active (px):", edid_bytes(edid,56)))
795+print("%20s %s" %("Horiz Blanking:", edid_bytes(edid,57)))
796+print("%20s %s" %("Horiz high:", edid_bytes(edid,58)))
797+print("%20s %s" %("Vert Active:", edid_bytes(edid,59)))
798+print("%20s %s" %("Vert Blank:", edid_bytes(edid,60)))
799+print("%20s %s" %("Vert high:", edid_bytes(edid,61)))
800+print("%20s %s" %("Horz Sync Offset (px):", edid_bytes(edid,62)))
801+print("%20s %s" %("Horiz Sync Pulse Width (px):", edid_bytes(edid,63)))
802+print("%20s %s" %("Vert Sync (lines):", edid_bytes(edid,64)))
803+print("%20s %s" %("high:", edid_bytes(edid,65)))
804+print("%20s %s" %("Horiz Image Size (mm):", edid_bytes(edid,66)))
805+print("%20s %s" %("Vert Image Size (mm):", edid_bytes(edid,67)))
806+print("%20s %s" %("Image Size high:", edid_bytes(edid,68)))
807+print("%20s %s" %("Horiz Border:", edid_bytes(edid,69)))
808+print("%20s %s" %("Vert Border:", edid_bytes(edid,70)))
809+print("%20s %s" %("Interlacing:", edid_bytes(edid,71)))
810+print("Descriptor Block 2")
811+print("%20s %s" %("Descriptor Block 2:", edid_bytes(edid,72,89)))
812+print("Descriptor Block 3")
813+print("%20s %s" %("Descriptor Block 3:", edid_bytes(edid,90,107)))
814+print("Descriptor Block 4")
815+print("%20s %s" %("Descriptor Block 4:", edid_bytes(edid,108,125)))
816+print("%20s %s" %("Extension Flag:", edid_bytes(edid,126)))
817+print("%20s %s" %("Checksum:", edid_bytes(edid,127)))
818
819
820
821
822=== modified file 'xdiagnose/errors_treeview.py'
823--- xdiagnose/errors_treeview.py 2012-03-16 06:25:58 +0000
824+++ xdiagnose/errors_treeview.py 2012-06-15 11:25:23 +0000
825@@ -1,4 +1,6 @@
826-#!/usr/bin/env python
827+#!/usr/bin/python3
828+
829+from __future__ import absolute_import, print_function, unicode_literals
830
831 # example basictreeview.py
832
833
834=== modified file 'xdiagnose/info.py'
835--- xdiagnose/info.py 2012-03-16 06:34:29 +0000
836+++ xdiagnose/info.py 2012-06-15 11:25:23 +0000
837@@ -1,6 +1,8 @@
838-#!/usr/bin/env python
839+#!/usr/bin/python3
840 # -*- coding: utf-8 -*-
841
842+from __future__ import absolute_import, print_function, unicode_literals
843+
844 '''High level package information'''
845 PROGNAME = 'xdiagnose'
846 URL = 'http://launchpad.net/xdiagnose'
847@@ -65,12 +67,12 @@
848
849
850 if __name__ == "__main__":
851- print PROGNAME, VERSION, URL
852- print "Copyright (C) %s %s <%s>" % (
853- DATE_COPYRIGHT, LEAD_DEVELOPER.name, LEAD_DEVELOPER.email)
854- print
855+ print(PROGNAME, VERSION, URL)
856+ print("Copyright (C) %s %s <%s>" % (
857+ DATE_COPYRIGHT, LEAD_DEVELOPER.name, LEAD_DEVELOPER.email))
858+ print()
859 for contributor in CONTRIBUTORS:
860- print "%s %s %s" % (
861+ print("%s %s %s" % (
862 contributor.name,
863 contributor.display_email,
864- contributor.display_roles)
865+ contributor.display_roles))
866
867=== modified file 'xdiagnose/pci_devices.py'
868--- xdiagnose/pci_devices.py 2012-04-05 01:06:49 +0000
869+++ xdiagnose/pci_devices.py 2012-06-15 11:25:23 +0000
870@@ -1,4 +1,6 @@
871-#!/usr/bin/python
872+#!/usr/bin/python3
873+
874+from __future__ import absolute_import, print_function, unicode_literals
875
876 import re
877
878@@ -1057,8 +1059,8 @@
879 """
880
881 for device in get_pci_devices(pci_text):
882- print device.name, device.supported, ','.join(device.drivers)
883+ print(device.name, device.supported, ','.join(device.drivers))
884
885 pci_text = Popen('lspci -vvnn', stdout=PIPE, shell=True).stdout.read()
886 for device in get_pci_devices(pci_text):
887- print device.name, device.supported, ','.join(device.drivers)
888+ print(device.name, device.supported, ','.join(device.drivers))
889
890=== modified file 'xdiagnose/utils/dates.py'
891--- xdiagnose/utils/dates.py 2012-03-17 02:45:04 +0000
892+++ xdiagnose/utils/dates.py 2012-06-15 11:25:23 +0000
893@@ -1,4 +1,6 @@
894-#!/usr/bin/env python
895+#!/usr/bin/python3
896+
897+from __future__ import absolute_import, print_function, unicode_literals
898
899 from datetime import (
900 datetime,
901@@ -41,10 +43,10 @@
902 return tsec
903
904 if __name__ == '__main__':
905- print week_start()
906+ print(week_start())
907
908 td = timedelta(days=10, seconds=2.999)
909 dt = datetime.today() - td
910- print week_start(dt)
911+ print(week_start(dt))
912
913- print "%d == %d\n" %(total_seconds(td), td.total_seconds())
914+ print("%d == %d\n" %(total_seconds(td), td.total_seconds()))
915
916=== modified file 'xdiagnose/utils/debug.py'
917--- xdiagnose/utils/debug.py 2012-03-17 02:45:04 +0000
918+++ xdiagnose/utils/debug.py 2012-06-15 11:25:23 +0000
919@@ -1,4 +1,6 @@
920-#!/usr/bin/env python
921+#!/usr/bin/python3
922+
923+from __future__ import absolute_import, print_function, unicode_literals
924
925 import sys
926
927
928=== modified file 'xdiagnose/utils/execute.py'
929--- xdiagnose/utils/execute.py 2012-03-17 02:45:04 +0000
930+++ xdiagnose/utils/execute.py 2012-06-15 11:25:23 +0000
931@@ -1,4 +1,6 @@
932-#!/usr/bin/env python
933+#!/usr/bin/python3
934+
935+from __future__ import absolute_import, print_function, unicode_literals
936
937 from subprocess import Popen, PIPE
938 def execute(cmd):
939
940=== modified file 'xdiagnose/utils/math.py'
941--- xdiagnose/utils/math.py 2012-03-17 02:45:04 +0000
942+++ xdiagnose/utils/math.py 2012-06-15 11:25:23 +0000
943@@ -1,4 +1,6 @@
944-#!/usr/bin/env python
945+#!/usr/bin/python3
946+
947+from __future__ import absolute_import, print_function, unicode_literals
948
949 def clamp(x, low, high):
950 """
951
952=== modified file 'xdiagnose/utils/option_handler.py'
953--- xdiagnose/utils/option_handler.py 2012-03-17 02:45:04 +0000
954+++ xdiagnose/utils/option_handler.py 2012-06-15 11:25:23 +0000
955@@ -1,6 +1,8 @@
956-#!/usr/bin/env python
957+#!/usr/bin/python3
958 # -*- coding: utf-8 -*-
959
960+from __future__ import absolute_import, print_function, unicode_literals
961+
962 '''Command line options'''
963
964 from optparse import OptionParser
965
966=== modified file 'xdiagnose/utils/paths.py'
967--- xdiagnose/utils/paths.py 2012-03-17 02:45:04 +0000
968+++ xdiagnose/utils/paths.py 2012-06-15 11:25:23 +0000
969@@ -1,4 +1,6 @@
970-#!/usr/bin/env python
971+#!/usr/bin/python3
972+
973+from __future__ import absolute_import, print_function, unicode_literals
974
975 from os.path import (
976 relpath,
977@@ -20,4 +22,4 @@
978
979
980 if __name__ == "__main__":
981- print find_datadir('xdiagnose')
982+ print(find_datadir('xdiagnose'))
983
984=== modified file 'xdiagnose/utils/screen.py'
985--- xdiagnose/utils/screen.py 2012-03-17 02:45:04 +0000
986+++ xdiagnose/utils/screen.py 2012-06-15 11:25:23 +0000
987@@ -1,4 +1,6 @@
988-#!/usr/bin/env python
989+#!/usr/bin/python3
990+
991+from __future__ import absolute_import, print_function, unicode_literals
992
993 from gi.repository.Gdk import Screen
994
995@@ -13,6 +15,6 @@
996
997 if __name__ == "__main__":
998 if X_is_running():
999- print "X is running"
1000+ print("X is running")
1001 else:
1002- print "X is not running"
1003+ print("X is not running")
1004
1005=== modified file 'xdiagnose/utils/text.py'
1006--- xdiagnose/utils/text.py 2012-03-17 02:45:04 +0000
1007+++ xdiagnose/utils/text.py 2012-06-15 11:25:23 +0000
1008@@ -1,4 +1,6 @@
1009-#!/usr/bin/env python
1010+#!/usr/bin/python3
1011+
1012+from __future__ import absolute_import, print_function, unicode_literals
1013
1014 def quote(msg):
1015 """
1016
1017=== modified file 'xdiagnose/welcome.py'
1018--- xdiagnose/welcome.py 2012-03-17 02:45:04 +0000
1019+++ xdiagnose/welcome.py 2012-06-15 11:25:23 +0000
1020@@ -1,4 +1,6 @@
1021-#!/usr/bin/env python
1022+#!/usr/bin/python3
1023+
1024+from __future__ import absolute_import, print_function, unicode_literals
1025
1026 import os
1027 import gtk
1028@@ -8,9 +10,9 @@
1029 from gettext import gettext as _
1030 gettext.textdomain('xdiagnose')
1031
1032-from application import Application
1033-from utils.debug import dbg
1034-from utils.execute import execute
1035+from .application import Application
1036+from .utils.debug import dbg
1037+from .utils.execute import execute
1038
1039
1040 class XDiagnoseApplication(Application):

Subscribers

People subscribed via source and target branches