sc-oa 0.7.0.15__py3-none-any.whl → 0.7.0.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sc-oa might be problematic. Click here for more details.

@@ -1,48 +1,48 @@
1
-
2
- import re
3
- from urllib.parse import urlparse
4
-
5
- from . import abc
6
- from .. import utils
7
- from docutils.parsers.rst import directives
8
-
9
-
10
- class TocRenderer(abc.RestructuredTextRenderer):
11
-
12
- option_spec = {
13
- # nb columns
14
- "nb_columns": directives.positive_int,
15
- "contextpath": directives.flag, # use the server path as prefix in service URL
16
- }
17
-
18
- def __init__(self, state, options):
19
- self._state = state
20
- self._options = options
21
- if 'nb_columns' not in self._options:
22
- self._options["nb_columns"] = 2
23
-
24
- def render_restructuredtext_markup(self, spec):
25
-
26
- utils.normalize_spec(spec, **self._options)
27
-
28
- contextpath = ''
29
- if 'contextpath' in self._options:
30
- if 'servers' in spec:
31
- h = spec['servers'][0]['url']
32
- contextpath = urlparse(h).path
33
- if contextpath and contextpath[-1] == '/':
34
- contextpath = contextpath[:-1]
35
-
36
- yield ""
37
- yield ".. hlist::"
38
- yield " :columns: {}".format(self._options["nb_columns"])
39
- yield ""
40
-
41
- for path in spec["paths"].keys():
42
- cpath = re.sub(r"[{}]", "", re.sub(r"[<>:/]", "-", contextpath+path))
43
- for verb, ope in spec["paths"][path].items():
44
- yield " - `{} <#{}>`_".format(
45
- ope.get("operationId", verb + " " + path),
46
- verb.lower() + "-" + cpath
47
- )
48
- yield ""
1
+
2
+ import re
3
+ from urllib.parse import urlparse
4
+
5
+ from . import abc
6
+ from .. import utils
7
+ from docutils.parsers.rst import directives
8
+
9
+
10
+ class TocRenderer(abc.RestructuredTextRenderer):
11
+
12
+ option_spec = {
13
+ # nb columns
14
+ "nb_columns": directives.positive_int,
15
+ "contextpath": directives.flag, # use the server path as prefix in service URL
16
+ }
17
+
18
+ def __init__(self, state, options):
19
+ self._state = state
20
+ self._options = options
21
+ if 'nb_columns' not in self._options:
22
+ self._options["nb_columns"] = 2
23
+
24
+ def render_restructuredtext_markup(self, spec):
25
+
26
+ utils.normalize_spec(spec, **self._options)
27
+
28
+ contextpath = ''
29
+ if 'contextpath' in self._options:
30
+ if 'servers' in spec:
31
+ h = spec['servers'][0]['url']
32
+ contextpath = urlparse(h).path
33
+ if contextpath and contextpath[-1] == '/':
34
+ contextpath = contextpath[:-1]
35
+
36
+ yield ""
37
+ yield ".. hlist::"
38
+ yield " :columns: {}".format(self._options["nb_columns"])
39
+ yield ""
40
+
41
+ for path in spec["paths"].keys():
42
+ cpath = re.sub(r"[{}]", "", re.sub(r"[<>:/]", "-", contextpath+path))
43
+ for verb, ope in spec["paths"][path].items():
44
+ yield " - `{} <#{}>`_".format(
45
+ ope.get("operationId", verb + " " + path),
46
+ verb.lower() + "-" + cpath
47
+ )
48
+ yield ""
@@ -1,46 +1,46 @@
1
- """Abstract Base Classes (ABCs) for OpenAPI renderers."""
2
-
3
- import abc
4
-
5
- from docutils import nodes
6
- from docutils.statemachine import ViewList
7
- from sphinx.util.nodes import nested_parse_with_titles
8
-
9
-
10
- class Renderer(metaclass=abc.ABCMeta):
11
- """Base class for OpenAPI renderers."""
12
-
13
- def __init__(self, state, options):
14
- self._state = state
15
- self._options = options
16
-
17
- @property
18
- @abc.abstractmethod
19
- def option_spec(self):
20
- """Renderer options and their converting functions."""
21
-
22
- @abc.abstractmethod
23
- def render(self, spec):
24
- """Render a given OpenAPI spec."""
25
-
26
-
27
- class RestructuredTextRenderer(Renderer):
28
- """Base class for reStructuredText OpenAPI renderers.
29
-
30
- Docutils DOM manipulation is quite a tricky task that requires passing
31
- dozen arguments around. Because of that a lot of Sphinx extensions instead
32
- of constructing DOM nodes directly produce and parse reStructuredText.
33
- This Sphinx extension is not an exception, and that's why this class
34
- exists. It's a convenient extension of :class:`Renderer` that converts
35
- produced markup text into docutils DOM elements.
36
- """
37
-
38
- def render(self, spec):
39
- viewlist = ViewList()
40
- for line in self.render_restructuredtext_markup(spec):
41
- viewlist.append(line, "<openapi>")
42
-
43
- node = nodes.section()
44
- node.document = self._state.document
45
- nested_parse_with_titles(self._state, viewlist, node)
46
- return node.children
1
+ """Abstract Base Classes (ABCs) for OpenAPI renderers."""
2
+
3
+ import abc
4
+
5
+ from docutils import nodes
6
+ from docutils.statemachine import ViewList
7
+ from sphinx.util.nodes import nested_parse_with_titles
8
+
9
+
10
+ class Renderer(metaclass=abc.ABCMeta):
11
+ """Base class for OpenAPI renderers."""
12
+
13
+ def __init__(self, state, options):
14
+ self._state = state
15
+ self._options = options
16
+
17
+ @property
18
+ @abc.abstractmethod
19
+ def option_spec(self):
20
+ """Renderer options and their converting functions."""
21
+
22
+ @abc.abstractmethod
23
+ def render(self, spec):
24
+ """Render a given OpenAPI spec."""
25
+
26
+
27
+ class RestructuredTextRenderer(Renderer):
28
+ """Base class for reStructuredText OpenAPI renderers.
29
+
30
+ Docutils DOM manipulation is quite a tricky task that requires passing
31
+ dozen arguments around. Because of that a lot of Sphinx extensions instead
32
+ of constructing DOM nodes directly produce and parse reStructuredText.
33
+ This Sphinx extension is not an exception, and that's why this class
34
+ exists. It's a convenient extension of :class:`Renderer` that converts
35
+ produced markup text into docutils DOM elements.
36
+ """
37
+
38
+ def render(self, spec):
39
+ viewlist = ViewList()
40
+ for line in self.render_restructuredtext_markup(spec):
41
+ viewlist.append(line, "<openapi>")
42
+
43
+ node = nodes.section()
44
+ node.document = self._state.document
45
+ nested_parse_with_titles(self._state, viewlist, node)
46
+ return node.children
@@ -1,137 +1,137 @@
1
- """OpenAPI schema utility functions."""
2
-
3
- from io import StringIO
4
-
5
-
6
- _DEFAULT_EXAMPLES = {
7
- "string": "string",
8
- "integer": 1,
9
- "number": 1.0,
10
- "boolean": True,
11
- "array": [],
12
- }
13
-
14
-
15
- _DEFAULT_STRING_EXAMPLES = {
16
- "date": "2020-01-01",
17
- "date-time": "2020-01-01T01:01:01Z",
18
- "password": "********",
19
- "byte": "QG1pY2hhZWxncmFoYW1ldmFucw==",
20
- "ipv4": "127.0.0.1",
21
- "ipv6": "::1",
22
- }
23
-
24
-
25
- def example_from_schema(schema):
26
- """
27
- Generates an example request/response body from the provided schema.
28
-
29
- >>> schema = {
30
- ... "type": "object",
31
- ... "required": ["id", "name"],
32
- ... "properties": {
33
- ... "id": {
34
- ... "type": "integer",
35
- ... "format": "int64"
36
- ... },
37
- ... "name": {
38
- ... "type": "string",
39
- ... "example": "John Smith"
40
- ... },
41
- ... "tag": {
42
- ... "type": "string"
43
- ... }
44
- ... }
45
- ... }
46
- >>> example = example_from_schema(schema)
47
- >>> assert example == {
48
- ... "id": 1,
49
- ... "name": "John Smith",
50
- ... "tag": "string"
51
- ... }
52
- """
53
- # If an example was provided then we use that
54
- if "example" in schema:
55
- return schema["example"]
56
-
57
- elif "oneOf" in schema:
58
- return example_from_schema(schema["oneOf"][0])
59
-
60
- elif "anyOf" in schema:
61
- return example_from_schema(schema["anyOf"][0])
62
-
63
- elif "allOf" in schema:
64
- # Combine schema examples
65
- example = {}
66
- for sub_schema in schema["allOf"]:
67
- example.update(example_from_schema(sub_schema))
68
- return example
69
-
70
- elif "enum" in schema:
71
- return schema["enum"][0]
72
-
73
- elif "type" not in schema:
74
- # Any type
75
- return _DEFAULT_EXAMPLES["integer"]
76
-
77
- elif schema["type"] == "object" or "properties" in schema:
78
- example = {}
79
- for prop, prop_schema in schema.get("properties", {}).items():
80
- example[prop] = example_from_schema(prop_schema)
81
- return example
82
-
83
- elif schema["type"] == "array":
84
- items = schema["items"]
85
- min_length = schema.get("minItems", 0)
86
- max_length = schema.get("maxItems", max(min_length, 2))
87
- assert min_length <= max_length
88
- # Try generate at least 2 example array items
89
- gen_length = min(2, max_length) if min_length <= 2 else min_length
90
-
91
- example_items = []
92
- if items == {}:
93
- # Any-type arrays
94
- example_items.extend(_DEFAULT_EXAMPLES.values())
95
- elif isinstance(items, dict) and "oneOf" in items:
96
- # Mixed-type arrays
97
- example_items.append(_DEFAULT_EXAMPLES[sorted(items["oneOf"])[0]])
98
- else:
99
- example_items.append(example_from_schema(items))
100
-
101
- # Generate array containing example_items and satisfying min_length and max_length
102
- return [example_items[i % len(example_items)] for i in range(gen_length)]
103
-
104
- elif schema["type"] == "string":
105
- example_string = _DEFAULT_STRING_EXAMPLES.get(
106
- schema.get("format", None), _DEFAULT_EXAMPLES["string"]
107
- )
108
- min_length = schema.get("minLength", 0)
109
- max_length = schema.get("maxLength", max(min_length, len(example_string)))
110
- gen_length = (
111
- min(len(example_string), max_length)
112
- if min_length <= len(example_string)
113
- else min_length
114
- )
115
- assert 0 <= min_length <= max_length
116
- if min_length <= len(example_string) <= max_length:
117
- return example_string
118
- else:
119
- example_builder = StringIO()
120
- for i in range(gen_length):
121
- example_builder.write(example_string[i % len(example_string)])
122
- example_builder.seek(0)
123
- return example_builder.read()
124
-
125
- elif schema["type"] in ("integer", "number"):
126
- example = _DEFAULT_EXAMPLES[schema["type"]]
127
- if "minimum" in schema and "maximum" in schema:
128
- # Take average
129
- example = schema["minimum"] + (schema["maximum"] - schema["minimum"]) / 2
130
- elif "minimum" in schema and example <= schema["minimum"]:
131
- example = schema["minimum"] + 1
132
- elif "maximum" in schema and example >= schema["maximum"]:
133
- example = schema["maximum"] - 1
134
- return float(example) if schema["type"] == "number" else int(example)
135
-
136
- else:
137
- return _DEFAULT_EXAMPLES[schema["type"]]
1
+ """OpenAPI schema utility functions."""
2
+
3
+ from io import StringIO
4
+
5
+
6
+ _DEFAULT_EXAMPLES = {
7
+ "string": "string",
8
+ "integer": 1,
9
+ "number": 1.0,
10
+ "boolean": True,
11
+ "array": [],
12
+ }
13
+
14
+
15
+ _DEFAULT_STRING_EXAMPLES = {
16
+ "date": "2020-01-01",
17
+ "date-time": "2020-01-01T01:01:01Z",
18
+ "password": "********",
19
+ "byte": "QG1pY2hhZWxncmFoYW1ldmFucw==",
20
+ "ipv4": "127.0.0.1",
21
+ "ipv6": "::1",
22
+ }
23
+
24
+
25
+ def example_from_schema(schema):
26
+ """
27
+ Generates an example request/response body from the provided schema.
28
+
29
+ >>> schema = {
30
+ ... "type": "object",
31
+ ... "required": ["id", "name"],
32
+ ... "properties": {
33
+ ... "id": {
34
+ ... "type": "integer",
35
+ ... "format": "int64"
36
+ ... },
37
+ ... "name": {
38
+ ... "type": "string",
39
+ ... "example": "John Smith"
40
+ ... },
41
+ ... "tag": {
42
+ ... "type": "string"
43
+ ... }
44
+ ... }
45
+ ... }
46
+ >>> example = example_from_schema(schema)
47
+ >>> assert example == {
48
+ ... "id": 1,
49
+ ... "name": "John Smith",
50
+ ... "tag": "string"
51
+ ... }
52
+ """
53
+ # If an example was provided then we use that
54
+ if "example" in schema:
55
+ return schema["example"]
56
+
57
+ elif "oneOf" in schema:
58
+ return example_from_schema(schema["oneOf"][0])
59
+
60
+ elif "anyOf" in schema:
61
+ return example_from_schema(schema["anyOf"][0])
62
+
63
+ elif "allOf" in schema:
64
+ # Combine schema examples
65
+ example = {}
66
+ for sub_schema in schema["allOf"]:
67
+ example.update(example_from_schema(sub_schema))
68
+ return example
69
+
70
+ elif "enum" in schema:
71
+ return schema["enum"][0]
72
+
73
+ elif "type" not in schema:
74
+ # Any type
75
+ return _DEFAULT_EXAMPLES["integer"]
76
+
77
+ elif schema["type"] == "object" or "properties" in schema:
78
+ example = {}
79
+ for prop, prop_schema in schema.get("properties", {}).items():
80
+ example[prop] = example_from_schema(prop_schema)
81
+ return example
82
+
83
+ elif schema["type"] == "array":
84
+ items = schema["items"]
85
+ min_length = schema.get("minItems", 0)
86
+ max_length = schema.get("maxItems", max(min_length, 2))
87
+ assert min_length <= max_length
88
+ # Try generate at least 2 example array items
89
+ gen_length = min(2, max_length) if min_length <= 2 else min_length
90
+
91
+ example_items = []
92
+ if items == {}:
93
+ # Any-type arrays
94
+ example_items.extend(_DEFAULT_EXAMPLES.values())
95
+ elif isinstance(items, dict) and "oneOf" in items:
96
+ # Mixed-type arrays
97
+ example_items.append(_DEFAULT_EXAMPLES[sorted(items["oneOf"])[0]])
98
+ else:
99
+ example_items.append(example_from_schema(items))
100
+
101
+ # Generate array containing example_items and satisfying min_length and max_length
102
+ return [example_items[i % len(example_items)] for i in range(gen_length)]
103
+
104
+ elif schema["type"] == "string":
105
+ example_string = _DEFAULT_STRING_EXAMPLES.get(
106
+ schema.get("format", None), _DEFAULT_EXAMPLES["string"]
107
+ )
108
+ min_length = schema.get("minLength", 0)
109
+ max_length = schema.get("maxLength", max(min_length, len(example_string)))
110
+ gen_length = (
111
+ min(len(example_string), max_length)
112
+ if min_length <= len(example_string)
113
+ else min_length
114
+ )
115
+ assert 0 <= min_length <= max_length
116
+ if min_length <= len(example_string) <= max_length:
117
+ return example_string
118
+ else:
119
+ example_builder = StringIO()
120
+ for i in range(gen_length):
121
+ example_builder.write(example_string[i % len(example_string)])
122
+ example_builder.seek(0)
123
+ return example_builder.read()
124
+
125
+ elif schema["type"] in ("integer", "number"):
126
+ example = _DEFAULT_EXAMPLES[schema["type"]]
127
+ if "minimum" in schema and "maximum" in schema:
128
+ # Take average
129
+ example = schema["minimum"] + (schema["maximum"] - schema["minimum"]) / 2
130
+ elif "minimum" in schema and example <= schema["minimum"]:
131
+ example = schema["minimum"] + 1
132
+ elif "maximum" in schema and example >= schema["maximum"]:
133
+ example = schema["maximum"] - 1
134
+ return float(example) if schema["type"] == "number" else int(example)
135
+
136
+ else:
137
+ return _DEFAULT_EXAMPLES[schema["type"]]