DefEssential 0.1.8__24-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.
- DefEssential/Adapter/Implements/Gunicorn/Server.py +152 -0
- DefEssential/Adapter/Implements/Gunicorn/Transport.py +171 -0
- DefEssential/Adapter/Implements/Gunicorn/__init__.py +5 -0
- DefEssential/Adapter/Implements/Python/Server.py +273 -0
- DefEssential/Adapter/Implements/Python/__init__.py +5 -0
- DefEssential/Adapter/Implements/Uvicorn/HTTP.py +256 -0
- DefEssential/Adapter/Implements/Uvicorn/Portal.py +65 -0
- DefEssential/Adapter/Implements/Uvicorn/Server.py +137 -0
- DefEssential/Adapter/Implements/Uvicorn/WebSocket.py +222 -0
- DefEssential/Adapter/Implements/Uvicorn/__init__.py +5 -0
- DefEssential/Adapter/Implements/__init__.py +3 -0
- DefEssential/Adapter/RequestHandler.py +109 -0
- DefEssential/Adapter/Server.py +54 -0
- DefEssential/Adapter/WSGI.py +219 -0
- DefEssential/Adapter/__init__.py +5 -0
- DefEssential/Application.py +657 -0
- DefEssential/Body.py +50 -0
- DefEssential/Content.py +18 -0
- DefEssential/Credentials.py +245 -0
- DefEssential/CrossOriginResourceSharing.py +107 -0
- DefEssential/Descriptor/DataObject.py +409 -0
- DefEssential/Descriptor/Types.py +248 -0
- DefEssential/Descriptor/Value.py +188 -0
- DefEssential/Descriptor/__init__.py +172 -0
- DefEssential/Error.py +66 -0
- DefEssential/Extension.py +191 -0
- DefEssential/Extensions/File.py +95 -0
- DefEssential/Extensions/FileSystem.py +195 -0
- DefEssential/Extensions/Metrics.py +511 -0
- DefEssential/Extensions/Ping.py +93 -0
- DefEssential/Extensions/Specifications.py +342 -0
- DefEssential/Extensions/Status.html +207 -0
- DefEssential/Extensions/Status.py +110 -0
- DefEssential/Extensions/Swagger.html +77 -0
- DefEssential/Extensions/Swagger.py +117 -0
- DefEssential/Extensions/Utils/Routes.py +42 -0
- DefEssential/Extensions/Utils/__init__.py +43 -0
- DefEssential/Extensions/__init__.py +21 -0
- DefEssential/IO/Readers/ChunkedStream.py +106 -0
- DefEssential/IO/Readers/ContentReader.py +36 -0
- DefEssential/IO/Readers/ContentReaders.py +241 -0
- DefEssential/IO/Readers/__init__.py +25 -0
- DefEssential/IO/RequestReader.py +125 -0
- DefEssential/IO/ResponseWriter.py +242 -0
- DefEssential/IO/WebSocket/WebSocket.py +288 -0
- DefEssential/IO/WebSocket/WebSocketError.py +17 -0
- DefEssential/IO/WebSocket/WebSocketFrame.py +68 -0
- DefEssential/IO/WebSocket/WebSocketFrameReader.py +98 -0
- DefEssential/IO/WebSocket/WebSocketHandshake.py +94 -0
- DefEssential/IO/WebSocket/__init__.py +13 -0
- DefEssential/IO/Writers/ChunkedStreamWriter.py +19 -0
- DefEssential/IO/Writers/ServerSentEvents.py +41 -0
- DefEssential/IO/Writers/ServerSentEventsWriter.py +67 -0
- DefEssential/IO/Writers/StreamWriter.py +57 -0
- DefEssential/IO/Writers/__init__.py +11 -0
- DefEssential/IO/__init__.py +7 -0
- DefEssential/Request.py +110 -0
- DefEssential/RequestRunner.py +261 -0
- DefEssential/Response.py +89 -0
- DefEssential/ResponseSpecification.py +23 -0
- DefEssential/Responses/ResponseFile.py +108 -0
- DefEssential/Responses/__init__.py +63 -0
- DefEssential/Route.py +55 -0
- DefEssential/Router.py +48 -0
- DefEssential/Runners/RunExtension.py +116 -0
- DefEssential/Runners/RunFactory.py +26 -0
- DefEssential/Runners/RunOptions.py +77 -0
- DefEssential/Runners/RunRequest.py +198 -0
- DefEssential/Runners/__init__.py +5 -0
- DefEssential/Startup.py +104 -0
- DefEssential/Utils/FileSystemObject/Configuration.py +15 -0
- DefEssential/Utils/FileSystemObject/Connection.py +57 -0
- DefEssential/Utils/FileSystemObject/File.py +41 -0
- DefEssential/Utils/FileSystemObject/Implements/FileSystem/Configuration.py +15 -0
- DefEssential/Utils/FileSystemObject/Implements/FileSystem/Connection.py +115 -0
- DefEssential/Utils/FileSystemObject/Implements/FileSystem/File.py +77 -0
- DefEssential/Utils/FileSystemObject/Implements/FileSystem/__init__.py +11 -0
- DefEssential/Utils/FileSystemObject/Implements/__init__.py +3 -0
- DefEssential/Utils/FileSystemObject/__init__.py +11 -0
- DefEssential/Utils/Loader.py +81 -0
- DefEssential/Utils/__init__.py +3 -0
- DefEssential/Validator/Pattern.py +36 -0
- DefEssential/Validator/Patterns/Array.py +30 -0
- DefEssential/Validator/Patterns/Common.py +92 -0
- DefEssential/Validator/Patterns/Compare.py +180 -0
- DefEssential/Validator/Patterns/Condition.py +60 -0
- DefEssential/Validator/Patterns/DataObject.py +85 -0
- DefEssential/Validator/Patterns/DateTime.py +111 -0
- DefEssential/Validator/Patterns/Number.py +43 -0
- DefEssential/Validator/Patterns/Object.py +150 -0
- DefEssential/Validator/Patterns/Size.py +110 -0
- DefEssential/Validator/Patterns/String.py +85 -0
- DefEssential/Validator/Patterns/Type.py +350 -0
- DefEssential/Validator/Patterns/__init__.py +137 -0
- DefEssential/Validator/Validate.py +29 -0
- DefEssential/Validator/Validator.py +30 -0
- DefEssential/Validator/__init__.py +11 -0
- DefEssential/Validators.py +255 -0
- DefEssential/__init__.py +83 -0
- defessential-0.1.8.dist-info/METADATA +86 -0
- defessential-0.1.8.dist-info/RECORD +104 -0
- defessential-0.1.8.dist-info/WHEEL +6 -0
- defessential-0.1.8.dist-info/licenses/LICENSE +674 -0
- defessential-0.1.8.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .Value import (
|
|
4
|
+
Descriptor,
|
|
5
|
+
Condition,
|
|
6
|
+
Value,
|
|
7
|
+
Schema,
|
|
8
|
+
OneOf,
|
|
9
|
+
TypeMapper,
|
|
10
|
+
TypeEncoder,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .Types import (
|
|
14
|
+
Boolean,
|
|
15
|
+
Integer,
|
|
16
|
+
Number,
|
|
17
|
+
String,
|
|
18
|
+
Binary,
|
|
19
|
+
Array,
|
|
20
|
+
Object,
|
|
21
|
+
Properties,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from dataclasses import (
|
|
25
|
+
is_dataclass,
|
|
26
|
+
MISSING,
|
|
27
|
+
asdict,
|
|
28
|
+
)
|
|
29
|
+
from json import (
|
|
30
|
+
dumps,
|
|
31
|
+
loads,
|
|
32
|
+
)
|
|
33
|
+
from typing import (
|
|
34
|
+
Type,
|
|
35
|
+
Any,
|
|
36
|
+
Union,
|
|
37
|
+
Optional,
|
|
38
|
+
Dict,
|
|
39
|
+
Iterable,
|
|
40
|
+
Annotated,
|
|
41
|
+
get_origin,
|
|
42
|
+
get_args,
|
|
43
|
+
get_type_hints,
|
|
44
|
+
ForwardRef,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
__all__ = (
|
|
48
|
+
'SchemaToDataObject',
|
|
49
|
+
'DataObjectToSchema',
|
|
50
|
+
'DataObjectToObject',
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def SchemaToDataObject(
|
|
55
|
+
o: Schema,
|
|
56
|
+
name: Optional[str] = None,
|
|
57
|
+
) -> object:
|
|
58
|
+
# TODO: Implement dynamic dataclass generation from the schema.
|
|
59
|
+
raise NotImplementedError('SchemaToDataObject is not implemented yet')
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class DataObjectToSchema(object):
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
mapper: Optional[TypeMapper] = None,
|
|
66
|
+
) -> None:
|
|
67
|
+
self.mapper = mapper
|
|
68
|
+
return
|
|
69
|
+
def __value__(
|
|
70
|
+
self,
|
|
71
|
+
o: object,
|
|
72
|
+
format: Optional[object] = None,
|
|
73
|
+
description: Optional[str] = None,
|
|
74
|
+
required: bool = True,
|
|
75
|
+
default: Any = MISSING,
|
|
76
|
+
metadata: Any = None,
|
|
77
|
+
) -> Union[Descriptor, Condition, Schema]:
|
|
78
|
+
args = get_args(o)
|
|
79
|
+
origin = get_origin(o)
|
|
80
|
+
if origin is not None and not args:
|
|
81
|
+
return self.__value__(
|
|
82
|
+
origin,
|
|
83
|
+
format=format,
|
|
84
|
+
description=description,
|
|
85
|
+
required=required,
|
|
86
|
+
default=default,
|
|
87
|
+
metadata=metadata,
|
|
88
|
+
)
|
|
89
|
+
if args:
|
|
90
|
+
if len(args) == 1:
|
|
91
|
+
if origin is list:
|
|
92
|
+
return self.__value__(
|
|
93
|
+
list,
|
|
94
|
+
format=args[0],
|
|
95
|
+
description=description,
|
|
96
|
+
required=required,
|
|
97
|
+
default=default,
|
|
98
|
+
metadata=metadata,
|
|
99
|
+
)
|
|
100
|
+
if origin is tuple:
|
|
101
|
+
return self.__value__(
|
|
102
|
+
tuple,
|
|
103
|
+
format=args[0],
|
|
104
|
+
description=description,
|
|
105
|
+
required=required,
|
|
106
|
+
default=default,
|
|
107
|
+
metadata=metadata,
|
|
108
|
+
)
|
|
109
|
+
if origin is set:
|
|
110
|
+
return self.__value__(
|
|
111
|
+
set,
|
|
112
|
+
format=args[0],
|
|
113
|
+
description=description,
|
|
114
|
+
required=required,
|
|
115
|
+
default=default,
|
|
116
|
+
metadata=metadata,
|
|
117
|
+
)
|
|
118
|
+
if origin is Union:
|
|
119
|
+
return self.__value__(
|
|
120
|
+
Union,
|
|
121
|
+
format=args[0],
|
|
122
|
+
description=description,
|
|
123
|
+
required=required,
|
|
124
|
+
default=default,
|
|
125
|
+
metadata=metadata,
|
|
126
|
+
)
|
|
127
|
+
raise TypeError('{} is not a supported type'.format(o))
|
|
128
|
+
if len(args) == 2:
|
|
129
|
+
if origin is Union:
|
|
130
|
+
if args[0] is type(None): # Union[type, None]
|
|
131
|
+
return self.__value__(
|
|
132
|
+
args[1],
|
|
133
|
+
description=description,
|
|
134
|
+
required=False,
|
|
135
|
+
default=None,
|
|
136
|
+
metadata=metadata,
|
|
137
|
+
)
|
|
138
|
+
if args[1] is type(None): # Union[None, type]
|
|
139
|
+
return self.__value__(
|
|
140
|
+
args[0],
|
|
141
|
+
description=description,
|
|
142
|
+
required=False,
|
|
143
|
+
default=None,
|
|
144
|
+
metadata=metadata,
|
|
145
|
+
)
|
|
146
|
+
# Union[type, type]
|
|
147
|
+
return self.__value__(
|
|
148
|
+
origin,
|
|
149
|
+
format=(args[0], args[1]),
|
|
150
|
+
description=description,
|
|
151
|
+
required=required,
|
|
152
|
+
default=default,
|
|
153
|
+
metadata=metadata,
|
|
154
|
+
)
|
|
155
|
+
if origin is dict: # Dict[type, type]
|
|
156
|
+
return self.__value__(
|
|
157
|
+
dict,
|
|
158
|
+
description=description,
|
|
159
|
+
required=required,
|
|
160
|
+
default=default,
|
|
161
|
+
metadata=metadata,
|
|
162
|
+
)
|
|
163
|
+
if origin is Annotated:
|
|
164
|
+
if isinstance(args[1], str):
|
|
165
|
+
return self.__value__(
|
|
166
|
+
args[0],
|
|
167
|
+
description=args[1],
|
|
168
|
+
required=required,
|
|
169
|
+
default=default,
|
|
170
|
+
)
|
|
171
|
+
return self.__value__(
|
|
172
|
+
args[0],
|
|
173
|
+
description=description,
|
|
174
|
+
required=required,
|
|
175
|
+
default=default,
|
|
176
|
+
metadata=args[1],
|
|
177
|
+
)
|
|
178
|
+
raise TypeError('{} is not a supported type'.format(o))
|
|
179
|
+
if origin is Union:
|
|
180
|
+
fs= [self.__value__(f) for f in args]
|
|
181
|
+
return OneOf(*fs, required=required)
|
|
182
|
+
if origin is Annotated:
|
|
183
|
+
if isinstance(args[1], str):
|
|
184
|
+
return self.__value__(
|
|
185
|
+
args[0],
|
|
186
|
+
description=args[1],
|
|
187
|
+
required=required,
|
|
188
|
+
default=default,
|
|
189
|
+
metadata=args[2] if isinstance(args[2], dict) else args[2:],
|
|
190
|
+
)
|
|
191
|
+
if isinstance(args[2], str):
|
|
192
|
+
return self.__value__(
|
|
193
|
+
args[0],
|
|
194
|
+
description=args[2],
|
|
195
|
+
required=required,
|
|
196
|
+
default=default,
|
|
197
|
+
metadata=args[1],
|
|
198
|
+
)
|
|
199
|
+
return self.__value__(
|
|
200
|
+
args[0],
|
|
201
|
+
description=description,
|
|
202
|
+
required=required,
|
|
203
|
+
default=default,
|
|
204
|
+
metadata=args[1:],
|
|
205
|
+
)
|
|
206
|
+
raise TypeError('{} is not a supported type'.format(o))
|
|
207
|
+
if o is bool:
|
|
208
|
+
kwargs: Dict[str, Any] = {
|
|
209
|
+
'description': description,
|
|
210
|
+
'required': required,
|
|
211
|
+
}
|
|
212
|
+
if default is not MISSING:
|
|
213
|
+
kwargs['default'] = default
|
|
214
|
+
if metadata and isinstance(metadata, dict):
|
|
215
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
216
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
217
|
+
return Boolean(**kwargs)
|
|
218
|
+
if o is int:
|
|
219
|
+
kwargs = {
|
|
220
|
+
'description': description,
|
|
221
|
+
'required': required,
|
|
222
|
+
}
|
|
223
|
+
if default is not MISSING:
|
|
224
|
+
kwargs['default'] = default
|
|
225
|
+
if metadata and isinstance(metadata, dict):
|
|
226
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
227
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
228
|
+
if 'format' in metadata.keys(): kwargs['format'] = metadata['format']
|
|
229
|
+
if 'min' in metadata.keys(): kwargs['min'] = metadata['min']
|
|
230
|
+
if 'max' in metadata.keys(): kwargs['max'] = metadata['max']
|
|
231
|
+
if 'enum' in metadata.keys(): kwargs['enum'] = metadata['enum']
|
|
232
|
+
return Integer(**kwargs)
|
|
233
|
+
if o is float:
|
|
234
|
+
kwargs = {
|
|
235
|
+
'description': description,
|
|
236
|
+
'required': required,
|
|
237
|
+
}
|
|
238
|
+
if default is not MISSING:
|
|
239
|
+
kwargs['default'] = default
|
|
240
|
+
if metadata and isinstance(metadata, dict):
|
|
241
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
242
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
243
|
+
if 'format' in metadata.keys(): kwargs['format'] = metadata['format']
|
|
244
|
+
if 'min' in metadata.keys(): kwargs['min'] = metadata['min']
|
|
245
|
+
if 'max' in metadata.keys(): kwargs['max'] = metadata['max']
|
|
246
|
+
if 'enum' in metadata.keys(): kwargs['enum'] = metadata['enum']
|
|
247
|
+
return Number(**kwargs)
|
|
248
|
+
if o is str:
|
|
249
|
+
kwargs = {
|
|
250
|
+
'description': description,
|
|
251
|
+
'required': required,
|
|
252
|
+
}
|
|
253
|
+
if default is not MISSING:
|
|
254
|
+
kwargs['default'] = default
|
|
255
|
+
if metadata and isinstance(metadata, dict):
|
|
256
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
257
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
258
|
+
if 'format' in metadata.keys(): kwargs['format'] = metadata['format']
|
|
259
|
+
if 'min' in metadata.keys(): kwargs['min'] = metadata['min']
|
|
260
|
+
if 'max' in metadata.keys(): kwargs['max'] = metadata['max']
|
|
261
|
+
if 'enum' in metadata.keys(): kwargs['enum'] = metadata['enum']
|
|
262
|
+
return String(**kwargs)
|
|
263
|
+
if o is bytes:
|
|
264
|
+
kwargs = {
|
|
265
|
+
'description': description,
|
|
266
|
+
'required': required,
|
|
267
|
+
}
|
|
268
|
+
if default is not MISSING:
|
|
269
|
+
kwargs['default'] = default
|
|
270
|
+
if metadata and isinstance(metadata, dict):
|
|
271
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
272
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
273
|
+
return Binary(**kwargs)
|
|
274
|
+
if o is list:
|
|
275
|
+
kwargs = {
|
|
276
|
+
'description': description,
|
|
277
|
+
'required': required,
|
|
278
|
+
}
|
|
279
|
+
if default is not MISSING:
|
|
280
|
+
kwargs['default'] = default
|
|
281
|
+
if metadata and isinstance(metadata, dict):
|
|
282
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
283
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
284
|
+
if format is None and 'format' in metadata:
|
|
285
|
+
format = metadata['format']
|
|
286
|
+
if format is not None:
|
|
287
|
+
candidates = tuple(format) if isinstance(format, Iterable) else (format,)
|
|
288
|
+
nodes = [self.__value__(candidate) for candidate in candidates]
|
|
289
|
+
kwargs['format'] = nodes[0] if len(nodes) == 1 else OneOf(*nodes)
|
|
290
|
+
return Array(**kwargs)
|
|
291
|
+
if o is tuple:
|
|
292
|
+
kwargs = {
|
|
293
|
+
'description': description,
|
|
294
|
+
'required': required,
|
|
295
|
+
}
|
|
296
|
+
if default is not MISSING:
|
|
297
|
+
kwargs['default'] = default
|
|
298
|
+
if metadata and isinstance(metadata, dict):
|
|
299
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
300
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
301
|
+
return Array(**kwargs)
|
|
302
|
+
if o is set:
|
|
303
|
+
kwargs = {
|
|
304
|
+
'description': description,
|
|
305
|
+
'required': required,
|
|
306
|
+
}
|
|
307
|
+
if default is not MISSING:
|
|
308
|
+
kwargs['default'] = default
|
|
309
|
+
if metadata and isinstance(metadata, dict):
|
|
310
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
311
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
312
|
+
return Array(**kwargs)
|
|
313
|
+
if o is dict:
|
|
314
|
+
kwargs = {
|
|
315
|
+
'description': description,
|
|
316
|
+
'required': required,
|
|
317
|
+
}
|
|
318
|
+
if default is not MISSING:
|
|
319
|
+
kwargs['default'] = default
|
|
320
|
+
if metadata and isinstance(metadata, dict):
|
|
321
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
322
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
323
|
+
return Object(**kwargs)
|
|
324
|
+
if o is Union:
|
|
325
|
+
kwargs = {}
|
|
326
|
+
if default is not MISSING:
|
|
327
|
+
kwargs['default'] = default
|
|
328
|
+
if not format:
|
|
329
|
+
raise TypeError('Union type must have format')
|
|
330
|
+
candidates = tuple(format) if isinstance(format, Iterable) else (format,)
|
|
331
|
+
return OneOf(*[self.__value__(f) for f in candidates], **kwargs)
|
|
332
|
+
if isinstance(o, type) and is_dataclass(o):
|
|
333
|
+
return self.__call__(o, required=required)
|
|
334
|
+
if isinstance(o, ForwardRef):
|
|
335
|
+
if o.__forward_arg__ in globals():
|
|
336
|
+
return self.__value__(globals()[o.__forward_arg__], description=description, required=required, default=default, metadata=metadata)
|
|
337
|
+
if o.__forward_arg__ in locals():
|
|
338
|
+
return self.__value__(locals()[o.__forward_arg__], description=description, required=required, default=default, metadata=metadata)
|
|
339
|
+
raise TypeError('Cannot resolve schema forward reference: ' + o.__forward_arg__)
|
|
340
|
+
if self.mapper and isinstance(o, type):
|
|
341
|
+
V, kws = self.mapper(o)
|
|
342
|
+
if V:
|
|
343
|
+
if not issubclass(V, Value):
|
|
344
|
+
raise TypeError('{} is not a Value'.format(V))
|
|
345
|
+
kwargs = {
|
|
346
|
+
'description': description,
|
|
347
|
+
'required': required,
|
|
348
|
+
}
|
|
349
|
+
if default is not MISSING:
|
|
350
|
+
kwargs['default'] = default
|
|
351
|
+
if metadata and isinstance(metadata, dict):
|
|
352
|
+
if 'description' in metadata.keys(): kwargs['description'] = metadata['description']
|
|
353
|
+
if 'required' in metadata.keys(): kwargs['required'] = metadata['required']
|
|
354
|
+
if V in (Integer, Number, String):
|
|
355
|
+
if 'format' in metadata.keys(): kwargs['format'] = metadata['format']
|
|
356
|
+
if 'min' in metadata.keys(): kwargs['min'] = metadata['min']
|
|
357
|
+
if 'max' in metadata.keys(): kwargs['max'] = metadata['max']
|
|
358
|
+
if 'enum' in metadata.keys(): kwargs['enum'] = metadata['enum']
|
|
359
|
+
kwargs.update(kws)
|
|
360
|
+
return V(**kwargs)
|
|
361
|
+
raise TypeError('{} is not a supported type'.format(o))
|
|
362
|
+
|
|
363
|
+
def __call__(
|
|
364
|
+
self,
|
|
365
|
+
o: Type[object],
|
|
366
|
+
description: Optional[str] = None,
|
|
367
|
+
required: bool = True,
|
|
368
|
+
) -> Schema:
|
|
369
|
+
if not is_dataclass(o):
|
|
370
|
+
raise TypeError('{} is not a DataObject(dataclass).'.format(o.__name__))
|
|
371
|
+
hints = get_type_hints(o, include_extras=True)
|
|
372
|
+
return Schema(
|
|
373
|
+
name=description or o.__name__,
|
|
374
|
+
format=Object(
|
|
375
|
+
description=description or o.__name__,
|
|
376
|
+
properties=Properties(
|
|
377
|
+
**{
|
|
378
|
+
f.name: self.__value__(
|
|
379
|
+
hints[f.name],
|
|
380
|
+
required=True if f.default is MISSING and f.default_factory is MISSING else False,
|
|
381
|
+
default=f.default_factory() if f.default_factory is not MISSING else f.default,
|
|
382
|
+
) for f in o.__dataclass_fields__.values()
|
|
383
|
+
}
|
|
384
|
+
),
|
|
385
|
+
required=required,
|
|
386
|
+
)
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
class DataObjectToObject(object):
|
|
391
|
+
def __init__(
|
|
392
|
+
self,
|
|
393
|
+
encoder: Optional[TypeEncoder] = None,
|
|
394
|
+
) -> None:
|
|
395
|
+
self.encoder = encoder
|
|
396
|
+
return
|
|
397
|
+
|
|
398
|
+
def __call__(
|
|
399
|
+
self,
|
|
400
|
+
o: object,
|
|
401
|
+
) -> Dict[str, Any]:
|
|
402
|
+
if not is_dataclass(o) or isinstance(o, type):
|
|
403
|
+
raise TypeError('{} is not a DataObject(dataclass) instance.'.format(type(o).__name__))
|
|
404
|
+
_ = dumps(
|
|
405
|
+
asdict(o),
|
|
406
|
+
default=self.encoder,
|
|
407
|
+
ensure_ascii=False,
|
|
408
|
+
)
|
|
409
|
+
return loads(_)
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .Value import (
|
|
4
|
+
Descriptor,
|
|
5
|
+
Type,
|
|
6
|
+
Value,
|
|
7
|
+
Condition,
|
|
8
|
+
Schema,
|
|
9
|
+
)
|
|
10
|
+
from typing import (
|
|
11
|
+
Optional,
|
|
12
|
+
Union,
|
|
13
|
+
Sequence,
|
|
14
|
+
Any,
|
|
15
|
+
Dict,
|
|
16
|
+
Iterable,
|
|
17
|
+
)
|
|
18
|
+
from enum import Enum
|
|
19
|
+
|
|
20
|
+
__all__ = (
|
|
21
|
+
'Boolean',
|
|
22
|
+
'IntegerFormat',
|
|
23
|
+
'Integer',
|
|
24
|
+
'NumberFormat',
|
|
25
|
+
'Number',
|
|
26
|
+
'StringFormat',
|
|
27
|
+
'String',
|
|
28
|
+
'Binary',
|
|
29
|
+
'BinaryBase64Encoded',
|
|
30
|
+
'Array',
|
|
31
|
+
'Object',
|
|
32
|
+
'Properties',
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Boolean(Value):
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
description: Optional[str] = None,
|
|
40
|
+
default: Any = None,
|
|
41
|
+
required: bool = True,
|
|
42
|
+
) -> None:
|
|
43
|
+
super().__init__(
|
|
44
|
+
type=Type.Boolean,
|
|
45
|
+
description=description,
|
|
46
|
+
default=default,
|
|
47
|
+
required=required,
|
|
48
|
+
)
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class IntegerFormat(str, Enum):
|
|
53
|
+
int32 = 'int32'
|
|
54
|
+
int64 = 'int64'
|
|
55
|
+
uint32 = 'uint32'
|
|
56
|
+
uint64 = 'uint64'
|
|
57
|
+
byte = 'byte'
|
|
58
|
+
uuid = 'uuid'
|
|
59
|
+
datetime = 'date-time'
|
|
60
|
+
def __str__(self): return self.value
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Integer(Value):
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
description: Optional[str] = None,
|
|
67
|
+
format: Optional[Union[str, IntegerFormat]] = None,
|
|
68
|
+
min: Any = None,
|
|
69
|
+
max: Any = None,
|
|
70
|
+
default: Any = None,
|
|
71
|
+
enum: Optional[Sequence[str]] = None,
|
|
72
|
+
required: bool = True,
|
|
73
|
+
) -> None:
|
|
74
|
+
super().__init__(
|
|
75
|
+
type=Type.Integer,
|
|
76
|
+
description=description,
|
|
77
|
+
format=str(format) if format and isinstance(format, IntegerFormat) else format,
|
|
78
|
+
min=min,
|
|
79
|
+
max=max,
|
|
80
|
+
default=default,
|
|
81
|
+
enum=enum,
|
|
82
|
+
required=required,
|
|
83
|
+
)
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class NumberFormat(str, Enum):
|
|
88
|
+
float = 'float'
|
|
89
|
+
double = 'double'
|
|
90
|
+
decimal = 'decimal'
|
|
91
|
+
def __str__(self): return self.value
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Number(Value):
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
description: Optional[str] = None,
|
|
98
|
+
format: Optional[Union[str, NumberFormat]] = None,
|
|
99
|
+
min: Any = None,
|
|
100
|
+
max: Any = None,
|
|
101
|
+
default: Any = None,
|
|
102
|
+
enum: Optional[Sequence[str]] = None,
|
|
103
|
+
required: bool = True,
|
|
104
|
+
) -> None:
|
|
105
|
+
super().__init__(
|
|
106
|
+
type=Type.Number,
|
|
107
|
+
description=description,
|
|
108
|
+
format=str(format) if format and isinstance(format, NumberFormat) else format,
|
|
109
|
+
min=min,
|
|
110
|
+
max=max,
|
|
111
|
+
default=default,
|
|
112
|
+
enum=enum,
|
|
113
|
+
required=required,
|
|
114
|
+
)
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class StringFormat(str, Enum):
|
|
119
|
+
datetime = 'date-time' # date-time, ISO 8601
|
|
120
|
+
date = 'date' # date, ISO 8601
|
|
121
|
+
time = 'time' # time, ISO 8601
|
|
122
|
+
password = 'password' # password
|
|
123
|
+
byte = 'byte' # byte, base64 encoded
|
|
124
|
+
binary = 'binary' # binary
|
|
125
|
+
email = 'email' # email
|
|
126
|
+
uuid = 'uuid' # uuid
|
|
127
|
+
uri = 'uri' # uri
|
|
128
|
+
hostname = 'hostname' # hostname
|
|
129
|
+
ipv4 = 'ipv4' # ipv4
|
|
130
|
+
ipv6 = 'ipv6' # ipv6
|
|
131
|
+
regex = 'regex' # regex
|
|
132
|
+
xml = 'xml' # xml
|
|
133
|
+
def __str__(self): return self.value
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class String(Value):
|
|
137
|
+
def __init__(
|
|
138
|
+
self,
|
|
139
|
+
description: Optional[str] = None,
|
|
140
|
+
format: Optional[Union[str, StringFormat]] = None,
|
|
141
|
+
min: Any = None,
|
|
142
|
+
max: Any = None,
|
|
143
|
+
default: Any = None,
|
|
144
|
+
enum: Optional[Sequence[str]] = None,
|
|
145
|
+
required: bool = True,
|
|
146
|
+
) -> None:
|
|
147
|
+
super().__init__(
|
|
148
|
+
type=Type.String,
|
|
149
|
+
description=description,
|
|
150
|
+
format=str(format) if format and isinstance(format, StringFormat) else format,
|
|
151
|
+
min=min,
|
|
152
|
+
max=max,
|
|
153
|
+
default=default,
|
|
154
|
+
enum=enum,
|
|
155
|
+
required=required,
|
|
156
|
+
)
|
|
157
|
+
if min is not None:
|
|
158
|
+
del self['minimum']
|
|
159
|
+
self['minLength'] = min
|
|
160
|
+
if max is not None:
|
|
161
|
+
del self['maximum']
|
|
162
|
+
self['maxLength'] = max
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class BinaryBase64Encoded(String):
|
|
167
|
+
def __init__(
|
|
168
|
+
self,
|
|
169
|
+
description: Optional[str] = None,
|
|
170
|
+
default: Optional[str] = None,
|
|
171
|
+
required: bool = True,
|
|
172
|
+
) -> None:
|
|
173
|
+
super().__init__(
|
|
174
|
+
description=description,
|
|
175
|
+
format=StringFormat.byte,
|
|
176
|
+
default=default,
|
|
177
|
+
required=required,
|
|
178
|
+
)
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class Binary(String):
|
|
183
|
+
def __init__(
|
|
184
|
+
self,
|
|
185
|
+
description: Optional[str] = None,
|
|
186
|
+
default: Optional[bytes] = None,
|
|
187
|
+
required: bool = True,
|
|
188
|
+
) -> None:
|
|
189
|
+
super().__init__(
|
|
190
|
+
description=description,
|
|
191
|
+
format=StringFormat.binary,
|
|
192
|
+
default=default,
|
|
193
|
+
required=required,
|
|
194
|
+
)
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class Properties(Descriptor):
|
|
199
|
+
def __init__(
|
|
200
|
+
self,
|
|
201
|
+
**kwargs: Union[Descriptor, Condition, Schema],
|
|
202
|
+
) -> None:
|
|
203
|
+
super().__init__(**{
|
|
204
|
+
k: v.format if isinstance(v, Schema) else v
|
|
205
|
+
for k, v in kwargs.items()
|
|
206
|
+
})
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class Object(Descriptor):
|
|
211
|
+
def __init__(
|
|
212
|
+
self,
|
|
213
|
+
description: Optional[str] = None,
|
|
214
|
+
properties: Optional[Properties] = None,
|
|
215
|
+
default: Optional[Dict[str, Any]] = None,
|
|
216
|
+
required: bool = True,
|
|
217
|
+
) -> None:
|
|
218
|
+
properties = properties if properties is not None else Properties()
|
|
219
|
+
super().__init__(
|
|
220
|
+
type=Type.Object,
|
|
221
|
+
properties=properties,
|
|
222
|
+
)
|
|
223
|
+
if description: self['description'] = description
|
|
224
|
+
self['required'] = []
|
|
225
|
+
for k, v in properties.items():
|
|
226
|
+
if hasattr(v, 'required') and getattr(v, 'required'):
|
|
227
|
+
self['required'].append(k)
|
|
228
|
+
if default is not None: self['default'] = default
|
|
229
|
+
self.required = required
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class Array(Descriptor):
|
|
234
|
+
def __init__(
|
|
235
|
+
self,
|
|
236
|
+
description: Optional[str] = None,
|
|
237
|
+
format: Optional[Union[Descriptor, Condition, Schema]] = None,
|
|
238
|
+
default: Optional[Iterable[Any]] = None,
|
|
239
|
+
required: bool = True,
|
|
240
|
+
) -> None:
|
|
241
|
+
super().__init__(
|
|
242
|
+
type=Type.Array,
|
|
243
|
+
)
|
|
244
|
+
if description: self['description'] = description
|
|
245
|
+
if format: self['items'] = format.format if isinstance(format, Schema) else format
|
|
246
|
+
if default is not None: self['default'] = default
|
|
247
|
+
self.required = required
|
|
248
|
+
return
|