DefEssential 0.1.8__23-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 +82 -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,30 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .Pattern import Pattern
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'Validator',
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Validator(object):
|
|
11
|
+
"""
|
|
12
|
+
Validator Class
|
|
13
|
+
"""
|
|
14
|
+
def __init__(self, *args):
|
|
15
|
+
for pattern in args:
|
|
16
|
+
if not isinstance(pattern, Pattern):
|
|
17
|
+
raise RuntimeError('{} must be based {}'.format(pattern, Pattern))
|
|
18
|
+
self.patterns = args
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
def __call__(self, parameter):
|
|
22
|
+
for pattern in self.patterns:
|
|
23
|
+
parameter = pattern(parameter)
|
|
24
|
+
return parameter
|
|
25
|
+
|
|
26
|
+
def __repr__(self):
|
|
27
|
+
return 'Validator({})'.format(
|
|
28
|
+
', '.join([repr(p) for p in self.patterns])
|
|
29
|
+
)
|
|
30
|
+
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
from abc import (
|
|
2
|
+
ABC,
|
|
3
|
+
abstractmethod,
|
|
4
|
+
)
|
|
5
|
+
from typing import (
|
|
6
|
+
Any,
|
|
7
|
+
Mapping,
|
|
8
|
+
Optional,
|
|
9
|
+
Sequence,
|
|
10
|
+
Union,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .Error import (
|
|
14
|
+
ClientError,
|
|
15
|
+
Error,
|
|
16
|
+
)
|
|
17
|
+
from .Request import Request
|
|
18
|
+
from .Validator import (
|
|
19
|
+
Pattern,
|
|
20
|
+
Validator,
|
|
21
|
+
)
|
|
22
|
+
from .Validator.Patterns.Object import (
|
|
23
|
+
IsMappingOf,
|
|
24
|
+
IsRequiredIn,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = (
|
|
28
|
+
'RequestValidator',
|
|
29
|
+
'Origin',
|
|
30
|
+
'Credentials',
|
|
31
|
+
'Authorization',
|
|
32
|
+
'Auth',
|
|
33
|
+
'Parameters',
|
|
34
|
+
'QueryString',
|
|
35
|
+
'Headers',
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class RequestValidator(ABC):
|
|
40
|
+
"""Define the interface for HTTP request validators."""
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def __call__(
|
|
44
|
+
self,
|
|
45
|
+
request: Request,
|
|
46
|
+
) -> None:
|
|
47
|
+
raise NotImplementedError
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Origin(RequestValidator):
|
|
51
|
+
"""Allow only configured origins and provide the CORS response policy."""
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
origin: Union[str, Sequence[str], None] = None,
|
|
56
|
+
all: bool = False,
|
|
57
|
+
error: Optional[Error] = None,
|
|
58
|
+
):
|
|
59
|
+
self.matches = tuple(origin) if origin is not None and not isinstance(origin, str) else (
|
|
60
|
+
(origin,) if origin is not None else ()
|
|
61
|
+
)
|
|
62
|
+
self.all = all
|
|
63
|
+
self.error = error
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
def allows(
|
|
67
|
+
self,
|
|
68
|
+
origin: Optional[str],
|
|
69
|
+
) -> bool:
|
|
70
|
+
return self.all or origin in self.matches
|
|
71
|
+
|
|
72
|
+
def __call__(
|
|
73
|
+
self,
|
|
74
|
+
request: Request,
|
|
75
|
+
) -> None:
|
|
76
|
+
if not self.allows(request.header('Origin')):
|
|
77
|
+
raise self.error if self.error is not None else ClientError(
|
|
78
|
+
'Origin not allowed',
|
|
79
|
+
status=403,
|
|
80
|
+
)
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class Credentials(ABC):
|
|
85
|
+
"""Define credential extraction and documentation metadata."""
|
|
86
|
+
|
|
87
|
+
@abstractmethod
|
|
88
|
+
def __call__(
|
|
89
|
+
self,
|
|
90
|
+
request: Request,
|
|
91
|
+
) -> Any:
|
|
92
|
+
raise NotImplementedError
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
@abstractmethod
|
|
96
|
+
def name(self) -> str:
|
|
97
|
+
raise NotImplementedError
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def format(self) -> dict:
|
|
102
|
+
raise NotImplementedError
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def headers(self) -> Sequence[str]:
|
|
106
|
+
return ()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class Authorization(ABC):
|
|
110
|
+
"""Define validation of extracted credentials and conversion to sessions."""
|
|
111
|
+
|
|
112
|
+
@abstractmethod
|
|
113
|
+
def __call__(
|
|
114
|
+
self,
|
|
115
|
+
credentials: Any,
|
|
116
|
+
) -> Any:
|
|
117
|
+
raise NotImplementedError
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class Auth(RequestValidator):
|
|
121
|
+
"""Perform required or optional authentication and attach a session to the request."""
|
|
122
|
+
|
|
123
|
+
def __init__(
|
|
124
|
+
self,
|
|
125
|
+
auth: Authorization,
|
|
126
|
+
credentials: Credentials,
|
|
127
|
+
optional: bool = False,
|
|
128
|
+
error: Optional[Error] = None,
|
|
129
|
+
):
|
|
130
|
+
self.auth = auth
|
|
131
|
+
self.credentials = credentials
|
|
132
|
+
self.optional = optional
|
|
133
|
+
self.error = error
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
def __call__(
|
|
137
|
+
self,
|
|
138
|
+
request: Request,
|
|
139
|
+
) -> None:
|
|
140
|
+
try:
|
|
141
|
+
credentials = self.credentials(request)
|
|
142
|
+
if credentials is None or credentials == '':
|
|
143
|
+
if self.optional:
|
|
144
|
+
return
|
|
145
|
+
raise ClientError(
|
|
146
|
+
'Missing credentials',
|
|
147
|
+
status=401,
|
|
148
|
+
)
|
|
149
|
+
request.session = self.auth(credentials)
|
|
150
|
+
except ClientError as error:
|
|
151
|
+
if self.error is not None:
|
|
152
|
+
raise self.error from error
|
|
153
|
+
raise
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class Parameters(RequestValidator):
|
|
158
|
+
"""Validate and convert mapped path parameters and retain their schemas."""
|
|
159
|
+
|
|
160
|
+
def __init__(
|
|
161
|
+
self,
|
|
162
|
+
parameters: Mapping[str, Union[Pattern, Validator, Sequence[Pattern]]],
|
|
163
|
+
format: Optional[Mapping[str, object]] = None,
|
|
164
|
+
):
|
|
165
|
+
self.va = Validator(IsMappingOf(dict(parameters)))
|
|
166
|
+
self.keys = tuple(parameters)
|
|
167
|
+
self.format = format
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
def validate(
|
|
171
|
+
self,
|
|
172
|
+
values: dict,
|
|
173
|
+
) -> dict:
|
|
174
|
+
try:
|
|
175
|
+
return self.va(dict(values))
|
|
176
|
+
except (ValueError, TypeError) as error:
|
|
177
|
+
raise ClientError(str(error)) from error
|
|
178
|
+
|
|
179
|
+
def __call__(
|
|
180
|
+
self,
|
|
181
|
+
request: Request,
|
|
182
|
+
) -> None:
|
|
183
|
+
request.params = self.validate(request.params)
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class QueryString(Parameters):
|
|
188
|
+
"""Enforce required query keys and validate their values."""
|
|
189
|
+
|
|
190
|
+
def __init__(
|
|
191
|
+
self,
|
|
192
|
+
qs: Mapping[str, Union[Pattern, Validator, Sequence[Pattern]]],
|
|
193
|
+
requires: Union[str, Sequence[str], None] = None,
|
|
194
|
+
requiresError: Optional[Error] = None,
|
|
195
|
+
format: Optional[Mapping[str, object]] = None,
|
|
196
|
+
):
|
|
197
|
+
super().__init__(
|
|
198
|
+
qs,
|
|
199
|
+
format=format,
|
|
200
|
+
)
|
|
201
|
+
keys = (requires,) if isinstance(requires, str) else tuple(requires or ())
|
|
202
|
+
self.required_keys = keys
|
|
203
|
+
self.va = Validator(
|
|
204
|
+
IsRequiredIn(
|
|
205
|
+
*keys,
|
|
206
|
+
error=requiresError,
|
|
207
|
+
),
|
|
208
|
+
IsMappingOf(dict(qs)),
|
|
209
|
+
)
|
|
210
|
+
return
|
|
211
|
+
|
|
212
|
+
def __call__(
|
|
213
|
+
self,
|
|
214
|
+
request: Request,
|
|
215
|
+
) -> None:
|
|
216
|
+
request.args = self.validate(request.args)
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class Headers(QueryString):
|
|
221
|
+
"""Validate request headers case-insensitively."""
|
|
222
|
+
|
|
223
|
+
def __init__(
|
|
224
|
+
self,
|
|
225
|
+
headers: Mapping[str, Union[Pattern, Validator, Sequence[Pattern]]],
|
|
226
|
+
requires: Union[str, Sequence[str], None] = None,
|
|
227
|
+
requiresError: Optional[Error] = None,
|
|
228
|
+
format: Optional[Mapping[str, object]] = None,
|
|
229
|
+
):
|
|
230
|
+
required = (requires,) if isinstance(requires, str) else tuple(requires or ())
|
|
231
|
+
super().__init__(
|
|
232
|
+
{key.lower(): value for key, value in headers.items()},
|
|
233
|
+
requires=tuple(key.lower() for key in required),
|
|
234
|
+
requiresError=requiresError,
|
|
235
|
+
format=format,
|
|
236
|
+
)
|
|
237
|
+
self.headers = tuple(headers)
|
|
238
|
+
self.keys = tuple(headers)
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
def __call__(
|
|
242
|
+
self,
|
|
243
|
+
request: Request,
|
|
244
|
+
) -> None:
|
|
245
|
+
values = self.validate({
|
|
246
|
+
key.lower(): value for key, value in request.headers()
|
|
247
|
+
})
|
|
248
|
+
for key in self.headers:
|
|
249
|
+
value = values[key.lower()]
|
|
250
|
+
if value is not None:
|
|
251
|
+
request.header(
|
|
252
|
+
key,
|
|
253
|
+
str(value),
|
|
254
|
+
)
|
|
255
|
+
return
|
DefEssential/__init__.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from .Application import (
|
|
2
|
+
Application,
|
|
3
|
+
ApplicationStartup,
|
|
4
|
+
ApplicationCleanup,
|
|
5
|
+
ApplicationRequest,
|
|
6
|
+
ApplicationRequestResponse,
|
|
7
|
+
ApplicationRequestError,
|
|
8
|
+
RequestHookRegistration,
|
|
9
|
+
)
|
|
10
|
+
from .Extension import (
|
|
11
|
+
Extension,
|
|
12
|
+
ExtensionStartup,
|
|
13
|
+
ExtensionCleanup,
|
|
14
|
+
ExtensionRequest,
|
|
15
|
+
ExtensionRequestResponse,
|
|
16
|
+
ExtensionRequestError,
|
|
17
|
+
)
|
|
18
|
+
from .Route import Route
|
|
19
|
+
from .Error import (
|
|
20
|
+
Error,
|
|
21
|
+
ClientError,
|
|
22
|
+
ServerError,
|
|
23
|
+
)
|
|
24
|
+
from .Body import Body
|
|
25
|
+
from .Content import Content
|
|
26
|
+
from .Validators import (
|
|
27
|
+
Origin,
|
|
28
|
+
Authorization,
|
|
29
|
+
Auth,
|
|
30
|
+
Parameters,
|
|
31
|
+
QueryString,
|
|
32
|
+
Headers,
|
|
33
|
+
RequestValidator,
|
|
34
|
+
)
|
|
35
|
+
from .RequestRunner import (
|
|
36
|
+
RequestRunner,
|
|
37
|
+
RequestRunnerRequest,
|
|
38
|
+
RequestRunnerRequestResponse,
|
|
39
|
+
RequestRunnerRequestError,
|
|
40
|
+
)
|
|
41
|
+
from .Request import Request
|
|
42
|
+
from .IO.RequestReader import RequestReader
|
|
43
|
+
from .Response import Response
|
|
44
|
+
from .ResponseSpecification import ResponseSpecification
|
|
45
|
+
from .IO.ResponseWriter import ResponseWriter
|
|
46
|
+
|
|
47
|
+
__all__ = (
|
|
48
|
+
'Application',
|
|
49
|
+
'ApplicationStartup',
|
|
50
|
+
'ApplicationCleanup',
|
|
51
|
+
'ApplicationRequest',
|
|
52
|
+
'ApplicationRequestResponse',
|
|
53
|
+
'ApplicationRequestError',
|
|
54
|
+
'RequestHookRegistration',
|
|
55
|
+
'Extension',
|
|
56
|
+
'ExtensionStartup',
|
|
57
|
+
'ExtensionCleanup',
|
|
58
|
+
'ExtensionRequest',
|
|
59
|
+
'ExtensionRequestResponse',
|
|
60
|
+
'ExtensionRequestError',
|
|
61
|
+
'Route',
|
|
62
|
+
'Error',
|
|
63
|
+
'ClientError',
|
|
64
|
+
'ServerError',
|
|
65
|
+
'RequestRunner',
|
|
66
|
+
'RequestRunnerRequest',
|
|
67
|
+
'RequestRunnerRequestResponse',
|
|
68
|
+
'RequestRunnerRequestError',
|
|
69
|
+
'Body',
|
|
70
|
+
'Content',
|
|
71
|
+
'Origin',
|
|
72
|
+
'Authorization',
|
|
73
|
+
'Auth',
|
|
74
|
+
'Parameters',
|
|
75
|
+
'QueryString',
|
|
76
|
+
'Headers',
|
|
77
|
+
'RequestValidator',
|
|
78
|
+
'Request',
|
|
79
|
+
'RequestReader',
|
|
80
|
+
'Response',
|
|
81
|
+
'ResponseSpecification',
|
|
82
|
+
'ResponseWriter',
|
|
83
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: DefEssential
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: The Modern Synchronous Python Web Application Framework
|
|
5
|
+
Home-page: https://github.com/yong5eon/DefEssential
|
|
6
|
+
Author: Heo Yongseon
|
|
7
|
+
Project-URL: Source, https://github.com/yong5eon/DefEssential
|
|
8
|
+
Project-URL: Issues, https://github.com/yong5eon/DefEssential/issues
|
|
9
|
+
Project-URL: Releases, https://github.com/yong5eon/DefEssential/releases
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Provides-Extra: gunicorn
|
|
20
|
+
Requires-Dist: gunicorn>=23; extra == "gunicorn"
|
|
21
|
+
Provides-Extra: uvicorn
|
|
22
|
+
Requires-Dist: uvicorn>=0.30; extra == "uvicorn"
|
|
23
|
+
Requires-Dist: a2wsgi>=1.10; extra == "uvicorn"
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
Dynamic: project-url
|
|
31
|
+
Dynamic: provides-extra
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
Dynamic: summary
|
|
34
|
+
|
|
35
|
+
# DefEssential
|
|
36
|
+
|
|
37
|
+
DefEssential is a synchronous Python web application framework for handling HTTP requests with ordinary Python methods. It provides route declarations, request validation, response helpers, streaming APIs, lifecycle hooks, and optional extensions without requiring `async` / `await`.
|
|
38
|
+
|
|
39
|
+
## Requirements
|
|
40
|
+
|
|
41
|
+
- Python 3.9 or later
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install DefEssential
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The package includes a built-in Python HTTP server. Optional extras provide additional server adapters:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install "DefEssential[Gunicorn]"
|
|
53
|
+
pip install "DefEssential[Uvicorn]"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from DefEssential import Application, Request, RequestRunner
|
|
60
|
+
from DefEssential.Adapter.Implements.Python import Server
|
|
61
|
+
from DefEssential.Responses import ResponseText
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Hello(RequestRunner, method='GET', url='/hello'):
|
|
65
|
+
def run(self, request: Request):
|
|
66
|
+
return ResponseText('Hello, world!')
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
application = Application()
|
|
70
|
+
application.add(Hello)
|
|
71
|
+
Server('127.0.0.1', 8000, application).run()
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The handler declares an HTTP method and path on its `RequestRunner` class. The application registers the handler, and the server runs the application. A `GET /hello` request returns a plain-text response.
|
|
75
|
+
|
|
76
|
+
## Request handling
|
|
77
|
+
|
|
78
|
+
Define handlers as `RequestRunner` subclasses and implement `run()` with synchronous Python code. Configure path, query, header, and body validation in the class declaration. The framework also provides JSON, text, and file responses, direct streaming, Server-Sent Events, WebSocket support, and extensions for status checks, metrics, OpenAPI specifications, Swagger UI, and file serving.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
See the `LICENSE` file included with the source distribution for license terms.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
DefEssential/Application.py,sha256=j9OVCGwenS65aQdcVgoCHeUwfWZLhtZfrNrBlejGCIk,21177
|
|
2
|
+
DefEssential/Body.py,sha256=bJCPKPCGu-68oNwdqlIa2UFDRwvXt50blFiGm2QRAZk,1087
|
|
3
|
+
DefEssential/Content.py,sha256=3f7zqIB11_ryKtwyZnu7GfNbFs4NPgYmc90U2GCfEr0,282
|
|
4
|
+
DefEssential/Credentials.py,sha256=YLJWuPmbazIo6UmzcTQv5hWVV8XmuLIEqqdtknHhwao,4754
|
|
5
|
+
DefEssential/CrossOriginResourceSharing.py,sha256=Jn2MeyCvthKegqg9KXPUbGmjivW1tUr8kmwCARjcmAU,2712
|
|
6
|
+
DefEssential/Error.py,sha256=Av7VSEPO5PS3eYCNfJ2UAGVeaOYcpYzcY14SFE0W2X4,1220
|
|
7
|
+
DefEssential/Extension.py,sha256=b25jq9RXLsm32cawlw7Bm9-QACzGqNaKNhbkbfHgyes,4247
|
|
8
|
+
DefEssential/Request.py,sha256=ie1HlKs-RyELzZdCaPwG_CL-f5F6QhBLfF_qOBR15oE,2623
|
|
9
|
+
DefEssential/RequestRunner.py,sha256=UE07_y3LngXFnI5lmc7Cob0rJpl_o4EirZX8OQvPqF0,6450
|
|
10
|
+
DefEssential/Response.py,sha256=rLV_qtmaYmQS6SHgbBziMWG5qkiOGUTgqa_TBhuIpxo,2045
|
|
11
|
+
DefEssential/ResponseSpecification.py,sha256=6bgZgcOiprokpaaT5TDZO_tS0HTlmkxBbwE4DQWxe6s,433
|
|
12
|
+
DefEssential/Route.py,sha256=u4UHBcZFtlpuWW2I_R8UXA0XG6Ur9GXH6Xt9azUxEU0,1039
|
|
13
|
+
DefEssential/Router.py,sha256=t4jRf0IPTxq9GAlxgnoy-TzVLuDKdGBXJZTcvzTMme4,949
|
|
14
|
+
DefEssential/Startup.py,sha256=0FUY7oOk3sXCBoqlhCEEMTFX5F2bgrrBD6Qpprot6sI,3121
|
|
15
|
+
DefEssential/Validators.py,sha256=p8fuh83hyJJJ4hp3a-Zcgp7YOfeD14XMlt-MAM6e9TA,5131
|
|
16
|
+
DefEssential/__init__.py,sha256=OwzZwjP-9GXXjn9Usq-iwTUhH-MP5kQi2SoETRUW_74,1610
|
|
17
|
+
DefEssential/Adapter/RequestHandler.py,sha256=B9ath5tVTbMQ5CJcYtkrL1AU4sMLzBOL6r29TPMSKTs,3062
|
|
18
|
+
DefEssential/Adapter/Server.py,sha256=TWj0c8fdKFH5nnNzYjHJ-pniNKHc1kcsLqHS7RXPNc0,1022
|
|
19
|
+
DefEssential/Adapter/WSGI.py,sha256=9kqWrvsr2FIZPLmLwh9AROXN9NTBGWv4UjkbG0GYOik,4559
|
|
20
|
+
DefEssential/Adapter/__init__.py,sha256=dVJzU5IXkiBrmp-iIIkvfXONhNuDDZGF9aoQiRATVaY,53
|
|
21
|
+
DefEssential/Adapter/Implements/__init__.py,sha256=s4lctNY1D4g5HlfQyer_zmPMVzFCSH6TtqOD4wQKbvM,98
|
|
22
|
+
DefEssential/Adapter/Implements/Gunicorn/Server.py,sha256=uHpiVCkVly62ziQXyN2yUcLGF823tHhmGwW8E-bJ__A,3408
|
|
23
|
+
DefEssential/Adapter/Implements/Gunicorn/Transport.py,sha256=kPJzF6MPAi0_hz-W6FbXImx9teIBFGZ63McuMDVNJCk,3255
|
|
24
|
+
DefEssential/Adapter/Implements/Gunicorn/__init__.py,sha256=dVJzU5IXkiBrmp-iIIkvfXONhNuDDZGF9aoQiRATVaY,53
|
|
25
|
+
DefEssential/Adapter/Implements/Python/Server.py,sha256=gM-yvyVLwPd7Wb_do0nMDbmNZPLV10Rn59FJ5NN2e3w,6211
|
|
26
|
+
DefEssential/Adapter/Implements/Python/__init__.py,sha256=dVJzU5IXkiBrmp-iIIkvfXONhNuDDZGF9aoQiRATVaY,53
|
|
27
|
+
DefEssential/Adapter/Implements/Uvicorn/HTTP.py,sha256=qQcZ2Pq41XBW48Jnws-7G6R4PJDhbbNEj8_cJZrfzII,5571
|
|
28
|
+
DefEssential/Adapter/Implements/Uvicorn/Portal.py,sha256=YcTsoUZm8rRl3te0GBbVRpMkSsyndOlx9FfPI4ObBU4,1205
|
|
29
|
+
DefEssential/Adapter/Implements/Uvicorn/Server.py,sha256=aVliEyTS972wQ43tu_nrw8Ca4gP5Ptd4hQ9A6KrOL10,3320
|
|
30
|
+
DefEssential/Adapter/Implements/Uvicorn/WebSocket.py,sha256=u0lel1GRisoOmvnJDmLDQF7mkYd8YVqcRaq74x9Q2mw,4652
|
|
31
|
+
DefEssential/Adapter/Implements/Uvicorn/__init__.py,sha256=dVJzU5IXkiBrmp-iIIkvfXONhNuDDZGF9aoQiRATVaY,53
|
|
32
|
+
DefEssential/Descriptor/DataObject.py,sha256=rrvi5oWYIwZqO4GBcbT9uKRLMcB7Ms8XOYk7LgOa16g,12007
|
|
33
|
+
DefEssential/Descriptor/Types.py,sha256=tnC9ZjsCx8e_zK5pXjJymx-UxRJNQPBPMxrfMyG2fIE,5112
|
|
34
|
+
DefEssential/Descriptor/Value.py,sha256=LDVPITos6yalKr_h-8akt6IiRajCzhjvOsT48GXpWwU,3515
|
|
35
|
+
DefEssential/Descriptor/__init__.py,sha256=xu_dDulMEItY6d7OjMZptsBb9_zdH--rqPTTnkz8ZGg,2544
|
|
36
|
+
DefEssential/Extensions/File.py,sha256=AjBh4LkRH4ccaRTWfBbLP1gV3thwbMwLvoHzgoIxqDg,2034
|
|
37
|
+
DefEssential/Extensions/FileSystem.py,sha256=WVRVsr13kmVpXTArrx_jPR6sjlifgrRC3RHNBd88ir0,4265
|
|
38
|
+
DefEssential/Extensions/Metrics.py,sha256=sCgBYkt5n5Y21fhL3KYgogOQtKENxXH_UfsvQsIy-XE,14281
|
|
39
|
+
DefEssential/Extensions/Ping.py,sha256=uLrmYgcQ5XKzO3JIDFHQ6usbOiyur0Vpv4QQioD1-kg,2030
|
|
40
|
+
DefEssential/Extensions/Specifications.py,sha256=eQ-NAFgvt36JbHZpt29AGJ0DESpBOfA1pgSsfE3ax1s,10243
|
|
41
|
+
DefEssential/Extensions/Status.html,sha256=o5IQVPG5VcFRwFYxEp5oAG67KTVw--rTwDGmqfNWosw,13488
|
|
42
|
+
DefEssential/Extensions/Status.py,sha256=SiN4Muil4GJewMnMFIL0CROOhGviVYcEvVkyRkg3nF8,2707
|
|
43
|
+
DefEssential/Extensions/Swagger.html,sha256=pkTUGU1ZY0qgpqHWq8CZiiIqWys2T643yi-w9KjsGMo,3508
|
|
44
|
+
DefEssential/Extensions/Swagger.py,sha256=lAT4U0KrDq3XUMV_nJrXes6hfJVEcUtjb5-fpley6pk,3043
|
|
45
|
+
DefEssential/Extensions/__init__.py,sha256=9shY7BPkhgbBVEWxmZLLFlAwHbnTYwd9aKPd8w_4cy4,357
|
|
46
|
+
DefEssential/Extensions/Utils/Routes.py,sha256=agAtkAn8TmPYzIDk-3PEEGxfqoeCrM4zGU8AVT5Ajlc,737
|
|
47
|
+
DefEssential/Extensions/Utils/__init__.py,sha256=h6ZnQMKHrNZEkX2fI27AiX7ldIP9fhCMqwQRT1OBqYE,1136
|
|
48
|
+
DefEssential/IO/RequestReader.py,sha256=bxyNhoHsJLueUjqCts4Ri6gdOQ2GWQoTde1iTkMeJBE,2810
|
|
49
|
+
DefEssential/IO/ResponseWriter.py,sha256=dmiUDwVpNMnPMl3TfEdAzJRzP0DNfbyx-f0JhnqhEAI,5732
|
|
50
|
+
DefEssential/IO/__init__.py,sha256=WxmYTA0lHfGYIyhsLG7I3cTztI96LH-xXxQgnb34NBg,136
|
|
51
|
+
DefEssential/IO/Readers/ChunkedStream.py,sha256=1BT40NiDWlEizVyGIUIVadiH-FkJHcMwf8uJ0UJeUEQ,2539
|
|
52
|
+
DefEssential/IO/Readers/ContentReader.py,sha256=Bhjug30AmX-IPUekwntmJsP6nqvyuO1en0xNhjKr2H4,575
|
|
53
|
+
DefEssential/IO/Readers/ContentReaders.py,sha256=z8tVMNk_kyGBFFTVCARn0Fg51XzD5d7bOXVrabSGmCc,5041
|
|
54
|
+
DefEssential/IO/Readers/__init__.py,sha256=w7nkWpHk42IbSz6W52WZGmSg7kQVXjxRVajGR4c5agk,545
|
|
55
|
+
DefEssential/IO/WebSocket/WebSocket.py,sha256=kIr37HeAPqsVcEwS9z37Q6wYTcch_3s34PQ4kZx9ZME,6584
|
|
56
|
+
DefEssential/IO/WebSocket/WebSocketError.py,sha256=PHyrdcwPYGdPU3uhxCFWieEMX_Irx7WZok6NukmEMX8,276
|
|
57
|
+
DefEssential/IO/WebSocket/WebSocketFrame.py,sha256=8Y5mnBQ14CrWktwzFlqc1oHbA7PdDNLGYvPQQ69YWuE,1165
|
|
58
|
+
DefEssential/IO/WebSocket/WebSocketFrameReader.py,sha256=HBWMzNgImTtEuL_p8cgK7Bo3mH6v2ZaJRdwz8FNKSQ8,2066
|
|
59
|
+
DefEssential/IO/WebSocket/WebSocketHandshake.py,sha256=WV0OnTWJCreYqLyM9bkXrhlDKCoFwNFEc8atxFYCZ2Q,2542
|
|
60
|
+
DefEssential/IO/WebSocket/__init__.py,sha256=BOplQIjz-H1tKLR4xlqsVUY18HAILjAhoa1IW6h6YUY,340
|
|
61
|
+
DefEssential/IO/Writers/ChunkedStreamWriter.py,sha256=vJQJcuHl4-y8RuTa9VQ6Pa5NEDRJtXjHtx-fDCvPvdk,283
|
|
62
|
+
DefEssential/IO/Writers/ServerSentEvents.py,sha256=ZWm6CfZyJnFqZlBljkHIIYU5y-bTJGz185njiLScfUA,1201
|
|
63
|
+
DefEssential/IO/Writers/ServerSentEventsWriter.py,sha256=IID_7DVcTPixrFLSYFUd6bHqscVb4ngHBNGupzcaAIQ,1363
|
|
64
|
+
DefEssential/IO/Writers/StreamWriter.py,sha256=BFM6thO53xUuwEhODu_EhPMazBchBABsTnWtqCQNr6A,863
|
|
65
|
+
DefEssential/IO/Writers/__init__.py,sha256=lc2ApKxe70aqk_mymaVC9BY2GF_XmFMMBVwQaFh3jt0,302
|
|
66
|
+
DefEssential/Responses/ResponseFile.py,sha256=ivMZZAH3agNQeM2DtjmNf7VNgAiRewO6qH8awxxR2yk,1907
|
|
67
|
+
DefEssential/Responses/__init__.py,sha256=GqaT7rhRvoO8GNqfkK08L7J15qEeWNbtBGDGgrUzALI,1104
|
|
68
|
+
DefEssential/Runners/RunExtension.py,sha256=Pw_WD1YGOfpPaV6nnIHPZTLdkKxQPUrqNJ2W9DB85ZA,4388
|
|
69
|
+
DefEssential/Runners/RunFactory.py,sha256=8FodjojcoG_r4QGwyiBXCWQWVKwvqqViA3-vlvz2QTY,330
|
|
70
|
+
DefEssential/Runners/RunOptions.py,sha256=d1bfnttCV8DwGEXDQHHrm-1v4kp_mIxNOqiwrEFeyp4,2158
|
|
71
|
+
DefEssential/Runners/RunRequest.py,sha256=w-fEmw8KgiPnjVL0LUkh5UdEo1I9SZQKEdDoIiFh8uo,6252
|
|
72
|
+
DefEssential/Runners/__init__.py,sha256=tc49lyoHNvJhR53iZYa7kndRzQmSLomHgg6mNQJWxLQ,65
|
|
73
|
+
DefEssential/Utils/Loader.py,sha256=ADo_RbABJvpejJs5uzFSmIOZHHeninbtQHVhqYTNF1c,1934
|
|
74
|
+
DefEssential/Utils/__init__.py,sha256=GYUwUI8d2-ZP08bODtmCw6csnU14ZLi3g_rze5V7jrA,38
|
|
75
|
+
DefEssential/Utils/FileSystemObject/Configuration.py,sha256=ZCXpQrz_pQl8KUrl4fWmDS-EvaqEDKU8hiSwoiRnvzs,322
|
|
76
|
+
DefEssential/Utils/FileSystemObject/Connection.py,sha256=U8WHCqQrWyhvwmmCa-nZo5nZhBGG-Zx29PSfuUQUNVM,1713
|
|
77
|
+
DefEssential/Utils/FileSystemObject/File.py,sha256=b-FvEuPjK6wcAIotruimkb5STEbpv_gWRCDUsgMCMjg,1178
|
|
78
|
+
DefEssential/Utils/FileSystemObject/__init__.py,sha256=uYHibei2P2GfmUuXdu3LSZE4E9sgRR5THu6G-qZEFSI,181
|
|
79
|
+
DefEssential/Utils/FileSystemObject/Implements/__init__.py,sha256=GYUwUI8d2-ZP08bODtmCw6csnU14ZLi3g_rze5V7jrA,38
|
|
80
|
+
DefEssential/Utils/FileSystemObject/Implements/FileSystem/Configuration.py,sha256=kktsUtOLX18f5EQJ-UkbJ58oOx5fcWs4MybLbau6xz8,308
|
|
81
|
+
DefEssential/Utils/FileSystemObject/Implements/FileSystem/Connection.py,sha256=7rOz4bgsPaDfA_baNJCkNYshQk8OkPWNE1HElyjFCNk,1940
|
|
82
|
+
DefEssential/Utils/FileSystemObject/Implements/FileSystem/File.py,sha256=GGPi3SWxA0VKqazNK4i-VgM7HHI9691PigKyvPe0ndI,1137
|
|
83
|
+
DefEssential/Utils/FileSystemObject/Implements/FileSystem/__init__.py,sha256=uYHibei2P2GfmUuXdu3LSZE4E9sgRR5THu6G-qZEFSI,181
|
|
84
|
+
DefEssential/Validator/Pattern.py,sha256=gRRlEzS908b9OCXRpFnEG4gujNKCSTlhPUGwWGi-Dqg,674
|
|
85
|
+
DefEssential/Validator/Validate.py,sha256=2Edk1sWh5_4QdYTc1xakDLPXMAWNrrjso1TLi7ZQ4Gg,700
|
|
86
|
+
DefEssential/Validator/Validator.py,sha256=lvJGzDKecKIBAQrfFuSHBRUh6PCxiHRsabul6cYxcdA,556
|
|
87
|
+
DefEssential/Validator/__init__.py,sha256=juhR_lm3XpqU-BUnTjbaYbFNXa_zs9Xi9-x_9EyvJgE,172
|
|
88
|
+
DefEssential/Validator/Patterns/Array.py,sha256=XPc88iPhU2k30TIyMsB6pdDqUO_wjv-5YP96mTHbApc,514
|
|
89
|
+
DefEssential/Validator/Patterns/Common.py,sha256=JJIOAcPO6epnIINaVu5SuwmnQoK3rLQn6vYyZ3JBuX8,1817
|
|
90
|
+
DefEssential/Validator/Patterns/Compare.py,sha256=5xYVvaiQydvIi8WYgIADltSk0tz_ki76k-c89vZsFcw,3726
|
|
91
|
+
DefEssential/Validator/Patterns/Condition.py,sha256=V8iEG9onH6bxlUnqFY8jDdmm6BIx2SBeEJAluVHeEUM,1135
|
|
92
|
+
DefEssential/Validator/Patterns/DataObject.py,sha256=BTdbKGSYs1ebXNXmKP2m3T0iJeTBxIwgwl45gacpuUA,2258
|
|
93
|
+
DefEssential/Validator/Patterns/DateTime.py,sha256=2ejPyRxFbvWf_0FmUrtXTBTvMnp8nakfW_TyCsRY_h4,2515
|
|
94
|
+
DefEssential/Validator/Patterns/Number.py,sha256=k59Ue1Sw-D1iWz8OywjQljPVXdZlTawSl9jBpPjJKKY,919
|
|
95
|
+
DefEssential/Validator/Patterns/Object.py,sha256=94aa5eC35dZyrgBlbAEH5eB7v9YB8k_haru_EBeU1vw,3563
|
|
96
|
+
DefEssential/Validator/Patterns/Size.py,sha256=n-PdMTYNCw0-KN2wqWqK7nN6smVvrGLO4YfwBLlGA9Y,2016
|
|
97
|
+
DefEssential/Validator/Patterns/String.py,sha256=sR4s0GM1J8r1kiOyu4HkDUgIrz-9PvLthHM1IFTgSqw,1805
|
|
98
|
+
DefEssential/Validator/Patterns/Type.py,sha256=-z75Q3vYw6Br7T-gACIZNLV2PLLkFdHn67VcLxTDqEs,8758
|
|
99
|
+
DefEssential/Validator/Patterns/__init__.py,sha256=2Kkk6BrvcLl0C22I0WhGphp2dF55Ig2b3LY0DMDNWm8,1603
|
|
100
|
+
defessential-0.1.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
101
|
+
defessential-0.1.8.dist-info/METADATA,sha256=DfO4oN-a8RyM2jpuzKxUqj9QiBBgA2uC2-sFJzsHTyc,2929
|
|
102
|
+
defessential-0.1.8.dist-info/WHEEL,sha256=KSlVbIgN-eymtdg_Co6oamVX2tQCTYpZCZhVrpplrHY,101
|
|
103
|
+
defessential-0.1.8.dist-info/top_level.txt,sha256=b0lV-WaTXvqY1C1fKJXmzw-aby4lKQvJGQhF5-x8-Sw,13
|
|
104
|
+
defessential-0.1.8.dist-info/RECORD,,
|