Manage some methods as class and instance method

issue4242
review9771002
This commit is contained in:
Cédric Krier committed 2014-10-23 20:19:55 +02:00
1 parent 8379c01819
commit fa4708c3e9
3 files changed
+115 -29

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
* Manage reload, save, delete, duplicate and click as class and instance method
Version 3.4.0 - 2014-10-20
* Bug fixes (see mercurial logs for details)
* New configuration syntax
+104 -29
View File
@@ -16,6 +16,7 @@ except ImportError:
sys.modules['cdecimal'] = decimal
import threading
import datetime
import functools
from decimal import Decimal
from types import NoneType
@@ -73,6 +74,37 @@ class _EvalEnvironment(dict):
return item in self.parent._fields
class dualmethod(object):
"""Descriptor implementing combination of class and instance method
When called on an instance, the class is passed as the first argument and a
list with the instance as the second.
When called on a class, the class itself is passed as the first argument.
>>> class Example(object):
... @dualmethod
... def method(cls, instances):
... print len(instances)
...
>>> Example.method([Example()])
1
>>> Example().method()
1
"""
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
@functools.wraps(self.func)
def newfunc(*args, **kwargs):
if instance:
return self.func(owner, [instance], *args, **kwargs)
else:
return self.func(owner, *args, **kwargs)
return newfunc
class FieldDescriptor(object):
default = None
@@ -660,6 +692,11 @@ class Model(object):
'The unique ID'
return self.__id
@id.setter
def id(self, value):
assert self.__id < 0
self.__id = int(value)
@classmethod
def find(cls, condition=None, offset=0, limit=None, order=None):
'Return records matching condition'
@@ -669,46 +706,84 @@ class Model(object):
cls._config.context)
return [cls(id) for id in ids]
def reload(self):
@dualmethod
def reload(cls, records):
'Reload record'
self._values = {}
self._changed = set()
for record in records:
record._values = {}
record._changed = set()
def save(self):
'Save the record'
context = self._config.context
if self.id < 0:
values = self._get_values()
self.__id, = self._proxy.create([values], context)
else:
if not self._changed:
return
values = self._get_values(fields=self._changed)
context['_timestamp'] = self._get_timestamp()
self._proxy.write([self.id], values, context)
self.reload()
@dualmethod
def save(cls, records):
'Save records'
if not records:
return
proxy = records[0]._proxy
config = records[0]._config
context = config.context
create, write = [], []
for record in records:
assert proxy == record._proxy
assert config == record._config
if record.id < 0:
create.append(record)
elif record._changed:
write.append(record)
def delete(self):
'Delete the record'
if self.id > 0:
context = self._config.context
context['_timestamp'] = self._get_timestamp()
return self._proxy.delete([self.id], context)
self.reload()
return True
if create:
values = [r._get_values() for r in create]
ids = proxy.create(values, context)
for record, id_ in zip(create, ids):
record.id = id_
if write:
values = []
context['_timestamp'] = {}
for record in write:
values.append([record.id])
values.append(record._get_values(fields=record._changed))
context['_timestamp'].update(record._get_timestamp())
values.append(context)
proxy.write(*values)
for record in records:
record.reload()
@classmethod
@dualmethod
def delete(cls, records):
'Delete records'
if not records:
return
proxy = records[0]._proxy
config = records[0]._config
context = config.context
context['_timestamp'] = {}
delete = []
for record in records:
assert proxy == record._proxy
assert config == record._config
if record.id > 0:
context['_timestamp'].update(record._get_timestamp())
delete.append(record.id)
if delete:
proxy.delete(delete, context)
cls.reload(records)
@dualmethod
def duplicate(cls, records, default=None):
'Duplicate the record'
ids = cls._proxy.copy([r.id for r in records], default,
cls._config.context)
return [cls(id) for id in ids]
def click(self, button):
@dualmethod
def click(cls, records, button):
'Click on button'
self.save()
self.reload() # Force reload because save doesn't always
return getattr(self._proxy, button)([self.id], self._config.context)
if not records:
return
cls.save(records)
cls.reload(records) # Force reload because save doesn't always
proxy = records[0]._proxy
context = records[0]._config.context
return getattr(proxy, button)([r.id for r in records], context)
def _get_values(self, fields=None):
'Return dictionary values'
+9
View File
@@ -126,6 +126,15 @@ class TestModel(ProteusTestCase):
self.assertEqual(test2.name, 'Test 2')
self.assertEqual(test2.login, 'test2')
test.signature = 'classmethod save'
test2.name = 'Test 2 classmethod'
test3 = User(name='Test 3', login='test3')
User.save([test, test2, test3])
self.assertEqual(test.signature, 'classmethod save')
self.assertEqual(test2.name, 'Test 2 classmethod')
self.assert_(test3.id > 0)
self.assertEqual(test3.name, 'Test 3')
def test_save_many2one(self):
User = Model.get('res.user')
test = User()