Skip to content

Commit b718258

Browse files
committed
Split general JSON schema formatting away from APIspec
1 parent 26cb16a commit b718258

26 files changed

+568
-79
lines changed

src/labthings/apispec/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .apispec import rule_to_apispec_path
2+
from .plugins import MarshmallowPlugin

src/labthings/spec/apispec.py renamed to src/labthings/apispec/apispec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from apispec import APISpec
2-
from .paths import rule_to_path, rule_to_params
2+
from ..json.paths import rule_to_path, rule_to_params
33
from .utilities import convert_to_schema_or_json
44

55
from ..utilities import get_docstring, get_summary
Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
from apispec.ext.marshmallow import (
2-
MarshmallowPlugin as _MarshmallowPlugin,
3-
OpenAPIConverter,
4-
)
1+
from apispec.ext.marshmallow import OpenAPIConverter
52
from ..fields import Bytes as BytesField
63

74

85
class ExtendedOpenAPIConverter(OpenAPIConverter):
96
field_mapping = OpenAPIConverter.field_mapping
10-
field_mapping.update({BytesField: ("string", None)})
117

128
def init_attribute_functions(self, *args, **kwargs):
139
OpenAPIConverter.init_attribute_functions(self, *args, **kwargs)
@@ -16,9 +12,5 @@ def init_attribute_functions(self, *args, **kwargs):
1612
def bytes2json(self, field, **kwargs):
1713
ret = {}
1814
if isinstance(field, BytesField):
19-
ret.update({"contentEncoding": "base64"})
15+
ret.update(BytesField()._jsonschema_type_mapping())
2016
return ret
21-
22-
23-
class MarshmallowPlugin(_MarshmallowPlugin):
24-
Converter = ExtendedOpenAPIConverter

src/labthings/apispec/plugins.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from apispec.ext.marshmallow import MarshmallowPlugin as _MarshmallowPlugin
2+
from .converter import ExtendedOpenAPIConverter
3+
4+
5+
class MarshmallowPlugin(_MarshmallowPlugin):
6+
Converter = ExtendedOpenAPIConverter
File renamed without changes.

src/labthings/core/utilities.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@
1212
snake_to_camel,
1313
path_relative_to,
1414
)
15-

src/labthings/fields.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272

7373

7474
class Bytes(Field):
75+
def _jsonschema_type_mapping(self):
76+
return {"type": "string", "contentEncoding": "base64"}
77+
7578
def _validate(self, value):
7679
if not isinstance(value, bytes):
7780
raise ValidationError("Invalid input type.")

src/labthings/json/__init__.py

Whitespace-only changes.

src/labthings/json/encoder.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from flask import make_response, current_app
2+
3+
# Flask JSON encoder so we get UUID, datetime etc support
4+
from flask.json import JSONEncoder
5+
from base64 import b64encode
6+
import json
7+
8+
9+
class LabThingsJSONEncoder(JSONEncoder):
10+
"""
11+
A custom JSON encoder, with type conversions for PiCamera fractions, Numpy integers, and Numpy arrays
12+
"""
13+
14+
def default(self, o):
15+
if isinstance(o, set):
16+
return list(o)
17+
if isinstance(o, bytes):
18+
try: # Try unicode
19+
return o.decode()
20+
except UnicodeDecodeError: # Otherwise, base64
21+
return b64encode(o).decode()
22+
return JSONEncoder.default(self, o)
23+
24+
25+
def encode_json(data, encoder=LabThingsJSONEncoder, **settings):
26+
"""Makes JSON encoded data using the LabThings JSON encoder"""
27+
return json.dumps(data, cls=encoder, **settings) + "\n"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Stephen J. Fuhry
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)