Use creation position to format warning key for new records
The opposite position in the creation order is used instead of the id (which is not stable over transaction retries) to format the warning key when the record has been created during the transaction. This ensures that the formatting of the warning key is stable over transaction retries. Closes #10591
This commit is contained in:
1 parent
cd223660ff
commit
476065cf11
6 files changed
+37
-4
No files matched your search
@@ -40,8 +40,16 @@ Transaction
|
||||
|
||||
.. attribute:: Transaction.create_records
|
||||
|
||||
A :py:class:`defaultdict <collections.defaultdict>` storing for each
|
||||
:attr:`~trytond.model.Model.__name__` a :py:class:`list` of ids created
|
||||
during the transaction.
|
||||
|
||||
.. attribute:: Transaction.delete_records
|
||||
|
||||
A :py:class:`defaultdict <collections.defaultdict>` storing for each
|
||||
:attr:`~trytond.model.Model.__name__` a :py:class:`set` of ids deleted
|
||||
during the transaction.
|
||||
|
||||
.. attribute:: Transaction.trigger_records
|
||||
|
||||
.. attribute:: Transaction.check_warnings
|
||||
|
||||
@@ -2312,7 +2312,7 @@ class ModelSQL(ModelStorage):
|
||||
def lock(cls, records=None):
|
||||
transaction = Transaction()
|
||||
if records is not None:
|
||||
new_ids = transaction.create_records[cls.__name__]
|
||||
new_ids = set(transaction.create_records[cls.__name__])
|
||||
ids = [id_ for id_ in map(int, records) if id_ not in new_ids]
|
||||
transaction.lock_records(cls._table, ids)
|
||||
else:
|
||||
|
||||
@@ -299,7 +299,7 @@ class ModelStorage(Model):
|
||||
for trigger in triggers:
|
||||
trigger.queue_trigger_action(records)
|
||||
|
||||
transaction.create_records[cls.__name__].update(ids)
|
||||
transaction.create_records[cls.__name__].extend(ids)
|
||||
return ids
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -964,7 +964,17 @@ class Warning_(ModelSQL, ModelView):
|
||||
|
||||
@classmethod
|
||||
def format(cls, name, records):
|
||||
key = '|'.join(map(str, records)).encode('utf-8')
|
||||
create_records = Transaction().create_records
|
||||
|
||||
def str_(record):
|
||||
name = record.__name__
|
||||
try:
|
||||
# start from 1 to avoid 0 == -0
|
||||
i = create_records[name].index(record.id) + 1
|
||||
return '%s,%s' % (name, -i)
|
||||
except ValueError:
|
||||
return str(record)
|
||||
key = '|'.join(map(str_, records)).encode('utf-8')
|
||||
return '%s.%s' % (hashlib.md5(key).hexdigest(), name)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -82,5 +82,20 @@ class ResTestCase(ModuleTestCase):
|
||||
self.assertFalse(Warning_.check('test'))
|
||||
self.assertFalse(Warning_.check('test'))
|
||||
|
||||
@with_transaction()
|
||||
def test_user_warning_format(self):
|
||||
"Test format of user warning"
|
||||
pool = Pool()
|
||||
Warning_ = pool.get('res.user.warning')
|
||||
Record = pool.get('res.user')
|
||||
transaction = Transaction()
|
||||
|
||||
key1 = Warning_.format('test', [Record(1)])
|
||||
|
||||
transaction.create_records[Record.__name__].append(1)
|
||||
key2 = Warning_.format('test', [Record(1)])
|
||||
|
||||
self.assertNotEqual(key1, key2)
|
||||
|
||||
|
||||
del ModuleTestCase
|
||||
@@ -197,7 +197,7 @@ class Transaction(object):
|
||||
self.readonly = readonly
|
||||
self.close = close
|
||||
self.context = ImmutableDict(context or {})
|
||||
self.create_records = defaultdict(set)
|
||||
self.create_records = defaultdict(list)
|
||||
self.delete_records = defaultdict(set)
|
||||
self.trigger_records = defaultdict(set)
|
||||
self.log_records = []
|
||||
|
||||
Reference in new issue
Block a user