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
|
import asyncio
|
||||||
from collections.abc import Awaitable, Callable, Coroutine
|
from collections.abc import Awaitable, Callable, Coroutine
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Any
|
from typing import Any, Self
|
||||||
|
|
||||||
from scopes.core import actor
|
from scopes.core import actor
|
||||||
from scopes.core.message import Message
|
from scopes.core.message import Message
|
||||||
|
from scopes import util
|
||||||
from scopes.util import keywords as k, Symbol
|
from scopes.util import keywords as k, Symbol
|
||||||
|
|
||||||
type Mailbox = asyncio.Queue
|
type Mailbox = asyncio.Queue
|
||||||
type Categ = tuple[Symbol, Symbol]
|
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 Program = Callable[[Scope], Proc]
|
||||||
type Syn = Callable[[Message], Message]
|
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)
|
await scope.environ.put(msg)
|
||||||
return scope
|
|
||||||
|
|
||||||
global_mailbox: Mailbox = asyncio.Queue()
|
global_mailbox: Mailbox = asyncio.Queue()
|
||||||
|
|
||||||
|
|
@ -38,19 +43,17 @@ class Scope:
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.set_proc()
|
self.set_proc()
|
||||||
|
|
||||||
def set_proc(self) -> Scope:
|
def set_proc(self) -> Self:
|
||||||
self.proc = self.program(self)
|
self.proc = self.program(self)
|
||||||
return 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)
|
return Scope(environ=env, categ=cat, **kw)
|
||||||
|
|
||||||
def neuron(scope: Scope) -> Mailbox:
|
def neuron(scope: Scope) -> Mailbox:
|
||||||
async def process(msg: Message) -> actor.Behavior | None:
|
async def process(msg: Message) -> actor.Behavior | None:
|
||||||
nonlocal scope
|
nonlocal scope
|
||||||
new_scope = await scope.proc(scope, msg)
|
scope = await scope.proc(msg, scope) or scope
|
||||||
if new_scope is not None:
|
|
||||||
scope = new_scope
|
|
||||||
return process
|
return process
|
||||||
return actor.create(process)
|
return actor.create(process)
|
||||||
|
|
||||||
|
|
@ -59,3 +62,19 @@ def create_zero(env: Mailbox) -> Mailbox:
|
||||||
zero = neuron(scope)
|
zero = neuron(scope)
|
||||||
return zero
|
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 import core
|
||||||
from scopes.core import actor
|
from scopes.core import actor
|
||||||
|
from scopes.core.message import Message
|
||||||
from scopes.util import keywords as k
|
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)
|
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)
|
scope = core.create_scope(meta_env, (k.env, k.c00), program=lambda x: proc_env)
|
||||||
return core.neuron(scope)
|
return core.neuron(scope)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# scopes.util
|
# scopes.util
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
from collections.abc import Iterable
|
||||||
import hashlib
|
import hashlib
|
||||||
from secrets import choice
|
from secrets import choice
|
||||||
import string
|
import string
|
||||||
|
|
@ -24,6 +25,20 @@ class Symbols:
|
||||||
|
|
||||||
keywords = 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
|
# random strings, hashes, encodings
|
||||||
# for authentication, encryption, and other purposes
|
# for authentication, encryption, and other purposes
|
||||||
|
|
|
||||||
|
|
@ -67,14 +67,12 @@ async def meta_env(collector):
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
async def test_core(meta_env, collector):
|
async def test_core(meta_env, collector):
|
||||||
env = environ.create(meta_env)
|
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)
|
zero = core.create_zero(env)
|
||||||
|
await env.put(Message(k.env, k.hello))
|
||||||
await zero.put(Message(k.csys, k.hello))
|
await zero.put(Message(k.csys, k.hello))
|
||||||
await asyncio.sleep(0.01)
|
await asyncio.sleep(0.01)
|
||||||
assert len(collector) == 2
|
assert len(collector) == 2
|
||||||
|
assert collector[0].domain is k.env
|
||||||
assert collector[1].domain is k.csys
|
assert collector[1].domain is k.csys
|
||||||
#print(collector)
|
#print(collector)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from scopes.util import keywords as k
|
from scopes.util import keywords as k, flatten
|
||||||
|
|
||||||
def test_keywords():
|
def test_keywords():
|
||||||
assert k.dummy is k.dummy
|
assert k.dummy is k.dummy
|
||||||
|
|
@ -13,3 +13,8 @@ def test_keywords():
|
||||||
assert k('dummy') is k.dummy
|
assert k('dummy') is k.dummy
|
||||||
assert k('new') is k('new')
|
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