Hello community,

here is the log from the commit of package python-jsonpatch for 
openSUSE:Factory checked in at 2013-11-04 13:26:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jsonpatch (Old)
 and      /work/SRC/openSUSE:Factory/.python-jsonpatch.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-jsonpatch"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-jsonpatch/python-jsonpatch.changes        
2013-07-22 13:48:20.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python-jsonpatch.new/python-jsonpatch.changes   
2013-11-04 13:26:28.000000000 +0100
@@ -1,0 +2,7 @@
+Mon Oct 21 13:18:40 UTC 2013 - dmuel...@suse.com
+
+- update to 1.3:
+  * Improved Tests, add command line utilities
+- add update-alternatives
+
+-------------------------------------------------------------------

Old:
----
  jsonpatch-1.1.tar.gz

New:
----
  jsonpatch-1.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-jsonpatch.spec ++++++
--- /var/tmp/diff_new_pack.Dt77Z6/_old  2013-11-04 13:26:30.000000000 +0100
+++ /var/tmp/diff_new_pack.Dt77Z6/_new  2013-11-04 13:26:30.000000000 +0100
@@ -17,9 +17,9 @@
 
 
 Name:           python-jsonpatch
-Version:        1.1
+Version:        1.3
 Release:        0
-Summary:        Apply JSON-Patches (according to draft 08)
+Summary:        Python - JSON-Patches
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
 Url:            https://github.com/stefankoegl/python-json-patch
@@ -27,6 +27,8 @@
 BuildRequires:  python-devel
 BuildRequires:  python-jsonpointer
 Requires:       python-jsonpointer >= 1.0
+Requires(post): update-alternatives
+Requires(postun): update-alternatives
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 %if 0%{?suse_version} && 0%{?suse_version} <= 1110
 %{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print get_python_lib()")}
@@ -35,7 +37,7 @@
 %endif
 
 %description
-Apply JSON-Patches (according to draft 08)
+Python module to apply JSON-Patches (according to RFC 6902).
 
 %prep
 %setup -q -n jsonpatch-%{version}
@@ -45,9 +47,30 @@
 
 %install
 python setup.py install --prefix=%{_prefix} --root=%{buildroot}
+for i in patch diff; do
+    mv %{buildroot}%{_bindir}/json$i %{buildroot}%{_bindir}/json$i-%{py_ver}
+done
+
+%pre
+[[ ! -L %{_bindir}/jsonpatch ]] && rm -f %{_bindir}/jsonpatch || :
+[[ ! -L %{_bindir}/jsondiff ]] && rm -f %{_bindir}/jsondiff || :
+
+%post
+update-alternatives --install \
+    %{_bindir}/jsonpatch jsonpatch %{_bindir}/jsonpatch-%{py_ver} 20 \
+    --slave %{_bindir}/jsondiff jsondiff %{_bindir}/jsondiff-%{py_ver}
+
+%preun
+if [ $1 -eq 0 ] ; then
+    update-alternatives --remove jsonpatch %{_bindir}/jsonpatch-%{py_ver}
+fi
 
 %files
 %defattr(-,root,root,-)
+%ghost %{_bindir}/jsonpatch
+%{_bindir}/jsonpatch-%{py_ver}
+%ghost %{_bindir}/jsondiff
+%{_bindir}/jsondiff-%{py_ver}
 %{python_sitelib}/*
 
 %changelog

++++++ jsonpatch-1.1.tar.gz -> jsonpatch-1.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/AUTHORS new/jsonpatch-1.3/AUTHORS
--- old/jsonpatch-1.1/AUTHORS   1970-01-01 01:00:00.000000000 +0100
+++ new/jsonpatch-1.3/AUTHORS   2013-10-13 15:06:14.000000000 +0200
@@ -0,0 +1,4 @@
+Stefan Kögl <ste...@skoegl.net>
+Alexander Shorin <kxe...@gmail.com>
+Byron Ruth <br...@codeomics.com>
+William Kral <william.k...@gmail.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/COPYING new/jsonpatch-1.3/COPYING
--- old/jsonpatch-1.1/COPYING   1970-01-01 01:00:00.000000000 +0100
+++ new/jsonpatch-1.3/COPYING   2013-10-13 15:06:14.000000000 +0200
@@ -0,0 +1,26 @@
+Copyright (c) 2011 Stefan Kögl <ste...@skoegl.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/MANIFEST.in 
new/jsonpatch-1.3/MANIFEST.in
--- old/jsonpatch-1.1/MANIFEST.in       2012-12-20 19:06:35.000000000 +0100
+++ new/jsonpatch-1.3/MANIFEST.in       2013-10-13 15:07:25.000000000 +0200
@@ -1 +1,6 @@
 include requirements.txt
+include COPYING
+include README.md
+include tests.py
+include ext_tests.py
+include AUTHORS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/PKG-INFO new/jsonpatch-1.3/PKG-INFO
--- old/jsonpatch-1.1/PKG-INFO  2013-06-27 21:50:38.000000000 +0200
+++ new/jsonpatch-1.3/PKG-INFO  2013-10-13 15:14:53.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: jsonpatch
-Version: 1.1
+Version: 1.3
 Summary:  Apply JSON-Patches (RFC 6902) 
 Home-page: https://github.com/stefankoegl/python-json-patch
 Author: Stefan Kögl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/README.md new/jsonpatch-1.3/README.md
--- old/jsonpatch-1.1/README.md 1970-01-01 01:00:00.000000000 +0100
+++ new/jsonpatch-1.3/README.md 2013-10-13 15:06:14.000000000 +0200
@@ -0,0 +1,19 @@
+python-json-patch [![Build 
Status](https://secure.travis-ci.org/stefankoegl/python-json-patch.png?branch=master)](https://travis-ci.org/stefankoegl/python-json-patch)
 [![Coverage 
Status](https://coveralls.io/repos/stefankoegl/python-json-patch/badge.png?branch=master)](https://coveralls.io/r/stefankoegl/python-json-patch?branch=master)
 ![Downloads](https://pypip.in/d/jsonpatch/badge.png) 
![Version](https://pypip.in/v/jsonpatch/badge.png)
+=================
+Applying JSON Patches in Python
+-------------------------------
+
+Library to apply JSON Patches according to
+[RFC 6902](http://tools.ietf.org/html/rfc6902)
+
+See Sourcecode for Examples
+
+* Website: https://github.com/stefankoegl/python-json-patch
+* Repository: https://github.com/stefankoegl/python-json-patch.git
+* Documentation: https://python-json-patch.readthedocs.org/
+
+Running external tests
+----------------------
+To run external tests (such as those from 
https://github.com/json-patch/json-patch-tests) use ext_test.py 
+
+    ./ext_tests.py ../json-patch-tests/tests.json
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/bin/jsondiff 
new/jsonpatch-1.3/bin/jsondiff
--- old/jsonpatch-1.1/bin/jsondiff      1970-01-01 01:00:00.000000000 +0100
+++ new/jsonpatch-1.3/bin/jsondiff      2013-10-13 15:06:14.000000000 +0200
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+
+import sys
+import os.path
+import json
+import jsonpatch
+import argparse
+
+
+parser = argparse.ArgumentParser(description='Diff two JSON files')
+parser.add_argument('FILE1', type=argparse.FileType('r'))
+parser.add_argument('FILE2', type=argparse.FileType('r'))
+parser.add_argument('--indent', type=int, default=None,
+                    help='Indent output by n spaces')
+parser.add_argument('-v', '--version', action='version',
+                    version='%(prog)s ' + jsonpatch.__version__)
+
+
+def main():
+    try:
+        diff_files()
+    except KeyboardInterrupt:
+        sys.exit(1)
+
+
+def diff_files():
+    """ Diffs two JSON files and prints a patch """
+    args = parser.parse_args()
+    doc1 = json.load(args.FILE1)
+    doc2 = json.load(args.FILE2)
+    patch = jsonpatch.make_patch(doc1, doc2)
+    print(json.dumps(patch.patch, indent=args.indent))
+
+
+if __name__ == "__main__":
+    main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/bin/jsonpatch 
new/jsonpatch-1.3/bin/jsonpatch
--- old/jsonpatch-1.1/bin/jsonpatch     1970-01-01 01:00:00.000000000 +0100
+++ new/jsonpatch-1.3/bin/jsonpatch     2013-10-13 15:06:14.000000000 +0200
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+
+import sys
+import os.path
+import json
+import jsonpatch
+import argparse
+
+
+parser = argparse.ArgumentParser(
+    description='Apply a JSON patch on a JSON file')
+parser.add_argument('ORIGINAL', type=argparse.FileType('r'),
+                    help='Original file')
+parser.add_argument('PATCH', type=argparse.FileType('r'),
+                    help='Patch file')
+parser.add_argument('--indent', type=int, default=None,
+                    help='Indent output by n spaces')
+parser.add_argument('-v', '--version', action='version',
+                    version='%(prog)s ' + jsonpatch.__version__)
+
+
+def main():
+    try:
+        patch_files()
+    except KeyboardInterrupt:
+        sys.exit(1)
+
+
+def patch_files():
+    """ Diffs two JSON files and prints a patch """
+    args = parser.parse_args()
+    doc = json.load(args.ORIGINAL)
+    patch = json.load(args.PATCH)
+    result = jsonpatch.apply_patch(doc, patch)
+    print(json.dumps(result, indent=args.indent))
+
+
+if __name__ == "__main__":
+    main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/ext_tests.py 
new/jsonpatch-1.3/ext_tests.py
--- old/jsonpatch-1.1/ext_tests.py      1970-01-01 01:00:00.000000000 +0100
+++ new/jsonpatch-1.3/ext_tests.py      2013-10-13 15:06:14.000000000 +0200
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# python-json-patch - An implementation of the JSON Patch format
+# https://github.com/stefankoegl/python-json-patch
+#
+# Copyright (c) 2011 Stefan Kögl <ste...@skoegl.net>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+""" Script to run external tests, eg from
+https://github.com/json-patch/json-patch-tests """
+
+from functools import partial
+import doctest
+import unittest
+import jsonpatch
+import sys
+
+
+class TestCaseTemplate(unittest.TestCase):
+    """ A generic test case for running external tests """
+
+    def _test(self, test):
+        if not 'doc' in test or not 'patch' in test:
+            # incomplete
+            return
+
+        if test.get('disabled', False):
+            # test is disabled
+            return
+
+        if 'error' in test:
+            self.assertRaises(
+                (jsonpatch.JsonPatchException, jsonpatch.JsonPointerException),
+                jsonpatch.apply_patch, test['doc'], test['patch']
+                )
+
+        else:
+            res = jsonpatch.apply_patch(test['doc'], test['patch'])
+
+            # if there is no 'expected' we only verify that applying the patch
+            # does not raies an exception
+            if 'expected' in test:
+                self.assertEquals(res, test['expected'])
+
+
+def make_test_case(tests):
+
+    class MyTestCase(TestCaseTemplate):
+        pass
+
+    for n, test in enumerate(tests):
+        add_test_method(MyTestCase, 'test_%d' % n, test)
+
+    return MyTestCase
+
+
+def add_test_method(cls, name, test):
+    setattr(cls, name, lambda self: self._test(test))
+
+
+
+modules = ['jsonpatch']
+coverage_modules = []
+
+
+def get_suite(filenames):
+    suite = unittest.TestSuite()
+
+    for testfile in filenames:
+        with open(testfile) as f:
+            # we use the (potentially) patched version of json.load here
+            tests = jsonpatch.json.load(f)
+            cls = make_test_case(tests)
+            suite.addTest(unittest.makeSuite(cls))
+
+    return suite
+
+
+suite = get_suite(sys.argv[1:])
+
+for module in modules:
+    m = __import__(module, fromlist=[module])
+    coverage_modules.append(m)
+    suite.addTest(doctest.DocTestSuite(m))
+
+runner = unittest.TextTestRunner(verbosity=1)
+
+try:
+    import coverage
+except ImportError:
+    coverage = None
+
+if coverage is not None:
+    coverage.erase()
+    coverage.start()
+
+result = runner.run(suite)
+
+if not result.wasSuccessful():
+    sys.exit(1)
+
+if coverage is not None:
+    coverage.stop()
+    coverage.report(coverage_modules)
+    coverage.erase()
+
+if coverage is None:
+    sys.stderr.write("""
+No coverage reporting done (Python module "coverage" is missing)
+Please install the python-coverage package to get coverage reporting.
+""")
+    sys.stderr.flush()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/jsonpatch.egg-info/PKG-INFO 
new/jsonpatch-1.3/jsonpatch.egg-info/PKG-INFO
--- old/jsonpatch-1.1/jsonpatch.egg-info/PKG-INFO       2013-06-27 
21:50:37.000000000 +0200
+++ new/jsonpatch-1.3/jsonpatch.egg-info/PKG-INFO       2013-10-13 
15:14:53.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: jsonpatch
-Version: 1.1
+Version: 1.3
 Summary:  Apply JSON-Patches (RFC 6902) 
 Home-page: https://github.com/stefankoegl/python-json-patch
 Author: Stefan Kögl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/jsonpatch.egg-info/SOURCES.txt 
new/jsonpatch-1.3/jsonpatch.egg-info/SOURCES.txt
--- old/jsonpatch-1.1/jsonpatch.egg-info/SOURCES.txt    2013-06-27 
21:50:38.000000000 +0200
+++ new/jsonpatch-1.3/jsonpatch.egg-info/SOURCES.txt    2013-10-13 
15:14:53.000000000 +0200
@@ -1,7 +1,14 @@
+AUTHORS
+COPYING
 MANIFEST.in
+README.md
+ext_tests.py
 jsonpatch.py
 requirements.txt
 setup.py
+tests.py
+bin/jsondiff
+bin/jsonpatch
 jsonpatch.egg-info/PKG-INFO
 jsonpatch.egg-info/SOURCES.txt
 jsonpatch.egg-info/dependency_links.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/jsonpatch.py 
new/jsonpatch-1.3/jsonpatch.py
--- old/jsonpatch-1.1/jsonpatch.py      2013-06-27 21:49:49.000000000 +0200
+++ new/jsonpatch-1.3/jsonpatch.py      2013-10-13 15:13:27.000000000 +0200
@@ -36,12 +36,14 @@
 
 # Will be parsed by setup.py to determine package metadata
 __author__ = 'Stefan Kögl <ste...@skoegl.net>'
-__version__ = '1.1'
+__version__ = '1.3'
 __website__ = 'https://github.com/stefankoegl/python-json-patch'
 __license__ = 'Modified BSD License'
 
 import copy
 import sys
+import operator
+import collections
 
 import json
 
@@ -69,6 +71,41 @@
     """ A Test operation failed """
 
 
+def multidict(ordered_pairs):
+    """Convert duplicate keys values to lists."""
+    # read all values into lists
+    d = collections.defaultdict(list)
+    for k, v in ordered_pairs:
+        d[k].append(v)
+
+    # unpack lists that have only 1 item
+    for k, v in d.items():
+        if len(v) == 1:
+            d[k] = v[0]
+    return dict(d)
+
+
+def get_loadjson():
+    """ adds the object_pairs_hook parameter to json.load when possible
+
+    The "object_pairs_hook" parameter is used to handle duplicate keys when
+    loading a JSON object. This parameter does not exist in Python 2.6. This
+    methods returns an unmodified json.load for Python 2.6 and a partial
+    function with object_pairs_hook set to multidict for Python versions that
+    support the parameter. """
+
+    import inspect
+    import functools
+
+    argspec = inspect.getargspec(json.load)
+    if 'object_pairs_hook' not in argspec.args:
+        return json.load
+
+    return functools.partial(json.load, object_pairs_hook=multidict)
+
+json.load = get_loadjson()
+
+
 def apply_patch(doc, patch, in_place=False):
     """Apply list of patches to specified json document.
 
@@ -195,14 +232,15 @@
 
 
     def __hash__(self):
-        return hash(tuple(self._get_operation(op) for op in self.patch))
+        return hash(tuple(self._ops))
 
 
     def __eq__(self, other):
         if not isinstance(other, JsonPatch):
             return False
 
-        return self.patch == other.patch
+        return len(list(self._ops)) == len(list(other._ops)) and \
+               all(map(operator.eq, self._ops, other._ops))
 
 
     @classmethod
@@ -282,6 +320,10 @@
         """Returns patch set as JSON string."""
         return json.dumps(self.patch)
 
+    @property
+    def _ops(self):
+        return map(self._get_operation, self.patch)
+
     def apply(self, obj, in_place=False):
         """Applies the patch to given object.
 
@@ -298,8 +340,7 @@
         if not in_place:
             obj = copy.deepcopy(obj)
 
-        for operation in self.patch:
-            operation = self._get_operation(operation)
+        for operation in self._ops:
             obj = operation.apply(obj)
 
         return obj
@@ -309,6 +350,10 @@
             raise JsonPatchException("Operation does not contain 'op' member")
 
         op = operation['op']
+
+        if not isinstance(op, basestring):
+            raise JsonPatchException("Operation must be a string")
+
         if op not in self.operations:
             raise JsonPatchException("Unknown operation '%s'" % op)
 
@@ -348,7 +393,7 @@
         subobj, part = self.pointer.to_last(obj)
         try:
             del subobj[part]
-        except KeyError as ex:
+        except IndexError as ex:
             raise JsonPatchConflict(str(ex))
 
         return obj
@@ -359,7 +404,12 @@
 
     def apply(self, obj):
         value = self.operation["value"]
-        subobj, part = self.pointer.to_last(obj, None)
+        subobj, part = self.pointer.to_last(obj)
+
+        # type is already checked in to_last(), so we assert here
+        # for consistency
+        assert isinstance(subobj, list) or isinstance(subobj, dict), \
+            "invalid document type %s" (type(doc),)
 
         if isinstance(subobj, list):
 
@@ -380,10 +430,6 @@
             else:
                 subobj[part] = value
 
-        else:
-            raise JsonPatchConflict("can't add to type '%s'"
-                                    "" % subobj.__class__.__name__)
-
         return obj
 
 
@@ -394,6 +440,11 @@
         value = self.operation["value"]
         subobj, part = self.pointer.to_last(obj)
 
+        # type is already checked in to_last(), so we assert here
+        # for consistency
+        assert isinstance(subobj, list) or isinstance(subobj, dict), \
+            "invalid document type %s" (type(doc),)
+
         if part is None:
             return value
 
@@ -406,10 +457,6 @@
                 raise JsonPatchConflict("can't replace non-existant object 
'%s'"
                                         "" % part)
 
-        else:
-            raise JsonPatchConflict("can't replace in type '%s'"
-                                    "" % subobj.__class__.__name__)
-
         subobj[part] = value
         return obj
 
@@ -422,7 +469,7 @@
         subobj, part = from_ptr.to_last(obj)
         value = subobj[part]
 
-        if from_ptr.contains(self.pointer):
+        if self.pointer.contains(from_ptr):
             raise JsonPatchException('Cannot move values into its own 
children')
 
         obj = RemoveOperation({'op': 'remove', 'path': 
self.operation['from']}).apply(obj)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/setup.py new/jsonpatch-1.3/setup.py
--- old/jsonpatch-1.1/setup.py  2013-03-26 12:54:25.000000000 +0100
+++ new/jsonpatch-1.3/setup.py  2013-10-13 15:06:14.000000000 +0200
@@ -52,5 +52,11 @@
       url=WEBSITE,
       py_modules=MODULES,
       package_data={'': ['requirements.txt']},
+      scripts=['bin/jsondiff', 'bin/jsonpatch'],
+      entry_poimts = {
+        'console_scripts': [
+            'jsondiff = jsondiff:main',
+            'jsonpatch = jsonpatch:main',
+        ]},
       **OPTIONS
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jsonpatch-1.1/tests.py new/jsonpatch-1.3/tests.py
--- old/jsonpatch-1.1/tests.py  1970-01-01 01:00:00.000000000 +0100
+++ new/jsonpatch-1.3/tests.py  2013-10-13 15:06:14.000000000 +0200
@@ -0,0 +1,358 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals
+
+import json
+import doctest
+import unittest
+import jsonpatch
+import jsonpointer
+import sys
+
+
+class ApplyPatchTestCase(unittest.TestCase):
+
+    def test_apply_patch_from_string(self):
+        obj = {'foo': 'bar'}
+        patch = '[{"op": "add", "path": "/baz", "value": "qux"}]'
+        res = jsonpatch.apply_patch(obj, patch)
+        self.assertTrue(obj is not res)
+        self.assertTrue('baz' in res)
+        self.assertEqual(res['baz'], 'qux')
+
+    def test_apply_patch_to_copy(self):
+        obj = {'foo': 'bar'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'add', 'path': '/baz', 
'value': 'qux'}])
+        self.assertTrue(obj is not res)
+
+    def test_apply_patch_to_same_instance(self):
+        obj = {'foo': 'bar'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'add', 'path': '/baz', 
'value': 'qux'}],
+                                    in_place=True)
+        self.assertTrue(obj is res)
+
+    def test_add_object_key(self):
+        obj = {'foo': 'bar'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'add', 'path': '/baz', 
'value': 'qux'}])
+        self.assertTrue('baz' in res)
+        self.assertEqual(res['baz'], 'qux')
+
+    def test_add_array_item(self):
+        obj = {'foo': ['bar', 'baz']}
+        res = jsonpatch.apply_patch(obj, [{'op': 'add', 'path': '/foo/1', 
'value': 'qux'}])
+        self.assertEqual(res['foo'], ['bar', 'qux', 'baz'])
+
+    def test_remove_object_key(self):
+        obj = {'foo': 'bar', 'baz': 'qux'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'remove', 'path': '/baz'}])
+        self.assertTrue('baz' not in res)
+
+    def test_remove_array_item(self):
+        obj = {'foo': ['bar', 'qux', 'baz']}
+        res = jsonpatch.apply_patch(obj, [{'op': 'remove', 'path': '/foo/1'}])
+        self.assertEqual(res['foo'], ['bar', 'baz'])
+
+    def test_replace_object_key(self):
+        obj = {'foo': 'bar', 'baz': 'qux'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '/baz', 
'value': 'boo'}])
+        self.assertTrue(res['baz'], 'boo')
+
+    def test_replace_whole_document(self):
+        obj = {'foo': 'bar'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '', 
'value': {'baz': 'qux'}}])
+        self.assertTrue(res['baz'], 'qux')
+
+    def test_add_replace_whole_document(self):
+        obj = {'foo': 'bar'}
+        new_obj = {'baz': 'qux'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'add', 'path': '', 'value': 
new_obj}])
+        self.assertTrue(res, new_obj)
+
+    def test_replace_array_item(self):
+        obj = {'foo': ['bar', 'qux', 'baz']}
+        res = jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '/foo/1',
+                                           'value': 'boo'}])
+        self.assertEqual(res['foo'], ['bar', 'boo', 'baz'])
+
+    def test_move_object_key(self):
+        obj = {'foo': {'bar': 'baz', 'waldo': 'fred'},
+               'qux': {'corge': 'grault'}}
+        res = jsonpatch.apply_patch(obj, [{'op': 'move', 'from': '/foo/waldo',
+                                           'path': '/qux/thud'}])
+        self.assertEqual(res, {'qux': {'thud': 'fred', 'corge': 'grault'},
+                               'foo': {'bar': 'baz'}})
+
+    def test_move_array_item(self):
+        obj =  {'foo': ['all', 'grass', 'cows', 'eat']}
+        res = jsonpatch.apply_patch(obj, [{'op': 'move', 'from': '/foo/1', 
'path': '/foo/3'}])
+        self.assertEqual(res, {'foo': ['all', 'cows', 'eat', 'grass']})
+
+    def test_copy_object_key(self):
+        obj = {'foo': {'bar': 'baz', 'waldo': 'fred'},
+               'qux': {'corge': 'grault'}}
+        res = jsonpatch.apply_patch(obj, [{'op': 'copy', 'from': '/foo/waldo',
+                                           'path': '/qux/thud'}])
+        self.assertEqual(res, {'qux': {'thud': 'fred', 'corge': 'grault'},
+                               'foo': {'bar': 'baz', 'waldo': 'fred'}})
+
+    def test_copy_array_item(self):
+        obj =  {'foo': ['all', 'grass', 'cows', 'eat']}
+        res = jsonpatch.apply_patch(obj, [{'op': 'copy', 'from': '/foo/1', 
'path': '/foo/3'}])
+        self.assertEqual(res, {'foo': ['all', 'grass', 'cows', 'grass', 
'eat']})
+
+
+    def test_copy_mutable(self):
+        """ test if mutable objects (dicts and lists) are copied by value """
+        obj = {'foo': [{'bar': 42}, {'baz': 3.14}], 'boo': []}
+        # copy object somewhere
+        res = jsonpatch.apply_patch(obj, [{'op': 'copy', 'from': '/foo/0', 
'path': '/boo/0' }])
+        self.assertEqual(res, {'foo': [{'bar': 42}, {'baz': 3.14}], 'boo': 
[{'bar': 42}]})
+        # modify original object
+        res = jsonpatch.apply_patch(res, [{'op': 'add', 'path': '/foo/0/zoo', 
'value': 255}])
+        # check if that didn't modify the copied object
+        self.assertEqual(res['boo'], [{'bar': 42}])
+
+
+    def test_test_success(self):
+        obj =  {'baz': 'qux', 'foo': ['a', 2, 'c']}
+        jsonpatch.apply_patch(obj, [{'op': 'test', 'path': '/baz', 'value': 
'qux'},
+                                    {'op': 'test', 'path': '/foo/1', 'value': 
2}])
+
+    def test_test_whole_obj(self):
+        obj =  {'baz': 1}
+        jsonpatch.apply_patch(obj, [{'op': 'test', 'path': '', 'value': obj}])
+
+
+    def test_test_error(self):
+        obj =  {'bar': 'qux'}
+        self.assertRaises(jsonpatch.JsonPatchTestFailed,
+                          jsonpatch.apply_patch,
+                          obj, [{'op': 'test', 'path': '/bar', 'value': 
'bar'}])
+
+
+    def test_test_not_existing(self):
+        obj =  {'bar': 'qux'}
+        self.assertRaises(jsonpatch.JsonPatchTestFailed,
+                          jsonpatch.apply_patch,
+                          obj, [{'op': 'test', 'path': '/baz', 'value': 
'bar'}])
+
+
+    def test_test_noval_existing(self):
+        obj =  {'bar': 'qux'}
+        jsonpatch.apply_patch(obj, [{'op': 'test', 'path': '/bar'}])
+
+
+    def test_test_noval_not_existing(self):
+        obj =  {'bar': 'qux'}
+        self.assertRaises(jsonpatch.JsonPatchTestFailed,
+                          jsonpatch.apply_patch,
+                          obj, [{'op': 'test', 'path': '/baz'}])
+
+
+    def test_test_noval_not_existing_nested(self):
+        obj =  {'bar': {'qux': 2}}
+        self.assertRaises(jsonpatch.JsonPatchTestFailed,
+                          jsonpatch.apply_patch,
+                          obj, [{'op': 'test', 'path': '/baz/qx'}])
+
+
+    def test_unrecognized_element(self):
+        obj = {'foo': 'bar', 'baz': 'qux'}
+        res = jsonpatch.apply_patch(obj, [{'op': 'replace', 'path': '/baz', 
'value': 'boo', 'foo': 'ignore'}])
+        self.assertTrue(res['baz'], 'boo')
+
+
+    def test_append(self):
+        obj = {'foo': [1, 2]}
+        res = jsonpatch.apply_patch(obj, [
+                {'op': 'add', 'path': '/foo/-', 'value': 3},
+                {'op': 'add', 'path': '/foo/-', 'value': 4},
+            ])
+        self.assertEqual(res['foo'], [1, 2, 3, 4])
+
+
+
+class EqualityTestCase(unittest.TestCase):
+
+    def test_patch_equality(self):
+        patch1 = jsonpatch.JsonPatch([{ "op": "add", "path": "/a/b/c", 
"value": "foo" }])
+        patch2 = jsonpatch.JsonPatch([{ "path": "/a/b/c", "op": "add", 
"value": "foo" }])
+        self.assertEqual(patch1, patch2)
+
+
+    def test_patch_unequal(self):
+        patch1 = jsonpatch.JsonPatch([{'op': 'test', 'path': '/test'}])
+        patch2 = jsonpatch.JsonPatch([{'op': 'test', 'path': '/test1'}])
+        self.assertNotEqual(patch1, patch2)
+
+    def test_patch_hash_equality(self):
+        patch1 = jsonpatch.JsonPatch([{ "op": "add", "path": "/a/b/c", 
"value": "foo" }])
+        patch2 = jsonpatch.JsonPatch([{ "path": "/a/b/c", "op": "add", 
"value": "foo" }])
+        self.assertEqual(hash(patch1), hash(patch2))
+
+
+    def test_patch_hash_unequal(self):
+        patch1 = jsonpatch.JsonPatch([{'op': 'test', 'path': '/test'}])
+        patch2 = jsonpatch.JsonPatch([{'op': 'test', 'path': '/test1'}])
+        self.assertNotEqual(hash(patch1), hash(patch2))
+
+
+    def test_patch_neq_other_objs(self):
+        p = [{'op': 'test', 'path': '/test'}]
+        patch = jsonpatch.JsonPatch(p)
+        # a patch will always compare not-equal to objects of other types
+        self.assertFalse(patch == p)
+        self.assertFalse(patch == None)
+
+        # also a patch operation will always compare
+        # not-equal to objects of other types
+        op = jsonpatch.PatchOperation(p[0])
+        self.assertFalse(op == p[0])
+        self.assertFalse(op == None)
+
+    def test_str(self):
+        patch_obj = [ { "op": "add", "path": "/child", "value": { 
"grandchild": { } } } ]
+        patch = jsonpatch.JsonPatch(patch_obj)
+
+        self.assertEqual(json.dumps(patch_obj), str(patch))
+        self.assertEqual(json.dumps(patch_obj), patch.to_string())
+
+
+
+class MakePatchTestCase(unittest.TestCase):
+
+    def test_apply_patch_to_copy(self):
+        src = {'foo': 'bar', 'boo': 'qux'}
+        dst = {'baz': 'qux', 'foo': 'boo'}
+        patch = jsonpatch.make_patch(src, dst)
+        res = patch.apply(src)
+        self.assertTrue(src is not res)
+
+    def test_apply_patch_to_same_instance(self):
+        src = {'foo': 'bar', 'boo': 'qux'}
+        dst = {'baz': 'qux', 'foo': 'boo'}
+        patch = jsonpatch.make_patch(src, dst)
+        res = patch.apply(src, in_place=True)
+        self.assertTrue(src is res)
+
+    def test_objects(self):
+        src = {'foo': 'bar', 'boo': 'qux'}
+        dst = {'baz': 'qux', 'foo': 'boo'}
+        patch = jsonpatch.make_patch(src, dst)
+        res = patch.apply(src)
+        self.assertEqual(res, dst)
+
+    def test_arrays(self):
+        src = {'numbers': [1, 2, 3], 'other': [1, 3, 4, 5]}
+        dst = {'numbers': [1, 3, 4, 5], 'other': [1, 3, 4]}
+        patch = jsonpatch.make_patch(src, dst)
+        res = patch.apply(src)
+        self.assertEqual(res, dst)
+
+    def test_complex_object(self):
+        src = {'data': [
+            {'foo': 1}, {'bar': [1, 2, 3]}, {'baz': {'1': 1, '2': 2}}
+        ]}
+        dst = {'data': [
+            {'foo': [42]}, {'bar': []}, {'baz': {'boo': 'oom!'}}
+        ]}
+        patch = jsonpatch.make_patch(src, dst)
+        res = patch.apply(src)
+        self.assertEqual(res, dst)
+
+    def test_array_add_remove(self):
+        # see https://github.com/stefankoegl/python-json-patch/issues/4
+        src = {'numbers': [], 'other': [1, 5, 3, 4]}
+        dst = {'numbers': [1, 3, 4, 5], 'other': []}
+        patch = jsonpatch.make_patch(src, dst)
+        res = patch.apply(src)
+        self.assertEqual(res, dst)
+
+    def test_add_nested(self):
+        # see 
http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-03#appendix-A.10
+        src = {"foo": "bar"}
+        patch_obj = [ { "op": "add", "path": "/child", "value": { 
"grandchild": { } } } ]
+        res = jsonpatch.apply_patch(src, patch_obj)
+        expected = { "foo": "bar",
+                      "child": { "grandchild": { } }
+                   }
+        self.assertEqual(expected, res)
+
+
+class InvalidInputTests(unittest.TestCase):
+
+    def test_missing_op(self):
+        # an "op" member is required
+        src = {"foo": "bar"}
+        patch_obj = [ { "path": "/child", "value": { "grandchild": { } } } ]
+        self.assertRaises(jsonpatch.JsonPatchException, jsonpatch.apply_patch, 
src, patch_obj)
+
+
+    def test_invalid_op(self):
+        # "invalid" is not a valid operation
+        src = {"foo": "bar"}
+        patch_obj = [ { "op": "invalid", "path": "/child", "value": { 
"grandchild": { } } } ]
+        self.assertRaises(jsonpatch.JsonPatchException, jsonpatch.apply_patch, 
src, patch_obj)
+
+
+class ConflictTests(unittest.TestCase):
+
+    def test_remove_indexerror(self):
+        src = {"foo": [1, 2]}
+        patch_obj = [ { "op": "remove", "path": "/foo/10"} ]
+        self.assertRaises(jsonpatch.JsonPatchConflict, jsonpatch.apply_patch, 
src, patch_obj)
+
+    def test_remove_keyerror(self):
+        src = {"foo": [1, 2]}
+        patch_obj = [ { "op": "remove", "path": "/foo/b"} ]
+        self.assertRaises(jsonpointer.JsonPointerException, 
jsonpatch.apply_patch, src, patch_obj)
+
+    def test_insert_oob(self):
+        src = {"foo": [1, 2]}
+        patch_obj = [ { "op": "add", "path": "/foo/10", "value": 1} ]
+        self.assertRaises(jsonpatch.JsonPatchConflict, jsonpatch.apply_patch, 
src, patch_obj)
+
+    def test_move_into_child(self):
+        src = {"foo": {"bar": {"baz": 1}}}
+        patch_obj = [ { "op": "move", "from": "/foo", "path": "/foo/bar" } ]
+        self.assertRaises(jsonpatch.JsonPatchException, jsonpatch.apply_patch, 
src, patch_obj)
+
+    def test_replace_oob(self):
+        src = {"foo": [1, 2]}
+        patch_obj = [ { "op": "replace", "path": "/foo/10", "value": 10} ]
+        self.assertRaises(jsonpatch.JsonPatchConflict, jsonpatch.apply_patch, 
src, patch_obj)
+
+    def test_replace_missing(self):
+        src = {"foo": 1}
+        patch_obj = [ { "op": "replace", "path": "/bar", "value": 10} ]
+        self.assertRaises(jsonpatch.JsonPatchConflict, jsonpatch.apply_patch, 
src, patch_obj)
+
+
+
+modules = ['jsonpatch']
+
+
+def get_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocTestSuite(jsonpatch))
+    suite.addTest(unittest.makeSuite(ApplyPatchTestCase))
+    suite.addTest(unittest.makeSuite(EqualityTestCase))
+    suite.addTest(unittest.makeSuite(MakePatchTestCase))
+    suite.addTest(unittest.makeSuite(InvalidInputTests))
+    suite.addTest(unittest.makeSuite(ConflictTests))
+    return suite
+
+
+suite = get_suite()
+
+for module in modules:
+    m = __import__(module, fromlist=[module])
+    suite.addTest(doctest.DocTestSuite(m))
+
+runner = unittest.TextTestRunner(verbosity=1)
+
+result = runner.run(suite)
+
+if not result.wasSuccessful():
+    sys.exit(1)

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to