allura
Revision | 15ed07eac5a3e5abd07f655e35178545f4d2d9e4 (tree) |
---|---|
Zeit | 2011-04-30 02:08:35 |
Autor | Rick Copeland <rcopeland@geek...> |
Commiter | Rick Copeland |
[#1831] Refactor tg compatibility shim
Signed-off-by: Rick Copeland <rcopeland@geek.net>
@@ -9,9 +9,11 @@ from paste.registry import RegistryManager | ||
9 | 9 | from pyramid.config import Configurator |
10 | 10 | from pyramid.session import UnencryptedCookieSessionFactoryConfig |
11 | 11 | |
12 | -import tg.error | |
13 | 12 | import ew |
14 | 13 | import ming |
14 | +import tg.view | |
15 | +import tg.error | |
16 | +import tg.traversal | |
15 | 17 | from ming.orm.middleware import MingMiddleware |
16 | 18 | from tg.shim import RootFactory |
17 | 19 |
@@ -45,10 +47,11 @@ def main(global_config, **settings): | ||
45 | 47 | secret=settings['session.secret'], |
46 | 48 | cookie_name=settings['session.key'])) |
47 | 49 | config.add_view( |
48 | - tg.shim.tg_view, | |
49 | - context='tg.shim.Resource', | |
50 | - renderer='allura:templates/mytemplate.pt') | |
51 | - config.add_view(tg.shim.error_view, context=exc.WSGIHTTPException) | |
50 | + tg.view.tg_view, | |
51 | + context=tg.traversal.Resource) | |
52 | + config.add_view( | |
53 | + tg.view.error_view, | |
54 | + context=exc.WSGIHTTPException) | |
52 | 55 | app = config.make_wsgi_app() |
53 | 56 | |
54 | 57 | if asbool(conf.get('auth.method', 'local')=='sfx'): |
@@ -1,3 +1,3 @@ | ||
1 | 1 | from .tg_globals import c, g, response, request, config, session, environ |
2 | -from .shim import redirect, url | |
2 | +from .util import redirect, url | |
3 | 3 | from .decorators import expose, validate |
@@ -16,7 +16,9 @@ class _tg_deco(object): | ||
16 | 16 | class expose(_tg_deco): pass |
17 | 17 | class validate(_tg_deco): pass |
18 | 18 | class before_validate(_tg_deco): pass |
19 | -class override_template(_tg_deco): pass | |
19 | + | |
20 | +def override_template(func, template): | |
21 | + c.override_template = template | |
20 | 22 | |
21 | 23 | def without_trailing_slash(func): |
22 | 24 | from tg import redirect |
@@ -54,6 +56,7 @@ class Decoration(object): | ||
54 | 56 | |
55 | 57 | def expose(self, template=None, content_type=None): |
56 | 58 | self.exposed = True |
59 | + assert not self._templates, 'Multiple @expose not supported in shim' | |
57 | 60 | if template or content_type: |
58 | 61 | self._templates[content_type] = template |
59 | 62 |
@@ -86,24 +89,32 @@ class Decoration(object): | ||
86 | 89 | return params |
87 | 90 | |
88 | 91 | def do_render_response(self, result): |
89 | - if len(self._templates) == 1: | |
90 | - ct, tname = self._templates.items()[0] | |
91 | - if ct is not None: | |
92 | - response.content_type = ct | |
93 | - if tname in ('json', 'json:'): | |
94 | - engine, tname = 'json', 'json' | |
95 | - response.content_type = 'application/json' | |
96 | - else: | |
97 | - engine, tname = tname.split(':', 1) | |
98 | - f = ew.render.File(tname, engine) | |
99 | - rendered_result = f(result) | |
100 | - elif self._templates: | |
101 | - assert False, 'Multiple @expose not supported in shim' | |
92 | + tname = self._lookup_template() | |
93 | + if tname in ('json', 'json:'): | |
94 | + engine, tname = 'json', 'json' | |
95 | + response.content_type = 'application/json' | |
96 | + elif tname is None: | |
97 | + return self._make_iter(result) | |
102 | 98 | else: |
103 | - rendered_result = result | |
104 | - if isinstance(rendered_result, unicode): | |
105 | - return [ rendered_result.encode('utf-8') ] | |
106 | - elif isinstance(rendered_result, str): | |
107 | - return [ rendered_result ] | |
99 | + engine, tname = tname.split(':', 1) | |
100 | + f = ew.render.File(tname, engine) | |
101 | + return self._make_iter(f(result)) | |
102 | + | |
103 | + def _lookup_template(self): | |
104 | + tpl = getattr(c, 'override_template', None) | |
105 | + if tpl is not None: return tpl | |
106 | + if len(self._templates) > 1: | |
107 | + assert False, 'Multiple @expose not supported in shim' | |
108 | + if not self._templates: return None | |
109 | + ct, tname = self._templates.items()[0] | |
110 | + if ct is not None: | |
111 | + response.content_type = ct | |
112 | + return tname | |
113 | + | |
114 | + def _make_iter(self, result): | |
115 | + if isinstance(result, unicode): | |
116 | + return [ result.encode('utf-8') ] | |
117 | + elif isinstance(result, str): | |
118 | + return [ result ] | |
108 | 119 | else: |
109 | - return rendered_result | |
120 | + return result |
@@ -1,21 +1,11 @@ | ||
1 | 1 | '''TG compatibility shim |
2 | 2 | ''' |
3 | -import types | |
4 | -import urllib | |
5 | - | |
6 | -import tg | |
7 | 3 | import pkg_resources |
8 | 4 | import pyramid.response |
9 | -from formencode import Invalid | |
10 | -from webob import exc | |
11 | - | |
12 | -from decorators import Decoration | |
13 | 5 | |
14 | 6 | from . import tg_globals |
15 | 7 | from .traversal import Resource |
16 | 8 | |
17 | -__all__ = [ 'redirect', 'url' ] | |
18 | - | |
19 | 9 | class RootFactory(object): |
20 | 10 | |
21 | 11 | def __init__(self, root): |
@@ -43,89 +33,3 @@ class RootFactory(object): | ||
43 | 33 | if hasattr(root_obj, '_cleanup_request'): |
44 | 34 | root_obj._cleanup_request() |
45 | 35 | |
46 | -def tg_view(context, request): | |
47 | - deco, func = context.get_deco() | |
48 | - try: | |
49 | - if not deco or not deco.exposed: raise exc.HTTPNotFound() | |
50 | - try: | |
51 | - # Validate params | |
52 | - params = deco.do_validate_params(request.params.mixed()) | |
53 | - result = func(**params) | |
54 | - except Invalid, inv: | |
55 | - tg.c.validation_exception = inv | |
56 | - eh = deco.error_handler | |
57 | - if eh: | |
58 | - result = eh(func.im_self, **request.params) | |
59 | - deco = Decoration.get(deco.error_handler, False) | |
60 | - else: | |
61 | - result = func(**request.params) | |
62 | - tg_globals.response.app_iter = deco.do_render_response(result) | |
63 | - except exc.WSGIHTTPException, err: | |
64 | - registry = request.environ['paste.registry'] | |
65 | - response = request.get_response(err) | |
66 | - registry.register(tg_globals.response, response) | |
67 | - return tg_globals.response | |
68 | - | |
69 | -def error_view(context, request): | |
70 | - return context | |
71 | - | |
72 | -def redirect(*args, **kwargs): | |
73 | - found = exc.HTTPFound(location=url(*args, **kwargs)) | |
74 | - raise found.exception | |
75 | - | |
76 | -def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): | |
77 | - """ | |
78 | - Returns a bytestring version of 's', encoded as specified in 'encoding'. | |
79 | - | |
80 | - If strings_only is True, don't convert (some) non-string-like objects. | |
81 | - | |
82 | - This function was borrowed from Django | |
83 | - """ | |
84 | - if strings_only and isinstance(s, (types.NoneType, int)): | |
85 | - return s | |
86 | - elif not isinstance(s, basestring): | |
87 | - try: | |
88 | - return str(s) | |
89 | - except UnicodeEncodeError: | |
90 | - if isinstance(s, Exception): | |
91 | - # An Exception subclass containing non-ASCII data that doesn't | |
92 | - # know how to print itself properly. We shouldn't raise a | |
93 | - # further exception. | |
94 | - return ' '.join([smart_str(arg, encoding, strings_only, | |
95 | - errors) for arg in s]) | |
96 | - return unicode(s).encode(encoding, errors) | |
97 | - elif isinstance(s, unicode): | |
98 | - r = s.encode(encoding, errors) | |
99 | - return r | |
100 | - elif s and encoding != 'utf-8': | |
101 | - return s.decode('utf-8', errors).encode(encoding, errors) | |
102 | - else: | |
103 | - return s | |
104 | - | |
105 | -def generate_smart_str(params): | |
106 | - for key, value in params.iteritems(): | |
107 | - if value is None: continue | |
108 | - if isinstance(value, (list, tuple)): | |
109 | - for item in value: | |
110 | - yield smart_str(key), smart_str(item) | |
111 | - else: | |
112 | - yield smart_str(key), smart_str(value) | |
113 | - | |
114 | -def urlencode(params): | |
115 | - """ | |
116 | - A version of Python's urllib.urlencode() function that can operate on | |
117 | - unicode strings. The parameters are first case to UTF-8 encoded strings and | |
118 | - then encoded as per normal. | |
119 | - """ | |
120 | - return urllib.urlencode([i for i in generate_smart_str(params)]) | |
121 | - | |
122 | -def url(base_url=None, params=None): | |
123 | - if base_url is None: base_url = '/' | |
124 | - if params is None: params = {} | |
125 | - if hasattr(base_url, '__iter__' ) and not isinstance(base_url, basestring): | |
126 | - base_url = '/'.join(base_url) | |
127 | - if base_url.startswith('/'): | |
128 | - base_url = tg.request.environ['SCRIPT_NAME'] + base_url | |
129 | - if params: | |
130 | - return '?'.join((base_url, urlencode(params))) | |
131 | - return base_url |
@@ -1,3 +1,10 @@ | ||
1 | +import types | |
2 | +import urllib | |
3 | + | |
4 | +from webob import exc | |
5 | + | |
6 | +from .tg_globals import request | |
7 | + | |
1 | 8 | def call_wsgi_application(application, environ, catch_exc_info=False): |
2 | 9 | """ |
3 | 10 | Call the given WSGI application, returning ``(status_string, |
@@ -30,3 +37,65 @@ def call_wsgi_application(application, environ, catch_exc_info=False): | ||
30 | 37 | return (captured[0], captured[1], app_iter, captured[2]) |
31 | 38 | else: |
32 | 39 | return (captured[0], captured[1], app_iter) |
40 | + | |
41 | + | |
42 | +def redirect(*args, **kwargs): | |
43 | + found = exc.HTTPFound(location=url(*args, **kwargs)) | |
44 | + raise found.exception | |
45 | + | |
46 | +def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): | |
47 | + """ | |
48 | + Returns a bytestring version of 's', encoded as specified in 'encoding'. | |
49 | + | |
50 | + If strings_only is True, don't convert (some) non-string-like objects. | |
51 | + | |
52 | + This function was borrowed from Django | |
53 | + """ | |
54 | + if strings_only and isinstance(s, (types.NoneType, int)): | |
55 | + return s | |
56 | + elif not isinstance(s, basestring): | |
57 | + try: | |
58 | + return str(s) | |
59 | + except UnicodeEncodeError: | |
60 | + if isinstance(s, Exception): | |
61 | + # An Exception subclass containing non-ASCII data that doesn't | |
62 | + # know how to print itself properly. We shouldn't raise a | |
63 | + # further exception. | |
64 | + return ' '.join([smart_str(arg, encoding, strings_only, | |
65 | + errors) for arg in s]) | |
66 | + return unicode(s).encode(encoding, errors) | |
67 | + elif isinstance(s, unicode): | |
68 | + r = s.encode(encoding, errors) | |
69 | + return r | |
70 | + elif s and encoding != 'utf-8': | |
71 | + return s.decode('utf-8', errors).encode(encoding, errors) | |
72 | + else: | |
73 | + return s | |
74 | + | |
75 | +def generate_smart_str(params): | |
76 | + for key, value in params.iteritems(): | |
77 | + if value is None: continue | |
78 | + if isinstance(value, (list, tuple)): | |
79 | + for item in value: | |
80 | + yield smart_str(key), smart_str(item) | |
81 | + else: | |
82 | + yield smart_str(key), smart_str(value) | |
83 | + | |
84 | +def urlencode(params): | |
85 | + """ | |
86 | + A version of Python's urllib.urlencode() function that can operate on | |
87 | + unicode strings. The parameters are first case to UTF-8 encoded strings and | |
88 | + then encoded as per normal. | |
89 | + """ | |
90 | + return urllib.urlencode([i for i in generate_smart_str(params)]) | |
91 | + | |
92 | +def url(base_url=None, params=None): | |
93 | + if base_url is None: base_url = '/' | |
94 | + if params is None: params = {} | |
95 | + if hasattr(base_url, '__iter__' ) and not isinstance(base_url, basestring): | |
96 | + base_url = '/'.join(base_url) | |
97 | + if base_url.startswith('/'): | |
98 | + base_url = request.environ['SCRIPT_NAME'] + base_url | |
99 | + if params: | |
100 | + return '?'.join((base_url, urlencode(params))) | |
101 | + return base_url |
@@ -0,0 +1,31 @@ | ||
1 | +from formencode import Invalid | |
2 | +from webob import exc | |
3 | + | |
4 | +from . import tg_globals | |
5 | +from .decorators import Decoration | |
6 | + | |
7 | +def tg_view(context, request): | |
8 | + deco, func = context.get_deco() | |
9 | + try: | |
10 | + if not deco or not deco.exposed: raise exc.HTTPNotFound() | |
11 | + try: | |
12 | + # Validate params | |
13 | + params = deco.do_validate_params(request.params.mixed()) | |
14 | + result = func(**params) | |
15 | + except Invalid, inv: | |
16 | + tg_globals.c.validation_exception = inv | |
17 | + eh = deco.error_handler | |
18 | + if eh: | |
19 | + result = eh(func.im_self, **request.params) | |
20 | + deco = Decoration.get(deco.error_handler, False) | |
21 | + else: | |
22 | + result = func(**request.params) | |
23 | + tg_globals.response.app_iter = deco.do_render_response(result) | |
24 | + except exc.WSGIHTTPException, err: | |
25 | + registry = request.environ['paste.registry'] | |
26 | + response = request.get_response(err) | |
27 | + registry.register(tg_globals.response, response) | |
28 | + return tg_globals.response | |
29 | + | |
30 | +def error_view(context, request): | |
31 | + return context |
@@ -303,9 +303,9 @@ class TestForum(TestController): | ||
303 | 303 | # beautiful soup is getting some unicode error here - test without it |
304 | 304 | assert thread.html.findAll('div',{'class':'display_post'})[0].find('p').string == 'aaa' |
305 | 305 | assert thread.html.findAll('div',{'class':'display_post'})[1].find('p').string == 'bbb' |
306 | - assert thread.response.body.count('<div class="promote_to_thread_form') == 1 | |
307 | - assert thread.response.body.count('<div class="row reply_post_form') == 2 | |
308 | - assert thread.response.body.count('<div class="edit_post_form') == 2 | |
306 | + assert thread.body.count('<div class="promote_to_thread_form') == 1 | |
307 | + assert thread.body.count('<div class="row reply_post_form') == 2 | |
308 | + assert thread.body.count('<div class="edit_post_form') == 2 | |
309 | 309 | |
310 | 310 | def get_table_rows(self, response, closest_id): |
311 | 311 | tbody = response.html.find('div', {'id': closest_id}).find('tbody') |