core: action and handler types, gen_proc; revert proc and handler args order
This commit is contained in:
parent
4b3af802cd
commit
49cac25cb7
5 changed files with 54 additions and 17 deletions
|
|
@ -6,21 +6,26 @@ from __future__ import annotations # no check of type annotations at runtime
|
|||
import asyncio
|
||||
from collections.abc import Awaitable, Callable, Coroutine
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
from typing import Any, Self
|
||||
|
||||
from scopes.core import actor
|
||||
from scopes.core.message import Message
|
||||
from scopes import util
|
||||
from scopes.util import keywords as k, Symbol
|
||||
|
||||
type Mailbox = asyncio.Queue
|
||||
type Categ = tuple[Symbol, Symbol]
|
||||
type Proc = Callable[[Scope, Message], Awaitable[Scope]]
|
||||
type Proc = Callable[[Message, Scope], Awaitable[Scope | None]]
|
||||
type Program = Callable[[Scope], Proc]
|
||||
type Syn = Callable[[Message], Message]
|
||||
|
||||
async def proc_dummy(scope: Scope, msg: Message) -> Scope:
|
||||
type Handler = Callable[[Message, Scope],
|
||||
Awaitable[Message | None | tuple[Message | None, Scope | None]]]
|
||||
type Handlers = Handler | None | list[Handlers]
|
||||
type Actions = dict[Symbol, Handlers]
|
||||
|
||||
async def proc_dummy(msg: Message, scope: Scope) -> None:
|
||||
await scope.environ.put(msg)
|
||||
return scope
|
||||
|
||||
global_mailbox: Mailbox = asyncio.Queue()
|
||||
|
||||
|
|
@ -38,19 +43,17 @@ class Scope:
|
|||
def __post_init__(self):
|
||||
self.set_proc()
|
||||
|
||||
def set_proc(self) -> Scope:
|
||||
def set_proc(self) -> Self:
|
||||
self.proc = self.program(self)
|
||||
return self
|
||||
|
||||
def create_scope(env: Mailbox, cat=(k.csys, k.c00), **kw) -> Scope:
|
||||
def create_scope(env: Mailbox, cat: Categ = (k.csys, k.c00), **kw) -> Scope:
|
||||
return Scope(environ=env, categ=cat, **kw)
|
||||
|
||||
def neuron(scope: Scope) -> Mailbox:
|
||||
async def process(msg: Message) -> actor.Behavior | None:
|
||||
nonlocal scope
|
||||
new_scope = await scope.proc(scope, msg)
|
||||
if new_scope is not None:
|
||||
scope = new_scope
|
||||
scope = await scope.proc(msg, scope) or scope
|
||||
return process
|
||||
return actor.create(process)
|
||||
|
||||
|
|
@ -59,3 +62,19 @@ def create_zero(env: Mailbox) -> Mailbox:
|
|||
zero = neuron(scope)
|
||||
return zero
|
||||
|
||||
def gen_proc(actions: Actions, default: Handlers = None,
|
||||
before: Handlers = None, after: Handlers = None) -> Proc:
|
||||
async def proc(msg: Message, scope: Scope) -> Scope:
|
||||
acts = actions.get(msg.head['action'], actions.get(k.default, default))
|
||||
acts = util.flatten(before, acts, after, ignore_none=True)
|
||||
for act in acts:
|
||||
msg = await act(msg, scope)
|
||||
if isinstance(msg, tuple):
|
||||
msg, new_scope = msg
|
||||
if new_scope is not None:
|
||||
scope = new_scope
|
||||
if msg is None:
|
||||
break
|
||||
return scope
|
||||
return proc
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
from scopes import core
|
||||
from scopes.core import actor
|
||||
from scopes.core.message import Message
|
||||
from scopes.util import keywords as k
|
||||
|
||||
async def proc_env(scope, msg):
|
||||
async def proc_env(msg: Message, scope: core.Scope) -> None:
|
||||
await scope.environ.put(msg)
|
||||
#return scope
|
||||
|
||||
def create(meta_env):
|
||||
def create(meta_env: core.Mailbox) -> core.Mailbox:
|
||||
scope = core.create_scope(meta_env, (k.env, k.c00), program=lambda x: proc_env)
|
||||
return core.neuron(scope)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# scopes.util
|
||||
|
||||
import base64
|
||||
from collections.abc import Iterable
|
||||
import hashlib
|
||||
from secrets import choice
|
||||
import string
|
||||
|
|
@ -24,6 +25,20 @@ class Symbols:
|
|||
|
||||
keywords = Symbols()
|
||||
|
||||
# list / iterable utilities
|
||||
|
||||
def flatten(*it, ignore_none=False):
|
||||
accu = []
|
||||
def doit(it):
|
||||
if ignore_none and it is None:
|
||||
return
|
||||
if isinstance(it, Iterable):
|
||||
for t in it:
|
||||
doit(t)
|
||||
else:
|
||||
accu.append(it)
|
||||
doit(it)
|
||||
return accu
|
||||
|
||||
# random strings, hashes, encodings
|
||||
# for authentication, encryption, and other purposes
|
||||
|
|
|
|||
|
|
@ -67,14 +67,12 @@ async def meta_env(collector):
|
|||
@pytest.mark.anyio
|
||||
async def test_core(meta_env, collector):
|
||||
env = environ.create(meta_env)
|
||||
await env.put(Message(k.env, k.hello))
|
||||
await asyncio.sleep(0.01)
|
||||
assert len(collector) == 1
|
||||
assert collector[0].domain is k.env
|
||||
zero = core.create_zero(env)
|
||||
await env.put(Message(k.env, k.hello))
|
||||
await zero.put(Message(k.csys, k.hello))
|
||||
await asyncio.sleep(0.01)
|
||||
assert len(collector) == 2
|
||||
assert collector[0].domain is k.env
|
||||
assert collector[1].domain is k.csys
|
||||
#print(collector)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from scopes.util import keywords as k
|
||||
from scopes.util import keywords as k, flatten
|
||||
|
||||
def test_keywords():
|
||||
assert k.dummy is k.dummy
|
||||
|
|
@ -13,3 +13,8 @@ def test_keywords():
|
|||
assert k('dummy') is k.dummy
|
||||
assert k('new') is k('new')
|
||||
|
||||
def test_flatten():
|
||||
lst = (1, (None, 2), (3, (4, 5)))
|
||||
assert flatten(lst) == [1, None, 2, 3, 4, 5]
|
||||
assert flatten(42, lst, (6, 7), ignore_none=True) == [42, 1, 2, 3, 4, 5, 6, 7]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue