# HG changeset patch # User Sylvain Thénault # Date 1319794406 -7200 # Node ID a36bd56f33bb892a82c45551415bbc24974f3f9e # Parent 140a093015f84e310b904d1b0733ed91bd808d7b [diet] move iprogress to its own cube. Closes #1916016 diff -r 140a093015f8 -r a36bd56f33bb entities/adapters.py --- a/entities/adapters.py Fri Oct 28 11:33:25 2011 +0200 +++ b/entities/adapters.py Fri Oct 28 11:33:26 2011 +0200 @@ -26,15 +26,15 @@ from logilab.mtconverter import TransformError from logilab.common.decorators import cached +from logilab.common.deprecation import class_deprecated -from cubicweb import ValidationError -from cubicweb.view import EntityAdapter, implements_adapter_compat +from cubicweb import ValidationError, view from cubicweb.selectors import (implements, is_instance, relation_possible, match_exception) from cubicweb.interfaces import IDownloadable, ITree, IProgress, IMileStone -class IEmailableAdapter(EntityAdapter): +class IEmailableAdapter(view.EntityAdapter): __regid__ = 'IEmailable' __select__ = relation_possible('primary_email') | relation_possible('use_email') @@ -67,12 +67,12 @@ for attr in self.allowed_massmail_keys() ) -class INotifiableAdapter(EntityAdapter): +class INotifiableAdapter(view.EntityAdapter): __needs_bw_compat__ = True __regid__ = 'INotifiable' __select__ = is_instance('Any') - @implements_adapter_compat('INotifiableAdapter') + @view.implements_adapter_compat('INotifiableAdapter') def notification_references(self, view): """used to control References field of email send on notification for this entity. `view` is the notification view. @@ -86,7 +86,7 @@ return () -class IFTIndexableAdapter(EntityAdapter): +class IFTIndexableAdapter(view.EntityAdapter): __regid__ = 'IFTIndexable' __select__ = is_instance('Any') @@ -156,35 +156,35 @@ for weight, words in newdict.iteritems(): maindict.setdefault(weight, []).extend(words) -class IDownloadableAdapter(EntityAdapter): +class IDownloadableAdapter(view.EntityAdapter): """interface for downloadable entities""" __needs_bw_compat__ = True __regid__ = 'IDownloadable' __select__ = implements(IDownloadable, warn=False) # XXX for bw compat, else should be abstract - @implements_adapter_compat('IDownloadable') + @view.implements_adapter_compat('IDownloadable') def download_url(self, **kwargs): # XXX not really part of this interface """return an url to download entity's content""" raise NotImplementedError - @implements_adapter_compat('IDownloadable') + @view.implements_adapter_compat('IDownloadable') def download_content_type(self): """return MIME type of the downloadable content""" raise NotImplementedError - @implements_adapter_compat('IDownloadable') + @view.implements_adapter_compat('IDownloadable') def download_encoding(self): """return encoding of the downloadable content""" raise NotImplementedError - @implements_adapter_compat('IDownloadable') + @view.implements_adapter_compat('IDownloadable') def download_file_name(self): """return file name of the downloadable content""" raise NotImplementedError - @implements_adapter_compat('IDownloadable') + @view.implements_adapter_compat('IDownloadable') def download_data(self): """return actual data of the downloadable content""" raise NotImplementedError # XXX should propose to use two different relations for children/parent -class ITreeAdapter(EntityAdapter): +class ITreeAdapter(view.EntityAdapter): """This adapter has to be overriden to be configured using the tree_relation, child_role and parent_role class attributes to benefit from this default implementation. @@ -225,12 +225,12 @@ return self.entity.tree_attribute # XXX should be removed from the public interface - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def children_rql(self): """Returns RQL to get the children of the entity.""" return self.entity.cw_related_rql(self.tree_relation, self.parent_role) - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def different_type_children(self, entities=True): """Return children entities of different type as this entity. @@ -244,7 +244,7 @@ return [e for e in res if e.e_schema != eschema] return res.filtered_rset(lambda x: x.e_schema != eschema, self.entity.cw_col) - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def same_type_children(self, entities=True): """Return children entities of the same type as this entity. @@ -258,23 +258,23 @@ return [e for e in res if e.e_schema == eschema] return res.filtered_rset(lambda x: x.e_schema is eschema, self.entity.cw_col) - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def is_leaf(self): """Returns True if the entity does not have any children.""" return len(self.children()) == 0 - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def is_root(self): """Returns true if the entity is root of the tree (e.g. has no parent). """ return self.parent() is None - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def root(self): """Return the root entity of the tree.""" return self._cw.entity_from_eid(self.path()[0]) - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def parent(self): """Returns the parent entity if any, else None (e.g. if we are on the root). @@ -285,7 +285,7 @@ except (KeyError, IndexError): return None - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def children(self, entities=True, sametype=False): """Return children entities. @@ -298,7 +298,7 @@ return self.entity.related(self.tree_relation, self.parent_role, entities=entities) - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def iterparents(self, strict=True): """Return an iterator on the parents of the entity.""" def _uptoroot(self): @@ -313,7 +313,7 @@ return chain([self.entity], _uptoroot(self)) return _uptoroot(self) - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def iterchildren(self, _done=None): """Return an iterator over the item's children.""" if _done is None: @@ -325,7 +325,7 @@ yield child _done.add(child.eid) - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') def prefixiter(self, _done=None): """Return an iterator over the item's descendants in a prefixed order.""" if _done is None: @@ -338,7 +338,7 @@ for entity in child.cw_adapt_to('ITree').prefixiter(_done): yield entity - @implements_adapter_compat('ITree') + @view.implements_adapter_compat('ITree') @cached def path(self): """Returns the list of eids from the root object to this object.""" @@ -363,40 +363,75 @@ return path -class IProgressAdapter(EntityAdapter): +# error handling adapters ###################################################### + +from cubicweb import UniqueTogetherError + +class IUserFriendlyError(view.EntityAdapter): + __regid__ = 'IUserFriendlyError' + __abstract__ = True + def __init__(self, *args, **kwargs): + self.exc = kwargs.pop('exc') + super(IUserFriendlyError, self).__init__(*args, **kwargs) + + +class IUserFriendlyUniqueTogether(IUserFriendlyError): + __select__ = match_exception(UniqueTogetherError) + def raise_user_exception(self): + etype, rtypes = self.exc.args + msg = self._cw._('violates unique_together constraints (%s)') % ( + ', '.join([self._cw._(rtype) for rtype in rtypes])) + raise ValidationError(self.entity.eid, dict((col, msg) for col in rtypes)) + +# deprecated ################################################################### + + +class adapter_deprecated(view.auto_unwrap_bw_compat): + """metaclass to print a warning on instantiation of a deprecated class""" + + def __call__(cls, *args, **kwargs): + msg = getattr(cls, "__deprecation_warning__", + "%(cls)s is deprecated") % {'cls': cls.__name__} + warn(msg, DeprecationWarning, stacklevel=2) + return type.__call__(cls, *args, **kwargs) + + +class IProgressAdapter(view.EntityAdapter): """something that has a cost, a state and a progression. You should at least override progress_info an in_progress methods on concrete implementations. """ + __metaclass__ = adapter_deprecated + __deprecation_warning__ = '[3.14] IProgressAdapter has been moved to iprogress cube' __needs_bw_compat__ = True __regid__ = 'IProgress' __select__ = implements(IProgress, warn=False) # XXX for bw compat, should be abstract @property - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def cost(self): """the total cost""" return self.progress_info()['estimated'] @property - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def revised_cost(self): return self.progress_info().get('estimatedcorrected', self.cost) @property - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def done(self): """what is already done""" return self.progress_info()['done'] @property - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def todo(self): """what remains to be done""" return self.progress_info()['todo'] - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def progress_info(self): """returns a dictionary describing progress/estimated cost of the version. @@ -411,17 +446,17 @@ """ raise NotImplementedError - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def finished(self): """returns True if status is finished""" return not self.in_progress() - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def in_progress(self): """returns True if status is not finished""" raise NotImplementedError - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def progress(self): """returns the % progress of the task item""" try: @@ -432,62 +467,44 @@ return 0. return 100 - @implements_adapter_compat('IProgress') + @view.implements_adapter_compat('IProgress') def progress_class(self): return '' class IMileStoneAdapter(IProgressAdapter): + __metaclass__ = adapter_deprecated + __deprecation_warning__ = '[3.14] IMileStoneAdapter has been moved to iprogress cube' __needs_bw_compat__ = True __regid__ = 'IMileStone' __select__ = implements(IMileStone, warn=False) # XXX for bw compat, should be abstract parent_type = None # specify main task's type - @implements_adapter_compat('IMileStone') + @view.implements_adapter_compat('IMileStone') def get_main_task(self): """returns the main ITask entity""" raise NotImplementedError - @implements_adapter_compat('IMileStone') + @view.implements_adapter_compat('IMileStone') def initial_prevision_date(self): """returns the initial expected end of the milestone""" raise NotImplementedError - @implements_adapter_compat('IMileStone') + @view.implements_adapter_compat('IMileStone') def eta_date(self): """returns expected date of completion based on what remains to be done """ raise NotImplementedError - @implements_adapter_compat('IMileStone') + @view.implements_adapter_compat('IMileStone') def completion_date(self): """returns date on which the subtask has been completed""" raise NotImplementedError - @implements_adapter_compat('IMileStone') + @view.implements_adapter_compat('IMileStone') def contractors(self): """returns the list of persons supposed to work on this task""" raise NotImplementedError - -# error handling adapters ###################################################### - -from cubicweb import UniqueTogetherError - -class IUserFriendlyError(EntityAdapter): - __regid__ = 'IUserFriendlyError' - __abstract__ = True - def __init__(self, *args, **kwargs): - self.exc = kwargs.pop('exc') - super(IUserFriendlyError, self).__init__(*args, **kwargs) - - -class IUserFriendlyUniqueTogether(IUserFriendlyError): - __select__ = match_exception(UniqueTogetherError) - def raise_user_exception(self): - etype, rtypes = self.exc.args - msg = self._cw._('violates unique_together constraints (%s)') % ( - ', '.join([self._cw._(rtype) for rtype in rtypes])) - raise ValidationError(self.entity.eid, dict((col, msg) for col in rtypes)) diff -r 140a093015f8 -r a36bd56f33bb web/views/iprogress.py --- a/web/views/iprogress.py Fri Oct 28 11:33:25 2011 +0200 +++ b/web/views/iprogress.py Fri Oct 28 11:33:26 2011 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -22,6 +22,7 @@ from math import floor +from logilab.common.deprecation import class_deprecated from logilab.mtconverter import xml_escape from cubicweb.utils import make_uid @@ -47,6 +48,8 @@ header_for_COLNAME methods allow to customize header's label """ + __metaclass__ = class_deprecated + __deprecation_warning__ = '[3.14] %(cls)s is deprecated' __regid__ = 'progress_table_view' __select__ = adaptable('IMileStone') @@ -59,6 +62,7 @@ _('cost'), _('progress'), _('todo_by')) def cell_call(self, row, col): + x _ = self._cw._ entity = self.cw_rset.get_entity(row, col) infos = {} @@ -150,9 +154,12 @@ """this views redirects to ``progress_table_view`` but removes the ``project`` column """ + __metaclass__ = class_deprecated + __deprecation_warning__ = '[3.14] %(cls)s is deprecated' __regid__ = 'ic_progress_table_view' def call(self, columns=None): + x view = self._cw.vreg['views'].select('progress_table_view', self._cw, rset=self.cw_rset) columns = list(columns or view.columns) @@ -165,6 +172,8 @@ class ProgressBarView(EntityView): """displays a progress bar""" + __metaclass__ = class_deprecated + __deprecation_warning__ = '[3.14] %(cls)s is deprecated' __regid__ = 'progressbar' __select__ = adaptable('IProgress') @@ -196,6 +205,7 @@ return cls.overrun(iprogress) * 100. / budget def cell_call(self, row, col): + x self._cw.add_css('cubicweb.iprogress.css') self._cw.add_js('cubicweb.iprogress.js') entity = self.cw_rset.get_entity(row, col)