aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.txt2
-rwxr-xr-xjson_diff.py50
-rw-r--r--setup.py6
-rw-r--r--test_json_diff.py42
-rw-r--r--test_strings.py55
5 files changed, 82 insertions, 73 deletions
diff --git a/README.txt b/README.txt
index 6b60584..b944db6 100644
--- a/README.txt
+++ b/README.txt
@@ -3,5 +3,7 @@ with the result. Allows exclusion of some keys from the comparison, or
in other way to include only some keys.
The development repository is at https://gitorious.org/json_diff/mainline
+Patches and pull requests are welcome, but please keep the script compatible
+with python 2.4.
Released under MIT/X11 license.
diff --git a/json_diff.py b/json_diff.py
index 8cda9fd..261acdd 100755
--- a/json_diff.py
+++ b/json_diff.py
@@ -22,27 +22,28 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
-from __future__ import division, absolute_import, print_function, unicode_literals
-import json, sys
-# import pdb
+try:
+ import json
+except ImportError:
+ import simplejson as json
import logging
from optparse import OptionParser
__author__ = "Matěj Cepl"
-__version__ = "0.9.0"
+__version__ = "0.9.2"
logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', level=logging.INFO)
STYLE_MAP = {
- "_append": "append_class",
- "_remove": "remove_class",
- "_update": "update_class"
+ u"_append": u"append_class",
+ u"_remove": u"remove_class",
+ u"_update": u"update_class"
}
INTERNAL_KEYS = set(STYLE_MAP.keys())
-LEVEL_INDENT = " "
+LEVEL_INDENT = u" "
-out_str_template = """
+out_str_template = u"""
<!DOCTYPE html>
<html lang='en'>
<meta charset="utf-8" />
@@ -67,9 +68,6 @@ td {
%s
"""
-# I would love to have better solution for this ...
-if sys.version_info[0] == 3: unicode = str
-
def is_scalar(value):
"""
Primitive version, relying on the fact that JSON cannot
@@ -85,16 +83,16 @@ class HTMLFormatter(object):
def _generate_page(self, in_dict, title="json_diff result"):
out_str = out_str_template % (title, title,
self._format_dict(in_dict))
- out_str += """</table>
+ out_str += u"""</table>
</body>
</html>"""
return out_str
def _format_item(self, item, index, typch, level=0):
- level_str = ("<td>" + LEVEL_INDENT + "</td>") * level
+ level_str = (u"<td>" + LEVEL_INDENT + u"</td>") * level
if is_scalar(item):
- out_str = ("<tr>\n %s<td class='%s'>%s = %s</td>\n </tr>\n" %
+ out_str = (u"<tr>\n %s<td class='%s'>%s = %s</td>\n </tr>\n" %
(level_str, STYLE_MAP[typch], index, unicode(item)))
elif isinstance(item, (list, tuple)):
out_str = self._format_array(item, typch, level + 1)
@@ -139,12 +137,12 @@ class Comparator(object):
if fn1:
try:
self.obj1 = json.load(fn1)
- except (TypeError, OverflowError, ValueError) as exc:
+ except (TypeError, OverflowError, ValueError), exc:
raise BadJSONError("Cannot decode object from JSON.\n%s" % unicode(exc))
if fn2:
try:
self.obj2 = json.load(fn2)
- except (TypeError, OverflowError, ValueError) as exc:
+ except (TypeError, OverflowError, ValueError), exc:
raise BadJSONError("Cannot decode object from JSON\n%s" % unicode(exc))
self.excluded_attributes = excluded_attrs
self.included_attributes = included_attrs
@@ -236,22 +234,22 @@ class Comparator(object):
inters = min(len(old_arr), len(new_arr)) # this is the smaller length
result = {
- "_append": {},
- "_remove": {},
- "_update": {}
+ u"_append": {},
+ u"_remove": {},
+ u"_update": {}
}
for idx in range(inters):
res = self._compare_elements(old_arr[idx], new_arr[idx])
if res is not None:
- result['_update'][idx] = res
+ result[u'_update'][idx] = res
# the rest of the larger array
if (inters == len(old_arr)):
for idx in range(inters, len(new_arr)):
- result['_append'][idx] = new_arr[idx]
+ result[u'_append'][idx] = new_arr[idx]
else:
for idx in range(inters, len(old_arr)):
- result['_remove'][idx] = old_arr[idx]
+ result[u'_remove'][idx] = old_arr[idx]
# Clear out unused keys in result
out_result = {}
@@ -287,14 +285,14 @@ class Comparator(object):
for name in keys:
# old_obj is missing
if name not in old_obj:
- result['_append'][name] = new_obj[name]
+ result[u'_append'][name] = new_obj[name]
# new_obj is missing
elif name not in new_obj:
- result['_remove'][name] = old_obj[name]
+ result[u'_remove'][name] = old_obj[name]
else:
res = self._compare_elements(old_obj[name], new_obj[name])
if res is not None:
- result['_update'][name] = res
+ result[u'_update'][name] = res
return self._filter_results(result)
diff --git a/setup.py b/setup.py
index 7f3e86c..4574d3d 100644
--- a/setup.py
+++ b/setup.py
@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
from distutils.core import setup
+import json_diff
setup(
name = 'json_diff',
- version = '0.9.1',
+ version = '%s' % json_diff.__version__,
description = 'Generates diff between two JSON files',
author = 'Matěj Cepl',
author_email = 'mcepl@redhat.com',
url = 'https://gitorious.org/json_diff/mainline',
- download_url = "http://mcepl.fedorapeople.org/scripts/json_diff-0.9.1.tar.gz",
+ download_url = "http://mcepl.fedorapeople.org/scripts/json_diff-%s.tar.gz" % json_diff.__version__,
py_modules = ['json_diff', 'test_json_diff', 'test_strings'],
package_data = ['test/*'],
long_description = """Compares two JSON files (http://json.org) and
@@ -17,7 +18,6 @@ keys from the comparison, or in other way to include only some keys.""",
keywords = ['json', 'diff'],
classifiers = [
"Programming Language :: Python",
- "Programming Language :: Python :: 3",
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Information Technology",
diff --git a/test_json_diff.py b/test_json_diff.py
index 855c170..1b601a4 100644
--- a/test_json_diff.py
+++ b/test_json_diff.py
@@ -2,15 +2,19 @@
"""
PyUnit unit tests
"""
-from __future__ import division, absolute_import, unicode_literals
-import unittest, sys
-if sys.version_info[0] == 3: unicode = str
-import json
+import unittest
+try:
+ import json
+except ImportError:
+ import simplejson as json
import json_diff
-from io import StringIO
+from StringIO import StringIO
import codecs
-from test_strings import * #@UnusedWildImport
+from test_strings import ARRAY_DIFF, ARRAY_NEW, ARRAY_OLD, \
+ NESTED_DIFF, NESTED_DIFF_EXCL, NESTED_DIFF_INCL, NESTED_NEW, NESTED_OLD, \
+ NO_JSON_NEW, NO_JSON_OLD, SIMPLE_ARRAY_DIFF, SIMPLE_ARRAY_NEW, \
+ SIMPLE_ARRAY_OLD, SIMPLE_DIFF, SIMPLE_DIFF_HTML, SIMPLE_NEW, SIMPLE_OLD
class OurTestCase(unittest.TestCase):
def _run_test(self, oldf, newf, difff, msg="", inc=(), exc=()):
@@ -35,7 +39,7 @@ class OurTestCase(unittest.TestCase):
"\n\nexpected = %s\n\nobserved = %s" %
(expected, diff))
-class TestBasicJSONHappyPath(OurTestCase):
+class TestBasicJSON(OurTestCase):
def test_empty(self):
diffator = json_diff.Comparator({}, {})
diff = diffator.compare_dicts()
@@ -56,16 +60,16 @@ class TestBasicJSONHappyPath(OurTestCase):
'{"_update": {"a": false}}', "Booleans")
def test_integer(self):
- self._run_test_strings('{"a": 1}', '{"a": 2}',
- '{"_update": {"a": 2}}', "Integers")
+ self._run_test_strings(u'{"a": 1}', '{"a": 2}',
+ u'{"_update": {"a": 2}}', "Integers")
def test_float(self):
- self._run_test_strings('{"a": 1.0}', '{"a": 1.1}',
- '{"_update": {"a": 1.1}}', "Floats")
+ self._run_test_strings(u'{"a": 1.0}', '{"a": 1.1}',
+ u'{"_update": {"a": 1.1}}', "Floats")
def test_int_to_float(self):
- self._run_test_strings('{"a": 1}', '{"a": 1.0}',
- '{"_update": {"a": 1.0}}', "Integer changed to float")
+ self._run_test_strings(u'{"a": 1}', '{"a": 1.0}',
+ u'{"_update": {"a": 1.0}}', "Integer changed to float")
def test_simple(self):
self._run_test_strings(SIMPLE_OLD, SIMPLE_NEW, SIMPLE_DIFF,
@@ -80,6 +84,12 @@ class TestBasicJSONHappyPath(OurTestCase):
self._run_test_strings(SIMPLE_ARRAY_OLD, SIMPLE_ARRAY_NEW,
SIMPLE_ARRAY_DIFF, "Simple array objects diff.")
+ def test_another_array(self):
+ self._run_test_strings(ARRAY_OLD, ARRAY_NEW,
+ ARRAY_DIFF, "Array objects diff.")
+
+
+class TestHappyPath(OurTestCase):
def test_realFile(self):
self._run_test(open("test/old.json"), open("test/new.json"),
open("test/diff.json"), "Simply nested objects (from file) diff.")
@@ -100,19 +110,19 @@ class TestBasicJSONHappyPath(OurTestCase):
self._run_test_strings(NESTED_OLD, NESTED_NEW, NESTED_DIFF_INCL,
"Nested objects diff.", inc=("nome",))
-class TestBasicJSONSadPath(OurTestCase):
+class TestadPath(OurTestCase):
def test_no_JSON(self):
self.assertRaises(json_diff.BadJSONError,
json_diff.Comparator, StringIO(NO_JSON_OLD), StringIO(NO_JSON_NEW))
def test_bad_JSON_no_hex(self):
self.assertRaises(json_diff.BadJSONError, self._run_test_strings,
- '{"a": 0x1}', '{"a": 2}', '{"_update": {"a": 2}}',
+ u'{"a": 0x1}', '{"a": 2}', u'{"_update": {"a": 2}}',
"Hex numbers not supported")
def test_bad_JSON_no_octal(self):
self.assertRaises(json_diff.BadJSONError, self._run_test_strings,
- '{"a": 01}', '{"a": 2}', '{"_update": {"a": 2}}',
+ u'{"a": 01}', '{"a": 2}', u'{"_update": {"a": 2}}',
"Octal numbers not supported")
#class TestPiglitData(OurTestCase):
diff --git a/test_strings.py b/test_strings.py
index c96db7a..1935912 100644
--- a/test_strings.py
+++ b/test_strings.py
@@ -1,15 +1,14 @@
# -*- coding: utf-8 -*-
-from __future__ import division, absolute_import, unicode_literals
-NO_JSON_OLD = """
+NO_JSON_OLD = u"""
THIS IS NOT A JSON STRING
"""
-NO_JSON_NEW = """
+NO_JSON_NEW = u"""
AND THIS NEITHER
"""
-SIMPLE_OLD = """
+SIMPLE_OLD = u"""
{
"a": 1,
"b": true,
@@ -17,7 +16,7 @@ SIMPLE_OLD = """
}
"""
-SIMPLE_NEW = """
+SIMPLE_NEW = u"""
{
"b": false,
"c": "Maruška",
@@ -25,7 +24,7 @@ SIMPLE_NEW = """
}
"""
-SIMPLE_DIFF = """
+SIMPLE_DIFF = u"""
{
"_append": {
"d": "přidáno"
@@ -40,7 +39,7 @@ SIMPLE_DIFF = """
}
"""
-SIMPLE_DIFF_HTML="""
+SIMPLE_DIFF_HTML = u"""
<!DOCTYPE html>
<html lang='en'>
<meta charset="utf-8" />
@@ -76,19 +75,19 @@ color: navy;
</html>
"""
-SIMPLE_ARRAY_OLD = """
+SIMPLE_ARRAY_OLD = u"""
{
"a": [ 1 ]
}
"""
-SIMPLE_ARRAY_NEW = """
+SIMPLE_ARRAY_NEW = u"""
{
"a": [ 1, 2 ]
}
"""
-SIMPLE_ARRAY_DIFF = """
+SIMPLE_ARRAY_DIFF = u"""
{
"_update": {
"a": {
@@ -100,7 +99,7 @@ SIMPLE_ARRAY_DIFF = """
}
"""
-NESTED_OLD = """
+NESTED_OLD = u"""
{
"a": 1,
"b": 2,
@@ -113,7 +112,7 @@ NESTED_OLD = """
}
"""
-NESTED_NEW = """
+NESTED_NEW = u"""
{
"a": 2,
"c": 3,
@@ -123,7 +122,7 @@ NESTED_NEW = """
}
"""
-NESTED_DIFF = """
+NESTED_DIFF = u"""
{
"_append": {
"c": 3
@@ -145,7 +144,7 @@ NESTED_DIFF = """
}
"""
-NESTED_DIFF_EXCL = """
+NESTED_DIFF_EXCL = u"""
{
"_append": {
"c": 3
@@ -162,7 +161,7 @@ NESTED_DIFF_EXCL = """
}
"""
-NESTED_DIFF_INCL = """
+NESTED_DIFF_INCL = u"""
{
"_update": {
"child": {
@@ -174,7 +173,7 @@ NESTED_DIFF_INCL = """
}
"""
-ARRAY_OLD = """
+ARRAY_OLD = u"""
{
"a": 1,
"b": 2,
@@ -184,7 +183,7 @@ ARRAY_OLD = """
}
"""
-ARRAY_NEW = """
+ARRAY_NEW = u"""
{
"a": 1,
"children": [
@@ -194,20 +193,20 @@ ARRAY_NEW = """
}
"""
-ARRAY_DIFF = """
-{
- "_remove": {
- "b": 2
- },
+ARRAY_DIFF = u"""
+ {
"_append": {
"c": 3
},
+ "_remove": {
+ "b": 2
+ },
"_update": {
- "children": [
- "Pepíček",
- "Tonička",
- "Maruška"
- ]
+ "children": {
+ "_update": {
+ "1": "Tonička"
+ }
+ }
}
}
-"""
+""" \ No newline at end of file