I'm not sure if the developers have any sort of Python 3 comparability roadmap (I didn't see anything on the issue tracker, and only this note
https://bugs.launchpad.net/webpy/+bug/277266 from 2008) but I agree, I think it should be possible to enable web.py to support both.
I just discovered web.py in the last week, and I'm totally hooked! It's exactly what I imagined wanting out of a Python web-framework. I have a Python project I've been working on, that I'd love to have hook into web.py, but it's Python 3 :( So I spent a few hours today trying to figure out what needed to be done to get it working, and it doesn't seem all that bad.
1. Pull in CherryPy's updated web server code, which is now 2/3 compatible.
2. Run python -3:
I ran this on a small test setup and saw the following:
$ python -3 code.py
/usr/lib/python2.6/site-packages/web/template.py:925: DeprecationWarning: the compiler package has been removed in Python 3.0
import compiler
/usr/lib/python2.6/site-packages/markdown/blockprocessors.py:163: DeprecationWarning: classic int division
indent_level = len(m.group(1))/markdown.TAB_LENGTH
127.0.0.1:57576 - - [22/Jul/2012 01:03:37] "HTTP/1.1 GET /Welcome" - 200 OK
3. Run 2to3:
2to3 runs successfully, and by and large cleans things up well. It runs into a fair bit of trouble with web.py's unicode handling, such as utils.safestr and utils.safeunicode, generating this diff of safestr:
- if isinstance(obj, unicode):
+ if isinstance(obj, str):
return obj.encode(encoding)
elif isinstance(obj, str):
elif hasattr(obj, 'next'): # iterator
- return itertools.imap(safestr, obj)
+ return map(safestr, obj)
You'll notice that it replaces unicode with str, breaking the method's expected behavior. I'm not sure if it makes more sense to define a custom 2to3 fixer, or figure out a better way to define / compartmentalize this code, but this will need to be cleaned up.
4. Fix runtime exceptions:
Running 2to3 isn't enough to kick of the server though, I got a handful of stack traces that I was able to correct with the following patch:
Series of fixes to resolve stack traces in 3.2.
Removed 'exceptions' import
---- Enough to start the server
Removed str decode('UTF-8') call
diff -r 1b5bb3b5399b -r c823902ee50f application.py
--- a/application.py Sat Jul 21 23:27:20 2012 -0400
+++ b/application.py Sat Jul 21 23:37:09 2012 -0400
-from exceptions import SystemExit
ctx.fullpath = ctx.path + ctx.query
- for k, v in ctx.items():
- # convert all string values to unicode values and replace
- # malformed data with a suitable replacement marker.
- ctx[k] = v.decode('utf-8', 'replace')
# status must always be str
diff -r 1b5bb3b5399b -r c823902ee50f template.py
--- a/template.py Sat Jul 21 23:27:20 2012 -0400
+++ b/template.py Sat Jul 21 23:37:09 2012 -0400
-from UserDict import DictMixin
+from collections import MutableMapping
from .utils import storage, safeunicode, safestr, re_compile
"__import__", # some c-libraries like datetime requires __import__ to present in the namespace
-TEMPLATE_BUILTINS = dict([(name, getattr(__builtin__, name)) for name in TEMPLATE_BUILTIN_NAMES if name in builtins.__dict__])
+import builtins as __builtin__
+TEMPLATE_BUILTINS = dict([(name, getattr(__builtin__, name)) for name in TEMPLATE_BUILTIN_NAMES if name in __builtin__.__dict__])
e = SecurityError("%s:%d - execution of '%s' statements is denied" % (self.filename, lineno, nodename))
-class TemplateResult(object, DictMixin):
+class TemplateResult(MutableMapping):
"""Dictionary like object for storing template output.
The result of a template execution is usally a string, but sometimes it
diff -r 1b5bb3b5399b -r c823902ee50f utils.py
--- a/utils.py Sat Jul 21 23:27:20 2012 -0400
+++ b/utils.py Sat Jul 21 23:37:09 2012 -0400
+import builtins as __builtin__
if hasattr(__builtin__, 'set'):
if hasattr(__builtin__, 'frozenset'):
This was enough to start a server, but there are likely more robust ways of solving these exceptions.
5. Update test suite
I saw 4 failures running the test suite locally on Python 2.7, and 41 failures and 12 errors on 3.2. Most of these were just encoding issues, like:
File ".\web\utils.py", line 337, in web.utils.safeunicode
Failed example:
safeunicode('hello')
Expected:
u'hello'
Got:
'hello'
But the tests will need to be updated and expanded to ensure no regressions.
Needless to say, it looks to me like there's still work to be done, but it's not impossible. To the maintainers, do you have any plans to move towards Python 3? I would be happy to help make this possible.
Michael