Skip to content
This repository has been archived by the owner on May 31, 2020. It is now read-only.

Commit

Permalink
Merge pull request #586 from abonie/json_decoding
Browse files Browse the repository at this point in the history
Json decoding
  • Loading branch information
freakboy3742 committed Jul 21, 2017
2 parents 961f30c + de75e9b commit 23587da
Show file tree
Hide file tree
Showing 7 changed files with 630 additions and 4 deletions.
2 changes: 1 addition & 1 deletion batavia/core/callables.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ var callables = {}

callables.call_function = function(func, args, kwargs) {
if (func.__call__) {
func = func.__call__
func = func.__call__.bind(func)
}

var retval = func(args, kwargs)
Expand Down
6 changes: 5 additions & 1 deletion batavia/modules/json.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var enc = require('./json/encoder.js')
var dec = require('./json/decoder.js')

module.exports = {
__doc__: '',
Expand All @@ -7,5 +8,8 @@ module.exports = {
__package__: '',
'JSONEncoder': enc.JSONEncoder,
'dumps': enc.dumps,
'dump': enc.dump
'dump': enc.dump,
'JSONDecoder': dec.JSONDecoder,
'loads': dec.loads,
'load': dec.load
}
136 changes: 136 additions & 0 deletions batavia/modules/json/decoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
var types = require('../../types')
var core = require('../../core')
var PyObject = core.Object
var exceptions = core.exceptions
var callables = core.callables
var validateParams = require('./utils').validateParams

function JSONDecoder() {
PyObject.call(this)
}

core.create_pyclass(JSONDecoder, 'JSONDecoder')

// TODO(abonie): actual defaults?
const decoder_defaults = {
'object_hook': null,
'parse_float': null,
'parse_int': null,
'parse_constant': null,
'object_pairs_hook': null
}

function _JSONDecoder(args = [], kwargs = {}) {
var keywords = [
'object_hook',
'parse_float',
'parse_int',
'parse_constant',
'strict',
'object_pairs_hook'
]
var params = validateParams({
args: args,
kwargs: kwargs,
names: keywords,
defaults: Object.assign({'strict': true}, decoder_defaults),
funcName: 'JSONDecoder'
})

var dec = new JSONDecoder()
Object.assign(dec, params)

return dec
}

_JSONDecoder.$pyargs = true

JSONDecoder.prototype.decode = function(s) {
// TODO(abonie): what if call to object_hook changes decoder's object_hook property?
var object_hook = this.object_hook
var reviver = (k, v) => types.js2py(v)
if (object_hook !== null && !types.isinstance(object_hook, types.NoneType)) {
reviver = function(k, v) {
var o = types.js2py(v)
if (types.isinstance(o, types.Dict)) {
o = callables.call_function(object_hook, [o], null)
}
return o
}
}

var ret
try {
ret = JSON.parse(s, reviver)
} catch (e) {
throw new exceptions.ValueError.$pyclass(e.message)
}
return ret
}

var loads = function(args, kwargs) {
var keywords = [
's',
'encoding',
'cls',
'object_hook',
'parse_float',
'parse_int',
'parse_constant',
'object_pairs_hook'
]
var params = validateParams({
args: args,
kwargs: kwargs,
names: keywords,
defaults: Object.assign({'encoding': null, 'cls': _JSONDecoder}, decoder_defaults),
numRequired: 1,
funcName: 'loads'
})
var cls = params['cls']
var s = params['s']
delete params['cls']
delete params['s']
delete params['encoding']
params['strict'] = true

// TODO(abonie): possible bug here? see test_cls in tests
var dec = callables.call_function(cls, [], params)
return callables.call_method(dec, 'decode', [s])
}

loads.$pyargs = true

var load = function(args, kwargs) {
var keywords = [
'fp',
'cls',
'object_hook',
'parse_float',
'parse_int',
'parse_constant',
'object_pairs_hook'
]
var params = validateParams({
args: args,
kwargs: kwargs,
names: keywords,
defaults: Object.assign({'cls': _JSONDecoder}, decoder_defaults),
numRequired: 1,
funcName: 'load'
})

var fp = params['fp']
delete params['fp']

var s = callables.call_method(fp, 'read', [])
return loads([s], params)
}

load.$pyargs = true

module.exports = {
'loads': loads,
'load': load,
'JSONDecoder': _JSONDecoder
}
149 changes: 149 additions & 0 deletions tests/modules/test_json/JSON_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# from http://json.org/JSON_checker/test/pass1.json
pass1 = r'''
[
"JSON Test Pattern pass1",
{"object with 1 member":["array with 1 element"]},
{},
[],
-42,
true,
false,
null,
{
"integer": 1234567890,
"real": -9876.543210,
"e": 0.123456789e-12,
"E": 1.234567890E+34,
"": 23456789012E66,
"zero": 0,
"one": 1,
"space": " ",
"quote": "\"",
"backslash": "\\",
"controls": "\b\f\n\r\t",
"slash": "/ & \/",
"alpha": "abcdefghijklmnopqrstuvwyz",
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
"digit": "0123456789",
"0123456789": "digit",
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
"true": true,
"false": false,
"null": null,
"array":[ ],
"object":{ },
"address": "50 St. James Street",
"url": "http://www.JSON.org/",
"comment": "// /* <!-- --",
"# -- --> */": " ",
" s p a c e d " :[1,2 , 3
,
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
"quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
: "A key can be any string"
},
0.5 ,98.6
,
99.44
,
1066,
1e1,
0.1e1,
1e-1,
1e00,2e+00,2e-00
,"rosebud"]
'''

# from http://json.org/JSON_checker/test/pass2.json
pass2 = r'''
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
'''

# from http://json.org/JSON_checker/test/pass3.json
pass3 = r'''
{
"JSON Test Pattern pass3": {
"The outermost value": "must be an object or array.",
"In this test": "It is an object."
}
}
'''

pass_data = [pass1, pass2, pass3]

fail_data = [
# http://json.org/JSON_checker/test/fail1.json
'"A JSON payload should be an object or array, not a string."',
# http://json.org/JSON_checker/test/fail2.json
'["Unclosed array"',
# http://json.org/JSON_checker/test/fail3.json
'{unquoted_key: "keys must be quoted"}',
# http://json.org/JSON_checker/test/fail4.json
'["extra comma",]',
# http://json.org/JSON_checker/test/fail5.json
'["double extra comma",,]',
# http://json.org/JSON_checker/test/fail6.json
'[ , "<-- missing value"]',
# http://json.org/JSON_checker/test/fail7.json
'["Comma after the close"],',
# http://json.org/JSON_checker/test/fail8.json
'["Extra close"]]',
# http://json.org/JSON_checker/test/fail9.json
'{"Extra comma": true,}',
# http://json.org/JSON_checker/test/fail10.json
'{"Extra value after close": true} "misplaced quoted value"',
# http://json.org/JSON_checker/test/fail11.json
'{"Illegal expression": 1 + 2}',
# http://json.org/JSON_checker/test/fail12.json
'{"Illegal invocation": alert()}',
# http://json.org/JSON_checker/test/fail13.json
'{"Numbers cannot have leading zeroes": 013}',
# http://json.org/JSON_checker/test/fail14.json
'{"Numbers cannot be hex": 0x14}',
# http://json.org/JSON_checker/test/fail15.json
'["Illegal backslash escape: \\x15"]',
# http://json.org/JSON_checker/test/fail16.json
'[\\naked]',
# http://json.org/JSON_checker/test/fail17.json
'["Illegal backslash escape: \\017"]',
# http://json.org/JSON_checker/test/fail18.json
'[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]',
# http://json.org/JSON_checker/test/fail19.json
'{"Missing colon" null}',
# http://json.org/JSON_checker/test/fail20.json
'{"Double colon":: null}',
# http://json.org/JSON_checker/test/fail21.json
'{"Comma instead of colon", null}',
# http://json.org/JSON_checker/test/fail22.json
'["Colon instead of comma": false]',
# http://json.org/JSON_checker/test/fail23.json
'["Bad value", truth]',
# http://json.org/JSON_checker/test/fail24.json
"['single quote']",
# http://json.org/JSON_checker/test/fail25.json
'["\ttab\tcharacter\tin\tstring\t"]',
# http://json.org/JSON_checker/test/fail26.json
'["tab\\ character\\ in\\ string\\ "]',
# http://json.org/JSON_checker/test/fail27.json
'["line\nbreak"]',
# http://json.org/JSON_checker/test/fail28.json
'["line\\\nbreak"]',
# http://json.org/JSON_checker/test/fail29.json
'[0e]',
# http://json.org/JSON_checker/test/fail30.json
'[0e+]',
# http://json.org/JSON_checker/test/fail31.json
'[0e+-1]',
# http://json.org/JSON_checker/test/fail32.json
'{"Comma instead if closing brace": true,',
# http://json.org/JSON_checker/test/fail33.json
'["mismatch"}',
# control characters
'["A\u001FZ control characters in string"]',
]
Empty file.
Loading

0 comments on commit 23587da

Please sign in to comment.