diff --git a/openerp/fields.py b/openerp/fields.py index a6775336a1e..b46e4e3cda7 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -30,6 +30,7 @@ import logging import pytz import xmlrpclib +from openerp.sql_db import LazyCursor from openerp.tools import float_round, frozendict, html_sanitize, ustr, OrderedSet from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT @@ -1070,7 +1071,7 @@ class Float(Field): @property def digits(self): if callable(self._digits): - with fields._get_cursor() as cr: + with LazyCursor() as cr: return self._digits(cr) else: return self._digits @@ -1882,7 +1883,7 @@ class Id(Field): raise TypeError("field 'id' cannot be assigned") # imported here to avoid dependency cycle issues -from openerp import SUPERUSER_ID, registry +from openerp import SUPERUSER_ID from .exceptions import Warning, AccessError, MissingError from .models import BaseModel, MAGIC_COLUMNS from .osv import fields diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 38b034dded1..54b39418b9c 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -43,21 +43,18 @@ import pytz import re import xmlrpclib from operator import itemgetter -from contextlib import contextmanager from psycopg2 import Binary import openerp import openerp.tools as tools +from openerp.sql_db import LazyCursor from openerp.tools.translate import _ from openerp.tools import float_repr, float_round, frozendict, html_sanitize import simplejson -from openerp import SUPERUSER_ID, registry +from openerp import SUPERUSER_ID -@contextmanager -def _get_cursor(): - # yield a valid cursor from any environment or create a new one if none found - with registry().cursor() as cr: - yield cr +# deprecated; kept for backward compatibility only +_get_cursor = LazyCursor EMPTY_DICT = frozendict() @@ -396,7 +393,7 @@ class float(_column): @property def digits(self): if self._digits_compute: - with _get_cursor() as cr: + with LazyCursor() as cr: return self._digits_compute(cr) else: return self._digits @@ -1323,7 +1320,7 @@ class function(_column): @property def digits(self): if self._digits_compute: - with _get_cursor() as cr: + with LazyCursor() as cr: return self._digits_compute(cr) else: return self._digits diff --git a/openerp/sql_db.py b/openerp/sql_db.py index f389a847548..a3af4be677a 100644 --- a/openerp/sql_db.py +++ b/openerp/sql_db.py @@ -443,6 +443,40 @@ class TestCursor(Cursor): self.execute("ROLLBACK TO SAVEPOINT test_cursor") self.execute("SAVEPOINT test_cursor") +class LazyCursor(object): + """ A proxy object to a cursor. The cursor itself is allocated only if it is + needed. This class is useful for cached methods, that use the cursor + only in the case of a cache miss. + """ + def __init__(self, dbname=None): + self._dbname = dbname + self._cursor = None + self._depth = 0 + + @property + def dbname(self): + return self._dbname or threading.currentThread().dbname + + def __getattr__(self, name): + cr = self._cursor + if cr is None: + from openerp import registry + cr = self._cursor = registry(self.dbname).cursor() + for _ in xrange(self._depth): + cr.__enter__() + return getattr(cr, name) + + def __enter__(self): + self._depth += 1 + if self._cursor is not None: + self._cursor.__enter__() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self._depth -= 1 + if self._cursor is not None: + self._cursor.__exit__(exc_type, exc_value, traceback) + class PsycoConnection(psycopg2.extensions.connection): pass