1
- # -*- coding: utf-8 -*-
2
- #
3
- # python-json-pointer - An implementation of the JSON Pointer syntax
4
- # https://github.com/stefankoegl/python-json-pointer
5
- #
6
- # Copyright (c) 2011 Stefan Kögl <[email protected] >
7
- # All rights reserved.
8
- #
9
- # Redistribution and use in source and binary forms, with or without
10
- # modification, are permitted provided that the following conditions
11
- # are met:
12
- #
13
- # 1. Redistributions of source code must retain the above copyright
14
- # notice, this list of conditions and the following disclaimer.
15
- # 2. Redistributions in binary form must reproduce the above copyright
16
- # notice, this list of conditions and the following disclaimer in the
17
- # documentation and/or other materials provided with the distribution.
18
- # 3. The name of the author may not be used to endorse or promote products
19
- # derived from this software without specific prior written permission.
20
- #
21
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
- # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23
- # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24
- # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25
- # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26
- # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30
- # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
- #
32
-
33
- """ Identify specific nodes in a JSON document (RFC 6901) """
34
-
35
- # Will be parsed by setup.py to determine package metadata
36
- __author__ = 'Stefan Kögl <[email protected] >'
37
- __version__ = '3.0.0'
38
- __website__ = 'https://github.com/stefankoegl/python-json-pointer'
39
- __license__ = 'Modified BSD License'
40
-
41
1
import copy
42
2
import re
43
3
from collections .abc import Mapping , Sequence
@@ -73,7 +33,7 @@ def set_pointer(doc, pointer, value, inplace=True):
73
33
74
34
75
35
def resolve_pointer (doc , pointer , default = _nothing ):
76
- """ Resolves pointer against doc and returns the referenced object
36
+ """Resolves pointer against doc and returns the referenced object
77
37
78
38
>>> obj = {'foo': {'anArray': [ {'prop': 44}], 'another prop': {'baz': 'A string' }}, 'a%20b': 1, 'c d': 2}
79
39
@@ -113,7 +73,7 @@ def resolve_pointer(doc, pointer, default=_nothing):
113
73
114
74
115
75
def pairwise (iterable ):
116
- """ Transforms a list to a list of tuples of adjacent items
76
+ """Transforms a list to a list of tuples of adjacent items
117
77
118
78
s -> (s0,s1), (s1,s2), (s2, s3), ...
119
79
@@ -143,29 +103,29 @@ def __init__(self, list_):
143
103
self .list_ = list_
144
104
145
105
def __repr__ (self ):
146
- return '{cls}({lst})' .format (cls = self .__class__ .__name__ ,
147
- lst = repr (self .list_ ))
106
+ return "{cls}({lst})" .format (cls = self .__class__ .__name__ , lst = repr (self .list_ ))
148
107
149
108
150
109
class JsonPointer (object ):
151
110
"""A JSON Pointer that can reference parts of a JSON document"""
152
111
153
112
# Array indices must not contain:
154
113
# leading zeros, signs, spaces, decimals, etc
155
- _RE_ARRAY_INDEX = re .compile (' 0|[1-9][0-9]*$' )
156
- _RE_INVALID_ESCAPE = re .compile (' (~[^01]|~$)' )
114
+ _RE_ARRAY_INDEX = re .compile (" 0|[1-9][0-9]*$" )
115
+ _RE_INVALID_ESCAPE = re .compile (" (~[^01]|~$)" )
157
116
158
117
def __init__ (self , pointer ):
159
118
160
119
# validate escapes
161
120
invalid_escape = self ._RE_INVALID_ESCAPE .search (pointer )
162
121
if invalid_escape :
163
- raise JsonPointerException ('Found invalid escape {}' .format (
164
- invalid_escape .group ()))
122
+ raise JsonPointerException (
123
+ "Found invalid escape {}" .format (invalid_escape .group ())
124
+ )
165
125
166
- parts = pointer .split ('/' )
167
- if parts .pop (0 ) != '' :
168
- raise JsonPointerException (' Location must start with /' )
126
+ parts = pointer .split ("/" )
127
+ if parts .pop (0 ) != "" :
128
+ raise JsonPointerException (" Location must start with /" )
169
129
170
130
parts = [unescape (part ) for part in parts ]
171
131
self .parts = parts
@@ -203,15 +163,15 @@ def set(self, doc, value, inplace=True):
203
163
204
164
if len (self .parts ) == 0 :
205
165
if inplace :
206
- raise JsonPointerException (' Cannot set root in place' )
166
+ raise JsonPointerException (" Cannot set root in place" )
207
167
return value
208
168
209
169
if not inplace :
210
170
doc = copy .deepcopy (doc )
211
171
212
172
(parent , part ) = self .to_last (doc )
213
173
214
- if isinstance (parent , Sequence ) and part == '-' :
174
+ if isinstance (parent , Sequence ) and part == "-" :
215
175
parent .append (value )
216
176
else :
217
177
parent [part ] = value
@@ -227,37 +187,39 @@ def get_part(cls, doc, part):
227
187
228
188
elif isinstance (doc , Sequence ):
229
189
230
- if part == '-' :
190
+ if part == "-" :
231
191
return part
232
192
233
193
if not JsonPointer ._RE_ARRAY_INDEX .match (str (part )):
234
194
raise JsonPointerException ("'%s' is not a valid sequence index" % part )
235
195
236
196
return int (part )
237
197
238
- elif hasattr (doc , ' __getitem__' ):
198
+ elif hasattr (doc , " __getitem__" ):
239
199
# Allow indexing via ducktyping
240
200
# if the target has defined __getitem__
241
201
return part
242
202
243
203
else :
244
- raise JsonPointerException ("Document '%s' does not support indexing, "
245
- "must be mapping/sequence or support __getitem__" % type (doc ))
204
+ raise JsonPointerException (
205
+ "Document '%s' does not support indexing, "
206
+ "must be mapping/sequence or support __getitem__" % type (doc )
207
+ )
246
208
247
209
def get_parts (self ):
248
210
"""Returns the list of the parts. For example, JsonPointer('/a/b').get_parts() == ['a', 'b']"""
249
211
250
212
return self .parts
251
213
252
214
def walk (self , doc , part ):
253
- """ Walks one step in doc and returns the referenced part """
215
+ """Walks one step in doc and returns the referenced part"""
254
216
255
217
part = JsonPointer .get_part (doc , part )
256
218
257
- assert hasattr (doc , ' __getitem__' ), "invalid document type %s" % (type (doc ),)
219
+ assert hasattr (doc , " __getitem__" ), "invalid document type %s" % (type (doc ),)
258
220
259
221
if isinstance (doc , Sequence ):
260
- if part == '-' :
222
+ if part == "-" :
261
223
return EndOfList (doc )
262
224
263
225
try :
@@ -274,15 +236,15 @@ def walk(self, doc, part):
274
236
raise JsonPointerException ("member '%s' not found in %s" % (part , doc ))
275
237
276
238
def contains (self , ptr ):
277
- """ Returns True if self contains the given ptr """
278
- return self .parts [:len (ptr .parts )] == ptr .parts
239
+ """Returns True if self contains the given ptr"""
240
+ return self .parts [: len (ptr .parts )] == ptr .parts
279
241
280
242
def __contains__ (self , item ):
281
- """ Returns True if self contains the given ptr """
243
+ """Returns True if self contains the given ptr"""
282
244
return self .contains (item )
283
245
284
246
def join (self , suffix ):
285
- """ Returns a new JsonPointer with the given suffix append to this ptr """
247
+ """Returns a new JsonPointer with the given suffix append to this ptr"""
286
248
if isinstance (suffix , JsonPointer ):
287
249
suffix_parts = suffix .parts
288
250
elif isinstance (suffix , str ):
@@ -304,7 +266,7 @@ def path(self):
304
266
>>> ptr = JsonPointer('/~0/0/~1').path == '/~0/0/~1'
305
267
"""
306
268
parts = [escape (part ) for part in self .parts ]
307
- return '' .join ('/' + part for part in parts )
269
+ return "" .join ("/" + part for part in parts )
308
270
309
271
def __eq__ (self , other ):
310
272
"""Compares a pointer to another object
@@ -336,13 +298,13 @@ def from_parts(cls, parts):
336
298
True
337
299
"""
338
300
parts = [escape (str (part )) for part in parts ]
339
- ptr = cls ('' .join ('/' + part for part in parts ))
301
+ ptr = cls ("" .join ("/" + part for part in parts ))
340
302
return ptr
341
303
342
304
343
305
def escape (s ):
344
- return s .replace ('~' , '~0' ).replace ('/' , '~1' )
306
+ return s .replace ("~" , "~0" ).replace ("/" , "~1" )
345
307
346
308
347
309
def unescape (s ):
348
- return s .replace ('~1' , '/' ).replace ('~0' , '~' )
310
+ return s .replace ("~1" , "/" ).replace ("~0" , "~" )
0 commit comments