Skip to content

Commit 8b72f3d

Browse files
committed
Fix proxies=False to recurse through references when replacing them. fix #48
1 parent 617a2cb commit 8b72f3d

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

jsonref.py

+14-10
Original file line numberDiff line numberDiff line change
@@ -257,23 +257,27 @@ def jsonloader(uri, **kwargs):
257257
return result
258258

259259

260-
_no_result = object()
261-
262-
263-
def _walk_refs(obj, func, replace=False):
260+
def _walk_refs(obj, func, replace=False, _processed=None):
261+
# Keep track of already processed items to prevent recursion
262+
_processed = _processed or {}
263+
oid = id(obj)
264+
if oid in _processed:
265+
return _processed[oid]
264266
if type(obj) is JsonRef:
265-
return func(obj)
267+
r = func(obj)
268+
obj = r if replace else obj
269+
_processed[oid] = obj
266270
if isinstance(obj, Mapping):
267271
for k, v in obj.items():
268-
r = _walk_refs(v, func, replace=replace)
269-
if r is not _no_result and replace:
272+
r = _walk_refs(v, func, replace=replace, _processed=_processed)
273+
if replace:
270274
obj[k] = r
271275
elif isinstance(obj, Sequence) and not isinstance(obj, str):
272276
for i, v in enumerate(obj):
273-
r = _walk_refs(v, func, replace=replace)
274-
if r is not _no_result and replace:
277+
r = _walk_refs(v, func, replace=replace, _processed=_processed)
278+
if replace:
275279
obj[i] = r
276-
return _no_result
280+
return obj
277281

278282

279283
def replace_refs(

tests.py

+26
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from jsonref import (
1111
JsonRef,
1212
JsonRefError,
13+
_walk_refs,
1314
dump,
1415
dumps,
1516
jsonloader,
@@ -186,6 +187,31 @@ def test_no_proxies(self):
186187
result = replace_refs(json, proxies=False)
187188
assert result["b"] is result["a"]
188189

190+
def test_walk_refs(self):
191+
docs = {
192+
"a.json": {"file": "a", "b": {"$ref": "b.json"}},
193+
"b.json": {"file": "b", "c": {"$ref": "c.json"}},
194+
"c.json": {"file": "c"},
195+
}
196+
test_func = mock.Mock()
197+
res = replace_refs(docs["a.json"], loader=docs.get)
198+
_walk_refs(res, test_func)
199+
# Make sure it followed the refs through documents
200+
assert test_func.call_count == 2
201+
202+
def test_multi_doc_no_proxies(self):
203+
docs = {
204+
"a.json": {"file": "a", "b": {"$ref": "b.json"}},
205+
"b.json": {"file": "b", "c": {"$ref": "c.json"}},
206+
"c.json": {"file": "c"},
207+
}
208+
test_func = mock.Mock()
209+
res = replace_refs(docs["a.json"], loader=docs.get, proxies=False)
210+
_walk_refs(res, test_func)
211+
# Make sure there aren't any JsonRefs left
212+
assert test_func.call_count == 0
213+
assert res == {"file": "a", "b": {"file": "b", "c": {"file": "c"}}}
214+
189215
def test_recursive_data_structures_local(self):
190216
json = {"a": "foobar", "b": {"$ref": "#"}}
191217
result = replace_refs(json)

0 commit comments

Comments
 (0)