dbfdg 3 dGZ_ @sdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl m Z m Z dZ dZyddlmZmZWn(ek rddlmZmZeZYnXdZdZd Zd Ze jd0kreefZGd d d eZGdddeZGdddeZGdddee Z!ddZ"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*Z0Gd,d-d-e(Z1d.d/Z2dS)2z Apply JSON-Patches (RFC 6902) )unicode_literalsN) JsonPointerJsonPointerException)MutableMappingMutableSequenceu Stefan Kögl z1.21z0https://github.com/stefankoegl/python-json-patchzModified BSD Licensec@seZdZdZdS)JsonPatchExceptionzBase Json Patch exceptionN)__name__ __module__ __qualname____doc__rr/usr/lib/python3.6/jsonpatch.pyr Gsr c@seZdZdZdS)InvalidJsonPatchz, Raised if an invalid JSON Patch is created N)r r r r rrrrrKsrc@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 rrrrrOsrc@seZdZdZdS)JsonPatchTestFailedz A Test operation failed N)r r r r rrrrrXsrcCs@tjt}x|D]\}}||j|qWtdd|jDS)z'Convert duplicate keys values to lists.css.|]&\}}|t|dkr |dn|fVqdS)rrN)len).0keyvaluesrrr eszmultidict..) collections defaultdictlistappenddictitems)Z ordered_pairsZmdictrvaluerrr multidict\s  r)Zobject_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_patchos  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)removeaddreplacemoveZtestcopy)r&RemoveOperation AddOperationReplaceOperation MoveOperation TestOperation CopyOperation operations)selfr&rrr__init__szJsonPatch.__init__cCs|jS)zstr(self) -> self.to_string()) to_string)r9rrr__str__szJsonPatch.__str__cCs t|jS)N)boolr&)r9rrr__bool__szJsonPatch.__bool__cCs t|jS)N)iterr&)r9rrr__iter__szJsonPatch.__iter__cCstt|jS)N)hashtuple_ops)r9rrr__hash__szJsonPatch.__hash__cCst|tsdS|j|jkS)NF)r r"rC)r9otherrrr__eq__s zJsonPatch.__eq__cCs ||k S)Nr)r9rErrr__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)rIr*r+ optimizationZbuilderZopsrrrr)s zJsonPatch.from_diffcCs tj|jS)z!Returns patch set as JSON string.)jsondumpsr&)r9rrrr;!szJsonPatch.to_stringcCstt|j|jS)N)rBmap_get_operationr&)r9rrrrC%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`. )r1deepcopyrCr$)r9objr' 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!r8format)r9rUrVrIrrrrR>s   zJsonPatch._get_operationN)T)F)r r r r r:r<r>Z __nonzero__r@rDrFrG classmethodr#r)r;propertyrCr$rRrrrrr"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.cCs |d|_t|j|_||_dS)Npath)locationrpointerrU)r9rUrrrr:Qs  zPatchOperation.__init__cCs tddS)zAAbstract method that applies patch operation to specified object.z!should implement patch operation.N)NotImplementedError)r9rTrrrr$VszPatchOperation.applycCstt|jjS)N)rA frozensetrUr)r9rrrrDZszPatchOperation.__hash__cCst|tsdS|j|jkS)NF)r rZrU)r9rErrrrF]s zPatchOperation.__eq__cCs ||k S)Nr)r9rErrrrGbszPatchOperation.__ne__cCsdj|jjddS)N/r)joinr]parts)r9rrrr[eszPatchOperation.pathc Cs2yt|jjdStk r,|jjdSXdS)Nrrara)intr]rc ValueError)r9rrrriszPatchOperation.keycCs*t||jjd<|jj|_|j|jd<dS)Nrr[ra)strr]rcr[r\rU)r9rrrrrps N) r r r r r:r$rDrFrGrYr[rsetterrrrrrZNs  rZc@s(eZdZdZddZddZddZdS) r2z/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}')r]to_lastKeyError IndexErrorrWr)r9rTsubobjpartexmsgrrrr$zs  zRemoveOperation.applycCs0|j|kr,|j|kr$|jd7_n|d8}|S)Nr)r[r)r9r[rrrr_on_undo_removes   zRemoveOperation._on_undo_removecCs0|j|kr,|j|kr$|jd8_n|d8}|S)Nr)r[r)r9r[rrrr _on_undo_adds   zRemoveOperation._on_undo_addN)r r r r r$rorprrrrr2ws r2c@s(eZdZdZddZddZddZdS) r3z,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})rUrirr]rhr rrrrinsertr TypeErrorrWtype)r9rTrrmrkrlrrrr$s$     zAddOperation.applycCs0|j|kr,|j|kr$|jd7_n|d7}|S)Nr)r[r)r9r[rrrrros   zAddOperation._on_undo_removecCs0|j|kr,|j|kr$|jd8_n|d7}|S)Nr)r[r)r9r[rrrrrps   zAddOperation._on_undo_addN)r r r r r$rorprrrrr3sr3c@s(eZdZdZddZddZddZdS) r4z=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}) rUrirr]rhr rrrrrWrsrt)r9rTrrmrkrlrnrrrr$s$     zReplaceOperation.applycCs|S)Nr)r9r[rrrrrosz ReplaceOperation._on_undo_removecCs|S)Nr)r9r[rrrrrpszReplaceOperation._on_undo_addN)r r r r r$rorprrrrr4sr4c@sNeZdZdZddZeddZeddZejddZd d Z d d Z d S)r5z=Moves an object property or an array element to new location.c!Csyt|jd}Wn*tk r<}ztdWYdd}~XnX|j|\}}y ||}Wn2ttfk r}ztt|WYdd}~XnX|j|kr|St |t r|jj |rtdt d|jddj |}td|j|dj |}|S)Nfromz.The operation does not contain a 'from' memberz(Cannot move values into its own childrenr-)rVr[r.)rVr[r)rrUrirrhrjrrfr]r rcontainsr2r$r3r\)r9rTfrom_ptrrmrkrlrrrrr$s2     zMoveOperation.applycCs"t|jd}dj|jddS)Nrur`rra)rrUrbrc)r9rwrrr from_pathszMoveOperation.from_pathc Cs<t|jd}yt|jdStk r6|jdSXdS)Nrurrara)rrUrdrcrs)r9rwrrrfrom_keys zMoveOperation.from_keycCs,t|jd}t||jd<|j|jd<dS)Nrurra)rrUrfrcr[)r9rrwrrrryscCs\|j|kr,|j|kr$|jd7_n|d8}|j|krX|j|krP|jd7_n|d7}|S)Nr)rxryr[r)r9r[rrrrro#s    zMoveOperation._on_undo_removecCs\|j|kr,|j|kr$|jd8_n|d8}|j|krX|j|krP|jd8_n|d7}|S)Nr)rxryr[r)r9r[rrrrrp0s    zMoveOperation._on_undo_addN) r r r r r$rYrxryrgrorprrrrr5s"   r5c@seZdZdZddZdS)r6z!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})) r]rhwalkrrrfrUrirrWrt)r9rTrkrlvalrmrrnrrrr$As"zTestOperation.applyN)r r r r r$rrrrr6>sr6c@seZdZdZddZdS)r7zA 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)Nruz.The operation does not contain a 'from' memberr.)rVr[r) rrUrirrhr1rSrjrrfr3r\r$)r9rTrwrmrkrlrrrrr$\s  zCopyOperation.applyN)r r r r r$rrrrr7Ysr7c@s|eZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ ddZddZddZdS)rKcCs4iig|_ggg|_g|_}||dg|dd<dS)N) index_storageindex_storage2_DiffBuilder__root)r9rootrrrr:ts   zDiffBuilder.__init__c Cshy:|j|}|j|}|dkr*|g||<n||j|Wn(tk rb|j|j||fYnXdS)N)r|getrrsr})r9rindexststoragestoredrrr store_indexzs   zDiffBuilder.store_indexc Csy |j|j|}|r|jSWnZtk rz|j|}x:tt|dddD]"}||d|krP|j|dSqPWYnXdS)Nrrrara)r|rpoprsr}ranger)r9rrrrirrr take_indexs  zDiffBuilder.take_indexcCs,|j}|d}|||g|d<|d<|dS)Nrr)r~)r9rVrZlastrrrrrszDiffBuilder.insertcCs*|\}}}||d<||d<g|dd<dS)Nrrr)r9rZ link_prevZ link_next_rrrr-s zDiffBuilder.removeccs2|j}|d}x||k r,|dV|d}qWdS)Nr)r~)r9startrcurrrrr iter_froms   zDiffBuilder.iter_fromccs2|j}|d}x||k r,|dV|d}qWdS)Nrr)r~)r9rrrrrr@s   zDiffBuilder.__iter__ccs|j}|d}x||k r|d|k r|d|dd}}|j|jkrt|tkrt|tkrtd|j|jddjV|dd}q|djV|d}qWdS)Nrrr/r)rVr[r)r~r\rtr2r3r4rU)r9rrZop_firstZ op_secondrrrrMs        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)Nrr0)rVrur[r.)rVr[r)r _ST_REMOVErtrrdrror[r-r\ _path_joinr5rrr3r_ST_ADD) r9r[ritemrrVvnew_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-)rVr[rr0)rVrur[)r2rrrrrrtrrdrrpr[r-r\r5rr) r9r[rrrrrrVrrrr _item_removeds&       zDiffBuilder._item_removedcCs |jtdt|||ddS)Nr/)rVr[r)rrr4r)r9r[rrrrr_item_replacedszDiffBuilder._item_replacedc Cst|j}t|j}||}||}x"|D]}|j|t|||q.Wx"|D]}|j|t|||qRWx(||@D]}|j||||||qzWdS)N)setkeysrrfrrL) r9r[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) r9r[r*r+Zlen_srcZlen_dstZmax_lenZmin_lenroldnewrrrr s&      zDiffBuilder._compare_listscCsr||kr dSt|tr6t|tr6|jt||||n8t|tr`t|tr`|jt||||n|j|||dS)N)r rrrrrr)r9r[rr*r+rrrrL's    zDiffBuilder._compare_valuesN)r r r r:rrrrr-rr@rMrrrrrrLrrrrrKrs  rKcCs,|dkr |S|dt|jddjddS)Nr`~z~0z~1)rfr/)r[rrrrr7sr)rr)F)3r Z __future__rrr1 functoolsinspect itertoolsrOsysZ jsonpointerrrrrcollections.abcrr ImportErrorZunicoderf __author__ __version__Z __website__Z __license__ version_infobytesr! Exceptionr rrAssertionErrorrrpartialloadsrHr(r,objectr"rZr2r3r4r5r6r7rKrrrrr!sT     %&)2$SF