# HG changeset patch # User Sylvain Thénault # Date 1316780293 -7200 # Node ID 2172978be23752fdd79b0634f1767be0d33eba08 # Parent 287813c487b790fecdf54b4c32baf95ad66ec487# Parent 0208c65a88a54dcbf4ee5c358045afcebe738478 backport stable diff -r 287813c487b7 -r 2172978be237 appobject.py --- a/appobject.py Fri Sep 23 09:17:37 2011 +0200 +++ b/appobject.py Fri Sep 23 14:18:13 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. @@ -241,7 +241,7 @@ for selector in selectors: try: selector = _instantiate_selector(selector) - except: + except Exception: pass #assert isinstance(selector, Selector), selector if isinstance(selector, cls): diff -r 287813c487b7 -r 2172978be237 cwconfig.py --- a/cwconfig.py Fri Sep 23 09:17:37 2011 +0200 +++ b/cwconfig.py Fri Sep 23 14:18:13 2011 +0200 @@ -144,7 +144,8 @@ from threading import Lock from os.path import (exists, join, expanduser, abspath, normpath, basename, isdir, dirname, splitext) -from warnings import warn +from warnings import warn, filterwarnings + from logilab.common.decorators import cached, classproperty from logilab.common.deprecation import deprecated from logilab.common.logging_ext import set_log_methods, init_log @@ -618,7 +619,7 @@ try: __import__('cubes.%s.ccplugin' % cube) cls.info('loaded cubicweb-ctl plugin from %s', cube) - except: + except Exception: cls.exception('while loading plugin %s', pluginfile) elif exists(oldpluginfile): warn('[3.6] %s: ecplugin module should be renamed to ccplugin' % cube, @@ -626,12 +627,12 @@ try: __import__('cubes.%s.ecplugin' % cube) cls.info('loaded cubicweb-ctl plugin from %s', cube) - except: + except Exception: cls.exception('while loading plugin %s', oldpluginfile) elif exists(initfile): try: __import__('cubes.%s' % cube) - except: + except Exception: cls.exception('while loading cube %s', cube) else: cls.warning('no __init__ file in cube %s', cube) @@ -696,6 +697,9 @@ return vregpath def __init__(self, debugmode=False): + if debugmode: + # in python 2.7, DeprecationWarning are not shown anymore by default + filterwarnings('default', category=DeprecationWarning) register_stored_procedures() self._cubes = None super(CubicWebNoAppConfiguration, self).__init__() diff -r 287813c487b7 -r 2172978be237 cwctl.py --- a/cwctl.py Fri Sep 23 09:17:37 2011 +0200 +++ b/cwctl.py Fri Sep 23 14:18:13 2011 +0200 @@ -554,7 +554,7 @@ pid = int(open(pidf).read().strip()) try: kill(pid, signal.SIGTERM) - except: + except Exception: print >> sys.stderr, "process %s seems already dead." % pid else: try: @@ -564,7 +564,7 @@ print >> sys.stderr, 'trying SIGKILL' try: kill(pid, signal.SIGKILL) - except: + except Exception: # probably dead now pass wait_process_end(pid) diff -r 287813c487b7 -r 2172978be237 dataimport.py --- a/dataimport.py Fri Sep 23 09:17:37 2011 +0200 +++ b/dataimport.py Fri Sep 23 14:18:13 2011 +0200 @@ -554,7 +554,7 @@ self.tell("Run import function '%s'..." % func_name) try: func(self) - except: + except Exception: if self.catcherrors: self.record_error(func_name, 'While calling %s' % func.__name__) else: diff -r 287813c487b7 -r 2172978be237 dbapi.py --- a/dbapi.py Fri Sep 23 09:17:37 2011 +0200 +++ b/dbapi.py Fri Sep 23 14:18:13 2011 +0200 @@ -301,7 +301,7 @@ def set_default_language(self, vreg): try: self.lang = vreg.property_value('ui.language') - except: # property may not be registered + except Exception: # property may not be registered self.lang = 'en' # use req.__ to translate a message without registering it to the catalog try: @@ -532,7 +532,7 @@ if self._closed is None and self._close_on_del: try: self.close() - except: + except Exception: pass # connection initialization methods ######################################## diff -r 287813c487b7 -r 2172978be237 devtools/__init__.py --- a/devtools/__init__.py Fri Sep 23 09:17:37 2011 +0200 +++ b/devtools/__init__.py Fri Sep 23 14:18:13 2011 +0200 @@ -577,7 +577,7 @@ templcursor.close() cnx.close() init_repository(self.config, interactive=False) - except: + except BaseException: if self.dbcnx is not None: self.dbcnx.rollback() print >> sys.stderr, 'building', self.dbname, 'failed' @@ -752,13 +752,13 @@ value = value.rsplit('.', 1)[0] try: row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S') - except: + except Exception: row[cellindex] = strptime(value, '%Y-%m-%d') if vtype == 'Time' and type(value) is unicode: found_date = True try: row[cellindex] = strptime(value, '%H:%M:%S') - except: + except Exception: # DateTime used as Time? row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S') if vtype == 'Interval' and type(value) is int: diff -r 287813c487b7 -r 2172978be237 devtools/fill.py --- a/devtools/fill.py Fri Sep 23 09:17:37 2011 +0200 +++ b/devtools/fill.py Fri Sep 23 14:18:13 2011 +0200 @@ -352,7 +352,7 @@ if objtype: rql += ', %s is %s' % (selectvar, objtype) rset = cursor.execute(rql) - except: + except Exception: print "could restrict eid_list with given constraints (%r)" % constraints return [] return set(eid for eid, in rset.rows) diff -r 287813c487b7 -r 2172978be237 devtools/stresstester.py --- a/devtools/stresstester.py Fri Sep 23 09:17:37 2011 +0200 +++ b/devtools/stresstester.py Fri Sep 23 14:18:13 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. @@ -38,7 +38,7 @@ -o / --report-output Write profiler report into rather than on stdout -Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. http://www.logilab.fr/ -- mailto:contact@logilab.fr """ @@ -73,9 +73,7 @@ start = clock() try: cursor.execute(query) - except KeyboardInterrupt: - raise - except: + except Exception: TB_LOCK.acquire() traceback.print_exc() TB_LOCK.release() diff -r 287813c487b7 -r 2172978be237 devtools/testlib.py --- a/devtools/testlib.py Fri Sep 23 09:17:37 2011 +0200 +++ b/devtools/testlib.py Fri Sep 23 14:18:13 2011 +0200 @@ -233,7 +233,7 @@ # web resources try: config.global_set_option('embed-allowed', re.compile('.*')) - except: # not in server only configuration + except Exception: # not in server only configuration pass #XXX this doesn't need to a be classmethod anymore @@ -787,15 +787,13 @@ """ try: output = viewfunc(**kwargs) - except (SystemExit, KeyboardInterrupt): - raise - except: + except Exception: # hijack exception: generative tests stop when the exception # is not an AssertionError klass, exc, tcbk = sys.exc_info() try: msg = '[%s in %s] %s' % (klass, view.__regid__, exc) - except: + except Exception: msg = '[%s in %s] undisplayable exception' % (klass, view.__regid__) raise AssertionError, msg, tcbk return self._check_html(output, view, template) @@ -837,9 +835,7 @@ def assertWellFormed(self, validator, content, context=None): try: return validator.parse_string(content) - except (SystemExit, KeyboardInterrupt): - raise - except: + except Exception: # hijack exception: generative tests stop when the exception # is not an AssertionError klass, exc, tcbk = sys.exc_info() @@ -851,7 +847,7 @@ try: str_exc = str(exc) - except: + except Exception: str_exc = 'undisplayable exception' msg += str_exc if content is not None: @@ -1154,7 +1150,7 @@ reg._selected = {} try: orig_select_best = reg.__class__.__orig_select_best - except: + except Exception: orig_select_best = reg.__class__._select_best def instr_select_best(self, *args, **kwargs): selected = orig_select_best(self, *args, **kwargs) diff -r 287813c487b7 -r 2172978be237 doc/book/en/admin/pyro.rst --- a/doc/book/en/admin/pyro.rst Fri Sep 23 09:17:37 2011 +0200 +++ b/doc/book/en/admin/pyro.rst Fri Sep 23 14:18:13 2011 +0200 @@ -1,14 +1,19 @@ Working with a distributed client (using Pyro) ============================================== +.. _UsingPyro: + In some circumstances, it is practical to split the repository and -web-client parts of the application, for load-balancing reasons. Or +web-client parts of the application for load-balancing reasons. Or one wants to access the repository from independant scripts to consult or update the database. +Prerequisites +------------- + For this to work, several steps have to be taken in order. -You must first ensure that the apropriate software is installed and +You must first ensure that the appropriate software is installed and running (see ref:`setup`):: pyro-nsd -x -p 6969 @@ -21,19 +26,40 @@ pyro-instance-id=myinstancename -Finally, the client (for instance in the case of a script) must -connect specifically, as in the following example code: +Connect to the CubicWeb repository from a python script +------------------------------------------------------- + +Assuming pyro-nsd is running and your instance is configured with ``pyro-server=yes``, +you will be able to use :mod:`cubicweb.dbapi` api to initiate the connection. + +.. note:: + Regardless of whether your instance is pyro activated or not, you can still + achieve this by using cubicweb-ctl shell scripts in a simpler way, as by default + it creates a repository 'in-memory' instead of connecting through pyro. That + also means you've to be on the host where the instance is running. + +Finally, the client (for instance a python script) must connect specifically +as in the following example code: .. sourcecode:: python from cubicweb import dbapi - def pyro_connect(instname, login, password, pyro_ns_host): - cnx = dbapi.connect(instname, login, password, pyro_ns_host) - cnx.load_appobjects() - return cnx + cnx = dbapi.connect(database='instance-id', user='admin', password='admin') + cnx.load_appobjects() + cur = cnx.cursor() + for name in (u'Personal', u'Professional', u'Computers'): + cur.execute('INSERT Tag T: T name %(n)s', {'n': name}) + cnx.commit() -The 'cnx.load_appobjects()' line is optional. Without it you will get -data through the connection roughly as you would from a DBAPI -connection. With it, provided the cubicweb-client part is installed -and accessible, you get the ORM goodies. +Calling :meth:`cubicweb.dbapi.load_appobjects`, will populates The `cubicweb +registries`_ with the application objects installed on the host where the script +runs. You'll then be allowed to use the ORM goodies and custom entity methods and +views. Of course this is optional, without it you can still get the repository +data through the connection but in a roughly way: only RQL cursors will be +available, e.g. you can't even build entity objects from the result set. + + + +.. _cubicweb registries: VRegistryIntro_ + diff -r 287813c487b7 -r 2172978be237 doc/book/en/annexes/faq.rst --- a/doc/book/en/annexes/faq.rst Fri Sep 23 09:17:37 2011 +0200 +++ b/doc/book/en/annexes/faq.rst Fri Sep 23 14:18:13 2011 +0200 @@ -148,25 +148,12 @@ to anonymous user, which will automatically execute what is decribed above. -How to load data from a script ? --------------------------------- - -The following script aims at loading data within a script assuming pyro-nsd is -running and your instance is configured with ``pyro-server=yes``, otherwise -you would not be able to use dbapi. - -.. sourcecode:: python +How to load data from a python script ? +--------------------------------------- +Please, refer to the `Pyro chapter`_. - from cubicweb import dbapi +.. _`Pyro chapter`: UsingPyro_ - cnx = dbapi.connect(database='instance-id', user='admin', password='admin') - cur = cnx.cursor() - for name in (u'Personal', u'Professional', u'Computers'): - cur.execute('INSERT Tag T: T name %(n)s', {'n': name}) - cnx.commit() - -Wether your instance as pyro activated or not, you can still acheive this by -using cubicweb-ctl shell scripts. How to format an entity date attribute ? ---------------------------------------- diff -r 287813c487b7 -r 2172978be237 doc/book/en/devweb/views/baseviews.rst --- a/doc/book/en/devweb/views/baseviews.rst Fri Sep 23 09:17:37 2011 +0200 +++ b/doc/book/en/devweb/views/baseviews.rst Fri Sep 23 14:18:13 2011 +0200 @@ -1,137 +1,17 @@ -.. -*- coding: utf-8 -*- - Base views ---------- -*CubicWeb* provides a lot of standard views, that can be found in +|cubicweb| provides a lot of standard views, that can be found in :mod:`cubicweb.web.views` sub-modules. A certain number of views are used to build the web interface, which apply to one -or more entities. As other appobject, Their identifier is what distinguish them +or more entities. As other appobjects, their identifier is what distinguish them from each others. The most generic ones, found in :mod:`cubicweb.web.views.baseviews`, are described below. -HTML views -~~~~~~~~~~ - -Special views -````````````` - -*noresult* - This view is the default view used when no result has been found - (e.g. empty result set). - -*final* - Display the value of a cell without trasnformation (in case of a non final - entity, we see the eid). Applicable on any result set. - -.. note:: - - `final` entities are merely attributes. - -*null* - This view is the default view used when nothing needs to be rendered. - It is always applicable. - - -Entity views -```````````` - -*incontext, outofcontext* - - Those are used to display a link to an entity, whose label depends on the - entity having to be displayed in or out of context (of another entity): some - entities make sense in the context of another entity. For instance, the - `Version` of a `Project` in forge. So one may expect that 'incontext' will - be called when display a version from within the context of a project, while - 'outofcontext"' will be called in other cases. In our example, the - 'incontext' view of the version would be something like '0.1.2', while the - 'outofcontext' view would include the project name, e.g. 'baz 0.1.2' (since - only a version number without the associated project doesn't make sense if - you don't know yet that you're talking about the famous 'baz' project. |cubicweb| - tries to make guess and call 'incontext'/'outofcontext' nicely. When it can't - know, the 'oneline' view should be used. - - By default it respectively produces the result of `textincontext` and - `textoutofcontext` wrapped in a link leading to the primary view of the - entity. - - -*oneline* - - This view is used when we can't tell if the entity should be considered as - displayed in or out of context. By default it produces the result of `text` - in a link leading to the primary view of the entity. +You'll probably want to customize one or more of the described views which are +default, generic, implementations. -List -````` - -*list* - - This view displays a list of entities by creating a HTML list (`
    `) and - call the view `listitem` for each entity of the result set. The 'list' view - will generate html like: - - .. sourcecode:: html - -
      -
    • "result of 'subvid' view for a row
    • - ... -
    - - -*simplelist* - - This view is not 'ul' based, and rely on div behaviour to separate items. html - will look like - - .. sourcecode:: html - -
    "result of 'subvid' view for a row
    - ... - - - It relies on base :class:`~cubicweb.view.View` class implementation of the - :meth:`call` method to insert those
    . - - -*sameetypelist* +.. automodule:: cubicweb.web.views.baseviews - This view displays a list of entities of the same type, in HTML section - (`
    `) and call the view `sameetypelistitem` for each entity of the result - set. It's designed to get a more adapted global list when displayed entities - are all of the same type. - - -*csv* - - This view displays each entity in a coma separated list. It is NOT related to - the well-known text file format. - - -Those list view can be given a 'subvid' arguments, telling the view to use of -each item in the list. When not specified, the value of the 'redirect_vid' -attribute of :class:`ListItemView` (for 'listview') or of :class:`SimpleListView` -will be used. This default to 'outofcontext' for 'list' / 'incontext' for -'simplelist' - - -Text entity views -~~~~~~~~~~~~~~~~~ - -Basic html view have some variantsto be used when generating raw text, not html -(for notifications for instance). - -*text* - - This is the simplest text view for an entity. By default it returns the - result of the `.dc_title` method, which is cut to fit the - `navigation.short-line-size` property if necessary. - -*textincontext, textoutofcontext* - - Similar to the `text` view, but called when an entity is considered out or in - context (see description of incontext/outofcontext html views for more - information on this). By default it returns respectively the result of the - methods `.dc_title()` and `.dc_long_title()` of the entity. diff -r 287813c487b7 -r 2172978be237 doc/book/en/devweb/views/primary.rst --- a/doc/book/en/devweb/views/primary.rst Fri Sep 23 09:17:37 2011 +0200 +++ b/doc/book/en/devweb/views/primary.rst Fri Sep 23 14:18:13 2011 +0200 @@ -10,11 +10,11 @@ It is automatically selected on a one line result set containing an entity. -This view is supposed to render a maximum of informations about the +It lives in the :mod:`cubicweb.web.views.primary` module. + +The *primary* view is supposed to render a maximum of informations about the entity. -It lives in the :mod:`cubicweb.web.views.primary` module. - .. _primary_view_layout: Layout @@ -139,8 +139,6 @@ that can't be done using rql for instance. - - .. sourcecode:: python pv_section = uicfg.primaryview_section @@ -163,62 +161,8 @@ ``tag_subject_of``. To avoid warnings during execution, they should be set to ``'*'``. -Rendering methods and attributes -```````````````````````````````` -The basic layout of a primary view is as in the -:ref:`primary_view_layout` section. This layout is actually drawn by -the `render_entity` method. - -The methods you may want to modify while customizing a ``PrimaryView`` -are: - -*render_entity_title(self, entity)* - Renders the entity title, by default using entity's :meth:`dc_title()` method. - -*render_entity_attributes(self, entity)* - Renders all attributes and relations in the 'attributes' section . The - :attr:`skip_none` attribute controls the display of `None` valued attributes. - -*render_entity_relations(self, entity)* - Renders all relations in the 'relations' section. - -*render_side_boxes(self, entity, boxes)* - Renders side boxes on the right side of the content. This will generate a box - for each relation in the 'sidebox' section, as well as explicit box - appobjects selectable in this context. - -The placement of relations in the relations section or in side boxes -can be controlled through the :ref:`primary_view_configuration` mechanism. - -*content_navigation_components(self, context)* - This method is applicable only for entity type implementing the interface - `IPrevNext`. This interface is for entities which can be linked to a previous - and/or next entity. This method will render the navigation links between - entities of this type, either at the top or at the bottom of the page - given the context (navcontent{top|bottom}). - -Also, please note that by setting the following attributes in your -subclass, you can already customize some of the rendering: - -*show_attr_label* - Renders the attribute label next to the attribute value if set to `True`. - Otherwise, does only display the attribute value. - -*show_rel_label* - Renders the relation label next to the relation value if set to `True`. - Otherwise, does only display the relation value. - -*skip_none* - Does not render an attribute value that is None if set to `True`. - -*main_related_section* - Renders the relations of the entity if set to `True`. - -A good practice is for you to identify the content of your entity type for which -the default rendering does not answer your need so that you can focus on the specific -method (from the list above) that needs to be modified. We do not advise you to -overwrite ``render_entity`` unless you want a completely different layout. +.. automodule:: cubicweb.web.views.primary Example of customization and creation @@ -329,3 +273,4 @@ .. image:: ../../images/lax-book_10-blog-with-two-entries_en.png :alt: a blog and all its entries + diff -r 287813c487b7 -r 2172978be237 doc/tools/pyjsrest.py --- a/doc/tools/pyjsrest.py Fri Sep 23 09:17:37 2011 +0200 +++ b/doc/tools/pyjsrest.py Fri Sep 23 14:18:13 2011 +0200 @@ -102,7 +102,7 @@ for fileid in INDEX_IN_ORDER: try: index.remove(fileid) - except: + except Exception: raise Exception( 'Bad file id %s referenced in INDEX_IN_ORDER in %s, ' 'fix this please' % (fileid, __file__)) diff -r 287813c487b7 -r 2172978be237 entities/adapters.py --- a/entities/adapters.py Fri Sep 23 09:17:37 2011 +0200 +++ b/entities/adapters.py Fri Sep 23 14:18:13 2011 +0200 @@ -1,4 +1,4 @@ -# copyright 2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2010-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -137,7 +137,7 @@ value = entity.printable_value(rschema, format='text/plain') except TransformError: continue - except: + except Exception: self.exception("can't add value of %s to text index for entity %s", rschema, entity.eid) continue diff -r 287813c487b7 -r 2172978be237 entities/authobjs.py --- a/entities/authobjs.py Fri Sep 23 09:17:37 2011 +0200 +++ b/entities/authobjs.py Fri Sep 23 14:18:13 2011 +0200 @@ -82,7 +82,7 @@ prop = self._cw.execute( 'CWProperty X WHERE X pkey %(k)s, X for_user U, U eid %(u)s', {'k': pkey, 'u': self.eid}).get_entity(0, 0) - except: + except Exception: kwargs = dict(pkey=unicode(pkey), value=value) if self.is_in_group('managers'): kwargs['for_user'] = self diff -r 287813c487b7 -r 2172978be237 etwist/server.py --- a/etwist/server.py Fri Sep 23 09:17:37 2011 +0200 +++ b/etwist/server.py Fri Sep 23 14:18:13 2011 +0200 @@ -308,7 +308,7 @@ # so we deferred that part to the cubicweb thread request.process_multipart() return self._render_request(request) - except: + except Exception: errorstream = StringIO() traceback.print_exc(file=errorstream) return HTTPResponse(stream='
    %s
    ' % errorstream.getvalue(), diff -r 287813c487b7 -r 2172978be237 ext/rest.py --- a/ext/rest.py Fri Sep 23 09:17:37 2011 +0200 +++ b/ext/rest.py Fri Sep 23 14:18:13 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. @@ -71,7 +71,7 @@ try: try: eid_num, rest = text.split(u':', 1) - except: + except ValueError: eid_num, rest = text, '#'+text eid_num = int(eid_num) if eid_num < 0: diff -r 287813c487b7 -r 2172978be237 hooks/notification.py --- a/hooks/notification.py Fri Sep 23 09:17:37 2011 +0200 +++ b/hooks/notification.py Fri Sep 23 14:18:13 2011 +0200 @@ -191,7 +191,7 @@ def _call(self): try: title = self.entity.dc_title() - except: + except Exception: # may raise an error during deletion process, for instance due to # missing required relation title = '#%s' % self.entity.eid diff -r 287813c487b7 -r 2172978be237 hooks/syncschema.py --- a/hooks/syncschema.py Fri Sep 23 09:17:37 2011 +0200 +++ b/hooks/syncschema.py Fri Sep 23 14:18:13 2011 +0200 @@ -87,7 +87,7 @@ session.system_sql(str('ALTER TABLE %s ADD %s integer' % (table, column)), rollback_on_failure=False) session.info('added column %s to table %s', column, table) - except: + except Exception: # silent exception here, if this error has not been raised because the # column already exists, index creation will fail anyway session.exception('error while adding column %s to table %s', @@ -221,8 +221,8 @@ cwuser_cls = self.session.vreg['etypes'].etype_class('CWUser') for session in repo._sessions.values(): session.user.__class__ = cwuser_cls - except: - self.critical('error while setting schmea', exc_info=True) + except Exception: + self.critical('error while setting schema', exc_info=True) def rollback_event(self): self.precommit_event() diff -r 287813c487b7 -r 2172978be237 hooks/test/unittest_syncschema.py --- a/hooks/test/unittest_syncschema.py Fri Sep 23 09:17:37 2011 +0200 +++ b/hooks/test/unittest_syncschema.py Fri Sep 23 14:18:13 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. @@ -182,7 +182,7 @@ self.assertFalse(self.index_exists('State', 'state_of')) rset = self.execute('Any X, Y WHERE X state_of Y') self.assertEqual(len(rset), 2) # user states - except: + except Exception: import traceback traceback.print_exc() finally: diff -r 287813c487b7 -r 2172978be237 mail.py --- a/mail.py Fri Sep 23 09:17:37 2011 +0200 +++ b/mail.py Fri Sep 23 14:18:13 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. @@ -67,7 +67,7 @@ values = b64decode(str(values + '='*padding), '.-') values = dict(v.split('=') for v in values.split('&')) fromappid, host = qualif.split('.', 1) - except: + except Exception: return None if appid != fromappid or host != gethostname(): return None diff -r 287813c487b7 -r 2172978be237 migration.py --- a/migration.py Fri Sep 23 09:17:37 2011 +0200 +++ b/migration.py Fri Sep 23 14:18:13 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. @@ -488,7 +488,7 @@ try: oper, version = constraint.split() self.reverse_dependencies[name].add( (oper, version, cube) ) - except: + except Exception: self.warnings.append( 'cube %s depends on %s but constraint badly ' 'formatted: %s' % (cube, name, constraint)) diff -r 287813c487b7 -r 2172978be237 misc/cwdesklets/rqlsensor/__init__.py --- a/misc/cwdesklets/rqlsensor/__init__.py Fri Sep 23 09:17:37 2011 +0200 +++ b/misc/cwdesklets/rqlsensor/__init__.py Fri Sep 23 14:18:13 2011 +0200 @@ -15,9 +15,6 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -""" - -""" import webbrowser reload(webbrowser) @@ -89,7 +86,7 @@ cursor = cnx.cursor() try: rset = cursor.execute(rql) - except: + except Exception: del self._v_cnx raise self._urls = [] @@ -101,7 +98,7 @@ output.set('resultbg[%s]' % i, 'black') try: self._urls.append(base % 'Any X WHERE X eid %s' % line[0]) - except: + except Exception: self._urls.append('') i += 1 diff -r 287813c487b7 -r 2172978be237 misc/migration/3.13.6_Any.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/migration/3.13.6_Any.py Fri Sep 23 14:18:13 2011 +0200 @@ -0,0 +1,1 @@ +sync_schema_props_perms('CWSourceSchemaConfig') diff -r 287813c487b7 -r 2172978be237 req.py --- a/req.py Fri Sep 23 09:17:37 2011 +0200 +++ b/req.py Fri Sep 23 14:18:13 2011 +0200 @@ -66,7 +66,7 @@ self.vreg = vreg try: encoding = vreg.property_value('ui.encoding') - except: # no vreg or property not registered + except Exception: # no vreg or property not registered encoding = 'utf-8' self.encoding = encoding # cache result of execution for (rql expr / eids), diff -r 287813c487b7 -r 2172978be237 rqlrewrite.py --- a/rqlrewrite.py Fri Sep 23 09:17:37 2011 +0200 +++ b/rqlrewrite.py Fri Sep 23 14:18:13 2011 +0200 @@ -337,43 +337,58 @@ """introduce the given snippet in a subquery""" subselect = stmts.Select() snippetrqlst = n.Exists(transformedsnippet.copy(subselect)) + get_rschema = self.schema.rschema aliases = [] - rels_done = set() - for i, (selectvar, snippetvar) in enumerate(varmap): + done = set() + for i, (selectvar, _) in enumerate(varmap): + need_null_test = False subselectvar = subselect.get_variable(selectvar) subselect.append_selected(n.VariableRef(subselectvar)) aliases.append(selectvar) - vi = self.varinfos[i] - need_null_test = False - stinfo = vi['stinfo'] - for rel in stinfo['relations']: - if rel in rels_done: - continue - rels_done.add(rel) - rschema = self.schema.rschema(rel.r_type) - if rschema.final or (rschema.inlined and - not rel in stinfo['rhsrelations']): - rel.children[0].name = selectvar # XXX explain why - subselect.add_restriction(rel.copy(subselect)) - for vref in rel.children[1].iget_nodes(n.VariableRef): - if isinstance(vref.variable, n.ColumnAlias): - # XXX could probably be handled by generating the - # subquery into the detected subquery - raise BadSchemaDefinition( - "cant insert security because of usage two inlined " - "relations in this query. You should probably at " - "least uninline %s" % rel.r_type) - subselect.append_selected(vref.copy(subselect)) - aliases.append(vref.name) - self.select.remove_node(rel) - # when some inlined relation has to be copied in the - # subquery, we need to test that either value is NULL or - # that the snippet condition is satisfied - if rschema.inlined and rel.optional: - need_null_test = True + todo = [(selectvar, self.varinfos[i]['stinfo'])] + while todo: + varname, stinfo = todo.pop() + done.add(varname) + for rel in stinfo['relations'] - stinfo['rhsrelations']: + if rel in done: + continue + done.add(rel) + rschema = get_rschema(rel.r_type) + if rschema.final or rschema.inlined: + rel.children[0].name = varname # XXX explain why + subselect.add_restriction(rel.copy(subselect)) + for vref in rel.children[1].iget_nodes(n.VariableRef): + if isinstance(vref.variable, n.ColumnAlias): + # XXX could probably be handled by generating the + # subquery into the detected subquery + raise BadSchemaDefinition( + "cant insert security because of usage two inlined " + "relations in this query. You should probably at " + "least uninline %s" % rel.r_type) + subselect.append_selected(vref.copy(subselect)) + aliases.append(vref.name) + self.select.remove_node(rel) + # when some inlined relation has to be copied in the + # subquery and that relation is optional, we need to + # test that either value is NULL or that the snippet + # condition is satisfied + if varname == selectvar and rel.optional and rschema.inlined: + need_null_test = True + # also, if some attributes or inlined relation of the + # object variable are accessed, we need to get all those + # from the subquery as well + if vref.name not in done and rschema.inlined: + # we can use vref here define in above for loop + ostinfo = vref.variable.stinfo + for orel in ostinfo['relations'] - ostinfo['rhsrelations']: + orschema = get_rschema(orel.r_type) + if orschema.final or orschema.inlined: + todo.append( (vref.name, ostinfo) ) + break if need_null_test: snippetrqlst = n.Or( - n.make_relation(subselectvar, 'is', (None, None), n.Constant, + n.make_relation(subselect.get_variable(selectvar), 'is', + (None, None), n.Constant, operator='='), snippetrqlst) subselect.add_restriction(snippetrqlst) diff -r 287813c487b7 -r 2172978be237 schemas/base.py --- a/schemas/base.py Fri Sep 23 09:17:37 2011 +0200 +++ b/schemas/base.py Fri Sep 23 14:18:13 2011 +0200 @@ -306,7 +306,6 @@ class CWSourceSchemaConfig(EntityType): __permissions__ = ENTITY_MANAGERS_PERMISSIONS - __unique_together__ = [('cw_for_source', 'cw_schema')] cw_for_source = SubjectRelation( 'CWSource', inlined=True, cardinality='1*', composite='object', __permissions__=RELATION_MANAGERS_PERMISSIONS) diff -r 287813c487b7 -r 2172978be237 server/checkintegrity.py --- a/server/checkintegrity.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/checkintegrity.py Fri Sep 23 14:18:13 2011 +0200 @@ -47,7 +47,7 @@ sqlcursor.execute('SELECT type, source FROM entities WHERE eid=%s' % eid) try: etype, source = sqlcursor.fetchone() - except: + except Exception: eids[eid] = False return False if source and source != 'system': @@ -58,7 +58,7 @@ {'x': eid}): eids[eid] = True return True - except: # TypeResolverError, Unauthorized... + except Exception: # TypeResolverError, Unauthorized... pass eids[eid] = False return False diff -r 287813c487b7 -r 2172978be237 server/migractions.py --- a/server/migractions.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/migractions.py Fri Sep 23 14:18:13 2011 +0200 @@ -161,7 +161,7 @@ migrscript, funcname, *args, **kwargs) except ExecutionError, err: print >> sys.stderr, "-> %s" % err - except: + except BaseException: self.rollback() raise @@ -1374,7 +1374,7 @@ prop = self.rqlexec( 'CWProperty X WHERE X pkey %(k)s, NOT X for_user U', {'k': pkey}, ask_confirm=False).get_entity(0, 0) - except: + except Exception: self.cmd_create_entity('CWProperty', pkey=unicode(pkey), value=value) else: prop.set_attributes(value=value) @@ -1492,14 +1492,14 @@ if not ask_confirm or self.confirm('Execute sql: %s ?' % sql): try: cu = self.session.system_sql(sql, args) - except: + except Exception: ex = sys.exc_info()[1] if self.confirm('Error: %s\nabort?' % ex, pdb=True): raise return try: return cu.fetchall() - except: + except Exception: # no result to fetch return diff -r 287813c487b7 -r 2172978be237 server/msplanner.py --- a/server/msplanner.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/msplanner.py Fri Sep 23 14:18:13 2011 +0200 @@ -1640,7 +1640,7 @@ self._pending_vrefs = [] try: res = self.visit_default(node, newroot, terms)[0] - except: + except Exception: # when a relation isn't supported, we should dereference potentially # introduced variable refs for vref in self._pending_vrefs: diff -r 287813c487b7 -r 2172978be237 server/pool.py --- a/server/pool.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/pool.py Fri Sep 23 14:18:13 2011 +0200 @@ -73,7 +73,7 @@ # catch exceptions, rollback other sources anyway try: cnx.rollback() - except: + except Exception: source.critical('rollback error', exc_info=sys.exc_info()) # error on rollback, the connection is much probably in a really # bad state. Replace it by a new one. @@ -86,12 +86,12 @@ for cu in self._cursors.values(): try: cu.close() - except: + except Exception: continue for _, cnx in self.source_cnxs.values(): try: cnx.close() - except: + except Exception: continue # internals ############################################################### @@ -135,7 +135,7 @@ try: # properly close existing connection if any self.source_cnxs[source.uri][1].close() - except: + except Exception: pass source.info('trying to reconnect') self.source_cnxs[source.uri] = (source, source.get_connection()) diff -r 287813c487b7 -r 2172978be237 server/repository.py --- a/server/repository.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/repository.py Fri Sep 23 14:18:13 2011 +0200 @@ -343,7 +343,7 @@ self.looping_task(cleanup_session_interval, self.clean_sessions) assert isinstance(self._looping_tasks, list), 'already started' for i, (interval, func, args) in enumerate(self._looping_tasks): - self._looping_tasks[i] = task = utils.LoopTask(interval, func, args) + self._looping_tasks[i] = task = utils.LoopTask(self, interval, func, args) self.info('starting task %s with interval %.2fs', task.name, interval) task.start() @@ -412,7 +412,7 @@ cnxset = self._cnxsets_pool.get_nowait() try: cnxset.close(True) - except: + except Exception: self.exception('error while closing %s' % cnxset) continue if self.pyro_registered: @@ -791,7 +791,7 @@ return session.commit() except (ValidationError, Unauthorized): raise - except: + except Exception: self.exception('unexpected error') raise @@ -802,7 +802,7 @@ session = self._get_session(sessionid) session.set_tx_data(txid) session.rollback() - except: + except Exception: self.exception('unexpected error') raise @@ -905,7 +905,7 @@ for sessionid in self._sessions.keys(): try: self.close(sessionid, checkshuttingdown=False) - except: + except Exception: # XXX BaseException? self.exception('error while closing session %s' % sessionid) def clean_sessions(self): diff -r 287813c487b7 -r 2172978be237 server/schemaserial.py --- a/server/schemaserial.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/schemaserial.py Fri Sep 23 14:18:13 2011 +0200 @@ -135,7 +135,7 @@ try: sqlexec('UPDATE deleted_entities SET type=%(n)s WHERE type=%(x)s', {'x': etype, 'n': netype}) - except: + except Exception: pass tocleanup = [eid] tocleanup += (eid for eid, cached in repo._type_source_cache.iteritems() diff -r 287813c487b7 -r 2172978be237 server/serverctl.py --- a/server/serverctl.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/serverctl.py Fri Sep 23 14:18:13 2011 +0200 @@ -248,7 +248,7 @@ cursor.execute, 'DROP USER %s' % user) is not ERROR: print '-> user %s dropped.' % user cnx.commit() - except: + except BaseException: cnx.rollback() raise @@ -363,7 +363,7 @@ createdb(helper, source, dbcnx, cursor) dbcnx.commit() print '-> database %s created.' % dbname - except: + except BaseException: dbcnx.rollback() raise cnx = system_source_cnx(source, special_privs='CREATE LANGUAGE', diff -r 287813c487b7 -r 2172978be237 server/session.py --- a/server/session.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/session.py Fri Sep 23 14:18:13 2011 +0200 @@ -574,7 +574,7 @@ return self.DEFAULT_SECURITY try: return txstore.write_security - except: + except AttributeError: txstore.write_security = self.DEFAULT_SECURITY return txstore.write_security @@ -776,7 +776,7 @@ self._threaddata.ctx_count += 1 try: cnxset.cnxset_set() - except: + except Exception: self._threaddata.cnxset = None self.repo._free_cnxset(cnxset) raise @@ -970,7 +970,7 @@ operation.handle_event('precommit_event') self.pending_operations[:] = processed self.debug('precommit session %s done', self.id) - except: + except BaseException: # if error on [pre]commit: # # * set .failed = True on the operation causing the failure @@ -985,7 +985,7 @@ for operation in reversed(processed): try: operation.handle_event('revertprecommit_event') - except: + except BaseException: self.critical('error while reverting precommit', exc_info=True) # XXX use slice notation since self.pending_operations is a @@ -1000,7 +1000,7 @@ operation.processed = 'postcommit' try: operation.handle_event('postcommit_event') - except: + except BaseException: self.critical('error while postcommit', exc_info=sys.exc_info()) self.debug('postcommit session %s done', self.id) @@ -1031,7 +1031,7 @@ try: operation = self.pending_operations.pop(0) operation.handle_event('rollback_event') - except: + except BaseException: self.critical('rollback error', exc_info=sys.exc_info()) continue cnxset.rollback() diff -r 287813c487b7 -r 2172978be237 server/sources/__init__.py --- a/server/sources/__init__.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/sources/__init__.py Fri Sep 23 14:18:13 2011 +0200 @@ -177,7 +177,7 @@ # cw < 3.10 bw compat try: processed['adapter'] = confdict['adapter'] - except: + except KeyError: pass # check for unknown options if confdict and not confdict.keys() == ['adapter']: diff -r 287813c487b7 -r 2172978be237 server/sources/extlite.py --- a/server/sources/extlite.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/sources/extlite.py Fri Sep 23 14:18:13 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. @@ -296,7 +296,7 @@ try: session.cnxset.connection(self.uri).rollback() self.critical('transaction has been rollbacked') - except: + except Exception: pass raise return cursor diff -r 287813c487b7 -r 2172978be237 server/sources/ldapuser.py --- a/server/sources/ldapuser.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/sources/ldapuser.py Fri Sep 23 14:18:13 2011 +0200 @@ -273,7 +273,7 @@ if self._conn is None: try: self._connect() - except: + except Exception: self.exception('unable to connect to ldap:') return ConnectionWrapper(self._conn) @@ -570,7 +570,7 @@ try: for i in range(len(value)): value[i] = unicode(value[i], 'utf8') - except: + except Exception: pass if isinstance(value, list) and len(value) == 1: rec_dict[key] = value = value[0] diff -r 287813c487b7 -r 2172978be237 server/sources/native.py --- a/server/sources/native.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/sources/native.py Fri Sep 23 14:18:13 2011 +0200 @@ -413,7 +413,8 @@ self.init_creating(source_entity._cw.cnxset) try: # test if 'asource' column exists - source_entity._cw.system_sql('SELECT asource FROM entities LIMIT 1') + query = self.dbhelper.sql_add_limit_offset('SELECT asource FROM entities', 1) + source_entity._cw.system_sql(query) except Exception, ex: self.eid_type_source = self.eid_type_source_pre_131 diff -r 287813c487b7 -r 2172978be237 server/sources/pyrorql.py --- a/server/sources/pyrorql.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/sources/pyrorql.py Fri Sep 23 14:18:13 2011 +0200 @@ -226,7 +226,7 @@ self.cross_relations.remove(ertype) else: self.dont_cross_relations.remove(ertype) - except: + except Exception: self.error('while updating mapping consequently to removal of %s', schemacfg) @@ -275,7 +275,7 @@ entity = rset.get_entity(0, 0) entity.complete(entity.e_schema.indexable_attributes()) source.index_entity(session, entity) - except: + except Exception: self.exception('while updating %s with external id %s of source %s', etype, extid, self.uri) continue @@ -288,7 +288,7 @@ entity = session.entity_from_eid(eid, etype) repo.delete_info(session, entity, self.uri, extid, scleanup=self.eid) - except: + except Exception: self.exception('while updating %s with external id %s of source %s', etype, extid, self.uri) continue @@ -667,7 +667,7 @@ value = const.eval(self.kwargs) try: return None, self._const_var[value] - except: + except Exception: var = self._varmaker.next() self.need_translation = True restr = '%s eid %s' % (var, self.visit_constant(const)) diff -r 287813c487b7 -r 2172978be237 server/test/data/site_cubicweb.py --- a/server/test/data/site_cubicweb.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/test/data/site_cubicweb.py Fri Sep 23 14:18:13 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. @@ -20,14 +20,10 @@ from logilab.database.sqlite import register_sqlite_pyfunc from rql.utils import register_function -try: - class DUMB_SORT(FunctionDescr): - pass +class DUMB_SORT(FunctionDescr): + pass - register_function(DUMB_SORT) - def dumb_sort(something): - return something - register_sqlite_pyfunc(dumb_sort) -except: - # already registered - pass +register_function(DUMB_SORT) +def dumb_sort(something): + return something +register_sqlite_pyfunc(dumb_sort) diff -r 287813c487b7 -r 2172978be237 server/utils.py --- a/server/utils.py Fri Sep 23 09:17:37 2011 +0200 +++ b/server/utils.py Fri Sep 23 14:18:13 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. @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """Some utilities for the CubicWeb server.""" + __docformat__ = "restructuredtext en" import sys @@ -121,11 +122,12 @@ class LoopTask(object): """threaded task restarting itself once executed""" - def __init__(self, interval, func, args): + def __init__(self, repo, interval, func, args): if interval <= 0: raise ValueError('Loop task interval must be > 0 ' '(current value: %f for %s)' % \ (interval, func_name(func))) + self.repo = repo self.interval = interval def auto_restart_func(self=self, func=func, args=args): restart = True @@ -138,7 +140,7 @@ except BaseException: restart = False finally: - if restart: + if restart and not self.repo.shutting_down: self.start() self.func = auto_restart_func self.name = func_name(func) @@ -167,7 +169,7 @@ def auto_remove_func(self=self, func=target): try: func() - except: + except Exception: logger = logging.getLogger('cubicweb.repository') logger.exception('Unhandled exception in RepoThread %s', self._name) raise diff -r 287813c487b7 -r 2172978be237 sobjects/textparsers.py --- a/sobjects/textparsers.py Fri Sep 23 09:17:37 2011 +0200 +++ b/sobjects/textparsers.py Fri Sep 23 14:18:13 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. @@ -83,7 +83,7 @@ trinfo = iworkflowable.fire_transition(tr) caller.fire_event('state-changed', {'trinfo': trinfo, 'entity': entity}) - except: + except Exception: self.exception('while changing state of %s', entity) else: self.error("can't pass transition %s on entity %s", diff -r 287813c487b7 -r 2172978be237 test/data/rewrite/schema.py --- a/test/data/rewrite/schema.py Fri Sep 23 09:17:37 2011 +0200 +++ b/test/data/rewrite/schema.py Fri Sep 23 14:18:13 2011 +0200 @@ -63,3 +63,15 @@ object = 'Card' inlined = True cardinality = '?*' + +class inlined_note(RelationDefinition): + subject = 'Card' + object = 'Note' + inlined = True + cardinality = '?*' + +class inlined_affaire(RelationDefinition): + subject = 'Note' + object = 'Affaire' + inlined = True + cardinality = '?*' diff -r 287813c487b7 -r 2172978be237 test/unittest_rqlrewrite.py --- a/test/unittest_rqlrewrite.py Fri Sep 23 09:17:37 2011 +0200 +++ b/test/unittest_rqlrewrite.py Fri Sep 23 14:18:13 2011 +0200 @@ -236,6 +236,18 @@ ('A2', 'X'): (c2,), }, {}) + def test_optional_var_inlined_linked(self): + c1 = ('X require_permission P') + c2 = ('X inlined_card O, O require_permission P') + rqlst = parse('Any A,W WHERE A inlined_card C?, C inlined_note N, ' + 'N inlined_affaire W') + rewrite(rqlst, {('C', 'X'): (c1,)}, {}) + self.failUnlessEqual(rqlst.as_string(), + 'Any A,W WHERE A inlined_card C?, A is Affaire ' + 'WITH C,N,W BEING (Any C,N,W WHERE C inlined_note N, ' + 'N inlined_affaire W, EXISTS(C require_permission B), ' + 'C is Card, N is Note, W is Affaire)') + def test_relation_optimization_1_lhs(self): # since Card in_state State as monovalued cardinality, the in_state # relation used in the rql expression can be ignored and S replaced by @@ -246,6 +258,7 @@ self.assertEqual(rqlst.as_string(), "Any C WHERE C in_state STATE, C is Card, " "EXISTS(STATE name 'hop'), STATE is State") + def test_relation_optimization_1_rhs(self): snippet = ('TW subworkflow_exit X, TW name "hop"') rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT') diff -r 287813c487b7 -r 2172978be237 uilib.py --- a/uilib.py Fri Sep 23 09:17:37 2011 +0200 +++ b/uilib.py Fri Sep 23 14:18:13 2011 +0200 @@ -406,10 +406,10 @@ def exc_message(ex, encoding): try: return unicode(ex) - except: + except Exception: try: return unicode(str(ex), encoding, 'replace') - except: + except Exception: return unicode(repr(ex), encoding, 'replace') @@ -423,7 +423,7 @@ res.append(u'\n') try: res.append(u'\t Error: %s\n' % exception) - except: + except Exception: pass return u'\n'.join(res) diff -r 287813c487b7 -r 2172978be237 view.py --- a/view.py Fri Sep 23 09:17:37 2011 +0200 +++ b/view.py Fri Sep 23 14:18:13 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. @@ -174,7 +174,7 @@ stream = self.set_stream(w) try: view_func(**context) - except: + except Exception: self.debug('view call %s failed (context=%s)', view_func, context) raise # return stream content if we have created it @@ -375,7 +375,19 @@ def call(self, **kwargs): if self.cw_rset is None: - self.entity_call(self.cw_extra_kwargs.pop('entity')) + # * cw_extra_kwargs is the place where extra selection arguments are + # stored + # * when calling req.view('somevid', entity=entity), 'entity' ends + # up in cw_extra_kwargs and kwargs + # + # handle that to avoid a TypeError with a sanity check + # + # Notice that could probably be avoided by handling entity_call in + # .render + entity = self.cw_extra_kwargs.pop('entity') + if 'entity' in kwargs: + assert kwargs.pop('entity') is entity + self.entity_call(entity, **kwargs) else: super(EntityView, self).call(**kwargs) diff -r 287813c487b7 -r 2172978be237 web/application.py --- a/web/application.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/application.py Fri Sep 23 14:18:13 2011 +0200 @@ -423,7 +423,7 @@ if req.cnx and not commited: try: req.cnx.rollback() - except: + except Exception: pass # ignore rollback error at this point self.info('query %s executed in %s sec', req.relative_path(), clock() - tstart) return result @@ -460,7 +460,7 @@ errview = self.vreg['views'].select('error', req) template = self.main_template_id(req) content = self.vreg['views'].main_template(req, template, view=errview) - except: + except Exception: content = self.vreg['views'].main_template(req, 'error-template') raise StatusResponse(code, content) diff -r 287813c487b7 -r 2172978be237 web/captcha.py --- a/web/captcha.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/captcha.py Fri Sep 23 14:18:13 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. @@ -17,8 +17,8 @@ # with CubicWeb. If not, see . """Simple captcha library, based on PIL. Monkey patch functions in this module if you want something better... +""" -""" __docformat__ = "restructuredtext en" from random import randint, choice diff -r 287813c487b7 -r 2172978be237 web/data/cubicweb.ajax.js --- a/web/data/cubicweb.ajax.js Fri Sep 23 09:17:37 2011 +0200 +++ b/web/data/cubicweb.ajax.js Fri Sep 23 14:18:13 2011 +0200 @@ -705,7 +705,7 @@ function setTab(tabname, cookiename) { // set appropriate cookie - loadRemote('json', ajaxFuncArgs('set_cookie', null, cookiename, tabname)); + jQuery.cookie(cookiename, tabname, {path: '/'}); // trigger show + tabname event triggerLoad(tabname); } diff -r 287813c487b7 -r 2172978be237 web/data/cubicweb.js --- a/web/data/cubicweb.js Fri Sep 23 09:17:37 2011 +0200 +++ b/web/data/cubicweb.js Fri Sep 23 14:18:13 2011 +0200 @@ -53,7 +53,13 @@ }, evalJSON: function (json) { // trust source - return eval("(" + json + ")"); + try { + return eval("(" + json + ")"); + } catch(e) { + cw.log(e); + cw.log('The faulty json source was', json); + throw (e); + } }, urlEncode: function (str) { diff -r 287813c487b7 -r 2172978be237 web/data/jquery.cookie.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/data/jquery.cookie.js Fri Sep 23 14:18:13 2011 +0200 @@ -0,0 +1,41 @@ +/** + * jQuery Cookie plugin + * + * Copyright (c) 2010 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ +jQuery.cookie = function (key, value, options) { + + // key and at least value given, set cookie... + if (arguments.length > 1 && String(value) !== "[object Object]") { + options = jQuery.extend({}, options); + + if (value === null || value === undefined) { + options.expires = -1; + } + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } + + value = String(value); + + return (document.cookie = [ + encodeURIComponent(key), '=', + options.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // key and possibly options given, get cookie... + options = value || {}; + var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent; + return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null; +}; diff -r 287813c487b7 -r 2172978be237 web/test/unittest_session.py --- a/web/test/unittest_session.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/test/unittest_session.py Fri Sep 23 14:18:13 2011 +0200 @@ -2,7 +2,7 @@ """unit tests for cubicweb.web.application :organization: Logilab -:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +:copyright: 2001-2011 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses """ diff -r 287813c487b7 -r 2172978be237 web/test/unittest_viewselector.py --- a/web/test/unittest_viewselector.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/test/unittest_viewselector.py Fri Sep 23 14:18:13 2011 +0200 @@ -76,7 +76,7 @@ return try: self.assertSetEqual(content.keys(), expected) - except: + except Exception: print registry, sorted(expected), sorted(content.keys()) print 'no more', [v for v in expected if not v in content.keys()] print 'missing', [v for v in content.keys() if not v in expected] @@ -126,7 +126,6 @@ ('rsetxml', xmlrss.XMLRsetView), ('rss', xmlrss.RSSView), ('sameetypelist', baseviews.SameETypeListView), - ('secondary', baseviews.SecondaryView), ('security', management.SecurityManagementView), ('table', tableview.TableView), ('text', baseviews.TextView), @@ -150,7 +149,6 @@ ('rsetxml', xmlrss.XMLRsetView), ('rss', xmlrss.RSSView), ('sameetypelist', baseviews.SameETypeListView), - ('secondary', baseviews.SecondaryView), ('security', management.SecurityManagementView), ('table', tableview.TableView), ('text', baseviews.TextView), @@ -204,7 +202,6 @@ ('primary', primary.PrimaryView),] + RDFVIEWS + [ ('rsetxml', xmlrss.XMLRsetView), ('rss', xmlrss.RSSView), - ('secondary', baseviews.SecondaryView), ('security', management.SecurityManagementView), ('table', tableview.TableView), ('text', baseviews.TextView), @@ -240,7 +237,6 @@ ('rsetxml', xmlrss.XMLRsetView), ('rss', xmlrss.RSSView), ('sameetypelist', baseviews.SameETypeListView), - ('secondary', baseviews.SecondaryView), ('security', management.SecurityManagementView), ('table', tableview.TableView), ('text', baseviews.TextView), @@ -468,7 +464,7 @@ try: obj = self.vreg['views'].select(vid, req, rset=rset, **args) return obj.render(**args) - except: + except Exception: print vid, rset, args raise diff -r 287813c487b7 -r 2172978be237 web/uicfg.py --- a/web/uicfg.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/uicfg.py Fri Sep 23 14:18:13 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. diff -r 287813c487b7 -r 2172978be237 web/views/autoform.py --- a/web/views/autoform.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/autoform.py Fri Sep 23 14:18:13 2011 +0200 @@ -325,7 +325,7 @@ def _entity(self): try: cls = self._cw.vreg['etypes'].etype_class(self.etype) - except: + except Exception: self.w(self._cw._('no such entity type %s') % self.etype) return entity = cls(self._cw) diff -r 287813c487b7 -r 2172978be237 web/views/basecontrollers.py --- a/web/views/basecontrollers.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/basecontrollers.py Fri Sep 23 14:18:13 2011 +0200 @@ -23,6 +23,7 @@ _ = unicode from logilab.common.date import strptime +from logilab.common.deprecation import deprecated from cubicweb import (NoSelectableObject, ObjectNotFound, ValidationError, AuthenticationError, typed_eid) @@ -546,8 +547,8 @@ self._cw.set_cookie(cookies, statename) @jsonize + @deprecated("[3.13] use jQuery.cookie(cookiename, cookievalue, {path: '/'}) in js land instead") def js_set_cookie(self, cookiename, cookievalue): - # XXX we should consider jQuery.Cookie cookiename, cookievalue = str(cookiename), str(cookievalue) cookies = self._cw.get_cookie() cookies[cookiename] = cookievalue diff -r 287813c487b7 -r 2172978be237 web/views/baseviews.py --- a/web/views/baseviews.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/baseviews.py Fri Sep 23 14:18:13 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. @@ -15,12 +15,64 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""Set of HTML generic base views: +""" +HTML views +~~~~~~~~~~ + +Special views +````````````` + +.. autoclass:: NullView +.. autoclass:: NoResultView +.. autoclass:: FinalView + + +Base entity views +````````````````` + +.. autoclass:: InContextView +.. autoclass:: OutOfContextView +.. autoclass:: OneLineView -* noresult, final -* primary, sidebox -* oneline, incontext, outofcontext, text -* list +Those are used to display a link to an entity, whose label depends on the entity +having to be displayed in or out of context (of another entity): some entities +make sense in the context of another entity. For instance, the `Version` of a +`Project` in forge. So one may expect that 'incontext' will be called when +display a version from within the context of a project, while 'outofcontext"' +will be called in other cases. In our example, the 'incontext' view of the +version would be something like '0.1.2', while the 'outofcontext' view would +include the project name, e.g. 'baz 0.1.2' (since only a version number without +the associated project doesn't make sense if you don't know yet that you're +talking about the famous 'baz' project. |cubicweb| tries to make guess and call +'incontext'/'outofcontext' nicely. When it can't know, the 'oneline' view should +be used. + + +List entity views +````````````````` + +.. autoclass:: ListView +.. autoclass:: SimpleListView +.. autoclass:: SameETypeListView +.. autoclass:: CSVView + +Those list views can be given a 'subvid' arguments, telling the view to use of +each item in the list. When not specified, the value of the 'redirect_vid' +attribute of :class:`ListItemView` (for 'listview') or of +:class:`SimpleListView` will be used. This default to 'outofcontext' for 'list' +/ 'incontext' for 'simplelist' + + +Text entity views +~~~~~~~~~~~~~~~~~ + +Basic HTML view have some variants to be used when generating raw text, not HTML +(for notifications for instance). Also, as explained above, some of the HTML +views use those text views as a basis. + +.. autoclass:: TextView +.. autoclass:: InContextTextView +.. autoclass:: OutOfContextView """ __docformat__ = "restructuredtext en" @@ -42,7 +94,12 @@ class NullView(AnyRsetView): - """default view when no result has been found""" + """:__regid__: *null* + + This view is the default view used when nothing needs to be rendered. It is + always applicable and is usually used as fallback view when calling + :meth:`_cw.view` to display nothing if the result set is empty. + """ __regid__ = 'null' __select__ = yes() def call(self, **kwargs): @@ -51,9 +108,16 @@ class NoResultView(View): - """default view when no result has been found""" + """:__regid__: *noresult* + + This view is the default view to be used when no result has been found + (i.e. empty result set). + + It's usually used as fallback view when calling :meth:`_cw.view` to display + "no results" if the result set is empty. + """ + __regid__ = 'noresult' __select__ = empty_rset() - __regid__ = 'noresult' def call(self, **kwargs): self.w(u'
    %s
    \n' @@ -61,8 +125,11 @@ class FinalView(AnyRsetView): - """display values without any transformation (i.e. get a number for - entities) + """:__regid__: *final* + + Display the value of a result set cell with minimal transformations + (i.e. you'll get a number for entities). It is applicable on any result set, + though usually dedicated for cells containing an attribute's value. """ __regid__ = 'final' # record generated i18n catalog messages @@ -126,21 +193,51 @@ self.wdata(printable_value(self._cw, etype, value, props)) -# XXX deprecated -class SecondaryView(EntityView): - __regid__ = 'secondary' - title = _('secondary') +class InContextView(EntityView): + """:__regid__: *incontext* + + This view is used whenthe entity should be considered as displayed in its + context. By default it produces the result of `textincontext` wrapped in a + link leading to the primary view of the entity. + """ + __regid__ = 'incontext' + + def cell_call(self, row, col): + entity = self.cw_rset.get_entity(row, col) + desc = cut(entity.dc_description(), 50) + self.w(u'' % ( + xml_escape(entity.absolute_url()), xml_escape(desc))) + self.w(xml_escape(self._cw.view('textincontext', self.cw_rset, + row=row, col=col))) + self.w(u'') - def cell_call(self, row, col, **kwargs): - """the secondary view for an entity - secondary = icon + view(oneline) - """ + +class OutOfContextView(EntityView): + """:__regid__: *outofcontext* + + This view is used whenthe entity should be considered as displayed out of + its context. By default it produces the result of `textoutofcontext` wrapped + in a link leading to the primary view of the entity. + """ + __regid__ = 'outofcontext' + + def cell_call(self, row, col): entity = self.cw_rset.get_entity(row, col) - self.w(u' ') - self.wview('oneline', self.cw_rset, row=row, col=col) + desc = cut(entity.dc_description(), 50) + self.w(u'' % ( + xml_escape(entity.absolute_url()), xml_escape(desc))) + self.w(xml_escape(self._cw.view('textoutofcontext', self.cw_rset, + row=row, col=col))) + self.w(u'') class OneLineView(EntityView): + """:__regid__: *oneline* + + This view is used when we can't tell if the entity should be considered as + displayed in or out of context. By default it produces the result of the + `text` view in a link leading to the primary view of the entity. + """ __regid__ = 'oneline' title = _('oneline') @@ -153,18 +250,25 @@ self.w(u'') +# text views ################################################################### + class TextView(EntityView): - """the simplest text view for an entity""" + """:__regid__: *text* + + This is the simplest text view for an entity. By default it returns the + result of the entity's `dc_title()` method, which is cut to fit the + `navigation.short-line-size` property if necessary. + """ __regid__ = 'text' title = _('text') content_type = 'text/plain' def call(self, **kwargs): - """the view is called for an entire result set, by default loop - other rows of the result set and call the same view on the - particular row + """The view is called for an entire result set, by default loop other + rows of the result set and call the same view on the particular row. - Views applicable on None result sets have to override this method + Subclasses views that are applicable on None result sets will have to + override this method. """ rset = self.cw_rset if rset is None: @@ -180,40 +284,14 @@ self._cw.property_value('navigation.short-line-size'))) -class MetaDataView(EntityView): - """paragraph view of some metadata""" - __regid__ = 'metadata' - show_eid = True +class InContextTextView(TextView): + """:__regid__: *textincontext* - def cell_call(self, row, col): - _ = self._cw._ - entity = self.cw_rset.get_entity(row, col) - self.w(u'
    ') - if self.show_eid: - self.w(u'%s #%s - ' % (entity.dc_type(), entity.eid)) - if entity.modification_date != entity.creation_date: - self.w(u'%s ' % _('latest update on')) - self.w(u'%s, ' - % self._cw.format_date(entity.modification_date)) - # entities from external source may not have a creation date (eg ldap) - if entity.creation_date: - self.w(u'%s ' % _('created on')) - self.w(u'%s' - % self._cw.format_date(entity.creation_date)) - if entity.creator: - if entity.creation_date: - self.w(u' %s ' % _('by')) - else: - self.w(u' %s ' % _('created_by')) - self.w(u'%s' % entity.creator.name()) - meta = entity.cw_metainformation() - if meta['source']['uri'] != 'system': - self.w(u' (%s' % _('cw_source')) - self.w(u' %s)' % meta['source']['uri']) - self.w(u'
    ') - - -class InContextTextView(TextView): + Similar to the `text` view, but called when an entity is considered in + context (see description of incontext HTML view for more information on + this). By default it displays what's returned by the `dc_title()` method of + the entity. + """ __regid__ = 'textincontext' title = None # not listed as a possible view def cell_call(self, row, col): @@ -222,6 +300,13 @@ class OutOfContextTextView(InContextTextView): + """:__regid__: *textoutofcontext* + + Similar to the `text` view, but called when an entity is considered out of + context (see description of outofcontext HTML view for more information on + this). By default it displays what's returned by the `dc_long_title()` + method of the entity. + """ __regid__ = 'textoutofcontext' def cell_call(self, row, col): @@ -229,35 +314,26 @@ self.w(entity.dc_long_title()) -class InContextView(EntityView): - __regid__ = 'incontext' - - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - desc = cut(entity.dc_description(), 50) - self.w(u'' % ( - xml_escape(entity.absolute_url()), xml_escape(desc))) - self.w(xml_escape(self._cw.view('textincontext', self.cw_rset, - row=row, col=col))) - self.w(u'') - - -class OutOfContextView(EntityView): - __regid__ = 'outofcontext' - - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - desc = cut(entity.dc_description(), 50) - self.w(u'' % ( - xml_escape(entity.absolute_url()), xml_escape(desc))) - self.w(xml_escape(self._cw.view('textoutofcontext', self.cw_rset, - row=row, col=col))) - self.w(u'') - - # list views ################################################################## class ListView(EntityView): + """:__regid__: *list* + + This view displays a list of entities by creating a HTML list (`
      `) and + call the view `listitem` for each entity of the result set. The 'list' view + will generate HTML like: + + .. sourcecode:: html + +
        +
      • "result of 'subvid' view for a row
      • + ... +
      + + If you wish to use a different view for each entity, either subclass and + change the :attr:`item_vid` class attribute or specify a `subvid` argument + when calling this view. + """ __regid__ = 'list' title = _('list') item_vid = 'listitem' @@ -312,7 +388,21 @@ class SimpleListView(ListItemView): - """list without bullets""" + """:__regid__: *simplelist* + + Similar to :class:~cubicweb.web.views.baseviews.ListView but using '
      ' + instead of '
        '. It rely on '
        ' behaviour to separate items. HTML will + look like + + .. sourcecode:: html + +
        "result of 'subvid' view for a row
        + ... + + + It relies on base :class:`~cubicweb.view.View` class implementation of the + :meth:`call` method to insert those
        . + """ __regid__ = 'simplelist' redirect_vid = 'incontext' @@ -330,8 +420,13 @@ class SameETypeListView(EntityView): - """list of entities of the same type, when asked explicitly for same etype list - view (for instance, display gallery if only images) + """:__regid__: *sameetypelist* + + This view displays a list of entities of the same type, in HTML section + ('
        ') and call the view `sameetypelistitem` for each entity of the + result set. It's designed to get a more adapted global list when displayed + entities are all of the same type (for instance, display gallery if there + are only images entities). """ __regid__ = 'sameetypelist' __select__ = EntityView.__select__ & one_etype_rset() @@ -361,6 +456,11 @@ class CSVView(SimpleListView): + """:__regid__: *csv* + + This view displays each entity in a coma separated list. It is NOT related + to the well-known text file format. + """ __regid__ = 'csv' redirect_vid = 'incontext' @@ -377,12 +477,48 @@ self.w(u", ") +# XXX to be documented views ################################################### + +class MetaDataView(EntityView): + """paragraph view of some metadata""" + __regid__ = 'metadata' + show_eid = True + + def cell_call(self, row, col): + _ = self._cw._ + entity = self.cw_rset.get_entity(row, col) + self.w(u'
        ') + if self.show_eid: + self.w(u'%s #%s - ' % (entity.dc_type(), entity.eid)) + if entity.modification_date != entity.creation_date: + self.w(u'%s ' % _('latest update on')) + self.w(u'%s, ' + % self._cw.format_date(entity.modification_date)) + # entities from external source may not have a creation date (eg ldap) + if entity.creation_date: + self.w(u'%s ' % _('created on')) + self.w(u'%s' + % self._cw.format_date(entity.creation_date)) + if entity.creator: + if entity.creation_date: + self.w(u' %s ' % _('by')) + else: + self.w(u' %s ' % _('created_by')) + self.w(u'%s' % entity.creator.name()) + meta = entity.cw_metainformation() + if meta['source']['uri'] != 'system': + self.w(u' (%s' % _('cw_source')) + self.w(u' %s)' % meta['source']['uri']) + self.w(u'
        ') + + class TreeItemView(ListItemView): __regid__ = 'treeitem' def cell_call(self, row, col): self.wview('incontext', self.cw_rset, row=row, col=col) + class TextSearchResultView(EntityView): """this view is used to display full-text search @@ -405,7 +541,7 @@ value = xml_escape(entity.printable_value(attr, format='text/plain').lower()) except TransformError, ex: continue - except: + except Exception: continue if searched in value: contexts = [] @@ -425,26 +561,6 @@ self.wview('oneline', self.cw_rset, row=row, col=col) -# XXX bw compat - -from logilab.common.deprecation import class_moved - -try: - from cubicweb.web.views.tableview import TableView - TableView = class_moved(TableView) -except ImportError: - pass # gae has no tableview module (yet) - -from cubicweb.web.views import boxes, xmlrss, primary -PrimaryView = class_moved(primary.PrimaryView) -SideBoxView = class_moved(boxes.SideBoxView) -XmlView = class_moved(xmlrss.XMLView) -XmlItemView = class_moved(xmlrss.XMLItemView) -XmlRsetView = class_moved(xmlrss.XMLRsetView) -RssView = class_moved(xmlrss.RSSView) -RssItemView = class_moved(xmlrss.RSSItemView) - - class GroupByView(EntityView): """grouped view of a result set. The `group_key` method return the group key of an entities (a string or tuple of string). @@ -452,7 +568,7 @@ For each group, display a link to entities of this group by generating url like / or //. """ - __abstrack__ = True + __abstract__ = True __select__ = EntityView.__select__ & match_kwargs('basepath') entity_attribute = None reversed = False @@ -550,3 +666,29 @@ url = self.index_url(basepath, key, vtitle=vtitle) title = self._cw._('archive for %(author)s') % {'author': key} return tags.a(label, href=url, title=title) + + +# bw compat #################################################################### + +from logilab.common.deprecation import class_moved, class_deprecated + +from cubicweb.web.views import boxes, xmlrss, primary, tableview +PrimaryView = class_moved(primary.PrimaryView) +SideBoxView = class_moved(boxes.SideBoxView) +XmlView = class_moved(xmlrss.XMLView) +XmlItemView = class_moved(xmlrss.XMLItemView) +XmlRsetView = class_moved(xmlrss.XMLRsetView) +RssView = class_moved(xmlrss.RSSView) +RssItemView = class_moved(xmlrss.RSSItemView) +TableView = class_moved(tableview.TableView) + + +class SecondaryView(EntityView): + __metaclass__ = class_deprecated + __deprecation_warning__ = '[3.9] the secondary view is deprecated, use one of oneline/incontext/outofcontext' + __regid__ = 'secondary' + + def cell_call(self, row, col, **kwargs): + entity = self.cw_rset.get_entity(row, col) + self.w(u' ') + self.wview('oneline', self.cw_rset, row=row, col=col) diff -r 287813c487b7 -r 2172978be237 web/views/cwsources.py --- a/web/views/cwsources.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/cwsources.py Fri Sep 23 14:18:13 2011 +0200 @@ -24,27 +24,41 @@ from itertools import repeat, chain +from cubicweb import Unauthorized from cubicweb.selectors import is_instance, score_entity, match_user_groups from cubicweb.view import EntityView, StartupView from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name from cubicweb.web import uicfg, formwidgets as wdgs -from cubicweb.web.views import tabs, actions, add_etype_button +from cubicweb.web.views import tabs, actions, ibreadcrumbs, add_etype_button _abaa = uicfg.actionbox_appearsin_addmenu +# there are explicit 'add' buttons for those _abaa.tag_object_of(('CWSourceSchemaConfig', 'cw_schema', '*'), False) _abaa.tag_object_of(('CWSourceSchemaConfig', 'cw_for_source', '*'), False) +_abaa.tag_object_of(('CWSourceSchemaConfig', 'cw_host_config_of', '*'), False) _afs = uicfg.autoform_section _afs.tag_attribute(('CWSource', 'synchronizing'), 'main', 'hidden') _afs.tag_object_of(('*', 'cw_for_source', 'CWSource'), 'main', 'hidden') + _affk = uicfg.autoform_field_kwargs _affk.tag_attribute(('CWSource', 'parser'), {'widget': wdgs.TextInput}) # source primary views ######################################################### _pvs = uicfg.primaryview_section +_pvs.tag_attribute(('CWSource', 'name'), 'hidden') _pvs.tag_object_of(('*', 'cw_for_source', 'CWSource'), 'hidden') +_pvs.tag_object_of(('*', 'cw_host_config_of', 'CWSource'), 'hidden') + +_pvdc = uicfg.primaryview_display_ctrl +_pvdc.tag_attribute(('CWSource', 'type'), {'vid': 'attribute'})# disable reledit + +_rc = uicfg.reledit_ctrl +_rc.tag_attribute(('CWSource', 'config'), {'rvid': 'verbatim'}) +_rc.tag_attribute(('CWSourceHostConfig', 'config'), {'rvid': 'verbatim'}) +_rc.tag_attribute(('CWSourceSchemaConfig', 'options'), {'rvid': 'verbatim'}) class CWSourcePrimaryView(tabs.TabbedPrimaryView): @@ -57,6 +71,23 @@ __regid__ = 'cwsource-main' __select__ = tabs.PrimaryTab.__select__ & is_instance('CWSource') + def render_entity_attributes(self, entity): + super(CWSourceMainTab, self).render_entity_attributes(entity) + self.w(add_etype_button(self._cw, 'CWSourceHostConfig', + __linkto='cw_host_config_of:%s:subject' % entity.eid, + __redirectpath=entity.rest_path())) + try: + hostconfig = self._cw.execute( + 'Any X, XC, XH WHERE X cw_host_config_of S, S eid %(s)s, ' + 'X config XC, X match_host XH', {'s': entity.eid}) + except Unauthorized: + pass + else: + if hostconfig: + self.w(u'

        %s

        ' % self._cw._('CWSourceHostConfig_plural')) + self._cw.view('editable-table', hostconfig, + displaycols=range(2), w=self.w) + MAPPED_SOURCE_TYPES = set( ('pyrorql', 'datafeed') ) @@ -239,3 +270,11 @@ self._cw._('add a CWSource'))) self.w(u'
        ') self.wview('table', self._cw.execute(self.rql), displaycols=range(4)) + + +# breadcrumbs configuration #################################################### + +class CWsourceConfigIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): + __select__ = is_instance('CWSourceHostConfig', 'CWSourceSchemaConfig') + def parent_entity(self): + return self.entity.cwsource diff -r 287813c487b7 -r 2172978be237 web/views/facets.py --- a/web/views/facets.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/facets.py Fri Sep 23 14:18:13 2011 +0200 @@ -207,6 +207,7 @@ __regid__ = 'facet.filtertable' __select__ = has_facets() wdg_stack_size = 8 + compact_layout_threshold = 5 def call(self, vid, divid, vidargs, cssclass=''): self.generate_form(self.w, self.cw_rset, divid, vid, vidargs, @@ -214,10 +215,23 @@ # divid=divid XXX ) + def _simple_horizontal_layout(self, w, wdgs): + w(u'\n') + w(u'\n') + for wdg in wdgs: + w(u'') + w(u'\n') + w(u'
        ') + wdg.render(w=w) + w(u'
        \n') + def layout_widgets(self, w, wdgs): """layout widgets: put them in a table where each column should have sum(wdg.height()) < wdg_stack_size. """ + if len(wdgs) < self.compact_layout_threshold: + self._simple_horizontal_layout(w, wdgs) + return w(u'\n') widget_queue = [] queue_height = 0 diff -r 287813c487b7 -r 2172978be237 web/views/forms.py --- a/web/views/forms.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/forms.py Fri Sep 23 14:18:13 2011 +0200 @@ -277,7 +277,7 @@ for editedfield in splitstrip(editedfields): try: name, role = editedfield.split('-') - except: + except Exception: name = editedfield role = None if entityform: diff -r 287813c487b7 -r 2172978be237 web/views/idownloadable.py --- a/web/views/idownloadable.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/idownloadable.py Fri Sep 23 14:18:13 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. @@ -75,7 +75,7 @@ class DownloadView(EntityView): """download view - + this view is replacing the deprecated 'download' controller and allow downloading of entities providing the necessary interface """ diff -r 287813c487b7 -r 2172978be237 web/views/magicsearch.py --- a/web/views/magicsearch.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/magicsearch.py Fri Sep 23 14:18:13 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. @@ -387,7 +387,7 @@ procname, query = uquery.split(':', 1) proc = self.by_name[procname.strip().lower()] uquery = query.strip() - except: + except Exception: # use processor chain unauthorized = None for proc in self.processors: diff -r 287813c487b7 -r 2172978be237 web/views/primary.py --- a/web/views/primary.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/primary.py Fri Sep 23 14:18:13 2011 +0200 @@ -15,7 +15,26 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""The default primary view""" +""" +Public API of the PrimaryView class +```````````````````````````````````` +.. autoclass:: cubicweb.web.views.primary.PrimaryView + +Views that may be used to display an entity's attribute or relation +``````````````````````````````````````````````````````````````````` + +Yoy may easily the display of an attribute or relation by simply configuring the +view using one of `primaryview_display_ctrl` or `reledit_ctrl` to use one of the +views describled below. For instance: + +.. sourcecode:: python + + primaryview_display_ctrl.tag_attribute(('Foo', 'bar'), {'vid': 'attribute'}) + + +.. autoclass:: AttributeView +.. autoclass:: URLAttributeView +""" __docformat__ = "restructuredtext en" _ = unicode @@ -34,7 +53,47 @@ class PrimaryView(EntityView): - """the full view of an non final entity""" + """ + The basic layout of a primary view is as in the :ref:`primary_view_layout` + section. This layout is actually drawn by the `render_entity` method. + + The methods you may want to modify while customizing a ``PrimaryView`` + are: + + .. automethod:: cubicweb.web.views.primary.PrimaryView.render_entity_title + .. automethod:: cubicweb.web.views.primary.PrimaryView.render_entity_attributes + .. automethod:: cubicweb.web.views.primary.PrimaryView.render_entity_relations + .. automethod:: cubicweb.web.views.primary.PrimaryView.render_side_boxes + + The placement of relations in the relations section or in side boxes + can be controlled through the :ref:`primary_view_configuration` mechanism. + + .. automethod:: cubicweb.web.views.primary.PrimaryView.content_navigation_components + + Also, please note that by setting the following attributes in your + subclass, you can already customize some of the rendering: + + :attr:`show_attr_label` + Renders the attribute label next to the attribute value if set to `True`. + Otherwise, does only display the attribute value. + + :attr:`show_rel_label` + Renders the relation label next to the relation value if set to `True`. + Otherwise, does only display the relation value. + + :attr:`skip_none` + Does not render an attribute value that is None if set to `True`. + + :attr:`main_related_section` + Renders the relations of the entity if set to `True`. + + A good practice is for you to identify the content of your entity type for + which the default rendering does not answer your need so that you can focus + on the specific method (from the list above) that needs to be modified. We + do not advise you to overwrite ``render_entity`` unless you want a + completely different layout. + """ + __regid__ = 'primary' title = _('primary') show_attr_label = True @@ -95,6 +154,12 @@ self.w(u'
        ') def content_navigation_components(self, context): + """This method is applicable only for entity type implementing the + interface `IPrevNext`. This interface is for entities which can be + linked to a previous and/or next entity. This method will render the + navigation links between entities of this type, either at the top or at + the bottom of the page given the context (navcontent{top|bottom}). + """ self.w(u'
        ' % context) for comp in self._cw.vreg['ctxcomponents'].poss_visible_objects( self._cw, rset=self.cw_rset, view=self, context=context): @@ -106,7 +171,9 @@ self.w(u'
        ') def render_entity_title(self, entity): - """default implementation return dc_title""" + """Renders the entity title, by default using entity's + :meth:`dc_title()` method. + """ title = xml_escape(entity.dc_title()) if title: if self.is_primary(): @@ -128,6 +195,10 @@ return u'' def render_entity_attributes(self, entity): + """Renders all attributes and relations in the 'attributes' section. The + :attr:`skip_none` attribute controls the display of `None` valued + attributes. + """ display_attributes = [] for rschema, _, role, dispctrl in self._section_def(entity, 'attributes'): vid = dispctrl.get('vid', 'reledit') @@ -165,6 +236,7 @@ self.field(label, value, tr=False, table=table) def render_entity_relations(self, entity): + """Renders all relations in the 'relations' section.""" for rschema, tschemas, role, dispctrl in self._section_def(entity, 'relations'): if rschema.final or dispctrl.get('rtypevid'): vid = dispctrl.get('vid', 'reledit') @@ -212,8 +284,9 @@ self.w(u'
        ') def render_side_boxes(self, boxes): - """display side related relations: - non-meta in a first step, meta in a second step + """Renders side boxes on the right side of the content. This will + generate a box for each relation in the 'sidebox' section, as well as + explicit box appobjects selectable in this context. """ for box in boxes: if isinstance(box, tuple): @@ -305,6 +378,8 @@ It will try to display nicely according to the number of items in the result set. + + XXX include me in the doc """ __regid__ = 'autolimited' @@ -347,31 +422,29 @@ class URLAttributeView(EntityView): - """use this view for attributes whose value is an url and that you want - to display as clickable link + """:__regid__: *urlattr* + + This view will wrap an attribute value (hence expect a string) into an '' + HTML tag to display a clickable link. """ __regid__ = 'urlattr' __select__ = EntityView.__select__ & match_kwargs('rtype') - def cell_call(self, row, col, rtype, **kwargs): - entity = self.cw_rset.get_entity(row, col) + def entity_call(self, entity, rtype, **kwargs): url = entity.printable_value(rtype) if url: self.w(u'%s' % (url, url)) class AttributeView(EntityView): - """use this view on an entity as an alternative to more sophisticated - views such as reledit. + """:__regid__: *attribute* - Ex. usage: - - uicfg.primaryview_display_ctrl.tag_attribute(('Foo', 'bar'), {'vid': 'attribute'}) + This view is generally used to disable the *reledit* feature. It works on + both relations and attributes. """ __regid__ = 'attribute' __select__ = EntityView.__select__ & match_kwargs('rtype') - def cell_call(self, row, col, rtype, role, **kwargs): - entity = self.cw_rset.get_entity(row, col) + def entity_call(self, entity, rtype, **kwargs): if self._cw.vreg.schema.rschema(rtype).final: self.w(entity.printable_value(rtype)) else: @@ -384,12 +457,14 @@ class ToolbarLayout(component.Layout): + # XXX include me in the doc __select__ = match_context('ctxtoolbar') def render(self, w): if self.init_rendering(): self.cw_extra_kwargs['view'].render_body(w) + ## default primary ui configuration ########################################### _pvs = uicfg.primaryview_section diff -r 287813c487b7 -r 2172978be237 web/views/reledit.py --- a/web/views/reledit.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/reledit.py Fri Sep 23 14:18:13 2011 +0200 @@ -104,7 +104,11 @@ self._handle_relation(rschema, role, divid, reload, formid, action) def _handle_attribute(self, rschema, role, divid, reload, action): - value = self.entity.printable_value(rschema.type) + rvid = self._rules.get('rvid', None) + if rvid is not None: + value = self._cw.view(rvid, entity=self.entity, rtype=rschema.type) + else: + value = self.entity.printable_value(rschema.type) if not self._should_edit_attribute(rschema): self.w(value) return diff -r 287813c487b7 -r 2172978be237 web/views/schema.py --- a/web/views/schema.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/schema.py Fri Sep 23 14:18:13 2011 +0200 @@ -102,7 +102,7 @@ # XXX get group entity and call it's incontext view groups = [u'%s' % ( group, self._cw.build_url('cwgroup/%s' % group), label) - for group, label in sorted((_(g), g) for g in groups)] + for label, group in sorted((_(g), g) for g in groups)] w(u'
        '.join(groups)) w(u'') w(u'
        '.join(rqlexprs)) diff -r 287813c487b7 -r 2172978be237 web/views/sessions.py --- a/web/views/sessions.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/sessions.py Fri Sep 23 14:18:13 2011 +0200 @@ -21,7 +21,8 @@ __docformat__ = "restructuredtext en" -from cubicweb import RepositoryError, Unauthorized, AuthenticationError +from cubicweb import (RepositoryError, Unauthorized, AuthenticationError, + BadConnectionId) from cubicweb.web import InvalidSession, Redirect from cubicweb.web.application import AbstractSessionManager from cubicweb.dbapi import DBAPISession @@ -119,7 +120,7 @@ req.cnx.commit() except (RepositoryError, Unauthorized): req.cnx.rollback() - except: + except Exception: req.cnx.rollback() raise @@ -132,8 +133,6 @@ if session.cnx: try: session.cnx.close() - except: - # already closed, may occur if the repository session expired - # but not the web session + except BadConnectionId: # expired on the repository side pass session.cnx = None diff -r 287813c487b7 -r 2172978be237 web/views/tableview.py --- a/web/views/tableview.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/tableview.py Fri Sep 23 14:18:13 2011 +0200 @@ -42,6 +42,9 @@ title = _('table') finalview = 'final' + table_widget_class = TableWidget + table_column_class = TableColumn + def form_filter(self, divid, displaycols, displayactions, displayfilter, paginate, hidden=True): try: @@ -144,7 +147,7 @@ if paginate: self.divid = divid # XXX iirk (see usage in page_navigation_url) self.paginate(page_size=page_size, show_all_option=False) - table = TableWidget(self) + table = self.table_widget_class(self) for column in self.get_columns(computed_labels, displaycols, headers, subvid, cellvids, cellattrs, mainindex): table.append_column(column) @@ -197,7 +200,7 @@ label = _label if colindex == mainindex and label is not None: label += ' (%s)' % self.cw_rset.rowcount - column = TableColumn(label, colindex) + column = self.table_column_class(label, colindex) coltype = self.cw_rset.description[0][colindex] # compute column cell view (if coltype is None, it's a left outer # join, use the default non final subvid) @@ -259,14 +262,17 @@ :param cellvid: cell view (defaults to 'outofcontext') """ etype, val = self.cw_rset.description[row][col], self.cw_rset[row][col] - if val is not None and etype is not None and not self._cw.vreg.schema.eschema(etype).final: - self.wview(cellvid or 'outofcontext', self.cw_rset, row=row, col=col) - elif val is None: - # This is usually caused by a left outer join and in that case, - # regular views will most certainly fail if they don't have - # a real eid - self.wview('final', self.cw_rset, row=row, col=col) + if etype is None or not self._cw.vreg.schema.eschema(etype).final: + if val is None: + # This is usually caused by a left outer join and in that case, + # regular views will most certainly fail if they don't have + # a real eid + # XXX if cellvid is e.g. reledit, we may wanna call it anyway + self.w(u' ') + else: + self.wview(cellvid or 'outofcontext', self.cw_rset, row=row, col=col) else: + # XXX why do we need a fallback view here? self.wview(cellvid or 'final', self.cw_rset, 'null', row=row, col=col) diff -r 287813c487b7 -r 2172978be237 web/views/tabs.py --- a/web/views/tabs.py Fri Sep 23 09:17:37 2011 +0200 +++ b/web/views/tabs.py Fri Sep 23 14:18:13 2011 +0200 @@ -128,7 +128,7 @@ entity.view(default, w=self.w) return self._cw.add_css('jquery.ui.css') - self._cw.add_js(('jquery.ui.js', 'cubicweb.ajax.js')) + self._cw.add_js(('jquery.ui.js', 'cubicweb.ajax.js', 'jquery.cookie.js')) # prune tabs : not all are to be shown tabs, active_tab = self.prune_tabs(tabs, default) # build the html structure @@ -140,9 +140,7 @@ for i, (tabid, domid, tabkwargs) in enumerate(tabs): w(u'
      • ') w(u'' % domid) - w(u'' % xml_escape(unicode(uilib.js.setTab(domid, self.cookie_name)))) w(tabkwargs.pop('label', self._cw._(tabid))) - w(u'') w(u'') w(u'
      • ') if domid == active_tab: @@ -160,7 +158,12 @@ # because the callback binding needs to be done before # XXX make work history: true self._cw.add_onload(u""" - jQuery('#entity-tabs-%(eeid)s').tabs( { selected: %(tabindex)s }); + jQuery('#entity-tabs-%(eeid)s').tabs( + { selected: %(tabindex)s, + select: function(event, ui) { + setTab(ui.panel.id, '%(cookiename)s'); + } + }); setTab('%(domid)s', '%(cookiename)s'); """ % {'tabindex' : active_tab_idx, 'domid' : active_tab, diff -r 287813c487b7 -r 2172978be237 wsgi/__init__.py --- a/wsgi/__init__.py Fri Sep 23 09:17:37 2011 +0200 +++ b/wsgi/__init__.py Fri Sep 23 14:18:13 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. @@ -37,7 +37,7 @@ """pretty prints `obj` if possible""" try: return _pformat(obj) - except: + except Exception: return u'' def qs2dict(qs):