[MERGE] osv: osv classes merged inside orm classes.
bzr revid: vmt@openerp.com-20110530074205-98kdkwhpbu9e19qw
This commit is contained in:
commit
52731ee4b8
|
@ -162,7 +162,7 @@ class ir_model(osv.osv):
|
|||
pass
|
||||
x_custom_model._name = model
|
||||
x_custom_model._module = False
|
||||
a = x_custom_model.createInstance(self.pool, '', cr)
|
||||
a = x_custom_model.createInstance(self.pool, cr)
|
||||
if (not a._columns) or ('x_name' in a._columns.keys()):
|
||||
x_name = 'x_name'
|
||||
else:
|
||||
|
|
|
@ -90,7 +90,7 @@ class RegistryManager(object):
|
|||
|
||||
cr = db.cursor()
|
||||
try:
|
||||
pool.init_set(cr, False)
|
||||
pool.do_parent_store(cr)
|
||||
pool.get('ir.actions.report.xml').register_all(cr)
|
||||
cr.commit()
|
||||
finally:
|
||||
|
|
|
@ -65,6 +65,9 @@ from openerp.tools import SKIPPED_ELEMENT_TYPES
|
|||
regex_order = re.compile('^(([a-z0-9_]+|"[a-z0-9_]+")( *desc| *asc)?( *, *|))+$', re.I)
|
||||
regex_object_name = re.compile(r'^[a-z0-9_.]+$')
|
||||
|
||||
# Mapping between openerp module names and their osv classes.
|
||||
module_class_list = {}
|
||||
|
||||
def check_object_name(name):
|
||||
""" Check if the given name is a valid openerp object name.
|
||||
|
||||
|
@ -414,6 +417,21 @@ def get_pg_type(f):
|
|||
|
||||
|
||||
class orm_template(object):
|
||||
""" Base class for OpenERP models.
|
||||
|
||||
OpenERP models are created by inheriting from this class (although
|
||||
not directly; more specifically by inheriting from osv or
|
||||
osv_memory). The constructor is called once, usually directly
|
||||
after the class definition, e.g.:
|
||||
|
||||
class user(osv):
|
||||
...
|
||||
user()
|
||||
|
||||
The system will later instanciate the class once per database (on
|
||||
which the class' module is installed).
|
||||
|
||||
"""
|
||||
_name = None
|
||||
_columns = {}
|
||||
_constraints = []
|
||||
|
@ -451,6 +469,18 @@ class orm_template(object):
|
|||
raise NotImplementedError(_('The read_group method is not implemented on this object !'))
|
||||
|
||||
def _field_create(self, cr, context=None):
|
||||
"""
|
||||
|
||||
Create/update entries in ir_model, ir_model_data, and ir_model_fields.
|
||||
|
||||
- create an entry in ir_model (if there is not already one),
|
||||
- create an entry in ir_model_data (if there is not already one, and if
|
||||
'module' is in the context),
|
||||
- update ir_model_fields with the fields found in _columns
|
||||
(TODO there is some redundancy as _columns is updated from
|
||||
ir_model_fields in __init__).
|
||||
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,))
|
||||
|
@ -542,7 +572,104 @@ class orm_template(object):
|
|||
raise_on_invalid_object_name(self._name)
|
||||
self._field_create(cr, context=context)
|
||||
|
||||
def __init__(self, cr):
|
||||
#
|
||||
# Goal: try to apply inheritance at the instanciation level and
|
||||
# put objects in the pool var
|
||||
#
|
||||
@classmethod
|
||||
def makeInstance(cls, pool, cr, attributes):
|
||||
""" Instanciate a given model.
|
||||
|
||||
This class method instanciates the class of some model (i.e. a class
|
||||
deriving from osv or osv_memory). The class might be the class passed
|
||||
in argument or, if it inherits from another class, a class constructed
|
||||
by combining the two classes.
|
||||
|
||||
The ``attributes`` argument specifies which parent class attributes
|
||||
have to be combined.
|
||||
|
||||
TODO: the creation of the combined class is repeated at each call of
|
||||
this method. This is probably unnecessary.
|
||||
|
||||
"""
|
||||
parent_names = getattr(cls, '_inherit', None)
|
||||
if parent_names:
|
||||
if isinstance(parent_names, (str, unicode)):
|
||||
name = cls._name or parent_names
|
||||
parent_names = [parent_names]
|
||||
else:
|
||||
name = cls._name
|
||||
|
||||
if not name:
|
||||
raise TypeError('_name is mandatory in case of multiple inheritance')
|
||||
|
||||
for parent_name in ((type(parent_names)==list) and parent_names or [parent_names]):
|
||||
parent_class = pool.get(parent_name).__class__
|
||||
if not pool.get(parent_name):
|
||||
raise TypeError('The model "%s" specifies an unexisting parent class "%s"\n'
|
||||
'You may need to add a dependency on the parent class\' module.' % (name, parent_name))
|
||||
nattr = {}
|
||||
for s in attributes:
|
||||
new = copy.copy(getattr(pool.get(parent_name), s))
|
||||
if s == '_columns':
|
||||
# Don't _inherit custom fields.
|
||||
for c in new.keys():
|
||||
if new[c].manual:
|
||||
del new[c]
|
||||
if hasattr(new, 'update'):
|
||||
new.update(cls.__dict__.get(s, {}))
|
||||
elif s=='_constraints':
|
||||
for c in cls.__dict__.get(s, []):
|
||||
exist = False
|
||||
for c2 in range(len(new)):
|
||||
#For _constraints, we should check field and methods as well
|
||||
if new[c2][2]==c[2] and (new[c2][0] == c[0] \
|
||||
or getattr(new[c2][0],'__name__', True) == \
|
||||
getattr(c[0],'__name__', False)):
|
||||
# If new class defines a constraint with
|
||||
# same function name, we let it override
|
||||
# the old one.
|
||||
new[c2] = c
|
||||
exist = True
|
||||
break
|
||||
if not exist:
|
||||
new.append(c)
|
||||
else:
|
||||
new.extend(cls.__dict__.get(s, []))
|
||||
nattr[s] = new
|
||||
cls = type(name, (cls, parent_class), nattr)
|
||||
obj = object.__new__(cls)
|
||||
obj.__init__(pool, cr)
|
||||
return obj
|
||||
|
||||
def __new__(cls):
|
||||
""" Register this model.
|
||||
|
||||
This doesn't create an instance but simply register the model
|
||||
as being part of the module where it is defined.
|
||||
|
||||
TODO make it possible to not even have to call the constructor
|
||||
to be registered.
|
||||
|
||||
"""
|
||||
|
||||
# Set the module name (e.g. base, sale, accounting, ...) on the class.
|
||||
module = cls.__module__.split('.')[0]
|
||||
if not hasattr(cls, '_module'):
|
||||
cls._module = module
|
||||
|
||||
# Remember which models to instanciate for this module.
|
||||
module_class_list.setdefault(cls._module, []).append(cls)
|
||||
|
||||
# Since we don't return an instance here, the __init__
|
||||
# method won't be called.
|
||||
return None
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
""" Initialize a model and make it part of the given registry."""
|
||||
pool.add(self._name, self)
|
||||
self.pool = pool
|
||||
|
||||
if not self._name and not hasattr(self, '_inherit'):
|
||||
name = type(self).__name__.split('.')[0]
|
||||
msg = "The class %s has to have a _name attribute" % name
|
||||
|
@ -1931,8 +2058,12 @@ class orm_memory(orm_template):
|
|||
_max_hours = config.get('osv_memory_age_limit')
|
||||
_check_time = 20
|
||||
|
||||
def __init__(self, cr):
|
||||
super(orm_memory, self).__init__(cr)
|
||||
@classmethod
|
||||
def createInstance(cls, pool, cr):
|
||||
return cls.makeInstance(pool, cr, ['_columns', '_defaults'])
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
super(orm_memory, self).__init__(pool, cr)
|
||||
self.datas = {}
|
||||
self.next_id = 0
|
||||
self.check_id = 0
|
||||
|
@ -2398,6 +2529,21 @@ class orm(orm_template):
|
|||
self._table, column['attname'])
|
||||
|
||||
def _auto_init(self, cr, context=None):
|
||||
"""
|
||||
|
||||
Call _field_create and, unless _auto is False:
|
||||
|
||||
- create the corresponding table in database for the model,
|
||||
- possibly add the parent columns in database,
|
||||
- possibly add the columns 'create_uid', 'create_date', 'write_uid',
|
||||
'write_date' in database if _log_access is True (the default),
|
||||
- report on database columns no more existing in _columns,
|
||||
- remove no more existing not null constraints,
|
||||
- alter existing database columns to match _columns,
|
||||
- create database tables to match _columns,
|
||||
- add database indices to match _columns,
|
||||
|
||||
"""
|
||||
raise_on_invalid_object_name(self._name)
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -2804,8 +2950,22 @@ class orm(orm_template):
|
|||
cr.commit()
|
||||
return todo_end
|
||||
|
||||
def __init__(self, cr):
|
||||
super(orm, self).__init__(cr)
|
||||
@classmethod
|
||||
def createInstance(cls, pool, cr):
|
||||
return cls.makeInstance(pool, cr, ['_columns', '_defaults',
|
||||
'_inherits', '_constraints', '_sql_constraints'])
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
"""
|
||||
|
||||
- copy the stored fields' functions in the osv_pool,
|
||||
- update the _columns with the fields found in ir_model_fields,
|
||||
- ensure there is a many2one for each _inherits'd parent,
|
||||
- update the children's _columns,
|
||||
- give a chance to each field to initialize itself.
|
||||
|
||||
"""
|
||||
super(orm, self).__init__(pool, cr)
|
||||
|
||||
if not hasattr(self, '_log_access'):
|
||||
# if not access is not specify, it is the same value as _auto
|
||||
|
@ -2890,6 +3050,8 @@ class orm(orm_template):
|
|||
for f in self._columns:
|
||||
self._columns[f].restart()
|
||||
|
||||
__init__.__doc__ = orm_template.__init__.__doc__ + __init__.__doc__
|
||||
|
||||
#
|
||||
# Update objects that uses this one to update their _inherits fields
|
||||
#
|
||||
|
|
|
@ -34,9 +34,7 @@ import logging
|
|||
from psycopg2 import IntegrityError, errorcodes
|
||||
from openerp.tools.func import wraps
|
||||
from openerp.tools.translate import translate
|
||||
|
||||
# Mapping between openerp module names and their osv classes.
|
||||
module_class_list = {}
|
||||
from openerp.osv.orm import module_class_list
|
||||
|
||||
class except_osv(Exception):
|
||||
def __init__(self, name, value, exc_type='warning'):
|
||||
|
@ -119,7 +117,7 @@ class object_proxy(netsvc.Service):
|
|||
return tr(src, 'code')
|
||||
|
||||
try:
|
||||
if not pooler.get_pool(dbname)._ready:
|
||||
if pooler.get_pool(dbname)._init:
|
||||
raise except_osv('Database not ready', 'Currently, this database is not fully loaded and can not be used.')
|
||||
return f(self, dbname, *args, **kwargs)
|
||||
except orm.except_orm, inst:
|
||||
|
@ -214,25 +212,16 @@ class osv_pool(object):
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._ready = False
|
||||
self.obj_pool = {} # model name/model instance mapping
|
||||
self._sql_error = {}
|
||||
self._store_function = {}
|
||||
self._init = True
|
||||
self._init_parent = {}
|
||||
|
||||
def init_set(self, cr, mode):
|
||||
different = mode != self._init
|
||||
if different:
|
||||
if mode:
|
||||
self._init_parent = {}
|
||||
if not mode:
|
||||
for o in self._init_parent:
|
||||
self.get(o)._parent_store_compute(cr)
|
||||
self._init = mode
|
||||
|
||||
self._ready = True
|
||||
return different
|
||||
def do_parent_store(self, cr):
|
||||
for o in self._init_parent:
|
||||
self.get(o)._parent_store_compute(cr)
|
||||
self._init = False
|
||||
|
||||
def obj_list(self):
|
||||
""" Return the list of model names in this registry."""
|
||||
|
@ -246,132 +235,27 @@ class osv_pool(object):
|
|||
""" Return a model for a given name or None if it doesn't exist."""
|
||||
return self.obj_pool.get(name)
|
||||
|
||||
#TODO: pass a list of modules to load
|
||||
def instanciate(self, module, cr):
|
||||
""" Instanciate all the classes of a given module for a particular db."""
|
||||
|
||||
res = []
|
||||
|
||||
# instanciate classes registered through their constructor
|
||||
# Instanciate classes registered through their constructor and
|
||||
# add them to the pool.
|
||||
for klass in module_class_list.get(module, []):
|
||||
res.append(klass.createInstance(self, module, cr))
|
||||
res.append(klass.createInstance(self, cr))
|
||||
|
||||
return res
|
||||
|
||||
class osv_base(object):
|
||||
""" Base class for openerp models.
|
||||
|
||||
OpenERP models are created by inheriting from this class (although
|
||||
not directly; more specifically by inheriting from osv or
|
||||
osv_memory). The constructor is called once, usually directly
|
||||
after the class definition, e.g.:
|
||||
|
||||
class user(osv):
|
||||
...
|
||||
user()
|
||||
|
||||
The system will later instanciate the class once per database (on
|
||||
which the class' module is installed).
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
""" Initialize a model and make it part of the given registry."""
|
||||
pool.add(self._name, self)
|
||||
self.pool = pool
|
||||
super(osv_base, self).__init__(cr)
|
||||
|
||||
def __new__(cls):
|
||||
""" Register this model.
|
||||
|
||||
This doesn't create an instance but simply register the model
|
||||
as being part of the module where it is defined.
|
||||
|
||||
TODO make it possible to not even have to call the constructor
|
||||
to be registered.
|
||||
|
||||
"""
|
||||
|
||||
# Set the module name (e.g. base, sale, accounting, ...) on the class.
|
||||
module = cls.__module__.split('.')[0]
|
||||
if not hasattr(cls, '_module'):
|
||||
cls._module = module
|
||||
|
||||
# Remember which models to instanciate for this module.
|
||||
module_class_list.setdefault(cls._module, []).append(cls)
|
||||
|
||||
# Since we don't return an instance here, the __init__
|
||||
# method won't be called.
|
||||
return None
|
||||
|
||||
#
|
||||
# Goal: try to apply inheritance at the instanciation level and
|
||||
# put objects in the pool var
|
||||
#
|
||||
@classmethod
|
||||
def makeInstance(cls, pool, module, cr, attributes):
|
||||
parent_names = getattr(cls, '_inherit', None)
|
||||
if parent_names:
|
||||
if isinstance(parent_names, (str, unicode)):
|
||||
name = cls._name or parent_names
|
||||
parent_names = [parent_names]
|
||||
else:
|
||||
name = cls._name
|
||||
|
||||
if not name:
|
||||
raise TypeError('_name is mandatory in case of multiple inheritance')
|
||||
|
||||
for parent_name in ((type(parent_names)==list) and parent_names or [parent_names]):
|
||||
parent_class = pool.get(parent_name).__class__
|
||||
assert pool.get(parent_name), "parent class %s does not exist in module %s !" % (parent_name, module)
|
||||
nattr = {}
|
||||
for s in attributes:
|
||||
new = copy.copy(getattr(pool.get(parent_name), s))
|
||||
if s == '_columns':
|
||||
# Don't _inherit custom fields.
|
||||
for c in new.keys():
|
||||
if new[c].manual:
|
||||
del new[c]
|
||||
if hasattr(new, 'update'):
|
||||
new.update(cls.__dict__.get(s, {}))
|
||||
elif s=='_constraints':
|
||||
for c in cls.__dict__.get(s, []):
|
||||
exist = False
|
||||
for c2 in range(len(new)):
|
||||
#For _constraints, we should check field and methods as well
|
||||
if new[c2][2]==c[2] and (new[c2][0] == c[0] \
|
||||
or getattr(new[c2][0],'__name__', True) == \
|
||||
getattr(c[0],'__name__', False)):
|
||||
# If new class defines a constraint with
|
||||
# same function name, we let it override
|
||||
# the old one.
|
||||
new[c2] = c
|
||||
exist = True
|
||||
break
|
||||
if not exist:
|
||||
new.append(c)
|
||||
else:
|
||||
new.extend(cls.__dict__.get(s, []))
|
||||
nattr[s] = new
|
||||
cls = type(name, (cls, parent_class), nattr)
|
||||
obj = object.__new__(cls)
|
||||
obj.__init__(pool, cr)
|
||||
return obj
|
||||
class osv_memory(orm.orm_memory):
|
||||
""" Deprecated class. """
|
||||
pass
|
||||
|
||||
|
||||
class osv_memory(osv_base, orm.orm_memory):
|
||||
|
||||
@classmethod
|
||||
def createInstance(cls, pool, module, cr):
|
||||
return cls.makeInstance(pool, module, cr, ['_columns', '_defaults'])
|
||||
|
||||
|
||||
class osv(osv_base, orm.orm):
|
||||
|
||||
@classmethod
|
||||
def createInstance(cls, pool, module, cr):
|
||||
return cls.makeInstance(pool, module, cr, ['_columns', '_defaults',
|
||||
'_inherits', '_constraints', '_sql_constraints'])
|
||||
class osv(orm.orm):
|
||||
""" Deprecated class. """
|
||||
pass
|
||||
|
||||
|
||||
def start_object_proxy():
|
||||
|
|
Loading…
Reference in New Issue