Update to Python 3
issue7488 review48431002
This commit is contained in:
1 parent
4885b75e41
commit
ce385af57d
76 files changed
+510
-474
No files matched your search
@@ -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
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
try:
|
||||
|
||||
+2
-2
@@ -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'),
|
||||
]
|
||||
|
||||
|
||||
@@ -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
|
||||
------------
|
||||
|
||||
@@ -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,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 *
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import gtk
|
||||
import gobject
|
||||
import locale
|
||||
from cellrendererinteger import CellRendererInteger
|
||||
from .cellrendererinteger import CellRendererInteger
|
||||
|
||||
|
||||
class CellRendererFloat(CellRendererInteger):
|
||||
|
||||
@@ -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
@@ -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('<', '<').replace('>', '>')
|
||||
|
||||
|
||||
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())
|
||||
|
||||
@@ -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
@@ -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),
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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: ']
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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,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
|
||||
|
||||
|
||||
@@ -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,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
@@ -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
|
||||
|
||||
@@ -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 *
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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,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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 *
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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':
|
||||
|
||||
@@ -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
@@ -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]
|
||||
|
||||
Reference in new issue
Block a user