work in progress: concept map, starting with types

This commit is contained in:
Helmut Merz 2024-03-14 10:21:43 +01:00
parent 0b765ad16b
commit 3e1127e798
6 changed files with 91 additions and 12 deletions

View file

@ -5,7 +5,7 @@ from zope.interface import Interface
class ITraversable(Interface): class ITraversable(Interface):
def get(key, default): def get(key, default=None):
"""Return the item addressed by `key`; return `default` if not found.""" """Return the item addressed by `key`; return `default` if not found."""
@ -15,7 +15,7 @@ class IContainer(ITraversable):
"""Return a sequence of child objects.""" """Return a sequence of child objects."""
def __getitem__(key): def __getitem__(key):
"""Return the item addressed by `key`; rais KeyError if not found.""" """Return the item addressed by `key`; raise KeyError if not found."""
def __setitem__(key, value): def __setitem__(key, value):
"""Store the `value` under the `key`. """Store the `value` under the `key`.
@ -24,6 +24,17 @@ class IContainer(ITraversable):
and the value object (e.g. `parent´ and `name`) are stored correctly.""" and the value object (e.g. `parent´ and `name`) are stored correctly."""
class IConcept(IContainer):
def parents(*predicates):
"""Return a sequence of `Triple`s in which this object is
referenced as `second`."""
def children(*predicates):
"""Return a sequence of `Triple`s in which this object is
referenced as `first`."""
class IView(Interface): class IView(Interface):
def __call__(): def __call__():

View file

@ -4,13 +4,16 @@ import json
from zope.interface import implementer from zope.interface import implementer
from scopes.interfaces import IContainer, IView from scopes.interfaces import IContainer, IView
views = {} views = {} # registry for all views: {name: {prefix: viewClass, ...}, ...}
def register(contextClass, name): def register(name, *contextClasses):
"""Use as decorator: `@register(name, class, ...).
class `None` means default view for all classes."""
def doRegister(viewClass): def doRegister(viewClass):
nameEntry = views.setdefault(name, {}) nameEntry = views.setdefault(name, {})
key = contextClass and contextClass.prefix or '' for cl in contextClasses:
nameEntry[key] = viewClass key = cl and cl.prefix or ''
nameEntry[key] = viewClass
return viewClass return viewClass
return doRegister return doRegister
@ -26,8 +29,8 @@ def getView(request, ob, name):
return viewClass(ob, request) return viewClass(ob, request)
@register(None, 'index.html') @register('index.html', None)
@register(None, 'index.json') @register('index.json', None)
@implementer(IView) @implementer(IView)
class DefaultView: class DefaultView:

View file

@ -1,12 +1,66 @@
# scopes.storage.concept # scopes.storage.concept
"""Abstract base classes for concept map application classes.""" """Core classes for concept map structure."""
from zope.interface import implementer
from scopes.interfaces import IConcept
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
@implementer(IConcept)
class Concept(Track): class Concept(Track):
headFields = ['name'] headFields = ['name']
class Concepts(Container):
insertOnChange = False
class Predicate(Concept):
prefix = 'pred'
@registerContainerClass
class Predicates(Concepts):
itemFactory = Predicate
tableName = 'preds'
class Triple(Track):
headFields = ['first', 'second', 'predicate']
prefix = 'rel'
@registerContainerClass
class Rels(Container):
itemFactory = Triple
indexes = [('first', 'predicate', 'second'),
('first', 'second'), ('predicate', 'second')]
tableName = 'rels'
insertOnChange = False
# types stuff
class Type(Concept):
headFields = ['name', 'prefix']
prefix = 'type'
def get(key, default=None):
return self.container.queryLast(name=key) or default
@registerContainerClass
class Types(Concepts):
itemFactory = Type
indexes = [('name',), ('prefix',)]
tableName = 'types'

View file

@ -9,7 +9,6 @@ from scopes.storage.tracking import Container, Track
@implementer(IContainer) @implementer(IContainer)
class Folder(Track): class Folder(Track):
"""Needs docstring to be traversable."""
headFields = ['parent', 'name', 'ref'] headFields = ['parent', 'name', 'ref']
prefix = 'fldr' prefix = 'fldr'

View file

@ -21,7 +21,10 @@ class Test(unittest.TestCase):
def test_002_folder(self): def test_002_folder(self):
tlib_storage.test_folder(self, config) tlib_storage.test_folder(self, config)
def test_003_server(self): def test_003_type(self):
tlib_storage.test_type(self, config)
def test_013_server(self):
tlib_server.test_app(self, config) tlib_server.test_app(self, config)

View file

@ -3,7 +3,7 @@
"""Test implementation for the `scopes.storage` package.""" """Test implementation for the `scopes.storage` package."""
from datetime import datetime from datetime import datetime
from scopes.storage import folder, tracking from scopes.storage import concept, folder, tracking
def test_tracking(self, config): def test_tracking(self, config):
@ -73,3 +73,12 @@ def test_folder(self, config):
storage.commit() storage.commit()
def test_type(self, config):
storage = config.storageFactory(config.dbschema)
storage.dropTable('types')
types = storage.create(concept.Types)
tid01 = types.save(concept.Type('type', 'type'))
self.assertEqual(tid01, 1)
storage.commit()