diff --git a/trytond/trytond/model/fields/binary.py b/trytond/trytond/model/fields/binary.py index fa49e4c569..342ba219d7 100644 --- a/trytond/trytond/model/fields/binary.py +++ b/trytond/trytond/model/fields/binary.py @@ -2,6 +2,7 @@ # this repository contains the full copyright notices and license terms. import logging +from collections import defaultdict from sql import Column, Literal, Null from sql.functions import CurrentTimestamp @@ -63,7 +64,6 @@ class Binary(Field): if values is None: values = {} transaction = Transaction() - res = {} converter = self.cast default = None format_ = Transaction().context.get( @@ -71,6 +71,7 @@ class Binary(Field): if format_ == 'size': converter = len default = 0 + result = defaultdict(type(default)) if self.file_id: table = model.__table__() @@ -93,24 +94,22 @@ class Binary(Field): & (Column(table, self.file_id) != ''))) for record_id, file_id in cursor: try: - res[record_id] = store_func(file_id, prefix) + result[record_id] = store_func(file_id, prefix) except (IOError, OSError): logger.exception( "failed to retrieve %r from filestore at %r", file_id, prefix) for i in values: - if i['id'] in res: + if i['id'] in result: continue value = i[name] if value: value = converter(value) else: value = default - res[i['id']] = value - for i in ids: - res.setdefault(i, default) - return res + result[i['id']] = value + return result def queue_for_removal(self, Model, name, ids): pool = Pool() diff --git a/trytond/trytond/model/fields/dict.py b/trytond/trytond/model/fields/dict.py index 34358081c2..1e369233c1 100644 --- a/trytond/trytond/model/fields/dict.py +++ b/trytond/trytond/model/fields/dict.py @@ -1,6 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the toplevel of this # repository contains the full copyright notices and license terms. import json +from collections import defaultdict from functools import partial from sql import Cast, CombiningQuery, Literal, Null, Select, operators @@ -34,7 +35,7 @@ class Dict(Field): self.search_unaccented = True def get(self, ids, model, name, values=None): - dicts = dict((id, None) for id in ids) + result = defaultdict(type(None)) for value in values or []: data = value[name] if data: @@ -44,8 +45,8 @@ class Dict(Field): for key, val in data.items(): if isinstance(val, list): data[key] = tuple(val) - dicts[value['id']] = ImmutableDict(data) - return dicts + result[value['id']] = ImmutableDict(data) + return result def sql_format(self, value): value = super().sql_format(value) diff --git a/trytond/trytond/model/fields/many2many.py b/trytond/trytond/model/fields/many2many.py index fc88a781bc..1d41d2ec37 100644 --- a/trytond/trytond/model/fields/many2many.py +++ b/trytond/trytond/model/fields/many2many.py @@ -128,13 +128,7 @@ class Many2Many(Field): ''' Return target records ordered. ''' - if values is None: - values = {} - res = {} - if not ids: - return res - for i in ids: - res[i] = [] + result = defaultdict(list) Relation = self.get_relation() origin_field = Relation._fields[self.origin] @@ -171,8 +165,9 @@ class Many2Many(Field): origin_id = int(origin_id) else: origin_id = relation[self.origin] - res[origin_id].append(relation[self.target]) - return dict((key, tuple(value)) for key, value in res.items()) + result[origin_id].append(relation[self.target]) + return defaultdict( + tuple, ((key, tuple(value)) for key, value in result.items())) def set(self, Model, name, ids, values, *args): ''' diff --git a/trytond/trytond/model/fields/multiselection.py b/trytond/trytond/model/fields/multiselection.py index 2a999990f4..dc2205b47c 100644 --- a/trytond/trytond/model/fields/multiselection.py +++ b/trytond/trytond/model/fields/multiselection.py @@ -1,6 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the toplevel of this # repository contains the full copyright notices and license terms. import json +from collections import defaultdict from functools import partial from sql import Literal, operators @@ -57,15 +58,15 @@ class MultiSelection(SelectionMixin, Field): self.selection, RPC(instantiate=instantiate, cache=cache)) def get(self, ids, model, name, values=None): - lists = {id: () for id in ids} + result = defaultdict(tuple) for value in values or []: data = value[name] if data: # If stored as JSON conversion is done on backend if isinstance(data, str): data = json.loads(data) - lists[value['id']] = tuple(data) - return lists + result[value['id']] = tuple(data) + return result def sql_format(self, value): value = super().sql_format(value) diff --git a/trytond/trytond/model/fields/one2many.py b/trytond/trytond/model/fields/one2many.py index e5d74201ab..239b113414 100644 --- a/trytond/trytond/model/fields/one2many.py +++ b/trytond/trytond/model/fields/one2many.py @@ -140,9 +140,7 @@ class One2Many(Field): Target = self.get_target() field = Target._fields[self.field] reference_key = field._type == 'reference' - res = {} - for i in ids: - res[i] = [] + result = defaultdict(list) if field.sortable(Target): if reference_key: @@ -175,8 +173,9 @@ class One2Many(Field): origin_id = int(origin_id) else: origin_id = target[self.field] - res[origin_id].append(target['id']) - return dict((key, tuple(value)) for key, value in res.items()) + result[origin_id].append(target['id']) + return defaultdict( + tuple, ((key, tuple(value)) for key, value in result.items())) def set(self, Model, name, ids, values, *args): ''' diff --git a/trytond/trytond/model/fields/one2one.py b/trytond/trytond/model/fields/one2one.py index 7a07e8c022..81a5ab9d3b 100644 --- a/trytond/trytond/model/fields/one2one.py +++ b/trytond/trytond/model/fields/one2one.py @@ -1,6 +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 collections import defaultdict + from trytond.model.fields.field import Field, instantiate_context from trytond.model.fields.many2many import Many2Many from trytond.pool import Pool @@ -21,10 +23,9 @@ class One2One(Many2Many): :param values: a dictionary with the read values :return: a dictionary with ids as key and target id as value ''' - res = super().get(ids, model, name, values=values) - for i, vals in res.items(): - res[i] = vals[0] if vals else None - return res + result = super().get(ids, model, name, values=values) + return defaultdict( + type(None), ((k, v[0] if v else None) for k, v in result.items())) def set(self, Model, name, ids, value, *args): ''' diff --git a/trytond/trytond/model/fields/reference.py b/trytond/trytond/model/fields/reference.py index 20d86d397a..227f6010fb 100644 --- a/trytond/trytond/model/fields/reference.py +++ b/trytond/trytond/model/fields/reference.py @@ -1,6 +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 warnings +from collections import defaultdict from sql import Cast, Expression, Literal, Null, Query from sql.functions import Position, Substring @@ -123,17 +124,17 @@ class Reference(SelectionMixin, Field): pool = Pool() if values is None: values = {} - res = {} + result = defaultdict(type(None)) for i in values: - res[i['id']] = i[name] + result[i['id']] = i[name] ref_to_check = {} for i in ids: - if not (i in res): - res[i] = None + if not (i in result): + result[i] = None continue - if not res[i]: + if not result[i]: continue - ref_model, ref_id = res[i].split(',', 1) + ref_model, ref_id = result[i].split(',', 1) if not ref_model: continue try: @@ -142,7 +143,7 @@ class Reference(SelectionMixin, Field): continue if ref_id < 0: continue - res[i] = ref_model + ',' + str(ref_id) + result[i] = ref_model + ',' + str(ref_id) ref_to_check.setdefault(ref_model, (set(), [])) ref_to_check[ref_model][0].add(ref_id) ref_to_check[ref_model][1].append(i) @@ -153,7 +154,8 @@ class Reference(SelectionMixin, Field): try: pool.get(ref_model) except KeyError: - res.update(dict((i, None) for i in ids)) + for i in ids: + result.pop(i, None) continue Ref = pool.get(ref_model) refs = Ref.search([ @@ -161,9 +163,9 @@ class Reference(SelectionMixin, Field): ], order=[]) refs = list(map(str, refs)) for i in ids: - if res[i] not in refs: - res[i] = None - return res + if result[i] not in refs: + result.pop(i, None) + return result def __set__(self, inst, value): from ..model import Model