Fixed a bug in the JSON templating engine.

This commit is contained in:
Jonathan LaCour
2010-11-17 10:01:08 -05:00
parent 93d42a7a4c
commit 3e2386cf9e
8 changed files with 51 additions and 39 deletions

View File

@@ -1,7 +1,7 @@
Metadata-Version: 1.0 Metadata-Version: 1.0
Name: pecan Name: pecan
Version: 0.1dev Version: 0.1dev
Summary: A WSGI object-dispatching web framework, in the spirit of TurboGears, only much much smaller, with many fewer dependancies. Summary: A WSGI object-dispatching web framework, in the spirit of TurboGears, only much much smaller, with many fewer dependencies.
Home-page: http://github.com/cleverdevil/pecan Home-page: http://github.com/cleverdevil/pecan
Author: Jonathan LaCour Author: Jonathan LaCour
Author-email: jonathan@cleverdevil.org Author-email: jonathan@cleverdevil.org

View File

@@ -6,6 +6,7 @@ pecan/decorators.py
pecan/hooks.py pecan/hooks.py
pecan/jsonify.py pecan/jsonify.py
pecan/pecan.py pecan/pecan.py
pecan/rest.py
pecan/routing.py pecan/routing.py
pecan/secure.py pecan/secure.py
pecan/templating.py pecan/templating.py

View File

@@ -1,4 +1,5 @@
WebOb >= 0.9.8 WebOb >= 1.0.0
WebCore >= 1.0.0
simplegeneric >= 0.7 simplegeneric >= 0.7
Genshi >= 0.6 Genshi >= 0.6
Kajiki >= 0.2.2 Kajiki >= 0.2.2
@@ -6,4 +7,5 @@ Mako >= 0.3
py >= 1.3.4 py >= 1.3.4
WebTest >= 1.2.2 WebTest >= 1.2.2
Paste >= 1.7.5.1 Paste >= 1.7.5.1
PasteScript >= 1.7.3 PasteScript >= 1.7.3
formencode >= 1.2.2

View File

@@ -1,14 +1,13 @@
try: try:
from json import JSONEncoder, dumps from json import JSONEncoder
except ImportError: except ImportError:
from simplejson import JSONEncoder, dumps from simplejson import JSONEncoder
from datetime import datetime, date from datetime import datetime, date
from decimal import Decimal from decimal import Decimal
from webob.multidict import MultiDict from webob.multidict import MultiDict
from simplegeneric import generic from simplegeneric import generic
# #
# exceptions # exceptions
# #
@@ -21,49 +20,58 @@ class JsonEncodeError(Exception):
# encoders # encoders
# #
class BaseEncoder(JSONEncoder): def is_saobject(obj):
def is_saobject(self, obj): return hasattr(obj, '_sa_class_manager')
return hasattr(obj, '_sa_class_manager')
def jsonify(self, obj): class GenericJSON(JSONEncoder):
return dumps(self.encode(obj)) def default(self, obj):
import pdb; pdb.set_trace()
def encode(self, obj):
if hasattr(obj, '__json__') and callable(obj.__json__): if hasattr(obj, '__json__') and callable(obj.__json__):
return obj.__json__() return obj.__json__()
elif isinstance(obj, (date, datetime)): elif isinstance(obj, (datetime.date, datetime.datetime)):
return obj.isoformat() return str(obj)
elif isinstance(obj, Decimal): elif isinstance(obj, decimal.Decimal):
return float(obj) return float(obj)
elif self.is_saobject(obj): elif is_saobject(obj):
props = {} props = {}
for key in obj.__dict__: for key in obj.__dict__:
if not key.startswith('_sa_'): if not key.startswith('_sa_'):
props[key] = getattr(obj, key) props[key] = getattr(obj, key)
return props return props
elif isinstance(obj, ResultProxy):
return dict(rows=list(obj), count=obj.rowcount)
elif isinstance(obj, RowProxy):
return dict(rows=dict(obj), count=1)
elif isinstance(obj, MultiDict): elif isinstance(obj, MultiDict):
return obj.mixed() return obj.mixed()
else: else:
try: return JSONEncoder.default(self, obj)
from sqlalchemy.engine.base import ResultProxy, RowProxy
if isinstance(obj, ResultProxy):
return dict(rows=list(obj), count=obj.rowcount)
elif isinstance(obj, RowProxy):
return dict(rows=dict(obj), count=1)
except:
pass
return obj
#
# generic function support
#
encoder = BaseEncoder() _default = GenericJSON()
@generic @generic
def jsonify(obj): def jsonify(obj):
return encoder.encode(obj) return _default.default(obj)
class GenericFunctionJSON(GenericJSON):
def default(self, obj):
return jsonify(obj)
_instance = GenericFunctionJSON()
def encode(obj): def encode(obj):
return dumps(jsonify(obj)) if isinstance(obj, basestring):
return _instance.encode(obj)
try:
value = obj['test']
except TypeError:
if not hasattr(obj, '__json__') and not is_saobject(obj):
raise JsonEncodeError('Your Encoded object must be dict-like.')
except:
pass
"""Return a JSON string representation of a Python object."""
return _instance.encode(obj)

View File

@@ -5,6 +5,7 @@ from pecan import request
class RestController(object): class RestController(object):
# TODO: implement the following: # TODO: implement the following:
# - get, new, edit, post_delete, get_delete # - get, new, edit, post_delete, get_delete
# - implement the "_method" parameter
# - see: http://turbogears.org/2.1/docs/modules/tgcontroller.html # - see: http://turbogears.org/2.1/docs/modules/tgcontroller.html
@expose() @expose()

View File

@@ -34,8 +34,7 @@ class JsonRenderer(object):
def render(self, template_path, namespace): def render(self, template_path, namespace):
from jsonify import encode from jsonify import encode
result = encode(namespace) return encode(namespace)
return result
# #

View File

@@ -169,6 +169,7 @@ class TestEngines(object):
@expose('json') @expose('json')
def index(self, argument=None): def index(self, argument=None):
assert argument == 'value' assert argument == 'value'
return dict()
# arguments should get passed appropriately # arguments should get passed appropriately
app = TestApp(Pecan(RootController())) app = TestApp(Pecan(RootController()))

View File

@@ -18,7 +18,7 @@ class TestRestController(object):
@expose('json') @expose('json')
def get_all(self): def get_all(self):
return self.data return dict(items=self.data)
@expose('json') @expose('json')
def post(self, value): def post(self, value):
@@ -45,7 +45,7 @@ class TestRestController(object):
# test get_all # test get_all
r = app.get('/things') r = app.get('/things')
assert r.status_int == 200 assert r.status_int == 200
assert r.body == dumps(ThingsController.data) assert r.body == dumps(dict(items=ThingsController.data))
# test get_one # test get_one
for i, value in enumerate(ThingsController.data): for i, value in enumerate(ThingsController.data):
@@ -81,4 +81,4 @@ class TestRestController(object):
# make sure it works # make sure it works
r = app.get('/things') r = app.get('/things')
assert r.status_int == 200 assert r.status_int == 200
assert len(loads(r.body)) == 4 assert len(loads(r.body)['items']) == 4