Port from Python 2 to six

Signed-off-by: James Cameron <quozl@laptop.org>
This commit is contained in:
Pro-Panda 2018-03-01 17:28:56 +05:30 committed by James Cameron
parent 6345da8e07
commit aa8a5e70c4
74 changed files with 623 additions and 700 deletions

View File

@ -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

View File

@ -1 +1 @@
dist_bin_SCRIPTS = sugar-activity sugar-activity-web
dist_bin_SCRIPTS = sugar-activity sugar-activity-web sugar-activity3

View File

@ -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()

View File

@ -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

5
bin/sugar-activity3 Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env python3
from sugar3.activity import activityinstance
activityinstance.main()

View File

@ -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

View File

@ -226,25 +226,25 @@ htmlhelp_basename = 'SugarToolkitGTK3doc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'SugarToolkitGTK3.tex', u'Sugar Toolkit GTK3 Documentation',
u'Sugar Labs', 'manual'),
(master_doc, 'SugarToolkitGTK3.tex', u'Sugar Toolkit GTK3 Documentation',
u'Sugar Labs', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@ -287,9 +287,9 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'SugarToolkitGTK3', u'Sugar Toolkit GTK3 Documentation',
author, 'SugarToolkitGTK3', 'One line description of project.',
'Miscellaneous'),
(master_doc, 'SugarToolkitGTK3', u'Sugar Toolkit GTK3 Documentation',
author, 'SugarToolkitGTK3', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.

View File

@ -21,11 +21,11 @@ box.pack_start(alert, False, False, 0)
# Called when an alert object throws a response event.
def __alert_response_cb(alert, response_id):
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')
alert.connect('response', __alert_response_cb)

View File

@ -23,7 +23,7 @@ class _Animation(animator.Animation):
def __animation_completed_cb(anim):
print 'Animation completed'
print('Animation completed')
w = Gtk.Window()

View File

@ -24,7 +24,7 @@ separator.show()
def color_changed_cb(button, pspec):
print button.get_color()
print(button.get_color())
color_button = ColorToolButton()

View File

@ -6,7 +6,7 @@ set_theme()
def __combo_changed_cb(combo):
print 'Combo changed to %r' % combo.get_value()
print('Combo changed to %r' % combo.get_value())
w = Gtk.Window()

View File

@ -13,14 +13,14 @@ class MyCellRenderer(Gtk.CellRenderer):
Gtk.CellRenderer.__init__(self)
def __del__(self):
print "cellrenderer destroy"
print("cellrenderer destroy")
def do_render(self, cairo_t, widget, background_area, cell_area, flags):
pass
def window_destroy_cb(*kwargs):
print "window destroy"
print("window destroy")
Gtk.main_quit()
@ -30,7 +30,7 @@ window.show()
def treeview_destroy_cb(*kwargs):
print "treeview destroy"
print("treeview destroy")
treeview = Gtk.TreeView()

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
from gi.repository import Gtk
import common

View File

@ -6,11 +6,11 @@ set_theme()
def __go_next_cb(entry, icon_pos, data=None):
print 'Go next'
print('Go next')
def __entry_activate_cb(widget, data=None):
print 'Entry activate'
print('Entry activate')
w = Gtk.Window()

View File

@ -19,7 +19,7 @@ box.show()
def echo(button, label):
if not button.props.active:
return
print label
print(label)
palette = RadioPalette()

View File

@ -12,12 +12,12 @@ import common
def _scroll_start_cb(event, treeview, invoker):
print "Scroll starts"
print("Scroll starts")
invoker.detach()
def _scroll_end_cb(event, treeview, invoker):
print "Scroll ends"
print("Scroll ends")
invoker.attach_treeview(treeview)
@ -30,7 +30,7 @@ data_dir = os.getenv('GTK_DATA_PREFIX', '/usr/')
iconlist = os.listdir(os.path.join(data_dir,
'share/icons/sugar/scalable/actions/'))
print "Displaying %s icons" % len(iconlist)
print("Displaying %s icons" % len(iconlist))
for icon in iconlist:
icon = os.path.basename(icon)
icon = icon[:icon.find('.')]

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
from gi.repository import Gtk
from sugar3.graphics.icon import Icon

View File

@ -21,7 +21,7 @@ toolbar_box.toolbar.insert(separator, -1)
def __clicked_cb(button):
n = int(button.get_tooltip())
button.set_tooltip(str(n + 1))
print "tool button click count %d" % n
print("tool button click count %d" % n)
tool_button = ToolButton(icon_name='view-radial', tooltip='0')

View File

@ -2,6 +2,7 @@ sugardir = $(pythondir)/sugar3/activity
sugar_PYTHON = \
__init__.py \
activity.py \
activityinstance.py \
activityfactory.py \
activityhandle.py \
activityservice.py \

View File

@ -158,6 +158,7 @@ Hint: A good and simple activity to learn from is the Read activity.
You may copy it and use it as a template.
'''
import six
import gettext
import logging
import os
@ -165,7 +166,6 @@ import signal
import time
from hashlib import sha1
from functools import partial
import StringIO
import cairo
import json
@ -206,7 +206,9 @@ from errno import EEXIST
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 @@ class Activity(Window, Gtk.Container):
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 @@ class Activity(Window, Gtk.Container):
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 @@ class Activity(Window, Gtk.Container):
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 @@ class Activity(Window, Gtk.Container):
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 @@ class Activity(Window, Gtk.Container):
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 @@ class Activity(Window, Gtk.Container):
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 @@ class Activity(Window, Gtk.Container):
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 @@ class _ClientHandler(dbus.service.Object, DBusProperties):
}
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 @@ class _ClientHandler(dbus.service.Object, DBusProperties):
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

View File

@ -23,7 +23,6 @@ the moment there is no reason to stabilize this API.
"""
import logging
import dbus
from gi.repository import GObject
from gi.repository import GLib
@ -53,7 +52,7 @@ except ValueError:
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 @@ class ActivityCreationHandler(GObject.GObject):
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()),

View File

@ -24,26 +24,26 @@ journal object id's,
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 @@ class ActivityHandle(object):
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:

View File

@ -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()

View File

@ -79,5 +79,5 @@ class ActivityService(dbus.service.Object):
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)

View File

@ -40,12 +40,13 @@ import gettext
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 @@ class Builder(object):
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 @@ class Installer(Packager):
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")

View File

@ -28,8 +28,8 @@ GObject.threads_init()
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 @@ class LocalHTTPServer(HTTPServer):
# 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 @@ class LocalHTTPServer(HTTPServer):
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

View File

@ -34,7 +34,7 @@ from sugar3.graphics.palettemenu import PaletteMenuBox
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):

View File

@ -44,7 +44,9 @@ an `[Activity]` header on the first line:
* `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 @@ Example `activity.info`
[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

View File

@ -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 @@ class ActivityBundle(Bundle):
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)

View File

@ -20,10 +20,10 @@
UNSTABLE.
"""
import six
import os
import logging
import shutil
import StringIO
import zipfile
@ -74,7 +74,7 @@ class Bundle(object):
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 @@ class Bundle(object):
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 @@ class Bundle(object):
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 @@ class Bundle(object):
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

View File

@ -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 = []

View File

@ -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 @@ class ContentBundle(Bundle):
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

View File

@ -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 @@ class DSMetadata(GObject.GObject):
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 @@ class DSMetadata(GObject.GObject):
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 @@ class DSMetadata(GObject.GObject):
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 @@ class DSMetadata(GObject.GObject):
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

View File

@ -1,4 +1,6 @@
import weakref
import six
try:
set
except NameError:
@ -11,7 +13,7 @@ WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
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 @@ class Signal(object):
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 @@ class Signal(object):
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__

View File

@ -5,6 +5,7 @@ Provides a way to safely weakref any function, including bound methods (which
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 @@ class BoundMethodWeakref(object):
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 @@ class BoundMethodWeakref(object):
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 @@ class BoundMethodWeakref(object):
__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 @@ class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
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 @@ class BoundNonDescriptorMethodWeakref(BoundMethodWeakref):
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__

View File

@ -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)

View File

@ -16,7 +16,6 @@ sugar_PYTHON = \
palettemenu.py \
palettewindow.py \
panel.py \
popwindow.py \
radiopalette.py \
radiotoolbutton.py \
scrollingdetector.py \

View File

@ -61,7 +61,7 @@ from sugar3.graphics import style
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 @@ class Alert(Gtk.EventBox):
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 @@ class ConfirmationAlert(Alert):
# 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 @@ class ErrorAlert(Alert):
# 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 @@ class _TimeoutIcon(Gtk.Alignment):
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 @@ class TimeoutAlert(_TimeoutAlert):
# 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 @@ class NotifyAlert(_TimeoutAlert):
# 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):

View File

@ -29,7 +29,7 @@ from sugar3.graphics.icon import Icon
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 @@ if not hasattr(GObject.ParamFlags, 'READWRITE'):
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 @@ class _ColorButton(Gtk.Button):
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 @@ class _ColorButton(Gtk.Button):
'''
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 @@ class _ColorButton(Gtk.Button):
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 @@ class ColorToolButton(Gtk.ToolItem):
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 @@ class ColorToolButton(Gtk.ToolItem):
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 @@ class ColorToolButton(Gtk.ToolItem):
'''
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 @@ class ColorToolButton(Gtk.ToolItem):
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

View File

@ -87,11 +87,13 @@ In this example, the badge will be centered at 97.0% on the X axis,
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 @@ class _SVGLoader(object):
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 @@ class _IconBuffer(object):
# 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 @@ class Icon(Gtk.Image):
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 @@ class Icon(Gtk.Image):
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 @@ class Icon(Gtk.Image):
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 @@ class EventIcon(Gtk.EventBox):
# 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 @@ class CanvasIcon(EventIcon):
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()

View File

@ -61,7 +61,7 @@ class IconEntry(Gtk.Entry):
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)

View File

@ -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 @@ class ObjectChooser(object):
def run(self):
"""
Runs the object chooser and displays it.
Returns:
Gtk.ResponseType constant, the response received from displaying the
object chooser.

View File

@ -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()

View File

@ -56,7 +56,7 @@ Example:
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()

View File

@ -43,6 +43,7 @@ from sugar3.graphics.icon import CellRendererIcon
_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 @@ class _PaletteWindowWidget(Gtk.Window):
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 @@ class Invoker(GObject.GObject):
dright = screen_area.x + screen_area.width - rect.x - rect.width
ih = 0
if palette_dim.width == 0:
ph = 0
@ -1315,7 +1319,7 @@ class CursorInvoker(Invoker):
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 @@ class CursorInvoker(Invoker):
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)

View File

@ -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)

View File

@ -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)

View File

@ -32,18 +32,18 @@ from gi.repository import GLib
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 @@ class ScrollingDetector(GObject.GObject):
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
'''

View File

@ -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 @@ class Color(object):
'''
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):
'''

View File

@ -203,6 +203,8 @@ class ToolbarBox(Gtk.VBox):
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')

View File

@ -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 @@ class Toolbox(Gtk.VBox):
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 @@ class Toolbox(Gtk.VBox):
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 @@ class Toolbox(Gtk.VBox):
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
'''

View File

@ -27,7 +27,7 @@ Example:
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)

View File

@ -330,6 +330,8 @@ class HTray(Gtk.EventBox):
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 @@ class VTray(Gtk.EventBox):
def scroll_to_item(self, item):
self._viewport.scroll_to_item(item)
if hasattr(VTray, 'set_css_name'):
VTray.set_css_name('VTray')

View File

@ -20,6 +20,7 @@ This class represents all of the colors that the XO can take on.
Each pair of colors represents the fill color and the stroke color
'''
import six
import random
import logging
@ -210,11 +211,11 @@ colors = [['#B20008', '#FF2B34'],
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 @@ class XoColor:
'''
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 @@ if __name__ == '__main__':
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()

View File

@ -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 start(log_filename=None):
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 start(log_filename=None):
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 start(log_filename=None):
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 start(log_filename=None):
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(logger=None, logger_name=None, skip_args=None, skip_kwargs=None,
[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

View File

@ -32,7 +32,9 @@ from gi.repository import GLib
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 []

View File

@ -21,14 +21,14 @@ STABLE.
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 @@ class GlibURLDownloader(GObject.GObject):
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 @@ class GlibURLDownloader(GObject.GObject):
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 @@ class GlibURLDownloader(GObject.GObject):
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

View File

@ -21,6 +21,7 @@
STABLE.
"""
import six
import logging
from functools import partial
@ -124,6 +125,11 @@ class Activity(GObject.GObject):
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 @@ class Activity(GObject.GObject):
'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 @@ class Activity(GObject.GObject):
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 @@ class Activity(GObject.GObject):
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 @@ class Activity(GObject.GObject):
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 @@ class _JoinCommand(_BaseCommand):
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

View File

@ -22,7 +22,7 @@ STABLE.
"""
import logging
import six
from gi.repository import GObject
import dbus
from telepathy.interfaces import CONNECTION, \
@ -103,7 +103,7 @@ class BaseBuddy(GObject.GObject):
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 @@ class Buddy(BaseBuddy):
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 @@ class Buddy(BaseBuddy):
'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 @@ class Owner(BaseBuddy):
self.props.nick = get_nick_name()
self.props.color = get_color().to_string()

View File

@ -92,7 +92,8 @@ class ConnectionManager(object):
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 @@ class ConnectionManager(object):
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

View File

@ -78,7 +78,8 @@ class PresenceService(GObject.GObject):
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 @@ class PresenceService(GObject.GObject):
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)

View File

@ -24,6 +24,7 @@ __all__ = ('TubeConnection', )
__docformat__ = 'reStructuredText'
import six
import logging
from dbus.connection import Connection
@ -77,7 +78,9 @@ class TubeConnection(Connection):
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 @@ class TubeConnection(Connection):
# 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, [])

View File

@ -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

View File

@ -33,7 +33,7 @@ try:
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 @@ class SpeechManager(GObject.GObject):
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):

View File

@ -3,4 +3,4 @@ sugar_PYTHON = \
__init__.py \
discover.py \
uitree.py \
unittest.py
_unittest.py

View File

@ -18,8 +18,6 @@
UNSTABLE.
"""
from __future__ import absolute_import
import logging
import os
import unittest
@ -52,11 +50,11 @@ class UITestCase(unittest.TestCase):
@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 @@ class UITestCase(unittest.TestCase):
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:

View File

@ -18,8 +18,6 @@
UNSTABLE.
"""
from __future__ import absolute_import
import argparse
import sys
import os

View File

@ -44,7 +44,7 @@ def _retry_find(func):
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

View File

@ -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 logging
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 @@ class LRU:
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 @@ class TempFilePath(str):
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)

View File

@ -2,6 +2,6 @@
name = Sample
activity_version = 1
bundle_id = org.sugarlabs.Sample
exec = sugar-activity activity.SampleActivity
exec = sugar-activity3 activity.SampleActivity
icon = activity-sample
license = GPLv2+

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
from sugar3.activity import bundlebuilder

View File

@ -59,6 +59,7 @@ def timeout_cb():
return False
return True
GLib.timeout_add(50, timeout_cb)
if __name__ == '__main__':

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
# Copyright (C) 2006, Red Hat, Inc.
# Copyright (C) 2007, One Laptop Per Child

View File

@ -23,7 +23,7 @@ from sugar3.test import uitree
class TestUITree(unittest.TestCase):
def test_tree(self):
process = subprocess.Popen(["python", __file__, "show_window1"])
process = subprocess.Popen(["python3", __file__, "show_window1"])
try:
root = uitree.get_root()
@ -49,5 +49,6 @@ def show_window1():
Gtk.main()
if __name__ == '__main__':
globals()[sys.argv[1]]()