omlish 0.0.0.dev160__py3-none-any.whl → 0.0.0.dev162__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.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev160'
2
- __revision__ = '7a7f89f635d413c2afb755bed939daa26703116f'
1
+ __version__ = '0.0.0.dev162'
2
+ __revision__ = 'd9129e1bcec87862768d3a2fc10011def8f3fd52'
3
3
 
4
4
 
5
5
  #
@@ -0,0 +1,6 @@
1
+ Based on bluelet ( https://github.com/sampsyo/bluelet ) by Adrian Sampson, original license:
2
+
3
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
4
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
5
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
6
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
File without changes
@@ -0,0 +1,67 @@
1
+ # ruff: noqa: I001
2
+ from .api import ( # noqa
3
+ bluelet,
4
+ )
5
+
6
+ from .core import ( # noqa
7
+ BlueletCoro as Coro,
8
+ BlueletExcInfo as ExcInfo,
9
+ CoreBlueletEvent as CoreEvent,
10
+ DelegationBlueletEvent as DelegationEvent,
11
+ ExceptionBlueletEvent as ExceptionEvent,
12
+ JoinBlueletEvent as JoinEvent,
13
+ KillBlueletEvent as KillEvent,
14
+ ReturnBlueletEvent as ReturnEvent,
15
+ SleepBlueletEvent as SleepEvent,
16
+ SpawnBlueletEvent as SpawnEvent,
17
+ ValueBlueletEvent as ValueEvent,
18
+ )
19
+
20
+ from .events import ( # noqa
21
+ BlueletEvent as Event,
22
+ BlueletFuture as Future,
23
+ BlueletHasFileno as HasFileno,
24
+ BlueletWaitable as Waitable,
25
+ BlueletWaitables as Waitables,
26
+ WaitableBlueletEvent as WaitableEvent,
27
+ )
28
+
29
+ from .files import ( # noqa
30
+ FileBlueletEvent as FileEvent,
31
+ ReadBlueletEvent as ReadEvent,
32
+ WriteBlueletEvent as WriteEvent,
33
+ )
34
+
35
+ from .runner import ( # noqa
36
+ BlueletCoroException as CoroException,
37
+ )
38
+
39
+ from .sockets import ( # noqa
40
+ AcceptBlueletEvent as AcceptEvent,
41
+ BlueletConnection as Connection,
42
+ BlueletListener as Listener,
43
+ ReceiveBlueletEvent as ReceiveEvent,
44
+ SendBlueletEvent as SendEvent,
45
+ SocketBlueletEvent as SocketEvent,
46
+ SocketClosedBlueletError as SocketClosedError,
47
+ )
48
+
49
+
50
+ ##
51
+
52
+
53
+ call = bluelet.call
54
+ end = bluelet.end
55
+ join = bluelet.join
56
+ kill = bluelet.kill
57
+ null = bluelet.null
58
+ sleep = bluelet.sleep
59
+ spawn = bluelet.spawn
60
+
61
+ read = bluelet.read
62
+ write = bluelet.write
63
+
64
+ run = bluelet.run
65
+
66
+ connect = bluelet.connect
67
+ server = bluelet.server
@@ -0,0 +1,23 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ # Based on bluelet ( https://github.com/sampsyo/bluelet ) by Adrian Sampson, original license:
4
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
5
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
6
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
7
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+ from .core import _CoreBlueletApi
9
+ from .files import _FilesBlueletApi
10
+ from .runner import _RunnerBlueletApi
11
+ from .sockets import _SocketsBlueletApi
12
+
13
+
14
+ class BlueletApi(
15
+ _RunnerBlueletApi,
16
+ _SocketsBlueletApi,
17
+ _FilesBlueletApi,
18
+ _CoreBlueletApi,
19
+ ):
20
+ pass
21
+
22
+
23
+ bluelet = BlueletApi()
@@ -0,0 +1,178 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ # Based on bluelet ( https://github.com/sampsyo/bluelet ) by Adrian Sampson, original license:
4
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
5
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
6
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
7
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+ import abc
9
+ import dataclasses as dc
10
+ import time
11
+ import types
12
+ import typing as ta
13
+
14
+ from .events import BlueletEvent
15
+ from .events import BlueletFuture
16
+ from .events import WaitableBlueletEvent
17
+
18
+
19
+ T = ta.TypeVar('T')
20
+
21
+ BlueletExcInfo = ta.Tuple[ta.Type[BaseException], BaseException, types.TracebackType] # ta.TypeAlias
22
+
23
+ BlueletCoro = ta.Generator[ta.Union['BlueletEvent', 'BlueletCoro'], ta.Any, None] # ta.TypeAlias
24
+
25
+ BlueletSpawnable = ta.Union[BlueletCoro, ta.Awaitable] # ta.TypeAlias
26
+
27
+
28
+ ##
29
+
30
+
31
+ @dc.dataclass(frozen=True, eq=False)
32
+ class _BlueletAwaitableDriver:
33
+ a: ta.Awaitable
34
+
35
+ def __call__(self) -> BlueletCoro:
36
+ g = self.a.__await__()
37
+ gi = iter(g)
38
+ while True:
39
+ try:
40
+ f = gi.send(None)
41
+ except StopIteration as e:
42
+ yield ReturnBlueletEvent(e.value)
43
+ break
44
+ else:
45
+ if not isinstance(f, BlueletFuture):
46
+ raise TypeError(f)
47
+ res = yield f.event
48
+ f.done = True
49
+ f.result = res
50
+
51
+
52
+ ##
53
+
54
+
55
+ class CoreBlueletEvent(BlueletEvent, abc.ABC): # noqa
56
+ pass
57
+
58
+
59
+ @dc.dataclass(frozen=True, eq=False)
60
+ class ValueBlueletEvent(CoreBlueletEvent, ta.Generic[T]):
61
+ """An event that does nothing but return a fixed value."""
62
+
63
+ value: T
64
+
65
+
66
+ @dc.dataclass(frozen=True, eq=False)
67
+ class ExceptionBlueletEvent(CoreBlueletEvent):
68
+ """Raise an exception at the yield point. Used internally."""
69
+
70
+ exc_info: BlueletExcInfo
71
+
72
+
73
+ @dc.dataclass(frozen=True, eq=False)
74
+ class SpawnBlueletEvent(CoreBlueletEvent):
75
+ """Add a new coroutine coro to the scheduler."""
76
+
77
+ spawned: BlueletSpawnable
78
+
79
+
80
+ @dc.dataclass(frozen=True, eq=False)
81
+ class JoinBlueletEvent(CoreBlueletEvent):
82
+ """Suspend the coro until the specified child coro has completed."""
83
+
84
+ child: BlueletCoro
85
+
86
+
87
+ @dc.dataclass(frozen=True, eq=False)
88
+ class KillBlueletEvent(CoreBlueletEvent):
89
+ """Unschedule a child coro."""
90
+
91
+ child: BlueletCoro
92
+
93
+
94
+ @dc.dataclass(frozen=True, eq=False)
95
+ class DelegationBlueletEvent(CoreBlueletEvent):
96
+ """
97
+ Suspend execution of the current coro, start a new coro and, once the child coro finished, return control to
98
+ the parent coro.
99
+ """
100
+
101
+ spawned: BlueletCoro
102
+
103
+
104
+ @dc.dataclass(frozen=True, eq=False)
105
+ class ReturnBlueletEvent(CoreBlueletEvent, ta.Generic[T]):
106
+ """Return a value the current coro's delegator at the point of delegation. Ends the current (delegate) coro."""
107
+
108
+ value: ta.Optional[T]
109
+
110
+
111
+ @dc.dataclass(frozen=True, eq=False)
112
+ class SleepBlueletEvent(WaitableBlueletEvent, CoreBlueletEvent):
113
+ """Suspend the coro for a given duration."""
114
+
115
+ wakeup_time: float
116
+
117
+ def time_left(self) -> float:
118
+ return max(self.wakeup_time - time.time(), 0.)
119
+
120
+
121
+ ##
122
+
123
+
124
+ class _CoreBlueletApi:
125
+ def value(self, v: T) -> ValueBlueletEvent[T]:
126
+ """Event: yield a value."""
127
+
128
+ return ValueBlueletEvent(v)
129
+
130
+ def null(self) -> ValueBlueletEvent[None]:
131
+ """Event: yield to the scheduler without doing anything special."""
132
+
133
+ return ValueBlueletEvent(None)
134
+
135
+ def spawn(self, spawned: BlueletSpawnable) -> SpawnBlueletEvent:
136
+ """Event: add another coroutine to the scheduler. Both the parent and child coroutines run concurrently."""
137
+
138
+ if isinstance(spawned, types.CoroutineType):
139
+ spawned = _BlueletAwaitableDriver(spawned)()
140
+
141
+ if not isinstance(spawned, types.GeneratorType):
142
+ raise TypeError(f'{spawned} is not spawnable')
143
+
144
+ return SpawnBlueletEvent(spawned)
145
+
146
+ def join(self, coro: BlueletCoro) -> JoinBlueletEvent:
147
+ """Suspend the coro until another, previously `spawn`ed coro completes."""
148
+
149
+ return JoinBlueletEvent(coro)
150
+
151
+ def kill(self, coro: BlueletCoro) -> KillBlueletEvent:
152
+ """Halt the execution of a different `spawn`ed coro."""
153
+
154
+ return KillBlueletEvent(coro)
155
+
156
+ def call(self, spawned: BlueletSpawnable) -> DelegationBlueletEvent:
157
+ """
158
+ Event: delegate to another coroutine. The current coroutine is resumed once the sub-coroutine finishes. If the
159
+ sub-coroutine returns a value using end(), then this event returns that value.
160
+ """
161
+
162
+ if isinstance(spawned, types.CoroutineType):
163
+ spawned = _BlueletAwaitableDriver(spawned)()
164
+
165
+ if not isinstance(spawned, types.GeneratorType):
166
+ raise TypeError(f'{spawned} is not spawnable')
167
+
168
+ return DelegationBlueletEvent(spawned)
169
+
170
+ def end(self, value: ta.Optional[T] = None) -> ReturnBlueletEvent[T]:
171
+ """Event: ends the coroutine and returns a value to its delegator."""
172
+
173
+ return ReturnBlueletEvent(value)
174
+
175
+ def sleep(self, duration: float) -> SleepBlueletEvent:
176
+ """Event: suspend the coro for ``duration`` seconds."""
177
+
178
+ return SleepBlueletEvent(time.time() + duration)
@@ -0,0 +1,78 @@
1
+ # ruff: noqa: UP007
2
+ # @omlish-lite
3
+ # Based on bluelet ( https://github.com/sampsyo/bluelet ) by Adrian Sampson, original license:
4
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
5
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
6
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
7
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+ import abc
9
+ import dataclasses as dc
10
+ import typing as ta
11
+
12
+
13
+ R = ta.TypeVar('R')
14
+
15
+ BlueletEventT = ta.TypeVar('BlueletEventT', bound='BlueletEvent') # ta.TypeAlias
16
+
17
+ BlueletWaitable = ta.Union[int, 'BlueletHasFileno'] # ta.TypeAlias
18
+
19
+
20
+ ##
21
+
22
+
23
+ class BlueletEvent(abc.ABC): # noqa
24
+ """
25
+ Just a base class identifying Bluelet events. An event is an object yielded from a Bluelet coro coroutine to
26
+ suspend operation and communicate with the scheduler.
27
+ """
28
+
29
+ def __await__(self):
30
+ return BlueletFuture(self).__await__()
31
+
32
+
33
+ ##
34
+
35
+
36
+ class BlueletHasFileno(ta.Protocol):
37
+ def fileno(self) -> int: ...
38
+
39
+
40
+ @dc.dataclass(frozen=True)
41
+ class BlueletWaitables:
42
+ r: ta.Sequence[BlueletWaitable] = ()
43
+ w: ta.Sequence[BlueletWaitable] = ()
44
+ x: ta.Sequence[BlueletWaitable] = ()
45
+
46
+
47
+ class WaitableBlueletEvent(BlueletEvent, abc.ABC): # noqa
48
+ """
49
+ A waitable event is one encapsulating an action that can be waited for using a select() call. That is, it's an event
50
+ with an associated file descriptor.
51
+ """
52
+
53
+ def waitables(self) -> BlueletWaitables:
54
+ """
55
+ Return "waitable" objects to pass to select(). Should return three iterables for input readiness, output
56
+ readiness, and exceptional conditions (i.e., the three lists passed to select()).
57
+ """
58
+ return BlueletWaitables()
59
+
60
+ def fire(self) -> ta.Any:
61
+ """Called when an associated file descriptor becomes ready (i.e., is returned from a select() call)."""
62
+
63
+
64
+ ##
65
+
66
+
67
+ @dc.dataclass(eq=False)
68
+ class BlueletFuture(ta.Generic[BlueletEventT, R]):
69
+ event: BlueletEventT
70
+ done: bool = False
71
+ result: ta.Optional[R] = None
72
+
73
+ def __await__(self):
74
+ if not self.done:
75
+ yield self
76
+ if not self.done:
77
+ raise RuntimeError("await wasn't used with event future")
78
+ return self.result
@@ -0,0 +1,80 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ # Based on bluelet ( https://github.com/sampsyo/bluelet ) by Adrian Sampson, original license:
4
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
5
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
6
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
7
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+ import abc
9
+ import dataclasses as dc
10
+ import typing as ta
11
+
12
+ from .core import DelegationBlueletEvent
13
+ from .core import ReturnBlueletEvent
14
+ from .events import BlueletEvent
15
+ from .events import BlueletWaitables
16
+ from .events import WaitableBlueletEvent
17
+
18
+
19
+ ##
20
+
21
+
22
+ class FileBlueletEvent(BlueletEvent, abc.ABC):
23
+ pass
24
+
25
+
26
+ @dc.dataclass(frozen=True, eq=False)
27
+ class ReadBlueletEvent(WaitableBlueletEvent, FileBlueletEvent):
28
+ """Reads from a file-like object."""
29
+
30
+ fd: ta.IO
31
+ bufsize: int
32
+
33
+ def waitables(self) -> BlueletWaitables:
34
+ return BlueletWaitables(r=[self.fd])
35
+
36
+ def fire(self) -> bytes:
37
+ return self.fd.read(self.bufsize)
38
+
39
+
40
+ @dc.dataclass(frozen=True, eq=False)
41
+ class WriteBlueletEvent(WaitableBlueletEvent, FileBlueletEvent):
42
+ """Writes to a file-like object."""
43
+
44
+ fd: ta.IO
45
+ data: bytes
46
+
47
+ def waitables(self) -> BlueletWaitables:
48
+ return BlueletWaitables(w=[self.fd])
49
+
50
+ def fire(self) -> None:
51
+ self.fd.write(self.data)
52
+
53
+
54
+ ##
55
+
56
+
57
+ class _FilesBlueletApi:
58
+ def read(self, fd: ta.IO, bufsize: ta.Optional[int] = None) -> BlueletEvent:
59
+ """Event: read from a file descriptor asynchronously."""
60
+
61
+ if bufsize is None:
62
+ # Read all.
63
+ def reader():
64
+ buf = []
65
+ while True:
66
+ data = yield self.read(fd, 1024)
67
+ if not data:
68
+ break
69
+ buf.append(data)
70
+ yield ReturnBlueletEvent(''.join(buf))
71
+
72
+ return DelegationBlueletEvent(reader())
73
+
74
+ else:
75
+ return ReadBlueletEvent(fd, bufsize)
76
+
77
+ def write(self, fd: ta.IO, data: bytes) -> BlueletEvent:
78
+ """Event: write to a file descriptor asynchronously."""
79
+
80
+ return WriteBlueletEvent(fd, data)