Update to Python 3

issue7488
review48431002
This commit is contained in:
Cédric Krier committed 2018-06-26 19:08:57 +02:00
1 parent 4885b75e41
commit ce385af57d
76 files changed
+510 -474

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Use Python 3
* Improve loading strategy by using views
* Use non conflicting keyboard shortcuts in sync with sao
* Use the context to get the suffix of window name
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
import os
try:
+2 -2
View File
@@ -38,7 +38,7 @@ master_doc = 'index'
# General information about the project.
project = 'tryton'
copyright = u'2008-2011, Anne Krings, Bertrand Chenal, Cédric Krier, \
copyright = '2008-2011, Anne Krings, Bertrand Chenal, Cédric Krier, \
Mathias Behrle, Tobias Paepke, Udo Spallek'
# The version info for the project you're documenting, acts as replacement for
@@ -174,7 +174,7 @@ htmlhelp_basename = 'trytonddoc'
# (source start file, target name, title, author, documentclass [howto/manual])
latex_documents = [
('index', 'tryton.tex', 'tryton Documentation',
u'Anne Krings, Bertrand Chenal, Cédric Krier, Mathias Behrle, '
'Anne Krings, Bertrand Chenal, Cédric Krier, Mathias Behrle, '
'Tobias Paepke, Udo Spallek', 'manual'),
]
+2 -2
View File
@@ -4,12 +4,12 @@ Installing tryton
Prerequisites
-------------
* Python 2.7.9 or later (http://www.python.org/)
* Python 3.4 or later (http://www.python.org/)
* gtk+ 3.20 or later and py-gobject3 (http://www.gtk.org/)
* librsvg (http://librsvg.sourceforge.net/)
* python-dateutil (http://labix.org/python-dateutil)
* Optional: cdecimal (http://www.bytereef.org/mpdecimal/index.html)
* Optional: GooCalendar (https://pypi.python.org/pypi/GooCalendar)
* Optional: GooCalendar 0.4 or later (https://pypi.python.org/pypi/GooCalendar)
Installation
------------
Regular → Executable
+12 -5
View File
@@ -1,17 +1,20 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from setuptools import setup, find_packages
import io
import os
import re
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
return io.open(
os.path.join(os.path.dirname(__file__), fname),
'r', encoding='utf-8').read()
args = {}
try:
from babel.messages import frontend as babel
@@ -45,6 +48,7 @@ def get_version():
init = read(os.path.join('tryton', '__init__.py'))
return re.search('__version__ = "([0-9.]*)"', init).group(1)
version = get_version()
major_version, minor_version, _ = version.split('.', 2)
major_version = int(major_version)
@@ -95,18 +99,21 @@ dist = setup(name=name,
'Natural Language :: Spanish',
'Natural Language :: Japanese',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Office/Business',
],
platforms='any',
license='GPL-3',
python_requires='>=3.4',
install_requires=[
# "py-gobject3",
"python-dateutil",
],
extras_require={
'cdecimal': ['cdecimal'],
'calendar': ['GooCalendar'],
'calendar': ['GooCalendar>=0.4'],
},
zip_safe=False,
**args
+1 -1
View File
@@ -1,3 +1,3 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from main import *
from .main import *
+1 -1
View File
@@ -93,7 +93,7 @@ class Action(object):
context=context)
name_suffix = _(', ').join([x['rec_name'] for x in rec_names])
if len(data['ids']) > max_records:
name_suffix += _(u',\u2026')
name_suffix += _(',\u2026')
return _('%s (%s)') % (name, name_suffix)
data['action_id'] = action['id']
+3 -3
View File
@@ -189,7 +189,7 @@ try:
except ImportError:
pass
gobject.threads_init()
from urlparse import urlparse
from urllib.parse import urlparse
import threading
import tryton.common as common
@@ -217,7 +217,7 @@ if sys.platform == 'win32':
return super(Dialog, self).run()
gtk.Dialog = Dialog
CSS = """
CSS = b"""
.readonly entry {
background-color: @insensitive_bg_color;
}
@@ -284,7 +284,7 @@ class TrytonClient(object):
lambda signum, frame: main.sig_quit())
def excepthook(*args):
import common
from . import common
import traceback
detail = ''.join(traceback.format_exception(*args))
common.error(str(args[1]), detail)
+5 -5
View File
@@ -1,8 +1,8 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from common import *
from datetime_strftime import *
from domain_inversion import domain_inversion, eval_domain, localize_domain, \
from .common import *
from .datetime_strftime import *
from .domain_inversion import domain_inversion, eval_domain, localize_domain, \
merge, inverse_leaf, filter_leaf, concat, simplify, unique_value
from environment import EvalEnvironment
import timedelta
from .environment import EvalEnvironment
from . import timedelta
+1 -1
View File
@@ -54,7 +54,7 @@ class Button(gtk.Button):
label += ' (%s)' % len(clicks)
if tip:
tip += '\n'
tip += _('By: ') + _(', ').join(clicks.itervalues())
tip += _('By: ') + _(', ').join(iter(clicks.values()))
self.set_label(label)
self.set_tooltip_text(tip)
+1 -1
View File
@@ -70,7 +70,7 @@ class CellRendererBinary(gtk.GenericCellRenderer):
return getattr(self, pspec.name)
def button_width(self):
return (sum(width for n, (_, _, width, _) in self.images.iteritems()
return (sum(width for n, (_, _, width, _) in self.images.items()
if n in self.buttons)
+ (2 * (BUTTON_BORDER + BUTTON_SPACING) * len(self.buttons))
- 2 * BUTTON_SPACING)
+1 -1
View File
@@ -3,7 +3,7 @@
import gtk
import gobject
import locale
from cellrendererinteger import CellRendererInteger
from .cellrendererinteger import CellRendererInteger
class CellRendererFloat(CellRendererInteger):
+1 -1
View File
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import gobject
from cellrenderertext import CellRendererText
from .cellrenderertext import CellRendererText
import locale
+63 -59
View File
@@ -17,7 +17,8 @@ from functools import partial
from tryton.config import CONFIG
from tryton.config import TRYTON_ICON, PIXMAPS_DIR
import sys
import xmlrpclib
import xmlrpc.client
from functools import reduce
try:
import hashlib
except ImportError:
@@ -27,10 +28,10 @@ import webbrowser
import traceback
import tryton.rpc as rpc
import socket
import thread
import urllib
import urllib2
import urlparse
import _thread
import urllib.request
import urllib.parse
import urllib.error
from string import Template
import shlex
try:
@@ -67,7 +68,7 @@ class TrytonIconFactory(gtk.IconFactory):
continue
try:
pixbuf = gtk.gdk.pixbuf_new_from_file(
os.path.join(PIXMAPS_DIR, fname).decode('utf-8'))
os.path.join(PIXMAPS_DIR, fname))
except (IOError, glib.GError):
continue
finally:
@@ -117,13 +118,14 @@ class TrytonIconFactory(gtk.IconFactory):
except TrytonServerError:
icons = []
for icon in icons:
pixbuf = _data2pixbuf(icon['icon'])
pixbuf = _data2pixbuf(icon['icon'].encode('utf-8'))
self._tryton_icons.remove((icon['id'], icon['name']))
del self._name2id[icon['name']]
self._loaded_icons.add(icon['name'])
iconset = gtk.IconSet(pixbuf)
self.add(icon['name'], iconset)
ICONFACTORY = TrytonIconFactory()
ICONFACTORY.add_default()
@@ -161,6 +163,7 @@ class ModelAccess(object):
self._access.update(access)
return self._access[model]
MODELACCESS = ModelAccess()
@@ -178,6 +181,7 @@ class ModelHistory(object):
def __contains__(self, model):
return model in self._models
MODELHISTORY = ModelHistory()
@@ -224,6 +228,7 @@ class ViewSearch(object):
del self.searches[model][i]
break
VIEW_SEARCH = ViewSearch()
@@ -341,7 +346,7 @@ def selection(title, values, alwaysask=False):
if not values or len(values) == 0:
return None
elif len(values) == 1 and (not alwaysask):
key = values.keys()[0]
key = list(values.keys())[0]
return (key, values[key])
parent = get_toplevel_window()
@@ -373,7 +378,7 @@ def selection(title, values, alwaysask=False):
treeview.set_search_column(0)
model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
keys = values.keys()
keys = list(values.keys())
keys.sort()
i = 0
for val in keys:
@@ -446,19 +451,13 @@ def file_selection(title, filename='',
win.set_preview_widget(img_preview)
win.connect('update-preview', update_preview_cb, img_preview)
if os.name == 'nt':
encoding = 'utf-8'
else:
encoding = sys.getfilesystemencoding()
button = win.run()
if button != gtk.RESPONSE_OK:
result = None
elif not multi:
result = win.get_filename()
if result:
result = unicode(result, encoding)
else:
result = [unicode(path, encoding) for path in win.get_filenames()]
result = win.get_filenames()
parent.present()
win.destroy()
return result
@@ -469,10 +468,10 @@ _slugify_hyphenate_re = re.compile(r'[-\s]+')
def slugify(value):
if not isinstance(value, unicode):
value = unicode(value)
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
value = unicode(_slugify_strip_re.sub('', value).strip())
if not isinstance(value, str):
value = str(value)
value = unicodedata.normalize('NFKD', value)
value = str(_slugify_strip_re.sub('', value).strip())
return _slugify_hyphenate_re.sub('-', value)
@@ -539,27 +538,17 @@ def mailto(to=None, cc=None, subject=None, body=None, attachment=None):
# http://www.faqs.org/rfcs/rfc2368.html
url = "mailto:"
if to:
if isinstance(to, unicode):
to = to.encode('utf-8')
url += urllib.quote(to.strip(), "@,")
url += urllib.parse.quote(to.strip(), "@,")
url += '?'
if cc:
if isinstance(cc, unicode):
cc = cc.encode('utf-8')
url += "&cc=" + urllib.quote(cc, "@,")
url += "&cc=" + urllib.parse.quote(cc, "@,")
if subject:
if isinstance(subject, unicode):
subject = subject.encode('utf-8')
url += "&subject=" + urllib.quote(subject, "")
url += "&subject=" + urllib.parse.quote(subject, "")
if body:
if isinstance(body, unicode):
body = body.encode('utf-8')
body = "\r\n".join(body.splitlines())
url += "&body=" + urllib.quote(body, "")
url += "&body=" + urllib.parse.quote(body, "")
if attachment:
if isinstance(attachment, unicode):
attachment = attachment.encode('utf-8')
url += "&attachment=" + urllib.quote(attachment, "")
url += "&attachment=" + urllib.parse.quote(attachment, "")
webbrowser.open(url, new=1)
@@ -598,6 +587,7 @@ class MessageDialog(UniqueDialog):
def __call__(self, message, msg_type=gtk.MESSAGE_INFO):
super(MessageDialog, self).__call__(message, msg_type)
message = MessageDialog()
@@ -610,6 +600,7 @@ class WarningDialog(UniqueDialog):
dialog.format_secondary_markup(to_xml(message))
return dialog
warning = WarningDialog()
@@ -643,6 +634,7 @@ class UserWarningDialog(WarningDialog):
return 'ok'
return 'cancel'
userwarning = UserWarningDialog()
@@ -680,6 +672,7 @@ class SurDialog(ConfirmationDialog):
response = super(SurDialog, self).__call__(message)
return response == gtk.RESPONSE_OK
sur = SurDialog()
@@ -707,6 +700,7 @@ class Sur3BDialog(ConfirmationDialog):
response = super(Sur3BDialog, self).__call__(message)
return self.response_mapping.get(response, 'cancel')
sur_3b = Sur3BDialog()
@@ -754,6 +748,7 @@ class AskDialog(UniqueDialog):
self.running = False
return result
ask = AskDialog()
@@ -814,6 +809,7 @@ class ConcurrencyDialog(UniqueDialog):
mode=['form', 'tree'])
return False
concurrency = ConcurrencyDialog()
@@ -898,6 +894,7 @@ class ErrorDialog(UniqueDialog):
if response == gtk.RESPONSE_OK:
send_bugtracker(title, details)
error = ErrorDialog()
@@ -958,17 +955,18 @@ def send_bugtracker(title, msg):
if response == gtk.RESPONSE_OK:
try:
msg = msg.encode('ascii', 'replace')
title = title.encode('ascii', 'replace')
protocol = 'http'
if ssl or hasattr(socket, 'ssl'):
protocol = 'https'
quote = partial(urllib.quote, safe="!$&'()*+,;=:")
server = xmlrpclib.Server(
quote = partial(urllib.parse.quote, safe="!$&'()*+,;=:")
server = xmlrpc.client.Server(
('%s://%s:%s@' + CONFIG['roundup.xmlrpc'])
% (protocol, quote(user), quote(password)), allow_none=True)
if hashlib:
msg_md5 = hashlib.md5(msg + '\n' + title).hexdigest()
msg_md5 = hashlib.md5(msg + b'\n' + title).hexdigest()
else:
msg_md5 = md5.new(msg + '\n' + title).hexdigest()
msg_md5 = md5.new(msg + b'\n' + title).hexdigest()
if not title:
title = '[no title]'
issue_id = None
@@ -1001,15 +999,15 @@ def send_bugtracker(title, msg):
+ 'issue%s' % issue_id)
webbrowser.open(CONFIG['roundup.url'] + 'issue%s' % issue_id,
new=2)
except (socket.error, xmlrpclib.Fault), exception:
if (isinstance(exception, xmlrpclib.Fault)
except (socket.error, xmlrpc.client.Fault) as exception:
if (isinstance(exception, xmlrpc.client.Fault)
and 'roundup.cgi.exceptions.Unauthorised' in
exception.faultString):
message(_('Connection error.\nBad username or password.'))
return send_bugtracker(title, msg)
tb_s = reduce(lambda x, y: x + y,
traceback.format_exception(sys.exc_type,
sys.exc_value, sys.exc_traceback))
traceback.format_exception(sys.exc_info()[0],
sys.exc_info()[1], sys.exc_info()[2]))
message(_('Exception:') + '\n' + tb_s, msg_type=gtk.MESSAGE_ERROR)
@@ -1019,7 +1017,7 @@ def check_version(box, version=__version__):
webbrowser.open(url)
box.remove(info_bar)
class HeadRequest(urllib2.Request):
class HeadRequest(urllib.request.Request):
def get_method(self):
return 'HEAD'
@@ -1033,14 +1031,15 @@ def check_version(box, version=__version__):
filename = 'tryton-setup-%s.exe' % version
elif sys.platform == 'darwin':
filename = 'tryton-%s.dmg' % version
url = list(urlparse.urlparse(CONFIG['download.url']))
url = list(urllib.parse.urlparse(CONFIG['download.url']))
url[2] = '/%s/%s' % (series, filename)
url = urlparse.urlunparse(url)
url = urllib.parse.urlunparse(url)
logger.info(_("Check URL: %s"), url)
try:
urllib2.urlopen(HeadRequest(url), timeout=5, cafile=rpc._CA_CERTS)
except (urllib2.HTTPError, socket.timeout):
urllib.request.urlopen(
HeadRequest(url), timeout=5, cafile=rpc._CA_CERTS)
except (urllib.error.HTTPError, socket.timeout):
return True
except Exception:
logger.error(
@@ -1063,6 +1062,7 @@ def to_xml(string):
return string.replace('&', '&'
).replace('<', '&lt;').replace('>', '&gt;')
PLOCK = Lock()
@@ -1098,12 +1098,14 @@ def process_exception(exception, *args, **kwargs):
from tryton.gui.main import Main
if PLOCK.acquire(False):
language = CONFIG['client.lang']
func = lambda parameters: rpc.login(
rpc._HOST, rpc._PORT, rpc._DATABASE, rpc._USERNAME,
parameters, language)
def login(parameters):
return rpc.login(
rpc._HOST, rpc._PORT, rpc._DATABASE, rpc._USERNAME,
parameters, language)
try:
Login(func)
except TrytonError, exception:
Login(login)
except TrytonError as exception:
if exception.faultCode == 'QueryCanceled':
Main.get_main().sig_quit()
raise
@@ -1124,7 +1126,7 @@ class Login(object):
while True:
try:
func(parameters)
except TrytonServerError, exception:
except TrytonServerError as exception:
if exception.faultCode.startswith('403'):
parameters.clear()
continue
@@ -1216,7 +1218,7 @@ class RPCProgress(object):
def start(self):
try:
self.res = getattr(rpc, self.method)(*self.args)
except Exception, exception:
except Exception as exception:
self.error = True
self.res = False
self.exception = exception
@@ -1239,7 +1241,7 @@ class RPCProgress(object):
if self.parent.get_window():
watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
self.parent.get_window().set_cursor(watch)
thread.start_new_thread(self.start, ())
_thread.start_new_thread(self.start, ())
return
else:
self.start()
@@ -1256,7 +1258,7 @@ class RPCProgress(object):
try:
return process_exception(
self.exception, *self.args, rpc_execute=rpc_execute)
except RPCException, exception:
except RPCException as exception:
self.exception = exception
def return_():
@@ -1313,6 +1315,7 @@ class Tooltips(object):
if self._tooltips:
self._tooltips.disable()
COLOR_SCHEMES = {
'red': '#cf1d1d',
'green': '#3fb41b',
@@ -1329,7 +1332,7 @@ def filter_domain(domain):
'''
res = []
for arg in domain:
if isinstance(arg, basestring):
if isinstance(arg, str):
if arg == 'OR':
res = []
break
@@ -1401,10 +1404,11 @@ def resize_pixbuf(pixbuf, width, height):
def _data2pixbuf(data):
loader = gtk.gdk.PixbufLoader()
loader.write(bytes(data))
loader.write(data)
loader.close()
return loader.get_pixbuf()
BIG_IMAGE_SIZE = 10 ** 6
with open(os.path.join(PIXMAPS_DIR, 'tryton-noimage.png'), 'rb') as no_image:
NO_IMG_PIXBUF = _data2pixbuf(no_image.read())
+3 -3
View File
@@ -33,7 +33,7 @@ def update_completion(entry, record, field, model, domain=None):
def update(search_text, domain):
if not entry.props.window:
return False
if search_text != entry.get_text().decode('utf-8'):
if search_text != entry.get_text():
return False
completion_model = entry.get_completion().get_model()
if not search_text or not model:
@@ -53,7 +53,7 @@ def update_completion(entry, record, field, model, domain=None):
results = results()
except (TrytonError, TrytonServerError):
results = []
if search_text != entry.get_text().decode('utf-8'):
if search_text != entry.get_text():
return False
completion_model.clear()
for result in results:
@@ -70,5 +70,5 @@ def update_completion(entry, record, field, model, domain=None):
_("Unable to search for completion of %s") % model,
exc_info=True)
return False
search_text = entry.get_text().decode('utf-8')
search_text = entry.get_text()
gobject.timeout_add(300, update, search_text, domain)
+13 -11
View File
@@ -3,17 +3,13 @@
import gettext
import datetime
import pygtk
pygtk.require('2.0')
import gobject
import gtk
from dateutil.relativedelta import relativedelta
from dateutil.parser import parse
from datetime_strftime import datetime_strftime as strftime
from .datetime_strftime import datetime_strftime as strftime
__all__ = ['Date', 'CellRendererDate', 'Time', 'CellRendererTime', 'DateTime']
@@ -165,7 +161,7 @@ class Date(gtk.Entry):
def do_set_property(self, prop, value):
if prop.name == 'value':
if isinstance(value, basestring):
if isinstance(value, str):
self.set_text(value)
self.parse()
value = self.__date
@@ -185,6 +181,7 @@ class Date(gtk.Entry):
elif prop.name == 'format':
return self.__format
gobject.type_register(Date)
@@ -226,6 +223,7 @@ class CellRendererDate(gtk.CellRendererText):
widget.show()
return widget
gobject.type_register(CellRendererDate)
@@ -314,7 +312,7 @@ class Time(gtk.ComboBoxEntry):
def do_set_property(self, prop, value):
if prop.name == 'value':
if isinstance(value, basestring):
if isinstance(value, str):
self.__entry.set_text(value)
self.parse()
value = self.__time
@@ -334,6 +332,7 @@ class Time(gtk.ComboBoxEntry):
elif prop.name == 'format':
return self.__format
gobject.type_register(Time)
@@ -377,6 +376,7 @@ class CellRendererTime(gtk.CellRendererText):
widget.show()
return widget
gobject.type_register(CellRendererTime)
@@ -457,6 +457,7 @@ class DateTime(gtk.HBox):
self.__date.modify_text(state, color)
self.__time.child.modify_text(state, color)
gobject.type_register(DateTime)
@@ -480,13 +481,13 @@ def popup_show(popup):
(gtk.gdk.BUTTON_PRESS_MASK
| gtk.gdk.BUTTON_RELEASE_MASK
| gtk.gdk.POINTER_MOTION_MASK),
None, cursor, 0L)
None, cursor, 0)
def popup_hide(popup):
popup.hide()
popup.grab_remove()
gtk.gdk.pointer_ungrab(0L)
gtk.gdk.pointer_ungrab(0)
def timelist_set_list(model, min_, max_, format_):
@@ -496,10 +497,10 @@ def timelist_set_list(model, min_, max_, format_):
model.append((time.strftime(format_), time))
hour = time.hour
minute = time.minute + delta
hour += minute / 60
hour, minute = divmod(minute, 60)
hour += time.hour
if hour >= 24:
break
minute = minute % 60
time = datetime.time(hour, minute)
@@ -534,6 +535,7 @@ def add_operators(widget):
editable.connect('key-press-event', key_press)
return widget
OPERATORS = {
gtk.keysyms.S: relativedelta(seconds=-1),
gtk.keysyms.s: relativedelta(seconds=1),
+15 -13
View File
@@ -2,9 +2,9 @@
# this repository contains the full copyright notices and license terms.
import operator
import types
import datetime
from collections import defaultdict
from functools import reduce
def in_(a, b):
@@ -16,6 +16,7 @@ def in_(a, b):
else:
return operator.contains(b, a)
OPERATORS = defaultdict(lambda: lambda a, b: True)
OPERATORS.update({
'=': operator.eq,
@@ -41,7 +42,7 @@ def locale_part(expression, field_name, locale_name='id'):
def is_leaf(expression):
return (isinstance(expression, (list, tuple))
and len(expression) > 2
and isinstance(expression[1], basestring))
and isinstance(expression[1], str))
def constrained_leaf(part, boolop=operator.and_):
@@ -72,14 +73,14 @@ def eval_leaf(part, context, boolop=operator.and_):
context_field = datetime.date.min
if isinstance(context_field, (list, tuple)) and value is None:
value = type(context_field)()
if (isinstance(context_field, basestring)
if (isinstance(context_field, str)
and isinstance(value, (list, tuple))):
try:
value = '%s,%s' % tuple(value)
except TypeError:
pass
elif (isinstance(context_field, (list, tuple))
and isinstance(value, basestring)):
and isinstance(value, str)):
try:
context_field = '%s,%s' % tuple(context_field)
except TypeError:
@@ -90,7 +91,7 @@ def eval_leaf(part, context, boolop=operator.and_):
value = list(value)
if (operand in ('=', '!=')
and isinstance(context_field, (list, tuple))
and isinstance(value, (int, long))):
and isinstance(value, int)):
operand = {
'=': 'in',
'!=': 'not in',
@@ -112,7 +113,7 @@ def inverse_leaf(domain):
return [domain[3]] + list(domain[1:])
return domain
else:
return map(inverse_leaf, domain)
return list(map(inverse_leaf, domain))
def filter_leaf(domain, field, model):
@@ -155,7 +156,7 @@ def localize_domain(domain, field_name=None, strip_target=False):
else:
return [domain[3]] + list(domain[1:-1])
locale_name = 'id'
if isinstance(domain[2], basestring):
if isinstance(domain[2], str):
locale_name = 'rec_name'
n = 3 if strip_target else 4
return [locale_part(domain[0], field_name, locale_name)] \
@@ -246,7 +247,7 @@ def domain_inversion(domain, symbol, context=None):
class And(object):
def __init__(self, expressions):
self.branches = map(parse, expressions)
self.branches = list(map(parse, expressions))
self.variables = set()
for expression in self.branches:
if is_leaf(expression):
@@ -265,7 +266,7 @@ class And(object):
for part in self.branches:
if isinstance(part, And):
part_inversion = part.inverse(symbol, context)
evaluated = isinstance(part_inversion, types.BooleanType)
evaluated = isinstance(part_inversion, bool)
if not evaluated:
result.append(part_inversion)
elif part_inversion:
@@ -284,7 +285,7 @@ class And(object):
else:
return False
result = filter(lambda e: e is not True, result)
result = [e for e in result if e is not True]
if result == []:
return True
else:
@@ -305,7 +306,7 @@ class Or(And):
for part in self.branches:
if isinstance(part, And):
part_inversion = part.inverse(symbol, context)
evaluated = isinstance(part_inversion, types.BooleanType)
evaluated = isinstance(part_inversion, bool)
if symbol not in part.variables:
if evaluated and part_inversion:
return True
@@ -329,7 +330,7 @@ class Or(And):
and not eval_leaf(part, context, operator.or_)):
result.append(False)
result = filter(lambda e: e is not False, result)
result = [e for e in result if e is not False]
if result == []:
return False
else:
@@ -390,7 +391,7 @@ def test_or_inversion():
assert domain_inversion(domain, 'y', {'z': 4}) == [['y', '<', 3]]
assert domain_inversion(domain, 'y', {'x': 3}) is True
domain = [u'OR', [u'length', u'>', 5], [u'language.code', u'=', u'de_DE']]
domain = ['OR', ['length', '>', 5], ['language.code', '=', 'de_DE']]
assert domain_inversion(domain, 'length', {'length': 0, 'name': 'n'}) ==\
[['length', '>', 5]]
@@ -636,6 +637,7 @@ def test_localize():
assert localize_domain(domain, 'x', False) == [['b.c', '=', 1, 'y', 'z']]
assert localize_domain(domain, 'x', True) == [['b.c', '=', 1, 'z']]
if __name__ == '__main__':
test_simple_inversion()
test_and_inversion()
+46 -46
View File
@@ -42,8 +42,8 @@ class udlex(shlex):
class DummyWordchars(object):
"Simulate str that contains all chars except somes"
def __contains__(self, item):
return item not in (u':', u'>', u'<', u'=', u'!', u'"', u';',
u'(', u')')
return item not in (':', '>', '<', '=', '!', '"', ';',
'(', ')')
self.wordchars = DummyWordchars()
@@ -116,7 +116,7 @@ def likify(value):
def quote(value):
"Quote string if needed"
if not isinstance(value, basestring):
if not isinstance(value, str):
return value
if '\\' in value:
value = value.replace('\\', '\\\\')
@@ -196,7 +196,7 @@ def split_target_value(field, value):
"Split the reference value into target and value"
assert field['type'] == 'reference'
target = None
if isinstance(value, basestring):
if isinstance(value, str):
for key, text in field['selection']:
if value.lower().startswith(text.lower() + ','):
target = key
@@ -230,8 +230,8 @@ def convert_value(field, value, context=None):
context = {}
def convert_boolean():
if isinstance(value, basestring):
return any(test.decode('utf-8').lower().startswith(value.lower())
if isinstance(value, str):
return any(test.lower().startswith(value.lower())
for test in (
_('y'), _('Yes'), _('True'), _('t'), '1'))
else:
@@ -256,7 +256,7 @@ def convert_value(field, value, context=None):
return
def convert_selection():
if isinstance(value, basestring):
if isinstance(value, str):
for key, text in field['selection']:
if value.lower() == text.lower():
return key
@@ -883,10 +883,10 @@ class DomainParser(object):
def __init__(self, fields, context=None):
self.fields = OrderedDict((name, f)
for name, f in fields.iteritems()
for name, f in fields.items()
if f.get('searchable', True))
self.strings = dict((f['string'].lower(), f)
for f in fields.itervalues()
for f in fields.values()
if f.get('searchable', True))
self.context = context
@@ -901,8 +901,8 @@ class DomainParser(object):
tokens = operatorize(tokens, 'and')
tokens = self.parse_clause(tokens)
return simplify(rlist(tokens))
except ValueError, exception:
if exception.message == 'No closing quotation':
except ValueError as exception:
if str(exception) == 'No closing quotation':
return self.parse(input_ + '"')
def stringable(self, domain):
@@ -930,7 +930,7 @@ class DomainParser(object):
def string_(clause):
if not clause:
return ''
if (not isinstance(clause[0], basestring)
if (not isinstance(clause[0], str)
or clause[0] in ('AND', 'OR')):
return '(%s)' % self.string(clause)
name, operator, value = clause[:3]
@@ -995,7 +995,7 @@ class DomainParser(object):
"Return completion for the input string"
domain = self.parse(input_)
closing = 0
for i in xrange(1, len(input_)):
for i in range(1, len(input_)):
if input_[-i] not in (')', ' '):
break
if input_[-i] == ')':
@@ -1018,7 +1018,7 @@ class DomainParser(object):
return
if len(input_) >= 2 and input_[-2] == ':':
return
for field in self.strings.itervalues():
for field in self.strings.values():
operator = default_operator(field)
value = ''
if 'ilike' in operator:
@@ -1052,7 +1052,7 @@ class DomainParser(object):
name = ''
if (name.lower() not in self.strings
and name not in self.fields):
for field in self.strings.itervalues():
for field in self.strings.values():
if field['string'].lower().startswith(name.lower()):
operator = default_operator(field)
value = ''
@@ -1310,81 +1310,81 @@ def test_group():
'string': '(Sur)Name',
},
})
assert rlist(dom.group(udlex(u'Name: Doe'))) == [('Name', None, 'Doe')]
assert rlist(dom.group(udlex(u'"(Sur)Name": Doe'))) == [
assert rlist(dom.group(udlex('Name: Doe'))) == [('Name', None, 'Doe')]
assert rlist(dom.group(udlex('"(Sur)Name": Doe'))) == [
('(Sur)Name', None, 'Doe'),
]
assert rlist(dom.group(udlex(u'Name: Doe Name: John'))) == [
assert rlist(dom.group(udlex('Name: Doe Name: John'))) == [
('Name', None, 'Doe'),
('Name', None, 'John')]
assert rlist(dom.group(udlex(u'Name: Name: John'))) == [
assert rlist(dom.group(udlex('Name: Name: John'))) == [
('Name', None, None),
('Name', None, 'John')]
assert rlist(dom.group(udlex(u'First Name: John'))) == [
assert rlist(dom.group(udlex('First Name: John'))) == [
('First Name', None, 'John'),
]
assert rlist(dom.group(udlex(u'Name: Doe First Name: John'))) == [
assert rlist(dom.group(udlex('Name: Doe First Name: John'))) == [
('Name', None, 'Doe'),
('First Name', None, 'John'),
]
assert rlist(dom.group(udlex(u'First Name: John Name: Doe'))) == [
assert rlist(dom.group(udlex('First Name: John Name: Doe'))) == [
('First Name', None, 'John'),
('Name', None, 'Doe'),
]
assert rlist(dom.group(udlex(u'First Name: John First Name: Jane'))) == [
assert rlist(dom.group(udlex('First Name: John First Name: Jane'))) == [
('First Name', None, 'John'),
('First Name', None, 'Jane'),
]
assert rlist(dom.group(udlex(u'Name: John Doe'))) == [
assert rlist(dom.group(udlex('Name: John Doe'))) == [
('Name', None, 'John'),
('Doe',),
]
assert rlist(dom.group(udlex(u'Name: "John Doe"'))) == [
assert rlist(dom.group(udlex('Name: "John Doe"'))) == [
('Name', None, 'John Doe'),
]
assert rlist(dom.group(udlex(u'Name: =Doe'))) == [('Name', '=', 'Doe')]
assert rlist(dom.group(udlex(u'Name: =Doe Name: >John'))) == [
assert rlist(dom.group(udlex('Name: =Doe'))) == [('Name', '=', 'Doe')]
assert rlist(dom.group(udlex('Name: =Doe Name: >John'))) == [
('Name', '=', 'Doe'),
('Name', '>', 'John'),
]
assert rlist(dom.group(udlex(u'First Name: =John First Name: =Jane'))) == [
assert rlist(dom.group(udlex('First Name: =John First Name: =Jane'))) == [
('First Name', '=', 'John'),
('First Name', '=', 'Jane'),
]
assert rlist(dom.group(udlex(u'Name: John;Jane'))) == [
assert rlist(dom.group(udlex('Name: John;Jane'))) == [
('Name', None, ['John', 'Jane'])
]
assert rlist(dom.group(udlex(u'Name: John;'))) == [
assert rlist(dom.group(udlex('Name: John;'))) == [
('Name', None, ['John'])
]
assert rlist(dom.group(udlex(u'Name: John;Jane Name: Doe'))) == [
assert rlist(dom.group(udlex('Name: John;Jane Name: Doe'))) == [
('Name', None, ['John', 'Jane']),
('Name', None, 'Doe'),
]
assert rlist(dom.group(udlex(u'Name: John; Name: Doe'))) == [
assert rlist(dom.group(udlex('Name: John; Name: Doe'))) == [
('Name', None, ['John']),
('Name', None, 'Doe'),
]
assert rlist(dom.group(udlex(u'Name:'))) == [
assert rlist(dom.group(udlex('Name:'))) == [
('Name', None, None),
]
assert rlist(dom.group(udlex(u'Name: ='))) == [
assert rlist(dom.group(udlex('Name: ='))) == [
('Name', '=', None),
]
assert rlist(dom.group(udlex(u'Name: =""'))) == [
assert rlist(dom.group(udlex('Name: =""'))) == [
('Name', '=', ''),
]
assert rlist(dom.group(udlex(u'Name: = ""'))) == [
assert rlist(dom.group(udlex('Name: = ""'))) == [
('Name', '=', ''),
]
assert rlist(dom.group(udlex(u'Name: = Name: Doe'))) == [
assert rlist(dom.group(udlex('Name: = Name: Doe'))) == [
('Name', '=', None),
('Name', None, 'Doe'),
]
assert rlist(dom.group(udlex(u'Name: \\"foo\\"'))) == [
assert rlist(dom.group(udlex('Name: \\"foo\\"'))) == [
('Name', None, '"foo"'),
]
assert rlist(dom.group(udlex(u'Name: "" <'))) == [
assert rlist(dom.group(udlex('Name: "" <'))) == [
('Name', '', '<'),
]
@@ -1497,10 +1497,10 @@ def test_completion():
'type': 'char',
},
})
assert list(dom.completion(u'Nam')) == ['Name: ']
assert list(dom.completion(u'Name:')) == ['Name: ']
assert list(dom.completion(u'Name: foo')) == []
assert list(dom.completion(u'Name: !=')) == []
assert list(dom.completion(u'Name: !=foo')) == []
assert list(dom.completion(u'')) == ['Name: ']
assert list(dom.completion(u' ')) == ['', 'Name: ']
assert list(dom.completion('Nam')) == ['Name: ']
assert list(dom.completion('Name:')) == ['Name: ']
assert list(dom.completion('Name: foo')) == []
assert list(dom.completion('Name: !=')) == []
assert list(dom.completion('Name: !=foo')) == []
assert list(dom.completion('')) == ['Name: ']
assert list(dom.completion(' ')) == ['', 'Name: ']
+1 -1
View File
@@ -35,7 +35,7 @@ class EvalEnvironment(dict):
pass
return super(EvalEnvironment, self).get(item, default)
def __nonzero__(self):
def __bool__(self):
return True
def __str__(self):
+21 -24
View File
@@ -1,11 +1,11 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from __future__ import division
import sys
from io import BytesIO
from io import StringIO
import xml.etree.ElementTree as ET
from xml.sax.saxutils import escape, unescape
from HTMLParser import HTMLParser
from html.parser import HTMLParser
from gi.repository import Gtk, Gdk, Pango
@@ -16,7 +16,7 @@ use_serialize_func = False
def _reverse_dict(dct):
return {j: i for i, j in dct.iteritems()}
return {j: i for i, j in dct.items()}
SIZE2SCALE = {
'1': 1 / (1.2 * 1.2 * 1.2),
@@ -41,7 +41,7 @@ FAMILIES = ['normal', 'sans', 'serif', 'monospace']
def gdk_to_hex(gdk_color):
"Convert color to 2 digit hex"
colors = [gdk_color.red, gdk_color.green, gdk_color.blue]
return "#" + "".join(["%02x" % (color / 256) for color in colors])
return "#" + "".join(["%02x" % (color // 256) for color in colors])
def _markup(text):
@@ -49,7 +49,7 @@ def _markup(text):
def _strip_markup(text):
return text[len(u'<markup>'):-len(u'</markup>')]
return text[len('<markup>'):-len('</markup>')]
def _strip_newline(text):
@@ -101,7 +101,7 @@ class MarkupHTMLParse(HTMLParser):
def parse_markup(markup_text):
'Return plain text and a list of start, end TextTag'
markup_text = BytesIO(_markup(markup_text))
markup_text = StringIO(_markup(markup_text))
plain_text = ''
tag_stack = []
tags = []
@@ -129,8 +129,6 @@ def parse_markup(markup_text):
def normalize_markup(markup_text, method='html'):
if isinstance(markup_text, unicode):
markup_text = markup_text.encode('utf-8')
parser = MarkupHTMLParse()
parser.feed(_strip_newline(markup_text))
root = parser.root
@@ -177,7 +175,8 @@ def normalize_markup(markup_text, method='html'):
if em.text is None and len(em) == 0:
em.append(ET.Element('br'))
# TODO order attributes
return _strip_markup(ET.tostring(root, encoding='utf-8', method=method))
return _strip_markup(
ET.tostring(root, encoding='utf-8', method=method).decode('utf-8'))
def find_list_delta(old, new):
@@ -268,7 +267,7 @@ def serialize(register, content, start, end, data):
def deserialize(register, content, iter_, text, create_tags, data):
if not isinstance(text, unicode):
if not isinstance(text, str):
for encoding in [sys.getfilesystemencoding(),
'utf-8', 'utf-16', 'utf-32']:
try:
@@ -278,14 +277,13 @@ def deserialize(register, content, iter_, text, create_tags, data):
break
else:
text = text.decode('ascii', errors='replace')
text = text.encode('utf-8')
text, tags = parse_markup(normalize_markup(text, method='xml'))
offset = iter_.get_offset()
content.insert(iter_, text)
def sort_key(tag):
start, end, element = tag
return start, -end, element
return start, -end, element.tag
for start, end, element in sorted(tags, key=sort_key):
for tag in _get_tags(content, element):
@@ -306,9 +304,9 @@ _TAGS = [
_TAGS.extend([('family %s' % family, {'family': family})
for family in FAMILIES])
_TAGS.extend([('size %s' % size, {'scale': scale})
for size, scale in SIZE2SCALE.iteritems()])
for size, scale in SIZE2SCALE.items()])
_TAGS.extend([('justification %s' % align, {'justification': justification})
for align, justification in ALIGN2JUSTIFICATION.iteritems()])
for align, justification in ALIGN2JUSTIFICATION.items()])
def register_foreground(text_buffer, color):
@@ -374,7 +372,7 @@ def _get_html(texttag, close=False, div_only=False):
if close:
return ''.join('</%s>' % t for t in tags)
return ''.join('<%s %s>' % (t, ' '.join('%s="%s"' % (a, v)
for a, v in attrib.get(t, {}).iteritems()))
for a, v in attrib.get(t, {}).items()))
for t in tags)
@@ -403,7 +401,7 @@ def remove_tags(content, start, end, *names):
if __name__ == '__main__':
html = u'''<b>Bold</b>
html = '''<b>Bold</b>
<i>Italic</i>
<u>Underline</u>
<div><br/></div>
@@ -416,13 +414,13 @@ if __name__ == '__main__':
def cb(window, event):
if use_serialize_func:
print text_buffer.serialize(
print(text_buffer.serialize(
text_buffer, MIME, text_buffer.get_start_iter(),
text_buffer.get_end_iter())
text_buffer.get_end_iter()))
else:
print serialize(
print(serialize(
text_buffer, text_buffer, text_buffer.get_start_iter(),
text_buffer.get_end_iter(), None)
text_buffer.get_end_iter(), None))
Gtk.main_quit()
win.connect('delete-event', cb)
vbox = Gtk.VBox()
@@ -439,8 +437,7 @@ if __name__ == '__main__':
if use_serialize_func:
text_buffer.deserialize(
text_buffer, MIME, text_buffer.get_start_iter(),
html.encode('utf-8'))
text_buffer, MIME, text_buffer.get_start_iter(), html)
result = text_buffer.serialize(
text_buffer, MIME, text_buffer.get_start_iter(),
@@ -455,7 +452,7 @@ if __name__ == '__main__':
text_buffer, text_buffer, text_buffer.get_start_iter(),
text_buffer.get_end_iter(), None)
assert normalize_markup(html) == result
assert normalize_markup(html) == result, (normalize_markup(html), result)
win.show_all()
Gtk.main()
+3 -3
View File
@@ -19,21 +19,21 @@ def populate(menu, model, record, title='', field=None, context=None):
'''
if record is None:
return
elif isinstance(record, (int, long)):
elif isinstance(record, int):
if record < 0:
return
elif record.id < 0:
return
def load(record):
if isinstance(record, (int, long)):
if isinstance(record, int):
screen = Screen(model, context=context)
screen.load([record])
record = screen.current_record
return record
def id_(record):
if not isinstance(record, (int, long)):
if not isinstance(record, int):
return record.id
return record
+7 -5
View File
@@ -90,10 +90,12 @@ class SelectionMixin(object):
def filter_selection(self, domain, record, field):
if not domain:
return
test = lambda value: eval_domain(domain, {
self.field_name: value[0],
})
self.selection = filter(test, self.selection)
def test(value):
return eval_domain(domain, {
self.field_name: value[0],
})
self.selection = list(filter(test, self.selection))
def get_inactive_selection(self, value):
if 'relation' not in self.attrs:
@@ -125,7 +127,7 @@ def selection_shortcuts(entry):
def freeze_value(value):
if isinstance(value, dict):
return tuple(sorted((k, freeze_value(v))
for k, v in value.iteritems()))
for k, v in value.items()))
elif isinstance(value, (list, set)):
return tuple(freeze_value(v) for v in value)
else:
+4 -4
View File
@@ -1,6 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from __future__ import division
import datetime
import gettext
import locale
@@ -46,7 +46,7 @@ def format(value, converter=None):
if value < 0:
sign = '-'
value = abs(value)
converter = sorted(converter.items(), key=operator.itemgetter(1),
converter = sorted(list(converter.items()), key=operator.itemgetter(1),
reverse=True)
values = []
for k, v in converter:
@@ -77,7 +77,7 @@ def parse(text, converter=None):
if not converter:
converter = DEFAULT_CONVERTER
for separator in _get_separators().values():
for separator in list(_get_separators().values()):
text = text.replace(separator, separator + ' ')
seconds = 0
@@ -90,7 +90,7 @@ def parse(text, converter=None):
except ValueError:
pass
else:
for key, separator in _get_separators().items():
for key, separator in list(_get_separators().items()):
if part.endswith(separator):
part = part[:-len(separator)]
try:
+17 -17
View File
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
"Options"
import ConfigParser
import configparser
import optparse
import os
import gettext
@@ -19,14 +19,14 @@ _ = gettext.gettext
def get_config_dir():
if os.name == 'nt':
appdata = os.environ['APPDATA']
if not isinstance(appdata, unicode):
appdata = unicode(appdata, sys.getfilesystemencoding())
if not isinstance(appdata, str):
appdata = str(appdata, sys.getfilesystemencoding())
return os.path.join(appdata, '.config', 'tryton',
__version__.rsplit('.', 1)[0])
return os.path.join(os.environ['HOME'], '.config', 'tryton',
__version__.rsplit('.', 1)[0])
if not os.path.isdir(get_config_dir()):
os.makedirs(get_config_dir(), 0700)
os.makedirs(get_config_dir(), 0o700)
class ConfigManager(object):
@@ -119,15 +119,15 @@ class ConfigManager(object):
def save(self):
try:
configparser = ConfigParser.ConfigParser()
for entry in self.config.keys():
parser = configparser.ConfigParser()
for entry in list(self.config.keys()):
if not len(entry.split('.')) == 2:
continue
section, name = entry.split('.')
if not configparser.has_section(section):
configparser.add_section(section)
configparser.set(section, name, self.config[entry])
configparser.write(open(self.rcfile, 'wb'))
if not parser.has_section(section):
parser.add_section(section)
parser.set(section, name, str(self.config[entry]))
parser.write(open(self.rcfile, 'w'))
except IOError:
logging.getLogger(__name__).warn(
_('Unable to write config file %s.')
@@ -136,10 +136,10 @@ class ConfigManager(object):
return True
def load(self):
configparser = ConfigParser.ConfigParser()
configparser.read([self.rcfile])
for section in configparser.sections():
for (name, value) in configparser.items(section):
parser = configparser.ConfigParser()
parser.read([self.rcfile])
for section in parser.sections():
for (name, value) in parser.items(section):
if value.lower() == 'true':
value = True
elif value.lower() == 'false':
@@ -164,8 +164,8 @@ CONFIG = ConfigManager()
CURRENT_DIR = os.path.dirname(__file__)
if hasattr(sys, 'frozen'):
CURRENT_DIR = os.path.dirname(sys.executable)
if not isinstance(CURRENT_DIR, unicode):
CURRENT_DIR = unicode(CURRENT_DIR, sys.getfilesystemencoding())
if not isinstance(CURRENT_DIR, str):
CURRENT_DIR = str(CURRENT_DIR, sys.getfilesystemencoding())
PIXMAPS_DIR = os.path.join(CURRENT_DIR, 'data', 'pixmaps', 'tryton')
if not os.path.isdir(PIXMAPS_DIR):
@@ -175,4 +175,4 @@ if not os.path.isdir(PIXMAPS_DIR):
'tryton', 'data/pixmaps/tryton')
TRYTON_ICON = gtk.gdk.pixbuf_new_from_file(
os.path.join(PIXMAPS_DIR, 'tryton-icon.png').encode('utf-8'))
os.path.join(PIXMAPS_DIR, 'tryton-icon.png'))
+1 -1
View File
@@ -1,6 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from jsonrpc import Fault
from .jsonrpc import Fault
TrytonServerError = Fault
+2 -2
View File
@@ -28,10 +28,10 @@ class Fingerprints(dict):
def save(self):
with open(KNOWN_HOSTS_PATH, 'w') as known_hosts:
known_hosts.writelines('%s %s' % (host, sha1)
+ os.linesep for host, sha1 in self.iteritems())
+ os.linesep for host, sha1 in self.items())
def __setitem__(self, key, value):
assert isinstance(key, basestring)
assert isinstance(key, str)
if value:
assert len(value) == 59 # len of formated sha1
else:
+1 -1
View File
@@ -1,3 +1,3 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from main import *
from .main import *
+17 -16
View File
@@ -4,15 +4,14 @@
import os
import sys
import gettext
from urlparse import urlparse, parse_qsl
import urllib
import gobject
import gtk
from urllib.parse import urlparse, parse_qsl, unquote
import json
import webbrowser
import threading
import logging
import gobject
import gtk
from gi.repository import GLib
import tryton.rpc as rpc
@@ -313,7 +312,7 @@ class Main(object):
if callback:
callback()
return False
if search_text != widget.get_text().decode('utf-8'):
if search_text != widget.get_text():
return end()
gmodel = global_search_completion.get_model()
if not search_text or not gmodel:
@@ -328,7 +327,7 @@ class Main(object):
result = result()
except RPCException:
result = []
if search_text != widget.get_text().decode('utf-8'):
if search_text != widget.get_text():
if callback:
callback()
return False
@@ -357,7 +356,7 @@ class Main(object):
return False
def changed(widget):
search_text = widget.get_text().decode('utf-8')
search_text = widget.get_text()
gobject.timeout_add(300, update, widget, search_text)
def activate(widget):
@@ -367,7 +366,7 @@ class Main(object):
common.message(_('No result found.'))
else:
widget.emit('changed')
search_text = widget.get_text().decode('utf-8')
search_text = widget.get_text()
update(widget, search_text, message)
self.global_search_entry.connect('changed', changed)
@@ -834,20 +833,22 @@ class Main(object):
language = CONFIG['client.lang']
try:
host, port, database, username = DBLogin().run()
except TrytonError, exception:
except TrytonError as exception:
if exception.faultCode == 'QueryCanceled':
return
raise
func = lambda parameters: rpc.login(
host, port, database, username, parameters, language)
def login(parameters):
return rpc.login(
host, port, database, username, parameters, language)
self.set_title() # Adds username/profile while password is asked
try:
common.Login(func)
except TrytonError, exception:
common.Login(login)
except TrytonError as exception:
if exception.faultCode == 'QueryCanceled':
return
raise
except TrytonServerError, exception:
except TrytonServerError as exception:
if exception.faultCode.startswith('404'):
return self.sig_login()
raise
@@ -1223,8 +1224,8 @@ class Main(object):
urlp = urlparse('http' + url[6:])
hostname = common.get_hostname(urlp.netloc)
port = common.get_port(urlp.netloc)
database, path = map(urllib.unquote,
(urlp.path[1:].split('/', 1) + [''])[:2])
database, path = list(map(unquote,
(urlp.path[1:].split('/', 1) + [''])[:2]))
if (not path or
hostname != rpc._HOST or
int(port) != rpc._PORT or
+3 -3
View File
@@ -1,5 +1,5 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from window import *
from email import *
from limit import *
from .window import *
from .email import *
from .limit import *
+1 -1
View File
@@ -42,7 +42,7 @@ class About(object):
self.win.set_authors(AUTHORS)
self.win.set_translator_credits(_('translator-credits'))
self.win.set_logo(GdkPixbuf.Pixbuf.new_from_file(
os.path.join(PIXMAPS_DIR, 'tryton.png').encode('utf-8')))
os.path.join(PIXMAPS_DIR, 'tryton.png')))
self.win.run()
parent.present()
self.win.destroy()
+5 -5
View File
@@ -2,8 +2,8 @@
# this repository contains the full copyright notices and license terms.
"Attachment"
import os
import urllib
import urlparse
import urllib.request
import urllib.parse
import sys
import gettext
@@ -42,9 +42,9 @@ class Attachment(WinForm):
data_field = self.screen.group.fields['data']
name_field = self.screen.group.fields[data_field.attrs['filename']]
new_record = self.screen.new()
file_name = os.path.basename(urlparse.urlparse(uri).path)
file_name = os.path.basename(urllib.parse.urlparse(uri).path)
name_field.set_client(new_record, file_name)
uri = urllib.unquote(uri)
uri = urllib.parse.unquote(uri)
uri = uri.decode('utf-8').encode(sys.getfilesystemencoding())
data_field.set_client(new_record, urllib.urlopen(uri).read())
data_field.set_client(new_record, urllib.request.urlopen(uri).read())
self.screen.display()
+4 -1
View File
@@ -7,7 +7,7 @@ from tryton.gui import Main
from tryton.gui.window.view_board import ViewBoard
from tryton.common import RPCExecute, RPCException
from tabcontent import TabContent
from .tabcontent import TabContent
_ = gettext.gettext
@@ -60,6 +60,9 @@ class Board(SignalEvent, TabContent):
and self.board.context == value.board.context
and self.name == value.name)
def __hash__(self):
return id(self)
def sig_win_close(self, widget):
Main.get_main().sig_win_close(widget)
+17 -17
View File
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import ConfigParser
import configparser
import gtk
import gobject
import os
@@ -29,7 +29,7 @@ class DBListEditor(object):
# GTK Stuffs
self.parent = parent
self.dialog = gtk.Dialog(title=_(u'Profile Editor'), parent=parent,
self.dialog = gtk.Dialog(title=_('Profile Editor'), parent=parent,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
self.ok_button = self.dialog.add_button(gtk.STOCK_OK,
gtk.RESPONSE_ACCEPT)
@@ -44,19 +44,19 @@ class DBListEditor(object):
self.cell.connect('editing-started', self.edit_started)
self.profile_tree = gtk.TreeView()
self.profile_tree.set_model(profile_store)
self.profile_tree.insert_column_with_attributes(-1, _(u'Profile'),
self.profile_tree.insert_column_with_attributes(-1, _('Profile'),
self.cell, text=0)
self.profile_tree.connect('cursor-changed', self.profile_selected)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(self.profile_tree)
self.add_button = gtk.Button(_(u'_Add'), use_underline=True)
self.add_button = gtk.Button(_('_Add'), use_underline=True)
self.add_button.connect('clicked', self.profile_create)
add_image = gtk.Image()
add_image.set_from_stock('gtk-add', gtk.ICON_SIZE_BUTTON)
self.add_button.set_image(add_image)
self.add_button.set_always_show_image(True)
self.remove_button = gtk.Button(_(u'_Remove'), use_underline=True)
self.remove_button = gtk.Button(_('_Remove'), use_underline=True)
self.remove_button.connect('clicked', self.profile_delete)
remove_image = gtk.Image()
remove_image.set_from_stock('gtk-remove', gtk.ICON_SIZE_BUTTON)
@@ -70,7 +70,7 @@ class DBListEditor(object):
table = gtk.Table(4, 2, homogeneous=False)
table.set_row_spacings(3)
table.set_col_spacings(3)
host = gtk.Label(set_underline(_(u'Host:')))
host = gtk.Label(set_underline(_('Host:')))
host.set_use_underline(True)
host.set_alignment(1, 0.5)
host.set_padding(3, 3)
@@ -81,7 +81,7 @@ class DBListEditor(object):
host.set_mnemonic_widget(self.host_entry)
table.attach(host, 0, 1, 1, 2, yoptions=False, xoptions=gtk.FILL)
table.attach(self.host_entry, 1, 2, 1, 2, yoptions=False)
database = gtk.Label(set_underline(_(u'Database:')))
database = gtk.Label(set_underline(_('Database:')))
database.set_use_underline(True)
database.set_alignment(1, 0.5)
database.set_padding(3, 3)
@@ -101,7 +101,7 @@ class DBListEditor(object):
self.database_combo.set_model(dbstore)
self.database_combo.connect('changed', self.dbcombo_changed)
self.database_progressbar = gtk.ProgressBar()
self.database_progressbar.set_text(_(u'Fetching databases list'))
self.database_progressbar.set_text(_('Fetching databases list'))
image = gtk.Image()
image.set_from_stock('tryton-new', gtk.ICON_SIZE_BUTTON)
db_box = gtk.VBox(homogeneous=True)
@@ -117,7 +117,7 @@ class DBListEditor(object):
db_box.set_size_request(width, height)
table.attach(database, 0, 1, 2, 3, yoptions=False, xoptions=gtk.FILL)
table.attach(db_box, 1, 2, 2, 3, yoptions=False)
username = gtk.Label(set_underline(_(u'Username:')))
username = gtk.Label(set_underline(_('Username:')))
username.set_use_underline(True)
username.set_alignment(1, 0.5)
username.set_padding(3, 3)
@@ -214,7 +214,7 @@ class DBListEditor(object):
try:
entry_value = self.profiles.get(self.current_profile['name'],
field)
except ConfigParser.NoOptionError:
except configparser.NoOptionError:
entry_value = ''
entry.set_text(entry_value)
if field == 'database':
@@ -304,9 +304,9 @@ class DBListEditor(object):
label = None
if self.test_server_version(host, port) is False:
label = _(u'Incompatible version of the server')
label = _('Incompatible version of the server')
elif dbs is None:
label = _(u'Could not connect to the server')
label = _('Could not connect to the server')
if label:
self.database_label.set_label('<b>%s</b>' % label)
self.database_label.show()
@@ -433,7 +433,7 @@ class DBLogin(object):
self.combo_profile.add_attribute(cell, 'sensitive', 1)
self.combo_profile.set_model(self.profile_store)
self.combo_profile.connect('changed', self.profile_changed)
self.profile_label = gtk.Label(set_underline(_(u'Profile:')))
self.profile_label = gtk.Label(set_underline(_('Profile:')))
self.profile_label.set_use_underline(True)
self.profile_label.set_justify(gtk.JUSTIFY_RIGHT)
self.profile_label.set_alignment(1, 0.5)
@@ -492,7 +492,7 @@ class DBLogin(object):
# Profile informations
self.profile_cfg = os.path.join(get_config_dir(), 'profiles.cfg')
self.profiles = ConfigParser.SafeConfigParser()
self.profiles = configparser.SafeConfigParser()
if not os.path.exists(self.profile_cfg):
short_version = '.'.join(__version__.split('.', 2)[:2])
name = 'demo%s.tryton.org' % short_version
@@ -533,7 +533,7 @@ class DBLogin(object):
profile = self.profile_store[position][0]
try:
username = self.profiles.get(profile, 'username')
except ConfigParser.NoOptionError:
except configparser.NoOptionError:
username = ''
host = self.profiles.get(profile, 'host')
self.entry_host.set_text('%s' % host)
@@ -624,10 +624,10 @@ class DBLogin(object):
if not test:
if test is False:
common.warning('',
_(u'Incompatible version of the server'))
_('Incompatible version of the server'))
else:
common.warning('',
_(u'Could not connect to the server'))
_('Could not connect to the server'))
continue
database = self.entry_database.get_text()
login = self.entry_login.get_text()
+5 -2
View File
@@ -20,7 +20,7 @@ from tryton.common import RPCExecute, RPCException
from tryton.common.datetime_strftime import datetime_strftime
from tryton import plugins
from tabcontent import TabContent
from .tabcontent import TabContent
_ = gettext.gettext
@@ -57,7 +57,7 @@ class Form(SignalEvent, TabContent):
self.screen.signal_connect(self, 'unread-note', self._unread_note)
if res_id not in (None, False):
if isinstance(res_id, (int, long)):
if isinstance(res_id, int):
res_id = [res_id]
self.screen.load(res_id)
else:
@@ -94,6 +94,9 @@ class Form(SignalEvent, TabContent):
and self.screen.limit == value.screen.limit
and self.screen.search_value == value.screen.search_value)
def __hash__(self):
return id(self)
def destroy(self):
super(Form, self).destroy()
self.screen.signal_unconnect(self)
+1 -1
View File
@@ -30,7 +30,7 @@ class Limit(object):
label = gtk.Label(_('Limit:'))
hbox.pack_start(label, expand=True, fill=True)
adjustment = gtk.Adjustment(value=CONFIG['client.limit'],
lower=1, upper=sys.maxint, step_incr=10, page_incr=100)
lower=1, upper=sys.maxsize, step_incr=10, page_incr=100)
self.spin_limit = gtk.SpinButton()
self.spin_limit.configure(adjustment, climb_rate=1, digits=0)
self.spin_limit.set_numeric(False)
+7 -5
View File
@@ -87,12 +87,14 @@ class Preference(NoModal):
if self.screen.current_record.validate():
vals = copy.copy(self.screen.get())
context = rpc.CONTEXT.copy()
func = lambda parameters: rpc.execute(
'model', 'res.user', 'set_preferences', vals, parameters,
context)
def login(parameters):
return rpc.execute(
'model', 'res.user', 'set_preferences',
vals, parameters, context)
try:
Login(func)
except TrytonError, exception:
Login(login)
except TrytonError as exception:
if exception.faultCode == 'QueryCanceled':
return
raise
+1 -1
View File
@@ -1,3 +1,3 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from view_board import *
from .view_board import *
+1 -1
View File
@@ -1,3 +1,3 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import screen
from . import screen
+28 -19
View File
@@ -287,7 +287,7 @@ class TimeDeltaField(Field):
return group.context.get(self.attrs.get('converter'))
def set_client(self, record, value, force_change=False):
if isinstance(value, basestring):
if isinstance(value, str):
value = common.timedelta.parse(value, self.converter(record.group))
super(TimeDeltaField, self).set_client(
record, value, force_change=force_change)
@@ -320,10 +320,14 @@ class FloatField(Field):
return self._default
def set_client(self, record, value, force_change=False, factor=1):
if isinstance(value, basestring):
if isinstance(value, str):
value = self.convert(value)
if value is not None:
value /= factor
# Keep the same type
if isinstance(value, int):
value //= factor
else:
value /= factor
super(FloatField, self).set_client(record, value,
force_change=force_change)
@@ -332,7 +336,7 @@ class FloatField(Field):
if value is not None:
digits = self.digits(record, factor=factor)
if digits:
p = digits[1]
p = int(digits[1])
else:
d = value * factor
if not isinstance(d, Decimal):
@@ -423,7 +427,7 @@ class M2OField(Field):
def set(self, record, value):
rec_name = record.value.get(self.name + '.rec_name') or ''
if not rec_name and value >= 0:
if not rec_name and value is not None and value >= 0:
try:
result, = RPCExecute('model', self.attrs['relation'], 'read',
[value], ['rec_name'])
@@ -496,7 +500,7 @@ class O2MField(Field):
def _set_default_value(self, record, fields=None):
if record.value.get(self.name) is not None:
return
from group import Group
from .group import Group
parent_name = self.attrs.get('relation_field', '')
fields = fields or {}
context = record.expr_eval(self.attrs.get('context', {}))
@@ -593,7 +597,7 @@ class O2MField(Field):
group = record.value[self.name]
if value is None:
value = []
if not value or isinstance(value[0], (int, long)):
if not value or isinstance(value[0], int):
mode = 'list ids'
else:
mode = 'list values'
@@ -640,7 +644,7 @@ class O2MField(Field):
fields = record.group.fields
if fields:
fields = dict((fname, field.attrs)
for fname, field in fields.iteritems())
for fname, field in fields.items())
record.value[self.name] = None
self._set_default_value(record, fields=fields)
@@ -655,7 +659,7 @@ class O2MField(Field):
if value is None:
value = []
# domain inversion could try to set id as value
if isinstance(value, (int, long)):
if isinstance(value, int):
value = [value]
previous_ids = self.get_eval(record)
@@ -801,7 +805,7 @@ class ReferenceField(Field):
def set_client(self, record, value, force_change=False):
if value:
if isinstance(value, basestring):
if isinstance(value, str):
value = value.split(',')
ref_model, ref_id = value
if isinstance(ref_id, (tuple, list)):
@@ -825,7 +829,7 @@ class ReferenceField(Field):
if not value:
record.value[self.name] = self._default
return
if isinstance(value, basestring):
if isinstance(value, str):
ref_model, ref_id = value.split(',')
if not ref_id:
ref_id = None
@@ -888,14 +892,13 @@ class _FileCache(object):
class BinaryField(Field):
_default = None
cast = bytearray if bytes == str else bytes
def get(self, record):
result = record.value.get(self.name, self._default)
if isinstance(result, _FileCache):
try:
with open(result.path, 'rb') as fp:
result = self.cast(fp.read())
result = fp.read()
except IOError:
result = self.get_data(record)
return result
@@ -905,8 +908,11 @@ class BinaryField(Field):
def set_client(self, record, value, force_change=False):
_, filename = tempfile.mkstemp(prefix='tryton_')
data = value or b''
if isinstance(data, str):
data = data.encode('utf-8')
with open(filename, 'wb') as fp:
fp.write(value or '')
fp.write(data)
self.set(record, _FileCache(filename))
record.modified_fields.setdefault(self.name)
record.signal('record-modified')
@@ -918,24 +924,27 @@ class BinaryField(Field):
result = record.value.get(self.name) or 0
if isinstance(result, _FileCache):
result = os.stat(result.path).st_size
elif isinstance(result, (basestring, bytes, bytearray)):
elif isinstance(result, (str, bytes)):
result = len(result)
return result
def get_data(self, record):
if not isinstance(record.value.get(self.name),
(basestring, bytes, bytearray, _FileCache)):
(str, bytes, _FileCache)):
if record.id < 0:
return ''
return b''
context = record.get_context()
try:
values, = RPCExecute('model', record.model_name, 'read',
[record.id], [self.name], context=context)
except RPCException:
return ''
return b''
_, filename = tempfile.mkstemp(prefix='tryton_')
data = values[self.name] or b''
if isinstance(data, str):
data = data.encode('utf-8')
with open(filename, 'wb') as fp:
fp.write(values[self.name] or '')
fp.write(data)
self.set(record, _FileCache(filename))
return self.get(record)
+7 -7
View File
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from record import Record
from field import Field, M2OField, ReferenceField
from .record import Record
from .field import Field, M2OField, ReferenceField
from tryton import rpc
from tryton.signal_event import SignalEvent
from tryton.common.domain_inversion import is_leaf
@@ -154,7 +154,7 @@ class Group(SignalEvent, list):
return '<Group %s at %s>' % (self.model_name, id(self))
def load_fields(self, fields):
for name, attr in fields.iteritems():
for name, attr in fields.items():
field = Field.get_field(attr['type'])
attr['name'] = name
self.fields[name] = field(attr)
@@ -184,7 +184,7 @@ class Group(SignalEvent, list):
return root
def written(self, ids):
if isinstance(ids, (int, long)):
if isinstance(ids, int):
ids = [ids]
ids = [x for x in self.on_write_ids(ids) or [] if x not in ids]
if not ids:
@@ -400,7 +400,7 @@ class Group(SignalEvent, list):
return None
return self[self.current_idx]
def next(self):
def __next__(self):
if len(self) and self.current_idx is not None:
self.current_idx = (self.current_idx + 1) % len(self)
elif len(self):
@@ -411,7 +411,7 @@ class Group(SignalEvent, list):
def add_fields(self, fields):
to_add = {}
for name, attr in fields.iteritems():
for name, attr in fields.items():
if name not in self.fields:
to_add[name] = attr
else:
@@ -429,7 +429,7 @@ class Group(SignalEvent, list):
if len(new) and len(to_add):
try:
values = RPCExecute('model', self.model_name, 'default_get',
to_add.keys(), context=self.context)
list(to_add.keys()), context=self.context)
except RPCException:
return False
for record in new:
+24 -24
View File
@@ -3,7 +3,7 @@
from tryton.signal_event import SignalEvent
import tryton.common as common
from tryton.pyson import PYSONDecoder
import field as fields
from . import field as fields
from tryton.common import RPCExecute, RPCException
from tryton.config import CONFIG
@@ -45,12 +45,12 @@ class Record(SignalEvent):
if name == '*':
loading = 'eager'
views = set()
for field in self.group.fields.itervalues():
for field in self.group.fields.values():
if field.attrs.get('loading', 'eager') == 'lazy':
loading = 'lazy'
views |= field.views
# Set a valid name for next loaded check
for fname, field in self.group.fields.iteritems():
for fname, field in self.group.fields.items():
if field.attrs.get('loading', 'eager') == loading:
name = fname
break
@@ -60,10 +60,10 @@ class Record(SignalEvent):
if loading == 'eager':
fields = ((fname, field)
for fname, field in self.group.fields.iteritems()
for fname, field in self.group.fields.items()
if field.attrs.get('loading', 'eager') == 'eager')
else:
fields = self.group.fields.iteritems()
fields = self.group.fields.items()
fnames = [fname for fname, field in fields
if fname not in self._loaded
@@ -113,20 +113,20 @@ class Record(SignalEvent):
ctx = record_context.copy()
ctx.update(dict(('%s.%s' % (self.model_name, fname), 'size')
for fname, field in self.group.fields.iteritems()
for fname, field in self.group.fields.items()
if field.attrs['type'] == 'binary' and fname in fnames))
exception = None
try:
values = RPCExecute('model', self.model_name, 'read',
id2record.keys(), fnames, context=ctx)
except RPCException, exception:
list(id2record.keys()), fnames, context=ctx)
except RPCException as exception:
values = [{'id': x} for x in id2record]
default_values = dict((f, None) for f in fnames)
for value in values:
value.update(default_values)
self.exception = True
id2value = dict((value['id'], value) for value in values)
for id, record in id2record.iteritems():
for id, record in id2record.items():
if not record.exception:
record.exception = bool(exception)
value = id2value.get(id)
@@ -253,7 +253,7 @@ class Record(SignalEvent):
def get(self):
value = {}
for name, field in self.group.fields.iteritems():
for name, field in self.group.fields.items():
if (field.attrs.get('readonly')
and not isinstance(field, fields.O2MField)):
continue
@@ -267,7 +267,7 @@ class Record(SignalEvent):
def get_eval(self):
value = {}
for name, field in self.group.fields.iteritems():
for name, field in self.group.fields.items():
if name not in self._loaded and self.id >= 0:
continue
value[name] = field.get_eval(self)
@@ -276,7 +276,7 @@ class Record(SignalEvent):
def get_on_change_value(self, skip=None):
value = {}
for name, field in self.group.fields.iteritems():
for name, field in self.group.fields.items():
if skip and name in skip:
continue
if (self.id >= 0
@@ -295,7 +295,7 @@ class Record(SignalEvent):
def get_timestamp(self):
result = {self.model_name + ',' + str(self.id): self._timestamp}
for name, field in self.group.fields.iteritems():
for name, field in self.group.fields.items():
if name in self._loaded:
result.update(field.get_timestamp(self))
return result
@@ -376,7 +376,7 @@ class Record(SignalEvent):
context.setdefault('default_rec_name', rec_name)
try:
vals = RPCExecute('model', self.model_name, 'default_get',
self.group.fields.keys(), context=context)
list(self.group.fields.keys()), context=context)
except RPCException:
return
if (self.parent
@@ -404,7 +404,7 @@ class Record(SignalEvent):
elif fields is None:
self._check_load()
res = True
for field_name, field in self.group.fields.iteritems():
for field_name, field in self.group.fields.items():
if fields is not None and field_name not in fields:
continue
if field.attrs.get('readonly'):
@@ -417,7 +417,7 @@ class Record(SignalEvent):
def _get_invalid_fields(self):
fields = {}
for fname, field in self.group.fields.iteritems():
for fname, field in self.group.fields.items():
invalid = field.get_state_attrs(self).get('invalid')
if invalid:
fields[fname] = invalid
@@ -430,7 +430,7 @@ class Record(SignalEvent):
def set_default(self, val, signal=True, validate=True):
fieldnames = []
for fieldname, value in val.items():
for fieldname, value in list(val.items()):
if fieldname not in self.group.fields:
continue
if fieldname == self.group.exclude_field:
@@ -455,7 +455,7 @@ class Record(SignalEvent):
def set(self, val, signal=True, validate=True):
later = {}
fieldnames = []
for fieldname, value in val.iteritems():
for fieldname, value in val.items():
if fieldname == '_timestamp':
# Always keep the older timestamp
if not self._timestamp:
@@ -478,7 +478,7 @@ class Record(SignalEvent):
self.group.fields[fieldname].set(self, value)
self._loaded.add(fieldname)
fieldnames.append(fieldname)
for fieldname, value in later.iteritems():
for fieldname, value in later.items():
self.group.fields[fieldname].set(self, value)
self._loaded.add(fieldname)
if validate:
@@ -487,7 +487,7 @@ class Record(SignalEvent):
self.signal('record-changed')
def set_on_change(self, values):
for fieldname, value in values.items():
for fieldname, value in list(values.items()):
if fieldname not in self.group.fields:
continue
if isinstance(self.group.fields[fieldname], (fields.M2OField,
@@ -520,7 +520,7 @@ class Record(SignalEvent):
self.signal('record-changed')
def expr_eval(self, expr):
if not isinstance(expr, basestring):
if not isinstance(expr, str):
return expr
ctx = self.get_eval()
ctx['context'] = self.get_context()
@@ -605,7 +605,7 @@ class Record(SignalEvent):
self.group.fields[fieldname].set_on_change(self, result)
def autocomplete_with(self, field_name):
for fieldname, fieldinfo in self.group.fields.iteritems():
for fieldname, fieldinfo in self.group.fields.items():
autocomplete = fieldinfo.attrs.get('autocomplete', [])
if field_name not in autocomplete:
continue
@@ -625,7 +625,7 @@ class Record(SignalEvent):
def set_field_context(self):
from .group import Group
for name, field in self.group.fields.iteritems():
for name, field in self.group.fields.items():
value = self.value.get(name)
if not isinstance(value, Group):
continue
@@ -677,7 +677,7 @@ class Record(SignalEvent):
return clicks
def destroy(self):
for v in self.value.itervalues():
for v in self.value.values():
if hasattr(v, 'destroy'):
v.destroy()
super(Record, self).destroy()
@@ -1,3 +1,3 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from screen import *
from .screen import *
+12 -12
View File
@@ -8,11 +8,11 @@ import datetime
import calendar
import json
import collections
import urllib
import urlparse
import urllib.parse
import xml.dom.minidom
import gettext
import logging
from operator import itemgetter
import gtk
@@ -170,7 +170,7 @@ class Screen(SignalEvent):
view_tree = self.fields_view_tree[view_id]
fields = copy.deepcopy(view_tree['fields'])
for name, props in fields.iteritems():
for name, props in fields.items():
if props['type'] not in ('selection', 'reference'):
continue
if isinstance(props['selection'], (tuple, list)):
@@ -202,7 +202,7 @@ class Screen(SignalEvent):
):
if name not in fields:
fields[name] = {
'string': string.decode('utf-8'),
'string': string,
'name': name,
'type': type_,
}
@@ -224,7 +224,7 @@ class Screen(SignalEvent):
props['selection'])
except RPCException:
selection = []
selection.sort(lambda x, y: cmp(x[1], y[1]))
selection.sort(key=itemgetter(1))
return selection
def search_prev(self, search_string):
@@ -355,7 +355,7 @@ class Screen(SignalEvent):
fields_views = {}
if self.group is not None:
self.group.signal_unconnect(self)
for name, field in self.group.fields.iteritems():
for name, field in self.group.fields.items():
fields[name] = field.attrs
fields_views[name] = field.views
self.tree_states_done.clear()
@@ -375,7 +375,7 @@ class Screen(SignalEvent):
self._record_modified)
self.__group.signal_connect(self, 'group-changed', self._group_changed)
self.__group.add_fields(fields)
for name, views in fields_views.iteritems():
for name, views in fields_views.items():
self.__group.fields[name].views.update(views)
self.__group.exclude_field = self.exclude_field
@@ -827,7 +827,7 @@ class Screen(SignalEvent):
timestamp = self.parent._timestamp if self.parent else None
for view in self.views:
if view.view_type == 'form':
for widgets in view.widgets.itervalues():
for widgets in view.widgets.values():
for widget in widgets:
if hasattr(widget, 'screen'):
widget.screen.save_tree_state(store)
@@ -1036,7 +1036,7 @@ class Screen(SignalEvent):
record = self.current_record
domain_string = _('"%s" is not valid according to its domain')
domain_parser = DomainParser(
{n: f.attrs for n, f in record.group.fields.iteritems()})
{n: f.attrs for n, f in record.group.fields.items()})
fields = []
for field, invalid in sorted(record.invalid_fields.items()):
string = record.group.fields[field].attrs['string']
@@ -1134,7 +1134,7 @@ class Screen(SignalEvent):
except RPCException:
action = None
self.reload(ids, written=True)
if isinstance(action, basestring):
if isinstance(action, str):
self.client_action(action)
elif action:
Action.execute(action, {
@@ -1208,7 +1208,7 @@ class Screen(SignalEvent):
if view_ids:
query_string.append(('views', json.dumps(
view_ids, separators=(',', ':'))))
query_string = urllib.urlencode(query_string)
return urlparse.urlunparse(('tryton',
query_string = urllib.parse.urlencode(query_string)
return urllib.parse.urlunparse(('tryton',
'%s:%s' % (rpc._HOST, rpc._PORT),
'/'.join(path), query_string, '', ''))
@@ -11,7 +11,7 @@ from . import View
try:
from .calendar_gtk.calendar_ import Calendar_
from .calendar_gtk.toolbar import Toolbar
except ImportError, e:
except ImportError as e:
Calendar_ = None
Toolbar = None
@@ -3,7 +3,7 @@
import calendar
import datetime
import goocalendar
from dates_period import DatesPeriod
from .dates_period import DatesPeriod
class Calendar_(goocalendar.Calendar):
+7 -7
View File
@@ -466,13 +466,13 @@ class ViewForm(View):
return cls.WIDGETS[name]
def get_fields(self):
return self.widgets.keys()
return list(self.widgets.keys())
def __getitem__(self, name):
return self.widgets[name][0]
def destroy(self):
for widget_name in self.widgets.keys():
for widget_name in list(self.widgets.keys()):
for widget in self.widgets[widget_name]:
widget.destroy()
self.widget.destroy()
@@ -480,7 +480,7 @@ class ViewForm(View):
def set_value(self, focused_widget=False):
record = self.screen.current_record
if record:
for name, widgets in self.widgets.iteritems():
for name, widgets in self.widgets.items():
if name in record.group.fields:
field = record.group.fields[name]
for widget in widgets:
@@ -498,7 +498,7 @@ class ViewForm(View):
@property
def modified(self):
return any(w.modified for widgets in self.widgets.itervalues()
return any(w.modified for widgets in self.widgets.values()
for w in widgets)
def get_buttons(self):
@@ -507,7 +507,7 @@ class ViewForm(View):
def reset(self):
record = self.screen.current_record
if record:
for name, widgets in self.widgets.iteritems():
for name, widgets in self.widgets.items():
field = record.group.fields.get(name)
if field and 'invalid' in field.get_state_attrs(record):
for widget in widgets:
@@ -523,13 +523,13 @@ class ViewForm(View):
(name,
field.attrs.get('loading', 'eager') == 'eager',
len(field.views))
for name, field in record.group.fields.iteritems()
for name, field in record.group.fields.items()
if self.view_id in field.views)
fields = sorted(fields, key=operator.itemgetter(1, 2))
for field, _, _ in fields:
record[field].get(record)
focused_widget = find_focused_child(self.widget)
for name, widgets in self.widgets.iteritems():
for name, widgets in self.widgets.items():
field = None
if record:
field = record.group.fields.get(name)
@@ -126,7 +126,7 @@ class DictSelectionEntry(DictEntry):
text = child.get_text()
value = None
if text:
for txt, val in self._selection.items():
for txt, val in list(self._selection.items()):
if not val:
continue
if txt[:len(text)].lower() == text.lower():
@@ -390,7 +390,7 @@ class DictWidget(Widget):
def _sig_add(self, *args):
context = self.field.get_context(self.record)
value = self.wid_text.get_text().decode('utf-8')
value = self.wid_text.get_text()
domain = self.field.domain_get(self.record)
def callback(result):
@@ -439,20 +439,20 @@ class DictWidget(Widget):
def get_value(self):
return dict((key, widget.get_value())
for key, widget in self.fields.items())
for key, widget in list(self.fields.items()))
@property
def modified(self):
if self.record and self.field:
value = self.field.get_client(self.record)
return any(widget.modified(value)
for widget in self.fields.itervalues())
for widget in self.fields.values())
return False
def _readonly_set(self, readonly):
self._readonly = readonly
self._set_button_sensitive()
for widget in self.fields.values():
for widget in list(self.fields.values()):
widget.set_readonly(readonly)
self.wid_text.set_sensitive(not readonly)
self.wid_text.set_editable(not readonly)
@@ -461,7 +461,7 @@ class DictWidget(Widget):
self.but_add.set_sensitive(bool(
not self._readonly
and self.attrs.get('create', True)))
for button in self.buttons.itervalues():
for button in self.buttons.values():
button.set_sensitive(bool(
not self._readonly
and self.attrs.get('delete', True)))
@@ -507,7 +507,7 @@ class DictWidget(Widget):
context = self.field.get_context(self.record)
domain = self.field.domain_get(self.record)
batchlen = min(10, CONFIG['client.limit'])
for i in xrange(0, len(keys), batchlen):
for i in range(0, len(keys), batchlen):
sub_keys = keys[i:i + batchlen]
try:
key_ids = RPCExecute('model', self.schema_model, 'search',
@@ -534,15 +534,15 @@ class DictWidget(Widget):
record_id = record.id if record else None
if record_id != self._record_id:
for key in self.fields.keys():
for key in list(self.fields.keys()):
self._sig_remove(None, key, modified=False)
self._record_id = record_id
value = field.get_client(record) if field else {}
new_key_names = set(value.iterkeys()) - set(self.keys)
new_key_names = set(value.keys()) - set(self.keys)
if new_key_names:
self.add_keys(list(new_key_names))
for key, val in sorted(value.iteritems()):
for key, val in sorted(value.items()):
if key not in self.keys:
continue
if key not in self.fields:
@@ -2,7 +2,7 @@
# this repository contains the full copyright notices and license terms.
import gtk
import gettext
import urllib
import urllib.request
from tryton.common import resize_pixbuf, data2pixbuf, BIG_IMAGE_SIZE
from .widget import Widget
@@ -76,12 +76,14 @@ class Image(BinaryMixin, Widget):
if info == 0:
uri = selection.get_text().split('\n')[0]
if uri:
self.field.set_client(self.record, urllib.urlopen(uri).read())
self.field.set_client(
self.record, urllib.request.urlopen(uri).read())
self.update_img()
elif info == 1:
uri = selection.data.split('\r\n')[0]
if uri:
self.field.set_client(self.record, urllib.urlopen(uri).read())
self.field.set_client(
self.record, urllib.request.urlopen(uri).read())
self.update_img()
elif info == 2:
data = selection.get_pixbuf()
@@ -93,7 +95,7 @@ class Image(BinaryMixin, Widget):
value = None
if self.field:
value = self.field.get_client(self.record)
if isinstance(value, (int, long)):
if isinstance(value, int):
if value > BIG_IMAGE_SIZE:
value = False
else:
@@ -151,7 +151,7 @@ class Many2Many(Widget):
domain = [domain, add_remove]
context = self.field.get_search_context(self.record)
order = self.field.get_search_order(self.record)
value = self.wid_text.get_text().decode('utf-8')
value = self.wid_text.get_text()
self.focus_out = False
@@ -121,7 +121,7 @@ class Many2One(Widget):
domain = self.field.domain_get(self.record)
context = self.field.get_search_context(self.record)
order = self.field.get_search_order(self.record)
text = self.wid_text.get_text().decode('utf-8')
text = self.wid_text.get_text()
def callback(result):
if result:
@@ -212,7 +212,7 @@ class Many2One(Widget):
domain = self.field.domain_get(self.record)
context = self.field.get_search_context(self.record)
order = self.field.get_search_order(self.record)
text = self.wid_text.get_text().decode('utf-8')
text = self.wid_text.get_text()
def callback(result):
if result:
@@ -413,8 +413,8 @@ class One2Many(Widget):
self.screen.group.remove(first, remove=True)
return
fields = product.keys()
for values in itertools.product(*product.values()):
fields = list(product.keys())
for values in itertools.product(*list(product.values())):
if first:
record = first
first = None
@@ -478,7 +478,7 @@ class One2Many(Widget):
domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))]
removed_ids = self.field.get_removed_ids(self.record)
domain = ['OR', domain, ('id', 'in', removed_ids)]
text = self.wid_text.get_text().decode('utf-8')
text = self.wid_text.get_text()
self.focus_out = False
@@ -259,7 +259,7 @@ class RichTextBox(TextBox):
start.backward_chars(length)
end = iter_.copy()
# Apply tags activated from toolbar
for name, widget in self.tag_widgets[textview].iteritems():
for name, widget in self.tag_widgets[textview].items():
self._apply_tool(text_buffer, name, widget, start, end)
def _apply_tool(self, text_buffer, name, tool, start, end):
@@ -93,7 +93,7 @@ class Notebook(StateMixin, gtk.Notebook):
else:
state_changes = {}
if state_changes.get('readonly', self.attrs.get('readonly')):
for widgets in self.widgets.itervalues():
for widgets in self.widgets.values():
for widget in widgets:
widget._readonly_set(True)
@@ -111,7 +111,7 @@ class TextBox(Widget, TranslateMixin):
buf = textview.get_buffer()
iter_start = buf.get_start_iter()
iter_end = buf.get_end_iter()
return buf.get_text(iter_start, iter_end, False).decode('utf-8')
return buf.get_text(iter_start, iter_end, False)
def display(self, record, field):
super(TextBox, self).display(record, field)
@@ -152,7 +152,6 @@ class TextBufferLimitSize(gtk.TextBuffer):
def do_insert_text(self, iter, text, length):
free_chars = self.max_length - self.get_char_count()
# Slice operation needs an unicode string to work as expected
text = text.decode('utf-8')[0:free_chars].encode('utf-8')
text = text[0:free_chars]
length = len(text)
return gtk.TextBuffer.do_insert_text(self, iter, text, length)
@@ -220,7 +220,7 @@ class TranslateDialog(NoModal):
def response(self, win, response):
if response == gtk.RESPONSE_OK:
for code, widget in self.widgets.iteritems():
for code, widget in self.widgets.items():
widget, editing, fuzzy = widget
if not editing.get_active():
continue
+3 -2
View File
@@ -111,7 +111,7 @@ class ViewGraph(View):
hbox.pack_start(gtk.Label(_('Width:')), False, True)
spinwidth = gtk.SpinButton()
spinwidth.configure(gtk.Adjustment(400.0, 0.0, sys.maxint, 1.0, 10.0),
spinwidth.configure(gtk.Adjustment(400.0, 0.0, sys.maxsize, 1.0, 10.0),
climb_rate=1, digits=0)
spinwidth.set_numeric(True)
spinwidth.set_activates_default(True)
@@ -119,7 +119,8 @@ class ViewGraph(View):
hbox.pack_start(gtk.Label(_('Height:')), False, True)
spinheight = gtk.SpinButton()
spinheight.configure(gtk.Adjustment(200.0, 0.0, sys.maxint, 1.0, 10.0),
spinheight.configure(gtk.Adjustment(
200.0, 0.0, sys.maxsize, 1.0, 10.0),
climb_rate=1, digits=0)
spinheight.set_numeric(True)
spinheight.set_activates_default(True)
@@ -8,7 +8,7 @@ import datetime
import cairo
from graph import Graph
from .graph import Graph
import tryton.common as common
import tryton.rpc as rpc
@@ -142,7 +142,7 @@ class VerticalBar(Bar):
self.bars = []
i = 0
keys = self.datas.keys()
keys = list(self.datas.keys())
keys.sort()
for xfield in keys:
j = 0
@@ -198,7 +198,7 @@ class HorizontalBar(Bar):
self.bars = []
i = 0
keys = self.datas.keys()
keys = list(self.datas.keys())
keys.sort()
for xfield in keys:
j = 0
@@ -127,7 +127,7 @@ class Graph(gtk.DrawingArea):
self.drawGraph(cx, width, height)
self.drawAxis(cx, width, height)
self.drawLegend(cx, width, height)
surface.write_to_png(filename.encode('utf-8'))
surface.write_to_png(filename)
self.queue_draw()
@@ -176,7 +176,7 @@ class Graph(gtk.DrawingArea):
base = 1
else:
base = 10 ** int(math.log(self.yrange, 10))
for i in xrange(int(self.yrange / base) + 1):
for i in range(int(self.yrange / base) + 1):
val = int(self.minyval / base) * base + i * base
h = (val - self.minyval) * self.yscale
label = locale.format('%.2f', val, True)
@@ -186,7 +186,7 @@ class Graph(gtk.DrawingArea):
def XLabels(self):
xlabels = []
i = 0.0
keys = self.datas.keys()
keys = list(self.datas.keys())
keys.sort()
for key in keys:
if self.xrange == 0:
@@ -439,7 +439,7 @@ class Graph(gtk.DrawingArea):
else:
self.xscale = 1.0 / self.xrange
if not self.datas.values():
if not list(self.datas.values()):
self.maxyval = 0.0
self.minyval = 0.0
else:
@@ -8,7 +8,7 @@ import datetime
import cairo
from graph import Graph
from .graph import Graph
import tryton.common as common
import tryton.rpc as rpc
@@ -23,7 +23,7 @@ class Line(Graph):
self.points = []
i = 0
keys = self.datas.keys()
keys = list(self.datas.keys())
keys.sort()
for xfield in keys:
j = 0
@@ -8,7 +8,7 @@ import datetime
import cairo
from graph import Graph, Area
from .graph import Graph, Area
import tryton.common as common
import tryton.rpc as rpc
@@ -16,7 +16,7 @@ import tryton.rpc as rpc
class Pie(Graph):
def _getDatasKeys(self):
return self.datas.keys()
return list(self.datas.keys())
def drawLegend(self, cr, width, height):
pass
@@ -71,7 +71,7 @@ class Pie(Graph):
def updateGraph(self):
self.sum = 0.0
for xkey in self.datas.iterkeys():
for xkey in self.datas.keys():
key = self.yfields[0].get('key', self.yfields[0]['name'])
if self.datas[xkey][key] > 0:
self.sum += self.datas[xkey][key]
@@ -79,7 +79,7 @@ class Pie(Graph):
fraction = angle = 0.0
self.slices = []
for xkey in self.datas.iterkeys():
for xkey in self.datas.keys():
key = self.yfields[0].get('key', self.yfields[0]['name'])
value = self.datas[xkey][key]
if value > 0:
+3 -4
View File
@@ -158,8 +158,7 @@ class AdaptModelGroup(gtk.GenericTreeModel):
pos += 1
except KeyError:
continue
self.group.sort(lambda x, y:
cmp(new_order[ids2pos[x.id]], new_order[ids2pos[y.id]]))
self.group.sort(key=lambda x: new_order[ids2pos[x.id]])
prev = None
for record in self.group:
if prev:
@@ -561,7 +560,7 @@ class ViewTree(View):
column.arrow.set(gtk.ARROW_NONE, gtk.SHADOW_NONE)
model = self.treeview.get_model()
unsaved_records = [x for x in model.group if x.id < 0]
search_string = self.screen.screen_container.get_text() or u''
search_string = self.screen.screen_container.get_text() or ''
if (self.screen.search_count == len(model)
or unsaved_records
or self.screen.parent):
@@ -969,7 +968,7 @@ class ViewTree(View):
if last_col and last_col.name in fields:
del fields[last_col.name]
if fields and any(fields.itervalues()):
if fields and any(fields.values()):
model_name = self.screen.model_name
try:
RPCExecute('model', 'ir.ui.view_tree_width', 'set_width',
@@ -142,7 +142,7 @@ class EditableTreeView(TreeView):
if event.keyval == gtk.keysyms.Right:
if isinstance(entry, gtk.Entry):
if entry.get_position() >= \
len(entry.get_text().decode('utf-8')) \
len(entry.get_text()) \
and not entry.get_selection_bounds():
leaving = True
else:
@@ -180,7 +180,7 @@ class EditableTreeView(TreeView):
gobject.idle_add(self.set_cursor, path,
self.prev_column(path, column), True)
elif keyval in self.leaving_record_events:
fields = self.view.widgets.keys()
fields = list(self.view.widgets.keys())
if not record.validate(fields):
invalid_fields = record.invalid_fields
col = None
@@ -480,9 +480,12 @@ class Binary(GenericText):
file_path = os.path.join(dtemp, filename)
with open(file_path, 'wb') as fp:
if hasattr(field, 'get_data'):
fp.write(field.get_data(record))
data = field.get_data(record)
else:
fp.write(field.get(record))
data = field.get(record)
if isinstance(data, str):
data = data.encode('utf-8')
fp.write(data)
root, type_ = os.path.splitext(filename)
if type_:
type_ = type_[1:]
@@ -527,7 +530,7 @@ class Image(GenericText):
record = store.get_value(iter_, 0)
field = record[self.field_name]
value = field.get_client(record)
if isinstance(value, (int, long)):
if isinstance(value, int):
if value > common.BIG_IMAGE_SIZE:
value = None
else:
@@ -665,7 +668,7 @@ class M2O(GenericText):
context=context, domain=domain,
order=order, view_ids=self.attrs.get('view_ids', '').split(','),
new=create_access, title=self.attrs.get('string'))
win.screen.search_filter(quote(text.decode('utf-8')))
win.screen.search_filter(quote(text))
return win
def set_completion(self, entry, path):
@@ -819,7 +822,8 @@ class Selection(GenericText, SelectionMixin, PopdownMixin):
record = store.get_value(store.get_iter(path), 0)
field = record[self.attrs['name']]
set_value = lambda *a: self.set_value(editable, record, field)
def set_value(*a):
return self.set_value(editable, record, field)
editable.get_child().connect('activate', set_value)
editable.get_child().connect('focus-out-event', set_value)
editable.connect('changed', set_value)
@@ -344,7 +344,7 @@ class ScreenContainer(object):
model.append([r.strip()])
def get_text(self):
return self.search_entry.get_text().decode('utf-8')
return self.search_entry.get_text()
def set_text(self, value):
self.search_entry.set_text(value)
@@ -370,7 +370,7 @@ class ScreenContainer(object):
bool(current_text))
for id_, name, domain in self.bookmarks():
text = self.screen.domain_parser.string(domain)
domain = self.screen.domain_parser.parse(text.decode('utf-8'))
domain = self.screen.domain_parser.parse(text)
if (text == current_text
or domain == current_domain):
if icon_stock != 'tryton-star':
@@ -549,7 +549,7 @@ class ScreenContainer(object):
self.search_window.handler_unblock_by_func(window_hide)
vbox = gtk.VBox()
fields = [f for f in self.screen.domain_parser.fields.itervalues()
fields = [f for f in self.screen.domain_parser.fields.values()
if f.get('searchable', True)]
self.search_table = gtk.Table(rows=len(fields), columns=2)
self.search_table.set_homogeneous(False)
@@ -617,8 +617,8 @@ class ScreenContainer(object):
self.search_window.add(vbox)
vbox.show_all()
new_size = map(sum, zip(self.search_table.size_request(),
scrolled.size_request()))
new_size = list(map(sum, list(zip(self.search_table.size_request(),
scrolled.size_request()))))
self.search_window.set_default_size(*new_size)
parent = widget.get_toplevel()
+6 -8
View File
@@ -3,7 +3,6 @@
import csv
import os
import tempfile
import types
import gtk
import gobject
@@ -94,8 +93,10 @@ class WinExport(WinCSV):
def model_populate(self, fields, parent_node=None, prefix_field='',
prefix_name=''):
key = lambda (n, f): f.get('string') or n
for name, field in sorted(fields.items(), key=key, reverse=True):
def key(n_f):
return n_f[1].get('string') or n_f[0]
for name, field in sorted(list(fields.items()), key=key, reverse=True):
string_ = field['string'] or name
@@ -314,7 +315,7 @@ class WinExport(WinCSV):
try:
writer = csv.writer(
open(fname, 'wb+'),
open(fname, 'w+', encoding=encoding),
quotechar=self.get_quotechar(),
delimiter=self.get_delimiter())
if self.add_field_names.get_active():
@@ -322,9 +323,6 @@ class WinExport(WinCSV):
for line in data:
row = []
for val in line:
if isinstance(type(val), types.StringType):
val = val.replace('\n', ' ').replace('\t', ' ')
val = val.encode(encoding)
row.append(val)
writer.writerow(row)
if popup:
@@ -333,7 +331,7 @@ class WinExport(WinCSV):
else:
common.message(_('%d records saved.') % len(data))
return True
except IOError, exception:
except IOError as exception:
common.warning(_("Operation failed.\nError message:\n%s")
% exception, _('Error'))
return False
+2 -2
View File
@@ -316,7 +316,7 @@ class WinForm(NoModal, InfoBar):
from tryton.gui.window.win_search import WinSearch
domain = self.domain[:]
model_name = self.screen.model_name
value = self.wid_text.get_text().decode('utf-8')
value = self.wid_text.get_text()
def callback(result):
if result:
@@ -390,7 +390,7 @@ class WinForm(NoModal, InfoBar):
validate = False
elif validate and self.screen.current_view.view_type == 'form':
view = self.screen.current_view
for widgets in view.widgets.itervalues():
for widgets in view.widgets.values():
for widget in widgets:
if (hasattr(widget, 'screen')
and widget.screen.pre_validate):
+7 -8
View File
@@ -56,9 +56,9 @@ class WinImport(WinCSV):
def model_populate(self, fields, parent_node=None, prefix_field='',
prefix_name=''):
fields_order = fields.keys()
fields_order.sort(lambda x, y: -cmp(fields[x].get('string', ''),
fields[y].get('string', '')))
fields_order = list(fields.keys())
fields_order.sort(
key=lambda x: fields[x].get('string', ''), reverse=True)
for field in fields_order:
if not fields[field].get('readonly', False):
self.fields_data[prefix_field + field] = fields[field]
@@ -101,21 +101,20 @@ class WinImport(WinCSV):
common.message(_('You must select an import file first.'))
return True
encoding = self.get_encoding()
self.csv_skip.set_value(1)
try:
data = csv.reader(
open(fname, 'rb'),
open(fname, 'r', encoding=encoding),
quotechar=self.get_quotechar(),
delimiter=self.get_delimiter())
except IOError:
common.warning(_('Error opening CSV file'), _('Error'))
return True
self.sig_unsel_all()
encoding = self.get_encoding()
word = ''
for line in data:
for word in line:
word = word.decode(encoding)
if word not in self.fields_invert and word not in self.fields:
iter = self.model1.get_iter_first()
prefix = ''
@@ -181,14 +180,14 @@ class WinImport(WinCSV):
skip = self.csv_skip.get_value_as_int()
encoding = self.get_encoding()
reader = csv.reader(
open(fname, 'rb'),
open(fname, 'r', encoding=encoding),
quotechar=self.get_quotechar(),
delimiter=self.get_delimiter())
data = []
for i, line in enumerate(reader):
if i < skip or not line:
continue
data.append([x.decode(encoding).encode('utf-8') for x in line])
data.append([x for x in line])
try:
count = RPCExecute(
'model', self.model, 'import_data', fields, data,
+3 -3
View File
@@ -22,10 +22,10 @@ class Window(object):
def create(model, **attributes):
from tryton.gui import Main
if model:
from form import Form
from .form import Form
win = Form(model, **attributes)
else:
from board import Board
from .board import Board
win = Board(model, **attributes)
win.icon = attributes.get('icon')
Main.get_main().win_add(win, hide_current=Window.hide_current,
@@ -35,7 +35,7 @@ class Window(object):
def create_wizard(action, data, direct_print=False, email_print=False,
email=None, name='', context=None, icon=None, window=False):
from tryton.gui import Main
from wizard import WizardForm, WizardDialog
from .wizard import WizardForm, WizardDialog
if window:
win = WizardForm(name=name)
win.icon = icon
+2 -2
View File
@@ -93,7 +93,7 @@ class Wizard(InfoBar):
def callback(result):
try:
result = result()
except RPCException, rpc_exception:
except RPCException as rpc_exception:
if (not isinstance(rpc_exception.exception,
TrytonServerError)
or not self.screen):
@@ -180,7 +180,7 @@ class Wizard(InfoBar):
self.update_buttons(record)
def update_buttons(self, record):
for button in self.states.itervalues():
for button in self.states.values():
button.state_set(record)
def update(self, view, defaults, buttons):
+5 -4
View File
@@ -58,7 +58,7 @@ class FileServer(IPCServer):
def setup(self):
config = open(self.config, 'w')
print >> config, self.tmpdir
print(self.tmpdir, file=config)
def clean(self):
try:
@@ -101,7 +101,7 @@ class FIFOServer(IPCServer):
def setup(self):
self.filename = os.path.join(self.tmpdir, 'Socket')
os.mkfifo(self.filename, 0600)
os.mkfifo(self.filename, 0o600)
if os.path.lexists(self.config):
os.remove(self.config)
os.symlink(self.filename, self.config)
@@ -160,7 +160,7 @@ class FileClient(IPCClient):
tmpdir = open(self.filename, 'r').readline().strip()
_, tmpfile = tempfile.mkstemp(dir=tmpdir, text=True)
with open(tmpfile, 'w') as tmpfile:
print >> tmpfile, message
print(message, file=tmpfile)
return True
@@ -173,9 +173,10 @@ class FIFOClient(IPCClient):
if not os.path.lexists(self.filename):
return False
fifo = open(self.filename, 'w')
print >> fifo, message
print(message, file=fifo)
return True
if hasattr(os, 'mkfifo'):
Server = FIFOServer
Client = FIFOClient
+28 -28
View File
@@ -1,21 +1,21 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import xmlrpclib
import xmlrpc.client
import json
import ssl
import httplib
import http.client
from decimal import Decimal
import datetime
import socket
import gzip
import StringIO
import io
import hashlib
import base64
import threading
import errno
from functools import partial
from contextlib import contextmanager
import string
from functools import reduce
__all__ = ["ResponseError", "Fault", "ProtocolError", "Transport",
"ServerProxy", "ServerPool"]
@@ -23,11 +23,11 @@ CONNECT_TIMEOUT = 5
DEFAULT_TIMEOUT = None
class ResponseError(xmlrpclib.ResponseError):
class ResponseError(xmlrpc.client.ResponseError):
pass
class Fault(xmlrpclib.Fault):
class Fault(xmlrpc.client.Fault):
def __init__(self, faultCode, faultString='', **extra):
super(Fault, self).__init__(faultCode, faultString, **extra)
@@ -40,7 +40,7 @@ class Fault(xmlrpclib.Fault):
)
class ProtocolError(xmlrpclib.ProtocolError):
class ProtocolError(xmlrpc.client.ProtocolError):
pass
@@ -57,8 +57,7 @@ def object_hook(dct):
elif dct['__class__'] == 'timedelta':
return datetime.timedelta(seconds=dct['seconds'])
elif dct['__class__'] == 'bytes':
cast = bytearray if bytes == str else bytes
return cast(base64.decodestring(dct['base64']))
return base64.decodestring(dct['base64'].encode('utf-8'))
elif dct['__class__'] == 'Decimal':
return Decimal(dct['decimal'])
return dct
@@ -94,9 +93,9 @@ class JSONEncoder(json.JSONEncoder):
return {'__class__': 'timedelta',
'seconds': obj.total_seconds(),
}
elif isinstance(obj, (bytes, bytearray)):
elif isinstance(obj, bytes):
return {'__class__': 'bytes',
'base64': base64.encodestring(obj),
'base64': base64.encodestring(obj).decode('utf-8'),
}
elif isinstance(obj, Decimal):
return {'__class__': 'Decimal',
@@ -122,19 +121,19 @@ class JSONUnmarshaller(object):
self.data = []
def feed(self, data):
self.data.append(data)
self.data.append(data.decode('utf-8'))
def close(self):
return json.loads(''.join(self.data), object_hook=object_hook)
class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport):
class Transport(xmlrpc.client.SafeTransport):
accept_gzip_encoding = True
encode_threshold = 1400 # common MTU
def __init__(self, fingerprints=None, ca_certs=None, session=None):
xmlrpclib.Transport.__init__(self)
xmlrpc.client.Transport.__init__(self)
self._connection = (None, None)
self.__fingerprints = fingerprints
self.__ca_certs = ca_certs
@@ -146,13 +145,14 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport):
return parser, target
def get_host_info(self, host):
host, extra_headers, x509 = xmlrpclib.Transport.get_host_info(
host, extra_headers, x509 = xmlrpc.client.Transport.get_host_info(
self, host)
if extra_headers is None:
extra_headers = []
if self.session:
auth = base64.encodestring(self.session)
auth = string.join(string.split(auth), "") # get rid of whitespace
auth = base64.encodestring(
self.session.encode('utf-8')).decode('ascii')
auth = ''.join(auth.split()) # get rid of whitespace
extra_headers.append(
('Authorization', 'Session ' + auth),
)
@@ -165,7 +165,7 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport):
self.encode_threshold < len(request_body) and
gzip):
connection.putheader("Content-Encoding", "gzip")
buffer = StringIO.StringIO()
buffer = io.BytesIO()
output = gzip.GzipFile(mode='wb', fileobj=buffer)
output.write(request_body)
output.close()
@@ -183,7 +183,7 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport):
ssl_ctx = ssl.create_default_context(cafile=self.__ca_certs)
class HTTPSConnection(httplib.HTTPSConnection):
class HTTPSConnection(http.client.HTTPSConnection):
def connect(self):
sock = socket.create_connection((self.host, self.port),
@@ -195,7 +195,7 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport):
sock, server_hostname=self.host)
def http_connection():
self._connection = host, httplib.HTTPConnection(host,
self._connection = host, http.client.HTTPConnection(host,
timeout=CONNECT_TIMEOUT)
self._connection[1].connect()
sock = self._connection[1].sock
@@ -242,7 +242,7 @@ class Transport(xmlrpclib.Transport, xmlrpclib.SafeTransport):
return self._connection[1]
class ServerProxy(xmlrpclib.ServerProxy):
class ServerProxy(xmlrpc.client.ServerProxy):
__id = 0
def __init__(self, host, port, database='', verbose=0,
@@ -262,7 +262,7 @@ class ServerProxy(xmlrpclib.ServerProxy):
'id': id_,
'method': methodname,
'params': params,
}, cls=JSONEncoder, separators=(',', ':'))
}, cls=JSONEncoder, separators=(',', ':')).encode('utf-8')
try:
try:
@@ -272,7 +272,7 @@ class ServerProxy(xmlrpclib.ServerProxy):
request,
verbose=self.__verbose
)
except (socket.error, httplib.HTTPException), v:
except (socket.error, http.client.HTTPException) as v:
if (isinstance(v, socket.error)
and v.args[0] == errno.EPIPE):
raise
@@ -284,9 +284,9 @@ class ServerProxy(xmlrpclib.ServerProxy):
request,
verbose=self.__verbose
)
except xmlrpclib.ProtocolError, e:
except xmlrpc.client.ProtocolError as e:
raise Fault(str(e.errcode), e.errmsg)
except:
except Exception:
self.__transport.close()
raise
@@ -303,7 +303,7 @@ class ServerProxy(xmlrpclib.ServerProxy):
@property
def ssl(self):
return isinstance(self.__transport.make_connection(self.__host),
httplib.HTTPSConnection)
http.client.HTTPSConnection)
class ServerPool(object):
@@ -337,14 +337,14 @@ class ServerPool(object):
def close(self):
with self._lock:
for conn in self._pool + self._used.values():
for conn in self._pool + list(self._used.values()):
conn.close()
self._pool = []
self._used.clear()
@property
def ssl(self):
for conn in self._pool + self._used.values():
for conn in self._pool + list(self._used.values()):
return conn.ssl
return False
+1 -1
View File
@@ -19,7 +19,7 @@ def register():
os.path.join(get_config_dir(), 'plugins'),
os.path.join(CURRENT_DIR, 'plugins'),
]
paths = filter(os.path.isdir, paths)
paths = list(filter(os.path.isdir, paths))
imported = set()
for path in paths:
+15 -15
View File
@@ -9,7 +9,7 @@ from functools import reduce, wraps
def reduced_type(types):
types = types.copy()
for k, r in [(long, int), (str, basestring), (unicode, basestring)]:
for k, r in [(int, int), (str, str), (str, str)]:
if k in types:
types.remove(k)
types.add(r)
@@ -313,10 +313,10 @@ class Greater(PYSON):
super(Greater, self).__init__()
for i in (statement1, statement2):
if isinstance(i, PYSON):
assert i.types().issubset({int, long, float, type(None)}), \
assert i.types().issubset({int, int, float, type(None)}), \
'statement must be an integer or a float'
else:
assert isinstance(i, (int, long, float, type(None))), \
assert isinstance(i, (int, float, type(None))), \
'statement must be an integer or a float'
if isinstance(equal, PYSON):
assert equal.types() == set([bool])
@@ -346,7 +346,7 @@ class Greater(PYSON):
for i in ('s1', 's2'):
if dct[i] is None:
dct[i] = 0.0
if not isinstance(dct[i], (int, long, float)):
if not isinstance(dct[i], (int, float)):
dct = dct.copy()
dct[i] = float(dct[i])
return dct
@@ -438,9 +438,9 @@ class Get(PYSON):
assert isinstance(obj, dict), 'obj must be a dict'
self._obj = obj
if isinstance(key, PYSON):
assert key.types() == set([basestring]), 'key must be a string'
assert key.types() == set([str]), 'key must be a string'
else:
assert isinstance(key, basestring), 'key must be a string'
assert isinstance(key, str), 'key must be a string'
self._key = key
self._default = default
@@ -474,20 +474,20 @@ class In(PYSON):
key, obj = k, v
super(In, self).__init__()
if isinstance(key, PYSON):
assert key.types().issubset(set([basestring, int])), \
assert key.types().issubset(set([str, int])), \
'key must be a string or an integer or a long'
else:
assert isinstance(key, (basestring, int, long)), \
assert isinstance(key, (str, int)), \
'key must be a string or an integer or a long'
if isinstance(obj, PYSON):
assert obj.types().issubset(set([dict, list])), \
'obj must be a dict or a list'
if obj.types() == set([dict]):
assert isinstance(key, basestring), 'key must be a string'
assert isinstance(key, str), 'key must be a string'
else:
assert isinstance(obj, (dict, list))
if isinstance(obj, dict):
assert isinstance(key, basestring), 'key must be a string'
assert isinstance(key, str), 'key must be a string'
self._key = key
self._obj = obj
@@ -523,10 +523,10 @@ class Date(PYSON):
super(Date, self).__init__()
for i in (year, month, day, delta_years, delta_months, delta_days):
if isinstance(i, PYSON):
assert i.types().issubset(set([int, long, type(None)])), \
assert i.types().issubset(set([int, int, type(None)])), \
'%s must be an integer or None' % (i,)
else:
assert isinstance(i, (int, long, type(None))), \
assert isinstance(i, (int, type(None))), \
'%s must be an integer or None' % (i,)
self._year = year
self._month = month
@@ -590,7 +590,7 @@ class DateTime(Date):
assert i.types() == set([int, type(None)]), \
'%s must be an integer or None' % (i,)
else:
assert isinstance(i, (int, long, type(None))), \
assert isinstance(i, (int, type(None))), \
'%s must be an integer or None' % (i,)
self._hour = hour
self._minute = minute
@@ -651,10 +651,10 @@ class Len(PYSON):
def __init__(self, v):
super(Len, self).__init__()
if isinstance(v, PYSON):
assert v.types().issubset(set([dict, list, basestring])), \
assert v.types().issubset(set([dict, list, str])), \
'value must be a dict or a list or a string'
else:
assert isinstance(v, (dict, list, basestring)), \
assert isinstance(v, (dict, list, str)), \
'value must be a dict or list or a string'
self._value = v
+5 -5
View File
@@ -1,6 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import httplib
import http.client
import logging
import socket
import ssl
@@ -41,7 +41,7 @@ def db_list(host, port):
result = connection.common.db.list()
logging.getLogger(__name__).debug(repr(result))
return result
except Fault, exception:
except Fault as exception:
if exception.faultCode == 'AccessDenied':
logging.getLogger(__name__).debug('AccessDenied')
return []
@@ -58,7 +58,7 @@ def server_version(host, port):
result = connection.common.server.version()
logging.getLogger(__name__).debug(repr(result))
return result
except (Fault, socket.error, ssl.SSLError, ssl.CertificateError), e:
except (Fault, socket.error, ssl.SSLError, ssl.CertificateError) as e:
logging.getLogger(__name__).error(e)
return None
@@ -96,7 +96,7 @@ def logout():
logging.getLogger(__name__).info('common.db.logout()')
with CONNECTION() as conn:
conn.common.db.logout()
except (Fault, socket.error, httplib.CannotSendRequest):
except (Fault, socket.error, http.client.CannotSendRequest):
pass
CONNECTION.close()
CONNECTION = None
@@ -136,7 +136,7 @@ def _execute(blocking, *args):
logging.getLogger(__name__).info('%s%s' % (name, args))
with CONNECTION() as conn:
result = getattr(conn, name)(*args)
except (httplib.CannotSendRequest, socket.error), exception:
except (http.client.CannotSendRequest, socket.error) as exception:
raise TrytonServerUnavailable(*exception.args)
if not CONFIG['dev']:
if key and method == 'fields_view_get':
+1 -1
View File
@@ -25,7 +25,7 @@ class SignalEvent(object):
def signal_unconnect(self, key, signal=None):
if signal is None:
signal = self.__connects.keys()
signal = list(self.__connects.keys())
else:
signal = [signal]
for sig in signal:
+1 -1
View File
@@ -190,7 +190,7 @@ def setlang(lang=None, locale_dict=None):
if locale_dict:
conv = locale.localeconv()
for field in locale_dict.keys():
for field in list(locale_dict.keys()):
if field == 'date':
continue
conv[field] = locale_dict[field]