backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 06 Jun 2011 15:03:00 +0200
changeset 7454 1090724f28ed
parent 7447 d5705c9bbe82 (current diff)
parent 7453 84046395d2cd (diff)
child 7455 694b21f0fc62
backport stable
server/session.py
server/sources/storages.py
--- a/selectors.py	Fri May 27 13:57:25 2011 +0200
+++ b/selectors.py	Mon Jun 06 15:03:00 2011 +0200
@@ -1342,7 +1342,7 @@
 
     @lltrace
     def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs):
-        if not req.cnx:
+        if not getattr(req, 'cnx', True): # default to True for repo session instances
             return 0
         user = req.user
         if user is None:
--- a/server/session.py	Fri May 27 13:57:25 2011 +0200
+++ b/server/session.py	Mon Jun 06 15:03:00 2011 +0200
@@ -75,6 +75,25 @@
     return req.is_internal_session
 
 
+class transaction(object):
+    """context manager to enter a transaction for a session: when exiting the
+    `with` block on exception, call `session.rollback()`, else call
+    `session.commit()` on normal exit
+    """
+    def __init__(self, session, free_cnxset=True):
+        self.session = session
+        self.free_cnxset = free_cnxset
+
+    def __enter__(self):
+        pass
+
+    def __exit__(self, exctype, exc, traceback):
+        if exctype:
+            self.session.rollback(free_cnxset=self.free_cnxset)
+        else:
+            self.session.commit(free_cnxset=self.free_cnxset)
+
+
 class hooks_control(object):
     """context manager to control activated hooks categories.
 
@@ -237,6 +256,16 @@
         return '<%ssession %s (%s 0x%x)>' % (
             self.cnxtype, unicode(self.user.login), self.id, id(self))
 
+    def transaction(self, free_cnxset=True):
+        """return context manager to enter a transaction for the session: when
+        exiting the `with` block on exception, call `session.rollback()`, else
+        call `session.commit()` on normal exit.
+
+        The `free_cnxset` will be given to rollback/commit methods to indicate
+        wether the connections set should be freed or not.
+        """
+        return transaction(self, free_cnxset)
+
     def set_tx_data(self, txid=None):
         if txid is None:
             txid = threading.currentThread().getName()
--- a/server/sources/storages.py	Fri May 27 13:57:25 2011 +0200
+++ b/server/sources/storages.py	Mon Jun 06 15:03:00 2011 +0200
@@ -173,13 +173,15 @@
             entity.cw_edited.edited_attribute(attr, Binary(fpath))
             # Mark the old file as useless so the file will be removed at
             # commit.
-            DeleteFileOp.get_instance(entity._cw).add_data(oldpath)
+            if oldpath is not None:
+                DeleteFileOp.get_instance(entity._cw).add_data(oldpath)
         return binary
 
     def entity_deleted(self, entity, attr):
         """an entity using this storage for attr has been deleted"""
         fpath = self.current_fs_path(entity, attr)
-        DeleteFileOp.get_instance(entity._cw).add_data(fpath)
+        if fpath is not None:
+            DeleteFileOp.get_instance(entity._cw).add_data(fpath)
 
     def new_fs_path(self, entity, attr):
         # We try to get some hint about how to name the file using attribute's
@@ -199,13 +201,16 @@
         return fspath
 
     def current_fs_path(self, entity, attr):
+        """return the current fs_path of the tribute.
+
+        Return None is the attr is not stored yet."""
         sysource = entity._cw.cnxset.source('system')
         cu = sysource.doexec(entity._cw,
                              'SELECT cw_%s FROM cw_%s WHERE cw_eid=%s' % (
                              attr, entity.__regid__, entity.eid))
         rawvalue = cu.fetchone()[0]
         if rawvalue is None: # no previous value
-            return self.new_fs_path(entity, attr)
+            return None
         return sysource._process_value(rawvalue, cu.description[0],
                                        binarywrap=str)
 
--- a/web/formwidgets.py	Fri May 27 13:57:25 2011 +0200
+++ b/web/formwidgets.py	Mon Jun 06 15:03:00 2011 +0200
@@ -435,6 +435,7 @@
     an unicode string, or a list of unicode strings.
     """
     vocabulary_widget = True
+    default_size = 5
 
     def __init__(self, attrs=None, multiple=False, **kwargs):
         super(Select, self).__init__(attrs, **kwargs)
@@ -442,11 +443,10 @@
 
     def _render(self, form, field, renderer):
         curvalues, attrs = self.values_and_attributes(form, field)
-        if not 'size' in attrs:
-            attrs['size'] = self._multiple and '5' or '1'
         options = []
         optgroup_opened = False
-        for option in field.vocabulary(form):
+        vocab = field.vocabulary(form)
+        for option in vocab:
             try:
                 label, value, oattrs = option
             except ValueError:
@@ -466,6 +466,12 @@
                 options.append(tags.option(label, value=value, **oattrs))
         if optgroup_opened:
             options.append(u'</optgroup>')
+        if not 'size' in attrs:
+            if self._multiple:
+                size = unicode(min(self.default_size, len(vocab) or 1))
+            else:
+                size = u'1'
+            attrs['size'] = size
         return tags.select(name=field.input_name(form, self.suffix),
                            multiple=self._multiple, options=options, **attrs)