Port from Python 2 to six
Signed-off-by: James Cameron <quozl@laptop.org>
This commit is contained in:
parent
6345da8e07
commit
aa8a5e70c4
@ -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
|
||||
|
@ -1 +1 @@
|
||||
dist_bin_SCRIPTS = sugar-activity sugar-activity-web
|
||||
dist_bin_SCRIPTS = sugar-activity sugar-activity-web sugar-activity3
|
||||
|
@ -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()
|
||||
|
@ -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
5
bin/sugar-activity3
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from sugar3.activity import activityinstance
|
||||
|
||||
activityinstance.main()
|
@ -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
|
||||
|
26
doc/conf.py
26
doc/conf.py
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -23,7 +23,7 @@ class _Animation(animator.Animation):
|
||||
|
||||
|
||||
def __animation_completed_cb(anim):
|
||||
print 'Animation completed'
|
||||
print('Animation completed')
|
||||
|
||||
|
||||
w = Gtk.Window()
|
||||
|
@ -24,7 +24,7 @@ separator.show()
|
||||
|
||||
|
||||
def color_changed_cb(button, pspec):
|
||||
print button.get_color()
|
||||
print(button.get_color())
|
||||
|
||||
|
||||
color_button = ColorToolButton()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
from gi.repository import Gtk
|
||||
|
||||
import common
|
||||
|
@ -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()
|
||||
|
@ -19,7 +19,7 @@ box.show()
|
||||
def echo(button, label):
|
||||
if not button.props.active:
|
||||
return
|
||||
print label
|
||||
print(label)
|
||||
|
||||
|
||||
palette = RadioPalette()
|
||||
|
@ -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('.')]
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
from gi.repository import Gtk
|
||||
|
||||
from sugar3.graphics.icon import Icon
|
||||
|
@ -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')
|
||||
|
@ -2,6 +2,7 @@ sugardir = $(pythondir)/sugar3/activity
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
activity.py \
|
||||
activityinstance.py \
|
||||
activityfactory.py \
|
||||
activityhandle.py \
|
||||
activityservice.py \
|
||||
|
@ -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()
|
||||
@ -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
|
||||
|
@ -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()),
|
||||
|
222
src/sugar3/activity/activityinstance.py
Normal file
222
src/sugar3/activity/activityinstance.py
Normal 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()
|
@ -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)
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 = []
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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__
|
||||
|
@ -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)
|
||||
|
@ -16,7 +16,6 @@ sugar_PYTHON = \
|
||||
palettemenu.py \
|
||||
palettewindow.py \
|
||||
panel.py \
|
||||
popwindow.py \
|
||||
radiopalette.py \
|
||||
radiotoolbutton.py \
|
||||
scrollingdetector.py \
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -19,8 +19,8 @@
|
||||
STABLE.
|
||||
"""
|
||||
|
||||
import six
|
||||
import logging
|
||||
import StringIO
|
||||
import cairo
|
||||
|
||||
from gi.repository import GObject
|
||||
@ -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)
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
|
||||
@ -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)
|
||||
|
||||
|
@ -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)
|
@ -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)
|
||||
|
@ -34,7 +34,7 @@ class ScrollingDetector(GObject.GObject):
|
||||
'''
|
||||
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
|
||||
|
@ -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):
|
||||
'''
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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
|
||||
|
||||
@ -214,7 +215,7 @@ def _parse_string(color_string):
|
||||
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
|
||||
|
||||
@ -236,10 +237,11 @@ class XoColor:
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 []
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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, [])
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -3,4 +3,4 @@ sugar_PYTHON = \
|
||||
__init__.py \
|
||||
discover.py \
|
||||
uitree.py \
|
||||
unittest.py
|
||||
_unittest.py
|
||||
|
@ -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:
|
@ -18,8 +18,6 @@
|
||||
UNSTABLE.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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+
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from sugar3.activity import bundlebuilder
|
||||
|
||||
|
@ -59,6 +59,7 @@ def timeout_cb():
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
GLib.timeout_add(50, timeout_cb)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -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
|
||||
|
@ -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]]()
|
||||
|
Loading…
Reference in New Issue
Block a user