Skip to content

Commit e90774a

Browse files
committed
allowremotejson: New feature
#24 Also fixed local ref in example docs
1 parent a20f213 commit e90774a

File tree

12 files changed

+233
-8
lines changed

12 files changed

+233
-8
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
99
### Added
1010

1111
- Add `externallinks` option to `jsonschema` directive https://github.com/OpenDataServices/sphinxcontrib-opendataservices-jsonschema/issues/24
12+
- Add `allowremotejson` option to `jsonschema` directive, off by default to preserve backwards compatibility
13+
https://github.com/OpenDataServices/sphinxcontrib-opendataservices-jsonschema/issues/24
1214

1315
## [0.3.0] - 2021-05-12
1416

docs/example_schema.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"$id": "example_schema.json",
23
"$schema": "http://json-schema.org/draft-04/schema#",
34
"properties": {
45
"id": {
@@ -30,9 +31,12 @@
3031
}
3132
},
3233
"address": {
33-
"$ref": "/definitions/Address",
34+
"$ref": "#/definitions/Address",
3435
"title": "Address",
3536
"description": "Where this person lives"
37+
},
38+
"pet": {
39+
"$ref": "example_schema_pets.json"
3640
}
3741
},
3842
"definitions": {

docs/example_schema_pets.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$id": "example_schema_pets.json",
3+
"$schema": "http://json-schema.org/draft-04/schema#",
4+
"properties": {
5+
"id": {
6+
"type": "string",
7+
"title": "Identifier"
8+
},
9+
"name": {
10+
"type": "string",
11+
"title": "Name",
12+
"description": "A casual name for this pet"
13+
},
14+
"type": {
15+
"type": "string",
16+
"title": "Type of pet",
17+
"enum": [
18+
"cat",
19+
"dog"
20+
]
21+
}
22+
}
23+
}

docs/examples.rst

+10
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,13 @@ With externallinks option
7272
:include: formalname
7373
:externallinks: {"formalname":{"url":"https://en.wikipedia.org/wiki/Butler","text":"A guide on how to use formal names"}}
7474

75+
With allowremotejson option
76+
---------------------------
77+
78+
.. code-block:: rst
79+
80+
.. jsonschema:: example_schema.json
81+
:allowremotejson:
82+
83+
.. jsonschema:: example_schema.json
84+
:allowremotejson:

docs/use.rst

+14
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,17 @@ You can pass a dictionary of dictionaries to this.
8585
8686
For every property included, a extra link will be included with the URL and text specified in the description section.
8787

88+
89+
Option: allowremotejson
90+
-----------------------
91+
92+
You can pass the optional flag `allowremotejson`.
93+
94+
.. code-block:: rst
95+
96+
.. jsonschema:: example_schema.json
97+
:allowremotejson:
98+
99+
If passed, you can use `$ref` to load remote files and they will be loaded.
100+
101+
If not passed, any remote references will silently be ignored.

sphinxcontrib/jsonschema.py

+18-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from docutils import nodes
1414
from docutils.parsers.rst import directives, Directive
1515
from myst_parser.main import to_docutils
16-
16+
from pathlib import Path
1717

1818
import json
1919
from collections import OrderedDict
@@ -34,6 +34,7 @@ class JSONSchemaDirective(Directive):
3434
'nocrossref': directives.flag,
3535
'addtargets': directives.flag,
3636
'externallinks': directives.unchanged,
37+
'allowremotejson': directives.flag,
3738
}
3839
# Add a rollup option here
3940

@@ -72,9 +73,12 @@ def run(self):
7273
self.arguments[0])
7374
env.note_dependency(relpath)
7475

75-
schema = JSONSchema.loadfromfile(abspath)
76+
schema = JSONSchema.loadfromfile(abspath, allow_remote_json=('allowremotejson' in self.options))
7677
else:
77-
schema = JSONSchema.loadfromfile(''.join(self.content))
78+
schema = JSONSchema.loadfromfile(
79+
''.join(self.content),
80+
allow_remote_json=('allowremotejson' in self.options)
81+
)
7882
except ValueError as exc:
7983
raise self.error('Failed to parse JSON Schema: %s' % exc)
8084

@@ -224,8 +228,11 @@ def simplify(obj):
224228

225229
class JSONSchema(object):
226230
@classmethod
227-
def load(cls, reader):
228-
obj = jsonref.load(reader, object_pairs_hook=OrderedDict, loader=CustomJsonrefLoader())
231+
def load(cls, reader, allow_remote_json=False, base_uri=None):
232+
args = {}
233+
if not allow_remote_json:
234+
args['loader'] = CustomJsonrefLoader()
235+
obj = jsonref.load(reader, object_pairs_hook=OrderedDict, base_uri=base_uri, **args)
229236
return cls.instantiate(None, obj)
230237

231238
@classmethod
@@ -234,9 +241,13 @@ def loads(cls, string):
234241
return cls.instantiate(None, obj)
235242

236243
@classmethod
237-
def loadfromfile(cls, filename):
244+
def loadfromfile(cls, filename, allow_remote_json=False):
238245
with io.open(filename, 'rt', encoding='utf-8') as reader:
239-
return cls.load(reader)
246+
args = {}
247+
if allow_remote_json:
248+
args['allow_remote_json'] = True
249+
args['base_uri'] = Path(os.path.realpath(filename)).as_uri()
250+
return cls.load(reader, **args)
240251

241252
@classmethod
242253
def instantiate(cls, name, obj, required=False, parent=None, rollup=True):

tests/examples/basic-remotejson.html

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<div class="documentwrapper">
2+
<div class="bodywrapper">
3+
4+
5+
<div class="body" role="main">
6+
7+
<div class="section" id="no-refs">
8+
<h1>NO REFS<a class="headerlink" href="#no-refs" title="Permalink to this headline">&#182;</a></h1>
9+
<table class="docutils align-default">
10+
<colgroup>
11+
<col style="width: 20%">
12+
<col style="width: 20%">
13+
<col style="width: 20%">
14+
<col style="width: 20%">
15+
<col style="width: 20%">
16+
</colgroup>
17+
<thead>
18+
<tr class="row-odd"><th class="head" colspan="1"><p>Title</p></th>
19+
<th class="head" colspan="1"><p>Description</p></th>
20+
<th class="head" colspan="1"><p>Type</p></th>
21+
<th class="head" colspan="1"><p>Format</p></th>
22+
<th class="head" colspan="1"><p>Required</p></th>
23+
</tr>
24+
</thead>
25+
<tbody>
26+
<tr class="row-even"><td colspan="2"><code class="docutils literal notranslate" id="test.json,,name"><span class="pre">name</span></code></td>
27+
<td colspan="1"><p>string</p></td>
28+
<td colspan="1"></td>
29+
<td colspan="1"></td>
30+
</tr>
31+
<tr class="row-odd"><td colspan="1"><p>None</p></td>
32+
</tr>
33+
<tr class="row-even"><td colspan="2"><code class="docutils literal notranslate" id="test.json,,pet"><span class="pre">pet</span></code></td>
34+
<td colspan="1"><p>object</p></td>
35+
<td colspan="1"></td>
36+
<td colspan="1"></td>
37+
</tr>
38+
<tr class="row-odd"><td colspan="1"><p>None</p></td>
39+
</tr>
40+
</tbody>
41+
</table>
42+
</div>
43+
<div class="section" id="with-refs">
44+
<h1>WITH REFS<a class="headerlink" href="#with-refs" title="Permalink to this headline">&#182;</a></h1>
45+
<table class="docutils align-default">
46+
<colgroup>
47+
<col style="width: 20%">
48+
<col style="width: 20%">
49+
<col style="width: 20%">
50+
<col style="width: 20%">
51+
<col style="width: 20%">
52+
</colgroup>
53+
<thead>
54+
<tr class="row-odd"><th class="head" colspan="1"><p>Title</p></th>
55+
<th class="head" colspan="1"><p>Description</p></th>
56+
<th class="head" colspan="1"><p>Type</p></th>
57+
<th class="head" colspan="1"><p>Format</p></th>
58+
<th class="head" colspan="1"><p>Required</p></th>
59+
</tr>
60+
</thead>
61+
<tbody>
62+
<tr class="row-even"><td colspan="2"><code class="docutils literal notranslate" id="test.json,,name"><span class="pre">name</span></code></td>
63+
<td colspan="1"><p>string</p></td>
64+
<td colspan="1"></td>
65+
<td colspan="1"></td>
66+
</tr>
67+
<tr class="row-odd"><td colspan="1"><p>None</p></td>
68+
</tr>
69+
<tr class="row-even"><td colspan="2"><code class="docutils literal notranslate" id="test.json,,pet"><span class="pre">pet</span></code></td>
70+
<td colspan="1"><p>object</p></td>
71+
<td colspan="1"></td>
72+
<td colspan="1"></td>
73+
</tr>
74+
<tr class="row-odd"><td colspan="1"><p>None</p></td>
75+
</tr>
76+
<tr class="row-even"><td colspan="2"><code class="docutils literal notranslate" id="test.json,,pet/id"><span class="pre">pet/id</span></code></td>
77+
<td colspan="1"><p>string</p></td>
78+
<td colspan="1"></td>
79+
<td colspan="1"></td>
80+
</tr>
81+
<tr class="row-odd"><td colspan="1"><p>Identifier</p></td>
82+
</tr>
83+
<tr class="row-even"><td colspan="2"><code class="docutils literal notranslate" id="test.json,,pet/name"><span class="pre">pet/name</span></code></td>
84+
<td colspan="1"><p>string</p></td>
85+
<td colspan="1"></td>
86+
<td colspan="1"></td>
87+
</tr>
88+
<tr class="row-odd"><td colspan="1"><p>Name</p></td>
89+
<td colspan="4"><p>A casual name for this pet</p></td>
90+
</tr>
91+
<tr class="row-even"><td colspan="2"><code class="docutils literal notranslate" id="test.json,,pet/type"><span class="pre">pet/type</span></code></td>
92+
<td colspan="1"><p>string</p></td>
93+
<td colspan="1"></td>
94+
<td colspan="1"></td>
95+
</tr>
96+
<tr class="row-odd"><td colspan="1"><p>Type of pet</p></td>
97+
</tr>
98+
</tbody>
99+
</table>
100+
</div>
101+
102+
103+
</div>
104+
105+
</div>
106+
</div>
107+
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
master_doc = 'index'
2+
extensions = ['sphinxcontrib.jsonschema']
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
NO REFS
2+
-------
3+
4+
.. jsonschema:: subdir/test.json
5+
6+
WITH REFS
7+
---------
8+
9+
.. jsonschema:: subdir/test.json
10+
:allowremotejson:
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"definitions": {
4+
"pet": {
5+
"properties": {
6+
"id": {
7+
"type": "string",
8+
"title": "Identifier"
9+
},
10+
"name": {
11+
"type": "string",
12+
"title": "Name",
13+
"description": "A casual name for this pet"
14+
},
15+
"type": {
16+
"type": "string",
17+
"title": "Type of pet",
18+
"enum": [
19+
"cat",
20+
"dog"
21+
]
22+
}
23+
}
24+
}
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"description": "Data for people",
3+
"type" : "object",
4+
"properties" : {
5+
"name" : "string",
6+
"pet" : {
7+
"$ref": "pet.json#/definitions/pet"
8+
}
9+
}
10+
}

tests/test_directive.py

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ def test_basic_externallinks(app, status, warning):
5757
assert_build(app, status, warning, 'basic-externallinks')
5858

5959

60+
@pytest.mark.sphinx(buildername='html', srcdir=path('basic-remotejson'), freshenv=True)
61+
def test_basic_remotejson(app, status, warning):
62+
assert_build(app, status, warning, 'basic-remotejson')
63+
64+
6065
@pytest.mark.sphinx(buildername='gettext', srcdir=path('basic-md'), freshenv=True)
6166
def test_basic_gettext_myst(app, status, warning):
6267
assert_build(app, status, warning, 'basic-md', buildername='gettext')

0 commit comments

Comments
 (0)