Compare commits

..

2 commits

5 changed files with 61 additions and 33 deletions

View file

@ -13,14 +13,12 @@ from scopes.core.message import Message
from scopes import util from scopes import util
from scopes.util import keywords as k, Symbol, Symbols from scopes.util import keywords as k, Symbol, Symbols
# keywords (domains, actions, categories, stages): # keywords (domains, actions, classes, stages, data keys):
k('csys', 'env', k('csys ctl env',
'connect', 'create', 'created', 'data', 'default', 'value', 'connect create created data default query set value',
'c00', 'e00', 's00', 'c00 e00 s00 rcvr op',
'initial', 'active', 'retired') 'initial active retired',
'address pred succ')
dom = util.Symbols('dom')('csys', 'env')
cat = util.Symbols('cat')('c00', 'e00', 's00')
type Mailbox = asyncio.Queue type Mailbox = asyncio.Queue
type Categ = tuple[Symbol, Symbol] type Categ = tuple[Symbol, Symbol]
@ -54,14 +52,14 @@ def synapse(rcvr: Mailbox, op: SynOp = lambda x: x) -> Syn:
env_dummy: Mailbox = asyncio.Queue() env_dummy: Mailbox = asyncio.Queue()
def notify() -> Handler: def notify() -> Handler:
async def handle(msg, scope) -> None: async def handle(msg: Message, scope: Scope) -> None:
await scope.environ.put(msg) await scope.environ.put(msg)
return handle return handle
def gen_proc(actions: Actions, default: Handlers = notify(), def gen_proc(actions: Actions, default: Handlers = notify(),
prepare: Handlers = None, finalize: Handlers = None) -> Proc: prepare: Handlers = None, finalize: Handlers = None) -> Proc:
async def proc(msg: Message, scope: Scope) -> Scope: async def proc(msg: Message, scope: Scope) -> Scope:
acts = actions.get(msg.head.action, actions.get(k.default, default)) acts = actions.get(msg.action, actions.get(k.default, default))
acts = util.flatten(prepare, acts, finalize, ignore_none=True) acts = util.flatten(prepare, acts, finalize, ignore_none=True)
for act in acts: for act in acts:
msg = await act(msg, scope) msg = await act(msg, scope)
@ -87,7 +85,7 @@ def gen_program(spec: ProgramSpec, default: Proc = gen_proc({})) -> Program:
class Scope: class Scope:
value: Any = 0 value: Any = 0
categ: Categ = (k.csys, cat.c00) categ: Categ = (k.csys, k.c00)
stage: Symbol = k.initial stage: Symbol = k.initial
proc: Proc = field(init=False) proc: Proc = field(init=False)
program: Program = gen_program({}) program: Program = gen_program({})
@ -101,7 +99,7 @@ class Scope:
self.proc = self.program(self) self.proc = self.program(self)
return self return self
def create_scope(env: Mailbox, cat: Categ = (k.csys, cat.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 clone_scope(scope: Scope, **kw) -> Scope: def clone_scope(scope: Scope, **kw) -> Scope:
@ -109,7 +107,7 @@ def clone_scope(scope: Scope, **kw) -> Scope:
categ = kw.get('categ', scope.categ) categ = kw.get('categ', scope.categ)
stage = kw.get('stage', k.initial) stage = kw.get('stage', k.initial)
return Scope(environ=scope.environ, value=value, categ=categ, stage=stage, return Scope(environ=scope.environ, value=value, categ=categ, stage=stage,
program=scope.program, syns=[], **kw) program=scope.program, syns=[])
async def create_zero(env: Mailbox) -> Mailbox: async def create_zero(env: Mailbox) -> Mailbox:
scope = create_scope(env, program=gen_program({}, default=std_proc())) scope = create_scope(env, program=gen_program({}, default=std_proc()))
@ -120,27 +118,33 @@ async def create_zero(env: Mailbox) -> Mailbox:
# predefined action handlers and Action sets # predefined action handlers and Action sets
def forward() -> Handler: def forward() -> Handler:
async def handle(msg, scope) -> None: async def handle(msg: Message, scope: Scope) -> None:
for syn in scope.syns: for syn in scope.syns:
await syn(msg) await syn(msg)
return handle return handle
def value_add() -> Handler: def value_add() -> Handler:
async def handle(msg, scope) -> tuple[Message, Scope]: async def handle(msg: Message, scope: Scope) -> tuple[Message, Scope]:
return msg, scope return msg, scope
return handle return handle
def create() -> Handler: def create() -> Handler:
async def handle(msg, scope) -> None: async def handle(msg: Message, scope: Scope) -> None:
new = neuron(clone_scope(scope, **msg.data)) new = neuron(clone_scope(scope, **msg.data))
await notify_created(msg, new, scope) await notify_created(msg, new, scope)
conn = msg.data.get(k.connect)
return handle
def connect() -> Handler:
async def handle(msg: Message, scope: Scope) -> None:
return None return None
return handle return handle
def basic_actions() -> Actions: def basic_actions() -> Actions:
acts: Actions = { acts: Actions = {
k.value: value_add(), k.value: value_add(),
k.create: create() k.create: create(),
k.connect: connect()
} }
return acts return acts
@ -149,12 +153,13 @@ def basic_actions() -> Actions:
def std_proc(actions: Actions | None = None, finalize: Handler = forward(), def std_proc(actions: Actions | None = None, finalize: Handler = forward(),
more: Actions = {}) -> Proc: more: Actions = {}) -> Proc:
if actions is None: if actions is None:
actions = basic_actions() | more actions = basic_actions()
actions.update(more)
return gen_proc(actions, finalize=finalize) return gen_proc(actions, finalize=finalize)
# helpers # helpers
async def notify_created(msg: Message, new: Mailbox, scope: Scope) -> None: async def notify_created(msg: Message, new: Mailbox, scope: Scope) -> None:
msg = Message(msg.head.domain, k.created, data=msg.data | {k.new: new}) msg = Message(msg.domain, k.created, data=msg.data | {k.new: new})
await scope.environ.put(msg) await scope.environ.put(msg)

View file

@ -7,8 +7,22 @@ from scopes.core import actor
from scopes.core.message import Message from scopes.core.message import Message
from scopes.util import keywords as k from scopes.util import keywords as k
def create(meta_env: core.Mailbox) -> core.Mailbox: def create_env(meta_env: core.Mailbox) -> core.Mailbox:
scope = core.create_scope(meta_env, (k.env, k.c00), scope = core.create_scope(meta_env, (k.env, k.c00),
program=core.gen_program({})) program=core.gen_program({}, default=env_proc()))
return core.neuron(scope) return core.neuron(scope)
def env_proc() -> core.Proc:
return core.gen_proc(env_actions(), default=None, finalize=core.notify())
def handle_created() -> core.Handler:
async def handle(msg: Message, scope: core.Scope) -> Message:
return msg
return handle
def env_actions() -> core.Actions:
return {
k.created: handle_created(),
}

View file

@ -15,14 +15,14 @@ class Symbol(str):
class Symbols: class Symbols:
def __init__(self, prefix=None): def __init__(self, ns=None):
self.__prefix = prefix self.__prefix = ns + '.' if ns else ''
def __call__(self, *ks): def __call__(self, *keys):
prefix = self.__prefix + '.' if self.__prefix else '' for segment in keys:
for k in ks: for key in segment.split():
if not hasattr(self, k): if not hasattr(self, key):
setattr(self, k, Symbol(prefix + k)) setattr(self, key, Symbol(self.__prefix + key))
return self return self
def __getattr__(self, k): def __getattr__(self, k):

View file

@ -67,12 +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_env(meta_env)
zero = await core.create_zero(env) zero = await core.create_zero(env)
await env.put(Message(k.env, k.hello)) 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 zero.put(Message(k.csys, k.create)) await zero.put(Message(k.csys, k.create,
#data={k.connect: k.pred, k.address: (1, 1)})) data={k.connect: k.pred, k.address: (1, 1)}))
await asyncio.sleep(0.01) await asyncio.sleep(0.01)
assert len(collector) == 4 assert len(collector) == 4
assert collector[0].action is k.created assert collector[0].action is k.created

View file

@ -4,15 +4,24 @@
import pytest import pytest
from scopes.util import keywords as k, flatten from scopes.util import keywords as k, flatten, Symbols
k('dummy', 'other', 'cd', 'new')
k('dummy other', 'cd', 'new', 'erp')
dom = Symbols('dom')('crm erp sys')
def test_keywords(): def test_keywords():
assert k.dummy == 'dummy'
assert k.dummy is not 'dummy'
assert k.dummy is k.dummy assert k.dummy is k.dummy
assert k.dummy is not k.other assert k.dummy is not k.other
assert getattr(k, "abcd"[-2:]) is k.cd assert getattr(k, "abcd"[-2:]) is k.cd
assert k['dummy'] is k.dummy assert k['dummy'] is k.dummy
assert k['new'] is k['new'] assert k['new'] is k['new']
assert dom.erp == 'dom.erp'
assert dom.erp is not 'dom.erp'
assert repr(dom.erp) == '<dom.erp>'
assert dom.erp != k.erp
def test_flatten(): def test_flatten():
lst = (1, (None, 2), (3, (4, 5))) lst = (1, (None, 2), (3, (4, 5)))