diff options
| author | xmo-odoo <xmo@odoo.com> | 2017-05-10 09:39:55 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-05-10 09:39:55 +0200 |
| commit | fffaf735f58f1ac57781c095eb552de6d1fcdc47 (patch) | |
| tree | 88ab0ab65430d871862a836524e0ecc890d1674d /odoo/tools | |
| parent | 10eee18a047d35305dc46282e610e88936d81ffc (diff) | |
[FIX] P3: list -> iterable builtins (#16811)
In Python 3:
* various builtins and dict methods were changed to return
view/iterable objects rather than lists
* and the separate Python 2 view/iterable builtins and methods were
removed altogether
This is problematic when using these items as list (which the happens
repeatedly in Odoo), but more viciously when iterating *multiple times*
over them (which also happens, which I've messed up multiple times while
writing this, and which is a pain to debug even when you've just created
the issue).
Convert all code using these to semantics-matching cross-version
helper functions to get the LCD behaviour between P2 and P3, and
forbid the builtins via lint.
issue #8530
Diffstat (limited to 'odoo/tools')
| -rw-r--r-- | odoo/tools/amount_to_text_en.py | 2 | ||||
| -rw-r--r-- | odoo/tools/appdirs.py | 2 | ||||
| -rw-r--r-- | odoo/tools/cache.py | 10 | ||||
| -rw-r--r-- | odoo/tools/config.py | 17 | ||||
| -rw-r--r-- | odoo/tools/convert.py | 10 | ||||
| -rw-r--r-- | odoo/tools/float_utils.py | 6 | ||||
| -rw-r--r-- | odoo/tools/func.py | 2 | ||||
| -rwxr-xr-x | odoo/tools/graph.py | 19 | ||||
| -rw-r--r-- | odoo/tools/lru.py | 7 | ||||
| -rw-r--r-- | odoo/tools/mail.py | 7 | ||||
| -rw-r--r-- | odoo/tools/mimetypes.py | 4 | ||||
| -rw-r--r-- | odoo/tools/misc.py | 26 | ||||
| -rw-r--r-- | odoo/tools/osutil.py | 2 | ||||
| -rw-r--r-- | odoo/tools/parse_version.py | 4 | ||||
| -rw-r--r-- | odoo/tools/pycompat.py | 11 | ||||
| -rw-r--r-- | odoo/tools/safe_eval.py | 3 | ||||
| -rw-r--r-- | odoo/tools/test_reports.py | 2 | ||||
| -rw-r--r-- | odoo/tools/translate.py | 10 | ||||
| -rw-r--r-- | odoo/tools/yaml_import.py | 36 | ||||
| -rw-r--r-- | odoo/tools/yaml_tag.py | 5 |
20 files changed, 104 insertions, 81 deletions
diff --git a/odoo/tools/amount_to_text_en.py b/odoo/tools/amount_to_text_en.py index 6a8e7020b4a..b1854b1c4d6 100644 --- a/odoo/tools/amount_to_text_en.py +++ b/odoo/tools/amount_to_text_en.py @@ -71,7 +71,7 @@ def amount_to_text(number, currency): cents_number = int(list[1]) cents_name = (cents_number > 1) and 'Cents' or 'Cent' - return ' '.join(filter(None, [start_word, units_name, (start_word or units_name) and (end_word or cents_name) and 'and', end_word, cents_name])) + return ' '.join(w for w in [start_word, units_name, (start_word or units_name) and (end_word or cents_name) and 'and', end_word, cents_name] if w) #------------------------------------------------------------- diff --git a/odoo/tools/appdirs.py b/odoo/tools/appdirs.py index f98fa1f8ae3..8617dabfa4f 100644 --- a/odoo/tools/appdirs.py +++ b/odoo/tools/appdirs.py @@ -15,7 +15,7 @@ from __future__ import print_function # - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html __version_info__ = (1, 3, 0) -__version__ = '.'.join(map(str, __version_info__)) +__version__ = '.'.join(str(v) for v in __version_info__) import sys diff --git a/odoo/tools/cache.py b/odoo/tools/cache.py index 48dc42ba04c..acc01895a48 100644 --- a/odoo/tools/cache.py +++ b/odoo/tools/cache.py @@ -8,6 +8,8 @@ from decorator import decorator from inspect import formatargspec, getargspec import logging +from odoo.tools import pycompat + unsafe_eval = eval _logger = logging.getLogger(__name__) @@ -112,7 +114,7 @@ class ormcache_context(ormcache): spec = getargspec(self.method) args = formatargspec(*spec)[1:-1] cont_expr = "(context or {})" if 'context' in spec.args else "self._context" - keys_expr = "tuple(map(%s.get, %r))" % (cont_expr, self.keys) + keys_expr = "tuple(%s.get(k) for k in %r)" % (cont_expr, self.keys) if self.args: code = "lambda %s: (%s, %s)" % (args, ", ".join(self.args), keys_expr) else: @@ -200,10 +202,10 @@ def log_ormcache_stats(sig=None, frame=None): me = threading.currentThread() me_dbname = me.dbname entries = defaultdict(int) - for dbname, reg in Registry.registries.iteritems(): - for key in reg.cache.iterkeys(): + for dbname, reg in pycompat.items(Registry.registries): + for key in reg.cache: entries[(dbname,) + key[:2]] += 1 - for key, count in sorted(entries.items()): + for key, count in sorted(pycompat.items(entries)): dbname, model_name, method = key me.dbname = dbname stat = STAT[key] diff --git a/odoo/tools/config.py b/odoo/tools/config.py index 3a227fb5142..0f51fbcb269 100644 --- a/odoo/tools/config.py +++ b/odoo/tools/config.py @@ -13,7 +13,8 @@ import odoo.conf import odoo.loglevels as loglevels import logging import odoo.release as release -from . import appdirs +from . import appdirs, pycompat + class MyOption (optparse.Option, object): """ optparse Option with two additional attributes. @@ -55,7 +56,7 @@ def _deduplicate_loggers(loggers): # there are no duplicates within the output sequence return ( '{}:{}'.format(logger, level) - for logger, level in dict(it.split(':') for it in loggers).iteritems() + for logger, level in pycompat.items(dict(it.split(':') for it in loggers)) ) @@ -453,10 +454,10 @@ class configmanager(object): self.options['demo'] = (dict(self.options['init']) if not self.options['without_demo'] else {}) self.options['update'] = opt.update and dict.fromkeys(opt.update.split(','), 1) or {} - self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all'] + self.options['translate_modules'] = opt.translate_modules and [m.strip() for m in opt.translate_modules.split(',')] or ['all'] self.options['translate_modules'].sort() - dev_split = opt.dev_mode and map(str.strip, opt.dev_mode.split(',')) or [] + dev_split = opt.dev_mode and [s.strip() for s in opt.dev_mode.split(',')] or [] self.options['dev_mode'] = 'all' in dev_split and dev_split + ['pdb', 'reload', 'qweb', 'werkzeug', 'xml'] or dev_split if opt.pg_path: @@ -527,9 +528,9 @@ class configmanager(object): def save(self): p = ConfigParser.ConfigParser() - loglevelnames = dict(zip(self._LOGLEVELS.values(), self._LOGLEVELS.keys())) + loglevelnames = dict(pycompat.izip(pycompat.values(self._LOGLEVELS), pycompat.keys(self._LOGLEVELS))) p.add_section('options') - for opt in sorted(self.options.keys()): + for opt in sorted(pycompat.keys(self.options)): if opt in ('version', 'language', 'translate_out', 'translate_in', 'overwrite_existing_translations', 'init', 'update'): continue if opt in self.blacklist_for_save: @@ -541,9 +542,9 @@ class configmanager(object): else: p.set('options', opt, self.options[opt]) - for sec in sorted(self.misc.keys()): + for sec in sorted(pycompat.keys(self.misc)): p.add_section(sec) - for opt in sorted(self.misc[sec].keys()): + for opt in sorted(pycompat.keys(self.misc[sec])): p.set(sec,opt,self.misc[sec][opt]) # try to create the directories and write the file diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py index 815ee9a64f1..7e8e9f6e3ce 100644 --- a/odoo/tools/convert.py +++ b/odoo/tools/convert.py @@ -98,7 +98,7 @@ def _eval_xml(self, node, env): q = safe_eval(f_search, idref2) ids = env[f_model].search(q).ids if f_use != 'id': - ids = map(lambda x: x[f_use], env[f_model].browse(ids).read([f_use])) + ids = [x[f_use] for x in env[f_model].browse(ids).read([f_use])] _fields = env[f_model]._fields if (f_name in _fields) and _fields[f_name].type == 'many2many': return ids @@ -659,7 +659,7 @@ form: module.record_id""" % (xml_id,) _fields = self.env[rec_model]._fields # if the current field is many2many if (f_name in _fields) and _fields[f_name].type == 'many2many': - f_val = [(6, 0, map(lambda x: x[f_use], s))] + f_val = [(6, 0, [x[f_use] for x in s])] elif len(s): # otherwise (we are probably in a many2one field), # take the first element of the search @@ -707,7 +707,7 @@ form: module.record_id""" % (xml_id,) 'model': 'ir.ui.view', } for att in ['forcecreate', 'context']: - if att in el.keys(): + if att in el.attrib: record_attrs[att] = el.attrib.pop(att) Field = builder.E.field @@ -733,7 +733,7 @@ form: module.record_id""" % (xml_id,) record.append(Field(name='customize_show', eval=el.get('customize_show'))) groups = el.attrib.pop('groups', None) if groups: - grp_lst = map(lambda x: "ref('%s')" % x, groups.split(',')) + grp_lst = [("ref('%s')" % x) for x in groups.split(',')] record.append(Field(name="groups_id", eval="[(6, 0, ["+', '.join(grp_lst)+"])]")) if el.attrib.pop('page', None) == 'True': record.append(Field(name="page", eval="True")) @@ -854,7 +854,7 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init', if not (line and any(line)): continue try: - datas.append(map(ustr, line)) + datas.append([ustr(v) for v in line]) except Exception: _logger.error("Cannot import the line: %s", line) diff --git a/odoo/tools/float_utils.py b/odoo/tools/float_utils.py index 8c71d7a29b2..fa150a1d902 100644 --- a/odoo/tools/float_utils.py +++ b/odoo/tools/float_utils.py @@ -217,10 +217,10 @@ if __name__ == "__main__": fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555] expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556'] precisions = [2, 2, 2, 2, 2, 2, 3, 4] - for magnitude in pycompat.range(7): - for frac, exp, prec in zip(fractions, expecteds, precisions): + for magnitude in range(7): + for frac, exp, prec in pycompat.izip(fractions, expecteds, precisions): for sign in [-1,1]: - for x in pycompat.range(0, 10000, 97): + for x in range(0, 10000, 97): n = x * 10**magnitude f = sign * (n + frac) f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp diff --git a/odoo/tools/func.py b/odoo/tools/func.py index 8f49864eda2..2e204206f04 100644 --- a/odoo/tools/func.py +++ b/odoo/tools/func.py @@ -33,7 +33,7 @@ class lazy_property(object): """ Reset all lazy properties on the instance `obj`. """ cls = type(obj) obj_dict = vars(obj) - for name in obj_dict.keys(): + for name in list(obj_dict): if isinstance(getattr(cls, name, None), lazy_property): obj_dict.pop(name) diff --git a/odoo/tools/graph.py b/odoo/tools/graph.py index 82fc0e0978a..5e3edabf05a 100755 --- a/odoo/tools/graph.py +++ b/odoo/tools/graph.py @@ -5,6 +5,9 @@ import operator import math +from odoo.tools import pycompat + + class graph(object): def __init__(self, nodes, transitions, no_ancester=None): """Initialize graph's object @@ -256,7 +259,7 @@ class graph(object): """The ranks are normalized by setting the least rank to zero. """ - least_rank = min(map(lambda x: x['x'], self.result.values())) + least_rank = min(x['x'] for x in pycompat.values(self.result.values)) if least_rank!=0: for node in self.result: @@ -380,7 +383,7 @@ class graph(object): """Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component """ mid_pos = 0.0 - max_level = max(map(lambda x: len(x), self.levels.values())) + max_level = max(len(x) for x in pycompat.values(self.levels.values)) for level in self.levels: if level: @@ -471,7 +474,7 @@ class graph(object): """ if self.Is_Cyclic: - max_level = max(map(lambda x: len(x), self.levels.values())) + max_level = max(len(x) for x in pycompat.values(self.levels.values)) if max_level%2: self.result[self.start]['y'] = (max_level+1)/2 + self.max_order + (self.max_order and 1) @@ -483,7 +486,7 @@ class graph(object): else: self.result[self.start]['y'] = 0 self.tree_order(self.start, 0) - min_order = math.fabs(min(map(lambda x: x['y'], self.result.values()))) + min_order = math.fabs(min(x['y'] for x in pycompat.values(self.result.values))) index = self.start_nodes.index(self.start) same = False @@ -537,7 +540,7 @@ class graph(object): self.result[start]['y'] = base + factor factor += 1 - self.max_order = max(map(lambda x: x['y'], self.result.values())) + self.max_order = max(x['y'] for x in pycompat.values(self.result.values)) def find_starts(self): """Finds other start nodes of the graph in the case when graph is disconneted @@ -626,7 +629,7 @@ class graph(object): self.make_chain() self.preprocess_order() self.order = {} - max_rank = max(map(lambda x: x, self.levels.keys())) + max_rank = max(x for x in self.levels) for i in range(max_rank+1): self.order[i] = 0 @@ -657,7 +660,7 @@ class graph(object): for node in self.no_ancester: for sec_node in self.transitions.get(node, []): - if sec_node in self.partial_order.keys(): + if sec_node in pycompat.keys(self.partial_order): self.transitions[self.start_nodes[0]].append(node) break @@ -743,7 +746,7 @@ if __name__=='__main__': for node in nodes: node_res[node] = result[node] - for name,node in node_res.items(): + for name,node in pycompat.items(node_res): draw.arc( (int(node['y']-radius), int(node['x']-radius),int(node['y']+radius), int(node['x']+radius) ), 0, 360, (128,128,128)) draw.text( (int(node['y']), int(node['x'])), str(name), (128,128,128)) diff --git a/odoo/tools/lru.py b/odoo/tools/lru.py index 7c485a039d3..a9e4a8b8f18 100644 --- a/odoo/tools/lru.py +++ b/odoo/tools/lru.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # taken from http://code.activestate.com/recipes/252524-length-limited-o1-lru-cache-implementation/ import threading + +from odoo.tools import pycompat from .func import synchronized __all__ = ['LRU'] @@ -92,6 +94,7 @@ class LRU(object): def __len__(self): return len(self.d) + # FIXME: should this have a P2 and a P3 version or something? @synchronized() def iteritems(self): cur = self.first @@ -106,12 +109,12 @@ class LRU(object): @synchronized() def itervalues(self): - for i,j in self.iteritems(): + for i,j in pycompat.items(self): yield j @synchronized() def keys(self): - return self.d.keys() + return list(pycompat.keys(self.d)) @synchronized() def pop(self,key): diff --git a/odoo/tools/mail.py b/odoo/tools/mail.py index 490006082d5..9689512df00 100644 --- a/odoo/tools/mail.py +++ b/odoo/tools/mail.py @@ -16,6 +16,7 @@ from lxml import etree import odoo from odoo.loglevels import ustr +from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -84,7 +85,7 @@ class _Cleaner(clean.Cleaner): new_node.text = text new_node.tail = tail if attrs: - for key, val in attrs.iteritems(): + for key, val in pycompat.items(attrs): new_node.set(key, val) return new_node @@ -153,7 +154,7 @@ class _Cleaner(clean.Cleaner): if style[0].lower() in self._style_whitelist: valid_styles[style[0].lower()] = style[1] if valid_styles: - el.attrib['style'] = '; '.join('%s: %s' % (key, val) for (key, val) in valid_styles.iteritems()) + el.attrib['style'] = '; '.join('%s: %s' % (key, val) for (key, val) in pycompat.items(valid_styles)) else: del el.attrib['style'] @@ -530,4 +531,4 @@ def decode_smtp_header(smtp_header): # was mail_thread.decode_header() def decode_message_header(message, header, separator=' '): - return separator.join(map(decode_smtp_header, filter(None, message.get_all(header, [])))) + return separator.join(decode_smtp_header(h) for h in message.get_all(header, []) if h) diff --git a/odoo/tools/mimetypes.py b/odoo/tools/mimetypes.py index 370c4b2e85b..3abdc22963d 100644 --- a/odoo/tools/mimetypes.py +++ b/odoo/tools/mimetypes.py @@ -10,6 +10,8 @@ import logging import re import zipfile +from odoo.tools import pycompat + __all__ = ['guess_mimetype'] _logger = logging.getLogger(__name__) @@ -33,7 +35,7 @@ def _check_ooxml(data): # then there is a directory whose name denotes the type of the file: # word, pt (powerpoint) or xl (excel) - for dirname, mime in _ooxml_dirs.iteritems(): + for dirname, mime in pycompat.items(_ooxml_dirs): if any(entry.startswith(dirname) for entry in filenames): return mime diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 492be9951e4..81c27105ff1 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -22,7 +22,7 @@ import time import werkzeug.utils import zipfile from collections import defaultdict, Iterable, Mapping, MutableSet, OrderedDict -from itertools import islice, izip, groupby, repeat +from itertools import islice, groupby, repeat from lxml import etree from .which import which @@ -282,7 +282,7 @@ def flatten(list): r = [] for e in list: if isiterable(e): - map(r.append, flatten(e)) + r.extend(flatten(e)) else: r.append(e) return r @@ -304,7 +304,7 @@ def reverse_enumerate(l): File "<stdin>", line 1, in <module> StopIteration """ - return izip(pycompat.range(len(l)-1, -1, -1), reversed(l)) + return pycompat.izip(range(len(l)-1, -1, -1), reversed(l)) def partition(pred, elems): """ Return a pair equivalent to: @@ -337,10 +337,12 @@ def topological_sort(elems): visited.add(n) if n in elems: # first visit all dependencies of n, then append n to result - map(visit, elems[n]) + for it in elems[n]: + visit(it) result.append(n) - map(visit, elems) + for el in elems: + visit(el) return result @@ -458,7 +460,7 @@ def logged(f): vector = ['Call -> function: %r' % f] for i, arg in enumerate(args): vector.append(' arg %02d: %s' % (i, pformat(arg))) - for key, value in kwargs.items(): + for key, value in pycompat.items(kwargs): vector.append(' kwarg %10s: %s' % (key, pformat(value))) timeb4 = time.time() @@ -523,9 +525,9 @@ def detect_ip_addr(): # try 32 bit kernel: if ip_addr is None: - ifaces = filter(None, [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]) + ifaces = [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)] - for ifname in [iface for iface in ifaces if iface != 'lo']: + for ifname in [iface for iface in ifaces if iface if iface != 'lo']: ip_addr = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, pack('256s', ifname[:15]))[20:24]) break @@ -909,7 +911,7 @@ def dumpstacks(sig=None, frame=None): 'uid': getattr(th, 'uid', 'n/a'), 'dbname': getattr(th, 'dbname', 'n/a')} for th in threading.enumerate()} - for threadId, stack in sys._current_frames().items(): + for threadId, stack in pycompat.items(sys._current_frames()): thread_info = threads_info.get(threadId, {}) code.append("\n# Thread: %s (id:%s) (db:%s) (uid:%s)" % (thread_info.get('name', 'n/a'), @@ -939,7 +941,7 @@ def freehash(arg): if isinstance(arg, Mapping): return hash(frozendict(arg)) elif isinstance(arg, Iterable): - return hash(frozenset(map(freehash, arg))) + return hash(frozenset(freehash(item) for item in arg)) else: return id(arg) @@ -960,7 +962,7 @@ class frozendict(dict): def update(self, *args, **kwargs): raise NotImplementedError("'update' not supported on frozendict") def __hash__(self): - return hash(frozenset((key, freehash(val)) for key, val in self.iteritems())) + return hash(frozenset((key, freehash(val)) for key, val in pycompat.items(self))) class Collector(Mapping): """ A mapping from keys to lists. This is essentially a space optimization @@ -1122,7 +1124,7 @@ def format_date(env, value, lang_code=False, date_format=False): def _consteq(str1, str2): """ Constant-time string comparison. Suitable to compare bytestrings of fixed, known length only, because length difference is optimized. """ - return len(str1) == len(str2) and sum(ord(x)^ord(y) for x, y in zip(str1, str2)) == 0 + return len(str1) == len(str2) and sum(ord(x)^ord(y) for x, y in pycompat.izip(str1, str2)) == 0 consteq = getattr(passlib.utils, 'consteq', _consteq) diff --git a/odoo/tools/osutil.py b/odoo/tools/osutil.py index af12c6558b2..2bb180a1d17 100644 --- a/odoo/tools/osutil.py +++ b/odoo/tools/osutil.py @@ -39,7 +39,7 @@ def walksymlinks(top, topdown=True, onerror=None): if topdown: yield dirpath, dirnames, filenames - symlinks = filter(lambda dirname: os.path.islink(os.path.join(dirpath, dirname)), dirnames) + symlinks = (dirname for dirname in dirnames if os.path.islink(os.path.join(dirpath, dirname))) for s in symlinks: for x in walksymlinks(os.path.join(dirpath, s), topdown, onerror): yield x diff --git a/odoo/tools/parse_version.py b/odoo/tools/parse_version.py index 348fb3664a6..e9ff071c0b6 100644 --- a/odoo/tools/parse_version.py +++ b/odoo/tools/parse_version.py @@ -7,6 +7,8 @@ from __future__ import print_function import re +from odoo.tools import pycompat + component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE) replace = {'pre':'c', 'preview':'c','-':'final-','_':'final-','rc':'c','dev':'@','saas':'','~':''}.get @@ -72,7 +74,7 @@ if __name__ == '__main__': if verbose: print(v, pv) - for a, b in zip(pvs, pvs[1:]): + for a, b in pycompat.izip(pvs, pvs[1:]): assert a < b, '%s < %s == %s' % (a, b, a < b) chk(('0', '4.2', '4.2.3.4', '5.0.0-alpha', '5.0.0-rc1', '5.0.0-rc1.1', '5.0.0_rc2', '5.0.0_rc3', '5.0.0'), False) diff --git a/odoo/tools/pycompat.py b/odoo/tools/pycompat.py index 50b6f492a59..3fbb847a9fa 100644 --- a/odoo/tools/pycompat.py +++ b/odoo/tools/pycompat.py @@ -6,10 +6,12 @@ import sys PY2 = sys.version_info[0] == 2 if PY2: - # pylint: disable=long-builtin,xrange-builtin + # pylint: disable=long-builtin,dict-iter-method integer_types = (int, long) - range = xrange + keys = lambda d: iter(d.iterkeys()) + values = lambda d: iter(d.itervalues()) + items = lambda d: iter(d.iteritems()) # noinspection PyUnresolvedReferences from itertools import imap, izip, ifilter @@ -19,9 +21,12 @@ if PY2: del cls.__next__ return cls else: + # pylint: disable=bad-functions integer_types = (int,) - range = range + keys = lambda d: iter(d.keys()) + values = lambda d: iter(d.values()) + items = lambda d: iter(d.items()) imap = map izip = zip diff --git a/odoo/tools/safe_eval.py b/odoo/tools/safe_eval.py index ebe97619e35..1897486eb82 100644 --- a/odoo/tools/safe_eval.py +++ b/odoo/tools/safe_eval.py @@ -23,7 +23,6 @@ from types import CodeType import logging import werkzeug -from odoo.tools import pycompat from .misc import ustr import odoo @@ -251,7 +250,7 @@ _BUILTINS = { 'divmod': divmod, 'isinstance': isinstance, 'range': range, - 'xrange': pycompat.range, + 'xrange': range, 'zip': zip, 'Exception': Exception, } diff --git a/odoo/tools/test_reports.py b/odoo/tools/test_reports.py index 17065848129..cad44431c1d 100644 --- a/odoo/tools/test_reports.py +++ b/odoo/tools/test_reports.py @@ -174,7 +174,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None, view_data.update(wiz_data) _logger.debug("View data is: %r", view_data) - for fk, field in view_res.get('fields',{}).items(): + for fk, field in pycompat.items(view_res.get('fields',{})): # Default fields returns list of int, while at create() # we need to send a [(6,0,[int,..])] if field['type'] in ('one2many', 'many2many') \ diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py index dcdb95d0955..b2996af6ae3 100644 --- a/odoo/tools/translate.py +++ b/odoo/tools/translate.py @@ -255,7 +255,7 @@ def translate_xml_node(node, callback, method, parser=None): append_content(result, translate_content(todo) if todo_has_text else todo) # translate the required attributes - for name, value in result.items(): + for name, value in pycompat.items(result.attrib): if name in TRANSLATED_ATTRS: result.set(name, translate_text(value) or value) @@ -660,7 +660,7 @@ def trans_export(lang, modules, buffer, format, cr): row.setdefault('tnrs', []).append((type, name, res_id)) row.setdefault('comments', set()).update(comments) - for src, row in sorted(grouped_rows.items()): + for src, row in sorted(pycompat.items(grouped_rows)): if not lang: # translation template, so no translation value row['translation'] = '' @@ -674,7 +674,7 @@ def trans_export(lang, modules, buffer, format, cr): module = row[0] rows_by_module.setdefault(module, []).append(row) tmpdir = tempfile.mkdtemp() - for mod, modrows in rows_by_module.items(): + for mod, modrows in pycompat.items(rows_by_module): tmpmoddir = join(tmpdir, mod, 'i18n') os.makedirs(tmpmoddir) pofilename = (lang if lang else mod) + ".po" + ('t' if not lang else '') @@ -1073,7 +1073,7 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, dic = dict.fromkeys(('type', 'name', 'res_id', 'src', 'value', 'comments', 'imd_model', 'imd_name', 'module')) dic['lang'] = lang - dic.update(zip(fields, row)) + dic.update(pycompat.izip(fields, row)) # discard the target from the POT targets. src = dic['src'] @@ -1111,7 +1111,7 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, # Then process the entries implied by the POT file (which is more # correct w.r.t. the targets) if some of them remain. pot_rows = [] - for src, target in pot_targets.iteritems(): + for src, target in pycompat.items(pot_targets): if target.value: for type, name, res_id in target.targets: pot_rows.append((type, name, res_id, src, target.value, target.comments)) diff --git a/odoo/tools/yaml_import.py b/odoo/tools/yaml_import.py index 36c6c248249..4cb2e7ea184 100644 --- a/odoo/tools/yaml_import.py +++ b/odoo/tools/yaml_import.py @@ -13,7 +13,7 @@ import yaml import odoo from . import assertion_report -from . import yaml_tag +from . import yaml_tag, pycompat from .config import config from .misc import file_open, DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT from odoo import SUPERUSER_ID @@ -36,8 +36,8 @@ class YamlImportAbortion(Exception): def _is_yaml_mapping(node, tag_constructor): value = isinstance(node, dict) \ - and len(node.keys()) == 1 \ - and isinstance(node.keys()[0], tag_constructor) + and len(node) == 1 \ + and isinstance(next(iter(node)), tag_constructor) return value def is_comment(node): @@ -202,7 +202,7 @@ class YamlInterpreter(object): def process_assert(self, node): if isinstance(node, dict): - assertion, expressions = node.items()[0] + assertion, expressions = next(pycompat.items(node)) else: assertion, expressions = node, [] @@ -275,7 +275,7 @@ class YamlInterpreter(object): return record_dict def process_record(self, node): - record, fields = node.items()[0] + record, fields = next(pycompat.items(node)) model = self.env[record.model] view_id = record.view if view_id and (view_id is not True) and isinstance(view_id, basestring): @@ -377,7 +377,7 @@ class YamlInterpreter(object): def process_vals(fg, vals): """ sanitize the given field values """ result = {} - for field_name, field_value in vals.iteritems(): + for field_name, field_value in pycompat.items(vals): if field_name not in fg: continue if fg[field_name]['type'] == 'many2one' and isinstance(field_value, (tuple, list)): @@ -391,14 +391,14 @@ class YamlInterpreter(object): elif isinstance(command, dict): return process_vals(sub_fg, command) return command - field_value = map(process, field_value or []) + field_value = [process(v) for v in (field_value or [])] result[field_name] = field_value return result def post_process(fg, elems, vals): """ filter out readonly fields from vals """ result = {} - for field_name, field_value in vals.iteritems(): + for field_name, field_value in pycompat.items(vals): if is_readonly(elems[field_name]): continue if fg[field_name]['type'] in ('one2many', 'many2many'): @@ -412,7 +412,7 @@ class YamlInterpreter(object): elif isinstance(command, dict): return (0, 0, post_process(sub_fg, sub_elems, command)) return command - field_value = map(process, field_value or []) + field_value = [process(v) for v in (field_value or [])] result[field_name] = field_value return result @@ -444,7 +444,7 @@ class YamlInterpreter(object): record_dict.update(process_vals(fg, result.get('value', {}))) # fill in fields, and execute onchange where necessary - for field_name, field_elem in elems.iteritems(): + for field_name, field_elem in pycompat.items(elems): assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % (field_name, model._name) if is_readonly(field_elem): # skip readonly fields @@ -474,7 +474,7 @@ class YamlInterpreter(object): result = recs.onchange(dict(record_dict, **parent_values), field_name, onchange_spec) record_dict.update(process_vals(fg, { key: val - for key, val in result.get('value', {}).iteritems() + for key, val in pycompat.items(result.get('value', {})) if key not in fields # do not shadow values explicitly set in yaml })) @@ -483,7 +483,7 @@ class YamlInterpreter(object): else: record_dict = {} - for field_name, expression in fields.iteritems(): + for field_name, expression in pycompat.items(fields): if record_dict.get(field_name): continue field_value = self._eval_field(model, field_name, expression, parent=record_dict, default=False, context=context) @@ -494,7 +494,7 @@ class YamlInterpreter(object): # should not be sent to create. This bug appears with not stored function fields in the new API. return { key: val - for key, val in record_dict.iteritems() + for key, val in pycompat.items(record_dict) for field in [model._fields[key].base_field] if field.store or field.inverse } @@ -580,7 +580,7 @@ class YamlInterpreter(object): self.sudo_env = self.env(user=SUPERUSER_ID) def process_python(self, node): - python, statements = node.items()[0] + python, statements = next(pycompat.items(node)) assert python.model or python.id, "!python node must have attribute `model` or `id`" if python.id is None: record = self.env[python.model] @@ -640,7 +640,7 @@ class YamlInterpreter(object): return args def process_function(self, node): - function, params = node.items()[0] + function, params = next(pycompat.items(node)) if self.isnoupdate(function) and self.mode != 'init': return model = self.env[function.model] @@ -770,9 +770,9 @@ class YamlInterpreter(object): def process_ir_set(self, node): if not self.mode == 'init': return False - _, fields = node.items()[0] + _, fields = next(pycompat.items(node)) res = {} - for fieldname, expression in fields.items(): + for fieldname, expression in pycompat.items(fields): if is_eval(expression): value = safe_eval(expression.expression, self.eval_context) else: @@ -878,7 +878,7 @@ class YamlInterpreter(object): elif not is_preceded_by_comment: if isinstance(node, dict): msg = "Creating %s\n with %s" - args = node.items()[0] + args = next(pycompat.items(node)) self._log(msg, *args) else: self._log(node) diff --git a/odoo/tools/yaml_tag.py b/odoo/tools/yaml_tag.py index f921c598f30..2b7141b6693 100644 --- a/odoo/tools/yaml_tag.py +++ b/odoo/tools/yaml_tag.py @@ -1,6 +1,9 @@ import yaml import logging +from . import pycompat + + class YamlTag(object): """ Superclass for constructors of custom tags defined in yaml file. @@ -13,7 +16,7 @@ class YamlTag(object): def __getattr__(self, attr): return None def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, sorted(self.__dict__.items())) + return "<%s %s>" % (self.__class__.__name__, sorted(pycompat.items(self.__dict__))) class Assert(YamlTag): def __init__(self, model, id=None, severity=logging.WARNING, string="NONAME", **kwargs): |
