[ADD] behavior and tests for default & ancestors, fallback handling in read_combined
bzr revid: xmo@openerp.com-20130424130907-6d6lkrkrgqv0hsfq
This commit is contained in:
parent
8715746672
commit
fb492d98ba
|
@ -29,6 +29,7 @@ from openerp import tools
|
|||
from openerp.osv import fields,osv
|
||||
from openerp.tools import graph, SKIPPED_ELEMENT_TYPES
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools.view_validation import valid_view
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
@ -51,6 +52,9 @@ class view_custom(osv.osv):
|
|||
class view(osv.osv):
|
||||
_name = 'ir.ui.view'
|
||||
|
||||
class NoViewError(Exception): pass
|
||||
class NoDefaultError(NoViewError): pass
|
||||
|
||||
def _type_field(self, cr, uid, ids, name, args, context=None):
|
||||
result = {}
|
||||
for record in self.browse(cr, uid, ids, context):
|
||||
|
@ -166,7 +170,7 @@ class view(osv.osv):
|
|||
cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)')
|
||||
|
||||
def read_combined(self, cr, uid, view_id, view_type, model,
|
||||
fields=None, context=None):
|
||||
fields=None, fallback=None, context=None):
|
||||
"""
|
||||
Utility function stringing together all method calls necessary to get
|
||||
a full, final view:
|
||||
|
@ -174,8 +178,7 @@ class view(osv.osv):
|
|||
* Gets the default view if no view_id is provided
|
||||
* Gets the top of the view tree if a sub-view is requested
|
||||
* Applies all inherited archs on the root view
|
||||
* Applies post-processing both generic (ir.ui.view) and specific
|
||||
(ir.ui.view.$type)
|
||||
* Applies post-processing
|
||||
* Returns the view with all requested fields
|
||||
|
||||
.. note:: ``arch`` is always added to the fields list even if not
|
||||
|
@ -183,29 +186,47 @@ class view(osv.osv):
|
|||
|
||||
If no view is available (no view_id or invalid view_id provided, or
|
||||
no view stored for (model, view_type)) a view record will be fetched
|
||||
from the ``defaults`` mapping.
|
||||
from the ``defaults`` mapping?
|
||||
|
||||
:param fallback: a mapping of {view_type: view_dict}, if no view can
|
||||
be found (read) will be used to provide a default
|
||||
before post-processing
|
||||
:type fallback: mapping
|
||||
"""
|
||||
if not view_id:
|
||||
view_id = self.default_view(cr, uid, model, view_type, context=context)
|
||||
root_id = self.root_ancestor(cr, uid, view_id, context=context)
|
||||
if context is None: context = {}
|
||||
try:
|
||||
if not view_id:
|
||||
view_id = self.default_view(cr, uid, model, view_type, context=context)
|
||||
root_id = self.root_ancestor(cr, uid, view_id, context=context)
|
||||
|
||||
if fields and 'arch' not in fields:
|
||||
fields = list(itertools.chain(['arch'], fields))
|
||||
if fields and 'arch' not in fields:
|
||||
fields = list(itertools.chain(['arch'], fields))
|
||||
|
||||
[view] = self.read(cr, uid, [root_id], fields=fields, context=context)
|
||||
[view] = self.read(cr, uid, [root_id], fields=fields, context=context)
|
||||
|
||||
arch_tree = etree.fromstring(
|
||||
view['arch'].encode('utf-8') if isinstance(view['arch'], unicode)
|
||||
else view['arch'])
|
||||
descendants = self.iter(
|
||||
cr, uid, view['id'], model, exclude_base=True, context=context)
|
||||
arch = self.apply_inherited_archs(
|
||||
cr, uid, arch_tree, descendants,
|
||||
model, view['id'], context=context)
|
||||
arch_tree = etree.fromstring(
|
||||
view['arch'].encode('utf-8') if isinstance(view['arch'], unicode)
|
||||
else view['arch'])
|
||||
descendants = self.iter(
|
||||
cr, uid, view['id'], model, exclude_base=True, context=context)
|
||||
arch = self.apply_inherited_archs(
|
||||
cr, uid, arch_tree, descendants,
|
||||
model, view['id'], context=context)
|
||||
|
||||
if view['model'] != model:
|
||||
context = dict(context, base_model_name=view['model'])
|
||||
except self.NoViewError:
|
||||
# defaultdict is "empty" until first __getattr__
|
||||
if fallback is None: raise
|
||||
view = fallback[view_type]
|
||||
arch = view['arch']
|
||||
if isinstance(arch, basestring):
|
||||
arch = etree.fromstring(
|
||||
arch.encode('utf-8') if isinstance(arch, unicode) else arch)
|
||||
|
||||
# TODO: post-processing
|
||||
|
||||
return dict(view, arch=arch)#etree.tostring(arch, 'utf-8'))
|
||||
return dict(view, arch=etree.tostring(arch, encoding='utf-8'))
|
||||
|
||||
def locate_node(self, arch, spec):
|
||||
""" Locate a node in a source (parent) architecture.
|
||||
|
@ -308,11 +329,16 @@ class view(osv.osv):
|
|||
:return: id of the default view for the (model, view_type) pair
|
||||
:rtype: int
|
||||
"""
|
||||
return self.search(cr, uid, [
|
||||
ids = self.search(cr, uid, [
|
||||
['model', '=', model],
|
||||
['type', '=', view_type],
|
||||
['inherit_id', '=', False],
|
||||
], limit=1, order='priority', context=context)[0]
|
||||
], limit=1, order='priority', context=context)
|
||||
if not ids:
|
||||
raise self.NoDefaultError(
|
||||
_("No default view of type %s for model %s") % (
|
||||
view_type, model))
|
||||
return ids[0]
|
||||
|
||||
def root_ancestor(self, cr, uid, view_id, context=None):
|
||||
"""
|
||||
|
@ -325,6 +351,9 @@ class view(osv.osv):
|
|||
:return: id of the root view for the tree
|
||||
"""
|
||||
view = self.browse(cr, uid, view_id, context=context)
|
||||
if not view.exists():
|
||||
raise self.NoViewError(
|
||||
_("No view for id %s, root ancestor not available") % view_id)
|
||||
|
||||
# Search for a root (i.e. without any parent) view.
|
||||
while view.inherit_id:
|
||||
|
|
|
@ -631,6 +631,27 @@ class MetaModel(type):
|
|||
if not self._custom:
|
||||
self.module_to_models.setdefault(self._module, []).append(self)
|
||||
|
||||
class FallbackViewMapping(collections.defaultdict):
|
||||
def __init__(self, cr, uid, model, context=None):
|
||||
super(FallbackViewMapping, self).__init__()
|
||||
self.cr = cr
|
||||
self.uid = uid
|
||||
self.model = model
|
||||
self.context = context
|
||||
|
||||
def __missing__(self, view_type):
|
||||
try:
|
||||
arch = getattr(self.model, '_get_default_%s_view' % view_type)(
|
||||
self.cr, self.uid, self.context)
|
||||
except AttributeError:
|
||||
raise except_orm(_('Invalid Architecture!'), _("There is no view of type '%s' defined for the structure!") % view_type)
|
||||
return {
|
||||
'id': 0,
|
||||
'type': view_type,
|
||||
'name': 'default',
|
||||
'field_parent': False,
|
||||
'arch': arch,
|
||||
}
|
||||
|
||||
# Definition of log access columns, automatically added to models if
|
||||
# self._log_access is True
|
||||
|
@ -2054,8 +2075,6 @@ class BaseModel(object):
|
|||
context = {}
|
||||
View = self.pool['ir.ui.view']
|
||||
|
||||
result = {'type': view_type, 'model': self._name}
|
||||
|
||||
view_ref = context.get(view_type + '_view_ref')
|
||||
|
||||
if view_ref and not view_id and '.' in view_ref:
|
||||
|
@ -2068,37 +2087,23 @@ class BaseModel(object):
|
|||
root_view = View.read_combined(
|
||||
cr, user, view_id, view_type, self._name, fields=[
|
||||
'id', 'name', 'field_parent', 'type', 'model', 'arch'
|
||||
], context=context)
|
||||
if root_view:
|
||||
result.update(
|
||||
arch=root_view['arch'],
|
||||
type=root_view['type'],
|
||||
view_id=root_view['id'],
|
||||
name=root_view['name'],
|
||||
field_parent=root_view['field_parent'] or False)
|
||||
else:
|
||||
# otherwise, build some kind of default view
|
||||
try:
|
||||
view = getattr(self, '_get_default_%s_view' % view_type)(
|
||||
cr, user, context)
|
||||
except AttributeError:
|
||||
# what happens here, graph case?
|
||||
raise except_orm(_('Invalid Architecture!'), _("There is no view of type '%s' defined for the structure!") % view_type)
|
||||
], fallback=FallbackViewMapping(cr, user, self, context=context),
|
||||
context=context)
|
||||
|
||||
result.update(
|
||||
arch=view,
|
||||
name='default',
|
||||
field_parent=False,
|
||||
view_id=0)
|
||||
result = {
|
||||
'model': self._name,
|
||||
'arch': root_view['arch'],
|
||||
'type': root_view['type'],
|
||||
'view_id': root_view['id'],
|
||||
'name': root_view['name'],
|
||||
'field_parent': root_view['field_parent'] or False
|
||||
}
|
||||
|
||||
parent_view_model = root_view['model'] if root_view else None
|
||||
if parent_view_model != self._name:
|
||||
ctx = context.copy()
|
||||
ctx['base_model_name'] = parent_view_model
|
||||
else:
|
||||
ctx = context
|
||||
ctx = context
|
||||
if root_view.get('model') != self._name:
|
||||
ctx = dict(context, base_model_name=root_view.get('model'))
|
||||
xarch, xfields = self.__view_look_dom_arch(
|
||||
cr, user, result['arch'], result['view_id'], context=ctx)
|
||||
cr, user, etree.fromstring(result['arch']), result['view_id'], context=ctx)
|
||||
result['arch'] = xarch
|
||||
result['fields'] = xfields
|
||||
|
||||
|
|
|
@ -184,12 +184,9 @@ class TestViewInheritance(common.TransactionCase):
|
|||
self.cr, self.uid, view_id=self.ids['B1'])
|
||||
self.assertEqual(root_id, self.ids['B'])
|
||||
|
||||
@unittest2.skip("What should the behavior be when no ancestor is found "
|
||||
"because view_id is invalid?")
|
||||
def test_no_root_ancestor(self):
|
||||
root = self.View.root_ancestor(
|
||||
self.cr, self.uid, view_id=12345678)
|
||||
self.assertFalse(root)
|
||||
with self.assertRaises(self.View.NoViewError):
|
||||
self.View.root_ancestor(self.cr, self.uid, view_id=12345678)
|
||||
|
||||
def test_default_view(self):
|
||||
default = self.View.default_view(
|
||||
|
@ -200,16 +197,22 @@ class TestViewInheritance(common.TransactionCase):
|
|||
self.cr, self.uid, model=self.model, view_type='tree')
|
||||
self.assertEqual(default_tree, self.ids['C'])
|
||||
|
||||
@unittest2.skip("What should the behavior be when no default is found "
|
||||
"because model does not exist or no view for model?")
|
||||
def test_no_default_view(self):
|
||||
default = self.View.default_view(
|
||||
self.cr, self.uid, model='does.not.exist', view_type='form')
|
||||
self.assertFalse(default)
|
||||
with self.assertRaises(self.View.NoDefaultError):
|
||||
self.View.default_view(
|
||||
self.cr, self.uid, model='does.not.exist', view_type='form')
|
||||
|
||||
default = self.View.default_view(
|
||||
self.cr, self.uid, model=self.model, view_type='graph')
|
||||
self.assertFalse(default)
|
||||
with self.assertRaises(self.View.NoDefaultError):
|
||||
self.View.default_view(
|
||||
self.cr, self.uid, model=self.model, view_type='graph')
|
||||
|
||||
@unittest2.skip("Not tested")
|
||||
def test_apply_inherited_archs(self):
|
||||
self.fail()
|
||||
|
||||
@unittest2.skip("Not tested")
|
||||
def test_apply_inheritance_specs(self):
|
||||
self.fail()
|
||||
|
||||
class TestViewCombined(common.TransactionCase):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue