From 5eeeb67e6dafa2e53a5af520d7a3ae77bfbe3b12 Mon Sep 17 00:00:00 2001
From: Xavier Morel <xmo@openerp.com>
Date: Wed, 5 Oct 2011 13:24:44 +0200
Subject: [PATCH] [IMP] raise error when iterating over browse_record

Python has an iteration fallback protocol: when iterating over an
object which does not define __iter__, if the object defines
__getitem__ it considers that it's a list, and invokes __getitem__
from index `0`.

This can be a problem in openerp in methods which expect an list of
ids but are only given a single id (not a singleton list), in that
case self.browse() will return a single browse_record (instea of a
list) and the method tries to iterate over it by calling
browse_record.__getitem__.

Problem is that browse_record.__getitem__ is pretty deep and does
little validation, so the error appears 3 frames below where the
actual issue is with a completely cryptic message of "KeyError: 0",
which makes the actual harder to track.

By raising an error immediately in browse_record.__iter__, this kind
of issues is much easier to handle, the stack points precisely to the
frame in error with a clearer message.

bzr revid: xmo@openerp.com-20111005112444-jcp9fw6pa36ahpsd
---
 openerp/osv/orm.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py
index 47f6ac34e1b2..5bafd964a61d 100644
--- a/openerp/osv/orm.py
+++ b/openerp/osv/orm.py
@@ -462,6 +462,9 @@ class browse_record(object):
     def __contains__(self, name):
         return (name in self._table._columns) or (name in self._table._inherit_fields) or hasattr(self._table, name)
 
+    def __iter__(self):
+        raise NotImplementedError("Iteration is not allowed on %s" % self)
+
     def __hasattr__(self, name):
         return name in self
 
-- 
GitLab