ó œ\Tc@sXdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl m Z m Z dZ dZdZdZe jd1kr¶eefZnd efd „ƒYZd efd„ƒYZdefd„ƒYZdeefd„ƒYZd„Zd„Zeƒe_ed„Zd„Z de!fd„ƒYZ"de!fd„ƒYZ#de#fd„ƒYZ$de#fd„ƒYZ%de#fd „ƒYZ&d!e#fd"„ƒYZ'd#e#fd$„ƒYZ(d%e#fd&„ƒYZ)d'„Z*d(„Z+d2d3d)„Z,d*„Z-d+„Z.d,„Z/d-„Z0d.„Z1d/„Z2d0„Z3dS(4u Apply JSON-Patches (RFC 6902) iÿÿÿÿ(tunicode_literalsN(t JsonPointertJsonPointerExceptionu Stefan Kögl u1.8u0https://github.com/stefankoegl/python-json-patchuModified BSD LicenseiitJsonPatchExceptioncBseZdZRS(uBase Json Patch exception(t__name__t __module__t__doc__(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR;stInvalidJsonPatchcBseZdZRS(u, Raised if an invalid JSON Patch is created (RRR(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR?stJsonPatchConflictcBseZdZRS(u Raised if patch could not be applied due to conflict situation such as: - attempt to add object key then it already exists; - attempt to operate with nonexistence object key; - attempt to insert value to array at position beyond of it size; - etc. (RRR(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRCstJsonPatchTestFailedcBseZdZRS(u A Test operation failed (RRR(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR LscCsQtjtƒ}x%|D]\}}||j|ƒqWtd„|jƒDƒƒS(u'Convert duplicate keys values to lists.css=|]3\}}|t|ƒdkr.|dn|fVqdS(iiN(tlen(t.0tkeytvalues((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pys Ys(t collectionst defaultdicttlisttappendtdicttitems(t ordered_pairstmdictR tvalue((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt multidictPs cCs>tjtjƒ}d|jkr(tjStjtjdtƒS(u 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. uobject_pairs_hooktobject_pairs_hook(tinspectt getargspectjsontloadtargst functoolstpartialR(targspec((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt get_loadjson^s cCs=t|tƒr!tj|ƒ}n t|ƒ}|j||ƒS(uOApply list of patches to specified json document. :param doc: Document object. :type doc: dict :param patch: JSON patch as list of dicts or raw JSON-encoded string. :type patch: list or str :param in_place: While :const:`True` patch will modify target document. By default patch will be applied to document copy. :type in_place: bool :return: Patched document object. :rtype: dict >>> doc = {'foo': 'bar'} >>> patch = [{'op': 'add', 'path': '/baz', 'value': 'qux'}] >>> other = apply_patch(doc, patch) >>> doc is not other True >>> other == {'foo': 'bar', 'baz': 'qux'} True >>> patch = [{'op': 'add', 'path': '/baz', 'value': 'qux'}] >>> apply_patch(doc, patch, in_place=True) == {'foo': 'bar', 'baz': 'qux'} True >>> doc == other True (t isinstancet basestringt JsonPatcht from_stringtapply(tdoctpatchtin_place((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt apply_patchps cCstj||ƒS(uÇGenerates patch by comparing of two document objects. Actually is a proxy to :meth:`JsonPatch.from_diff` method. :param src: Data source document object. :type src: dict :param dst: Data source document object. :type dst: dict >>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]} >>> dst = {'baz': 'qux', 'numbers': [1, 4, 7]} >>> patch = make_patch(src, dst) >>> new = patch.apply(src) >>> new == dst True (R$t from_diff(tsrctdst((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt make_patch•sR$cBsžeZdZd„Zd„Zd„ZeZd„Zd„Zd„Z d„Z e d„ƒZ e d „ƒZ d „Zed „ƒZed „Zd „ZRS(ugA JSON Patch is a list of Patch Operations. >>> patch = JsonPatch([ ... {'op': 'add', 'path': '/foo', 'value': 'bar'}, ... {'op': 'add', 'path': '/baz', 'value': [1, 2, 3]}, ... {'op': 'remove', 'path': '/baz/1'}, ... {'op': 'test', 'path': '/baz', 'value': [1, 3]}, ... {'op': 'replace', 'path': '/baz/0', 'value': 42}, ... {'op': 'remove', 'path': '/baz/1'}, ... ]) >>> doc = {} >>> result = patch.apply(doc) >>> expected = {'foo': 'bar', 'baz': [42]} >>> result == expected True JsonPatch object is iterable, so you could easily access to each patch statement in loop: >>> lpatch = list(patch) >>> expected = {'op': 'add', 'path': '/foo', 'value': 'bar'} >>> lpatch[0] == expected True >>> lpatch == patch.patch True Also JsonPatch could be converted directly to :class:`bool` if it contains any operation statements: >>> bool(patch) True >>> bool(JsonPatch([])) False This behavior is very handy with :func:`make_patch` to write more readable code: >>> old = {'foo': 'bar', 'numbers': [1, 3, 4, 8]} >>> new = {'baz': 'qux', 'numbers': [1, 4, 7]} >>> patch = make_patch(old, new) >>> if patch: ... # document have changed, do something useful ... patch.apply(old) #doctest: +ELLIPSIS {...} cCs@||_itd6td6td6td6td6td6|_dS(Nuremoveuaddureplaceumoveutestucopy(R(tRemoveOperationt AddOperationtReplaceOperationt MoveOperationt TestOperationt CopyOperationt operations(tselfR(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt__init__×s cCs |jƒS(ustr(self) -> self.to_string()(t to_string(R6((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt__str__ãscCs t|jƒS(N(tboolR((R6((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt__bool__çscCs t|jƒS(N(titerR((R6((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt__iter__ìscCstt|jƒƒS(N(thashttuplet_ops(R6((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt__hash__ïscCs#t|tƒstS|j|jkS(N(R"R$tFalseR@(R6tother((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt__eq__òscCs ||k S(N((R6RC((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt__ne__÷scCstj|ƒ}||ƒS(u¸Creates JsonPatch instance from string source. :param patch_str: JSON patch as raw string. :type patch_str: str :return: :class:`JsonPatch` instance. (Rtloads(tclst patch_strR(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR%ús csF‡‡fd†‰‡fd†‰d„‰|tˆg||ƒƒƒS(uOCreates JsonPatch instance based on comparing of two document objects. Json patch would be created for `src` argument against `dst` one. :param src: Data source document object. :type src: dict :param dst: Data source document object. :type dst: dict :return: :class:`JsonPatch` instance. >>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]} >>> dst = {'baz': 'qux', 'numbers': [1, 4, 7]} >>> patch = JsonPatch.from_diff(src, dst) >>> new = patch.apply(src) >>> new == dst True c3sÆ||krdSt|tƒrSt|tƒrSx‘ˆ|||ƒD] }|VqAWnot|tƒr–t|tƒr–xNˆ|||ƒD] }|Vq„Wn,tj|ƒ}idd6|jd6|d6VdS(Nureplaceuopupathuvalue(R"RRRt from_partstpath(RJRRCt operationtptr(t compare_dictst compare_lists(s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pytcompare_valuess   c3sáxƒ|D]{}||krKtj||gƒ}idd6|jd6Vqn||g}x'ˆ|||||ƒD] }|VqsWqWxT|D]L}||krtj||gƒ}idd6|jd6||d6VqqWdS(Nuremoveuopupathuadduvalue(RRIRJ(RJR,R-R RLtcurrentRK(RO(s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRM(s   !     cSst|||ƒS(N(t_compare_lists(RJR,R-((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRN8s(R(RGR,R-((RMRNROs6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR+s  cCstj|jƒS(u!Returns patch set as JSON string.(RtdumpsR((R6((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR8=scCstt|j|jƒƒS(N(R?tmapt_get_operationR((R6((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR@AscCs?|stj|ƒ}nx |jD]}|j|ƒ}q"W|S(u/Applies the patch to given object. :param obj: Document object. :type obj: dict :param in_place: Tweaks way how patch would be applied - directly to specified `obj` or to his copy. :type in_place: bool :return: Modified `obj`. (tcopytdeepcopyR@R&(R6tobjR)RK((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR&Es cCsd|krtdƒ‚n|d}t|tƒsCtdƒ‚n||jkrjtdj|ƒƒ‚n|j|}||ƒS(Nuopu&Operation does not contain 'op' memberuOperation must be a stringuUnknown operation {0!r}(RR"R#R5tformat(R6RKtopRG((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRTZs   (RRRR7R9R;t __nonzero__R=RARDREt classmethodR%R+R8tpropertyR@RBR&RT(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR$©s-       7  tPatchOperationcBs;eZdZd„Zd„Zd„Zd„Zd„ZRS(u'A single operation inside a JSON Patch.cCs,|d|_t|jƒ|_||_dS(Nupath(tlocationRtpointerRK(R6RK((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR7ms cCstdƒ‚dS(uAAbstract method that applies patch operation to specified object.u!should implement patch operation.N(tNotImplementedError(R6RW((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR&rscCstt|jjƒƒƒS(N(R>t frozensetRKR(R6((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRAvscCs#t|tƒstS|j|jkS(N(R"R]RBRK(R6RC((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRDyscCs ||k S(N((R6RC((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRE~s(RRRR7R&RARDRE(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR]js     R/cBseZdZd„ZRS(u/Removes an object property or an array element.cCs^|jj|ƒ\}}y ||=Wn4ttfk rY}dj|ƒ}t|ƒ‚nX|S(Nu&can't remove non-existent object '{0}'(R_tto_lasttKeyErrort IndexErrorRXR(R6RWtsubobjtparttextmsg((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR&…s (RRRR&(((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR/‚sR0cBseZdZd„ZRS(u,Adds an object property or an array element.cCsy|jd}Wntk r2}tdƒ‚nX|jj|ƒ\}}t|tƒr¶|dkrv|j|ƒq|t|ƒks”|dkr£t dƒ‚q|j ||ƒnLt|t ƒrç|dkrÚ|}q|||>> src = [1, 2, 3, 4] >>> dst = [0, 1, 2, 3, 5] >>> # The longest common subsequence for these lists is [1, 2, 3] ... # which is located at (0, 3) index range for src list and (1, 4) for ... # dst one. Tuple of these ranges we should get back. ... assert ((0, 3), (1, 4)) == _longest_common_subseq(src, dst) iiN(NN(R RtrangeRjt itertoolstproduct( R,R-tlsrctldsttdranget_tmatrixtzt range_srct range_dsttitj((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyt_longest_common_subseq*s" & %"c CsK|d|dkr|nd}|d|dkr:|nd}|sPd|gS|s`|dgSt||ƒ\}}|dks|dkr—||gSt||d ||d |d|d|df|d|d|dfƒt||d||d|d|d|dt|ƒf|d|d|dt|ƒfƒgS(uåRecursively splits the `dst` list onto two parts: left and right. The left part contains differences on left from common subsequence, same as the right part by for other side. To easily understand the process let's take two lists: [0, 1, 2, 3] as `src` and [1, 2, 4, 5] for `dst`. If we've tried to generate the binary tree where nodes are common subsequence for both lists, leaves on the left side are subsequence for `src` list and leaves on the right one for `dst`, our tree would looks like:: [1, 2] / [0] [] / [3] [4, 5] This function generate the similar structure as flat tree, but without nodes with common subsequences - since we're don't need them - only with left and right leaves:: [] / [0] [] / [3] [4, 5] The `bx` is the absolute range for currently processed subsequence of `src` list. The `by` means the same, but for the `dst` list. iiN(RjR‚RtR (R,R-tbxtbytxty((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRtJs     #ccs5x.t|||||dƒD]\}}|VqWdS(uESame as :func:`_compare_with_shift` but strips emitted `shift` value.iN(t_compare_with_shift(RJR,R-tlefttrightRYR{((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRss(ccst|tƒrIxwt|||d||ŒD]\}}||fVq+Wn@|dk r‰x1t||||ƒD]\}}||fVqkWnt|tƒrÒxwt|||d||ŒD]\}}||fVq´Wn@|dk rx1t||||ƒD]\}}||fVqôWndS(uRecursively compares differences from `left` and `right` sides from common subsequences. The `shift` parameter is used to store index shift which caused by ``add`` and ``remove`` operations. Yields JSON patch operations and list index shift. tshiftN(R"RR‡Rjt _compare_leftt_compare_right(RJR,R-RˆR‰RŠtitem((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR‡…s  " "ccs¨|\}}|dkr't|ƒ}nxztt||||ƒƒD][}tj|t|ƒgƒ}idd6|||d6|jd6|dfV|d8}qEWdS(u`Yields JSON patch ``remove`` operations for elements that are only exists in the `src` list.iÿÿÿÿuremoveuopuvalueupathiN(R treversedRuRRIRmRJ(RJR,RˆRŠtstarttendtidxRL((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyR‹Ÿs  $   ccs–|\}}|dkr't|ƒ}nxht||ƒD]W}tj|t|ƒgƒ}idd6|jd6||d6|dfV|d7}q7WdS(u\Yields JSON patch ``add`` operations for elements that are only exists in the `dst` listiÿÿÿÿuadduopupathuvalueiN(R RuRRIRmRJ(RJR-R‰RŠRRR‘RL((s6/opt/freeware/lib/python2.7/site-packages/jsonpatch.pyRŒµs   ccseg}i}i}tddgƒ}xð|D]è}t|dttfƒ }|d|krvt||d|ƒq+n|rá|d|krá||d}t|d|dgƒ|krát||ƒ|j|dƒq+qán|j|ƒ|||d<|r+|||d!sT            % Á"!  5     )