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
+1
View File
@@ -2,6 +2,7 @@ sugardir = $(pythondir)/sugar3/activity
sugar_PYTHON = \
__init__.py \
activity.py \
activityinstance.py \
activityfactory.py \
activityhandle.py \
activityservice.py \
+19 -15
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
+6 -7
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()),
+7 -7
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:
+222
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()
+1 -1
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)
+24 -20
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")
+4 -4
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
+1 -1
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):