DefStream 0.1.2__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.
Files changed (54) hide show
  1. DefStream/Broker/Configuration.py +18 -0
  2. DefStream/Broker/Connection.py +97 -0
  3. DefStream/Broker/Consumer.py +59 -0
  4. DefStream/Broker/Errors.py +14 -0
  5. DefStream/Broker/Event.py +35 -0
  6. DefStream/Broker/Implements/__init__.py +1 -0
  7. DefStream/Broker/Policies.py +25 -0
  8. DefStream/Broker/Protocol.py +45 -0
  9. DefStream/Broker/__init__.py +47 -0
  10. DefStream/Descriptor/DataObject.py +384 -0
  11. DefStream/Descriptor/Types.py +229 -0
  12. DefStream/Descriptor/Value.py +132 -0
  13. DefStream/Descriptor/__init__.py +172 -0
  14. DefStream/Inspector/Extension.py +69 -0
  15. DefStream/Inspector/Extensions/Console.html +373 -0
  16. DefStream/Inspector/Extensions/Console.py +396 -0
  17. DefStream/Inspector/Extensions/Dashboard.html +206 -0
  18. DefStream/Inspector/Extensions/Dashboard.py +114 -0
  19. DefStream/Inspector/Extensions/HealthCheck.py +92 -0
  20. DefStream/Inspector/Extensions/Metrics.py +281 -0
  21. DefStream/Inspector/Extensions/Specifications.py +160 -0
  22. DefStream/Inspector/Extensions/__init__.py +13 -0
  23. DefStream/Inspector/Inspector.py +216 -0
  24. DefStream/Inspector/Response.py +14 -0
  25. DefStream/Inspector/__init__.py +9 -0
  26. DefStream/Validator/Pattern.py +36 -0
  27. DefStream/Validator/Patterns/Array.py +30 -0
  28. DefStream/Validator/Patterns/Common.py +93 -0
  29. DefStream/Validator/Patterns/Compare.py +180 -0
  30. DefStream/Validator/Patterns/Condition.py +60 -0
  31. DefStream/Validator/Patterns/DataObject.py +85 -0
  32. DefStream/Validator/Patterns/DateTime.py +111 -0
  33. DefStream/Validator/Patterns/Number.py +43 -0
  34. DefStream/Validator/Patterns/Object.py +150 -0
  35. DefStream/Validator/Patterns/Size.py +110 -0
  36. DefStream/Validator/Patterns/String.py +85 -0
  37. DefStream/Validator/Patterns/Type.py +350 -0
  38. DefStream/Validator/Patterns/__init__.py +137 -0
  39. DefStream/Validator/Validate.py +29 -0
  40. DefStream/Validator/Validator.py +30 -0
  41. DefStream/Validator/__init__.py +11 -0
  42. DefStream/Worker/Executor.py +298 -0
  43. DefStream/Worker/Message.py +103 -0
  44. DefStream/Worker/Pool.py +203 -0
  45. DefStream/Worker/Run.py +187 -0
  46. DefStream/Worker/Specification.py +91 -0
  47. DefStream/Worker/Worker.py +321 -0
  48. DefStream/Worker/__init__.py +49 -0
  49. DefStream/__init__.py +0 -0
  50. defstream-0.1.2.dist-info/METADATA +1197 -0
  51. defstream-0.1.2.dist-info/RECORD +54 -0
  52. defstream-0.1.2.dist-info/WHEEL +5 -0
  53. defstream-0.1.2.dist-info/licenses/LICENSE +674 -0
  54. defstream-0.1.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,216 @@
1
+ from logging import getLogger
2
+ from socketserver import ThreadingMixIn
3
+ from threading import Thread
4
+ from typing import (
5
+ Callable,
6
+ Dict,
7
+ Iterable,
8
+ Optional,
9
+ Sequence,
10
+ TYPE_CHECKING,
11
+ Tuple,
12
+ )
13
+ from wsgiref.simple_server import (
14
+ WSGIRequestHandler,
15
+ WSGIServer,
16
+ make_server,
17
+ )
18
+
19
+ from .Extension import Extension
20
+ from .Response import Response
21
+
22
+ if TYPE_CHECKING:
23
+ from ..Worker.Worker import Worker
24
+
25
+ __all__ = (
26
+ 'Inspector',
27
+ )
28
+
29
+ logger = getLogger(__name__)
30
+
31
+
32
+ class Server(
33
+ ThreadingMixIn,
34
+ WSGIServer,
35
+ ):
36
+ daemon_threads = True
37
+ block_on_close = False
38
+
39
+ def get_request(self):
40
+ connection, address = super().get_request()
41
+ connection.settimeout(5)
42
+ return connection, address
43
+
44
+
45
+ class RequestHandler(WSGIRequestHandler):
46
+ def log_message(
47
+ self,
48
+ format: str,
49
+ *args,
50
+ ) -> None:
51
+ logger.info(
52
+ '%s - %s',
53
+ self.client_address[0],
54
+ format % args,
55
+ )
56
+
57
+
58
+ class Inspector:
59
+ def __init__(
60
+ self,
61
+ host: str = '127.0.0.1',
62
+ port: int = 9999,
63
+ exts: Sequence[Extension] = (),
64
+ ):
65
+ if isinstance(
66
+ port,
67
+ bool,
68
+ ) or not isinstance(
69
+ port,
70
+ int,
71
+ ) or not 0 <= port <= 65535:
72
+ raise ValueError('Inspector port must be between 0 and 65535')
73
+ self.host = host
74
+ self.port = port
75
+ self.exts: Dict[str, Extension] = {}
76
+ for ext in exts:
77
+ if not isinstance(
78
+ ext,
79
+ Extension,
80
+ ):
81
+ raise TypeError('Inspector extensions must inherit Extension')
82
+ if ext.path in self.exts:
83
+ raise ValueError('Duplicate Inspector path: ' + ext.path)
84
+ self.exts[ext.path] = ext
85
+ self.worker: Optional['Worker'] = None
86
+ self.server: Optional[WSGIServer] = None
87
+ self.thread: Optional[Thread] = None
88
+
89
+ def start(
90
+ self,
91
+ worker: 'Worker',
92
+ ) -> None:
93
+ if self.worker is not None:
94
+ raise RuntimeError('Inspector can only be attached and started once')
95
+ self.worker = worker
96
+ for ext in self.exts.values():
97
+ ext.start(self)
98
+ server = make_server(
99
+ self.host,
100
+ self.port,
101
+ self,
102
+ server_class=Server,
103
+ handler_class=RequestHandler,
104
+ )
105
+ self.server = server
106
+ thread = Thread(
107
+ target=self.serve,
108
+ daemon=True,
109
+ )
110
+ self.thread = thread
111
+ try:
112
+ thread.start()
113
+ except BaseException:
114
+ server.server_close()
115
+ raise
116
+
117
+ def serve(self) -> None:
118
+ server = self.server
119
+ if server is None:
120
+ raise RuntimeError('Inspector server is not initialized')
121
+ try:
122
+ server.serve_forever(poll_interval=0.1)
123
+ except Exception:
124
+ logger.exception('Inspector HTTP server failed')
125
+ if self.worker is not None:
126
+ self.worker.stop()
127
+ raise
128
+
129
+ def stop(self) -> None:
130
+ server = self.server
131
+ thread = self.thread
132
+ if server is not None:
133
+ try:
134
+ if thread is not None and thread.is_alive():
135
+ server.shutdown()
136
+ thread.join()
137
+ finally:
138
+ server.server_close()
139
+
140
+ def begin(
141
+ self,
142
+ task: str,
143
+ ) -> Tuple[Tuple[Extension, object], ...]:
144
+ return tuple(
145
+ (
146
+ ext,
147
+ ext.begin(task),
148
+ )
149
+ for ext in self.exts.values()
150
+ )
151
+
152
+ def end(
153
+ self,
154
+ task: str,
155
+ contexts: Tuple[Tuple[Extension, object], ...],
156
+ success: Optional[bool],
157
+ ) -> None:
158
+ for ext, context in contexts:
159
+ ext.end(
160
+ task,
161
+ context,
162
+ success,
163
+ )
164
+
165
+ def __call__(
166
+ self,
167
+ environ: dict,
168
+ start_response: Callable,
169
+ ) -> Iterable[bytes]:
170
+ method = environ['REQUEST_METHOD']
171
+ environ['wsgi.multithread'] = True
172
+ headers = []
173
+ ext = self.exts.get(environ['PATH_INFO'])
174
+ methods = ext.methods if ext is not None else (
175
+ 'GET',
176
+ 'HEAD',
177
+ )
178
+ if method not in methods:
179
+ response = Response(
180
+ '405 Method Not Allowed',
181
+ b'Method not allowed\n',
182
+ 'text/plain; charset=utf-8',
183
+ )
184
+ headers.append((
185
+ 'Allow',
186
+ ', '.join(methods),
187
+ ))
188
+ else:
189
+ response = ext.handle(
190
+ self,
191
+ environ,
192
+ ) if ext is not None else Response(
193
+ '404 Not Found',
194
+ b'Not found\n',
195
+ 'text/plain; charset=utf-8',
196
+ )
197
+ headers.extend(response.headers)
198
+ headers.extend((
199
+ (
200
+ 'Content-Type',
201
+ response.content_type,
202
+ ),
203
+ (
204
+ 'Content-Length',
205
+ str(len(response.body)),
206
+ ),
207
+ (
208
+ 'Cache-Control',
209
+ 'no-store',
210
+ ),
211
+ ))
212
+ start_response(
213
+ response.status,
214
+ headers,
215
+ )
216
+ return [b'' if method == 'HEAD' else response.body]
@@ -0,0 +1,14 @@
1
+ from dataclasses import dataclass
2
+ from typing import Tuple
3
+
4
+ __all__ = (
5
+ 'Response',
6
+ )
7
+
8
+
9
+ @dataclass
10
+ class Response:
11
+ status: str
12
+ body: bytes
13
+ content_type: str
14
+ headers: Tuple[Tuple[str, str], ...] = ()
@@ -0,0 +1,9 @@
1
+ from .Inspector import Inspector
2
+ from .Extension import Extension
3
+ from .Response import Response
4
+
5
+ __all__ = (
6
+ 'Inspector',
7
+ 'Extension',
8
+ 'Response',
9
+ )
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from abc import (
4
+ ABC,
5
+ abstractmethod,
6
+ )
7
+
8
+ __all__ = (
9
+ 'Pattern',
10
+ )
11
+
12
+
13
+ class Pattern(ABC):
14
+ """
15
+ Pattern Interface Class for Validator
16
+
17
+ Sample:
18
+ from operator import eq
19
+
20
+ class SamplePattern(Pattern):
21
+ def __init__(self, compare):
22
+ super(SamplePattern, self).__init__(error)
23
+ self.compare = compare
24
+ return
25
+
26
+ def __call__(self, parameter):
27
+ if not eq(parameter, self.compare):
28
+ raise ValueError('{} is not equal to {}'.format(parameter, self.condition))
29
+ return parameter # if true, return parameter
30
+ """
31
+ @abstractmethod
32
+ def __call__(self, parameter):
33
+ pass
34
+
35
+ def __repr__(self):
36
+ return '{}()'.format(self.__class__.__name__)
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from ..Pattern import Pattern
4
+
5
+ from typing import Any
6
+
7
+ __all__ = (
8
+ 'IsElementOf',
9
+ )
10
+
11
+
12
+ class IsElementOf(Pattern):
13
+ def __init__(self, *args):
14
+ self.patterns = args
15
+ return
16
+
17
+ def __call__(self, parameter: Any) -> Any:
18
+ _ = list(parameter)
19
+ for pattern in self.patterns:
20
+ for i, e in enumerate(_):
21
+ _[i] = pattern(e)
22
+ return type(parameter)(_)
23
+
24
+ def __repr__(self):
25
+ return '{}({})'.format(
26
+ self.__class__.__name__,
27
+ ', '.join(
28
+ [repr(p) for p in self.patterns]
29
+ )
30
+ )
@@ -0,0 +1,93 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from ..Pattern import Pattern
4
+
5
+ from operator import eq
6
+
7
+ __all__ = (
8
+ 'SetDefault',
9
+ 'IsToNone',
10
+ 'IsNotToNone',
11
+ 'IsNotEmpty',
12
+ )
13
+
14
+
15
+ class SetDefault(Pattern):
16
+ def __init__(self, default):
17
+ self.default = default
18
+ return
19
+
20
+ def __call__(self, parameter):
21
+ if parameter == None:
22
+ return self.default
23
+ return parameter
24
+
25
+ def __repr__(self):
26
+ return '{}({})'.format(
27
+ self.__class__.__name__,
28
+ self.default
29
+ )
30
+
31
+
32
+ class IsToNone(Pattern):
33
+ def __init__(self, *args):
34
+ self.patterns = args
35
+ return
36
+
37
+ def __call__(self, parameter):
38
+ if parameter is None:
39
+ return parameter
40
+ for pattern in self.patterns:
41
+ parameter = pattern(parameter)
42
+ return parameter
43
+
44
+ def __repr__(self):
45
+ return '{}({})'.format(
46
+ self.__class__.__name__,
47
+ ', '.join([p.__repr__() for p in self.patterns])
48
+ )
49
+
50
+
51
+ class IsNotToNone(Pattern):
52
+ def __init__(self, *args, error=None):
53
+ self.patterns = args
54
+ self.error = error
55
+ return
56
+
57
+ def __call__(self, parameter):
58
+ if parameter is None:
59
+ if self.error:
60
+ raise self.error
61
+ raise ValueError('{} is None'.format(parameter))
62
+ for pattern in self.patterns:
63
+ parameter = pattern(parameter)
64
+ return parameter
65
+
66
+ def __repr__(self):
67
+ return '{}({})'.format(
68
+ self.__class__.__name__,
69
+ ', '.join([p.__repr__() for p in self.patterns])
70
+ )
71
+
72
+
73
+ class IsNotEmpty(Pattern):
74
+ def __init__(self, *args, error=None):
75
+ self.patterns = args
76
+ self.error = error
77
+ return
78
+
79
+ def __call__(self, parameter):
80
+ if eq(len(parameter), 0):
81
+ if self.error:
82
+ raise self.error
83
+ raise ValueError('{} must be not empty'.format(parameter))
84
+ for pattern in self.patterns:
85
+ parameter = pattern(parameter)
86
+ return parameter
87
+
88
+ def __repr__(self):
89
+ return '{}({})'.format(
90
+ self.__class__.__name__,
91
+ ', '.join([p.__repr__() for p in self.patterns])
92
+ )
93
+
@@ -0,0 +1,180 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from ..Pattern import Pattern
4
+
5
+ from operator import eq, ne, gt, ge, lt, le
6
+
7
+ __all__ = (
8
+ 'IsIn',
9
+ 'IsNotIn',
10
+ 'IsEqualTo',
11
+ 'IsNotEqualTo',
12
+ 'IsGreaterThan',
13
+ 'IsGreaterEqualTo',
14
+ 'IsLessThan',
15
+ 'IsLessEqualTo',
16
+ )
17
+
18
+
19
+ class IsIn(Pattern):
20
+ def __init__(self, *args, error=None):
21
+ self.compares = args
22
+ self.error = error
23
+ return
24
+
25
+ def __call__(self, parameter):
26
+ if parameter not in self.compares:
27
+ if self.error:
28
+ raise self.error
29
+ raise ValueError('{} must be in {}'.format(parameter, self.compares))
30
+ return parameter
31
+
32
+ def __repr__(self):
33
+ return '{}({})'.format(
34
+ self.__class__.__name__,
35
+ ', '.join(
36
+ [repr(c) for c in self.compares]
37
+ )
38
+ )
39
+
40
+
41
+ class IsNotIn(Pattern):
42
+ def __init__(self, *args, error=None):
43
+ self.compares = args
44
+ self.error = error
45
+ return
46
+
47
+ def __call__(self, parameter):
48
+ if parameter in self.compares:
49
+ if self.error:
50
+ raise self.error
51
+ raise ValueError('{} must be not in {}'.format(parameter, self.compares))
52
+ return parameter
53
+
54
+ def __repr__(self):
55
+ return '{}({})'.format(
56
+ self.__class__.__name__,
57
+ ', '.join(
58
+ [repr(c) for c in self.compares]
59
+ )
60
+ )
61
+
62
+
63
+ class IsEqualTo(Pattern):
64
+ def __init__(self, equal, error=None):
65
+ self.equal = equal
66
+ self.error = error
67
+ return
68
+
69
+ def __call__(self, parameter):
70
+ if not eq(parameter, self.equal):
71
+ if self.error:
72
+ raise self.error
73
+ raise ValueError('{} must equal to {}'.format(parameter, self.equal))
74
+ return parameter
75
+
76
+ def __repr__(self):
77
+ return '{}({})'.format(
78
+ self.__class__.__name__,
79
+ self.equal
80
+ )
81
+
82
+
83
+ class IsNotEqualTo(Pattern):
84
+ def __init__(self, equal, error=None):
85
+ self.equal = equal
86
+ self.error = error
87
+ return
88
+
89
+ def __call__(self, parameter):
90
+ if not ne(parameter, self.equal):
91
+ if self.error:
92
+ raise self.error
93
+ raise ValueError('{} must not equal to {}'.format(parameter, self.equal))
94
+ return parameter
95
+
96
+ def __repr__(self):
97
+ return '{}({})'.format(
98
+ self.__class__.__name__,
99
+ self.equal
100
+ )
101
+
102
+
103
+ class IsGreaterEqualTo(Pattern):
104
+ def __init__(self, compare, error=None):
105
+ self.compare = compare
106
+ self.error = error
107
+ return
108
+
109
+ def __call__(self, parameter):
110
+ if not ge(parameter, self.compare):
111
+ if self.error:
112
+ raise self.error
113
+ raise ValueError('{} must be greater equal to {}'.format(parameter, self.compare))
114
+ return parameter
115
+
116
+ def __repr__(self):
117
+ return '{}({})'.format(
118
+ self.__class__.__name__,
119
+ self.compare
120
+ )
121
+
122
+
123
+ class IsGreaterThan(Pattern):
124
+ def __init__(self, compare, error=None):
125
+ self.compare = compare
126
+ self.error = error
127
+ return
128
+
129
+ def __call__(self, parameter):
130
+ if not gt(parameter, self.compare):
131
+ if self.error:
132
+ raise self.error
133
+ raise ValueError('{} must be greater than {}'.format(parameter, self.compare))
134
+ return parameter
135
+
136
+ def __repr__(self):
137
+ return '{}({})'.format(
138
+ self.__class__.__name__,
139
+ self.compare
140
+ )
141
+
142
+
143
+ class IsLessEqualTo(Pattern):
144
+ def __init__(self, compare, error=None):
145
+ self.compare = compare
146
+ self.error = error
147
+ return
148
+
149
+ def __call__(self, parameter):
150
+ if not le(parameter, self.compare):
151
+ if self.error:
152
+ raise self.error
153
+ raise ValueError('{} must be less equal to {}'.format(parameter, self.compare))
154
+ return parameter
155
+
156
+ def __repr__(self):
157
+ return '{}({})'.format(
158
+ self.__class__.__name__,
159
+ self.compare
160
+ )
161
+
162
+
163
+ class IsLessThan(Pattern):
164
+ def __init__(self, compare, error=None):
165
+ self.compare = compare
166
+ self.error = error
167
+ return
168
+
169
+ def __call__(self, parameter):
170
+ if not lt(parameter, self.compare):
171
+ if self.error:
172
+ raise self.error
173
+ raise ValueError('{} must be less than {}'.format(parameter, self.compare))
174
+ return parameter
175
+
176
+ def __repr__(self):
177
+ return '{}({})'.format(
178
+ self.__class__.__name__,
179
+ self.compare
180
+ )
@@ -0,0 +1,60 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from ..Pattern import Pattern
4
+
5
+ __all__ = (
6
+ 'All',
7
+ 'Any',
8
+ )
9
+
10
+
11
+ class All(Pattern):
12
+ def __init__(self, *args, error=None) -> None:
13
+ self.patterns = args
14
+ self.error = error
15
+ return
16
+
17
+ def __call__(self, parameter):
18
+ try:
19
+ for pattern in self.patterns:
20
+ parameter = pattern(parameter)
21
+ return parameter
22
+ except Exception as e:
23
+ if self.error:
24
+ raise self.error
25
+ raise e
26
+
27
+ def __repr__(self):
28
+ return '{}({})'.format(
29
+ self.__class__.__name__,
30
+ ', '.join(
31
+ [p.__repr__() for p in self.patterns]
32
+ )
33
+ )
34
+
35
+
36
+ class Any(Pattern):
37
+ def __init__(self, *args, error=None) -> None:
38
+ self.patterns = args
39
+ self.error = error
40
+ return
41
+
42
+ def __call__(self, parameter):
43
+ for pattern in self.patterns:
44
+ try:
45
+ parameter = pattern(parameter)
46
+ return parameter
47
+ except Exception:
48
+ pass
49
+ if self.error:
50
+ raise self.error
51
+ raise ValueError('{} must be validated in {}'.format(
52
+ parameter,
53
+ ', '.join([p.__repr__() for p in self.patterns])
54
+ ))
55
+
56
+ def __repr__(self):
57
+ return '{}({})'.format(
58
+ self.__class__.__name__,
59
+ ', '.join([p.__repr__() for p in self.patterns])
60
+ )