I forgot to attach the patch file to the original bug report. Here it is.
-- Dwayne C. Litzenberger <[EMAIL PROTECTED]>
diff -ruN ../pyl.orig/pylons-0.9.5/CHANGELOG pylons-0.9.5/CHANGELOG --- ../pyl.orig/pylons-0.9.5/CHANGELOG 2007-04-12 17:27:57.000000000 -0600 +++ pylons-0.9.5/CHANGELOG 2007-06-05 11:29:11.000000000 -0600 @@ -1,6 +1,15 @@ Pylons Changelog ================= +Backported from SVN repository (Jun 5th, 2007 - Debian) +* Fixed the validate decorator triggering the following error with + FormEncode>=0.7 and non-ascii rendered form content: + UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 10: + ordinal not in range(128) the form was passed in as an encoded string, but + some data or error messages were unicode strings; the form should be passed + in as a unicode string + Reported by Christoph Haas. + 0.9.5 (Apr 11th, 2007) * Fixed a Python 2.3 incompatibility with paster shell, causing the Exception: diff -ruN ../pyl.orig/pylons-0.9.5/pylons/decorators/__init__.py pylons-0.9.5/pylons/decorators/__init__.py --- ../pyl.orig/pylons-0.9.5/pylons/decorators/__init__.py 2007-04-12 17:17:54.000000000 -0600 +++ pylons-0.9.5/pylons/decorators/__init__.py 2007-06-05 11:29:11.000000000 -0600 @@ -1,7 +1,7 @@ """Pylons Decorators: ``jsonify``, ``validate``, REST, and Cache decorators""" import simplejson as json import sys -from paste.util.multidict import UnicodeMultiDict +from paste.util.multidict import MultiDict from decorator import decorator @@ -95,17 +95,35 @@ pylons.request.environ['pylons.routes_dict']['action'] = form response = self._dispatch_call() form_content = ''.join(response.content) - if isinstance(params, UnicodeMultiDict) and \ - not isinstance(form_content, unicode): + if isinstance(params, MultiDict): + # Passing raw string form values to htmlfill: Ensure + # form_content and FormEncode's errors dict are also raw + # strings so htmlfill can safely combine them + encoding = determine_response_charset(response) + # WSGIResponse's content may (unlikely) be unicode + if isinstance(form_content, unicode): + form_content = form_content.encode(encoding) + # FormEncode>=0.7 error strings are unicode (due to being + # localized via ugettext) + for key, value in errors.iteritems(): + if isinstance(value, unicode): + errors[key] = value.encode(encoding) + elif not isinstance(form_content, unicode): # Passing unicode form values to htmlfill: decode the response # to unicode so htmlfill can safely combine the two - encoding = response.determine_charset() - if encoding is None: - encoding = sys.getdefaultencoding() + encoding = determine_response_charset(response) form_content = form_content.decode(encoding, response.errors) response.content = [htmlfill.render(form_content, params, errors)] return response return func(self, *args, **kwargs) return decorator(wrapper) +def determine_response_charset(response): + """Determine the charset of the specified Response object, returning the + default system encoding when none is set""" + charset = response.determine_charset() + if charset is None: + charset = sys.getdefaultencoding() + return charset + __all__ = ['jsonify', 'validate'] diff -ruN ../pyl.orig/pylons-0.9.5/tests/test_units/test_decorator_validate.py pylons-0.9.5/tests/test_units/test_decorator_validate.py --- ../pyl.orig/pylons-0.9.5/tests/test_units/test_decorator_validate.py 1969-12-31 18:00:00.000000000 -0600 +++ pylons-0.9.5/tests/test_units/test_decorator_validate.py 2007-06-05 11:29:11.000000000 -0600 @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from paste.fixture import TestApp +from paste.registry import RegistryManager + +from pylons import Response +from pylons.decorators import validate + +from pylons.controllers import WSGIController + +from __init__ import ControllerWrap, SetupCacheGlobal, TestWSGIController + +import formencode + +class DhcpZoneForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = True + new_network = formencode.validators.URL(not_empty=True) + +class ValidatingController(WSGIController): + def new(self): + return Response(""" +<html> + <form action="/dhcp/new_form" method="POST"> + <table> + <tr> + <th>Network</th> + <td> + <input id="new_network" name="new_network" type="text" class="error" value="" /> + </td> + </tr> + </table> + <input name="commit" type="submit" value="Save changes" /> + </form> +</html> + """) + + def test_str_params_unicode_fe_errors(self): + return Response('Your network is: %s' % + self.form_result.get('new_network')) + test_str_params_unicode_fe_errors = \ + validate(schema=DhcpZoneForm, form='new')(test_str_params_unicode_fe_errors) + +class TestValidateDecorator(TestWSGIController): + def setUp(self): + TestWSGIController.setUp(self) + app = SetupCacheGlobal(ControllerWrap(ValidatingController), + self.environ, setup_cache=False) + app = RegistryManager(app) + self.app = TestApp(app) + + def test_validated(self): + response = self.post_response(action='test_str_params_unicode_fe_errors', + new_network='http://pylonshq.com/') + assert 'Your network is: http://pylonshq.com/' in response + + def test_failed_validation_non_ascii(self): + response = self.post_response(action='test_str_params_unicode_fe_errors', + new_network='РПÑÑОÌÑ') + print response + assert 'That is not a valid URL' in response + assert 'РПÑÑОÌÑ' in response