Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/rdflib_jsonld/context.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
| author | shellac |
|---|---|
| date | Mon, 22 Mar 2021 18:12:50 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:4f3585e2f14b |
|---|---|
| 1 # -*- coding: utf-8 -*- | |
| 2 """ | |
| 3 Implementation of the JSON-LD Context structure. See: | |
| 4 | |
| 5 http://json-ld.org/ | |
| 6 | |
| 7 """ | |
| 8 from collections import namedtuple | |
| 9 from rdflib.namespace import RDF | |
| 10 | |
| 11 from ._compat import str, str | |
| 12 from .keys import (BASE, CONTAINER, CONTEXT, GRAPH, ID, INDEX, LANG, LIST, | |
| 13 REV, SET, TYPE, VALUE, VOCAB) | |
| 14 from . import errors | |
| 15 from .util import source_to_json, urljoin, urlsplit, split_iri, norm_url | |
| 16 | |
| 17 | |
| 18 NODE_KEYS = set([LANG, ID, TYPE, VALUE, LIST, SET, REV, GRAPH]) | |
| 19 | |
| 20 class Defined(int): pass | |
| 21 UNDEF = Defined(0) | |
| 22 | |
| 23 | |
| 24 class Context(object): | |
| 25 | |
| 26 def __init__(self, source=None, base=None): | |
| 27 self.language = None | |
| 28 self.vocab = None | |
| 29 self.base = base | |
| 30 self.doc_base = base | |
| 31 self.terms = {} | |
| 32 # _alias maps NODE_KEY to list of aliases | |
| 33 self._alias = {} | |
| 34 self._lookup = {} | |
| 35 self._prefixes = {} | |
| 36 self.active = False | |
| 37 if source: | |
| 38 self.load(source) | |
| 39 | |
| 40 @property | |
| 41 def base(self): | |
| 42 return self._base | |
| 43 | |
| 44 @base.setter | |
| 45 def base(self, base): | |
| 46 if base: | |
| 47 hash_index = base.find('#') | |
| 48 if hash_index > -1: | |
| 49 base = base[0:hash_index] | |
| 50 self._base = self.resolve_iri(base) if ( | |
| 51 hasattr(self, '_base') and base is not None) else base | |
| 52 self._basedomain = '%s://%s' % urlsplit(base)[0:2] if base else None | |
| 53 | |
| 54 def subcontext(self, source): | |
| 55 # IMPROVE: to optimize, implement SubContext with parent fallback support | |
| 56 ctx = Context() | |
| 57 ctx.language = self.language | |
| 58 ctx.vocab = self.vocab | |
| 59 ctx.base = self.base | |
| 60 ctx.doc_base = self.doc_base | |
| 61 ctx._alias = self._alias.copy() | |
| 62 ctx.terms = self.terms.copy() | |
| 63 ctx._lookup = self._lookup.copy() | |
| 64 ctx._prefixes = self._prefixes.copy() | |
| 65 ctx.load(source) | |
| 66 return ctx | |
| 67 | |
| 68 def get_id(self, obj): | |
| 69 return self._get(obj, ID) | |
| 70 | |
| 71 def get_type(self, obj): | |
| 72 return self._get(obj, TYPE) | |
| 73 | |
| 74 def get_language(self, obj): | |
| 75 return self._get(obj, LANG) | |
| 76 | |
| 77 def get_value(self, obj): | |
| 78 return self._get(obj, VALUE) | |
| 79 | |
| 80 def get_graph(self, obj): | |
| 81 return self._get(obj, GRAPH) | |
| 82 | |
| 83 def get_list(self, obj): | |
| 84 return self._get(obj, LIST) | |
| 85 | |
| 86 def get_set(self, obj): | |
| 87 return self._get(obj, SET) | |
| 88 | |
| 89 def get_rev(self, obj): | |
| 90 return self._get(obj, REV) | |
| 91 | |
| 92 def _get(self, obj, key): | |
| 93 for alias in self._alias.get(key, []): | |
| 94 if alias in obj: | |
| 95 return obj.get(alias) | |
| 96 return obj.get(key) | |
| 97 | |
| 98 def get_key(self, key): | |
| 99 return self.get_keys(key)[0] | |
| 100 | |
| 101 def get_keys(self, key): | |
| 102 return self._alias.get(key, [key]) | |
| 103 | |
| 104 lang_key = property(lambda self: self.get_key(LANG)) | |
| 105 id_key = property(lambda self: self.get_key(ID)) | |
| 106 type_key = property(lambda self: self.get_key(TYPE)) | |
| 107 value_key = property(lambda self: self.get_key(VALUE)) | |
| 108 list_key = property(lambda self: self.get_key(LIST)) | |
| 109 rev_key = property(lambda self: self.get_key(REV)) | |
| 110 graph_key = property(lambda self: self.get_key(GRAPH)) | |
| 111 | |
| 112 def add_term(self, name, idref, coercion=UNDEF, container=UNDEF, | |
| 113 language=UNDEF, reverse=False): | |
| 114 term = Term(idref, name, coercion, container, language, reverse) | |
| 115 self.terms[name] = term | |
| 116 self._lookup[(idref, coercion or language, container, reverse)] = term | |
| 117 self._prefixes[idref] = name | |
| 118 | |
| 119 def find_term(self, idref, coercion=None, container=UNDEF, | |
| 120 language=None, reverse=False): | |
| 121 lu = self._lookup | |
| 122 if coercion is None: | |
| 123 coercion = language | |
| 124 if coercion is not UNDEF and container: | |
| 125 found = lu.get((idref, coercion, container, reverse)) | |
| 126 if found: return found | |
| 127 if coercion is not UNDEF: | |
| 128 found = lu.get((idref, coercion, UNDEF, reverse)) | |
| 129 if found: return found | |
| 130 if container: | |
| 131 found = lu.get((idref, coercion, container, reverse)) | |
| 132 if found: return found | |
| 133 elif language: | |
| 134 found = lu.get((idref, UNDEF, LANG, reverse)) | |
| 135 if found: return found | |
| 136 else: | |
| 137 found = lu.get((idref, coercion or UNDEF, SET, reverse)) | |
| 138 if found: return found | |
| 139 return lu.get((idref, UNDEF, UNDEF, reverse)) | |
| 140 | |
| 141 def resolve(self, curie_or_iri): | |
| 142 iri = self.expand(curie_or_iri, False) | |
| 143 if self.isblank(iri): | |
| 144 return iri | |
| 145 return self.resolve_iri(iri) | |
| 146 | |
| 147 def resolve_iri(self, iri): | |
| 148 return norm_url(self._base, iri) | |
| 149 | |
| 150 def isblank(self, ref): | |
| 151 return ref.startswith('_:') | |
| 152 | |
| 153 def expand(self, term_curie_or_iri, use_vocab=True): | |
| 154 if use_vocab: | |
| 155 term = self.terms.get(term_curie_or_iri) | |
| 156 if term: | |
| 157 return term.id | |
| 158 is_term, pfx, local = self._prep_expand(term_curie_or_iri) | |
| 159 if pfx == '_': | |
| 160 return term_curie_or_iri | |
| 161 if pfx is not None: | |
| 162 ns = self.terms.get(pfx) | |
| 163 if ns and ns.id: | |
| 164 return ns.id + local | |
| 165 elif is_term and use_vocab: | |
| 166 if self.vocab: | |
| 167 return self.vocab + term_curie_or_iri | |
| 168 return None | |
| 169 return self.resolve_iri(term_curie_or_iri) | |
| 170 | |
| 171 def shrink_iri(self, iri): | |
| 172 ns, name = split_iri(str(iri)) | |
| 173 pfx = self._prefixes.get(ns) | |
| 174 if pfx: | |
| 175 return ":".join((pfx, name)) | |
| 176 elif self._base: | |
| 177 if str(iri) == self._base: | |
| 178 return "" | |
| 179 elif iri.startswith(self._basedomain): | |
| 180 return iri[len(self._basedomain):] | |
| 181 return iri | |
| 182 | |
| 183 def to_symbol(self, iri): | |
| 184 iri = str(iri) | |
| 185 term = self.find_term(iri) | |
| 186 if term: | |
| 187 return term.name | |
| 188 ns, name = split_iri(iri) | |
| 189 if ns == self.vocab: | |
| 190 return name | |
| 191 pfx = self._prefixes.get(ns) | |
| 192 if pfx: | |
| 193 return ":".join((pfx, name)) | |
| 194 return iri | |
| 195 | |
| 196 def load(self, source, base=None): | |
| 197 self.active = True | |
| 198 sources = [] | |
| 199 source = source if isinstance(source, list) else [source] | |
| 200 self._prep_sources(base, source, sources) | |
| 201 for source_url, source in sources: | |
| 202 self._read_source(source, source_url) | |
| 203 | |
| 204 def _prep_sources(self, base, inputs, sources, referenced_contexts=None, | |
| 205 in_source_url=None): | |
| 206 referenced_contexts = referenced_contexts or set() | |
| 207 for source in inputs: | |
| 208 if isinstance(source, str): | |
| 209 source_url = urljoin(base, source) | |
| 210 if source_url in referenced_contexts: | |
| 211 raise errors.RECURSIVE_CONTEXT_INCLUSION | |
| 212 referenced_contexts.add(source_url) | |
| 213 source = source_to_json(source_url) | |
| 214 if CONTEXT not in source: | |
| 215 raise errors.INVALID_REMOTE_CONTEXT | |
| 216 else: | |
| 217 source_url = in_source_url | |
| 218 | |
| 219 if isinstance(source, dict): | |
| 220 if CONTEXT in source: | |
| 221 source = source[CONTEXT] | |
| 222 source = source if isinstance(source, list) else [source] | |
| 223 if isinstance(source, list): | |
| 224 self._prep_sources(base, source, sources, referenced_contexts, source_url) | |
| 225 else: | |
| 226 sources.append((source_url, source)) | |
| 227 | |
| 228 def _read_source(self, source, source_url=None): | |
| 229 self.vocab = source.get(VOCAB, self.vocab) | |
| 230 for key, value in list(source.items()): | |
| 231 if key == LANG: | |
| 232 self.language = value | |
| 233 elif key == VOCAB: | |
| 234 continue | |
| 235 elif key == BASE: | |
| 236 if source_url: | |
| 237 continue | |
| 238 self.base = value | |
| 239 else: | |
| 240 self._read_term(source, key, value) | |
| 241 | |
| 242 def _read_term(self, source, name, dfn): | |
| 243 idref = None | |
| 244 if isinstance(dfn, dict): | |
| 245 #term = self._create_term(source, key, value) | |
| 246 rev = dfn.get(REV) | |
| 247 idref = rev or dfn.get(ID, UNDEF) | |
| 248 if idref == TYPE: | |
| 249 idref = str(RDF.type) | |
| 250 elif idref is not UNDEF: | |
| 251 idref = self._rec_expand(source, idref) | |
| 252 elif ':' in name: | |
| 253 idref = self._rec_expand(source, name) | |
| 254 elif self.vocab: | |
| 255 idref = self.vocab + name | |
| 256 coercion = dfn.get(TYPE, UNDEF) | |
| 257 if coercion and coercion not in (ID, TYPE, VOCAB): | |
| 258 coercion = self._rec_expand(source, coercion) | |
| 259 self.add_term(name, idref, coercion, | |
| 260 dfn.get(CONTAINER, UNDEF), dfn.get(LANG, UNDEF), bool(rev)) | |
| 261 else: | |
| 262 if isinstance(dfn, str): | |
| 263 idref = self._rec_expand(source, dfn) | |
| 264 self.add_term(name, idref) | |
| 265 | |
| 266 if idref in NODE_KEYS: | |
| 267 self._alias.setdefault(idref, []).append(name) | |
| 268 | |
| 269 def _rec_expand(self, source, expr, prev=None): | |
| 270 if expr == prev or expr in NODE_KEYS: | |
| 271 return expr | |
| 272 | |
| 273 is_term, pfx, nxt = self._prep_expand(expr) | |
| 274 if pfx: | |
| 275 iri = self._get_source_id(source, pfx) | |
| 276 if iri is None: | |
| 277 if pfx + ':' == self.vocab: | |
| 278 return expr | |
| 279 else: | |
| 280 term = self.terms.get(pfx) | |
| 281 if term: | |
| 282 iri = term.id | |
| 283 | |
| 284 if iri is None: | |
| 285 nxt = expr | |
| 286 else: | |
| 287 nxt = iri + nxt | |
| 288 else: | |
| 289 nxt = self._get_source_id(source, nxt) or nxt | |
| 290 if ':' not in nxt and self.vocab: | |
| 291 return self.vocab + nxt | |
| 292 | |
| 293 return self._rec_expand(source, nxt, expr) | |
| 294 | |
| 295 def _prep_expand(self, expr): | |
| 296 if ':' not in expr: | |
| 297 return True, None, expr | |
| 298 pfx, local = expr.split(':', 1) | |
| 299 if not local.startswith('//'): | |
| 300 return False, pfx, local | |
| 301 else: | |
| 302 return False, None, expr | |
| 303 | |
| 304 def _get_source_id(self, source, key): | |
| 305 # .. from source dict or if already defined | |
| 306 term = source.get(key) | |
| 307 if term is None: | |
| 308 dfn = self.terms.get(key) | |
| 309 if dfn: | |
| 310 term = dfn.id | |
| 311 elif isinstance(term, dict): | |
| 312 term = term.get(ID) | |
| 313 return term | |
| 314 | |
| 315 | |
| 316 Term = namedtuple('Term', | |
| 317 'id, name, type, container, language, reverse') | |
| 318 Term.__new__.__defaults__ = (UNDEF, UNDEF, UNDEF, False) |
