[arch-commits] Commit in sugar-toolkit-gtk3/trunk (PKGBUILD six.patch)
Balló György
bgyorgy at archlinux.org
Wed Jun 19 11:00:28 UTC 2019
Date: Wednesday, June 19, 2019 @ 11:00:27
Author: bgyorgy
Revision: 482333
upgpkg: sugar-toolkit-gtk3 0.114-1
Update to new version
Modified:
sugar-toolkit-gtk3/trunk/PKGBUILD
Deleted:
sugar-toolkit-gtk3/trunk/six.patch
-----------+
PKGBUILD | 25
six.patch | 2987 ------------------------------------------------------------
2 files changed, 9 insertions(+), 3003 deletions(-)
Modified: PKGBUILD
===================================================================
--- PKGBUILD 2019-06-19 10:46:00 UTC (rev 482332)
+++ PKGBUILD 2019-06-19 11:00:27 UTC (rev 482333)
@@ -1,8 +1,8 @@
# Maintainer: Balló György <ballogyor+arch at gmail dot com>
pkgname=sugar-toolkit-gtk3
-pkgver=0.113
-pkgrel=2
+pkgver=0.114
+pkgrel=1
pkgdesc="Sugar GTK library"
arch=('x86_64')
url="https://sugarlabs.org/"
@@ -11,16 +11,14 @@
'python2-telepathy' 'sugar-artwork' 'sugar-datastore' 'telepathy-mission-control' 'unzip')
makedepends=('intltool' 'gobject-introspection')
optdepends=('webkit2gtk: run sugar-activity-web')
-source=(https://download.sugarlabs.org/sources/sucrose/glucose/$pkgname/$pkgname-$pkgver.tar.xz
- six.patch)
-sha256sums=('4062d981d551f1567d073389385ffc28793b75f0ed2485e8f9250a145239cba7'
- '3adf9d6ddc817c31887f1c22e9976d9865ca17c608a5142ef97ffbd8c0de3424')
+source=(https://download.sugarlabs.org/sources/sucrose/glucose/$pkgname/$pkgname-$pkgver.tar.xz)
+sha256sums=('4b8ca467b85b6273fdb3ae86b1afa5071f4c0c6e11a27e9166a394620c2c77e5')
prepare() {
cd $pkgname-$pkgver
- # Revert 'Port from Python 2 to six', it's not complete yet
- patch -RNp1 -i ../six.patch
- autoreconf -fi
+ # Don't use incomplete python3 port
+ sed -i 's/exec sugar-activity3/exec sugar-activity/' bin/sugar-activity-web
+ sed -i '/dist_bin_SCRIPTS/ s/ sugar-activity3//' bin/Makefile.{am,in}
}
build() {
@@ -30,14 +28,9 @@
export CFLAGS=${CFLAGS/ -fno-plt}
export LDFLAGS=${LDFLAGS/,-z,now}
- # Don't use incomplete python3 port
- sed -i 's/PYTHON=python3/PYTHON=python2/' configure
- sed -i 's/exec sugar-activity3/exec sugar-activity/' bin/sugar-activity-web
- sed -i '/dist_bin_SCRIPTS/ s/ sugar-activity3//' bin/Makefile.in
-
- ./configure --prefix=/usr
+ ./configure --prefix=/usr PYTHON=python2
sed -i 's/ -shared / -Wl,-O1,--as-needed\0/g' libtool
- make
+ make -j1
}
package() {
Deleted: six.patch
===================================================================
--- six.patch 2019-06-19 10:46:00 UTC (rev 482332)
+++ six.patch 2019-06-19 11:00:27 UTC (rev 482333)
@@ -1,2987 +0,0 @@
-From aa8a5e70c415e6c2acf4ff373d9b366ac4692bb1 Mon Sep 17 00:00:00 2001
-From: Pro-Panda <f2016015 at pilani.bits-pilani.ac.in>
-Date: Thu, 1 Mar 2018 17:28:56 +0530
-Subject: [PATCH] Port from Python 2 to six
-
-Signed-off-by: James Cameron <quozl at laptop.org>
----
- Makefile.am | 2 +-
- bin/Makefile.am | 2 +-
- bin/sugar-activity | 218 +----------------
- bin/sugar-activity-web | 4 +-
- bin/sugar-activity3 | 5 +
- configure.ac | 2 +-
- doc/conf.py | 26 +-
- examples/alert.py | 6 +-
- examples/animator.py | 2 +-
- examples/colorbutton.py | 2 +-
- examples/combobox.py | 2 +-
- examples/customdestroy.py | 6 +-
- examples/gtktreesensitive.py | 2 +-
- examples/iconentry.py | 4 +-
- examples/radiotoolbutton.py | 2 +-
- examples/scrollingdetector.py | 6 +-
- examples/tabs.py | 2 +-
- examples/toolbutton.py | 2 +-
- src/sugar3/activity/Makefile.am | 1 +
- src/sugar3/activity/activity.py | 34 +--
- src/sugar3/activity/activityfactory.py | 13 +-
- src/sugar3/activity/activityhandle.py | 14 +-
- src/sugar3/activity/activityinstance.py | 222 ++++++++++++++++++
- src/sugar3/activity/activityservice.py | 2 +-
- src/sugar3/activity/bundlebuilder.py | 44 ++--
- src/sugar3/activity/webkit1.py | 8 +-
- src/sugar3/activity/widgets.py | 2 +-
- src/sugar3/bundle/__init__.py | 6 +-
- src/sugar3/bundle/activitybundle.py | 4 +-
- src/sugar3/bundle/bundle.py | 10 +-
- src/sugar3/bundle/bundleversion.py | 1 +
- src/sugar3/bundle/contentbundle.py | 7 +-
- src/sugar3/datastore/datastore.py | 17 +-
- src/sugar3/dispatch/dispatcher.py | 20 +-
- src/sugar3/dispatch/saferef.py | 48 ++--
- src/sugar3/env.py | 4 +-
- src/sugar3/graphics/Makefile.am | 1 -
- src/sugar3/graphics/alert.py | 22 +-
- src/sugar3/graphics/colorbutton.py | 42 ++--
- src/sugar3/graphics/icon.py | 21 +-
- src/sugar3/graphics/iconentry.py | 2 +-
- src/sugar3/graphics/objectchooser.py | 24 +-
- src/sugar3/graphics/palettegroup.py | 2 +-
- src/sugar3/graphics/palettemenu.py | 2 +-
- src/sugar3/graphics/palettewindow.py | 14 +-
- src/sugar3/graphics/popwindow.py | 202 ----------------
- src/sugar3/graphics/progressicon.py | 1 +
- src/sugar3/graphics/scrollingdetector.py | 12 +-
- src/sugar3/graphics/style.py | 5 +-
- src/sugar3/graphics/toolbarbox.py | 2 +
- src/sugar3/graphics/toolbox.py | 14 +-
- src/sugar3/graphics/toolbutton.py | 2 +-
- src/sugar3/graphics/tray.py | 4 +
- src/sugar3/graphics/xocolor.py | 24 +-
- src/sugar3/logger.py | 25 +-
- src/sugar3/mime.py | 8 +-
- src/sugar3/network.py | 24 +-
- src/sugar3/presence/activity.py | 24 +-
- src/sugar3/presence/buddy.py | 16 +-
- src/sugar3/presence/connectionmanager.py | 6 +-
- src/sugar3/presence/presenceservice.py | 7 +-
- src/sugar3/presence/tubeconn.py | 7 +-
- src/sugar3/profile.py | 3 +-
- src/sugar3/speech.py | 9 +-
- src/sugar3/test/Makefile.am | 2 +-
- src/sugar3/test/{unittest.py => _unittest.py} | 10 +-
- src/sugar3/test/discover.py | 2 -
- src/sugar3/test/uitree.py | 2 +-
- src/sugar3/util.py | 20 +-
- .../sample.activity/activity/activity.info | 2 +-
- tests/data/sample.activity/setup.py | 2 +-
- tests/graphics/progressicon.py | 1 +
- tests/test_mime.py | 2 +-
- tests/test_uitree.py | 3 +-
- 74 files changed, 623 insertions(+), 700 deletions(-)
- create mode 100755 bin/sugar-activity3
- create mode 100644 src/sugar3/activity/activityinstance.py
- delete mode 100644 src/sugar3/graphics/popwindow.py
- rename src/sugar3/test/{unittest.py => _unittest.py} (93%)
-
-diff --git a/Makefile.am b/Makefile.am
-index 70ed1a8ff..d89c4a61b 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -26,4 +26,4 @@ check-po:
- test: check-po
- pyflakes $(top_srcdir)
- pep8 $(top_srcdir)
-- python -m sugar3.test.discover $(top_srcdir)/tests
-+ python3 -m sugar3.test.discover $(top_srcdir)/tests
-diff --git a/bin/Makefile.am b/bin/Makefile.am
-index 2d214b3cc..3b5f6f8f8 100644
---- a/bin/Makefile.am
-+++ b/bin/Makefile.am
-@@ -1 +1 @@
--dist_bin_SCRIPTS = sugar-activity sugar-activity-web
-+dist_bin_SCRIPTS = sugar-activity sugar-activity-web sugar-activity3
-diff --git a/bin/sugar-activity b/bin/sugar-activity
-index a184655ae..9e12d61ae 100755
---- a/bin/sugar-activity
-+++ b/bin/sugar-activity
-@@ -1,219 +1,5 @@
- #!/usr/bin/env python2
-
--# Copyright (C) 2006-2008, Red Hat, Inc.
--#
--# This program is free software; you can redistribute it and/or modify
--# it under the terms of the GNU General Public License as published by
--# the Free Software Foundation; either version 2 of the License, or
--# (at your option) any later version.
--#
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--# GNU General Public License for more details.
--#
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+from sugar3.activity import activityinstance
-
--import os
--import sys
--
--# Change the default encoding to avoid UnicodeDecodeError
--# http://lists.sugarlabs.org/archive/sugar-devel/2012-August/038928.html
--reload(sys)
--sys.setdefaultencoding('utf-8')
--
--import gettext
--from optparse import OptionParser
--
--import dbus
--import dbus.service
--from dbus.mainloop.glib import DBusGMainLoop
--DBusGMainLoop(set_as_default=True)
--
--from sugar3.activity import activityhandle
--from sugar3 import config
--from sugar3.bundle.activitybundle import ActivityBundle
--from sugar3 import logger
--
--from sugar3.bundle.bundle import MalformedBundleException
--
--from distutils.dir_util import mkpath
--import time
--import hashlib
--import random
--
--def create_activity_instance(constructor, handle):
-- activity = constructor(handle)
-- activity.show()
-- return activity
--
--
--def get_single_process_name(bundle_id):
-- return bundle_id
--
--
--def get_single_process_path(bundle_id):
-- return '/' + bundle_id.replace('.', '/')
--
--
--class SingleProcess(dbus.service.Object):
--
-- def __init__(self, name_service, constructor):
-- self.constructor = constructor
--
-- bus = dbus.SessionBus()
-- bus_name = dbus.service.BusName(name_service, bus=bus)
-- object_path = get_single_process_path(name_service)
-- dbus.service.Object.__init__(self, bus_name, object_path)
--
-- @dbus.service.method('org.laptop.SingleProcess', in_signature='a{sv}')
-- def create(self, handle_dict):
-- handle = activityhandle.create_from_dict(handle_dict)
-- create_activity_instance(self.constructor, handle)
--
--
--def main():
-- usage = 'usage: %prog [options] [activity dir] [python class]'
-- epilog = 'If you are running from a directory containing an Activity, ' \
-- 'the argument may be omitted. Otherwise please provide either '\
-- 'a directory containing a Sugar Activity [activity dir], a '\
-- '[python_class], or both.'
--
-- parser = OptionParser(usage=usage, epilog=epilog)
-- parser.add_option('-b', '--bundle-id', dest='bundle_id',
-- help='identifier of the activity bundle')
-- parser.add_option('-a', '--activity-id', dest='activity_id',
-- help='identifier of the activity instance')
-- parser.add_option('-o', '--object-id', dest='object_id',
-- help='identifier of the associated datastore object')
-- parser.add_option('-u', '--uri', dest='uri',
-- help='URI to load')
-- parser.add_option('-s', '--single-process', dest='single_process',
-- action='store_true',
-- help='start all the instances in the same process')
-- parser.add_option('-i', '--invited', dest='invited',
-- action='store_true', default=False,
-- help='the activity is being launched for handling an '
-- 'invite from the network')
-- (options, args) = parser.parse_args()
--
-- logger.start()
--
-- activity_class = None
-- if len(args) == 2:
-- activity_class = args[1]
-- os.chdir(args[0])
-- elif len(args) == 1:
-- if os.path.isdir(args[0]):
-- os.chdir(args[0])
-- else:
-- activity_class = args[0]
--
-- os.environ['SUGAR_BUNDLE_PATH'] = os.path.abspath(os.curdir)
--
-- bundle_path = os.environ['SUGAR_BUNDLE_PATH']
-- sys.path.insert(0, bundle_path)
--
-- try:
-- bundle = ActivityBundle(bundle_path)
-- except MalformedBundleException:
-- parser.print_help()
-- exit(0)
--
-- if not activity_class:
-- if bundle.get_command().startswith('sugar-activity'):
-- activity_class = bundle.get_command().split(" ")[1]
--
-- if 'SUGAR_VERSION' not in os.environ:
-- profile_id = os.environ.get('SUGAR_PROFILE', 'default')
-- home_dir = os.environ.get('SUGAR_HOME', os.path.expanduser('~/.sugar'))
-- base = os.path.join(home_dir, profile_id)
-- activity_root = os.path.join(base, bundle.get_bundle_id())
--
-- instance_dir = os.path.join(activity_root, 'instance')
-- mkpath(instance_dir)
--
-- data_dir = os.path.join(activity_root, 'data')
-- mkpath(data_dir)
--
-- tmp_dir = os.path.join(activity_root, 'tmp')
-- mkpath(tmp_dir)
--
-- os.environ['SUGAR_ACTIVITY_ROOT'] = activity_root
-- os.environ['SUGAR_BUNDLE_PATH'] = bundle.get_path()
--
-- os.environ['SUGAR_BUNDLE_ID'] = bundle.get_bundle_id()
-- os.environ['SUGAR_BUNDLE_NAME'] = bundle.get_name()
-- os.environ['SUGAR_BUNDLE_VERSION'] = str(bundle.get_activity_version())
--
-- # must be done early, some activities set translations globally, SL #3654
-- activity_locale_path = os.environ.get("SUGAR_LOCALEDIR",
-- config.locale_path)
--
-- gettext.bindtextdomain(bundle.get_bundle_id(), activity_locale_path)
-- gettext.bindtextdomain('sugar-toolkit-gtk3', config.locale_path)
-- gettext.textdomain(bundle.get_bundle_id())
--
-- splitted_module = activity_class.rsplit('.', 1)
-- module_name = splitted_module[0]
-- class_name = splitted_module[1]
--
-- module = __import__(module_name)
-- for comp in module_name.split('.')[1:]:
-- module = getattr(module, comp)
--
-- activity_constructor = getattr(module, class_name)
--
-- if not options.activity_id:
-- # Generate random hash
-- data = '%s%s' % (time.time(), random.randint(10000, 100000))
-- random_hash = hashlib.sha1(data).hexdigest()
-- options.activity_id = random_hash
-- options.bundle_id = bundle.get_bundle_id()
--
-- activity_handle = activityhandle.ActivityHandle(
-- activity_id=options.activity_id,
-- object_id=options.object_id, uri=options.uri,
-- invited=options.invited)
--
-- if options.single_process is True:
-- sessionbus = dbus.SessionBus()
--
-- service_name = get_single_process_name(options.bundle_id)
-- service_path = get_single_process_path(options.bundle_id)
--
-- bus_object = sessionbus.get_object(
-- 'org.freedesktop.DBus', '/org/freedesktop/DBus')
-- try:
-- name = bus_object.GetNameOwner(
-- service_name, dbus_interface='org.freedesktop.DBus')
-- except dbus.DBusException:
-- name = None
--
-- if not name:
-- SingleProcess(service_name, activity_constructor)
-- else:
-- try:
-- single_process = sessionbus.get_object(service_name,
-- service_path)
-- single_process.create(
-- activity_handle.get_dict(),
-- dbus_interface='org.laptop.SingleProcess')
--
-- print 'Created %s in a single process.' % service_name
-- sys.exit(0)
-- except (TypeError, dbus.DBusException):
-- print 'Could not communicate with the instance process,' \
-- 'launching a new process'
--
-- if hasattr(module, 'start'):
-- module.start()
--
-- instance = create_activity_instance(activity_constructor, activity_handle)
--
-- if hasattr(instance, 'run_main_loop'):
-- instance.run_main_loop()
--
--main()
-+activityinstance.main()
-diff --git a/bin/sugar-activity-web b/bin/sugar-activity-web
-index b204b3e69..8fd7a59ce 100644
---- a/bin/sugar-activity-web
-+++ b/bin/sugar-activity-web
-@@ -18,7 +18,7 @@
- # Boston, MA 02111-1307, USA.
-
- if [ "$SUGAR_USE_WEBKIT1" = "yes" ]; then
-- exec sugar-activity sugar3.activity.webkit1.WebActivity $@
-+ exec sugar-activity3 sugar3.activity.webkit1.WebActivity $@
- else
-- exec sugar-activity sugar3.activity.webactivity.WebActivity $@
-+ exec sugar-activity3 sugar3.activity.webactivity.WebActivity $@
- fi
-diff --git a/bin/sugar-activity3 b/bin/sugar-activity3
-new file mode 100755
-index 000000000..6798bc328
---- /dev/null
-+++ b/bin/sugar-activity3
-@@ -0,0 +1,5 @@
-+#!/usr/bin/env python3
-+
-+from sugar3.activity import activityinstance
-+
-+activityinstance.main()
-diff --git a/configure.ac b/configure.ac
-index e0cfdc6d7..e28e4b310 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -15,7 +15,7 @@ GNOME_COMPILE_WARNINGS(maximum)
-
- AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal])
-
--PYTHON=python2
-+PYTHON=python3
- AM_PATH_PYTHON
-
- PKG_CHECK_MODULES(EXT, gtk+-3.0 gdk-3.0 gdk-pixbuf-2.0 sm ice alsa
-diff --git a/src/sugar3/activity/Makefile.am b/src/sugar3/activity/Makefile.am
-index ace612e96..e3cf05bcd 100644
---- a/src/sugar3/activity/Makefile.am
-+++ b/src/sugar3/activity/Makefile.am
-@@ -2,6 +2,7 @@ sugardir = $(pythondir)/sugar3/activity
- sugar_PYTHON = \
- __init__.py \
- activity.py \
-+ activityinstance.py \
- activityfactory.py \
- activityhandle.py \
- activityservice.py \
-diff --git a/src/sugar3/activity/activity.py b/src/sugar3/activity/activity.py
-index fdb7db01a..0fbd1de4f 100644
---- a/src/sugar3/activity/activity.py
-+++ b/src/sugar3/activity/activity.py
-@@ -158,6 +158,7 @@ class MySpecialToolbar(Gtk.Toolbar):
- You may copy it and use it as a template.
- '''
-
-+import six
- import gettext
- import logging
- import os
-@@ -165,7 +166,6 @@ class MySpecialToolbar(Gtk.Toolbar):
- import time
- from hashlib import sha1
- from functools import partial
--import StringIO
- import cairo
- import json
-
-@@ -206,7 +206,9 @@ class MySpecialToolbar(Gtk.Toolbar):
-
- from gi.repository import SugarExt
-
--_ = lambda msg: gettext.dgettext('sugar-toolkit-gtk3', msg)
-+
-+def _(msg): return gettext.dgettext('sugar-toolkit-gtk3', msg)
-+
-
- SCOPE_PRIVATE = 'private'
- SCOPE_INVITE_ONLY = 'invite' # shouldn't be shown in UI, it's implicit
-@@ -881,7 +883,7 @@ def get_preview(self):
- cr.set_source_surface(screenshot_surface)
- cr.paint()
-
-- preview_str = StringIO.StringIO()
-+ preview_str = six.BytesIO()
- preview_surface.write_to_png(preview_str)
- return preview_str.getvalue()
-
-@@ -919,7 +921,7 @@ def save(self):
-
- buddies_dict = self._get_buddies()
- if buddies_dict:
-- self.metadata['buddies_id'] = json.dumps(buddies_dict.keys())
-+ self.metadata['buddies_id'] = json.dumps(list(buddies_dict.keys()))
- self.metadata['buddies'] = json.dumps(self._get_buddies())
-
- # update spent time before saving
-@@ -1103,8 +1105,9 @@ def share(self, private=False):
- raise RuntimeError('Activity %s already shared.' %
- self._activity_id)
- verb = private and 'private' or 'public'
-- logging.debug('Requesting %s share of activity %s.' % (verb,
-- self._activity_id))
-+ logging.debug(
-+ 'Requesting %s share of activity %s.' %
-+ (verb, self._activity_id))
- pservice = presenceservice.get_instance()
- pservice.connect('activity-shared', self.__share_cb)
- pservice.share_activity(self, private=private)
-@@ -1197,8 +1200,8 @@ def __stop_dialog_response_cb(self, alert, response_id):
- if response_id == Gtk.ResponseType.OK:
- title = alert.entry.get_text()
- if self._is_resumed and \
-- title == self._original_title:
-- datastore.delete(self._jobject_old.get_object_id())
-+ title == self._original_title:
-+ datastore.delete(self._jobject_old.get_object_id())
- self._jobject.metadata['title'] = title
- self._do_close(False)
-
-@@ -1222,7 +1225,7 @@ def _get_save_label_tip(self, title):
- label = _('Save new')
- tip = _('Save a new journal entry')
- if self._is_resumed and \
-- title == self._original_title:
-+ title == self._original_title:
- label = _('Save')
- tip = _('Save into the old journal entry')
-
-@@ -1244,7 +1247,7 @@ def _prepare_close(self, skip_save=False):
- if not skip_save:
- try:
- self.save()
-- except:
-+ except BaseException:
- # pylint: disable=W0702
- logging.exception('Error saving activity object to datastore')
- self._show_keep_failed_dialog()
-@@ -1306,12 +1309,12 @@ def close(self, skip_save=False):
-
- def __realize_cb(self, window):
- display_name = Gdk.Display.get_default().get_name()
-- if ':' in display_name:
-+ if ':' in display_name:
- # X11 for sure; this only works in X11
- xid = window.get_window().get_xid()
- SugarExt.wm_set_bundle_id(xid, self.get_bundle_id())
- SugarExt.wm_set_activity_id(xid, str(self._activity_id))
-- elif display_name is 'Broadway':
-+ elif display_name is 'Broadway':
- # GTK3's HTML5 backend
- # This is needed so that the window takes the whole browser window
- self.maximize()
-@@ -1432,7 +1435,7 @@ def __get_filters_cb(self):
- }
- filter_dict = dbus.Dictionary(filters, signature='sv')
- logging.debug('__get_filters_cb %r' % dbus.Array([filter_dict],
-- signature='a{sv}'))
-+ signature='a{sv}'))
- return dbus.Array([filter_dict], signature='a{sv}')
-
- @dbus.service.method(dbus_interface=CLIENT_HANDLER,
-@@ -1448,9 +1451,10 @@ def HandleChannels(self, account, connection, channels, requests_satisfied,
- handle_type = properties[CHANNEL + '.TargetHandleType']
- if channel_type == CHANNEL_TYPE_TEXT:
- self._got_channel_cb(connection, object_path, handle_type)
-- except Exception, e:
-+ except Exception as e:
- logging.exception(e)
-
-+
- _session = None
-
-
-@@ -1503,7 +1507,7 @@ def get_activity_root():
- activity_root = env.get_profile_path(os.environ['SUGAR_BUNDLE_ID'])
- try:
- os.mkdir(activity_root)
-- except OSError, e:
-+ except OSError as e:
- if e.errno != EEXIST:
- raise e
- return activity_root
-diff --git a/src/sugar3/activity/activityfactory.py b/src/sugar3/activity/activityfactory.py
-index 31895a5d1..b46ecceb0 100644
---- a/src/sugar3/activity/activityfactory.py
-+++ b/src/sugar3/activity/activityfactory.py
-@@ -23,7 +23,6 @@
- """
-
- import logging
--
- import dbus
- from gi.repository import GObject
- from gi.repository import GLib
-@@ -53,7 +52,7 @@
-
-
- def _close_fds():
-- for i in xrange(3, MAXFD):
-+ for i in range(3, MAXFD):
- try:
- os.close(i)
- # pylint: disable=W0704
-@@ -69,7 +68,7 @@ def create_activity_id():
- def _mkdir(path):
- try:
- os.mkdir(path)
-- except OSError, e:
-+ except OSError as e:
- if e.errno != EEXIST:
- raise e
-
-@@ -137,10 +136,10 @@ def open_log_file(activity):
- while True:
- path = env.get_logs_path('%s-%s.log' % (activity.get_bundle_id(), i))
- try:
-- fd = os.open(path, os.O_EXCL | os.O_CREAT | os.O_WRONLY, 0644)
-- f = os.fdopen(fd, 'w', 0)
-+ fd = os.open(path, os.O_EXCL | os.O_CREAT | os.O_WRONLY, 0o644)
-+ f = os.fdopen(fd, 'w')
- return (path, f)
-- except OSError, e:
-+ except OSError as e:
- if e.errno == EEXIST:
- i += 1
- elif e.errno == ENOSPC:
-@@ -225,7 +224,7 @@ def _create_activity(self):
- self._handle.object_id, self._handle.uri,
- self._handle.invited)
-
-- dev_null = file('/dev/null', 'r')
-+ dev_null = open('/dev/null', 'r')
- child = subprocess.Popen([str(s) for s in command],
- env=environ,
- cwd=str(self._bundle.get_path()),
-diff --git a/src/sugar3/activity/activityhandle.py b/src/sugar3/activity/activityhandle.py
-index d7973a995..d989a8927 100644
---- a/src/sugar3/activity/activityhandle.py
-+++ b/src/sugar3/activity/activityhandle.py
-@@ -24,26 +24,26 @@
- class ActivityHandle(object):
- '''
- Data structure storing simple activity metadata
--
-+
- Args:
- activity_id (string): unique id for the activity to be
- created
--
-+
- object_id (string): identity of the journal object
- associated with the activity.
--
-+
- When you resume an activity from the journal
- the object_id will be passed in. It is optional
- since new activities does not have an
- associated object.
--
-+
- uri (string): URI associated with the activity. Used when
- opening an external file or resource in the
- activity, rather than a journal object
- (downloads stored on the file system for
- example or web pages)
--
-- invited (bool): True if the activity is being
-+
-+ invited (bool): True if the activity is being
- launched for handling an invite from the network
- '''
-
-@@ -55,7 +55,7 @@ def __init__(self, activity_id=None, object_id=None, uri=None,
- self.invited = invited
-
- def get_dict(self):
-- '''Returns activity settings as a dictionary in format
-+ '''Returns activity settings as a dictionary in format
- {activity_id:XXXX, object_id:XXXX, uri:XXXX, invited:BOOL}'''
- result = {'activity_id': self.activity_id, 'invited': self.invited}
- if self.object_id:
-diff --git a/src/sugar3/activity/activityinstance.py b/src/sugar3/activity/activityinstance.py
-new file mode 100644
-index 000000000..b756f54f9
---- /dev/null
-+++ b/src/sugar3/activity/activityinstance.py
-@@ -0,0 +1,222 @@
-+# Copyright (C) 2006-2008, Red Hat, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+import os
-+import sys
-+import six
-+import logging
-+
-+# Change the default encoding to avoid UnicodeDecodeError
-+# http://lists.sugarlabs.org/archive/sugar-devel/2012-August/038928.html
-+if six.PY2:
-+ reload(sys)
-+ sys.setdefaultencoding('utf-8')
-+
-+import gettext
-+from optparse import OptionParser
-+
-+import dbus
-+import dbus.service
-+from dbus.mainloop.glib import DBusGMainLoop
-+DBusGMainLoop(set_as_default=True)
-+
-+from sugar3.activity import activityhandle
-+from sugar3 import config
-+from sugar3.bundle.activitybundle import ActivityBundle
-+from sugar3 import logger
-+
-+from sugar3.bundle.bundle import MalformedBundleException
-+
-+from distutils.dir_util import mkpath
-+import time
-+import hashlib
-+import random
-+
-+
-+def create_activity_instance(constructor, handle):
-+ activity = constructor(handle)
-+ activity.show()
-+ return activity
-+
-+
-+def get_single_process_name(bundle_id):
-+ return bundle_id
-+
-+
-+def get_single_process_path(bundle_id):
-+ return '/' + bundle_id.replace('.', '/')
-+
-+
-+class SingleProcess(dbus.service.Object):
-+
-+ def __init__(self, name_service, constructor):
-+ self.constructor = constructor
-+
-+ bus = dbus.SessionBus()
-+ bus_name = dbus.service.BusName(name_service, bus=bus)
-+ object_path = get_single_process_path(name_service)
-+ dbus.service.Object.__init__(self, bus_name, object_path)
-+
-+ @dbus.service.method('org.laptop.SingleProcess', in_signature='a{sv}')
-+ def create(self, handle_dict):
-+ handle = activityhandle.create_from_dict(handle_dict)
-+ create_activity_instance(self.constructor, handle)
-+
-+
-+def main():
-+ usage = 'usage: %prog [options] [activity dir] [python class]'
-+ epilog = 'If you are running from a directory containing an Activity, ' \
-+ 'the argument may be omitted. Otherwise please provide either '\
-+ 'a directory containing a Sugar Activity [activity dir], a '\
-+ '[python_class], or both.'
-+
-+ parser = OptionParser(usage=usage, epilog=epilog)
-+ parser.add_option('-b', '--bundle-id', dest='bundle_id',
-+ help='identifier of the activity bundle')
-+ parser.add_option('-a', '--activity-id', dest='activity_id',
-+ help='identifier of the activity instance')
-+ parser.add_option('-o', '--object-id', dest='object_id',
-+ help='identifier of the associated datastore object')
-+ parser.add_option('-u', '--uri', dest='uri',
-+ help='URI to load')
-+ parser.add_option('-s', '--single-process', dest='single_process',
-+ action='store_true',
-+ help='start all the instances in the same process')
-+ parser.add_option('-i', '--invited', dest='invited',
-+ action='store_true', default=False,
-+ help='the activity is being launched for handling an '
-+ 'invite from the network')
-+ (options, args) = parser.parse_args()
-+
-+ logger.start()
-+
-+ activity_class = None
-+ if len(args) == 2:
-+ activity_class = args[1]
-+ os.chdir(args[0])
-+ elif len(args) == 1:
-+ if os.path.isdir(args[0]):
-+ os.chdir(args[0])
-+ else:
-+ activity_class = args[0]
-+
-+ os.environ['SUGAR_BUNDLE_PATH'] = os.path.abspath(os.curdir)
-+
-+ bundle_path = os.environ['SUGAR_BUNDLE_PATH']
-+ sys.path.insert(0, bundle_path)
-+
-+ try:
-+ bundle = ActivityBundle(bundle_path)
-+ except MalformedBundleException:
-+ parser.print_help()
-+ exit(0)
-+
-+ if not activity_class:
-+ command = bundle.get_command()
-+ if command.startswith('sugar-activity'):
-+ if not command.startswith('sugar-activity3'):
-+ logging.warning("Activity written for Python 2, consider porting to Python 3.")
-+ activity_class = command.split(" ")[1]
-+
-+ if 'SUGAR_VERSION' not in os.environ:
-+ profile_id = os.environ.get('SUGAR_PROFILE', 'default')
-+ home_dir = os.environ.get('SUGAR_HOME', os.path.expanduser('~/.sugar'))
-+ base = os.path.join(home_dir, profile_id)
-+ activity_root = os.path.join(base, bundle.get_bundle_id())
-+
-+ instance_dir = os.path.join(activity_root, 'instance')
-+ mkpath(instance_dir)
-+
-+ data_dir = os.path.join(activity_root, 'data')
-+ mkpath(data_dir)
-+
-+ tmp_dir = os.path.join(activity_root, 'tmp')
-+ mkpath(tmp_dir)
-+
-+ os.environ['SUGAR_ACTIVITY_ROOT'] = activity_root
-+ os.environ['SUGAR_BUNDLE_PATH'] = bundle.get_path()
-+
-+ os.environ['SUGAR_BUNDLE_ID'] = bundle.get_bundle_id()
-+ os.environ['SUGAR_BUNDLE_NAME'] = bundle.get_name()
-+ os.environ['SUGAR_BUNDLE_VERSION'] = str(bundle.get_activity_version())
-+
-+ # must be done early, some activities set translations globally, SL #3654
-+ activity_locale_path = os.environ.get("SUGAR_LOCALEDIR",
-+ config.locale_path)
-+
-+ gettext.bindtextdomain(bundle.get_bundle_id(), activity_locale_path)
-+ gettext.bindtextdomain('sugar-toolkit-gtk3', config.locale_path)
-+ gettext.textdomain(bundle.get_bundle_id())
-+
-+ splitted_module = activity_class.rsplit('.', 1)
-+ module_name = splitted_module[0]
-+ class_name = splitted_module[1]
-+
-+ module = __import__(module_name)
-+ for comp in module_name.split('.')[1:]:
-+ module = getattr(module, comp)
-+
-+ activity_constructor = getattr(module, class_name)
-+
-+ if not options.activity_id:
-+ # Generate random hash
-+ data = '%s%s' % (time.time(), random.randint(10000, 100000))
-+ random_hash = hashlib.sha1(data.encode()).hexdigest()
-+ options.activity_id = random_hash
-+ options.bundle_id = bundle.get_bundle_id()
-+
-+ activity_handle = activityhandle.ActivityHandle(
-+ activity_id=options.activity_id,
-+ object_id=options.object_id, uri=options.uri,
-+ invited=options.invited)
-+
-+ if options.single_process is True:
-+ sessionbus = dbus.SessionBus()
-+
-+ service_name = get_single_process_name(options.bundle_id)
-+ service_path = get_single_process_path(options.bundle_id)
-+
-+ bus_object = sessionbus.get_object(
-+ 'org.freedesktop.DBus', '/org/freedesktop/DBus')
-+ try:
-+ name = bus_object.GetNameOwner(
-+ service_name, dbus_interface='org.freedesktop.DBus')
-+ except dbus.DBusException:
-+ name = None
-+
-+ if not name:
-+ SingleProcess(service_name, activity_constructor)
-+ else:
-+ try:
-+ single_process = sessionbus.get_object(service_name,
-+ service_path)
-+ single_process.create(
-+ activity_handle.get_dict(),
-+ dbus_interface='org.laptop.SingleProcess')
-+
-+ print('Created %s in a single process.' % service_name)
-+ sys.exit(0)
-+ except (TypeError, dbus.DBusException):
-+ print('Could not communicate with the instance process,'
-+ 'launching a new process')
-+
-+ if hasattr(module, 'start'):
-+ module.start()
-+
-+ instance = create_activity_instance(activity_constructor, activity_handle)
-+
-+ if hasattr(instance, 'run_main_loop'):
-+ instance.run_main_loop()
-diff --git a/src/sugar3/activity/activityservice.py b/src/sugar3/activity/activityservice.py
-index 738e602e0..25329029e 100644
---- a/src/sugar3/activity/activityservice.py
-+++ b/src/sugar3/activity/activityservice.py
-@@ -79,5 +79,5 @@ def HandleViewSource(self):
- def GetDocumentPath(self, async_cb, async_err_cb):
- try:
- self._activity.get_document_path(async_cb, async_err_cb)
-- except Exception, e:
-+ except Exception as e:
- async_err_cb(e)
-diff --git a/src/sugar3/activity/bundlebuilder.py b/src/sugar3/activity/bundlebuilder.py
-index 403484456..f270346c2 100644
---- a/src/sugar3/activity/bundlebuilder.py
-+++ b/src/sugar3/activity/bundlebuilder.py
-@@ -40,12 +40,13 @@
- import logging
- from glob import glob
- from fnmatch import fnmatch
--from ConfigParser import ConfigParser
-+from six.moves.configparser import ConfigParser
- import xml.etree.cElementTree as ET
--from HTMLParser import HTMLParser
-+from six.moves.html_parser import HTMLParser
-
- from sugar3 import env
- from sugar3.bundle.activitybundle import ActivityBundle
-+from six.moves import reduce
-
-
- IGNORE_DIRS = ['dist', '.git', 'screenshots']
-@@ -150,7 +151,7 @@ def build_locale(self):
- args = ['msgfmt', '--output-file=%s' % mo_file, file_name]
- retcode = subprocess.call(args)
- if retcode:
-- print 'ERROR - msgfmt failed with return code %i.' % retcode
-+ print('ERROR - msgfmt failed with return code %i.' % retcode)
- if self._no_fail:
- continue
-
-@@ -301,8 +302,8 @@ def install(self, prefix, install_mime=True, install_desktop_file=True):
-
- source_to_dest[source_path] = dest_path
-
-- for source, dest in source_to_dest.items():
-- print 'Install %s to %s.' % (source, dest)
-+ for source, dest in list(source_to_dest.items()):
-+ print('Install %s to %s.' % (source, dest))
-
- path = os.path.dirname(dest)
- if not os.path.exists(path):
-@@ -429,7 +430,7 @@ def cmd_check(config, options):
- if options.choice == 'integration':
- run_unit_test = False
-
-- print "Running Tests"
-+ print("Running Tests")
-
- test_path = os.path.join(config.source_dir, "tests")
-
-@@ -443,22 +444,22 @@ def cmd_check(config, options):
- all_tests = unittest.defaultTestLoader.discover(unit_test_path)
- unittest.TextTestRunner(verbosity=options.verbose).run(all_tests)
- elif not run_unit_test:
-- print "Not running unit tests"
-+ print("Not running unit tests")
- else:
-- print 'No "unit" directory found.'
-+ print('No "unit" directory found.')
-
- if os.path.isdir(integration_test_path) and run_integration_test:
- all_tests = unittest.defaultTestLoader.discover(
- integration_test_path)
- unittest.TextTestRunner(verbosity=options.verbose).run(all_tests)
- elif not run_integration_test:
-- print "Not running integration tests"
-+ print("Not running integration tests")
- else:
-- print 'No "integration" directory found.'
-+ print('No "integration" directory found.')
-
-- print "Finished testing"
-+ print("Finished testing")
- else:
-- print "Error: No tests/ directory"
-+ print("Error: No tests/ directory")
-
-
- def cmd_dev(config, options):
-@@ -472,9 +473,9 @@ def cmd_dev(config, options):
- os.symlink(config.source_dir, bundle_path)
- except OSError:
- if os.path.islink(bundle_path):
-- print 'ERROR - The bundle has been already setup for development.'
-+ print('ERROR - The bundle has been already setup for development.')
- else:
-- print 'ERROR - A bundle with the same name is already installed.'
-+ print('ERROR - A bundle with the same name is already installed.')
-
-
- def cmd_dist_xo(config, options):
-@@ -490,9 +491,9 @@ def cmd_dist_xo(config, options):
- def cmd_fix_manifest(config, options):
- '''Add missing files to the manifest (OBSOLETE)'''
-
-- print 'WARNING: The fix_manifest command is obsolete.'
-- print ' The MANIFEST file is no longer used in bundles,'
-- print ' please remove it.'
-+ print('WARNING: The fix_manifest command is obsolete.')
-+ print(' The MANIFEST file is no longer used in bundles,')
-+ print(' please remove it.')
-
-
- def cmd_dist_source(config, options):
-@@ -506,7 +507,10 @@ def cmd_install(config, options):
- """Install the activity in the system"""
-
- installer = Installer(Builder(config))
-- installer.install(options.prefix, options.install_mime, options.install_desktop_file)
-+ installer.install(
-+ options.prefix,
-+ options.install_mime,
-+ options.install_desktop_file)
-
-
- def _po_escape(string):
-@@ -568,7 +572,7 @@ def cmd_genpot(config, options):
- args += python_files
- retcode = subprocess.call(args)
- if retcode:
-- print 'ERROR - xgettext failed with return code %i.' % retcode
-+ print('ERROR - xgettext failed with return code %i.' % retcode)
-
-
- def cmd_build(config, options):
-@@ -603,7 +607,7 @@ def start():
- choices=['unit', 'integration'],
- help="run unit/integration test")
- check_parser.add_argument("--verbosity", "-v", dest="verbose",
-- type=int, choices=range(0, 3),
-+ type=int, choices=list(range(0, 3)),
- default=1, nargs='?',
- help="verbosity for the unit tests")
-
-diff --git a/src/sugar3/activity/webkit1.py b/src/sugar3/activity/webkit1.py
-index a2d015480..8ea7dade8 100644
---- a/src/sugar3/activity/webkit1.py
-+++ b/src/sugar3/activity/webkit1.py
-@@ -28,8 +28,8 @@
- from gi.repository import WebKit
- import socket
- from threading import Thread
--from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
--import SocketServer
-+from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-+from six.moves import socketserver
- import select
- import errno
- import mimetypes
-@@ -80,7 +80,7 @@ def serve_forever(self, poll_interval=0.5):
- # shutdown request and wastes cpu at all other times.
- try:
- r, w, e = select.select([self], [], [], poll_interval)
-- except select.error, e:
-+ except select.error as e:
- if e[0] == errno.EINTR:
- logging.debug("got eintr")
- continue
-@@ -92,7 +92,7 @@ def serve_forever(self, poll_interval=0.5):
- def server_bind(self):
- """Override server_bind in HTTPServer to not use
- getfqdn to get the server name because is very slow."""
-- SocketServer.TCPServer.server_bind(self)
-+ socketserver.TCPServer.server_bind(self)
- _host, port = self.socket.getsockname()[:2]
- self.server_name = 'localhost'
- self.server_port = port
-diff --git a/src/sugar3/activity/widgets.py b/src/sugar3/activity/widgets.py
-index 06606e807..21e717287 100644
---- a/src/sugar3/activity/widgets.py
-+++ b/src/sugar3/activity/widgets.py
-@@ -34,7 +34,7 @@
- from sugar3 import profile
-
-
--_ = lambda msg: gettext.dgettext('sugar-toolkit-gtk3', msg)
-+def _(msg): return gettext.dgettext('sugar-toolkit-gtk3', msg)
-
-
- def _create_activity_icon(metadata):
-diff --git a/src/sugar3/bundle/__init__.py b/src/sugar3/bundle/__init__.py
-index 9b8f78f7c..ea06fb45b 100644
---- a/src/sugar3/bundle/__init__.py
-+++ b/src/sugar3/bundle/__init__.py
-@@ -44,7 +44,9 @@
- * `icon` - the icon file for the activity, shown by Sugar in the list
- of installed activities,
-
--* `exec` - how to execute the activity, e.g. `sugar-activity module.Class`,
-+* `exec` - how to execute the activity, e.g.
-+ `sugar-activity3 module.Class` (For activities written for Python 3),
-+ `sugar-activity module.Class` (For activities written for Python 2)
-
- Optional metadata keys are;
-
-@@ -117,7 +119,7 @@
- [Activity]
- name = Browse
- bundle_id = org.laptop.WebActivity
-- exec = sugar-activity webactivity.WebActivity -s
-+ exec = sugar-activity3 webactivity.WebActivity -s
- activity_version = 200
- icon = activity-web
- max_participants = 100
-diff --git a/src/sugar3/bundle/activitybundle.py b/src/sugar3/bundle/activitybundle.py
-index c0d9d985f..879831e53 100644
---- a/src/sugar3/bundle/activitybundle.py
-+++ b/src/sugar3/bundle/activitybundle.py
-@@ -20,7 +20,7 @@
- UNSTABLE.
- """
-
--from ConfigParser import ConfigParser, ParsingError
-+from six.moves.configparser import ConfigParser, ParsingError
- from locale import normalize
- import os
- import shutil
-@@ -441,7 +441,7 @@ def uninstall(self, force=False, delete_profile=False):
- if delete_profile:
- bundle_profile_path = env.get_profile_path(self._bundle_id)
- if os.path.exists(bundle_profile_path):
-- os.chmod(bundle_profile_path, 0775)
-+ os.chmod(bundle_profile_path, 0o775)
- shutil.rmtree(bundle_profile_path, ignore_errors=True)
-
- self._uninstall(install_path)
-diff --git a/src/sugar3/bundle/bundle.py b/src/sugar3/bundle/bundle.py
-index 59cd885ad..c5716107b 100644
---- a/src/sugar3/bundle/bundle.py
-+++ b/src/sugar3/bundle/bundle.py
-@@ -20,10 +20,10 @@
- UNSTABLE.
- """
-
-+import six
- import os
- import logging
- import shutil
--import StringIO
- import zipfile
-
-
-@@ -74,7 +74,7 @@ def __init__(self, path):
- if not os.path.isdir(self._path):
- try:
- self._zip_file = zipfile.ZipFile(self._path)
-- except zipfile.error, exception:
-+ except zipfile.error as exception:
- raise MalformedBundleException('Error accessing zip file %r: '
- '%s' % (self._path, exception))
- self._check_zip_bundle()
-@@ -115,7 +115,7 @@ def get_file(self, filename):
- if self._zip_file is None:
- path = os.path.join(self._path, filename)
- try:
-- f = open(path, 'rb')
-+ f = open(path, 'r')
- except IOError:
- logging.debug("cannot open path %s" % path)
- return None
-@@ -123,7 +123,7 @@ def get_file(self, filename):
- path = os.path.join(self._zip_root_dir, filename)
- try:
- data = self._zip_file.read(path)
-- f = StringIO.StringIO(data)
-+ f = six.StringIO(data)
- except KeyError:
- logging.debug('%s not found in zip %s.' % (filename, path))
- return None
-@@ -171,7 +171,7 @@ def _unzip(self, install_dir):
- raise AlreadyInstalledException
-
- if not os.path.isdir(install_dir):
-- os.mkdir(install_dir, 0775)
-+ os.mkdir(install_dir, 0o775)
-
- # zipfile provides API that in theory would let us do this
- # correctly by hand, but handling all the oddities of
-diff --git a/src/sugar3/bundle/bundleversion.py b/src/sugar3/bundle/bundleversion.py
-index 91df406ae..7ad9e3e09 100644
---- a/src/sugar3/bundle/bundleversion.py
-+++ b/src/sugar3/bundle/bundleversion.py
-@@ -82,6 +82,7 @@ class NormalizedVersion(object):
- Attributes:
- parts (list): the numeric parts of the version after normalization.
- """
-+
- def __init__(self, activity_version):
- self._activity_version = activity_version
- self.parts = []
-diff --git a/src/sugar3/bundle/contentbundle.py b/src/sugar3/bundle/contentbundle.py
-index 146e7f8c6..0e61ade08 100644
---- a/src/sugar3/bundle/contentbundle.py
-+++ b/src/sugar3/bundle/contentbundle.py
-@@ -21,10 +21,11 @@
- UNSTABLE.
- """
-
--from ConfigParser import ConfigParser
-+from six.moves import urllib
-+from six.moves.configparser import ConfigParser
-+
- import tempfile
- import os
--import urllib
-
- from sugar3 import env
- from sugar3.bundle.bundle import Bundle, MalformedBundleException
-@@ -142,7 +143,7 @@ def get_icon(self):
-
- def get_start_uri(self):
- path = os.path.join(self.get_path(), self._activity_start)
-- return 'file://' + urllib.pathname2url(path)
-+ return 'file://' + urllib.request.pathname2url(path)
-
- def get_bundle_id(self):
- return self._global_name
-diff --git a/src/sugar3/datastore/datastore.py b/src/sugar3/datastore/datastore.py
-index f132f0c8b..e1b3f8b9a 100644
---- a/src/sugar3/datastore/datastore.py
-+++ b/src/sugar3/datastore/datastore.py
-@@ -20,6 +20,7 @@
- STABLE
- """
-
-+import six
- import logging
- import time
- from datetime import datetime
-@@ -69,6 +70,7 @@ def __datastore_updated_cb(object_id):
- def __datastore_deleted_cb(object_id):
- deleted.send(None, object_id=object_id)
-
-+
- created = dispatch.Signal()
- deleted = dispatch.Signal()
- updated = dispatch.Signal()
-@@ -85,6 +87,12 @@ def __init__(self, properties=None):
- if not properties:
- self._properties = {}
- else:
-+ if six.PY3:
-+ for x, y in properties.items():
-+ try:
-+ properties[x] = y.decode()
-+ except BaseException:
-+ pass
- self._properties = properties
-
- default_keys = ['activity', 'activity_id',
-@@ -97,6 +105,11 @@ def __getitem__(self, key):
- return self._properties[key]
-
- def __setitem__(self, key, value):
-+ if six.PY3:
-+ try:
-+ value = value.decode()
-+ except BaseException:
-+ pass
- if key not in self._properties or self._properties[key] != value:
- self._properties[key] = value
- self.emit('updated')
-@@ -112,7 +125,7 @@ def has_key(self, key):
- return key in self._properties
-
- def keys(self):
-- return self._properties.keys()
-+ return list(self._properties.keys())
-
- def get_dictionary(self):
- return self._properties
-@@ -128,7 +141,7 @@ def get(self, key, default=None):
-
- def update(self, properties):
- """Update all of the metadata"""
-- for (key, value) in properties.items():
-+ for (key, value) in list(properties.items()):
- self[key] = value
-
-
-diff --git a/src/sugar3/dispatch/dispatcher.py b/src/sugar3/dispatch/dispatcher.py
-index 89d219c12..4b437a3aa 100644
---- a/src/sugar3/dispatch/dispatcher.py
-+++ b/src/sugar3/dispatch/dispatcher.py
-@@ -1,4 +1,6 @@
- import weakref
-+import six
-+
- try:
- set
- except NameError:
-@@ -11,7 +13,7 @@
-
- def _make_id(target):
- if hasattr(target, 'im_func'):
-- return (id(target.im_self), id(target.im_func))
-+ return (id(im_self(target)), id(im_func(target)))
- return id(target)
-
-
-@@ -159,7 +161,7 @@ def send_robust(self, sender, **named):
- for receiver in self._live_receivers(_make_id(sender)):
- try:
- response = receiver(signal=self, sender=sender, **named)
-- except Exception, err:
-+ except Exception as err:
- responses.append((receiver, err))
- else:
- responses.append((receiver, response))
-@@ -195,3 +197,17 @@ def _remove_receiver(self, receiver):
- for idx, (r_key, _) in enumerate(self.receivers):
- if r_key == key:
- del self.receivers[idx]
-+
-+
-+def im_self(func):
-+ if six.PY2:
-+ return func.im_self
-+ elif six.PY3:
-+ return func.__self__
-+
-+
-+def im_func(func):
-+ if six.PY2:
-+ return func.im_func
-+ elif six.PY3:
-+ return func.__func__
-diff --git a/src/sugar3/dispatch/saferef.py b/src/sugar3/dispatch/saferef.py
-index df899cddb..581703c21 100644
---- a/src/sugar3/dispatch/saferef.py
-+++ b/src/sugar3/dispatch/saferef.py
-@@ -5,6 +5,7 @@
- aren't handled by the core weakref module).
- """
-
-+import six
- import weakref
- import traceback
-
-@@ -21,7 +22,7 @@ def safeRef(target, onDelete=None):
- weakref or a BoundMethodWeakref) as argument.
- """
- if hasattr(target, 'im_self'):
-- if target.im_self is not None:
-+ if im_self(target) is not None:
- # Turn a bound method into a BoundMethodWeakref instance.
- # Keep track of these instances for lookup by disconnect().
- assert hasattr(target, 'im_func'), \
-@@ -123,18 +124,18 @@ def remove(weak, self=self):
- try:
- if callable(function):
- function(self)
-- except Exception, e:
-+ except Exception as e:
- try:
- traceback.print_exc()
- except AttributeError:
-- print "Exception during saferef %s cleanup "
-- "function %s: %s" % (self, function, e)
-+ print("Exception during saferef %s cleanup "
-+ "function %s: %s" % (self, function, e))
- self.deletionMethods = [onDelete]
- self.key = self.calculateKey(target)
-- self.weakSelf = weakref.ref(target.im_self, remove)
-- self.weakFunc = weakref.ref(target.im_func, remove)
-- self.selfName = str(target.im_self)
-- self.funcName = str(target.im_func.__name__)
-+ self.weakSelf = weakref.ref(im_self(target), remove)
-+ self.weakFunc = weakref.ref(im_func(target), remove)
-+ self.selfName = str(im_self(target))
-+ self.funcName = str(im_func(target).__name__)
-
- def calculateKey(cls, target):
- """Calculate the reference key for this reference
-@@ -142,7 +143,7 @@ def calculateKey(cls, target):
- Currently this is a two-tuple of the id()'s of the
- target object and the target function respectively.
- """
-- return (id(target.im_self), id(target.im_func))
-+ return (id(im_self(target)), id(im_func(target)))
- calculateKey = classmethod(calculateKey)
-
- def __str__(self):
-@@ -155,15 +156,19 @@ def __str__(self):
-
- __repr__ = __str__
-
-- def __nonzero__(self):
-+ def __bool__(self):
- """Whether we are still a valid reference"""
- return self() is not None
-
-+ def __nonzero__(self):
-+ """Python2 alternative for __bool__"""
-+ return self() is not None
-+
- def __cmp__(self, other):
- """Compare with another reference"""
- if not isinstance(other, self.__class__):
-- return cmp(self.__class__, type(other))
-- return cmp(self.key, other.key)
-+ return ((self.__class__ > type(other)) - (self.__class__ < type(other)))
-+ return ((self.key > other.key) - (self.key < other.key))
-
- def __call__(self):
- """Return a strong reference to the bound method
-@@ -201,6 +206,7 @@ def foo(self): return "foo"
- aren't descriptors (such as Jython) this implementation has the advantage
- of working in the most cases.
- """
-+
- def __init__(self, target, onDelete=None):
- """Return a weak-reference-like instance for a bound method
-
-@@ -215,9 +221,9 @@ def __init__(self, target, onDelete=None):
- collected). Should take a single argument,
- which will be passed a pointer to this object.
- """
-- assert getattr(target.im_self, target.__name__) == target, \
-+ assert getattr(im_self(target), target.__name__) == target, \
- ("method %s isn't available as the attribute %s of %s" %
-- (target, target.__name__, target.im_self))
-+ (target, target.__name__, im_self(target)))
- super(BoundNonDescriptorMethodWeakref, self).__init__(target, onDelete)
-
- def __call__(self):
-@@ -255,3 +261,17 @@ def get_bound_method_weakref(target, onDelete):
- # no luck, use the alternative implementation:
- return BoundNonDescriptorMethodWeakref(target=target,
- onDelete=onDelete)
-+
-+
-+def im_self(func):
-+ if six.PY2:
-+ return func.im_self
-+ elif six.PY3:
-+ return func.__self__
-+
-+
-+def im_func(func):
-+ if six.PY2:
-+ return func.im_func
-+ elif six.PY3:
-+ return func.__func__
-diff --git a/src/sugar3/env.py b/src/sugar3/env.py
-index a18d5c93f..bbb1a9a18 100644
---- a/src/sugar3/env.py
-+++ b/src/sugar3/env.py
-@@ -36,9 +36,9 @@ def get_profile_path(path=None):
- base = os.path.join(home_dir, profile_id)
- if not os.path.isdir(base):
- try:
-- os.makedirs(base, 0770)
-+ os.makedirs(base, 0o770)
- except OSError:
-- print 'Could not create user directory.'
-+ print('Could not create user directory.')
-
- if path is not None:
- return os.path.join(base, path)
-diff --git a/src/sugar3/graphics/Makefile.am b/src/sugar3/graphics/Makefile.am
-index e5fdf09a1..0621750ef 100644
---- a/src/sugar3/graphics/Makefile.am
-+++ b/src/sugar3/graphics/Makefile.am
-@@ -16,7 +16,6 @@ sugar_PYTHON = \
- palettemenu.py \
- palettewindow.py \
- panel.py \
-- popwindow.py \
- radiopalette.py \
- radiotoolbutton.py \
- scrollingdetector.py \
-diff --git a/src/sugar3/graphics/alert.py b/src/sugar3/graphics/alert.py
-index d262a209e..66cefd9df 100644
---- a/src/sugar3/graphics/alert.py
-+++ b/src/sugar3/graphics/alert.py
-@@ -61,7 +61,7 @@
- from sugar3.graphics.icon import Icon
-
-
--_ = lambda msg: gettext.dgettext('sugar-toolkit-gtk3', msg)
-+def _(msg): return gettext.dgettext('sugar-toolkit-gtk3', msg)
-
-
- if not hasattr(GObject.ParamFlags, 'READWRITE'):
-@@ -258,6 +258,8 @@ def _response(self, response_id):
-
- def __button_clicked_cb(self, button, response_id):
- self._response(response_id)
-+
-+
- if hasattr(Alert, 'set_css_name'):
- Alert.set_css_name('alert')
-
-@@ -294,9 +296,9 @@ def _alert_response_cb(self, alert, response_id):
-
- # Check the response identifier.
- if response_id is Gtk.ResponseType.OK:
-- print 'Ok Button was clicked.'
-+ print('Ok Button was clicked.')
- elif response_id is Gtk.ResponseType.CANCEL:
-- print 'Cancel Button was clicked.'
-+ print('Cancel Button was clicked.')
- """
-
- def __init__(self, **kwargs):
-@@ -341,7 +343,7 @@ def _alert_response_cb(self, alert, response_id):
-
- # Check the response identifier.
- if response_id is Gtk.ResponseType.OK:
-- print 'Ok Button was clicked.'
-+ print('Ok Button was clicked.')
- """
-
- def __init__(self, **kwargs):
-@@ -390,6 +392,8 @@ def _draw(self, context):
-
- def set_text(self, text):
- self._text.set_markup('<b>%s</b>' % GLib.markup_escape_text(str(text)))
-+
-+
- if hasattr(_TimeoutIcon, 'set_css_name'):
- _TimeoutIcon.set_css_name('timeouticon')
-
-@@ -458,11 +462,11 @@ def __alert_response_cb(self, alert, response_id):
-
- # Check the response identifier.
- if response_id is Gtk.ResponseType.OK:
-- print 'Continue Button was clicked.'
-+ print('Continue Button was clicked.')
- elif response_id is Gtk.ResponseType.CANCEL:
-- print 'Cancel Button was clicked.'
-+ print('Cancel Button was clicked.')
- elif response_id == -1:
-- print 'Timeout occurred'
-+ print('Timeout occurred')
- """
-
- def __init__(self, timeout=5, **kwargs):
-@@ -508,9 +512,9 @@ def __alert_response_cb(self, alert, response_id):
-
- # Check the response identifier.
- if response_id is Gtk.ResponseType.OK:
-- print 'Ok Button was clicked.'
-+ print('Ok Button was clicked.')
- elif response_id == -1:
-- print 'Timeout occurred'
-+ print('Timeout occurred')
- """
-
- def __init__(self, timeout=5, **kwargs):
-diff --git a/src/sugar3/graphics/colorbutton.py b/src/sugar3/graphics/colorbutton.py
-index 2ca6851c2..10c188ef6 100644
---- a/src/sugar3/graphics/colorbutton.py
-+++ b/src/sugar3/graphics/colorbutton.py
-@@ -29,7 +29,7 @@
- from sugar3.graphics.palette import Palette, ToolInvoker, WidgetInvoker
-
-
--_ = lambda msg: gettext.dgettext('sugar-toolkit-gtk3', msg)
-+def _(msg): return gettext.dgettext('sugar-toolkit-gtk3', msg)
-
-
- if not hasattr(GObject.ParamFlags, 'READWRITE'):
-@@ -38,8 +38,8 @@
-
-
- def get_svg_color_string(color):
-- return '#%.2X%.2X%.2X' % (color.red / 257, color.green / 257,
-- color.blue / 257)
-+ return '#%.2X%.2X%.2X' % (color.red // 257, color.green // 257,
-+ color.blue // 257)
-
-
- class _ColorButton(Gtk.Button):
-@@ -123,8 +123,8 @@ def _get_fg_style_color_str(self):
- context = self.get_style_context()
- fg_color = context.get_color(Gtk.StateType.NORMAL)
- # the color components are stored as float values between 0.0 and 1.0
-- return '#%.2X%.2X%.2X' % (fg_color.red * 255, fg_color.green * 255,
-- fg_color.blue * 255)
-+ return '#%.2X%.2X%.2X' % (int(fg_color.red * 255), int(fg_color.green * 255),
-+ int(fg_color.blue * 255))
-
- def set_color(self, color):
- assert isinstance(color, Gdk.Color)
-@@ -149,11 +149,11 @@ def set_icon_name(self, icon_name):
- '''
- Sets the icon for the tool button from a named themed icon.
- If it is none then no icon will be shown.
--
-+
- Args:
- icon_name(string): The name for a themed icon.
- It can be set as 'None' too.
--
-+
- Example:
- set_icon_name('view-radial')
- '''
-@@ -169,11 +169,11 @@ def get_icon_name(self):
- icon_name = GObject.Property(type=str,
- getter=get_icon_name, setter=set_icon_name)
-
-- def set_icon_size(self, icon_size):
-- self._preview.props.icon_size = icon_size
-+ def set_icon_size(self, pixel_size):
-+ self._preview.props.pixel_size = pixel_size
-
- def get_icon_size(self):
-- return self._preview.props.icon_size
-+ return self._preview.props.pixel_size
-
- icon_size = GObject.Property(type=int,
- getter=get_icon_size, setter=set_icon_size)
-@@ -496,13 +496,13 @@ def __button_can_activate_accel_cb(self, button, signal_id):
- def set_accelerator(self, accelerator):
- '''
- Sets keyboard shortcut that activates this button.
--
-+
- Args:
- accelerator(string): accelerator to be set. Should be in
- form <modifier>Letter
- Find about format here :
- https://developer.gnome.org/gtk3/stable/gtk3-Keyboard-Accelerators.html#gtk-accelerator-parse
--
-+
- Example:
- set_accelerator(self, 'accel')
- '''
-@@ -523,21 +523,21 @@ def create_palette(self):
- The create_palette function is called when the palette needs to be
- invoked. For example, when the user has right clicked the icon or
- the user has hovered over the icon for a long time.
--
-+
- The create_palette will only be called once or zero times. The palette
- returned will be stored and re-used if the user invokes the palette
- multiple times.
--
-+
- Your create_palette implementation does not need to
- :any:`Gtk.Widget.show` the palette, as this will be done by the
- invoker. However, you still need to show
- the menu items, etc that you place in the palette.
--
-+
- Returns:
--
-+
- sugar3.graphics.palette.Palette, or None to indicate that you
- do not want a palette shown
--
-+
- The default implementation returns None, to indicate no palette should
- be shown.
- '''
-@@ -595,11 +595,11 @@ def set_icon_name(self, icon_name):
- '''
- Sets the icon for the tool button from a named themed icon.
- If it is none then no icon will be shown.
--
-+
- Args:
- icon_name(string): The name for a themed icon.
- It can be set as 'None' too.
--
-+
- Example:
- set_icon_name('view-radial')
- '''
-@@ -632,8 +632,8 @@ def get_icon_size(self):
-
- def set_title(self, title):
- '''
-- The set_title() method sets the "title" property to the value of
-- title. The "title" property contains the string that is used to
-+ The set_title() method sets the "title" property to the value of
-+ title. The "title" property contains the string that is used to
- set the colorbutton title.
- '''
- self.get_child().props.title = title
-diff --git a/src/sugar3/graphics/icon.py b/src/sugar3/graphics/icon.py
-index 0666dc158..2343aee36 100644
---- a/src/sugar3/graphics/icon.py
-+++ b/src/sugar3/graphics/icon.py
-@@ -87,11 +87,13 @@
- and 85.0% on the Y axis.
- '''
-
-+import six
- import re
- import math
- import logging
- import os
--from ConfigParser import ConfigParser
-+
-+from six.moves.configparser import ConfigParser
-
- import gi
- gi.require_version('Rsvg', '2.0')
-@@ -127,8 +129,8 @@ def load(self, file_name, entities, cache):
- if cache:
- self._cache[file_name] = icon
-
-- for entity, value in entities.items():
-- if isinstance(value, basestring):
-+ for entity, value in list(entities.items()):
-+ if isinstance(value, six.string_types):
- xml = '<!ENTITY %s "%s">' % (entity, value)
- icon = re.sub('<!ENTITY %s .*>' % entity, xml, icon)
- else:
-@@ -207,7 +209,7 @@ def _get_attach_points(self, info, size_request):
- # try read from the .icon file
- icon_filename = info.get_filename().replace('.svg', '.icon')
- if icon_filename != info.get_filename() and \
-- os.path.exists(icon_filename):
-+ os.path.exists(icon_filename):
-
- try:
- with open(icon_filename) as config_file:
-@@ -470,7 +472,6 @@ class Icon(Gtk.Image):
-
- __gtype_name__ = 'SugarIcon'
-
-- # FIXME: deprecate icon_size
- _MENU_SIZES = (Gtk.IconSize.MENU, Gtk.IconSize.DND,
- Gtk.IconSize.SMALL_TOOLBAR, Gtk.IconSize.BUTTON)
-
-@@ -483,7 +484,6 @@ def __init__(self, **kwargs):
- self._alpha = 1.0
- self._scale = 1.0
-
-- # FIXME: deprecate icon_size
- if 'icon_size' in kwargs:
- logging.warning("icon_size is deprecated. Use pixel_size instead.")
-
-@@ -532,7 +532,6 @@ def _sync_image_properties(self):
- if self._buffer.file_name != self.props.file:
- self._buffer.file_name = self.props.file
-
-- # FIXME: deprecate icon_size
- pixel_size = None
- if self.props.pixel_size == -1:
- if self.props.icon_size in self._MENU_SIZES:
-@@ -549,7 +548,7 @@ def _sync_image_properties(self):
- self._buffer.height = height
-
- def _icon_size_changed_cb(self, image, pspec):
-- self._buffer.icon_size = self.props.icon_size
-+ self._buffer.icon_size = self.props.pixel_size
-
- def _icon_name_changed_cb(self, image, pspec):
- self._buffer.icon_name = self.props.icon_name
-@@ -805,7 +804,7 @@ def __init__(self, **kwargs):
- # for example, after a touch palette invocation
- self.connect_after('button-release-event',
- self.__button_release_event_cb)
-- for key, value in kwargs.iteritems():
-+ for key, value in six.iteritems(kwargs):
- self.set_property(key, value)
-
- from sugar3.graphics.palette import CursorInvoker
-@@ -1152,6 +1151,8 @@ def __palette_popup_cb(self, palette):
-
- def __palette_popdown_cb(self, palette):
- self.unset_state_flags(Gtk.StateFlags.PRELIGHT)
-+
-+
- if hasattr(CanvasIcon, 'set_css_name'):
- CanvasIcon.set_css_name('canvasicon')
-
-@@ -1447,6 +1448,6 @@ def get_surface(**kwargs):
- cairo surface or None if image was not found
- '''
- icon = _IconBuffer()
-- for key, value in kwargs.items():
-+ for key, value in list(kwargs.items()):
- icon.__setattr__(key, value)
- return icon.get_surface()
-diff --git a/src/sugar3/graphics/iconentry.py b/src/sugar3/graphics/iconentry.py
-index 243807fa5..bc4746168 100644
---- a/src/sugar3/graphics/iconentry.py
-+++ b/src/sugar3/graphics/iconentry.py
-@@ -61,7 +61,7 @@ def set_icon_from_name(self, position, name):
- self.set_icon(position, pixbuf)
-
- def set_icon(self, position, pixbuf):
-- if type(pixbuf) is not GdkPixbuf.Pixbuf:
-+ if not isinstance(pixbuf, GdkPixbuf.Pixbuf):
- raise ValueError('Argument must be a pixbuf, not %r.' % pixbuf)
- self.set_icon_from_pixbuf(position, pixbuf)
-
-diff --git a/src/sugar3/graphics/objectchooser.py b/src/sugar3/graphics/objectchooser.py
-index e7fad8853..7cbe860f2 100644
---- a/src/sugar3/graphics/objectchooser.py
-+++ b/src/sugar3/graphics/objectchooser.py
-@@ -19,8 +19,8 @@
- STABLE.
- """
-
-+import six
- import logging
--import StringIO
- import cairo
-
- from gi.repository import GObject
-@@ -59,13 +59,13 @@ def get_preview_pixbuf(preview_data, width=-1, height=-1):
- None, if it could not be created
-
- Example:
-- pixbuf = get_preview_pixbuf(metadata.get('preview', ''))
-- has_preview = pixbuf is not None
--
-- if has_preview:
-- im = Gtk.Image()
-- im.set_from_pixbuf(pixbuf)
-- box.add(im)
-+ pixbuf = get_preview_pixbuf(metadata.get('preview', ''))
-+ has_preview = pixbuf is not None
-+
-+ if has_preview:
-+ im = Gtk.Image()
-+ im.set_from_pixbuf(pixbuf)
-+ box.add(im)
- im.show()
- """
- if width == -1:
-@@ -82,7 +82,7 @@ def get_preview_pixbuf(preview_data, width=-1, height=-1):
- import base64
- preview_data = base64.b64decode(preview_data)
-
-- png_file = StringIO.StringIO(preview_data)
-+ png_file = six.StringIO(preview_data)
- try:
- # Load image and scale to dimensions
- surface = cairo.ImageSurface.create_from_png(png_file)
-@@ -126,7 +126,7 @@ class ObjectChooser(object):
- what_filter (str): an activity bundle_id or a generic mime type as
- defined in :mod:`sugar3.mime` used to determine which objects
- will be presented in the object chooser
--
-+
- filter_type (str): should be one of [None, FILTER_TYPE_GENERIC_MIME,
- FILTER_TYPE_ACTIVITY, FILTER_TYPE_MIME_BY_ACTIVITY]
-
-@@ -155,7 +155,7 @@ class ObjectChooser(object):
-
- Examples:
- chooser = ObjectChooser(self._activity, what_filter='Image')
--
-+
- chooser = ObjectChooser(parent=self,
- what_filter=self.get_bundle_id(),
- filter_type=FILTER_TYPE_ACTIVITY)
-@@ -192,7 +192,7 @@ def __init__(self, parent=None, what_filter=None, filter_type=None,
- def run(self):
- """
- Runs the object chooser and displays it.
--
-+
- Returns:
- Gtk.ResponseType constant, the response received from displaying the
- object chooser.
-diff --git a/src/sugar3/graphics/palettegroup.py b/src/sugar3/graphics/palettegroup.py
-index 98539feb2..9940e355b 100644
---- a/src/sugar3/graphics/palettegroup.py
-+++ b/src/sugar3/graphics/palettegroup.py
-@@ -36,7 +36,7 @@ def get_group(group_id):
-
-
- def popdown_all():
-- for group in _groups.values():
-+ for group in list(_groups.values()):
- group.popdown()
-
-
-diff --git a/src/sugar3/graphics/palettemenu.py b/src/sugar3/graphics/palettemenu.py
-index 231280716..ddc871164 100644
---- a/src/sugar3/graphics/palettemenu.py
-+++ b/src/sugar3/graphics/palettemenu.py
-@@ -56,7 +56,7 @@ def __init__(self):
- menu_item.show()
-
- def __edit_cb(self, menu_item):
-- print 'Edit...'
-+ print('Edit...')
-
- # Usually the Palette instance is returned in a create_palette function
- p = ItemPalette()
-diff --git a/src/sugar3/graphics/palettewindow.py b/src/sugar3/graphics/palettewindow.py
-index 3253fd00a..1cadbb677 100644
---- a/src/sugar3/graphics/palettewindow.py
-+++ b/src/sugar3/graphics/palettewindow.py
-@@ -43,6 +43,7 @@
-
- _pointer = None
-
-+
- def _get_pointer_position(widget):
- global _pointer
-
-@@ -53,6 +54,7 @@ def _get_pointer_position(widget):
- screen, x, y = _pointer.get_position()
- return (x, y)
-
-+
- def _calculate_gap(a, b):
- """Helper function to find the gap position and size of widget a"""
- # Test for each side if the palette and invoker are
-@@ -420,6 +422,8 @@ def popdown(self):
- self.disconnect_by_func(self.__enter_notify_event_cb)
- self.disconnect_by_func(self.__leave_notify_event_cb)
- self.hide()
-+
-+
- if hasattr(_PaletteWindowWidget, 'set_css_name'):
- _PaletteWindowWidget.set_css_name('palette')
-
-@@ -954,7 +958,7 @@ def get_alignment(self, palette_dim):
- dright = screen_area.x + screen_area.width - rect.x - rect.width
-
- ih = 0
--
-+
- if palette_dim.width == 0:
- ph = 0
-
-@@ -1315,7 +1319,7 @@ def attach(self, parent):
- self._leave_hid = self._item.connect('leave-notify-event',
- self.__leave_notify_event_cb)
- self._release_hid = self._item.connect('button-release-event',
-- self.__button_release_event_cb)
-+ self.__button_release_event_cb)
- self._long_pressed_hid = self._long_pressed_controller.connect(
- 'pressed',
- self.__long_pressed_event_cb, self._item)
-@@ -1325,9 +1329,9 @@ def attach(self, parent):
-
- def detach(self):
- Invoker.detach(self)
-- self._item.disconnect(self._enter_hid)
-- self._item.disconnect(self._leave_hid)
-- self._item.disconnect(self._release_hid)
-+ self._item.disconnect_by_func(self.__enter_notify_event_cb)
-+ self._item.disconnect_by_func(self.__leave_notify_event_cb)
-+ self._item.disconnect_by_func(self.__button_release_event_cb)
- self._long_pressed_controller.detach(self._item)
- self._long_pressed_controller.disconnect(self._long_pressed_hid)
-
-diff --git a/src/sugar3/graphics/popwindow.py b/src/sugar3/graphics/popwindow.py
-deleted file mode 100644
-index 5a4a4d9ea..000000000
---- a/src/sugar3/graphics/popwindow.py
-+++ /dev/null
-@@ -1,202 +0,0 @@
--# Copyright (C) 2016 Abhijit Patel
--#
--# This program is free software; you can redistribute it and/or modify
--# it under the terms of the GNU General Public License as published by
--# the Free Software Foundation; either version 2 of the License, or
--# (at your option) any later version.
--#
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--# GNU General Public License for more details.
--#
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
--
--'''
--Provide a PopWindow class for pop-up windows.
--Making PopWindow containing Gtk.Toolbar which also contains Gtk.Label
--and Toolbutton at the end of the Gtk.Toolbar.
--
--It is possible to change props like size and add more widgets PopWindow
--and also to Gtk.Toolbar.
--
--Example:
-- .. literalinclude: ..sugar/src/jarabe/view/viewsource.py
-- .. literalinclude: ..sugar/src/jarabe/view/viewhelp.py
--'''
--from gettext import gettext as _
--from gi.repository import Gtk
--from gi.repository import Gdk
--from gi.repository import GdkX11
--from gi.repository import GObject
--
--from sugar3.graphics import style
--from sugar3.graphics.toolbutton import ToolButton
--
--from jarabe.model import shell
--
--
--class PopWindow(Gtk.Window):
-- """
-- UI interface for activity Pop-up Windows.
-- PopWindows are the windows that open on the top of the current window.
-- These pop-up windows don't cover the whole screen.
-- They contain canvas content, alerts messages, a tray and a
-- toolbar.
--
-- FULLSCREEN and HALF_WIDTH for setting size of the window.
--
-- Kwargs:
-- size (int,int): size to be set of the window
-- window_xid (xlib.Window): xid of the parent window
-- """
-- FULLSCREEN = (Gdk.Screen.width() - style.GRID_CELL_SIZE * 3,
-- Gdk.Screen.height() - style.GRID_CELL_SIZE * 2)
--
-- HALF_WIDTH = ((Gdk.Screen.height() - style.GRID_CELL_SIZE * 3)/2,
-- (Gdk.Screen.height() - style.GRID_CELL_SIZE * 2))
--
-- def __init__(self, window_xid=None, **kwargs):
-- Gtk.Window.__init__(self, **kwargs)
-- self._parent_window_xid = window_xid
--
-- self.set_decorated(False)
-- self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
-- self.set_border_width(style.LINE_WIDTH)
-- self.set_has_resize_grip(False)
-- self.props.size = self.FULLSCREEN
--
-- self.connect('realize', self.__realize_cb)
-- self.connect('key-press-event', self.__key_press_event_cb)
-- self.connect('hide', self.__hide_cb)
--
-- self._vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
-- self.add(self._vbox)
-- self._vbox.show()
--
-- self._title_box = TitleBox()
-- self._title_box.close_button.connect(
-- 'clicked',
-- self.__close_button_clicked_cb)
-- self._title_box.set_size_request(-1, style.GRID_CELL_SIZE)
--
-- self._vbox.pack_start(self._title_box, False, True, 0)
-- self._title_box.show()
--
-- # Note:
-- # Not displaying the pop-up from here instead allowing
-- # the child class to display the window after modifications
-- # like chaninging window size, decorating, changing position.
--
-- def set_size(self, size):
-- width, height = size
-- self.set_size_request(width, height)
--
-- size = GObject.Property(type=None, setter=set_size)
--
-- def get_title_box(self):
-- '''
-- Getter method for title-box
--
-- Returns:
-- self._title_box (): Title or Tool Box
-- '''
-- return self._title_box
--
-- title_box = GObject.Property(type=str, getter=get_title_box)
--
-- def get_vbox(self):
-- '''
-- Getter method for canvas
--
-- Returns:
-- self._vbox (Gtk.Box): canvas
-- '''
-- return self._vbox
-- vbox = GObject.Property(type=str, getter=get_vbox)
--
-- def __close_button_clicked_cb(self, button):
-- self.destroy()
--
-- def __key_press_event_cb(self, window, event):
-- keyname = Gdk.keyval_name(event.keyval)
-- if keyname == 'Escape':
-- self.destroy()
--
-- def __realize_cb(self, widget):
-- self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
-- window = self.get_window()
-- window.set_accept_focus(True)
--
-- if self._parent_window_xid is not None:
-- display = Gdk.Display.get_default()
-- parent = GdkX11.X11Window.foreign_new_for_display(
-- display, self._parent_window_xid)
-- window.set_transient_for(parent)
-- shell.get_model().push_modal()
--
-- def __hide_cb(self, widget):
-- shell.get_model().pop_modal()
--
-- def add_view(self, widget, expand=True, fill=True, padding=0):
-- '''
-- Adds child to the vbox.
--
-- Args:
-- widget (Gtk.Widget): widget to be added
--
-- expand (bool): True if child is to be given extra space allocated
-- to vbox.
--
-- fill (bool): True if space given to child by the expand option is
-- actually allocated to child, rather than just padding it.
--
-- padding (int): extra space in pixels to put between child and its
-- neighbors, over and above the global amount specified
-- by spacing in vbox.
--
-- Returns:
-- None
-- '''
-- self._vbox.pack_start(widget, expand, fill, padding)
--
--
--class TitleBox(Gtk.Toolbar):
-- '''
-- Title box at the top of the pop-up window.
-- Title and close button are added to the box and as needed more widgets
-- can be added using self.add_widget method.
-- This box is optional as the inherited class can remove this block by
-- setting the self._set_title_box to False.
-- '''
--
-- def __init__(self):
-- Gtk.Toolbar.__init__(self)
--
-- self.close_button = ToolButton(icon_name='dialog-cancel')
-- self.close_button.set_tooltip(_('Close'))
-- self.insert(self.close_button, -1)
-- self.close_button.show()
--
-- self._label = Gtk.Label()
-- self._label.set_alignment(0, 0.5)
--
-- tool_item = Gtk.ToolItem()
-- tool_item.set_expand(True)
-- tool_item.add(self._label)
-- self._label.show()
-- self.insert(tool_item, 0)
-- tool_item.show()
--
-- def set_title(self, title):
-- '''
-- setter function for 'title' property.
-- Args:
-- title (str): title for the pop-up window
-- '''
-- self._label.set_markup('<b>%s</b>' % title)
-- self._label.show()
--
-- title = GObject.Property(type=str, setter=set_title)
-diff --git a/src/sugar3/graphics/progressicon.py b/src/sugar3/graphics/progressicon.py
-index 327487102..d001efc7c 100644
---- a/src/sugar3/graphics/progressicon.py
-+++ b/src/sugar3/graphics/progressicon.py
-@@ -41,6 +41,7 @@ class ProgressIcon(Gtk.DrawingArea):
- fill_color (string): The main (inside) color of progressicon
- [e.g. fill_color=style.COLOR_BLUE.get_svg()
- '''
-+
- def __init__(self, icon_name, pixel_size, stroke_color, fill_color,
- direction='vertical'):
- Gtk.DrawingArea.__init__(self)
-diff --git a/src/sugar3/graphics/scrollingdetector.py b/src/sugar3/graphics/scrollingdetector.py
-index c0b483b27..a533aae04 100644
---- a/src/sugar3/graphics/scrollingdetector.py
-+++ b/src/sugar3/graphics/scrollingdetector.py
-@@ -32,18 +32,18 @@
-
- class ScrollingDetector(GObject.GObject):
- '''
-- The scrolling detector sends signals when a scrolled window is scrolled and
-+ The scrolling detector sends signals when a scrolled window is scrolled and
- when a scrolled window stops scrolling. Only one `scroll-start` signal will be
-- emitted until scrolling stops.
--
-+ emitted until scrolling stops.
-+
- The `scroll-start` signal is emitted when scrolling begins and
- The `scroll-end` signal is emitted when scrolling ends
- Neither of these two signals have any arguments
--
-+
- Args:
- scrolled_window (Gtk.ScrolledWindow): A GTK scrolled window object for which
- scrolling is to be detected
--
-+
- timeout (int): time in milliseconds to establish the interval for which
- scrolling is detected
- '''
-@@ -65,7 +65,7 @@ def connect_scrolled_window(self):
- Connects scrolling detector to a scrolled window.
- Detects scrolling when the vertical scrollbar
- adjustment value is changed
--
-+
- Should be used to link an instance of a scrolling detector
- to a Scrolled Window, after setting scrolled_window
- '''
-diff --git a/src/sugar3/graphics/style.py b/src/sugar3/graphics/style.py
-index 1a5f47f66..8dafd5b7d 100644
---- a/src/sugar3/graphics/style.py
-+++ b/src/sugar3/graphics/style.py
-@@ -59,6 +59,7 @@ class Font(object):
- Args:
- desc (str): a description of the Font object
- '''
-+
- def __init__(self, desc):
- self._desc = desc
-
-@@ -84,6 +85,7 @@ class Color(object):
-
- alpha (double): transparency of color
- '''
-+
- def __init__(self, color, alpha=1.0):
- self._r, self._g, self._b = self._html_to_rgb(color)
- self._a = alpha
-@@ -112,7 +114,8 @@ def get_html(self):
- '''
- Returns string in the standard html Color format (#FFFFFF)
- '''
-- return '#%02x%02x%02x' % (self._r * 255, self._g * 255, self._b * 255)
-+ return '#%02x%02x%02x' % (
-+ int(self._r * 255), int(self._g * 255), int(self._b * 255))
-
- def _html_to_rgb(self, html_color):
- '''
-diff --git a/src/sugar3/graphics/toolbarbox.py b/src/sugar3/graphics/toolbarbox.py
-index c813da065..804e2b24f 100644
---- a/src/sugar3/graphics/toolbarbox.py
-+++ b/src/sugar3/graphics/toolbarbox.py
-@@ -203,6 +203,8 @@ def __remove_cb(self, sender, button):
- if button == self.expanded_button:
- self.remove(button.page_widget)
- self._expanded_button_index = -1
-+
-+
- if hasattr(ToolbarBox, 'set_css_name'):
- ToolbarBox.set_css_name('toolbarbox')
-
-diff --git a/src/sugar3/graphics/toolbox.py b/src/sugar3/graphics/toolbox.py
-index 5cd41f11d..23843b11b 100644
---- a/src/sugar3/graphics/toolbox.py
-+++ b/src/sugar3/graphics/toolbox.py
-@@ -32,7 +32,7 @@ class Toolbox(Gtk.VBox):
- Class to represent the toolbox of an activity. Groups a
- number of toolbars vertically, which can be accessed using their
- indices. The current toolbar is the only one displayed.
--
-+
- Emits `current-toolbar-changed` signal when the
- current toolbar is changed. This signal takes the current page index
- as an argument.
-@@ -71,13 +71,13 @@ def _notify_page_cb(self, notebook, pspec):
- def add_toolbar(self, name, toolbar):
- '''
- Adds a toolbar to this toolbox. Toolbar will be added
-- to the end of this toolbox, and it's index will be
-+ to the end of this toolbox, and it's index will be
- 1 greater than the previously added index (index will be
- 0 if it is the first toolbar added).
--
-+
- Args:
- name (string): name of toolbar to be added
--
-+
- toolbar (.. :class:`Gtk.Toolbar`): Gtk.Toolbar to be appended to this toolbox
- '''
- label = Gtk.Label(label=name)
-@@ -106,7 +106,7 @@ def add_toolbar(self, name, toolbar):
- def remove_toolbar(self, index):
- '''
- Removes toolbar at the index specified.
--
-+
- Args:
- index (int): index of the toolbar to be removed
- '''
-@@ -118,9 +118,9 @@ def remove_toolbar(self, index):
-
- def set_current_toolbar(self, index):
- '''
-- Sets the current toolbar to that of the index specified and
-+ Sets the current toolbar to that of the index specified and
- displays it.
--
-+
- Args:
- index (int): index of toolbar to be set as current toolbar
- '''
-diff --git a/src/sugar3/graphics/toolbutton.py b/src/sugar3/graphics/toolbutton.py
-index e8f4e9ed2..8b0031f77 100644
---- a/src/sugar3/graphics/toolbutton.py
-+++ b/src/sugar3/graphics/toolbutton.py
-@@ -27,7 +27,7 @@
- from sugar3.graphics.toolbutton import ToolButton
-
- def __clicked_cb(button):
-- print "tool button was clicked"
-+ print("tool button was clicked")
-
- w = Gtk.Window()
- w.connect('destroy', Gtk.main_quit)
-diff --git a/src/sugar3/graphics/tray.py b/src/sugar3/graphics/tray.py
-index da8dda99c..55db31afe 100644
---- a/src/sugar3/graphics/tray.py
-+++ b/src/sugar3/graphics/tray.py
-@@ -330,6 +330,8 @@ def get_item_index(self, item):
-
- def scroll_to_item(self, item):
- self._viewport.scroll_to_item(item)
-+
-+
- if hasattr(HTray, 'set_css_name'):
- HTray.set_css_name('htray')
-
-@@ -424,6 +426,8 @@ def get_item_index(self, item):
-
- def scroll_to_item(self, item):
- self._viewport.scroll_to_item(item)
-+
-+
- if hasattr(VTray, 'set_css_name'):
- VTray.set_css_name('VTray')
-
-diff --git a/src/sugar3/graphics/xocolor.py b/src/sugar3/graphics/xocolor.py
-index 4c6e33a87..e5d7e4e85 100644
---- a/src/sugar3/graphics/xocolor.py
-+++ b/src/sugar3/graphics/xocolor.py
-@@ -20,6 +20,7 @@
- Each pair of colors represents the fill color and the stroke color
- '''
-
-+import six
- import random
- import logging
-
-@@ -210,11 +211,11 @@
- def _parse_string(color_string):
- '''
- Returns array of length 2 of two colors in standard html form of [stroke color, fill color]
--
-+
- Args:
- color_string (string): two html format strings separated by a comma
- '''
-- if not isinstance(color_string, (str, unicode)):
-+ if not isinstance(color_string, (six.text_type, six.binary_type)):
- logging.error('Invalid color string: %r', color_string)
- return None
-
-@@ -233,13 +234,14 @@ def _parse_string(color_string):
- class XoColor:
- '''
- Defines color for XO
--
-+
- Args:
-- color_string (string): two html format strings separated
-- by a comma, "white", or "insensitive". If color_string
-- is None, the user's color will be created. If parsed_color
-- cannot be created, a random color will be used
-+ color_string (string): two html format strings separated
-+ by a comma, "white", or "insensitive". If color_string
-+ is None, the user's color will be created. If parsed_color
-+ cannot be created, a random color will be used
- '''
-+
- def __init__(self, color_string=None):
- parsed_color = None
-
-@@ -261,7 +263,7 @@ def __cmp__(self, other):
- '''
- Compares two XO colors by their stroke and fill color
- Returns 0 if they are equal and -1 if they are unequal
--
-+
- Args:
- other (object): other XO color to compare
- '''
-@@ -295,12 +297,12 @@ def to_string(self):
-
- f = open(sys.argv[1], 'r')
-
-- print 'colors = ['
-+ print('colors = [')
-
- for line in f.readlines():
- match = re.match(r'fill: ([A-Z0-9]*) stroke: ([A-Z0-9]*)', line)
-- print "['#%s', '#%s'], \\" % (match.group(2), match.group(1))
-+ print("['#%s', '#%s'], \\" % (match.group(2), match.group(1)))
-
-- print ']'
-+ print(']')
-
- f.close()
-diff --git a/src/sugar3/logger.py b/src/sugar3/logger.py
-index 2e01b1cb4..43ef5b56c 100644
---- a/src/sugar3/logger.py
-+++ b/src/sugar3/logger.py
-@@ -20,16 +20,17 @@
- STABLE.
- """
-
-+import six
- import array
- import collections
- import errno
- import logging
- import sys
- import os
--import repr as repr_
- import decorator
- import time
-
-+from six.moves import reprlib as repr_
- from sugar3 import env
-
- # Let's keep this module self contained so that it can be easily
-@@ -104,8 +105,8 @@ def cleanup():
- for f in os.listdir(root):
- os.remove(os.path.join(root, f))
- os.rmdir(root)
-- except OSError, e:
-- print "Could not remove old logs files %s" % e
-+ except OSError as e:
-+ print("Could not remove old logs files %s" % e)
-
- if len(backup_logs) > 0:
- name = str(int(time.time()))
-@@ -116,7 +117,7 @@ def cleanup():
- source_path = os.path.join(logs_dir, log)
- dest_path = os.path.join(backup_dir, log)
- os.rename(source_path, dest_path)
-- except OSError, e:
-+ except OSError as e:
- # gracefully deal w/ disk full
- if e.errno != errno.ENOSPC:
- raise e
-@@ -145,7 +146,7 @@ def __init__(self, stream):
- def write(self, s):
- try:
- self._stream.write(s)
-- except IOError, e:
-+ except IOError as e:
- # gracefully deal w/ disk full
- if e.errno != errno.ENOSPC:
- raise e
-@@ -153,7 +154,7 @@ def write(self, s):
- def flush(self):
- try:
- self._stream.flush()
-- except IOError, e:
-+ except IOError as e:
- # gracefully deal w/ disk full
- if e.errno != errno.ENOSPC:
- raise e
-@@ -177,7 +178,7 @@ def flush(self):
-
- sys.stdout = SafeLogWrapper(sys.stdout)
- sys.stderr = SafeLogWrapper(sys.stderr)
-- except OSError, e:
-+ except OSError as e:
- # if we're out of space, just continue
- if e.errno != errno.ENOSPC:
- raise e
-@@ -188,13 +189,15 @@ def flush(self):
- class TraceRepr(repr_.Repr):
-
- # better handling of subclasses of basic types, e.g. for DBus
-- _TYPES = [int, long, bool, tuple, list, array.array, set, frozenset,
-+ _TYPES = [int, bool, tuple, list, array.array, set, frozenset,
- collections.deque, dict, str]
-+ if six.PY2:
-+ _TYPES.append(long)
-
- def repr1(self, x, level):
- for t in self._TYPES:
- if isinstance(x, t):
-- return getattr(self, 'repr_'+t.__name__)(x, level)
-+ return getattr(self, 'repr_' + t.__name__)(x, level)
-
- return repr_.Repr.repr1(self, x, level)
-
-@@ -232,14 +235,14 @@ def _trace(f, *args, **kwargs):
- [trace_repr.repr(a)
- for (idx, a) in enumerate(args) if idx not in skip_args] +
- ['%s=%s' % (k, trace_repr.repr(v))
-- for (k, v) in kwargs.items() if k not in skip_kwargs])
-+ for (k, v) in list(kwargs.items()) if k not in skip_kwargs])
-
- trace_logger.log(TRACE, "%s(%s) invoked", f.__name__,
- params_formatted)
-
- try:
- res = f(*args, **kwargs)
-- except:
-+ except BaseException:
- trace_logger.exception("Exception occurred in %s" % f.__name__)
- raise
-
-diff --git a/src/sugar3/mime.py b/src/sugar3/mime.py
-index cd30fa70d..a2797d0d0 100644
---- a/src/sugar3/mime.py
-+++ b/src/sugar3/mime.py
-@@ -32,7 +32,9 @@
- from gi.repository import GdkPixbuf
- from gi.repository import Gio
-
--_ = lambda msg: gettext.dgettext('sugar-toolkit-gtk3', msg)
-+
-+def _(msg): return gettext.dgettext('sugar-toolkit-gtk3', msg)
-+
-
- GENERIC_TYPE_TEXT = 'Text'
- GENERIC_TYPE_IMAGE = 'Image'
-@@ -185,14 +187,14 @@ def get_mime_parents(mime_type):
- with open(subclasses_path) as parents_file:
- for line in parents_file:
- subclass, parent = line.split()
-- if subclass not in _subclasses.keys():
-+ if subclass not in list(_subclasses.keys()):
- _subclasses[subclass] = [parent]
- else:
- _subclasses[subclass].append(parent)
-
- _subclasses_timestamps = timestamps
-
-- if mime_type in _subclasses.keys():
-+ if mime_type in list(_subclasses.keys()):
- return _subclasses[mime_type]
- else:
- return []
-diff --git a/src/sugar3/network.py b/src/sugar3/network.py
-index 771a3caed..6afa4f8a8 100644
---- a/src/sugar3/network.py
-+++ b/src/sugar3/network.py
-@@ -21,14 +21,14 @@
-
- import os
- import threading
--import urllib
-+from six.moves import urllib
- import fcntl
- import tempfile
-
- from gi.repository import GObject
- from gi.repository import GLib
--import SimpleHTTPServer
--import SocketServer
-+from six.moves import SimpleHTTPServer
-+from six.moves import socketserver
-
-
- __authinfos = {}
-@@ -46,7 +46,7 @@ def _del_authinfo():
- del __authinfos[threading.currentThread()]
-
-
--class GlibTCPServer(SocketServer.TCPServer):
-+class GlibTCPServer(socketserver.TCPServer):
- """GlibTCPServer
-
- Integrate socket accept into glib mainloop.
-@@ -56,7 +56,7 @@ class GlibTCPServer(SocketServer.TCPServer):
- request_queue_size = 20
-
- def __init__(self, server_address, RequestHandlerClass):
-- SocketServer.TCPServer.__init__(self, server_address,
-+ socketserver.TCPServer.__init__(self, server_address,
- RequestHandlerClass)
- self.socket.setblocking(0) # Set nonblocking
-
-@@ -212,7 +212,7 @@ def __init__(self, url, destdir=None):
- GObject.GObject.__init__(self)
-
- def start(self, destfile=None, destfd=None):
-- self._info = urllib.urlopen(self._url)
-+ self._info = urllib.request.urlopen(self._url)
- self._outf = None
- self._fname = None
- if destfd and not destfile:
-@@ -226,14 +226,14 @@ def start(self, destfile=None, destfd=None):
- self._outf = destfd
- else:
- self._outf = os.open(self._fname, os.O_RDWR |
-- os.O_TRUNC | os.O_CREAT, 0644)
-+ os.O_TRUNC | os.O_CREAT, 0o644)
- else:
- fname = self._get_filename_from_headers(self._info.headers)
- self._suggested_fname = fname
-- garbage_, path = urllib.splittype(self._url)
-- garbage_, path = urllib.splithost(path or "")
-- path, garbage_ = urllib.splitquery(path or "")
-- path, garbage_ = urllib.splitattr(path or "")
-+ garbage_, path = urllib.parse.splittype(self._url)
-+ garbage_, path = urllib.parse.splithost(path or "")
-+ path, garbage_ = urllib.parse.splitquery(path or "")
-+ path, garbage_ = urllib.parse.splitattr(path or "")
- suffix = os.path.splitext(path)[1]
- (self._outf, self._fname) = tempfile.mkstemp(suffix=suffix,
- dir=self._destdir)
-@@ -291,7 +291,7 @@ def _read_next_chunk(self, source, condition):
- self.cleanup()
- self.emit('finished', self._fname, self._suggested_fname)
- return False
-- except Exception, err:
-+ except Exception as err:
- self.cleanup(remove=True)
- self.emit('error', 'Error downloading file: %r' % err)
- return False
-diff --git a/src/sugar3/presence/activity.py b/src/sugar3/presence/activity.py
-index f07aab827..6097b8379 100644
---- a/src/sugar3/presence/activity.py
-+++ b/src/sugar3/presence/activity.py
-@@ -21,6 +21,7 @@
- STABLE.
- """
-
-+import six
- import logging
- from functools import partial
-
-@@ -124,6 +125,11 @@ def __init__(self, account_path, connection, room_handle=None,
-
- def _start_tracking_properties(self):
- bus = dbus.SessionBus()
-+ arg_dict = dict(reply_handler=self.__got_properties_cb,
-+ error_handler=self.__error_handler_cb)
-+ if six.PY2:
-+ arg_dict = arg_dict.update(utf8_strings=True)
-+
- self._get_properties_call = bus.call_async(
- self.telepathy_conn.requested_bus_name,
- self.telepathy_conn.object_path,
-@@ -131,9 +137,7 @@ def _start_tracking_properties(self):
- 'GetProperties',
- 'u',
- (self.room_handle,),
-- reply_handler=self.__got_properties_cb,
-- error_handler=self.__error_handler_cb,
-- utf8_strings=True)
-+ arg_dict)
-
- # As only one Activity instance is needed per activity process,
- # we can afford listening to ActivityPropertiesChanged like this.
-@@ -144,7 +148,7 @@ def _start_tracking_properties(self):
-
- def __activity_properties_changed_cb(self, room_handle, properties):
- _logger.debug('%r: Activity properties changed to %r' % (self,
-- properties))
-+ properties))
- self._update_properties(properties)
-
- def __got_properties_cb(self, properties):
-@@ -239,7 +243,7 @@ def get_joined_buddies(self):
- returns list of presence Buddy objects that we can successfully
- create from the buddy object paths that PS has for this activity.
- """
-- return self._joined_buddies.values()
-+ return list(self._joined_buddies.values())
-
- def get_buddy_by_handle(self, handle):
- """Retrieve the Buddy object given a telepathy handle.
-@@ -300,8 +304,9 @@ def _start_tracking_channel(self):
- channel.connect_to_signal('Closed', self.__text_channel_closed_cb)
-
- def __get_all_members_cb(self, members, local_pending, remote_pending):
-- _logger.debug('__get_all_members_cb %r %r' % (members,
-- self._text_channel_group_flags))
-+ _logger.debug(
-+ '__get_all_members_cb %r %r' %
-+ (members, self._text_channel_group_flags))
- if self._channel_self_handle in members:
- members.remove(self._channel_self_handle)
-
-@@ -631,8 +636,9 @@ def _tubes_ready(self):
- self._add_self_to_channel()
-
- def __text_channel_group_flags_changed_cb(self, added, removed):
-- _logger.debug('__text_channel_group_flags_changed_cb %r %r' % (added,
-- removed))
-+ _logger.debug(
-+ '__text_channel_group_flags_changed_cb %r %r' %
-+ (added, removed))
- self.text_channel_group_flags |= added
- self.text_channel_group_flags &= ~removed
-
-diff --git a/src/sugar3/presence/buddy.py b/src/sugar3/presence/buddy.py
-index 6f85ae894..2e0190c00 100644
---- a/src/sugar3/presence/buddy.py
-+++ b/src/sugar3/presence/buddy.py
-@@ -22,7 +22,7 @@
- """
-
- import logging
--
-+import six
- from gi.repository import GObject
- import dbus
- from telepathy.interfaces import CONNECTION, \
-@@ -103,7 +103,7 @@ def set_color(self, color):
- def get_current_activity(self):
- if self._current_activity is None:
- return None
-- for activity in self._activities.values():
-+ for activity in list(self._activities.values()):
- if activity.props.id == self._current_activity:
- return activity
- return None
-@@ -164,6 +164,12 @@ def __init__(self, account_path, contact_id):
- dbus_interface=CONNECTION)
- self.contact_handle = handles[0]
-
-+ arg_dict = dict(reply_handler=self.__got_properties_cb,
-+ error_handler=self.__error_handler_cb,
-+ byte_arrays = True)
-+ if six.PY2:
-+ arg_dict = arg_dict.update(utf8_strings=True)
-+
- self._get_properties_call = bus.call_async(
- connection_name,
- connection.object_path,
-@@ -171,10 +177,7 @@ def __init__(self, account_path, contact_id):
- 'GetProperties',
- 'u',
- (self.contact_handle,),
-- reply_handler=self.__got_properties_cb,
-- error_handler=self.__error_handler_cb,
-- utf8_strings=True,
-- byte_arrays=True)
-+ arg_dict)
-
- self._get_attributes_call = bus.call_async(
- connection_name,
-@@ -245,4 +248,3 @@ def __init__(self):
-
- self.props.nick = get_nick_name()
- self.props.color = get_color().to_string()
--
-diff --git a/src/sugar3/presence/connectionmanager.py b/src/sugar3/presence/connectionmanager.py
-index 325c200cc..dbb957caf 100644
---- a/src/sugar3/presence/connectionmanager.py
-+++ b/src/sugar3/presence/connectionmanager.py
-@@ -92,7 +92,8 @@ def __status_changed_cb(self, account_path, status, reason):
-
- def get_preferred_connection(self):
- best_connection = None, None
-- for account_path, connection in self._connections_per_account.items():
-+ for account_path, connection in list(
-+ self._connections_per_account.items()):
- if 'salut' in account_path and connection.connected:
- best_connection = account_path, connection.connection
- elif 'gabble' in account_path and connection.connected:
-@@ -107,7 +108,8 @@ def get_connections_per_account(self):
- return self._connections_per_account
-
- def get_account_for_connection(self, connection_path):
-- for account_path, connection in self._connections_per_account.items():
-+ for account_path, connection in list(
-+ self._connections_per_account.items()):
- if connection.connection.object_path == connection_path:
- return account_path
- return None
-diff --git a/src/sugar3/presence/presenceservice.py b/src/sugar3/presence/presenceservice.py
-index 8b66b0e54..2f9f85104 100644
---- a/src/sugar3/presence/presenceservice.py
-+++ b/src/sugar3/presence/presenceservice.py
-@@ -78,7 +78,8 @@ def get_activity(self, activity_id, warn_if_none=True):
- connection_manager = get_connection_manager()
- connections_per_account = \
- connection_manager.get_connections_per_account()
-- for account_path, connection in connections_per_account.items():
-+ for account_path, connection in list(
-+ connections_per_account.items()):
- if not connection.connected:
- continue
- logging.debug('Calling GetActivity on %s' % account_path)
-@@ -86,13 +87,13 @@ def get_activity(self, activity_id, warn_if_none=True):
- room_handle = connection.connection.GetActivity(
- activity_id,
- dbus_interface=CONN_INTERFACE_ACTIVITY_PROPERTIES)
-- except dbus.exceptions.DBusException, e:
-+ except dbus.exceptions.DBusException as e:
- name = 'org.freedesktop.Telepathy.Error.NotAvailable'
- if e.get_dbus_name() == name:
- logging.debug("There's no shared activity with the id "
- "%s" % activity_id)
- elif e.get_dbus_name() == \
-- 'org.freedesktop.DBus.Error.UnknownMethod':
-+ 'org.freedesktop.DBus.Error.UnknownMethod':
- logging.warning(
- 'Telepathy Account %r does not support '
- 'Sugar collaboration', account_path)
-diff --git a/src/sugar3/presence/tubeconn.py b/src/sugar3/presence/tubeconn.py
-index 9a496d984..8b1e2ff92 100644
---- a/src/sugar3/presence/tubeconn.py
-+++ b/src/sugar3/presence/tubeconn.py
-@@ -24,6 +24,7 @@
- __docformat__ = 'reStructuredText'
-
-
-+import six
- import logging
-
- from dbus.connection import Connection
-@@ -77,7 +78,9 @@ def _on_get_self_handle_error(self, e):
-
- def close(self):
- self._dbus_names_changed_match.remove()
-- self._on_dbus_names_changed(self.tube_id, (), self.participants.keys())
-+ self._on_dbus_names_changed(
-+ self.tube_id, (), list(
-+ self.participants.keys()))
- super(TubeConnection, self).close()
-
- def _on_get_dbus_names_reply(self, names):
-@@ -111,6 +114,6 @@ def watch_participants(self, callback):
- # GetDBusNames already returned: fake a participant add event
- # immediately
- added = []
-- for k, v in self.participants.iteritems():
-+ for k, v in six.iteritems(self.participants):
- added.append((k, v))
- callback(added, [])
-diff --git a/src/sugar3/profile.py b/src/sugar3/profile.py
-index 818afe05a..e46943fde 100644
---- a/src/sugar3/profile.py
-+++ b/src/sugar3/profile.py
-@@ -21,7 +21,8 @@
- from gi.repository import Gio
- import os
- import logging
--from ConfigParser import ConfigParser
-+
-+from six.moves.configparser import ConfigParser
-
- from sugar3 import env
- from sugar3 import util
-diff --git a/src/sugar3/speech.py b/src/sugar3/speech.py
-index fd2c5b5f7..19416043e 100644
---- a/src/sugar3/speech.py
-+++ b/src/sugar3/speech.py
-@@ -33,7 +33,7 @@
- from gi.repository import Gst
- Gst.init(None)
- Gst.parse_launch('espeak')
--except:
-+except BaseException:
- logging.error('Gst or the espeak plugin is not installed in the system.')
- _HAS_GST = False
-
-@@ -268,7 +268,12 @@ def say_text(self, text, pitch=None, rate=None, lang_code=None):
- else:
- voice_name = self._player.get_all_voices()[lang_code]
- if text:
-- logging.error('PLAYING %r lang %r pitch %r rate %r', text, voice_name, pitch, rate)
-+ logging.error(
-+ 'PLAYING %r lang %r pitch %r rate %r',
-+ text,
-+ voice_name,
-+ pitch,
-+ rate)
- self._player.speak(pitch, rate, voice_name, text)
-
- def say_selected_text(self):
-diff --git a/src/sugar3/test/Makefile.am b/src/sugar3/test/Makefile.am
-index 2ccac0223..6d77c2fc6 100644
---- a/src/sugar3/test/Makefile.am
-+++ b/src/sugar3/test/Makefile.am
-@@ -3,4 +3,4 @@ sugar_PYTHON = \
- __init__.py \
- discover.py \
- uitree.py \
-- unittest.py
-+ _unittest.py
-diff --git a/src/sugar3/test/unittest.py b/src/sugar3/test/_unittest.py
-similarity index 93%
-rename from src/sugar3/test/unittest.py
-rename to src/sugar3/test/_unittest.py
-index d3e65ee24..6c51d7ee6 100644
---- a/src/sugar3/test/unittest.py
-+++ b/src/sugar3/test/_unittest.py
-@@ -18,8 +18,6 @@
- UNSTABLE.
- """
-
--from __future__ import absolute_import
--
- import logging
- import os
- import unittest
-@@ -52,11 +50,11 @@ def tearDown(self):
- @contextmanager
- def run_view(self, name):
- view_path = os.path.join("views", "%s.py" % name)
-- process = subprocess.Popen(["python", view_path])
-+ process = subprocess.Popen(["python3", view_path])
-
- try:
- yield
-- except:
-+ except BaseException:
- logging.debug(uitree.get_root().dump())
- raise
- finally:
-@@ -77,12 +75,12 @@ def _run_activity(self, options=None):
- cmd += options
- process = subprocess.Popen(cmd)
- else:
-- print "No bundle_id specified."
-+ print("No bundle_id specified.")
- return
-
- try:
- yield
-- except:
-+ except BaseException:
- logging.debug(uitree.get_root().dump())
- raise
- finally:
-diff --git a/src/sugar3/test/discover.py b/src/sugar3/test/discover.py
-index 8de28f8c7..dbf898d1d 100644
---- a/src/sugar3/test/discover.py
-+++ b/src/sugar3/test/discover.py
-@@ -18,8 +18,6 @@
- UNSTABLE.
- """
-
--from __future__ import absolute_import
--
- import argparse
- import sys
- import os
-diff --git a/src/sugar3/test/uitree.py b/src/sugar3/test/uitree.py
-index a4e8e7109..3da33c1c2 100644
---- a/src/sugar3/test/uitree.py
-+++ b/src/sugar3/test/uitree.py
-@@ -44,7 +44,7 @@ def wrapped(*args, **kwargs):
-
- try:
- result = func(*args, **kwargs)
-- except GLib.GError, e:
-+ except GLib.GError as e:
- # The application is not responding, try again
- if e.code == Atspi.Error.IPC:
- continue
-diff --git a/src/sugar3/util.py b/src/sugar3/util.py
-index f44f250cb..45cbd3688 100644
---- a/src/sugar3/util.py
-+++ b/src/sugar3/util.py
-@@ -20,6 +20,7 @@
- UNSTABLE. We have been adding helpers randomly to this module.
- """
-
-+import six
- import os
- import time
- import hashlib
-@@ -31,20 +32,26 @@
- import atexit
-
-
--_ = lambda msg: gettext.dgettext('sugar-toolkit-gtk3', msg)
-+def _(msg): return gettext.dgettext('sugar-toolkit-gtk3', msg)
-
-
- def printable_hash(in_hash):
- """Convert binary hash data into printable characters."""
- printable = ""
- for char in in_hash:
-- printable = printable + binascii.b2a_hex(char)
-+ if six.PY3:
-+ char = bytes([char])
-+ printable = printable + binascii.b2a_hex(char).decode()
-+ else:
-+ printable = printable + binascii.b2a_hex(char)
- return printable
-
-
- def sha_data(data):
- """sha1 hash some bytes."""
- sha_hash = hashlib.sha1()
-+ if six.PY3:
-+ data = data.encode('utf-8')
- sha_hash.update(data)
- return sha_hash.digest()
-
-@@ -81,7 +88,7 @@ def is_hex(s):
-
- def validate_activity_id(actid):
- """Validate an activity ID."""
-- if not isinstance(actid, (str, unicode)):
-+ if not isinstance(actid, (six.binary_type, six.text_type)):
- return False
- if len(actid) != ACTIVITY_ID_LEN:
- return False
-@@ -204,7 +211,7 @@ def itervalues(self):
- yield j
-
- def keys(self):
-- return self.d.keys()
-+ return list(self.d.keys())
-
-
- units = [['%d year', '%d years', 356 * 24 * 60 * 60],
-@@ -331,13 +338,14 @@ def __del__(self):
-
- def _cleanup_temp_files():
- logging.debug('_cleanup_temp_files')
-- for path in _tracked_paths.keys():
-+ for path in list(_tracked_paths.keys()):
- try:
- os.unlink(path)
-- except:
-+ except BaseException:
- # pylint: disable=W0702
- logging.exception('Exception occurred in _cleanup_temp_files')
-
-+
- atexit.register(_cleanup_temp_files)
-
-
More information about the arch-commits
mailing list