3 G\` @sdZddlmZddlZddlZddlZddlZddlZddlm Z m Z dZ dZ yddl mZmZWn(ek rddlmZmZeZYnXdZdZd Zd Zejd0kreefZGd d d eZGdddeZGdddeZGdddeeZddZ ej!ej"e dZ#d1ddZ$ddZ%Gddde&Z'Gddde&Z(Gd d!d!e(Z)Gd"d#d#e(Z*Gd$d%d%e(Z+Gd&d'd'e(Z,Gd(d)d)e(Z-Gd*d+d+e(Z.Gd,d-d-e&Z/d.d/Z0dS)2z Apply JSON-Patches (RFC 6902) )unicode_literalsN) JsonPointerJsonPointerException)MutableMappingMutableSequenceu Stefan Kögl z1.23z0https://github.com/stefankoegl/python-json-patchzModified BSD Licensec@seZdZdZdS)JsonPatchExceptionzBase Json Patch exceptionN)__name__ __module__ __qualname____doc__rrd/private/var/folders/pf/wv4htv3x0qs2c2mp0dnn0kchsvlck3/T/pip-install-emcbgzcf/jsonpatch/jsonpatch.pyr Esr c@seZdZdZdS)InvalidJsonPatchz, Raised if an invalid JSON Patch is created N)r r r r rrrrrIsrc@seZdZdZdS)JsonPatchConflicta 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. N)r r r r rrrrrMsrc@seZdZdZdS)JsonPatchTestFailedz A Test operation failed N)r r r r rrrrrVsrcCs@tjt}x|D]\}}||j|qWtdd|jDS)z'Convert duplicate keys values to lists.css.|]&\}}|t|dkr |dn|fVqdS)rrN)len).0keyvaluesrrr cszmultidict..) collections defaultdictlistappenddictitems)Z ordered_pairsZmdictrvaluerrr multidictZs  r)object_pairs_hookFcCs*t|trtj|}nt|}|j||S)aOApply 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 ) isinstance basestring JsonPatch from_stringapply)docpatchin_placerrr apply_patchms  r)cCs tj||S)aGenerates 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# from_diff)srcdstrrr make_patchsr-c@seZdZdZddZddZddZeZdd Zd d Z d d Z ddZ e ddZ e dddZddZeddZd ddZddZdS)!r#agA 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||_ttttttd|_dS)N)removeaddreplacemovetestcopy)r'RemoveOperation AddOperationReplaceOperation MoveOperation TestOperation CopyOperation operations)selfr'rrr__init__szJsonPatch.__init__cCs|jS)zstr(self) -> self.to_string()) to_string)r;rrr__str__szJsonPatch.__str__cCs t|jS)N)boolr')r;rrr__bool__szJsonPatch.__bool__cCs t|jS)N)iterr')r;rrr__iter__szJsonPatch.__iter__cCstt|jS)N)hashtuple_ops)r;rrr__hash__szJsonPatch.__hash__cCst|tsdS|j|jkS)NF)r!r#rE)r;otherrrr__eq__s zJsonPatch.__eq__cCs ||k S)Nr)r;rGrrr__ne__szJsonPatch.__ne__cCst|}||S)zCreates JsonPatch instance from string source. :param patch_str: JSON patch as raw string. :type patch_str: str :return: :class:`JsonPatch` instance. ) _jsonloads)clsZ patch_strr'rrrr$s zJsonPatch.from_stringTcCs*t}|jdd||t|j}||S)aOCreates 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 N) DiffBuilder_compare_valuesrexecute)rKr+r, optimizationbuilderopsrrrr*s zJsonPatch.from_diffcCs tj|jS)z!Returns patch set as JSON string.)jsondumpsr')r;rrrr=szJsonPatch.to_stringcCstt|j|jS)N)rDmap_get_operationr')r;rrrrE#szJsonPatch._opsFcCs,|stj|}x|jD]}|j|}qW|S)a/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`. )r3deepcopyrEr%)r;objr( operationrrrr%'s   zJsonPatch.applycCsTd|krtd|d}t|ts*td||jkrBtdj||j|}||S)Nopz&Operation does not contain 'op' memberzOperation must be a stringzUnknown operation {0!r})rr!r"r:format)r;rYrZrKrrrrV<s   zJsonPatch._get_operationN)T)F)r r r r r<r>r@ __nonzero__rBrFrHrI classmethodr$r*r=propertyrEr%rVrrrrr#s -     r#c@s^eZdZdZddZddZddZdd Zd d Ze d d Z e ddZ e j ddZ dS)PatchOperationz'A single operation inside a JSON Patch.cCsFt|dtr&|dj|_|d|_n|d|_t|j|_||_dS)Npath)r!rr`locationpointerrY)r;rYrrrr<Os     zPatchOperation.__init__cCs tddS)zAAbstract method that applies patch operation to specified object.z!should implement patch operation.N)NotImplementedError)r;rXrrrr%ZszPatchOperation.applycCstt|jjS)N)rC frozensetrYr)r;rrrrF^szPatchOperation.__hash__cCst|tsdS|j|jkS)NF)r!r_rY)r;rGrrrrHas zPatchOperation.__eq__cCs ||k S)Nr)r;rGrrrrIfszPatchOperation.__ne__cCsdj|jjddS)N/r)joinrbparts)r;rrrr`iszPatchOperation.pathc Cs2yt|jjdStk r,|jjdSXdS)Nrrfrf)intrbrh ValueError)r;rrrrmszPatchOperation.keycCs*t||jjd<|jj|_|j|jd<dS)Nrr`rf)strrbrhr`rarY)r;rrrrrts N) r r r r r<r%rFrHrIr^r`rsetterrrrrr_Ls   r_c@s(eZdZdZddZddZddZdS) r4z/Removes an object property or an array element.cCsX|jj|\}}y ||=Wn8ttfk rR}zdj|}t|WYdd}~XnX|S)Nz&can't remove non-existent object '{0}')rbto_lastKeyError IndexErrorr[r)r;rXsubobjpartexmsgrrrr%~s  zRemoveOperation.applycCs0|j|kr,|j|kr$|jd7_n|d8}|S)Nr)r`r)r;r`rrrr_on_undo_removes   zRemoveOperation._on_undo_removecCs0|j|kr,|j|kr$|jd8_n|d8}|S)Nr)r`r)r;r`rrrr _on_undo_adds   zRemoveOperation._on_undo_addN)r r r r r%rtrurrrrr4{s r4c@s(eZdZdZddZddZddZdS) r5z,Adds an object property or an array element.cCsy|jd}Wn*tk r8}ztdWYdd}~XnX|jj|\}}t|tr|dkrh|j|q|t|ks||dkrt dq|j ||n4t|t r|dkr|}q|||<nt dj t||S)Nrz/The operation does not contain a 'value' member-rzcan't insert outside of listzinvalid document type {0})rYrnrrbrmr!rrrrinsertr TypeErrorr[type)r;rXrrrrprqrrrr%s$     zAddOperation.applycCs0|j|kr,|j|kr$|jd7_n|d7}|S)Nr)r`r)r;r`rrrrrts   zAddOperation._on_undo_removecCs0|j|kr,|j|kr$|jd8_n|d7}|S)Nr)r`r)r;r`rrrrrus   zAddOperation._on_undo_addN)r r r r r%rtrurrrrr5sr5c@s(eZdZdZddZddZddZdS) r6z=Replaces an object property or an array element by new value.cCsy|jd}Wn*tk r8}ztdWYdd}~XnX|jj|\}}|dkrV|St|tr~|t|kst|dkrtdn8t|t r||krdj |}t|nt dj t ||||<|S)Nrz/The operation does not contain a 'value' memberrzcan't replace outside of listz'can't replace non-existent object '{0}'zinvalid document type {0}) rYrnrrbrmr!rrrrr[rxry)r;rXrrrrprqrsrrrr%s$     zReplaceOperation.applycCs|S)Nr)r;r`rrrrrtsz ReplaceOperation._on_undo_removecCs|S)Nr)r;r`rrrrruszReplaceOperation._on_undo_addN)r r r r r%rtrurrrrr6sr6c@sNeZdZdZddZeddZeddZejddZd d Z d d Z d S)r7z=Moves an object property or an array element to new location.c!Cs y.t|jdtr|jd}nt|jd}Wn*tk rX}ztdWYdd}~XnX|j|\}}y ||}Wn2ttfk r}ztt|WYdd}~XnX|j |kr|St|t r|j j |rtdt d|jddj |}td|j|dj |}|S)Nfromz.The operation does not contain a 'from' memberz(Cannot move values into its own childrenr.)rZr`r/)rZr`r)r!rYrrnrrmrorrkrbrcontainsr4r%r5ra)r;rXfrom_ptrrrrprqrrrrr%s6      zMoveOperation.applycCs"t|jd}dj|jddS)Nrzrerrf)rrYrgrh)r;r|rrr from_pathszMoveOperation.from_pathc Cs<t|jd}yt|jdStk r6|jdSXdS)Nrzrrfrf)rrYrirhrx)r;r|rrrfrom_keys zMoveOperation.from_keycCs,t|jd}t||jd<|j|jd<dS)Nrzrrf)rrYrkrhr`)r;rr|rrrr~$scCs\|j|kr,|j|kr$|jd7_n|d8}|j|krX|j|krP|jd7_n|d7}|S)Nr)r}r~r`r)r;r`rrrrrt*s    zMoveOperation._on_undo_removecCs\|j|kr,|j|kr$|jd8_n|d8}|j|krX|j|krP|jd8_n|d7}|S)Nr)r}r~r`r)r;r`rrrrru7s    zMoveOperation._on_undo_addN) r r r r r%r^r}r~rlrtrurrrrr7s%   r7c@seZdZdZddZdS)r8z!Test value by specified location.c#Csy0|jj|\}}|dkr |}n|jj||}Wn.tk r^}ztt|WYdd}~XnXy|jd}Wn*tk r}ztdWYdd}~XnX||krd}t|j |t ||t ||S)Nrz/The operation does not contain a 'value' memberz0{0} ({1}) is not equal to tested value {2} ({3})) rbrmwalkrrrkrYrnrr[ry)r;rXrprqvalrrrrsrrrr%Hs"zTestOperation.applyN)r r r r r%rrrrr8Esr8c@seZdZdZddZdS)r9zA Copies an object property or an array element to a new location c!Csyt|jd}Wn*tk r<}ztdWYdd}~XnX|j|\}}ytj||}Wn2ttfk r}ztt |WYdd}~XnXt d|j |dj |}|S)Nrzz.The operation does not contain a 'from' memberr/)rZr`r) rrYrnrrmr3rWrorrkr5rar%)r;rXr|rrrprqrrrrr%cs  zCopyOperation.applyN)r r r r r%rrrrr9`sr9c@s|eZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ ddZddZddZdS)rMcCs4iig|_ggg|_g|_}||dg|dd<dS)N) index_storageindex_storage2_DiffBuilder__root)r;rootrrrr<{s   zDiffBuilder.__init__c Cshy:|j|}|j|}|dkr*|g||<n||j|Wn(tk rb|j|j||fYnXdS)N)rgetrrxr)r;rindexststoragestoredrrr store_indexs   zDiffBuilder.store_indexc Csy |j|j|}|r|jSWnZtk rz|j|}x:tt|dddD]"}||d|krP|j|dSqPWYnXdS)Nrrrfrf)rrpoprxrranger)r;rrrrirrr take_indexs  zDiffBuilder.take_indexcCs,|j}|d}|||g|d<|d<|dS)Nrr)r)r;rZrlastrrrrwszDiffBuilder.insertcCs*|\}}}||d<||d<g|dd<dS)Nrrr)r;rZ link_prevZ link_next_rrrr.s zDiffBuilder.removeccs2|j}|d}x||k r,|dV|d}qWdS)Nr)r)r;startrcurrrrr iter_froms   zDiffBuilder.iter_fromccs2|j}|d}x||k r,|dV|d}qWdS)Nrr)r)r;rrrrrrBs   zDiffBuilder.__iter__ccs|j}|d}x||k r|d|k r|d|dd}}|j|jkrt|tkrt|tkrtd|j|jddjV|dd}q|djV|d}qWdS)Nrrr0r)rZr`r)rraryr4r5r6rY)r;rrZop_firstZ op_secondrrrrOs        zDiffBuilder.executec Cs|j|t}|dk r|d}t|jtkrPx$|j|D]}|j|j|j|_q6W|j||j t ||krt d|j t ||d}|j |n.t dt |||d}|j |}|j||tdS)Nrr1)rZrzr`r/)rZr`r)r _ST_REMOVEryrrirrtr`r.ra _path_joinr7rwr5r_ST_ADD) r;r`ritemrrZvnew_op new_indexrrr _item_addeds&     zDiffBuilder._item_addedc Cstdt||d}|j|t}|j|}|dk r|d}t|jtkrnx$|j|D]}|j |j |j|_qTW|j ||j |j krt d|j |j d}||d<q|j |n|j||tdS)Nr.)rZr`rr1)rZrzr`)r4rrrrwryrrirrur`r.rar7rr) r;r`rrrrrrZrrrr _item_removeds&       zDiffBuilder._item_removedcCs |jtdt|||ddS)Nr0)rZr`r)rwr6r)r;r`rrrrr_item_replacedszDiffBuilder._item_replacedc Cst|j}t|j}||}||}x"|D]}|j|t|||q.Wx"|D]}|j|t|||qRWx(||@D]}|j||||||qzWdS)N)setkeysrrkrrN) r;r`r+r,Zsrc_keysZdst_keysZ added_keysZ removed_keysrrrr_compare_dictss    zDiffBuilder._compare_dictsc Cst|t|}}t||}t||}xt|D]}||kr||||} } | | krZq0qt| trt| tr|jt||| | qt| trt| tr|j t||| | q|j ||| |j ||| q0||kr|j ||||q0|j ||||q0WdS)N) rmaxminrr!rrrr_compare_listsrr) r;r`r+r,Zlen_srcZlen_dstmax_lenZmin_lenroldnewrrrrs&      zDiffBuilder._compare_listscCsr||kr dSt|tr6t|tr6|jt||||n8t|tr`t|tr`|jt||||n|j|||dS)N)r!rrrrrr)r;r`rr+r,rrrrN.s    zDiffBuilder._compare_valuesN)r r r r<rrrwr.rrBrOrrrrrrNrrrrrMys  rMcCs,|dkr |S|dt|jddjddS)Nre~z~0z~1)rkr0)r`rrrrr>sr)rr)F)1r __future__rrr3 functoolsrSsysZ jsonpointerrrrrcollections.abcrr ImportErrorunicoderk __author__ __version__Z __website__ __license__ version_infobytesr" Exceptionr rrAssertionErrorrrpartialloadsrJr)r-objectr#r_r4r5r6r7r8r9rMrrrrr!sP     %&/2$VF