From b379e32745b4dc06fb1be56a34652cd4513573da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 27 Nov 2014 22:20:43 +0100 Subject: [PATCH] Add translated descriptor for Dict field issue4343 review11641002 --- CHANGELOG | 1 + doc/ref/models/fields.rst | 8 ++++++ trytond/model/fields/dict.py | 49 ++++++++++++++++++++++++++++++++++++ trytond/tests/__init__.py | 1 + trytond/tests/test.py | 13 +++++++--- trytond/tests/test_fields.py | 33 ++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a71c0da70e..c06d2aab6c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add translated descriptor for Dict field * Clean private context keyword in RPC * Add cache section in configuration * Use dualmethod on ModelStorage.save diff --git a/doc/ref/models/fields.rst b/doc/ref/models/fields.rst index 82b4b1e292..55a23b570c 100644 --- a/doc/ref/models/fields.rst +++ b/doc/ref/models/fields.rst @@ -770,3 +770,11 @@ A dictionary field with predefined keys. The name of the :class:`DictSchemaMixin` model that stores the definition of keys. + +Instance methods: + +.. method:: Dict.translated([name[, type_]]) + + Returns a descriptor for the translated `values` or `keys` of the field + following `type_`. The descriptor must be used on the same class as the + field. Default `type_` is `values`. diff --git a/trytond/model/fields/dict.py b/trytond/model/fields/dict.py index ef63d52e14..be65ba2ec2 100644 --- a/trytond/model/fields/dict.py +++ b/trytond/model/fields/dict.py @@ -8,6 +8,8 @@ from sql import Query, Expression from .field import Field, SQLType from ...protocols.jsonrpc import JSONDecoder, JSONEncoder +from ...pool import Pool +from ...tools import grouped_slice class Dict(Field): @@ -42,3 +44,50 @@ class Dict(Field): def sql_type(self): return SQLType('TEXT', 'TEXT') + + def translated(self, name=None, type_='values'): + "Return a descriptor for the translated value of the field" + if name is None: + name = self.name + if name is None: + raise ValueError('Missing name argument') + return TranslatedDict(name, type_) + + +class TranslatedDict(object): + 'A descriptor for translated values of Dict field' + + def __init__(self, name, type_): + assert type_ in ['keys', 'values'] + self.name = name + self.type_ = type_ + + def __get__(self, inst, cls): + if inst is None: + return self + pool = Pool() + schema_model = getattr(cls, self.name).schema_model + SchemaModel = pool.get(schema_model) + + value = getattr(inst, self.name) + if not value: + return value + + domain = [] + if self.type_ == 'values': + domain = [('type_', '=', 'selection')] + + records = [] + for key_names in grouped_slice(value.keys()): + records += SchemaModel.search([ + ('name', 'in', key_names), + ] + domain) + keys = SchemaModel.get_keys(records) + + if self.type_ == 'keys': + return {k['name']: k['string'] for k in keys} + + elif self.type_ == 'values': + trans = {k['name']: dict(k['selection']) for k in keys} + return {k: v if k not in trans else trans[k].get(v, v) + for k, v in value.iteritems()} diff --git a/trytond/tests/__init__.py b/trytond/tests/__init__.py index 8c3d272d1f..c16313c03f 100644 --- a/trytond/tests/__init__.py +++ b/trytond/tests/__init__.py @@ -89,6 +89,7 @@ def register(): Property, Selection, SelectionRequired, + DictSchema, Dict, DictDefault, DictRequired, diff --git a/trytond/tests/test.py b/trytond/tests/test.py index 5f812f24c7..969d8c2e29 100644 --- a/trytond/tests/test.py +++ b/trytond/tests/test.py @@ -3,7 +3,7 @@ import datetime from decimal import Decimal -from trytond.model import ModelSQL, fields +from trytond.model import ModelSQL, DictSchemaMixin, fields from trytond.pyson import Eval __all__ = [ @@ -32,7 +32,7 @@ __all__ = [ 'Reference', 'ReferenceTarget', 'ReferenceRequired', 'Property', 'Selection', 'SelectionRequired', - 'Dict', 'DictDefault', 'DictRequired', + 'DictSchema', 'Dict', 'DictDefault', 'DictRequired', 'Binary', 'BinaryDefault', 'BinaryRequired', 'Many2OneDomainValidation', 'Many2OneTarget', ] @@ -629,10 +629,17 @@ class SelectionRequired(ModelSQL): 'Selection', required=True) +class DictSchema(DictSchemaMixin, ModelSQL): + 'Dict Schema' + __name__ = 'test.dict.schema' + + class Dict(ModelSQL): 'Dict' __name__ = 'test.dict' - dico = fields.Dict(None, 'Test Dict') + dico = fields.Dict('test.dict.schema', 'Test Dict') + dico_string = dico.translated('dico') + dico_string_keys = dico.translated('dico', 'keys') class DictDefault(ModelSQL): diff --git a/trytond/tests/test_fields.py b/trytond/tests/test_fields.py index 2c436f6e2e..b04a4035b3 100644 --- a/trytond/tests/test_fields.py +++ b/trytond/tests/test_fields.py @@ -102,6 +102,7 @@ class FieldsTestCase(unittest.TestCase): self.selection_required = POOL.get('test.selection_required') self.dict_ = POOL.get('test.dict') + self.dict_schema = POOL.get('test.dict.schema') self.dict_default = POOL.get('test.dict_default') self.dict_required = POOL.get('test.dict_required') @@ -3108,6 +3109,23 @@ class FieldsTestCase(unittest.TestCase): 'Test Dict' with Transaction().start(DB_NAME, USER, context=CONTEXT) as transaction: + + self.dict_schema.create([{ + 'name': 'a', + 'string': 'A', + 'type_': 'integer', + }, { + 'name': 'b', + 'string': 'B', + 'type_': 'integer', + }, { + 'name': 'type', + 'string': 'Type', + 'type_': 'selection', + 'selection': ('arabic: Arabic\n' + 'hexa: Hexadecimal'), + }]) + dict1, = self.dict_.create([{ 'dico': {'a': 1, 'b': 2}, }]) @@ -3116,6 +3134,21 @@ class FieldsTestCase(unittest.TestCase): self.dict_.write([dict1], {'dico': {'z': 26}}) self.assert_(dict1.dico == {'z': 26}) + dict1.dico = { + 'a': 1, + 'type': 'arabic', + } + dict1.save() + self.assertEqual(dict1.dico, {'a': 1, 'type': 'arabic'}) + self.assertEqual(dict1.dico_string, { + 'a': 1, + 'type': 'Arabic', + }) + self.assertEqual(dict1.dico_string_keys, { + 'a': 'A', + 'type': 'Type', + }) + dict2, = self.dict_.create([{}]) self.assert_(dict2.dico is None)