Archive for web.py

在GAE上使用web.py模板出现 No module named templates 错误的解决方法

在 GAE 环境使用 web.py 的模板系统会出现错误。原因大概是web.py使用了一些GAE环境受限的功能(猜的,没看代码)。
解决办法是在手工编译模板。
执行
python /usr/lib/python2.5/site-packages/web/template.py –compile templates

templates 是项目的模板目录,如果你的不是请修改。如果有多个模板目录都需要执行一次,每次修改模板也需要执行一次。

下面是错误提示:

Python 2.5.2: /usr/bin/python
Mon Feb 23 08:28:24 2009

A problem occurred in a Python script. Here is the sequence of function calls leading up to the error, in the order they occurred.
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in _HandleRequest(self=)
2459 infile,
2460 outfile,
2461 base_env_dict=env_dict)
2462 finally:
2463 self.module_manager.UpdateModuleFileModificationTimes()
base_env_dict undefined, env_dict = {‘APPLICATION_ID’: ‘zcsino-dvd’, ‘CURRENT_VERSION_ID’: ‘1.1’, ‘REMOTE_ADDR’: ‘127.0.0.1’, ‘REQUEST_METHOD’: ‘GET’, ‘SERVER_NAME’: ‘localhost’, ‘SERVER_PORT’: ‘8080’, ‘SERVER_PROTOCOL’: ‘HTTP/1.0’, ‘SERVER_SOFTWARE’: ‘Development/1.0′}
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in Dispatch(self=, relative_url=’/’, path=None, headers=, infile=, outfile=, base_env_dict={‘APPLICATION_ID’: ‘zcsino-dvd’, ‘CURRENT_VERSION_ID’: ‘1.1’, ‘REMOTE_ADDR’: ‘127.0.0.1’, ‘REQUEST_METHOD’: ‘GET’, ‘SERVER_NAME’: ‘localhost’, ‘SERVER_PORT’: ‘8080’, ‘SERVER_PROTOCOL’: ‘HTTP/1.0’, ‘SERVER_SOFTWARE’: ‘Development/1.0’})
352 infile,
353 outfile,
354 base_env_dict=base_env_dict)
355
356 return
base_env_dict = {‘APPLICATION_ID’: ‘zcsino-dvd’, ‘CURRENT_VERSION_ID’: ‘1.1’, ‘REMOTE_ADDR’: ‘127.0.0.1’, ‘REQUEST_METHOD’: ‘GET’, ‘SERVER_NAME’: ‘localhost’, ‘SERVER_PORT’: ‘8080’, ‘SERVER_PROTOCOL’: ‘HTTP/1.0’, ‘SERVER_SOFTWARE’: ‘Development/1.0′}
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in Dispatch(self=, relative_url=’/’, path=’gae.py’, headers=, infile=, outfile=, base_env_dict={‘APPLICATION_ID’: ‘zcsino-dvd’, ‘CURRENT_VERSION_ID’: ‘1.1’, ‘REMOTE_ADDR’: ‘127.0.0.1’, ‘REQUEST_METHOD’: ‘GET’, ‘SERVER_NAME’: ‘localhost’, ‘SERVER_PORT’: ‘8080’, ‘SERVER_PROTOCOL’: ‘HTTP/1.0’, ‘SERVER_SOFTWARE’: ‘Development/1.0’})
1869 infile,
1870 outfile,
1871 self._module_dict)
1872 handler.AddDebuggingConsole(relative_url, env, outfile)
1873 finally:
self = , self._module_dict = {‘Cookie’: , ‘StringIO’: , ‘UserDict’: , ‘__builtin__’: , ‘__future__’: , ‘__main__’: , ‘_bisect’: , ‘_hashlib’: , ‘_random’: , ‘_struct’: , …}
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in ExecuteCGI(root_path=’/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd’, handler_path=’gae.py’, cgi_path=’/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/gae.py’, env={‘APPLICATION_ID’: ‘zcsino-dvd’, ‘AUTH_DOMAIN’: ‘gmail.com’, ‘CONTENT_LENGTH’: ”, ‘CONTENT_TYPE’: ‘application/x-www-form-urlencoded’, ‘CURRENT_VERSION_ID’: ‘1.1’, ‘GATEWAY_INTERFACE’: ‘CGI/1.1’, ‘HTTP_ACCEPT’: ‘text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8’, ‘HTTP_ACCEPT_CHARSET’: ‘GB2312,utf-8;q=0.7,*;q=0.7’, ‘HTTP_ACCEPT_LANGUAGE’: ‘zh-cn,zh;q=0.5’, ‘HTTP_CONNECTION’: ‘keep-alive’, …}, infile=, outfile=, module_dict={‘Cookie’: , ‘StringIO’: , ‘UserDict’: , ‘__builtin__’: , ‘__future__’: , ‘__main__’: , ‘_bisect’: , ‘_hashlib’: , ‘_random’: , ‘_struct’: , …}, exec_script=)
1787 logging.debug(‘Executing CGI with env:\n%s’, pprint.pformat(env))
1788 try:
1789 reset_modules = exec_script(handler_path, cgi_path, hook)
1790 except SystemExit, e:
1791 logging.debug(‘CGI exited with status: %s’, e)
reset_modules = True, exec_script = , handler_path = ‘gae.py’, cgi_path = ‘/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/gae.py’, hook =
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in ExecuteOrImportScript(handler_path=’gae.py’, cgi_path=’/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/gae.py’, import_hook=)
1683 try:
1684 if module_code:
1685 exec module_code in script_module.__dict__
1686 else:
1687 script_module.main()
module_code = <code object at 0x85e2380, file “/mnt/s…g/mpython/gae/project/zcsino-dvd/gae.py”, line 5>, script_module = , script_module.__dict__ = {‘__builtins__’: {‘ArithmeticError’: , ‘AssertionError’: , ‘AttributeError’: , ‘BaseException’: , ‘DeprecationWarning’: , ‘EOFError’: , ‘Ellipsis’: Ellipsis, ‘EnvironmentError’: , ‘Exception’: , ‘False’: False, …}, ‘__doc__’: None, ‘__file__’: ‘/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/gae.py’, ‘__loader__’: , ‘__name__’: ‘gae’, ‘import_wrapper’: }
/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/gae.py in ()
4 # 优先使用自带库
5 import import_wrapper
6 import views
7
8
views undefined
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in decorate(self=, *args=(‘views’,), **kwargs={})
847 self._indent_level += 1
848 try:
849 return func(self, *args, **kwargs)
850 finally:
851 self._indent_level -= 1
func = , self = , args = (‘views’,), kwargs = {}
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in load_module(self=, fullname=’views’)
1443 search_path = parent_module.__path__
1444
1445 return self.FindAndLoadModule(submodule, fullname, search_path)
1446
1447 @Trace
self = , self.FindAndLoadModule = <bound method HardenedModulesHook.decorate of >, submodule = ‘views’, fullname = ‘views’, search_path = None
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in decorate(self=, *args=(‘views’, ‘views’, None), **kwargs={})
847 self._indent_level += 1
848 try:
849 return func(self, *args, **kwargs)
850 finally:
851 self._indent_level -= 1
func = , self = , args = (‘views’, ‘views’, None), kwargs = {}
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in FindAndLoadModule(self=, submodule=’views’, submodule_fullname=’views’, search_path=None)
1351 source_file,
1352 pathname,
1353 description)
1354
1355 module.__loader__ = self
description = (‘.py’, ‘U’, 1)
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in decorate(self=, *args=(‘views’, , ‘/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/views.py’, (‘.py’, ‘U’, 1)), **kwargs={})
847 self._indent_level += 1
848 try:
849 return func(self, *args, **kwargs)
850 finally:
851 self._indent_level -= 1
func = , self = , args = (‘views’, , ‘/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/views.py’, (‘.py’, ‘U’, 1)), kwargs = {}
/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py in LoadModuleRestricted(self=, submodule_fullname=’views’, source_file=, pathname=’/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/views.py’, description=(‘.py’, ‘U’, 1))
1301 source_file,
1302 pathname,
1303 description)
1304 except:
1305 if submodule_fullname in self._module_dict:
description = (‘.py’, ‘U’, 1)
/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/views.py in ()
6 import config
7
8 render = web.template.render(‘templates/’, base=’base’)
9
10 urls = (
render undefined, web = None, web.template undefined, base undefined
/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/libs/web.zip/web/template.py in __init__(self=, loc=’templates/’, *a=(), **kw={‘base’: ‘base’})

: No module named templates
args = (‘No module named templates’,)
message = ‘No module named templates’

INFO 2009-02-23 08:28:24,069 dev_appserver.py] “GET / HTTP/1.1” 500 –
ERROR 2009-02-23 08:28:25,806 dev_appserver.py] Exception encountered handling request
Traceback (most recent call last):
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 2461, in _HandleRequest
base_env_dict=env_dict)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 354, in Dispatch
base_env_dict=base_env_dict)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 1871, in Dispatch
self._module_dict)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 1789, in ExecuteCGI
reset_modules = exec_script(handler_path, cgi_path, hook)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 1685, in ExecuteOrImportScript
exec module_code in script_module.__dict__
File “/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/gae.py”, line 6, in
import views
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 849, in decorate
return func(self, *args, **kwargs)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 1445, in load_module
return self.FindAndLoadModule(submodule, fullname, search_path)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 849, in decorate
return func(self, *args, **kwargs)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 1353, in FindAndLoadModule
description)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 849, in decorate
return func(self, *args, **kwargs)
File “/mnt/source/home/gamexg/mpython/gae/google_appengine/google/appengine/tools/dev_appserver.py”, line 1303, in LoadModuleRestricted
description)
File “/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/views.py”, line 8, in
render = web.template.render(‘templates/’, base=’base’)
File “/mnt/source/home/gamexg/mpython/gae/project/zcsino-dvd/libs/web.zip/web/template.py”, line 995, in __init__
ImportError: No module named templates

Comments (4) »

web.py 文档中文翻译:web.py 模板系统 (代码名称templetor)

原文:web.py templating system (codename: templetor)

There are almost as many Python templating systems as there are web frameworks (and, indeed, it seems like many templating systems are adopting web framework-like features), so it is with some trepidation that I work on a new one. Sadly, again I find that my requirements are met by nothing else:
Python 模板系统几乎和web框架一样多(甚至一些 web 框架的特色是拥有多个模板系统。)我总是带着忧虑使用一个新的。令人沮丧的,但是我发现我只需要:

1. The templating system has to look decent. No crud.
1. 这个模板系统看起来不错。不混乱。
2. Reuse Python terms and semantics as much as possible.
2. 尽可能的使用 Python 关键字和语法。
3. Expressive enough to do real computation.
3. 充足的表达式用于真正使用
4. Usable for any text language, not just HTML and XML.
4. 可用于任何文本语言,不要只支持 HTML 和 XML。

And requirements for the implementation as well:

和良好的可用性:

1. Sandboxable so that you can let untrusted users write templates.
1. 沙盒支持,使得你可以允许未信任的用户写模板。
2. Simple and fast implementation.
2. 简单和快速的使用

So here’s my entry.
那么此时我参与。
Variable substitution
替换变量

[coolcode lang=”python”]
Look, a $string.
Hark, an ${arbitrary + expression}.
Gawk, a $dictionary[key].function(‘argument’).
Cool, a $(limit)ing.

Stop, \$money isn’t evaluated.
[/coolcode]

We use basically the same semantics as (rejected) PEP 215. Variables can go anywhere in a document.
我们使用基本上和(不合格?) PEP 215 一样的语义。变量可以在文档的任何地方。
Newline suppression
新行抑制

[coolcode lang=”python”]
If you put a backslash \
at the end of a line \
(like these) \
then there will be no newline.
[/coolcode]

renders as all one line.
所有的显示在一行。
Expressions
表达式

[coolcode lang=”python”]
Here are some expressions:

$for var in iterator: I like $var!

$if times > max:
Stop! In the name of love.
$else:
Keep on, you can do it.
[/coolcode]

That’s all, folks.

All your old Python friends are here: if, while, for, else, break, continue, and pass also act as you’d expect. (Obviously, you can’t have variables named any of these.) The Python code starts at the $ and ends at the :. The $ has to be at the beginning of the line, but that’s not such a burden because of newline suppression (above).
你所有的旧的 Python 朋友在这里:if, while, for, else, break, continue, 和 pass 也为你预期的动作。(明显你不能将变量名称设置为这些。)这些 Python 代码以 $ 开头,以 : 结尾。 $ 在行开始位置,只是叠句因为新行抑制所以不是这样(上面)

Also, we’re very careful about spacing — all the lines will render with no spaces at the beginning. (Open question: what if you want spaces at the beginning?) Also, a trailing space might break your code.
同样,我们非常小心空白 – 所有的行会呈现为开始出没有空白。(问题:如果你需要行开始出有空白怎么做?)同样,结尾处的空白可终止你的代码。

There are a couple changes from Python: for and while now take an else clause that gets called if the loop is never evaluated.
有两个和python不同的更改:for 和 while 现在获得 else 子句,它将在从未执行循环体内代码时执行。

(Possible feature to add: Django-style for loop variables.)
(可能增加的特征:Django-style 循环变量)
Comments
注释

[coolcode lang=”python”]
$# Here’s where we hoodwink the folks at home:

Please enter in your deets:

CC: [ ] $#this is the important one
SSN: $#Social Security Number#$ [ ]
[/coolcode]

Comments start with $# and go to #$ or the end of the line, whichever is first.
Code

注释开始与 $# , 结束与 #$ 或行结尾。

NOTE: This feature has not been implemented in the current web.py implementation of templetor.
注释:这个特征不受到通用的支持。

[coolcode lang=”python”]
Sometimes you just need to break out the Python.

$ mapping = {
$ ‘cool’: [‘nice’, ‘sweet’, ‘hot’],
$ ‘suck’: [‘bad’, ‘evil’, ‘awful’]
$ }

Isn’t that $mapping[thought]?
That’s$ del mapping $ fine with me.

$ complicatedfunc()

$ for x in bugs:
$ if bug.level == ‘severe’:
Ooh, this one is bad.
$ continue
And there’s $x…
[/coolcode]

Body of loops have to be indented with exactly 4 spaces.
循环体的缩进格式是4个空白。

Code begins with a $ and a space and goes until the next $ or the end of the line, whichever comes first. Nothing ever gets output if the first character after the $ is a space (so complicatedfunc above doesn’t write anything to the screen like it might without the space).
代码开始与 $ 和 一个空白 ,直到下一个 $ 或者 行结束。绝不输出$之后的第一个空白(那么执行上面代码绝不输出空白)
Python integration
Python 集成

A template begins with a line like this:
一个模板以这个一样的行开始:

[coolcode lang=”python”]
$def with (name, title, company=’BigCo’)
[/coolcode]

which declares that the template takes those arguments. (The with keyword is special, like def or if.)
声明使用哪些参数。(with 关键字是专用的, like def or if.)

Don’t forget to put spaces in the definition
不要忘记为这个定义放置空格

The following will not work:
下面的必定不能工作:

[coolcode lang=”python”]
$def with (name,title,company=’BigCo’)
[/coolcode]

Inside Python, the template looks like a function that takes these arguments. It returns a storage object with the special property that evaluating it as a string returns the value of the body of the template. The elements in the storage object are the results of the defs and the sets.
这个模板的样子像 Python 内部一个程序使用这些参数。它返回一个和这个模板相关的对象,这个对象模仿字符串的行为。The elements in the storage object are the results of the defs and the sets.

Perhaps an example will make this clearer. Here’s a template, “entry”:
大概一个示例更清晰。像这个例子,‘entry’:

[coolcode lang=”python”]
$def with (post)

$var title: $post.title

$markdown(post.body)

[/coolcode]

Here’s another; “base”:
这里有另外一个;’base’:

[coolcode lang=”python”]
$def with (self)

$self.title

$self.title

$:self
[/coolcode]

Now let’s say we compile both from within Python, the first as entry, the second as base. Here’s how we might use them:
现在假定说我们在 Pyhon 中使用两者,第一个是 entry,第二个是 base。我们应该使用:

[coolcode lang=”python”]
print base( entry( post ) )
[/coolcode]

entry takes the argument post and returns an object whose string value is a bit of HTML showing the post with its title in the property title. base takes this object and places the title in the appropriate place and displays the page itself in the body of the page. The Python code prints out the result.

_Where did markdown come from? It wasn’t passed as an argument._ You can pass a list of functions and variables to the template compiler to be made globally available to templates. Why $:self? See below

Here’s an example:

[coolcode lang=”python”]
import template
render = template.render(‘templates/’)
template.Template.globals[‘len’] = len

print render.base(render.message(‘Hello, world!’))
[/coolcode]

The first line imports templetor. The second says that our templates are in the directory templates/. The third give all our templates access to the len function. The fourth grabs the template message.html, passes it the argument ‘Hello, world!’, passes the result of rendering it to the template base.html and prints the result. (If your templates don’t end in .html or .xml, templetor will still find them, but it won’t do its automatic HTML-encoding.)

Turning Off Filter

By default template.render will use web.websafe filter to do HTML-encoding. To turn it off, put a : after the $ as in:

[coolcode lang=”python”]
$:form.render()
[/coolcode]

Output from form.render() will be displayed as is.

[coolcode lang=”python”]
$:fooBar $# fooBar = lorem ipsum
[/coolcode]

Output from variable in template will be displayed as is.
Including / nesting templates

If you want to nest one template within another, you nest the render() calls, and then include the variable (unfiltered) in the page. In your handler:

[coolcode lang=”python”]
print render.foo(render.bar())
[/coolcode]

or (to make things a little more clear):

[coolcode lang=”python”]
barhtml = render.bar()
print render.foo(barhtml)
[/coolcode]

Then in the template foo.html:

[coolcode lang=”python”]
$def with (bar)
html goes here
$:bar
more html
[/coolcode]

This replaces the $:bar with the output of the render.bar() call (which is why it must be $:/unfiltered, so that you get un-encoded HTML (unless you want something else of course)). You can pass variables in, in the same way:

[coolcode lang=”python”]

print render.foo(render.bar(baz), qux)
[/coolcode]

In the template bar (bar.html):

[coolcode lang=”python”]
$def with (baz)
bar stuff goes here + baz
[/coolcode]

In template foo (foo.html):

[coolcode lang=”python”]
$def with (bar, qux)
html goes here
$:bar
Value of qux is $qux
[/coolcode]

No comment »