1
0
datagraph/datagraph/schemeld.py
2024-07-08 18:54:14 +02:00

107 lines
3.2 KiB
Python

import urllib.parse
STRICT_VALIDATION = True
def canonical_keys(base_key, context):
if isinstance(base_key, urllib.parse.ParseResult):
return [base_key]
if not isinstance(base_key, str):
return [base_key]
elif base_key.startswith('@'):
return [base_key]
if context is None:
return [base_key]
return [context._replace(path=base_key), base_key]
class Concept:
def __init__(self, context, pairs):
self.pairs = []
for k, v in pairs.items():
keys = canonical_keys(k, context)
self.pairs.append(
{'canonical_key': keys[0], 'keys': set(keys), 'values': v}
)
self.regenerate_by_keys()
def regenerate_by_keys(self):
self.by_keys = {k: pair for pair in self.pairs for k in pair['keys']}
def __copy__(self):
new = Concept(None, {})
for p in self.pairs:
new.pairs.append(
{
'canonical_key': p['canonical_key'],
'keys': set(p['keys']),
'values': p['values'],
}
)
new.regenerate_by_keys()
return new
def get(self, key, default=None):
pairs = self.by_keys.get(key, None)
return pairs['values'] if pairs is not None else default
def getlist(self, key):
result = self.get(key)
if result is None:
return []
assert isinstance(result, list), 'Not a list: ' + str(result)
return [r['value'] for r in result]
def keys(self):
for pair in self.pairs:
yield pair['canonical_key']
def setdefault(self, key, value):
if key not in self.by_keys:
self[key] = value
return self.by_keys[key]['values']
def to_dict(self):
return {p['canonical_key']: p['values'] for p in self.pairs}
def __getitem__(self, key):
return self.by_keys[key]['values']
def __setitem__(self, key, value):
if STRICT_VALIDATION:
if not isinstance(key, str) or key != '@id':
assert isinstance(value, list), value
for v in value:
assert isinstance(v, dict), value
assert 'value' in v, value
for subk in v:
assert not isinstance(v[subk], list), value
if key in self.by_keys:
self.by_keys[key]['values'] = value
else:
pair = {'canonical_key': key, 'keys': {key}, 'values': value}
self.pairs.append(pair)
self.by_keys[key] = pair
def __contains__(self, key):
return key in self.by_keys
def __delitem__(self, key):
self.pairs.remove(self.by_keys[key])
del self.by_keys[key]
def __repr__(self):
if id := self.by_keys.get('@id'):
return 'Concept {{ @id = {} }}'.format(id['values'])
return 'Concept ' + str({p['canonical_key']: p['values'] for p in self.pairs})
def __str__(self):
return repr(self)
def set_canonical_key(self, new_canonical_key, key=None):
if key is None:
key = new_canonical_key
self.by_keys[key]['canonical_key'] = new_canonical_key