[IMP] openerp/osv/fields: add `__slots__` on all column classes
Use the same technique as for field classes. This saves about 1.6Mb of memory per registry.
This commit is contained in:
parent
e7928e1265
commit
4259fe0072
|
@ -74,7 +74,6 @@ class _column(object):
|
|||
_classic_read = True
|
||||
_classic_write = True
|
||||
_auto_join = False
|
||||
_prefetch = True
|
||||
_properties = False
|
||||
_type = 'unknown'
|
||||
_obj = None
|
||||
|
@ -85,59 +84,64 @@ class _column(object):
|
|||
_symbol_get = None
|
||||
_deprecated = False
|
||||
|
||||
copy = True # whether value is copied by BaseModel.copy()
|
||||
string = None
|
||||
help = ""
|
||||
required = False
|
||||
readonly = False
|
||||
_domain = []
|
||||
_context = {}
|
||||
states = None
|
||||
priority = 0
|
||||
change_default = False
|
||||
size = None
|
||||
ondelete = None
|
||||
translate = False
|
||||
select = False
|
||||
manual = False
|
||||
write = False
|
||||
read = False
|
||||
selectable = True
|
||||
group_operator = False
|
||||
groups = False # CSV list of ext IDs of groups
|
||||
deprecated = False # Optional deprecation warning
|
||||
__slots__ = [
|
||||
'copy', # whether value is copied by BaseModel.copy()
|
||||
'string',
|
||||
'help',
|
||||
'required',
|
||||
'readonly',
|
||||
'_domain',
|
||||
'_context',
|
||||
'states',
|
||||
'priority',
|
||||
'change_default',
|
||||
'size',
|
||||
'ondelete',
|
||||
'translate',
|
||||
'select',
|
||||
'manual',
|
||||
'write',
|
||||
'read',
|
||||
'selectable',
|
||||
'group_operator',
|
||||
'groups', # CSV list of ext IDs of groups
|
||||
'deprecated', # Optional deprecation warning
|
||||
'_args',
|
||||
'_prefetch',
|
||||
]
|
||||
|
||||
def __init__(self, string='unknown', required=False, readonly=False, domain=None, context=None, states=None, priority=0, change_default=False, size=None, ondelete=None, translate=False, select=False, manual=False, **args):
|
||||
def __init__(self, string='unknown', required=False, readonly=False, domain=[], context={}, states=None, priority=0, change_default=False, size=None, ondelete=None, translate=False, select=False, manual=False, **args):
|
||||
"""
|
||||
|
||||
The 'manual' keyword argument specifies if the field is a custom one.
|
||||
It corresponds to the 'state' column in ir_model_fields.
|
||||
|
||||
"""
|
||||
args0 = {
|
||||
'string': string,
|
||||
'help': args.pop('help', None),
|
||||
'required': required,
|
||||
'readonly': readonly,
|
||||
'_domain': domain,
|
||||
'_context': context,
|
||||
'states': states,
|
||||
'priority': priority,
|
||||
'change_default': change_default,
|
||||
'size': size,
|
||||
'ondelete': ondelete.lower() if ondelete else None,
|
||||
'translate': translate,
|
||||
'select': select,
|
||||
'manual': manual,
|
||||
'group_operator': args.pop('group_operator', None),
|
||||
'groups': args.pop('groups', None),
|
||||
'deprecated': args.pop('deprecated', None),
|
||||
}
|
||||
for key, val in args0.iteritems():
|
||||
if val:
|
||||
setattr(self, key, val)
|
||||
# add parameters and default values
|
||||
args['copy'] = args.get('copy', True)
|
||||
args['string'] = string
|
||||
args['help'] = args.get('help', '')
|
||||
args['required'] = required
|
||||
args['readonly'] = readonly
|
||||
args['_domain'] = domain
|
||||
args['_context'] = context
|
||||
args['states'] = states
|
||||
args['priority'] = priority
|
||||
args['change_default'] = change_default
|
||||
args['size'] = size
|
||||
args['ondelete'] = ondelete.lower() if ondelete else None
|
||||
args['translate'] = translate
|
||||
args['select'] = select
|
||||
args['manual'] = manual
|
||||
args['write'] = args.get('write', False)
|
||||
args['read'] = args.get('read', False)
|
||||
args['selectable'] = args.get('selectable', True)
|
||||
args['group_operator'] = args.get('group_operator', None)
|
||||
args['groups'] = args.get('groups', None)
|
||||
args['deprecated'] = args.get('deprecated', None)
|
||||
args['_prefetch'] = args.get('_prefetch', True)
|
||||
|
||||
self._args = args or EMPTY_DICT
|
||||
self._args = EMPTY_DICT
|
||||
for key, val in args.iteritems():
|
||||
setattr(self, key, val)
|
||||
|
||||
|
@ -145,6 +149,32 @@ class _column(object):
|
|||
if not self._classic_write or self.deprecated or self.manual:
|
||||
self._prefetch = False
|
||||
|
||||
def __getattr__(self, name):
|
||||
""" Access a non-slot attribute. """
|
||||
if name == '_args':
|
||||
raise AttributeError(name)
|
||||
try:
|
||||
return self._args[name]
|
||||
except KeyError:
|
||||
raise AttributeError(name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
""" Set a slot or non-slot attribute. """
|
||||
try:
|
||||
object.__setattr__(self, name, value)
|
||||
except AttributeError:
|
||||
if self._args:
|
||||
self._args[name] = value
|
||||
else:
|
||||
self._args = {name: value} # replace EMPTY_DICT
|
||||
|
||||
def __delattr__(self, name):
|
||||
""" Remove a non-slot attribute. """
|
||||
try:
|
||||
del self._args[name]
|
||||
except KeyError:
|
||||
raise AttributeError(name)
|
||||
|
||||
def new(self, _computed_field=False, **args):
|
||||
""" Return a column like `self` with the given parameters; the parameter
|
||||
`_computed_field` tells whether the corresponding field is computed.
|
||||
|
@ -224,6 +254,7 @@ class boolean(_column):
|
|||
_symbol_c = '%s'
|
||||
_symbol_f = bool
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
__slots__ = []
|
||||
|
||||
def __init__(self, string='unknown', required=False, **args):
|
||||
super(boolean, self).__init__(string=string, required=required, **args)
|
||||
|
@ -239,6 +270,7 @@ class integer(_column):
|
|||
_symbol_f = lambda x: int(x or 0)
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
_symbol_get = lambda self,x: x or 0
|
||||
__slots__ = []
|
||||
|
||||
def __init__(self, string='unknown', required=False, **args):
|
||||
super(integer, self).__init__(string=string, required=required, **args)
|
||||
|
@ -246,6 +278,7 @@ class integer(_column):
|
|||
class reference(_column):
|
||||
_type = 'reference'
|
||||
_classic_read = False # post-process to handle missing target
|
||||
__slots__ = ['selection']
|
||||
|
||||
def __init__(self, string, selection, size=None, **args):
|
||||
if callable(selection):
|
||||
|
@ -298,6 +331,7 @@ def _symbol_set_char(self, symb):
|
|||
|
||||
class char(_column):
|
||||
_type = 'char'
|
||||
__slots__ = ['_symbol_f', '_symbol_set', '_symbol_set_char']
|
||||
|
||||
def __init__(self, string="unknown", size=None, **args):
|
||||
_column.__init__(self, string=string, size=size or None, **args)
|
||||
|
@ -307,11 +341,13 @@ class char(_column):
|
|||
|
||||
class text(_column):
|
||||
_type = 'text'
|
||||
__slots__ = []
|
||||
|
||||
|
||||
class html(text):
|
||||
_type = 'html'
|
||||
_symbol_c = '%s'
|
||||
__slots__ = ['_sanitize', '_strip_style', '_symbol_f', '_symbol_set']
|
||||
|
||||
def _symbol_set_html(self, value):
|
||||
if value is None or value is False:
|
||||
|
@ -347,6 +383,7 @@ class float(_column):
|
|||
_type = 'float'
|
||||
_symbol_c = '%s'
|
||||
_symbol_get = lambda self,x: x or 0.0
|
||||
__slots__ = ['_digits', '_digits_compute', '_symbol_f', '_symbol_set']
|
||||
|
||||
@property
|
||||
def digits(self):
|
||||
|
@ -374,6 +411,7 @@ class float(_column):
|
|||
|
||||
class date(_column):
|
||||
_type = 'date'
|
||||
__slots__ = []
|
||||
|
||||
MONTHS = [
|
||||
('01', 'January'),
|
||||
|
@ -464,6 +502,7 @@ class date(_column):
|
|||
|
||||
class datetime(_column):
|
||||
_type = 'datetime'
|
||||
__slots__ = []
|
||||
|
||||
MONTHS = [
|
||||
('01', 'January'),
|
||||
|
@ -533,7 +572,7 @@ class datetime(_column):
|
|||
|
||||
class binary(_column):
|
||||
_type = 'binary'
|
||||
_symbol_c = '%s'
|
||||
_classic_read = False
|
||||
|
||||
# Binary values may be byte strings (python 2.6 byte array), but
|
||||
# the legacy OpenERP convention is to transfer and store binaries
|
||||
|
@ -541,17 +580,16 @@ class binary(_column):
|
|||
# unicode in some circumstances, hence the str() cast in symbol_f.
|
||||
# This str coercion will only work for pure ASCII unicode strings,
|
||||
# on purpose - non base64 data must be passed as a 8bit byte strings.
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = lambda symb: symb and Binary(str(symb)) or None
|
||||
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
_symbol_get = lambda self, x: x and str(x)
|
||||
|
||||
_classic_read = False
|
||||
_prefetch = False
|
||||
__slots__ = ['filters']
|
||||
|
||||
def __init__(self, string='unknown', filters=None, **args):
|
||||
_column.__init__(self, string=string, **args)
|
||||
self.filters = filters
|
||||
args['_prefetch'] = args.get('_prefetch', False)
|
||||
_column.__init__(self, string=string, filters=filters, **args)
|
||||
|
||||
def get(self, cr, obj, ids, name, user=None, context=None, values=None):
|
||||
if not context:
|
||||
|
@ -579,13 +617,13 @@ class binary(_column):
|
|||
|
||||
class selection(_column):
|
||||
_type = 'selection'
|
||||
__slots__ = ['selection']
|
||||
|
||||
def __init__(self, selection, string='unknown', **args):
|
||||
if callable(selection):
|
||||
from openerp import api
|
||||
selection = api.expected(api.cr_uid_context, selection)
|
||||
_column.__init__(self, string=string, **args)
|
||||
self.selection = selection
|
||||
_column.__init__(self, string=string, selection=selection, **args)
|
||||
|
||||
def to_field_args(self):
|
||||
args = super(selection, self).to_field_args()
|
||||
|
@ -646,9 +684,10 @@ class many2one(_column):
|
|||
_symbol_f = lambda x: x or None
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
|
||||
ondelete = 'set null'
|
||||
__slots__ = ['ondelete', '_obj', '_auto_join']
|
||||
|
||||
def __init__(self, obj, string='unknown', auto_join=False, **args):
|
||||
args['ondelete'] = args.get('ondelete', 'set null')
|
||||
_column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
self._auto_join = auto_join
|
||||
|
@ -694,13 +733,14 @@ class many2one(_column):
|
|||
class one2many(_column):
|
||||
_classic_read = False
|
||||
_classic_write = False
|
||||
_prefetch = False
|
||||
_type = 'one2many'
|
||||
|
||||
# one2many columns are not copied by default
|
||||
copy = False
|
||||
__slots__ = ['_obj', '_fields_id', '_limit', '_auto_join']
|
||||
|
||||
def __init__(self, obj, fields_id, string='unknown', limit=None, auto_join=False, **args):
|
||||
# one2many columns are not copied by default
|
||||
args['copy'] = args.get('copy', False)
|
||||
args['_prefetch'] = args.get('_prefetch', False)
|
||||
_column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
self._fields_id = fields_id
|
||||
|
@ -841,12 +881,14 @@ class many2many(_column):
|
|||
"""
|
||||
_classic_read = False
|
||||
_classic_write = False
|
||||
_prefetch = False
|
||||
_type = 'many2many'
|
||||
|
||||
__slots__ = ['_obj', '_rel', '_id1', '_id2', '_limit', '_auto_join']
|
||||
|
||||
def __init__(self, obj, rel=None, id1=None, id2=None, string='unknown', limit=None, **args):
|
||||
"""
|
||||
"""
|
||||
args['_prefetch'] = args.get('_prefetch', False)
|
||||
_column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
if rel and '.' in rel:
|
||||
|
@ -856,6 +898,7 @@ class many2many(_column):
|
|||
self._id1 = id1
|
||||
self._id2 = id2
|
||||
self._limit = limit
|
||||
self._auto_join = False
|
||||
|
||||
def to_field_args(self):
|
||||
args = super(many2many, self).to_field_args()
|
||||
|
@ -1238,14 +1281,30 @@ class function(_column):
|
|||
}
|
||||
|
||||
"""
|
||||
_classic_read = False
|
||||
_classic_write = False
|
||||
_prefetch = False
|
||||
_type = 'function'
|
||||
_properties = True
|
||||
|
||||
# function fields are not copied by default
|
||||
copy = False
|
||||
__slots__ = [
|
||||
'_type',
|
||||
'_classic_read',
|
||||
'_classic_write',
|
||||
'_symbol_c',
|
||||
'_symbol_f',
|
||||
'_symbol_set',
|
||||
'_symbol_get',
|
||||
|
||||
'_fnct',
|
||||
'_arg',
|
||||
'_fnct_inv',
|
||||
'_fnct_inv_arg',
|
||||
'_fnct_search',
|
||||
'_multi',
|
||||
'store',
|
||||
|
||||
'_digits',
|
||||
'_digits_compute',
|
||||
'selection',
|
||||
'_obj',
|
||||
]
|
||||
|
||||
@property
|
||||
def digits(self):
|
||||
|
@ -1259,33 +1318,43 @@ class function(_column):
|
|||
# multi: compute several fields in one call
|
||||
#
|
||||
def __init__(self, fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type='float', fnct_search=None, obj=None, store=False, multi=False, **args):
|
||||
self._classic_read = False
|
||||
self._classic_write = False
|
||||
self._prefetch = False
|
||||
self._symbol_c = '%s'
|
||||
self._symbol_f = _symbol_set
|
||||
self._symbol_set = (self._symbol_c, self._symbol_f)
|
||||
self._symbol_get = None
|
||||
|
||||
# pop attributes that should not be assigned to self
|
||||
self._digits = args.pop('digits', (16,2))
|
||||
self._digits_compute = args.pop('digits_compute', None)
|
||||
self._obj = args.pop('relation', obj)
|
||||
|
||||
# function fields are not copied by default
|
||||
args['copy'] = args.get('copy', False)
|
||||
|
||||
_column.__init__(self, **args)
|
||||
self._obj = obj
|
||||
|
||||
self._type = type
|
||||
self._fnct = fnct
|
||||
self._fnct_inv = fnct_inv
|
||||
self._arg = arg
|
||||
self._fnct_inv = fnct_inv
|
||||
self._fnct_inv_arg = fnct_inv_arg
|
||||
self._fnct_search = fnct_search
|
||||
self.store = store
|
||||
self._multi = multi
|
||||
if 'relation' in args:
|
||||
self._obj = args['relation']
|
||||
|
||||
if not fnct_inv:
|
||||
self.readonly = 1
|
||||
|
||||
if not fnct_search and not store:
|
||||
self.selectable = False
|
||||
|
||||
if callable(args.get('selection')):
|
||||
from openerp import api
|
||||
self.selection = api.expected(api.cr_uid_context, args['selection'])
|
||||
|
||||
self._fnct_inv_arg = fnct_inv_arg
|
||||
if not fnct_inv:
|
||||
self.readonly = 1
|
||||
self._type = type
|
||||
self._fnct_search = fnct_search
|
||||
self.store = store
|
||||
|
||||
if not fnct_search and not store:
|
||||
self.selectable = False
|
||||
|
||||
if store:
|
||||
if self._type != 'many2one':
|
||||
# m2o fields need to return tuples with name_get, not just foreign keys
|
||||
|
@ -1421,6 +1490,7 @@ class related(function):
|
|||
'bar': fields.related('foo_id', 'frol', type='char', string='Frol of Foo'),
|
||||
}
|
||||
"""
|
||||
__slots__ = ['arg', '_relations']
|
||||
|
||||
def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context=None):
|
||||
# assume self._arg = ('foo', 'bar', 'baz')
|
||||
|
@ -1472,7 +1542,8 @@ class related(function):
|
|||
pass
|
||||
|
||||
|
||||
class sparse(function):
|
||||
class sparse(function):
|
||||
__slots__ = ['serialization_field']
|
||||
|
||||
def convert_value(self, obj, cr, uid, record, value, read_value, context=None):
|
||||
"""
|
||||
|
@ -1521,7 +1592,6 @@ class sparse(function):
|
|||
return read_value
|
||||
return value
|
||||
|
||||
|
||||
def _fnct_write(self,obj,cr, uid, ids, field_name, value, args, context=None):
|
||||
if not type(ids) == list:
|
||||
ids = [ids]
|
||||
|
@ -1564,7 +1634,6 @@ class sparse(function):
|
|||
def __init__(self, serialization_field, **kwargs):
|
||||
self.serialization_field = serialization_field
|
||||
super(sparse, self).__init__(self._fnct_read, fnct_inv=self._fnct_write, multi='__sparse_multi', **kwargs)
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
@ -1572,6 +1641,8 @@ class sparse(function):
|
|||
# ---------------------------------------------------------
|
||||
|
||||
class dummy(function):
|
||||
__slots__ = ['arg', '_relations']
|
||||
|
||||
def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context=None):
|
||||
return []
|
||||
|
||||
|
@ -1595,23 +1666,27 @@ class serialized(_column):
|
|||
|
||||
Note: only plain components allowed.
|
||||
"""
|
||||
|
||||
_type = 'serialized'
|
||||
__slots__ = []
|
||||
|
||||
def _symbol_set_struct(val):
|
||||
return simplejson.dumps(val)
|
||||
|
||||
def _symbol_get_struct(self, val):
|
||||
return simplejson.loads(val or '{}')
|
||||
|
||||
_prefetch = False
|
||||
_type = 'serialized'
|
||||
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = _symbol_set_struct
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
_symbol_get = _symbol_get_struct
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['_prefetch'] = kwargs.get('_prefetch', False)
|
||||
super(serialized, self).__init__(*args, **kwargs)
|
||||
|
||||
# TODO: review completly this class for speed improvement
|
||||
class property(function):
|
||||
__slots__ = []
|
||||
|
||||
def to_field_args(self):
|
||||
args = super(property, self).to_field_args()
|
||||
|
|
Loading…
Reference in New Issue