From ff3670f1417f82b74a5c08b8be4469bb034cc047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Thu, 27 Sep 2012 11:37:55 +0200 Subject: [PATCH] Add new and find methods to ModelList. Added set_context on Config objects. review501003 --- README | 4 +-- proteus/__init__.py | 50 ++++++++++++++++++++++++++++------- proteus/config.py | 24 +++++++++++++++++ proteus/tests/test_context.py | 21 +++++++++++++++ 4 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 proteus/tests/test_context.py diff --git a/README b/README index 390ee65d84..aa9f9a7268 100644 --- a/README +++ b/README @@ -75,9 +75,7 @@ Creating an address for the party Addresses are store on party with a `One2Many` field. So the new address just needs to be appended to the list `addresses`. - >>> Address = Model.get('party.address') - >>> address = Address() - >>> party.addresses.append(address) + >>> address = party.addresses.new() >>> party.save() >>> party.addresses #doctest: +ELLIPSIS [proteus.Model.get('party.address')(...)] diff --git a/proteus/__init__.py b/proteus/__init__.py index bba979778e..153df28dcd 100644 --- a/proteus/__init__.py +++ b/proteus/__init__.py @@ -211,9 +211,8 @@ class One2ManyDescriptor(FieldDescriptor): relation = Model.get(self.definition['relation'], instance._config) value = super(One2ManyDescriptor, self).__get__(instance, owner) if not isinstance(value, ModelList): - value = ModelList((relation(id) - for id in value or []), instance, self.name, - self.definition.get('relation_field')) + value = ModelList(self.definition, (relation(id) + for id in value or []), instance, self.name) instance._values[self.name] = value return value @@ -398,22 +397,26 @@ class MetaModelFactory(object): class ModelList(list): 'List for Model' - def __init__(self, sequence=None, parent=None, parent_field_name='', - parent_name=''): + def __init__(self, definition, sequence=None, parent=None, + parent_field_name=''): + self.model_name = definition['relation'] if sequence is None: sequence = [] self.parent = parent if parent: assert parent_field_name self.parent_field_name = parent_field_name - self.parent_name = parent_name + self.parent_name = definition.get('relation_field', '') + self.domain = definition.get('domain', []) + self.context = definition.get('context') + self.add_remove = definition.get('add_remove') self.record_removed = set() self.record_deleted = set() result = super(ModelList, self).__init__(sequence) for record in self: record._parent = parent record._parent_field_name = parent_field_name - record._parent_name = parent_name + record._parent_name = self.parent_name return result __init__.__doc__ = list.__init__.__doc__ @@ -423,6 +426,13 @@ class ModelList(list): self.parent._changed.add(self.parent_field_name) self.parent._on_change(self.parent_field_name) + def _get_context(self): + from .pyson import PYSONDecoder + decoder = PYSONDecoder(_EvalEnvironment(self.parent)) + ctx = self.parent._context.copy() if self.parent._context else {} + ctx.update(decoder.decode(self.context) if self.context else {}) + return ctx + def append(self, record): assert isinstance(record, Model) if self.parent: @@ -497,6 +507,27 @@ class ModelList(list): raise NotImplementedError sort.__doc__ = list.sort.__doc__ + def new(self): + 'Adds a new record to the ModelList and returns it' + Relation = Model.get(self.model_name, self.parent._config) + with Relation._config.set_context(self._get_context()): + new_record = Relation() + self.append(new_record) + return new_record + + def find(self, condition=None, offset=0, limit=None, order=None): + 'Returns records matching condition taking into account list domain' + from .pyson import PYSONDecoder + decoder = PYSONDecoder(_EvalEnvironment(self.parent)) + Relation = Model.get(self.model_name, self.parent._config) + if condition is None: + condition = [] + add_remove_domain = (decoder.decode(self.add_remove) + if self.add_remove else []) + new_domain = [self.domain, add_remove_domain, condition] + with Relation._config.set_context(self._get_context()): + return Relation.find(new_domain, offset, limit, order) + class Model(object): 'Model class for Tryton records' @@ -518,6 +549,7 @@ class Model(object): self._parent = None # store the parent record self._parent_field_name = '' # store the field name in parent record self._parent_name = '' # store the field name to parent record + self._context = self._config.context # store the context if self.id < 0 and _default: self._default_get() @@ -684,8 +716,8 @@ class Model(object): record = relation() record._default_set(vals) records.append(record) - self._values[field] = ModelList(records, self, field, - definition.get('relation_field', '')) + self._values[field] = ModelList(definition, records, self, + field) else: self._values[field] = value diff --git a/proteus/config.py b/proteus/config.py index eb8463bf2c..6b155915b2 100644 --- a/proteus/config.py +++ b/proteus/config.py @@ -72,6 +72,20 @@ _CONFIG = threading.local() _CONFIG.current = None +class ContextManager(object): + 'Context Manager for the tryton context' + + def __init__(self, config): + self.config = config + self.context = config.context + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.config._context = self.context + + class Config(object): 'Config interface' @@ -83,6 +97,16 @@ class Config(object): def context(self): return self._context.copy() + def set_context(self, context=None, **kwargs): + ctx_manager = ContextManager(self) + + if context is None: + context = None + self._context = self.context + self._context.update(context) + self._context.update(kwargs) + return ctx_manager + def get_proxy(self, name): raise NotImplementedError diff --git a/proteus/tests/test_context.py b/proteus/tests/test_context.py new file mode 100644 index 0000000000..dc7faeac83 --- /dev/null +++ b/proteus/tests/test_context.py @@ -0,0 +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. + +from unittest import TestCase +from proteus import config + + +class TestContext(TestCase): + + def setUp(self): + self.config = config.set_trytond(database_type='sqlite') + + def test_config(self): + prev_ctx = self.config._context + + with self.config.set_context({'a': 1}): + self.assertEqual(self.config.context['a'], 1) + for key, value in prev_ctx.items(): + self.assertEqual(self.config.context[key], value) + + self.assertEqual(self.config.context, prev_ctx)