rearrange class hierarchies for Record / Track with regard to shape, core, storage packages

This commit is contained in:
Helmut Merz 2026-10-02 09:22:04 +02:00
parent 5b54e76327
commit 5f9d8a73d2
9 changed files with 72 additions and 52 deletions

View file

@ -0,0 +1,5 @@
# scopes.api.core.message
"""routes and views for Message objects"""

View file

@ -2,14 +2,12 @@
import asyncio import asyncio
from scopes import util from scopes.util import keywords as k
quit = util.Symbol("quit")
async def loop(q, bhv): async def loop(q, bhv):
while True: while True:
msg = await q.get() msg = await q.get()
if msg is quit: if msg is k.quit:
break break
bhv = await bhv(msg) or bhv bhv = await bhv(msg) or bhv

15
scopes/core/message.py Normal file
View file

@ -0,0 +1,15 @@
# scopes.core.message
"""Generic message definition"""
from scopes import shape
class Message(shape.Record):
headFields = ['domain', 'action', 'class', 'item']
customer = None
def __repr__(self):
return f'<{self.__class__.__name__}: {self.headValues}, {self.data}>'

View file

@ -19,3 +19,31 @@ class Record:
setattr(self, k, self.head[k]) setattr(self, k, self.head[k])
self.data = data or {} self.data = data or {}
@property
def headValues(self):
return [self.head[k] for k in self.headFields]
def set(self, attr, value):
if attr in self.headFields:
if value is None:
value = ''
self.head[attr] = value
setattr(self, attr, value)
else:
raise AttributeError(attr)
def update(self, data, overwrite=False):
if data is None:
return
if overwrite:
self.data = data
else:
self.data.update(data)
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.asDict())
def asDict(self):
return dict(head=self.head, data=self.data)

View file

@ -2,13 +2,14 @@
"""Generic messages (or events) to be stored in SQL database.""" """Generic messages (or events) to be stored in SQL database."""
from scopes.core.message import Message as BaseMessage
from scopes.storage.common import registerContainerClass from scopes.storage.common import registerContainerClass
from scopes.storage.tracking import Container, Track #from scopes.storage.tracking import Container, Track
from scopes.storage.tracking import Container, Record
class Message(Track): class Message(Record, BaseMessage):
headFields = ['domain', 'action', 'class', 'item']
prefix = 'msg' prefix = 'msg'

View file

@ -12,47 +12,22 @@ from sqlalchemy import Table, Column, Index
from sqlalchemy import DateTime, Text, func from sqlalchemy import DateTime, Text, func
from sqlalchemy import and_ from sqlalchemy import and_
from scopes import shape
from scopes.storage.common import registerContainerClass from scopes.storage.common import registerContainerClass
class Track: class Record(shape.Record):
headFields = ['taskId', 'userName']
prefix = 'rec'
def __init__(self, *headValues, data=None, timeStamp=None, trackId=None, def __init__(self, *headValues, data=None, timeStamp=None, trackId=None,
container=None, **kw): container=None, **kw):
self.head = {} super().__init__(*headValues, data=data, **kw)
for k, v in kw.items():
if k in self.headFields:
self.head[k] = kw.pop(k)
for ix, hv in enumerate(headValues):
self.head[self.headFields[ix]] = hv
for k in self.headFields:
if self.head.get(k) is None:
self.head[k] = ''
setattr(self, k, self.head[k])
self.data = data or {}
self.timeStamp = timeStamp self.timeStamp = timeStamp
self.trackId = trackId self.trackId = trackId
self.container = container self.container = container
def set(self, attr, value): def asDict(self):
if attr in self.headFields: return dict(uid=self.uid, head=self.head, data=self.data,
if value is None: timeStamp=str(self.timeStamp)[:19])
value = ''
self.head[attr] = value
setattr(self, attr, value)
else:
raise AttributeError(attr)
def update(self, data, overwrite=False):
if data is None:
return
if overwrite:
self.data = data
else:
self.data.update(data)
@property @property
def uid(self): def uid(self):
@ -66,13 +41,6 @@ class Track:
return '' return ''
return str(self.trackId) return str(self.trackId)
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.asDict())
def asDict(self):
return dict(uid=self.uid, head=self.head, data=self.data,
timeStamp=str(self.timeStamp)[:19])
# shortcuts for compatibility with existing software: # shortcuts for compatibility with existing software:
def updateIndex(self, **kw): def updateIndex(self, **kw):
@ -83,6 +51,11 @@ class Track:
def storeTrack(self): def storeTrack(self):
self.container.update(self) self.container.update(self)
class Track(Record):
headFields = ['taskId', 'userName']
prefix = 'rec'
@registerContainerClass @registerContainerClass
class Container: class Container:

View file

@ -10,7 +10,7 @@ import string
class Symbol(str): class Symbol(str):
def __repr__(self): def __repr__(self):
return f'<Symbol "{self}">' return f'<{self}>'
class Symbols: class Symbols:

View file

@ -5,7 +5,7 @@
import asyncio import asyncio
import pytest import pytest
from scopes.core import actor from scopes.core import actor, message
from scopes.util import keywords as k from scopes.util import keywords as k
collector = [] collector = []
@ -29,17 +29,17 @@ async def test_actor():
async with asyncio.TaskGroup() as group: async with asyncio.TaskGroup() as group:
q1 = actor.create(handle_basic, group) q1 = actor.create(handle_basic, group)
q2 = actor.create(handle_basic, group) q2 = actor.create(handle_basic, group)
await q1.put("actor 1") await q1.put(message.Message(k.test, k.hello))
await q1.put(k.show) await q1.put(k.show)
await q1.put(k.switch) await q1.put(k.switch)
await q1.put(k.show) await q1.put(k.show)
await q1.put("actor 1: Goodbye") await q1.put("actor 1: Goodbye")
await q2.put("actor 2") await q2.put("actor 2")
await q2.put(k.show) await q2.put(k.show)
await q1.put(actor.quit) await q1.put(k.quit)
await q2.put(actor.quit) await q2.put(k.quit)
#await asyncio.wait([t1, t2]) #await asyncio.wait([t1, t2])
#print(collector) print(collector)
assert len(collector) == 6 assert len(collector) == 6
assert collector[-1] == 'actor 1: Goodbye' assert collector[-1] == 'actor 1: Goodbye'

View file

@ -44,7 +44,7 @@ def async_client():
#async with async_client() as clt: #async with async_client() as clt:
#response = await clt.get('/') #response = await clt.get('/')
def test_root(storage): def test_root():
with TestClient(app) as clt: with TestClient(app) as clt:
response = clt.get('/') response = clt.get('/')
assert response.status_code == 200 assert response.status_code == 200