[Zope-Checkins] SVN: Zope/trunk/ The ZPublisher HTTP request has now both the debug and locale attributes available, like its Zope 3 counterpart, as discussed in http://mail.zope.org/pipermail/zope-dev/2007-September/029719.html.

Hanno Schlichting plone at hannosch.info
Sun Sep 16 13:15:43 EDT 2007


Log message for revision 79698:
  The ZPublisher HTTP request has now both the debug and locale attributes available, like its Zope 3 counterpart, as discussed in http://mail.zope.org/pipermail/zope-dev/2007-September/029719.html.
  

Changed:
  U   Zope/trunk/doc/CHANGES.txt
  U   Zope/trunk/lib/python/Products/Five/form/__init__.py
  U   Zope/trunk/lib/python/Products/Five/formlib/formbase.py
  U   Zope/trunk/lib/python/ZPublisher/HTTPRequest.py
  U   Zope/trunk/lib/python/ZPublisher/tests/testHTTPRequest.py

-=-
Modified: Zope/trunk/doc/CHANGES.txt
===================================================================
--- Zope/trunk/doc/CHANGES.txt	2007-09-16 16:54:06 UTC (rev 79697)
+++ Zope/trunk/doc/CHANGES.txt	2007-09-16 17:15:42 UTC (rev 79698)
@@ -69,6 +69,15 @@
 
     Features added
 
+      - The ZPublisher HTTP request has now both the debug and locale
+        attributes available, like its Zope 3 counterpart. The debug attribute
+        was so far limited to code from the zope.* namespace in order to make
+        the Zope 3 ZPT engine work. The locale attribute provides access to an
+        zope.i18n.interfaces.locales.ILocale object with access to locale
+        related information like date / time formatting or translated language
+        and country names. Form variables of both debug and locale will shadow
+        these two attributes and their use is therefor discouraged.
+
       - MailHost: now uses zope.sendmail for delivering the mail. With this change
         MailHost integrates with the Zope transaction system (avoids sending dupe
         emails in case of conflict errors). In addition MailHost now provides 

Modified: Zope/trunk/lib/python/Products/Five/form/__init__.py
===================================================================
--- Zope/trunk/lib/python/Products/Five/form/__init__.py	2007-09-16 16:54:06 UTC (rev 79697)
+++ Zope/trunk/lib/python/Products/Five/form/__init__.py	2007-09-16 17:15:42 UTC (rev 79698)
@@ -120,14 +120,11 @@
                                  names=self.fieldNames)
                 if changed:
                     self.changed()
-                    # XXX: Needs locale support:
-                    #formatter = self.request.locale.dates.getFormatter(
-                    #    'dateTime', 'medium')
-                    #status = _("Updated on ${date_time}",
-                    #           mapping={'date_time':
-                    #                    formatter.format(datetime.utcnow())})
+                    formatter = self.request.locale.dates.getFormatter(
+                       'dateTime', 'medium')
                     status = _("Updated on ${date_time}",
-                               mapping={'date_time': str(datetime.utcnow())})
+                              mapping={'date_time':
+                                       formatter.format(datetime.utcnow())})
 
         self.update_status = status
         return status

Modified: Zope/trunk/lib/python/Products/Five/formlib/formbase.py
===================================================================
--- Zope/trunk/lib/python/Products/Five/formlib/formbase.py	2007-09-16 16:54:06 UTC (rev 79697)
+++ Zope/trunk/lib/python/Products/Five/formlib/formbase.py	2007-09-16 17:15:42 UTC (rev 79698)
@@ -60,27 +60,8 @@
 
 
 class EditFormBase(FiveFormlibMixin, form.EditFormBase):
+    pass
 
-    # Overrides formlib.form.EditFormBase.handle_edit_action, to remove
-    # dependecy on request.locale
-    
-    @form.action(_("Apply"), condition=form.haveInputWidgets)
-    def handle_edit_action(self, action, data):
-        if form.applyChanges(
-            self.context, self.form_fields, data, self.adapters):
-
-            zope.event.notify(
-                zope.lifecycleevent.ObjectModifiedEvent(self.context)
-                )
-            # TODO: Needs locale support. See also Five.form.EditView.
-            self.status = _(
-                "Updated on ${date_time}", 
-                mapping={'date_time': str(datetime.utcnow())}
-                )
-        else:
-            self.status = _('No changes')
-
-
 class DisplayFormBase(FiveFormlibMixin, form.DisplayFormBase):
     pass
 

Modified: Zope/trunk/lib/python/ZPublisher/HTTPRequest.py
===================================================================
--- Zope/trunk/lib/python/ZPublisher/HTTPRequest.py	2007-09-16 16:54:06 UTC (rev 79697)
+++ Zope/trunk/lib/python/ZPublisher/HTTPRequest.py	2007-09-16 17:15:42 UTC (rev 79698)
@@ -13,7 +13,7 @@
 
 __version__='$Revision: 1.96 $'[11:-2]
 
-import re, sys, os, time, random, codecs, inspect, tempfile
+import re, sys, os, time, random, codecs, tempfile
 from types import StringType, UnicodeType
 from BaseRequest import BaseRequest, quote
 from HTTPResponse import HTTPResponse
@@ -25,6 +25,8 @@
 from maybe_lock import allocate_lock
 xmlrpc=None # Placeholder for module that we'll import if we have to.
 
+from zope.i18n.interfaces import IUserPreferredLanguages
+from zope.i18n.locales import locales, LoadLocaleError
 from zope.publisher.base import DebugFlags
 
 # This may get overwritten during configuration
@@ -240,6 +242,26 @@
         """
         return self._client_addr
 
+    def setupLocale(self):
+        envadapter = IUserPreferredLanguages(self, None)
+        if envadapter is None:
+            self._locale = None
+            return
+
+        langs = envadapter.getPreferredLanguages()
+        for httplang in langs:
+            parts = (httplang.split('-') + [None, None])[:3]
+            try:
+                self._locale = locales.getLocale(*parts)
+                return
+            except LoadLocaleError:
+                # Just try the next combination
+                pass
+        else:
+            # No combination gave us an existing locale, so use the default,
+            # which is guaranteed to exist
+            self._locale = locales.getLocale(None, None, None)
+
     def __init__(self, stdin, environ, response, clean=0):
         self._orig_env=environ
         # Avoid the overhead of scrubbing the environment in the
@@ -265,8 +287,9 @@
         self._steps=[]
         self._lazies={}
         self._debug = DebugFlags()
+        # We don't set up the locale initially but just on first access
+        self._locale = _marker
 
-
         if environ.has_key('REMOTE_ADDR'):
             self._client_addr = environ['REMOTE_ADDR']
             if environ.has_key('HTTP_X_FORWARDED_FOR') and self._client_addr in trusted_proxies:
@@ -1229,16 +1252,17 @@
     # is discouraged and is likely to be deprecated in the future.
     # request.get(key) or request[key] should be used instead
     def __getattr__(self, key, default=_marker, returnTaints=0):
-        # ugly hack to make request.debug work for Zope 3 code (the
-        # ZPT engine, to be exact) while retaining request.debug
-        # functionality for all other code
-        if key == 'debug':
-            lastframe = inspect.currentframe().f_back
-            if lastframe.f_globals['__name__'].startswith('zope.'):
-                return self._debug
-        
         v = self.get(key, default, returnTaints=returnTaints)
         if v is _marker:
+            if key == 'locale':
+                # we only create the _locale on first access, as setting it
+                # up might be slow and we don't want to slow down every
+                # request
+                if self._locale is _marker:
+                    self.setupLocale()
+                return self._locale
+            if key == 'debug':
+                return self._debug
             raise AttributeError, key
         return v
 

Modified: Zope/trunk/lib/python/ZPublisher/tests/testHTTPRequest.py
===================================================================
--- Zope/trunk/lib/python/ZPublisher/tests/testHTTPRequest.py	2007-09-16 16:54:06 UTC (rev 79697)
+++ Zope/trunk/lib/python/ZPublisher/tests/testHTTPRequest.py	2007-09-16 17:15:42 UTC (rev 79698)
@@ -734,7 +734,7 @@
         self.assertEqual(f.next(),'test\n')
         f.seek(0)
         self.assertEqual(f.xreadlines(),f)
-	
+
     def testDebug(self):
         TEST_ENVIRON = {
             'REQUEST_METHOD': 'GET',
@@ -743,37 +743,116 @@
             }
         from StringIO import StringIO
         from ZPublisher.HTTPRequest import HTTPRequest
+        from zope.publisher.base import DebugFlags
         s = StringIO('')
 
-        # accessing request.debug from non-Zope3 code will raise an
-        # AttributeError
+        # when accessing request.debug we will see the DebugFlags instance
         env = TEST_ENVIRON.copy()
         request = HTTPRequest(s, env, None)
-        request.processInputs()
-        self.assertRaises(AttributeError, getattr, request, 'debug')
+        self.assert_(isinstance(request.debug, DebugFlags))
+        # It won't be available through dictonary lookup, though
+        self.assert_(request.get('debug') is None)
 
-        # or it will actually yield a 'debug' form variable if it
-        # exists
+        # request.debug will actually yield a 'debug' form variable
+        # if it exists
         env = TEST_ENVIRON.copy()
         env['QUERY_STRING'] = 'debug=1'
         request = HTTPRequest(s, env, None)
         request.processInputs()
         self.assertEqual(request.debug, '1')
+        self.assertEqual(request.get('debug'), '1')
+        self.assertEqual(request['debug'], '1')
 
-        # if we access request.debug from a Zope 3 package, however,
-        # we will see the DebugFlags instance
-        def getDebug(request):
-            return request.debug
-        # make a forged copy of getDebug that looks as if its module
-        # was a Zope 3 package
-        z3globals = globals().copy()
-        z3globals['__name__'] = 'zope.apackage'
-        import new
-        getDebugFromZope3 = new.function(getDebug.func_code, z3globals)
-        from zope.publisher.base import DebugFlags
-        self.assertEqual(getDebug(request), '1')
-        self.assert_(isinstance(getDebugFromZope3(request), DebugFlags))
-        
+        # we can still override request.debug with a form variable or directly
+        env = TEST_ENVIRON.copy()
+        request = HTTPRequest(s, env, None)
+        request.processInputs()
+        self.assert_(isinstance(request.debug, DebugFlags))
+        request.form['debug'] = '1'
+        self.assertEqual(request.debug, '1')
+        request['debug'] = '2'
+        self.assertEqual(request.debug, '2')
+
+    def testLocale(self):
+        TEST_ENVIRON = {
+            'HTTP_ACCEPT_LANGUAGE': 'en',
+            'REQUEST_METHOD': 'GET',
+            'SERVER_NAME': 'localhost',
+            'SERVER_PORT': '80',
+            }
+        from StringIO import StringIO
+        from ZPublisher.HTTPRequest import HTTPRequest
+        from zope.component import provideAdapter
+        from zope.publisher.browser import BrowserLanguages
+        from zope.publisher.interfaces.http import IHTTPRequest
+        from zope.i18n.interfaces import IUserPreferredLanguages
+        from zope.i18n.interfaces.locales import ILocale
+
+        provideAdapter(BrowserLanguages, [IHTTPRequest],
+                       IUserPreferredLanguages)
+        s = StringIO('')
+
+        # before accessing request.locale for the first time, request._locale
+        # is still a marker
+        from ZPublisher.HTTPRequest import _marker
+        env = TEST_ENVIRON.copy()
+        request = HTTPRequest(s, env, None)
+        self.assert_(request._locale is _marker)
+        # when accessing request.locale we will see an ILocale
+        self.assert_(ILocale.providedBy(request.locale))
+        # and request._locale has been set
+        self.assert_(request._locale is request.locale)
+        # It won't be available through dictonary lookup, though
+        self.assert_(request.get('locale') is None)
+
+        # request.locale will actually yield a 'locale' form variable
+        # if it exists
+        env = TEST_ENVIRON.copy()
+        env['QUERY_STRING'] = 'locale=1'
+        request = HTTPRequest(s, env, None)
+        request.processInputs()
+        self.assertEqual(request.locale, '1')
+        self.assertEqual(request.get('locale'), '1')
+        self.assertEqual(request['locale'], '1')
+
+        # we can still override request.locale with a form variable
+        env = TEST_ENVIRON.copy()
+        request = HTTPRequest(s, env, None)
+        request.processInputs()
+        self.assert_(ILocale.providedBy(request.locale))
+        request.form['locale'] = '1'
+        self.assertEqual(request.locale, '1')
+        request['locale'] = '2'
+        self.assertEqual(request.locale, '2')
+
+        # we should also test the correct semantics of the locale
+        for httplang in ('it', 'it-ch', 'it-CH', 'IT', 'IT-CH', 'IT-ch'):
+            env = TEST_ENVIRON.copy()
+            env['HTTP_ACCEPT_LANGUAGE'] = httplang
+            request = HTTPRequest(s, env, None)
+            locale = request.locale
+            self.assert_(ILocale.providedBy(locale))
+            parts = httplang.split('-')
+            lang = parts.pop(0).lower()
+            territory = variant = None
+            if parts:
+                territory = parts.pop(0).upper()
+            if parts:
+                variant = parts.pop(0).upper()
+            self.assertEqual(locale.id.language, lang)
+            self.assertEqual(locale.id.territory, territory)
+            self.assertEqual(locale.id.variant, variant)
+
+        # Now test for non-existant locale fallback
+        env = TEST_ENVIRON.copy()
+        env['HTTP_ACCEPT_LANGUAGE'] = 'xx'
+        request = HTTPRequest(s, env, None)
+        locale = request.locale
+        self.assert_(ILocale.providedBy(locale))
+        self.assert_(locale.id.language is None)
+        self.assert_(locale.id.territory is None)
+        self.assert_(locale.id.variant is None)
+
     def testMethod(self):
         TEST_ENVIRON = {
             'REQUEST_METHOD': 'GET',



More information about the Zope-Checkins mailing list