Wiking branch, master, updated. f349a0cd6700d5791d766161c1a5aee1eaa1d44d

Milan Zamazal pdm at devel.brailcom.org
Mon Jun 6 19:31:33 CEST 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Wiking".

The branch, master has been updated
       via  f349a0cd6700d5791d766161c1a5aee1eaa1d44d (commit)
       via  4258670a52da0c652b1d8655864e2cf68400eab3 (commit)
       via  1e07b7423754b432f69900473e568aaaf4c65de4 (commit)
       via  dbcdb2e29ee7ae633c814ac53ba4677760180c63 (commit)
      from  3840112b7868639ec62d5b292d7b84df7ce2bb64 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f349a0cd6700d5791d766161c1a5aee1eaa1d44d
Author: Milan Zamazal <pdm at brailcom.org>
Date:   Wed Feb 23 16:53:53 2011 +0100

    Use pytis.data date&time functions

commit 4258670a52da0c652b1d8655864e2cf68400eab3
Author: Milan Zamazal <pdm at brailcom.org>
Date:   Wed Feb 16 15:14:33 2011 +0100

    mx.DateTime -> datetime

commit 1e07b7423754b432f69900473e568aaaf4c65de4
Author: Milan Zamazal <pdm at brailcom.org>
Date:   Tue Feb 15 17:00:47 2011 +0100

    ISO 8859-2 -> UTF-8

commit dbcdb2e29ee7ae633c814ac53ba4677760180c63
Author: Milan Zamazal <pdm at brailcom.org>
Date:   Tue Feb 15 16:57:51 2011 +0100

    Adjustments for Python 2.6

-----------------------------------------------------------------------

Summary of changes:
 bin/bulkmailer                     |   13 ++---
 defs/application.py                |    6 +-
 doc/src/devel/application.py       |    3 +-
 lib/wiking/__init__.py             |    6 +-
 lib/wiking/application.py          |    1 -
 lib/wiking/cms/appl.py             |    2 +-
 lib/wiking/cms/certificates.py     |   10 ++--
 lib/wiking/cms/cms.py              |   54 +++++++++---------
 lib/wiking/cms/users.py            |   17 +++---
 lib/wiking/db.py                   |   31 ++++++-----
 lib/wiking/export.py               |    2 +-
 lib/wiking/handler.py              |   16 +++---
 lib/wiking/mod_python_interface.py |    8 ++--
 lib/wiking/modules.py              |    6 ++-
 lib/wiking/request.py              |   15 +++---
 lib/wiking/util.py                 |  103 +++++++++++++++++++++++++++---------
 16 files changed, 173 insertions(+), 120 deletions(-)

diff --git a/bin/bulkmailer b/bin/bulkmailer
index be51898..8b68ed8 100755
--- a/bin/bulkmailer
+++ b/bin/bulkmailer
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-# Copyright (C) 2009 Brailcom, o.p.s.
+# Copyright (C) 2009, 2011 Brailcom, o.p.s.
 #
 # COPYRIGHT NOTICE
 #
@@ -30,7 +30,7 @@ The script must be invoked with the database name as its argument:
 """
 
 import os
-import popen2
+import subprocess
 import sys
 
 import psycopg2 as dbapi
@@ -46,13 +46,8 @@ def open_database(database):
 
 def pid_dead(pid):
     my_name = sys.argv[0]
-    child_output, child_input = popen2.popen2(['/usr/bin/pgrep', '-f', '-x', my_name])
-    output = ''
-    while True:
-        next_output = child_output.read()
-        if not next_output:
-            break
-        output = output + next_output
+    command = ['/usr/bin/pgrep', '-f', '-x', my_name]
+    output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
     return pid not in output.split()
     
 def check_obsolete_pids(connection):
diff --git a/defs/application.py b/defs/application.py
index 1148ebb..d0ec75f 100644
--- a/defs/application.py
+++ b/defs/application.py
@@ -1,5 +1,5 @@
-# -*- coding: iso-8859-2 -*-
-# Copyright (C) 2006, 2007, 2008 Brailcom, o.p.s.
+# -*- coding: utf-8 -*-
+# Copyright (C) 2006, 2007, 2008, 2011 Brailcom, o.p.s.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ def init(resolver):
     pass
     
 def default_font_encoding(resolver):
-    return wx.FONTENCODING_ISO8859_2    
+    return wx.FONTENCODING_UTF8
 
 def menu(resolver):
     import config
diff --git a/doc/src/devel/application.py b/doc/src/devel/application.py
index 9a0da1a..9489353 100644
--- a/doc/src/devel/application.py
+++ b/doc/src/devel/application.py
@@ -1,3 +1,4 @@
+import collections
 import lcg, inspect, re
 
 class Reader(lcg.Reader):
@@ -19,7 +20,7 @@ class Reader(lcg.Reader):
                   [lcg.TableOfContents(title="Application methods:", depth=1)]
         for name, method in sorted(Application.__dict__.items()):
             if name.startswith('_') or name.startswith('action_') \
-                   or not callable(method) or not method.__doc__:
+                   or not isinstance(method, collections.Callable) or not method.__doc__:
                 continue
             args, varargs, varkw, defaults = inspect.getargspec(method)
             title = name + inspect.formatargspec(args[1:], varargs, varkw, defaults)
diff --git a/lib/wiking/__init__.py b/lib/wiking/__init__.py
index 48d71eb..06932f5 100644
--- a/lib/wiking/__init__.py
+++ b/lib/wiking/__init__.py
@@ -17,11 +17,11 @@
 
 __version__ = '1.2.0'
 
-import sys, os, time, string, re, copy, urllib
+import sys, os, time, string, re, copy, urllib, imp
 
 # TODO: this can be removed once it is solved in Pytis...
-reload(sys)
-sys.setdefaultencoding('iso-8859-2')
+imp.reload(sys)
+sys.setdefaultencoding('utf-8')
 
 import pytis, pytis.util
 import pytis.data as pd
diff --git a/lib/wiking/application.py b/lib/wiking/application.py
index db0c91c..baa3cb7 100644
--- a/lib/wiking/application.py
+++ b/lib/wiking/application.py
@@ -20,7 +20,6 @@
 
 from wiking import *
 
-import mx.DateTime
 from pytis.presentation import Computer, CbComputer
 
 _ = lcg.TranslatableTextFactory('wiking')
diff --git a/lib/wiking/cms/appl.py b/lib/wiking/cms/appl.py
index f0ec732..dbed8f5 100644
--- a/lib/wiking/cms/appl.py
+++ b/lib/wiking/cms/appl.py
@@ -399,7 +399,7 @@ class Application(CookieAuthentication, wiking.Application):
                 conn.commit()
             finally:
                 conn.close()
-        except dbapi.ProgrammingError, e:
+        except dbapi.ProgrammingError as e:
             return e.args[0]
 
     def handle_exception(self, req, exception):
diff --git a/lib/wiking/cms/certificates.py b/lib/wiking/cms/certificates.py
index 2b464bf..41fb154 100644
--- a/lib/wiking/cms/certificates.py
+++ b/lib/wiking/cms/certificates.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2006-2010 Brailcom, o.p.s.
+# Copyright (C) 2006-2011 Brailcom, o.p.s.
 # Author: Milan Zamazal
 #
 # This program is free software; you can redistribute it and/or modify
@@ -27,9 +27,9 @@ in the version control system history.
 from wiking.cms import *
 
 import cStringIO
+import datetime
 import os
 import subprocess
-import mx.DateTime
 
 import pytis.data
 from pytis.presentation import computer, Computer, Fields, Field
@@ -145,7 +145,7 @@ class Certificates(CMSModule):
                 return None
             try:
                 x509 = gnutls.crypto.X509Certificate(certificate)
-            except Exception, e:
+            except Exception as e:
                 raise Exception(_("Invalid certificate"), e)
             if not x509.has_issuer(x509) and not x509.has_issuer(self._ca_x509):
                 x509 = None
@@ -173,8 +173,8 @@ class Certificates(CMSModule):
                     (x509.subject, x509.issuer, x509.serial_number, x509.version, time.ctime(x509.activation_time), time.ctime(x509.expiration_time),))
         def _convert_x509_timestamp(self, timestamp):
             time_tuple = time.gmtime(timestamp)
-            mx_time = mx.DateTime.DateTime(*time_tuple[:6])
-            return mx_time
+            dt = datetime.datetime(*time_tuple[:6])
+            return dt
             
         def check(self, record):
             x509 = record['x509'].value()
diff --git a/lib/wiking/cms/cms.py b/lib/wiking/cms/cms.py
index 1f6bbe3..8a81742 100644
--- a/lib/wiking/cms/cms.py
+++ b/lib/wiking/cms/cms.py
@@ -28,15 +28,14 @@ import wiking
 from wiking.cms import *
 
 import cStringIO
+import collections
+import datetime
 import os
 import random
 import re
 import string
 import time
 
-import mx.DateTime
-from mx.DateTime import today, TimeDelta
-
 from pytis.util import *
 import pytis.data
 from pytis.presentation import computer, Computer, CbComputer, Fields, HGroup, CodebookSpec, \
@@ -51,7 +50,7 @@ NEVER = pp.Editable.NEVER
 ALWAYS = pp.Editable.ALWAYS
 ASC = pd.ASCENDENT
 DESC = pd.DESCENDANT
-now = pytis.data.DateTime.current_gmtime
+now = pytis.data.DateTime.datetime
 enum = lambda seq: pd.FixedEnumerator(seq)
 
 _ = lcg.TranslatableTextFactory('wiking-cms')
@@ -403,7 +402,7 @@ class CMSExtension(Module, Embeddable, RequestHandler):
             """
             if __debug__:
                 assert isinstance(modname, (str, unicode)), modname
-                assert enabled is None or callable(enabled), enabled
+                assert enabled is None or isinstance(enabled, collections.Callable), enabled
                 for item in submenu:
                     assert isinstance(item, CMSExtension.MenuItem), item
             self.modname = modname
@@ -517,12 +516,12 @@ class Session(PytisModule, wiking.Session):
     def init(self, req, user, session_key):
         # Delete all expired records first...
         data = self._data
-        now = mx.DateTime.now().gmtime()
+        now_ = now()
         uid = user.uid()
-        expiration = mx.DateTime.TimeDelta(hours=cfg.session_expiration)
-        data.delete_many(pd.LE('last_access', pd.Value(pd.DateTime(), now - expiration)))
-        row, success = data.insert(data.make_row(uid=uid, session_key=session_key, last_access=now))
-        self._module('SessionLog').log(req, now, row['session_id'].value(), uid, user.login())
+        expiration = datetime.timedelta(hours=cfg.session_expiration)
+        data.delete_many(pd.LE('last_access', pd.Value(pd.DateTime(), now_ - expiration)))
+        row, success = data.insert(data.make_row(uid=uid, session_key=session_key, last_access=now_))
+        self._module('SessionLog').log(req, now_, row['session_id'].value(), uid, user.login())
         # Display info page for users without proper access
         def abort(title, text_id, form=None):
             texts = self._module('Texts')
@@ -543,16 +542,16 @@ class Session(PytisModule, wiking.Session):
             abort(_("Account not approved"), wiking.cms.texts.unapproved)
     
     def failure(self, req, user, login):
-        self._module('SessionLog').log(req, mx.DateTime.now().gmtime(), None,
+        self._module('SessionLog').log(req, pytis.data.DateTime.datetime(), None,
                                        user and user.uid(), login)
         
     def check(self, req, user, session_key):
         row = self._data.get_row(uid=user.uid(), session_key=session_key)
         if row:
-            now = mx.DateTime.now().gmtime()
-            expiration = mx.DateTime.TimeDelta(hours=cfg.session_expiration)
-            if row['last_access'].value() > now - expiration:
-                self._data.update((row['session_id'],), self._data.make_row(last_access=now))
+            now_ = now()
+            expiration = datetime.datetime.timedelta(hours=cfg.session_expiration)
+            if row['last_access'].value() > now_ - expiration:
+                self._data.update((row['session_id'],), self._data.make_row(last_access=now_))
                 return True
         return False
 
@@ -658,7 +657,7 @@ class Config(SettingsManagementModule):
         record = self._record(req, row)
         try:
             record.update(theme_id=theme_id)
-        except pd.DBException, e:
+        except pd.DBException as e:
             return self._error_message(*self._analyze_exception(e))
     
 
@@ -1253,9 +1252,9 @@ class Pages(ContentManagementModule):
                             variants=titles.keys(), submenu=submenu)
         for row in self._data.get_rows(sorting=self._sorting, published=True):
             mapping_id = row['mapping_id'].value()
-            if not translations.has_key(mapping_id):
+            if mapping_id not in translations:
                 parent = row['parent'].value()
-                if not children.has_key(parent):
+                if parent not in children:
                     children[parent] = []
                 children[parent].append(row)
                 translations[mapping_id] = ({}, {})
@@ -1405,7 +1404,7 @@ class Pages(ContentManagementModule):
                 raise Redirect(self._current_record_uri(req, record))
         try:
             record.update(**values)
-        except pd.DBException, e:
+        except pd.DBException as e:
             req.message(self._error_message(*self._analyze_exception(e)), type=req.ERROR)
         else:
             req.message(_("The changes were published."))
@@ -1415,7 +1414,7 @@ class Pages(ContentManagementModule):
     def action_revert(self, req, record):
         try:
             record.update(_content=record['content'].value())
-        except pd.DBException, e:
+        except pd.DBException as e:
             req.message(self._error_message(*self._analyze_exception(e)), type=req.ERROR)
         else:
             req.message(_("The page contents was reverted to its previous state."))
@@ -1425,7 +1424,7 @@ class Pages(ContentManagementModule):
     def action_unpublish(self, req, record):
         try:
             record.update(published=False)
-        except pd.DBException, e:
+        except pd.DBException as e:
             req.message(self._error_message(*self._analyze_exception(e)), type=req.ERROR)
         else:
             req.message(_("The page was unpublished."))
@@ -1854,7 +1853,7 @@ class Planner(News):
         list_layout = pp.ListLayout('date_title', meta=('author', 'timestamp'), content='content',
                                     anchor="item-%s")
         def _check_date(self, date):
-            if date < today():
+            if date < pd.Date.datetime():
                 return _("Date in the past")
         def _date(self, record, start_date, end_date):
             date = record['start_date'].export(show_weekday=True)
@@ -1871,8 +1870,9 @@ class Planner(News):
     _RSS_DATE_COLUMN = None
     def _condition(self, req, **kwargs):
         scondition = super(Planner, self)._condition(req, **kwargs)
-        condition = pd.OR(pd.GE('start_date', pd.Value(pd.Date(), today())),
-                          pd.GE('end_date', pd.Value(pd.Date(), today())))
+        today = pd.Date.datetime()
+        condition = pd.OR(pd.GE('start_date', pd.Value(pd.Date(), today)),
+                          pd.GE('end_date', pd.Value(pd.Date(), today)))
         if scondition:
             return pd.AND(scondition, condition)
         else:
@@ -1929,7 +1929,7 @@ class Discussions(News):
             try:
                 transaction = self._transaction()
                 self._in_transaction(transaction, self._insert, req, record, transaction)
-            except pd.DBException, e:
+            except pd.DBException as e:
                 req.message(self._error_message(*self._analyze_exception(e)), type=req.ERROR)
             else:
                 req.message(_("Your comment was posted to the discussion."))
@@ -2153,7 +2153,7 @@ class CommonTexts(SettingsManagementModule):
         """
         texts = class_.Spec._texts
         label = text.label()
-        if not texts.has_key(label):
+        if label not in texts:
             texts[label] = text
 
     def _select_language(self, req, lang):
@@ -2473,7 +2473,7 @@ class TextReferrer(object):
                 email_args = self._email_args(req, text, lang=lang, args=args)
                 email_args['cc'] = list(email_args['cc']) + list(kwargs.get('cc', []))
                 for k, v in kwargs.items():
-                    if not email_args.has_key(k):
+                    if k not in email_args:
                         email_args[k] = v
                 lang_args[lang] = email_args
             return email_args
diff --git a/lib/wiking/cms/users.py b/lib/wiking/cms/users.py
index 0b67659..66e5681 100644
--- a/lib/wiking/cms/users.py
+++ b/lib/wiking/cms/users.py
@@ -29,6 +29,7 @@ L{RoleSets}, L{RoleMembers}, L{ApplicationRoles}.
 
 """
 
+import datetime
 import time
 import weakref
 
@@ -437,7 +438,7 @@ class Users(UserManagementModule):
                 return firstname or surname or login
         def _registration_expiry(self):
             expiry_days = cfg.registration_expiry_days
-            return mx.DateTime.now().gmtime() + mx.DateTime.TimeDelta(hours=expiry_days*24)
+            return pd.DateTime.datetime() + datetime.timedelta(days=expiry_days)
         @staticmethod
         def _generate_registration_code():
             import random
@@ -518,7 +519,7 @@ class Users(UserManagementModule):
         def _state_info(self, record, state, regexpire):
             req = record.req()
             if state == Users.AccountState.NEW:
-                if regexpire > mx.DateTime.now().gmtime():
+                if regexpire > pd.DateTime.datetime():
                     texts = (_("The activation code was not yet confirmed by the user. Therefore "
                                "it is not possible to trust that given e-mail address belongs to "
                                "the person who requested the registration."),
@@ -713,7 +714,7 @@ class Users(UserManagementModule):
         def cms_text(cms_text):
             texts = self._module('Texts')
             return texts.parsed_text(req, cms_text, lang=req.prefered_language())
-        if not self._LAYOUT.has_key(action): # Allow overriding this layout in derived classes.
+        if action not in self._LAYOUT: # Allow overriding this layout in derived classes.
             if action == 'view':
                 # Translators: Personal data -- first name, surname, nickname ...
                 layout = [FieldSet(_("Personal data"), ('firstname', 'surname', 'nickname',)),
@@ -942,7 +943,7 @@ class Users(UserManagementModule):
     def _change_state(self, req, record, state):
         try:
             record.update(state=state)
-        except pd.DBException, e:
+        except pd.DBException as e:
             req.message(self._error_message(*self._analyze_exception(e)), type=req.ERROR)
         else:
             if state == self.AccountState.ENABLED:
@@ -963,7 +964,7 @@ class Users(UserManagementModule):
     
     def action_enable(self, req, record):
         if record['state'].value() == self.AccountState.NEW and not req.param('submit'):
-            if record['regexpire'].value() <= mx.DateTime.now().gmtime():
+            if record['regexpire'].value() <= pd.DateTime.datetime():
                 req.message(_("The registration expired on %(date)s.",
                               date=record['regexpire'].export()), type=req.WARNING)
             form = self._form(pw.ShowForm, req, record, layout=self._layout(req, 'view', record))
@@ -1040,7 +1041,7 @@ class Users(UserManagementModule):
         user_cache = self._user_cache.get(req)
         if user_cache is None:
             user_cache = self._user_cache[req] = {}
-        elif user_cache.has_key(key):
+        elif key in user_cache:
             return user_cache[key]
         # Get the user data from db
         if login is not None and uid is None:
@@ -1105,7 +1106,7 @@ class Users(UserManagementModule):
         user_cache = self._find_users_cache.get(req)
         if user_cache is None:
             user_cache = self._find_users_cache[req] = {}
-        elif user_cache.has_key(key):
+        elif key in user_cache:
             return user_cache[key]
         if role is not None:
             role_user_ids = self._module('RoleMembers').user_ids(role)
@@ -1298,7 +1299,7 @@ class Registration(Module, ActionHandler):
                 if cfg.password_storage == 'md5':
                     try:
                         password = users_module.reset_password(user)
-                    except Exception, e:
+                    except Exception as e:
                         req.message(unicode(e.exception()), type=req.ERROR)
                         return Document(title, self.ReminderForm())
                     # Translators: Credentials such as password...
diff --git a/lib/wiking/db.py b/lib/wiking/db.py
index ab6ff95..2d3e069 100644
--- a/lib/wiking/db.py
+++ b/lib/wiking/db.py
@@ -16,6 +16,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
+import collections
 import string
 
 from wiking import *
@@ -466,7 +467,7 @@ class PytisModule(Module, ActionHandler):
                 if match:
                     if isinstance(msg, tuple):
                         field_id, msg = msg
-                    elif match.groupdict().has_key('id'):
+                    elif 'id' in match.groupdict():
                         matched_id = match.group('id')
                         if matched_id.endswith('_key'):
                             # The identifier is (maybe) a name of a PostgreSQL UNIQUE index.
@@ -594,7 +595,7 @@ class PytisModule(Module, ActionHandler):
     def _action_menu(self, req, record=None, actions=None, uri=None, **kwargs):
         def visible(action):
             result = action.visible()
-            if callable(result):
+            if isinstance(result, collections.Callable):
                 context = action.context()
                 if context == pp.ActionContext.RECORD:
                     args = (record,)
@@ -679,7 +680,7 @@ class PytisModule(Module, ActionHandler):
         """
         if cid is None:
             return uri and req.make_uri(uri +'/'+ record[self._referer].export(), **kwargs)
-        if self._links.has_key(cid):
+        if cid in self._links:
             value_column, link = self._links[cid]
             try:
                 module = self._module(link.name())
@@ -756,13 +757,13 @@ class PytisModule(Module, ActionHandler):
             uri = self._current_base_uri(req, record)
         if issubclass(form, pw.BrowseForm):
             kwargs['req'] = req
-            if not kwargs.has_key('limits'):
+            if 'limits' not in kwargs:
                 kwargs['limits'] = self._BROWSE_FORM_LIMITS
-            if not kwargs.has_key('limit'):
+            if 'limit' not in kwargs:
                 kwargs['limit'] = self._BROWSE_FORM_DEFAULT_LIMIT
             kwargs['allow_query_search'] = self._ALLOW_QUERY_SEARCH
             kwargs['filter_fields'] = self._filter_fields(req)
-            if not kwargs.has_key('immediate_filters'):
+            if 'immediate_filters' not in kwargs:
                 kwargs['immediate_filters'] = cfg.immediate_filters
         layout = kwargs.get('layout')
         if layout is not None and not isinstance(layout, pp.GroupSpec):
@@ -1061,9 +1062,9 @@ class PytisModule(Module, ActionHandler):
                 main_form_column = self._type[binding_column].enumerator().value_column()
                 prefill[binding_column] = binding_record[main_form_column].value()
         if self._OWNER_COLUMN and self._SUPPLY_OWNER and req.user() \
-               and not prefill.has_key(self._OWNER_COLUMN):
+               and self._OWNER_COLUMN not in prefill:
             prefill[self._OWNER_COLUMN] = req.user().uid()
-        if self._LIST_BY_LANGUAGE and not prefill.has_key('lang'):
+        if self._LIST_BY_LANGUAGE and 'lang' not in prefill:
             lang = req.prefered_language(raise_error=False)
             if lang:
                 prefill['lang'] = lang
@@ -1083,7 +1084,7 @@ class PytisModule(Module, ActionHandler):
             if not isinstance(type, (pd.Binary, pd.Password)):
                 if req.has_param(key):
                     result[key] = req.param(key)
-                elif prefill.has_key(key):
+                elif key in prefill:
                     result[key] = type.export(prefill[key])
         return result
 
@@ -1486,7 +1487,7 @@ class PytisModule(Module, ActionHandler):
             else:
                 cache_key = key
             try:
-                if self._link_cache.has_key(cache_key):
+                if cache_key in self._link_cache:
                     return self._link_cache[cache_key]
             except TypeError:           # catch unhashable keys
                 pass
@@ -1635,7 +1636,7 @@ class PytisModule(Module, ActionHandler):
                 try:
                     transaction = self._insert_transaction(req, record)
                     self._in_transaction(transaction, self._insert, req, record, transaction)
-                except pd.DBException, e:
+                except pd.DBException as e:
                     errors = (self._analyze_exception(e),)
                 else:
                     return self._redirect_after_insert(req, record)
@@ -1675,7 +1676,7 @@ class PytisModule(Module, ActionHandler):
                 transaction = self._update_transaction(req, record)
                 self._in_transaction(transaction, self._update, req, record, transaction)
                 record.reload()
-            except pd.DBException, e:
+            except pd.DBException as e:
                 errors = (self._analyze_exception(e),)
             else:
                 return self._redirect_after_update(req, record)
@@ -1690,7 +1691,7 @@ class PytisModule(Module, ActionHandler):
             try:
                 transaction = self._delete_transaction(req, record)
                 self._in_transaction(transaction, self._delete, req, record, transaction)
-            except pd.DBException, e:
+            except pd.DBException as e:
                 req.message(self._error_message(*self._analyze_exception(e)), type=req.ERROR)
             else:
                 return self._redirect_after_delete(req, record)
@@ -2071,7 +2072,7 @@ class PytisRssModule(PytisModule):
                     return default
                 else:
                     return lambda record: None
-            elif callable(spec):
+            elif isinstance(spec, collections.Callable):
                 return lambda record: translate(spec(req, record))
             elif raw:
                 return lambda record: translate(record[spec].value())
@@ -2177,7 +2178,7 @@ class Publishable(object):
             if publish != record['published'].value():
                 Publishable._change_published(record)
                 record.reload()
-        except pd.DBException, e:
+        except pd.DBException as e:
             req.message(self._error_message(*self._analyze_exception(e)), type=req.ERROR)
         else:
             req.message(publish and self._MSG_PUBLISHED or self._MSG_UNPUBLISHED)
diff --git a/lib/wiking/export.py b/lib/wiking/export.py
index 778ffe7..07bd4a9 100644
--- a/lib/wiking/export.py
+++ b/lib/wiking/export.py
@@ -145,7 +145,7 @@ class Exporter(lcg.StyledHtmlExporter, lcg.HtmlExporter):
                 attr = getattr(self, '_'+name+'_attr')(context)
             else:
                 attr = {}
-            if self._PART_TITLE.has_key(name):
+            if name in self._PART_TITLE:
                 attr['title'] = self._PART_TITLE[name]
             return self._generator.div(content, id=name.replace('_', '-'), **attr)
         else:
diff --git a/lib/wiking/handler.py b/lib/wiking/handler.py
index 36867ff..e50e460 100644
--- a/lib/wiking/handler.py
+++ b/lib/wiking/handler.py
@@ -37,7 +37,7 @@ class Handler(object):
             separator = value.find(':') != -1 and ':' or ','
             return tuple([d.strip() for d in value.split(separator)])
         # Read the configuration file first, so that the Apache options have a higher priority.
-        if options.has_key('config_file'):
+        if 'config_file' in options:
             cfg.user_config_file = options.pop('config_file')
         for name, value in options.items():
             if name == 'translation_path':
@@ -137,35 +137,35 @@ class Handler(object):
                 else:
                     # int is deprecated! Just for backwards compatibility.  
                     assert result is None or isinstance(result, int)
-            except RequestError, error:
+            except RequestError as error:
                 try:
                     req.user()
                 except RequestError:
                     # Ignore all errors within authentication except for AuthenticationError.
                     pass
-                except AuthenticationError, auth_error:
+                except AuthenticationError as auth_error:
                     self._serve_error_document(req, auth_error)
                 self._serve_error_document(req, error)
             except (ClosedConnection, Redirect):
                 raise
-            except Exception, e:
+            except Exception as e:
                 # Try to return a nice error document produced by the exporter.
                 try:
                     return application.handle_exception(req, e)
-                except RequestError, error:
+                except RequestError as error:
                     return self._serve_error_document(req, error)
         except ClosedConnection:
             pass
-        except Redirect, r:
+        except Redirect as r:
             req.redirect(r.uri(), args=r.args(), permanent=r.permanent())
-        except Exception, e:
+        except Exception as e:
             # If error document export fails, return a minimal error page.  It is reasonable to
             # assume, that if RequestError handling fails, somethong is wrong with the exporter and
             # error document export will fail too, so it is ok, to have them handled both at the
             # same level above.
             try:
                 application.handle_exception(req, e)
-            except RequestError, error:
+            except RequestError as error:
                 self._serve_minimal_error_document(req, error)
             
     def handle(self, req):
diff --git a/lib/wiking/mod_python_interface.py b/lib/wiking/mod_python_interface.py
index f8f71fa..def13a1 100644
--- a/lib/wiking/mod_python_interface.py
+++ b/lib/wiking/mod_python_interface.py
@@ -66,11 +66,11 @@ class ModPythonRequest(wiking.Request):
         return self._params.keys()
         
     def has_param(self, name):
-        return self._params.has_key(name)
+        return name in self._params
     
     def set_param(self, name, value):
         if value is None:
-            if self._params.has_key(name):
+            if name in self._params:
                 del self._params[name]
         else:
             self._params[name] = value
@@ -111,13 +111,13 @@ class ModPythonRequest(wiking.Request):
         self._req.status = status_code
         try:
             self._req.send_http_header()
-        except IOError, e:
+        except IOError as e:
             raise wiking.ClosedConnection(str(e))
 
     def write(self, data):
         try:
             self._req.write(data)
-        except IOError, e:
+        except IOError as e:
             raise wiking.ClosedConnection(str(e))
         
     def option(self, name, default=None):
diff --git a/lib/wiking/modules.py b/lib/wiking/modules.py
index 4efbcbf..f8cc986 100644
--- a/lib/wiking/modules.py
+++ b/lib/wiking/modules.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Brailcom, o.p.s.
+# Copyright (C) 2005-2011 Brailcom, o.p.s.
 # Author: Tomas Cerha.
 #
 # This program is free software; you can redistribute it and/or modify
@@ -15,6 +15,8 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
+import pytis.data
+
 from wiking import *
 
 """Definition of the basic Wiking module classes."""
@@ -506,7 +508,7 @@ class CookieAuthentication(object):
             password_expiration = user.password_expiration()
             if password_expiration is not None and req.uri() != self.password_change_uri(req):
                 import datetime
-                if password_expiration <= datetime.date.today():
+                if password_expiration <= pytis.data.Date.datetime():
                     raise PasswordExpirationError()
         return user
 
diff --git a/lib/wiking/request.py b/lib/wiking/request.py
index cdc771b..44d782f 100644
--- a/lib/wiking/request.py
+++ b/lib/wiking/request.py
@@ -15,7 +15,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-import os, string, Cookie, re, urllib, mx.DateTime, httplib
+import os, string, Cookie, re, urllib, datetime, httplib
 import wiking, lcg, pytis
 from wiking import log, OPR
 
@@ -363,7 +363,7 @@ class Request(ServerInterface):
                         if type not in self._MESSAGE_TYPES:
                             raise ValueError("Invalid type:", type)
                         message = urllib.unquote(quoted).decode(self._encoding)
-                    except Exception, e:
+                    except Exception as e:
                         log(OPR, "Error unpacking stored messages:", e)
                     else:
                         messages.append((message, type))
@@ -372,7 +372,7 @@ class Request(ServerInterface):
 
     def cookie(self, name, default=None):
         """Get the value of given cookie as unicode or return DEFAULT if cookie was not set."""
-        if self._cookies.has_key(name):
+        if name in self._cookies:
             try:
                 return unicode(self._cookies[name].value, self._encoding)
             except UnicodeDecodeError:
@@ -391,7 +391,7 @@ class Request(ServerInterface):
 
         """
         if value is None:
-            if self._cookies.has_key(name):
+            if name in self._cookies:
                 del self._cookies[name]
         else:
             if isinstance(value, unicode):
@@ -521,14 +521,15 @@ class Request(ServerInterface):
         except OSError:
             log(OPR, "File not found:", filename)
             raise wiking.NotFound()
-        mtime = mx.DateTime.localtime(info.st_mtime)
+        mtime = datetime.datetime.utcfromtimestamp(info.st_mtime)
         since_header = self.header('If-Modified-Since')
+        date_format = ''
         if since_header:
-            since = mx.DateTime.ARPA.ParseDateTime(since_header)
+            since = parse_http_date(since_header)
             if mtime == since:
                 self.start_response(httplib.NOT_MODIFIED)
                 return
-        self.set_header('Last-Modified', mx.DateTime.ARPA.str(mtime))
+        self.set_header('Last-Modified', format_http_date(mtime))
         self.start_response(content_type=content_type, content_length=info.st_size)
         f = file(filename)
         if lock:
diff --git a/lib/wiking/util.py b/lib/wiking/util.py
index d838a09..cd966cb 100644
--- a/lib/wiking/util.py
+++ b/lib/wiking/util.py
@@ -16,7 +16,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 import lcg, pytis
-import sys, email.Header, httplib
+import sys, email.Header, httplib, collections, datetime
 from xml.sax import saxutils
 
 DBG = pytis.util.DEBUG
@@ -506,7 +506,7 @@ class Theme(object):
                                       for key in self._colors.keys()])}
         
     def _color(self, key, colors):
-        if colors.has_key(key):
+        if key in colors:
             return colors[key]
         else:
             inherit = self._colors[key].inherit()
@@ -671,8 +671,8 @@ class LoginPanel(Panel):
                         result += g.br()+'\n' + lcg.concat(role_names, separator=', ')
                 expiration = user.password_expiration()
                 if expiration:
-                    import datetime
-                    if datetime.date.today() >= expiration:
+                    import pytis.data
+                    if pytis.data.Date.datetime() >= expiration:
                         # Translators: Information text on login panel.
                         result += g.br() +'\n'+ _("Your password expired")
                     else:
@@ -860,10 +860,10 @@ class Document(object):
         parent = None
         for i in range(len(req.path)-1):
             key = '/'.join(req.path[:len(req.path)-i-1])
-            if nodes.has_key(key):
+            if key in nodes:
                 parent = nodes[key]
                 break
-        if nodes.has_key(id):
+        if id in nodes:
             node = nodes[id]
         else: 
             # Create the current document's node if it was not created with the menu.
@@ -1005,9 +1005,9 @@ class ChannelContent(object):
         
         @type date: str, callable or None
         @param date: Item date field specification.  The result must be
-        'mx.DateTime' instance.  If column name is used, its type must be
-        'pytis.data.DateTime'.  If function is used, it must return an
-        'mx.DateTime' instance.
+        'datetime.datetime' instance.  If column name is used, its type must be
+        'pytis.data.DateTime'.  If function is used, it must return a
+        'datetime.datetime' instance.
         
         @type author: str, callable or None
         @param author: Item author field specification.
@@ -1016,11 +1016,11 @@ class ChannelContent(object):
         specifications.
 
         """
-        assert isinstance(title, str) or callable(title), title
-        assert link is None or isinstance(link, str) or callable(link), link
-        assert descr is None or isinstance(descr, str) or callable(descr), descr
-        assert date is None or isinstance(date, str) or callable(date), date
-        assert author is None or isinstance(author, str) or callable(author), author
+        assert isinstance(title, str) or isinstance(title, collections.Callable), title
+        assert link is None or isinstance(link, str) or isinstance(link, collections.Callable), link
+        assert descr is None or isinstance(descr, str) or isinstance(descr, collections.Callable), descr
+        assert date is None or isinstance(date, str) or isinstance(date, collections.Callable), date
+        assert author is None or isinstance(author, str) or isinstance(author, collections.Callable), author
         self._title = title
         self._link = link
         self._descr = descr
@@ -1068,8 +1068,7 @@ class RssWriter(object):
     def item(self, link, title, guid=None, description=None, pubdate=None, author=None):
         """Call repeatedly to write a single channel item."""
         if pubdate:
-            import mx.DateTime
-            pubdate = mx.DateTime.ARPA.str(pubdate.localtime())
+            pubdate = format_http_string(pubdate)
         self._stream.write('<item>\n')
         self._write_tag('title', title or '')
         self._write_tag('guid', guid or link or '', escape=False)
@@ -1160,7 +1159,7 @@ class ActionCtrl(lcg.Content):
         g = context.generator()
         action = self._action
         enabled = action.enabled()
-        if callable(enabled):
+        if isinstance(enabled, collections.Callable):
             enabled = enabled(self._row)
         uri = self._uri
         args = dict(action=action.id(), **action.kwargs())
@@ -1371,7 +1370,7 @@ class Action(pytis.presentation.Action):
     """
     def __init__(self, title, id, allow_referer=True, **kwargs):
         self._allow_referer = allow_referer
-        if kwargs.has_key('context') and kwargs['context'] is None:
+        if 'context' in kwargs and kwargs['context'] is None:
             # Make context specification in applications backwards compatible.
             kwargs['context'] = pp.ActionContext.GLOBAL
         super(Action, self).__init__(id, title, **kwargs)
@@ -1472,7 +1471,7 @@ class Specification(pp.Specification):
         if self.table is None:
             self.table = pytis.util.camel_case_to_lower(module.name(), '_')
         actions = self.actions
-        if callable(actions):
+        if isinstance(actions, collections.Callable):
             actions = actions()
         actions = list(actions)
         for base in module.__bases__ + (module,):
@@ -1506,7 +1505,7 @@ class Binding(pp.Binding):
         enabled = kwargs.pop('enabled', None)
         super(Binding, self).__init__(*args, **kwargs)
         assert form is None or issubclass(form, pytis.web.BrowseForm), form
-        assert enabled is None or callable(enabled), enabled
+        assert enabled is None or isinstance(enabled, collections.Callable), enabled
         self._form = form
         self._enabled = enabled
 
@@ -1534,7 +1533,7 @@ class WikingResolver(pytis.util.Resolver):
         for python_module_name in cfg.modules:
             python_module = self._import_python_module(python_module_name)
             for name, mod in python_module.__dict__.items():
-                if not modules.has_key(name) and type(mod) == type(Module) \
+                if name not in modules and type(mod) == type(Module) \
                        and issubclass(mod, Module):
                     modules[name] = mod
         return tuple(modules.values())
@@ -1820,7 +1819,7 @@ def send_mail(addr, subject, text, sender=None, html=None, export=False, lang=No
             out.close()
             server.quit()
         return None
-    except Exception, e:
+    except Exception as e:
         return str(e)
 
 def validate_email_address(address, helo=None):
@@ -1860,14 +1859,14 @@ def validate_email_address(address, helo=None):
         # Translators: Computer terminology. `gmail.com' is a domain name in email address
         # `joe at gmail.com'.
         return False, _("Domain not found")
-    except Exception, e:
+    except Exception as e:
         return False, str(e) or e.__class__.__name__
     if mxhosts is None:
         try:
             ahosts = dns.resolver.query(domain, 'A')
         except dns.resolver.NoAnswer:
             return False, _("Domain not found")
-        except Exception, e:
+        except Exception as e:
             return False, str(e) or e.__class__.__name__
         hosts = [h.to_text() for h in ahosts]
     else:
@@ -1888,7 +1887,7 @@ def validate_email_address(address, helo=None):
                     raise Exception('SMTP command RCPT failed', code, message)
                 smtp.quit()
                 break
-            except Exception, e:
+            except Exception as e:
                 reasons += ('%s: %s; ' % (host, e,))
         else:
             return False, reasons
@@ -1935,3 +1934,57 @@ def translator(lang):
         return lcg.GettextTranslator(str(lang), path=cfg.translation_path, fallback=True)
     else:
         return lcg.NullTranslator()
+
+_WKDAY = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun',)
+_MONTH = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',)
+    
+def format_http_date(dt):
+    """Return datetime as a basestring in the RFC 1123 format.
+
+    Arguments:
+
+      dt -- 'datetime.datetime' instance to be formatted
+
+    """
+    formatted = dt.strftime('%%s, %d %%s %Y %H:%M:%S GMT')
+    formatted = formatted % (_WKDAY[dt.weekday()], _MONTH[dt.month-1],)
+    return formatted
+
+def parse_http_date(date_string):
+    """Return datetime corresponding to RFC 2616 date_string.
+
+    Arguments:
+    
+      date_string -- basestring representing date and time in one of the
+        formats supported by RFC 2616
+
+    Return corresponding 'datetime.datetime' instance.
+    
+    """
+    date_string.strip()
+    # Remove weekday
+    pos = date_string.find(' ')
+    if pos < 0:
+        raise Exception("Invalid date format")
+    date_string = date_string[pos+1:].lstrip()
+    # Remove GMT
+    if date_string[-3:] == 'GMT':
+        date_string = date_string[:-3].rstrip()
+    # Replace month name by a number
+    for i in range(len(_MONTH)):
+        m = _MONTH[i]
+        pos = date_string.find(m)
+        if pos >= 0:
+            date_string = '%s%02d%s' % (date_string[:pos], i+1, date_string[pos+3:],)
+            break
+    # Parse the date
+    dt = None
+    for format_ in ('%d %m %Y %H:%M:%S', '%d-%m-%y %H:%M:%S', '%m %d %H:%M:%S %Y',):
+        try:
+            dt = datetime.datetime.strptime(date_string, format_)
+            break
+        except ValueError:
+            pass
+    if dt is None:
+        raise Exception("Invalid date format")
+    return dt


hooks/post-receive
-- 
Wiking



More information about the Wiking-cvs mailing list