Commit 58af3054 authored by Hanno Schlichting's avatar Hanno Schlichting

The ZPublisher HTTP request has now both the debug and locale attributes...

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.
parent 77428856
...@@ -69,6 +69,15 @@ Zope Changes ...@@ -69,6 +69,15 @@ Zope Changes
Features added 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: now uses zope.sendmail for delivering the mail. With this change
MailHost integrates with the Zope transaction system (avoids sending dupe MailHost integrates with the Zope transaction system (avoids sending dupe
emails in case of conflict errors). In addition MailHost now provides emails in case of conflict errors). In addition MailHost now provides
......
...@@ -120,14 +120,11 @@ class EditView(BrowserView): ...@@ -120,14 +120,11 @@ class EditView(BrowserView):
names=self.fieldNames) names=self.fieldNames)
if changed: if changed:
self.changed() self.changed()
# XXX: Needs locale support: formatter = self.request.locale.dates.getFormatter(
#formatter = self.request.locale.dates.getFormatter( 'dateTime', 'medium')
# 'dateTime', 'medium')
#status = _("Updated on ${date_time}",
# mapping={'date_time':
# formatter.format(datetime.utcnow())})
status = _("Updated on ${date_time}", status = _("Updated on ${date_time}",
mapping={'date_time': str(datetime.utcnow())}) mapping={'date_time':
formatter.format(datetime.utcnow())})
self.update_status = status self.update_status = status
return status return status
......
...@@ -60,26 +60,7 @@ class FormBase(FiveFormlibMixin, form.FormBase): ...@@ -60,26 +60,7 @@ class FormBase(FiveFormlibMixin, form.FormBase):
class EditFormBase(FiveFormlibMixin, form.EditFormBase): 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): class DisplayFormBase(FiveFormlibMixin, form.DisplayFormBase):
pass pass
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
__version__='$Revision: 1.96 $'[11:-2] __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 types import StringType, UnicodeType
from BaseRequest import BaseRequest, quote from BaseRequest import BaseRequest, quote
from HTTPResponse import HTTPResponse from HTTPResponse import HTTPResponse
...@@ -25,6 +25,8 @@ from TaintedString import TaintedString ...@@ -25,6 +25,8 @@ from TaintedString import TaintedString
from maybe_lock import allocate_lock from maybe_lock import allocate_lock
xmlrpc=None # Placeholder for module that we'll import if we have to. 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 from zope.publisher.base import DebugFlags
# This may get overwritten during configuration # This may get overwritten during configuration
...@@ -240,6 +242,26 @@ class HTTPRequest(BaseRequest): ...@@ -240,6 +242,26 @@ class HTTPRequest(BaseRequest):
""" """
return self._client_addr 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): def __init__(self, stdin, environ, response, clean=0):
self._orig_env=environ self._orig_env=environ
# Avoid the overhead of scrubbing the environment in the # Avoid the overhead of scrubbing the environment in the
...@@ -265,7 +287,8 @@ class HTTPRequest(BaseRequest): ...@@ -265,7 +287,8 @@ class HTTPRequest(BaseRequest):
self._steps=[] self._steps=[]
self._lazies={} self._lazies={}
self._debug = DebugFlags() 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'): if environ.has_key('REMOTE_ADDR'):
self._client_addr = environ['REMOTE_ADDR'] self._client_addr = environ['REMOTE_ADDR']
...@@ -1229,16 +1252,17 @@ class HTTPRequest(BaseRequest): ...@@ -1229,16 +1252,17 @@ class HTTPRequest(BaseRequest):
# is discouraged and is likely to be deprecated in the future. # is discouraged and is likely to be deprecated in the future.
# request.get(key) or request[key] should be used instead # request.get(key) or request[key] should be used instead
def __getattr__(self, key, default=_marker, returnTaints=0): 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) v = self.get(key, default, returnTaints=returnTaints)
if v is _marker: 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 raise AttributeError, key
return v return v
......
...@@ -734,7 +734,7 @@ class RequestTests( unittest.TestCase ): ...@@ -734,7 +734,7 @@ class RequestTests( unittest.TestCase ):
self.assertEqual(f.next(),'test\n') self.assertEqual(f.next(),'test\n')
f.seek(0) f.seek(0)
self.assertEqual(f.xreadlines(),f) self.assertEqual(f.xreadlines(),f)
def testDebug(self): def testDebug(self):
TEST_ENVIRON = { TEST_ENVIRON = {
'REQUEST_METHOD': 'GET', 'REQUEST_METHOD': 'GET',
...@@ -743,37 +743,116 @@ class RequestTests( unittest.TestCase ): ...@@ -743,37 +743,116 @@ class RequestTests( unittest.TestCase ):
} }
from StringIO import StringIO from StringIO import StringIO
from ZPublisher.HTTPRequest import HTTPRequest from ZPublisher.HTTPRequest import HTTPRequest
from zope.publisher.base import DebugFlags
s = StringIO('') s = StringIO('')
# accessing request.debug from non-Zope3 code will raise an # when accessing request.debug we will see the DebugFlags instance
# AttributeError
env = TEST_ENVIRON.copy() env = TEST_ENVIRON.copy()
request = HTTPRequest(s, env, None) request = HTTPRequest(s, env, None)
request.processInputs() self.assert_(isinstance(request.debug, DebugFlags))
self.assertRaises(AttributeError, getattr, request, 'debug') # 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 # request.debug will actually yield a 'debug' form variable
# exists # if it exists
env = TEST_ENVIRON.copy() env = TEST_ENVIRON.copy()
env['QUERY_STRING'] = 'debug=1' env['QUERY_STRING'] = 'debug=1'
request = HTTPRequest(s, env, None) request = HTTPRequest(s, env, None)
request.processInputs() request.processInputs()
self.assertEqual(request.debug, '1') self.assertEqual(request.debug, '1')
self.assertEqual(request.get('debug'), '1')
self.assertEqual(request['debug'], '1')
# 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)
# 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))
def testMethod(self): def testMethod(self):
TEST_ENVIRON = { TEST_ENVIRON = {
'REQUEST_METHOD': 'GET', 'REQUEST_METHOD': 'GET',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment