remove most 3.10 bw compat
authorAurelien Campeas <aurelien.campeas@logilab.fr>
Fri, 02 May 2014 17:57:37 +0200
changeset 10006 8391bf718485
parent 10005 7769d0f61810
child 10007 727bbb361ed1
remove most 3.10 bw compat Related to #3799117. The boxes and entityvcomponent objects cannot really be removed as they are still used throughout the code base (and possible cubes). This may be caused by a non-working deprecation and needs some more work.
devtools/htmlparser.py
doc/3.20.rst
entity.py
server/hook.py
view.py
web/component.py
web/formfields.py
web/request.py
web/test/unittest_form.py
web/views/formrenderers.py
web/views/forms.py
web/views/ibreadcrumbs.py
web/views/idownloadable.py
web/views/primary.py
web/views/workflow.py
--- a/devtools/htmlparser.py	Fri May 02 17:41:11 2014 +0200
+++ b/devtools/htmlparser.py	Fri May 02 17:57:37 2014 +0200
@@ -176,23 +176,6 @@
         return super(XMLSyntaxValidator, self)._parse(data)
 
 
-class XMLDemotingValidator(XMLValidator):
-    """ some views produce html instead of xhtml, using demote_to_html
-
-    this is typically related to the use of external dependencies
-    which do not produce valid xhtml (google maps, ...)
-    """
-    __metaclass__ = class_deprecated
-    __deprecation_warning__ = '[3.10] this is now handled in testlib.py'
-
-    def preprocess_data(self, data):
-        if data.startswith('<?xml'):
-            self.parser = etree.XMLParser()
-        else:
-            self.parser = etree.HTMLParser()
-        return data
-
-
 class HTMLValidator(Validator):
 
     def __init__(self):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/3.20.rst	Fri May 02 17:57:37 2014 +0200
@@ -0,0 +1,8 @@
+What's new in CubicWeb 3.20
+===========================
+
+Deprecated Code Drops
+----------------------
+
+* most 3.10 backward compat is gone (box related objects are still
+  there, but you are encouraged to not depend on them)
--- a/entity.py	Fri May 02 17:41:11 2014 +0200
+++ b/entity.py	Fri May 02 17:57:37 2014 +0200
@@ -1367,100 +1367,6 @@
     def clear_all_caches(self):
         return self.cw_clear_all_caches()
 
-    @property
-    @deprecated('[3.10] use entity.cw_edited')
-    def edited_attributes(self):
-        return self.cw_edited
-
-    @property
-    @deprecated('[3.10] use entity.cw_edited.skip_security')
-    def skip_security_attributes(self):
-        return self.cw_edited.skip_security
-
-    @property
-    @deprecated('[3.10] use entity.cw_edited.skip_security')
-    def _cw_skip_security_attributes(self):
-        return self.cw_edited.skip_security
-
-    @property
-    @deprecated('[3.10] use entity.cw_edited.querier_pending_relations')
-    def querier_pending_relations(self):
-        return self.cw_edited.querier_pending_relations
-
-    @deprecated('[3.10] use key in entity.cw_attr_cache')
-    def __contains__(self, key):
-        return key in self.cw_attr_cache
-
-    @deprecated('[3.10] iter on entity.cw_attr_cache')
-    def __iter__(self):
-        return iter(self.cw_attr_cache)
-
-    @deprecated('[3.10] use entity.cw_attr_cache[attr]')
-    def __getitem__(self, key):
-        return self.cw_attr_cache[key]
-
-    @deprecated('[3.10] use entity.cw_attr_cache.get(attr[, default])')
-    def get(self, key, default=None):
-        return self.cw_attr_cache.get(key, default)
-
-    @deprecated('[3.10] use entity.cw_attr_cache.clear()')
-    def clear(self):
-        self.cw_attr_cache.clear()
-        # XXX clear cw_edited ?
-
-    @deprecated('[3.10] use entity.cw_edited[attr] = value or entity.cw_attr_cache[attr] = value')
-    def __setitem__(self, attr, value):
-        """override __setitem__ to update self.cw_edited.
-
-        Typically, a before_[update|add]_hook could do::
-
-            entity['generated_attr'] = generated_value
-
-        and this way, cw_edited will be updated accordingly. Also, add
-        the attribute to skip_security since we don't want to check security
-        for such attributes set by hooks.
-        """
-        try:
-            self.cw_edited[attr] = value
-        except AttributeError:
-            self.cw_attr_cache[attr] = value
-
-    @deprecated('[3.10] use del entity.cw_edited[attr]')
-    def __delitem__(self, attr):
-        """override __delitem__ to update self.cw_edited on cleanup of
-        undesired changes introduced in the entity's dict. For example, see the
-        code snippet below from the `forge` cube:
-
-        .. sourcecode:: python
-
-            edited = self.entity.cw_edited
-            has_load_left = 'load_left' in edited
-            if 'load' in edited and self.entity.load_left is None:
-                self.entity.load_left = self.entity['load']
-            elif not has_load_left and edited:
-                # cleanup, this may cause undesired changes
-                del self.entity['load_left']
-        """
-        del self.cw_edited[attr]
-
-    @deprecated('[3.10] use entity.cw_edited.setdefault(attr, default)')
-    def setdefault(self, attr, default):
-        """override setdefault to update self.cw_edited"""
-        return self.cw_edited.setdefault(attr, default)
-
-    @deprecated('[3.10] use entity.cw_edited.pop(attr[, default])')
-    def pop(self, attr, *args):
-        """override pop to update self.cw_edited on cleanup of
-        undesired changes introduced in the entity's dict. See `__delitem__`
-        """
-        return self.cw_edited.pop(attr, *args)
-
-    @deprecated('[3.10] use entity.cw_edited.update(values)')
-    def update(self, values):
-        """override update to update self.cw_edited. See `__setitem__`
-        """
-        self.cw_edited.update(values)
-
 
 # attribute and relation descriptors ##########################################
 
--- a/server/hook.py	Fri May 02 17:41:11 2014 +0200
+++ b/server/hook.py	Fri May 02 17:57:37 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -415,10 +415,6 @@
 for event in ALL_HOOKS:
     CWRegistryStore.REGISTRY_FACTORY['%s_hooks' % event] = HooksRegistry
 
-@deprecated('[3.10] use entity.cw_edited.oldnewvalue(attr)')
-def entity_oldnewvalue(entity, attr):
-    return entity.cw_edited.oldnewvalue(attr)
-
 
 # some hook specific predicates #################################################
 
@@ -763,10 +759,6 @@
 
     def handle_event(self, event):
         """delegate event handling to the opertaion"""
-        if event == 'postcommit_event' and hasattr(self, 'commit_event'):
-            warn('[3.10] %s: commit_event method has been replaced by postcommit_event'
-                 % self.__class__, DeprecationWarning)
-            self.commit_event() # pylint: disable=E1101
         getattr(self, event)()
 
     def precommit_event(self):
@@ -903,58 +895,6 @@
         return self._container
 
 
-@deprecated('[3.10] use opcls.get_instance(cnx, **opkwargs).add_data(value)')
-def set_operation(cnx, datakey, value, opcls, containercls=set, **opkwargs):
-    """Function to ease applying a single operation on a set of data, avoiding
-    to create as many as operation as they are individual modification. You
-    should try to use this instead of creating on operation for each `value`,
-    since handling operations becomes coslty on massive data import.
-
-    Arguments are:
-
-    * `cnx`, the current connection
-
-    * `datakey`, a specially forged key that will be used as key in
-      cnx.transaction_data
-
-    * `value` that is the actual payload of an individual operation
-
-    * `opcls`, the class of the operation. An instance is created on the first
-      call for the given key, and then subsequent calls will simply add the
-      payload to the container (hence `opkwargs` is only used on that first
-      call)
-
-    * `containercls`, the container class that should be instantiated to hold
-      payloads.  An instance is created on the first call for the given key, and
-      then subsequent calls will add the data to the existing container. Default
-      to a set. Give `list` if you want to keep arrival ordering.
-
-    * more optional parameters to give to the operation (here the rtype which do not
-      vary accross operations).
-
-    The body of the operation must then iterate over the values that have been mapped
-    in the transaction_data dictionary to the forged key, e.g.:
-
-    .. sourcecode:: python
-
-           for value in self._cw.transaction_data.pop(datakey):
-               ...
-
-    .. Note::
-       **poping** the key from `transaction_data` is not an option, else you may
-       get unexpected data loss in some case of nested hooks.
-    """
-    try:
-        # Search for cnx.transaction_data[`datakey`] (expected to be a set):
-        # if found, simply append `value`
-        _container_add(cnx.transaction_data[datakey], value)
-    except KeyError:
-        # else, initialize it to containercls([`value`]) and instantiate the given
-        # `opcls` operation class with additional keyword arguments
-        opcls(cnx, **opkwargs)
-        cnx.transaction_data[datakey] = containercls()
-        _container_add(cnx.transaction_data[datakey], value)
-
 
 class LateOperation(Operation):
     """special operation which should be called after all possible (ie non late)
--- a/view.py	Fri May 02 17:41:11 2014 +0200
+++ b/view.py	Fri May 02 17:57:37 2014 +0200
@@ -290,12 +290,6 @@
             clabel = vtitle
         return u'%s (%s)' % (clabel, self._cw.property_value('ui.site-title'))
 
-    @deprecated('[3.10] use vreg["etypes"].etype_class(etype).cw_create_url(req)')
-    def create_url(self, etype, **kwargs):
-        """ return the url of the entity creation form for a given entity type"""
-        return self._cw.vreg["etypes"].etype_class(etype).cw_create_url(
-            self._cw, **kwargs)
-
     def field(self, label, value, row=True, show_label=True, w=None, tr=True,
               table=False):
         """read-only field"""
@@ -505,10 +499,6 @@
     def domid(self):
         return domid(self.__regid__)
 
-    @deprecated('[3.10] use .domid property')
-    def div_id(self):
-        return self.domid
-
 
 class Component(ReloadableMixIn, View):
     """base class for components"""
@@ -526,10 +516,6 @@
     def domid(self):
         return '%sComponent' % domid(self.__regid__)
 
-    @deprecated('[3.10] use .cssclass property')
-    def div_class(self):
-        return self.cssclass
-
 
 class Adapter(AppObject):
     """base class for adapters"""
--- a/web/component.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/component.py	Fri May 02 17:57:37 2014 +0200
@@ -270,7 +270,7 @@
     layout_id = None # to be defined in concret class
     layout_args = {}
 
-    def layout_render(self, w):
+    def layout_render(self, w, **kwargs):
         getlayout = self._cw.vreg['components'].select
         layout = getlayout(self.layout_id, self._cw, **self.layout_select_args())
         layout.render(w)
@@ -331,19 +331,8 @@
     title = None
     layout_id = 'component_layout'
 
-    # XXX support kwargs for compat with old boxes which gets the view as
-    # argument
     def render(self, w, **kwargs):
-        if hasattr(self, 'call'):
-            warn('[3.10] should not anymore implement call on %s, see new CtxComponent api'
-                 % self.__class__, DeprecationWarning)
-            self.w = w
-            def wview(__vid, rset=None, __fallback_vid=None, **kwargs):
-                self._cw.view(__vid, rset, __fallback_vid, w=self.w, **kwargs)
-            self.wview = wview
-            self.call(**kwargs) # pylint: disable=E1101
-            return
-        self.layout_render(w)
+        self.layout_render(w, **kwargs)
 
     def layout_select_args(self):
         args = super(CtxComponent, self).layout_select_args()
@@ -410,19 +399,6 @@
     def separator(self):
         return Separator()
 
-    @deprecated('[3.10] use action_link() / link()')
-    def box_action(self, action): # XXX action_link
-        return self.build_link(self._cw._(action.title), action.url())
-
-    @deprecated('[3.10] use action_link() / link()')
-    def build_link(self, title, url, **kwargs):
-        if self._cw.selected(url):
-            try:
-                kwargs['klass'] += ' selected'
-            except KeyError:
-                kwargs['klass'] = 'selected'
-        return tags.a(title, href=url, **kwargs)
-
 
 class EntityCtxComponent(CtxComponent):
     """base class for boxes related to a single entity"""
@@ -725,30 +701,3 @@
     def entity_call(self, entity, view=None):
         raise NotImplementedError()
 
-
-class RelatedObjectsVComponent(EntityVComponent):
-    """a section to display some related entities"""
-    __select__ = EntityVComponent.__select__ & partial_has_related_entities()
-
-    vid = 'list'
-    # to be defined in concrete classes
-    rtype = title = None
-
-    def rql(self):
-        """override this method if you want to use a custom rql query"""
-        return None
-
-    def cell_call(self, row, col, view=None):
-        rql = self.rql()
-        if rql is None:
-            entity = self.cw_rset.get_entity(row, col)
-            rset = entity.related(self.rtype, role(self))
-        else:
-            eid = self.cw_rset[row][col]
-            rset = self._cw.execute(self.rql(), {'x': eid})
-        if not rset.rowcount:
-            return
-        self.w(u'<div class="%s">' % self.cssclass)
-        self.w(u'<h4>%s</h4>\n' % self._cw._(self.title).capitalize())
-        self.wview(self.vid, rset)
-        self.w(u'</div>')
--- a/web/formfields.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/formfields.py	Fri May 02 17:57:37 2014 +0200
@@ -349,13 +349,7 @@
     def initial_typed_value(self, form, load_bytes):
         if self.value is not _MARKER:
             if callable(self.value):
-                # pylint: disable=E1102
-                if support_args(self.value, 'form', 'field'):
-                    return self.value(form, self)
-                else:
-                    warn("[3.10] field's value callback must now take form and "
-                         "field as argument (%s)" % self, DeprecationWarning)
-                    return self.value(form)
+                return self.value(form, self)
             return self.value
         formattr = '%s_%s_default' % (self.role, self.name)
         if self.eidparam and self.role is not None:
--- a/web/request.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/request.py	Fri May 02 17:57:37 2014 +0200
@@ -439,10 +439,6 @@
         """
         self.add_js('cubicweb.ajax.js')
         jsfunc = kwargs.pop('jsfunc', 'userCallbackThenReloadPage')
-        if 'msg' in kwargs:
-            warn('[3.10] msg should be given as positional argument',
-                 DeprecationWarning, stacklevel=2)
-            args = (kwargs.pop('msg'),) + args
         assert not kwargs, 'dunno what to do with remaining kwargs: %s' % kwargs
         cbname = self.register_onetime_callback(cb, *cbargs)
         return "javascript: %s" % getattr(js, jsfunc)(cbname, *args)
--- a/web/test/unittest_form.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/test/unittest_form.py	Fri May 02 17:57:37 2014 +0200
@@ -104,7 +104,9 @@
             req.form['__linkto'] = 'in_group:%s:subject' % geid
             form = self.vreg['forms'].select('edition', req, entity=e)
             form.content_type = 'text/html'
-            pageinfo = self._check_html(form.render(), form, template=None)
+            data = []
+            form.render(w=data.append)
+            pageinfo = self._check_html(u'\n'.join(data), form, template=None)
             inputs = pageinfo.find_tag('select', False)
             ok = False
             for selectnode in pageinfo.matching_nodes('select', name='from_in_group-subject:A'):
@@ -133,14 +135,18 @@
                 creation_date = DateTimeField(widget=DateTimePicker)
             form = CustomChangeStateForm(req, redirect_path='perdu.com',
                                          entity=req.user)
-            form.render(formvalues=dict(state=123, trcomment=u'',
+            data = []
+            form.render(w=data.append,
+                        formvalues=dict(state=123, trcomment=u'',
                                         trcomment_format=u'text/plain'))
 
     def test_change_state_form(self):
         with self.admin_access.web_request() as req:
             form = ChangeStateForm(req, redirect_path='perdu.com',
                                    entity=req.user)
-            form.render(formvalues=dict(state=123, trcomment=u'',
+            data = []
+            form.render(w=data.append,
+                        formvalues=dict(state=123, trcomment=u'',
                                         trcomment_format=u'text/plain'))
 
     # fields tests ############################################################
--- a/web/views/formrenderers.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/views/formrenderers.py	Fri May 02 17:57:37 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -142,12 +142,7 @@
         help = []
         descr = field.help
         if callable(descr):
-            if support_args(descr, 'form', 'field'):
-                descr = descr(form, field)
-            else:
-                warn("[3.10] field's help callback must now take form and field as argument (%s)"
-                     % field, DeprecationWarning)
-                descr = descr(form)
+            descr = descr(form, field)
         if descr:
             help.append('<div class="helper">%s</div>' % self._cw._(descr))
         example = field.example_format(self._cw)
--- a/web/views/forms.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/views/forms.py	Fri May 02 17:57:37 2014 +0200
@@ -197,24 +197,10 @@
         Extra keyword arguments will be given to renderer's :meth:`render` method.
         """
         w = kwargs.pop('w', None)
-        if w is None:
-            warn('[3.10] you should specify "w" to form.render() named arguments',
-                 DeprecationWarning, stacklevel=2)
-            data = []
-            w = data.append
-        else:
-            data = None
         self.build_context(formvalues)
         if renderer is None:
             renderer = self.default_renderer()
-        if support_args(renderer.render, 'w'):
-            renderer.render(w, self, kwargs)
-        else:
-            warn('[3.10] you should add "w" as first argument o %s.render()'
-                 % renderer.__class__, DeprecationWarning)
-            w(renderer.render(self, kwargs))
-        if data is not None:
-            return '\n'.join(data)
+        renderer.render(w, self, kwargs)
 
     def default_renderer(self):
         return self._cw.vreg['formrenderers'].select(
--- a/web/views/ibreadcrumbs.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/views/ibreadcrumbs.py	Fri May 02 17:57:37 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -64,16 +64,9 @@
         """
         parent = self.parent_entity()
         if parent is not None:
-            if recurs is True:
-                _recurs = set()
-                warn('[3.10] recurs argument should be a set() or None',
-                     DeprecationWarning, stacklevel=2)
-            elif recurs:
+            if recurs:
                 _recurs = recurs
             else:
-                if recurs is False:
-                    warn('[3.10] recurs argument should be a set() or None',
-                         DeprecationWarning, stacklevel=2)
                 _recurs = set()
             if _recurs and parent.eid in _recurs:
                 self.error('cycle in breadcrumbs for entity %s' % self.entity)
--- a/web/views/idownloadable.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/views/idownloadable.py	Fri May 02 17:57:37 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -34,23 +34,6 @@
 from cubicweb.web.views import primary, baseviews
 
 
-@deprecated('[3.10] use a custom IDownloadable adapter instead')
-def download_box(w, entity, title=None, label=None, footer=u''):
-    req = entity._cw
-    w(u'<div class="sideBox">')
-    if title is None:
-        title = req._('download')
-    w(u'<div class="sideBoxTitle downloadBoxTitle"><span>%s</span></div>'
-      % xml_escape(title))
-    w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">')
-    w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
-      % (xml_escape(entity.cw_adapt_to('IDownloadable').download_url()),
-         req.uiprops['DOWNLOAD_ICON'],
-         req._('download icon'), xml_escape(label or entity.dc_title())))
-    w(u'%s</div>' % footer)
-    w(u'</div></div>\n')
-
-
 class DownloadBox(component.EntityCtxComponent):
     """add download box"""
     __regid__ = 'download_box'    # no download box for images
@@ -175,10 +158,6 @@
         self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' %
                (url, name, durl, self._cw._('download')))
 
-IDownloadableLineView = class_renamed(
-    'IDownloadableLineView', IDownloadableOneLineView,
-    '[3.10] IDownloadableLineView is deprecated, use IDownloadableOneLineView')
-
 
 class AbstractEmbeddedView(EntityView):
     __abstract__ = True
--- a/web/views/primary.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/views/primary.py	Fri May 02 17:57:37 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -131,16 +131,7 @@
             boxes = None
         if boxes or hasattr(self, 'render_side_related'):
             self.w(u'<table width="100%"><tr><td style="width: 75%">')
-        if hasattr(self, 'render_entity_summary'):
-            warn('[3.10] render_entity_summary method is deprecated (%s)' % self,
-                 DeprecationWarning)
-            self.render_entity_summary(entity) # pylint: disable=E1101
 
-        summary = self.summary(entity)
-        if summary:
-            warn('[3.10] summary method is deprecated (%s)' % self,
-                 DeprecationWarning)
-            self.w(u'<div class="summary">%s</div>' % summary)
         self.w(u'<div class="mainInfo">')
         self.content_navigation_components('navcontenttop')
         self.render_entity_attributes(entity)
@@ -189,10 +180,6 @@
     def render_entity_toolbox(self, entity):
         self.content_navigation_components('ctxtoolbar')
 
-    def summary(self, entity):
-        """default implementation return an empty string"""
-        return u''
-
     def render_entity_attributes(self, entity):
         """Renders all attributes and relations in the 'attributes' section. 
         """
@@ -263,23 +250,10 @@
         explicit box appobjects selectable in this context.
         """
         for box in boxes:
-            if isinstance(box, tuple):
-                try:
-                    label, rset, vid, dispctrl  = box
-                except ValueError:
-                    label, rset, vid = box
-                    dispctrl = {}
-                warn('[3.10] box views should now be a RsetBox instance, '
-                     'please update %s' % self.__class__.__name__,
-                     DeprecationWarning)
-                self.w(u'<div class="sideBox">')
-                self.wview(vid, rset, title=label, initargs={'dispctrl': dispctrl})
-                self.w(u'</div>')
-            else:
-                 try:
-                     box.render(w=self.w, row=self.cw_row)
-                 except TypeError:
-                     box.render(w=self.w)
+            try:
+                box.render(w=self.w, row=self.cw_row)
+            except TypeError:
+                box.render(w=self.w)
 
     def _prepare_side_boxes(self, entity):
         sideboxes = []
--- a/web/views/workflow.py	Fri May 02 17:41:11 2014 +0200
+++ b/web/views/workflow.py	Fri May 02 17:57:37 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -169,14 +169,7 @@
     title = _('Workflow history')
 
     def render_body(self, w):
-        if hasattr(self, 'cell_call'):
-            warn('[3.10] %s should now implement render_body instead of cell_call'
-                 % self.__class__, DeprecationWarning)
-            self.w = w
-            # pylint: disable=E1101
-            self.cell_call(self.entity.cw_row, self.entity.cw_col)
-        else:
-            self.entity.view('wfhistory', w=w, title=None)
+        self.entity.view('wfhistory', w=w, title=None)
 
 
 class InContextWithStateView(EntityView):