[FIX] move conversion code from ir.fields.converter into website.qweb structures
authorXavier Morel <xmo@openerp.com>
Wed, 9 Oct 2013 13:31:12 +0000 (15:31 +0200)
committerXavier Morel <xmo@openerp.com>
Wed, 9 Oct 2013 13:31:12 +0000 (15:31 +0200)
bzr revid: xmo@openerp.com-20131009133112-05dglhptiw019838

addons/website/models/__init__.py
addons/website/models/ir_fields.py [deleted file]
addons/website/models/ir_qweb.py
addons/website/models/test_models.py [new file with mode: 0644]
addons/website/models/view.py
addons/website/tests/test_converter.py
addons/website/tests/test_views.py

index 5fcab98..af592ba 100644 (file)
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 
-import ir_fields
 import view
 import website
 import ir_qweb
+
+import test_models
diff --git a/addons/website/models/ir_fields.py b/addons/website/models/ir_fields.py
deleted file mode 100644 (file)
index fbccf9c..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-# -*- coding: utf-8 -*-
-from lxml import etree, html
-
-from openerp.osv import orm, fields
-from openerp.tools import ustr
-
-class converter(orm.Model):
-    _inherit = 'ir.fields.converter'
-
-    def _html_to_integer(self, cr, uid, model, column, value, context=None):
-        return int(value.text_content().strip()), []
-
-    def _html_to_float(self, cr, uid, model, column, value, context=None):
-        return float(value.text_content().strip()), []
-
-    def _html_to_passthrough(self, cr, uid, model, column, value, context=None):
-        return value.text_content().strip(), []
-
-    _html_to_char = _html_to_date = _html_to_datetime = _html_to_passthrough
-
-    def _html_to_text(self, cr, uid, model, column, value, context=None):
-        return value.text_content(), []
-
-    def _html_to_selection(self, cr, uid, model, column, value, context=None):
-        text = value.text_content().strip()
-
-        selection = column.reify(cr, uid, model, column, context=context)
-        for k, v in selection:
-            if isinstance(v, str):
-                v = ustr(v)
-            if text == v:
-                return k, []
-
-        warning = u"No value found for label %s in selection %s" % (text, selection)
-        # FIXME: ?
-        return False, [Warning(warning.encode('utf-8'))]
-
-    def _html_to_many2one(self, cr, uid, model, column, value, context=None):
-        matches = self.pool[column._obj].name_search(
-            cr, uid, name=value.text_content().strip(), context=context)
-        # FIXME: more than one match, error reporting
-        return matches[0][0], []
-
-    def _html_to_html(self, cr, uid, model, column, value, context=None):
-        content = []
-        if value.text: content.append(value.text)
-        content.extend(html.tostring(child)
-                       for child in value.iterchildren(tag=etree.Element))
-        return '\n'.join(content), []
-
-
-class test_converter(orm.Model):
-    _name = 'website.converter.test'
-
-    _columns = {
-        'char': fields.char(),
-        'integer': fields.integer(),
-        'float': fields.float(),
-        'numeric': fields.float(digits=(16, 2)),
-        'many2one': fields.many2one('website.converter.test.sub'),
-        'binary': fields.binary(),
-        'date': fields.date(),
-        'datetime': fields.datetime(),
-        'selection': fields.selection([
-            (1, "réponse A"),
-            (2, "réponse B"),
-            (3, "réponse C"),
-            (4, "réponse D"),
-        ]),
-        'selection_str': fields.selection([
-            ('A', "Qu'il n'est pas arrivé à Toronto"),
-            ('B', "Qu'il était supposé arriver à Toronto"),
-            ('C', "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?"),
-            ('D', "La réponse D"),
-        ], string="Lorsqu'un pancake prend l'avion à destination de Toronto et "
-                  "qu'il fait une escale technique à St Claude, on dit:"),
-        'html': fields.html(),
-        'text': fields.text(),
-    }
-
-
-class test_converter_sub(orm.Model):
-    _name = 'website.converter.test.sub'
-
-    _columns = {
-        'name': fields.char(),
-    }
index ec60ce9..dd6a832 100644 (file)
@@ -9,8 +9,10 @@ Also, adds methods to convert values back to openerp models.
 import itertools
 
 import werkzeug.utils
+from lxml import etree, html
 
 from openerp.osv import orm, fields
+from openerp.tools import ustr
 
 class QWeb(orm.AbstractModel):
     """ QWeb object for rendering stuff in the website context
@@ -37,26 +39,71 @@ class Field(orm.AbstractModel):
             [('data-oe-translate', 1 if column.translate else 0)]
         )
 
+    def value_from_string(self, value):
+        return value
+
+    def from_html(self, cr, uid, model, column, element, context=None):
+        return self.value_from_string(element.text_content().strip())
+
+class Integer(orm.AbstractModel):
+    _name = 'website.qweb.field.integer'
+    _inherit = ['website.qweb.field']
+
+    value_from_string = int
+
 class Float(orm.AbstractModel):
     _name = 'website.qweb.field.float'
     _inherit = ['website.qweb.field', 'ir.qweb.field.float']
 
+    value_from_string = float
+
 class Text(orm.AbstractModel):
     _name = 'website.qweb.field.text'
     _inherit = ['website.qweb.field', 'ir.qweb.field.text']
 
+    def from_html(self, cr, uid, model, column, element, context=None):
+        return element.text_content()
+
 class Selection(orm.AbstractModel):
     _name = 'website.qweb.field.selection'
     _inherit = ['website.qweb.field', 'ir.qweb.field.selection']
 
+    def from_html(self, cr, uid, model, column, element, context=None):
+        value = element.text_content().strip()
+        selection = column.reify(cr, uid, model, column, context=context)
+        for k, v in selection:
+            if isinstance(v, str):
+                v = ustr(v)
+            if value == v:
+                return k
+
+        raise ValueError(u"No value found for label %s in selection %s" % (
+                         value, selection))
+
 class ManyToOne(orm.AbstractModel):
     _name = 'website.qweb.field.many2one'
     _inherit = ['website.qweb.field', 'ir.qweb.field.many2one']
 
+    def from_html(self, cr, uid, model, column, element, context=None):
+        # FIXME: this behavior is really weird, what if the user wanted to edit the name of the related thingy? Should m2os really be editable without a widget?
+        matches = self.pool[column._obj].name_search(
+            cr, uid, name=element.text_content().strip(), context=context)
+        # FIXME: no match? More than 1 match?
+        assert len(matches) == 1
+        return matches[0][0]
+
 class HTML(orm.AbstractModel):
     _name = 'website.qweb.field.html'
     _inherit = ['website.qweb.field', 'ir.qweb.field.html']
 
+    def from_html(self, cr, uid, model, column, element, context=None):
+        content = []
+        if element.text: content.append(element.text)
+        content.extend(html.tostring(child)
+                       for child in element.iterchildren(tag=etree.Element))
+        return '\n'.join(content)
+
+
 class Image(orm.AbstractModel):
     """
     Widget options:
diff --git a/addons/website/models/test_models.py b/addons/website/models/test_models.py
new file mode 100644 (file)
index 0000000..d028cdd
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+from openerp.osv import orm, fields
+
+class test_converter(orm.Model):
+    _name = 'website.converter.test'
+
+    _columns = {
+        'char': fields.char(),
+        'integer': fields.integer(),
+        'float': fields.float(),
+        'numeric': fields.float(digits=(16, 2)),
+        'many2one': fields.many2one('website.converter.test.sub'),
+        'binary': fields.binary(),
+        'date': fields.date(),
+        'datetime': fields.datetime(),
+        'selection': fields.selection([
+            (1, "réponse A"),
+            (2, "réponse B"),
+            (3, "réponse C"),
+            (4, "réponse D"),
+        ]),
+        'selection_str': fields.selection([
+            ('A', "Qu'il n'est pas arrivé à Toronto"),
+            ('B', "Qu'il était supposé arriver à Toronto"),
+            ('C', "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?"),
+            ('D', "La réponse D"),
+        ], string="Lorsqu'un pancake prend l'avion à destination de Toronto et "
+                  "qu'il fait une escale technique à St Claude, on dit:"),
+        'html': fields.html(),
+        'text': fields.text(),
+    }
+
+
+class test_converter_sub(orm.Model):
+    _name = 'website.converter.test.sub'
+
+    _columns = {
+        'name': fields.char(),
+    }
index 6ddae12..aaf2551 100644 (file)
@@ -60,11 +60,9 @@ class view(osv.osv):
         field = el.get('data-oe-field')
 
         column = Model._all_columns[field].column
-        convert = self.pool['ir.fields.converter'].to_field(
-            cr, uid, Model, column, fromtype="html", context=context)
-        value, warnings = convert(el)
-        # FIXME: report error
-        if warnings: return
+        converter = self.pool['website.qweb'].get_converter_for(
+            el.get('data-oe-type'))
+        value = converter.from_html(cr, uid, Model, column, el)
 
         Model.write(cr, uid, [int(el.get('data-oe-id'))], {
             field: value
index bd7d449..b2f2b69 100644 (file)
@@ -1,5 +1,4 @@
 # -*- coding: utf-8 -*-
-from collections import namedtuple
 from functools import partial
 from xml.dom.minidom import getDOMImplementation
 
@@ -10,19 +9,10 @@ from openerp.tests import common
 impl = getDOMImplementation()
 document = impl.createDocument(None, None, None)
 
-Request = namedtuple('Request', 'cr uid registry')
-class RegistryProxy(object):
-    def __init__(self, func):
-        self.func = func
-    def __getitem__(self, name):
-        return self.func(name)
-
 class TestConvertBack(common.TransactionCase):
     def setUp(self):
         super(TestConvertBack, self).setUp()
 
-        self.Converter = self.registry('ir.fields.converter')
-
     def field_rountrip_result(self, field, value, expected):
         model = 'website.converter.test'
         Model = self.registry(model)
@@ -36,7 +26,7 @@ class TestConvertBack(common.TransactionCase):
         field_value = 'record.%s' % field
         e.setAttribute('t-field', field_value)
 
-        rendered = self.registry('ir.qweb').render_tag_field(
+        rendered = self.registry('website.qweb').render_tag_field(
             e, {'field': field_value}, '', {
                 'record': record,
             })
@@ -44,12 +34,11 @@ class TestConvertBack(common.TransactionCase):
             rendered, parser=html.HTMLParser(encoding='utf-8'))
 
         column = Model._all_columns[field].column
+        converter = self.registry('website.qweb').get_converter_for(
+            element.get('data-oe-type'))
 
-        from_html = self.Converter.to_field(
-            self.cr, self.uid, model, column, 'html')
-
-        value_back, warnings = from_html(element)
-        self.assertEqual(warnings, [])
+        value_back = converter.from_html(
+            self.cr, self.uid, model, column, element)
 
         if isinstance(expected, str):
             expected = expected.decode('utf-8')
index 8fc1128..812981c 100644 (file)
@@ -31,8 +31,8 @@ class TestViewSaving(common.TransactionCase):
                 h.H3("Column 2"),
                 h.UL(
                     h.LI("Item 1"),
-                    h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name'))),
-                    h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone')))
+                    h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char'))),
+                    h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone', type='char')))
                 ))
         )
         self.view_id = self.registry('ir.ui.view').create(self.cr, self.uid, {
@@ -46,14 +46,15 @@ class TestViewSaving(common.TransactionCase):
             self.cr, self.uid, self.arch, context=None)
 
         expect = [
-            h.SPAN("My Company", attrs(model='res.company', id=1, field='name')),
-            h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone')),
+            h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char')),
+            h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone', type='char')),
         ]
         for actual, expected in itertools.izip_longest(fields, expect):
             self.eq(actual, expected)
 
     def test_embedded_save(self):
-        embedded = h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone'))
+        embedded = h.SPAN("+00 00 000 00 0 000", attrs(
+            model='res.company', id=1, field='phone', type='char'))
 
         self.registry('ir.ui.view').save_embedded_field(self.cr, self.uid, embedded)
 
@@ -118,8 +119,8 @@ class TestViewSaving(common.TransactionCase):
                 h.H3("Column 2"),
                 h.UL(
                     h.LI("Item 1"),
-                    h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name'))),
-                    h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone')))
+                    h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char'))),
+                    h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone', type='char')))
                 ))
         ))
 
@@ -137,8 +138,8 @@ class TestViewSaving(common.TransactionCase):
             h.H3("Column 2"),
             h.UL(
                 h.LI("wob wob wob"),
-                h.LI(h.SPAN("Acme Corporation", attrs(model='res.company', id=1, field='name', expression="bob"))),
-                h.LI(h.SPAN("+12 3456789", attrs(model='res.company', id=1, field='phone', expression="edmund"))),
+                h.LI(h.SPAN("Acme Corporation", attrs(model='res.company', id=1, field='name', expression="bob", type='char'))),
+                h.LI(h.SPAN("+12 3456789", attrs(model='res.company', id=1, field='phone', expression="edmund", type='char'))),
             )
         ), encoding='utf-8')
         View.save(self.cr, self.uid, res_id=self.view_id, value=replacement,
@@ -173,7 +174,7 @@ class TestViewSaving(common.TransactionCase):
 
         node = html.tostring(h.SPAN(
             "Acme Corporation",
-            attrs(model='res.company', id=company_id, field="name", expression='bob')))
+            attrs(model='res.company', id=company_id, field="name", expression='bob', type='char')))
 
         self.registry('ir.ui.view').save(self.cr, self.uid, res_id=company_id,value=node)
 
@@ -184,7 +185,9 @@ class TestViewSaving(common.TransactionCase):
     def test_field_tail(self):
         View = self.registry('ir.ui.view')
         replacement = ET.tostring(
-            h.LI(h.SPAN("+12 3456789", attrs(model='res.company', id=1, field='phone', expression="edmund")),
+            h.LI(h.SPAN("+12 3456789", attrs(
+                        model='res.company', id=1, type='char',
+                        field='phone', expression="edmund")),
                  "whop whop"
         ), encoding="utf-8")
         View.save(self.cr, self.uid, res_id = self.view_id, value=replacement,
@@ -203,7 +206,7 @@ class TestViewSaving(common.TransactionCase):
                     h.H3("Column 2"),
                     h.UL(
                         h.LI("Item 1"),
-                        h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name'))),
+                        h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char'))),
                         h.LI(h.SPAN({'t-field': "edmund"}), "whop whop"),
                     ))
             )