Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions lib/pyld/context_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def __init__(self, shared_cache, document_loader):
self.shared_cache = shared_cache
self.document_loader = document_loader

def resolve(self, active_ctx, context, base, cycles=None):
def resolve(self, active_ctx, context, path, base, cycles=None):
"""
Resolve a context.

Expand Down Expand Up @@ -56,7 +56,7 @@ def resolve(self, active_ctx, context, base, cycles=None):
resolved = self._get(ctx)
if not resolved:
resolved = self._resolve_remote_context(
active_ctx, ctx, base, cycles)
active_ctx, path, ctx, base, cycles)

# add to output and continue
if isinstance(resolved, list):
Expand All @@ -72,7 +72,7 @@ def resolve(self, active_ctx, context, base, cycles=None):
code='invalid local context')
else:
# context is an object, get/create `ResolvedContext` for it
key = canonicalize(dict(ctx)).decode('UTF-8')
key = canonicalize([*path, dict(ctx)]).decode('UTF-8')
resolved = self._get(key)
if not resolved:
# create a new static `ResolvedContext` and cache it
Expand Down Expand Up @@ -102,7 +102,7 @@ def _cache_resolved_context(self, key, resolved, tag):
tag_map[tag] = resolved
return resolved

def _resolve_remote_context(self, active_ctx, url, base, cycles):
def _resolve_remote_context(self, active_ctx, path, url, base, cycles):
# resolve relative URL and fetch context
url = jsonld.prepend_base(base, url)
context, remote_doc = self._fetch_context(active_ctx, url, cycles)
Expand All @@ -112,7 +112,7 @@ def _resolve_remote_context(self, active_ctx, url, base, cycles):
self._resolve_context_urls(context, base)

# resolve, cache, and return context
resolved = self.resolve(active_ctx, context, base, cycles)
resolved = self.resolve(active_ctx, context, path, base, cycles)
self._cache_resolved_context(url, resolved, remote_doc.get('tag'))
return resolved

Expand Down
79 changes: 42 additions & 37 deletions lib/pyld/jsonld.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ def compact(self, input_, ctx, options):
'jsonld.CompactError', cause=cause)

# do compaction
compacted = self._compact(active_ctx, None, expanded, options)
compacted = self._compact(active_ctx, [], expanded, options)

if (options['compactArrays'] and not options['graph'] and
_is_array(compacted)):
Expand Down Expand Up @@ -867,7 +867,7 @@ def expand(self, input_, options):
active_ctx, remote_context, options)

# do expansion
expanded = self._expand(active_ctx, None, document, options,
expanded = self._expand(active_ctx, [], document, options,
inside_list=False)

# optimize away @graph with no other properties
Expand Down Expand Up @@ -1270,7 +1270,7 @@ def process_context(self, active_ctx, local_ctx, options):
options.setdefault('contextResolver',
ContextResolver(_resolved_context_cache, options['documentLoader']))

return self._process_context(active_ctx, local_ctx, options)
return self._process_context(active_ctx, local_ctx, [], options)

def register_rdf_parser(self, content_type, parser):
"""
Expand Down Expand Up @@ -1757,7 +1757,7 @@ def _compare_rdf_triples(t1, t2):

return True

def _compact(self, active_ctx, active_property, element, options):
def _compact(self, active_ctx, path, element, options):
"""
Recursively compacts an element using the given active context. All
values must be in expanded form before this method is called.
Expand All @@ -1770,12 +1770,14 @@ def _compact(self, active_ctx, active_property, element, options):

:return: the compacted value.
"""
active_property = path[-1] if len(path) > 0 else None

# recursively compact array
if _is_array(element):
rval = []
for e in element:
# compact, dropping any None values
e = self._compact(active_ctx, active_property, e, options)
e = self._compact(active_ctx, path, e, options)
if e is not None:
rval.append(e)
if options['compactArrays'] and len(rval) == 1:
Expand All @@ -1792,7 +1794,7 @@ def _compact(self, active_ctx, active_property, element, options):
active_ctx, active_property, '@context')
if ctx is not None:
active_ctx = self._process_context(
active_ctx, ctx, options,
active_ctx, ctx, path, options,
propagate=True,
override_protected=True)

Expand Down Expand Up @@ -1823,7 +1825,7 @@ def _compact(self, active_ctx, active_property, element, options):
JsonLdProcessor.get_context_value(
active_ctx, active_property, '@container'))
if '@list' in container:
return self._compact(active_ctx, active_property, element['@list'], options)
return self._compact(active_ctx, path, element['@list'], options)

# FIXME: avoid misuse of active property as an expanded property?
inside_reverse = (active_property == '@reverse')
Expand All @@ -1842,7 +1844,7 @@ def _compact(self, active_ctx, active_property, element, options):
input_ctx, active_property, '@context')
if property_scoped_ctx is not None:
active_ctx = self._process_context(
active_ctx, property_scoped_ctx, options,
active_ctx, property_scoped_ctx, path, options,
propagate=True,
override_protected=True)

Expand All @@ -1866,7 +1868,7 @@ def _compact(self, active_ctx, active_property, element, options):
input_ctx, compacted_type, '@context')
if ctx is not None:
active_ctx = self._process_context(
active_ctx, ctx, options,
active_ctx, ctx, [*path, compacted_type], options,
propagate=False)

# recursively process element keys in order
Expand Down Expand Up @@ -1915,7 +1917,7 @@ def _compact(self, active_ctx, active_property, element, options):
if expanded_property == '@reverse':
# recursively compact expanded value
compacted_value = self._compact(
active_ctx, '@reverse', expanded_value, options)
active_ctx, [*path, '@reverse'], expanded_value, options)

# handle double-reversed properties
for compacted_property, value in \
Expand Down Expand Up @@ -1945,7 +1947,7 @@ def _compact(self, active_ctx, active_property, element, options):
if expanded_property == '@preserve':
# compact using active_property
compacted_value = self._compact(
active_ctx, active_property, expanded_value, options)
active_ctx, path, expanded_value, options)
if not (_is_array(compacted_value) and len(compacted_value) == 0):
JsonLdProcessor.add_value(rval, expanded_property, compacted_value)
continue
Expand Down Expand Up @@ -2029,7 +2031,7 @@ def _compact(self, active_ctx, active_property, element, options):

# recursively compact expanded item
compacted_item = self._compact(
active_ctx, item_active_property,
active_ctx, [*path, item_active_property],
inner_ if (is_list or is_graph) else expanded_item, options)

# handle @list
Expand Down Expand Up @@ -2157,7 +2159,7 @@ def _compact(self, active_ctx, active_property, element, options):
# whose key maps to @id, recompact without @type
if len(compacted_item.keys()) == 1 and '@id' in expanded_item:
compacted_item = self._compact(
active_ctx, item_active_property,
active_ctx, [*path, item_active_property],
{'@id': expanded_item['@id']}, options)

key = key or self._compact_iri(active_ctx, '@none')
Expand Down Expand Up @@ -2191,7 +2193,7 @@ def _compact(self, active_ctx, active_property, element, options):
return element

def _expand(
self, active_ctx, active_property, element, options,
self, active_ctx, path, element, options,
inside_list=False,
inside_index=False,
type_scoped_ctx=None):
Expand All @@ -2213,6 +2215,7 @@ def _expand(

:return: the expanded value.
"""
active_property = path[-1] if len(path) > 0 else None
# nothing to expand
if element is None:
return element
Expand All @@ -2231,7 +2234,7 @@ def _expand(
for e in element:
# expand element
e = self._expand(
active_ctx, active_property, e, options,
active_ctx, path, e, options,
inside_list=inside_list,
inside_index=inside_index,
type_scoped_ctx=type_scoped_ctx)
Expand Down Expand Up @@ -2293,14 +2296,14 @@ def _expand(
# apply property-scoped context after reverting term-scoped context
if property_scoped_ctx is not None:
active_ctx = self._process_context(
active_ctx, property_scoped_ctx, options,
active_ctx, property_scoped_ctx, path, options,
override_protected=True)

# recursively expand object
# if element has a context, process it
if '@context' in element:
active_ctx = self._process_context(
active_ctx, element['@context'], options)
active_ctx, element['@context'], path, options)

# set the type-scoped context to the context on input, for use later
type_scoped_ctx = active_ctx
Expand All @@ -2322,12 +2325,12 @@ def _expand(
type_scoped_ctx, type_, '@context')
if ctx is not None and ctx is not False:
active_ctx = self._process_context(
active_ctx, ctx, options, propagate=False)
active_ctx, ctx, [*path, key], options, propagate=False)

# process each key and value in element, ignoring @nest content
rval = {}
self._expand_object(
active_ctx, active_property, expanded_active_property,
active_ctx, path, expanded_active_property,
element, rval, options,
inside_list,
type_key,
Expand Down Expand Up @@ -2420,7 +2423,7 @@ def _expand(
return rval

def _expand_object(
self, active_ctx, active_property, expanded_active_property,
self, active_ctx, path, expanded_active_property,
element, expanded_parent, options,
inside_list=False,
type_key=None,
Expand All @@ -2438,6 +2441,7 @@ def _expand_object(

:return: the expanded value.
"""
active_property = path[-1] if len(path) > 0 else None

nests = []
unexpanded_value = None
Expand Down Expand Up @@ -2547,7 +2551,7 @@ def _expand_object(
if (expanded_property == '@included' and
self._processing_mode(active_ctx, 1.1)):
included_result = JsonLdProcessor.arrayify(
self._expand(active_ctx, active_property, value, options))
self._expand(active_ctx, path, value, options))
if not all(_is_subject(v) for v in included_result):
raise JsonLdError(
'Invalid JSON-LD syntax; "values of @included '
Expand Down Expand Up @@ -2636,7 +2640,7 @@ def _expand_object(
code='invalid @reverse value')

expanded_value = self._expand(
active_ctx, '@reverse', value, options,
active_ctx, [*path, '@reverse'], value, options,
inside_list=inside_list)

# properties double-reversed
Expand Down Expand Up @@ -2680,7 +2684,7 @@ def _expand_object(
term_ctx = active_ctx
ctx = JsonLdProcessor.get_context_value(active_ctx, key, '@context')
if ctx is not None:
term_ctx = self._process_context(active_ctx, ctx, options,
term_ctx = self._process_context(active_ctx, ctx, [*path, key], options,
propagate=True, override_protected=True)

container = JsonLdProcessor.arrayify(
Expand All @@ -2700,14 +2704,14 @@ def _expand_object(
property_index = None
if index_key != '@index':
property_index = self._expand_iri(active_ctx, index_key, vocab=options.get('base', ''))
expanded_value = self._expand_index_map(term_ctx, key, value, index_key, as_graph, property_index, options)
expanded_value = self._expand_index_map(term_ctx, [*path, key], value, index_key, as_graph, property_index, options)
elif '@id' in container and _is_object(value):
as_graph = '@graph' in container
expanded_value = self._expand_index_map(term_ctx, key, value, '@id', as_graph, None, options)
expanded_value = self._expand_index_map(term_ctx, [*path, key], value, '@id', as_graph, None, options)
elif '@type' in container and _is_object(value):
expanded_value = self._expand_index_map(
self._revert_to_previous_context(term_ctx),
key, value, '@type', False, None, options)
[*path, key], value, '@type', False, None, options)
else:
# recurse into @list or @set
is_list = (expanded_property == '@list')
Expand All @@ -2716,7 +2720,7 @@ def _expand_object(
if is_list and expanded_active_property == '@graph':
next_active_property = None
expanded_value = self._expand(
term_ctx, next_active_property, value, options,
term_ctx, [*path, next_active_property], value, options,
inside_list=is_list)
elif JsonLdProcessor.get_context_value(active_ctx, key, '@type') == '@json':
expanded_value = {
Expand All @@ -2726,7 +2730,7 @@ def _expand_object(
else:
# recursively expand value w/key as new active property
expanded_value = self._expand(
term_ctx, key, value, options,
term_ctx, [*path, key], value, options,
inside_list=False)

# drop None values if property is not @value (dropped below)
Expand Down Expand Up @@ -2798,7 +2802,7 @@ def _expand_object(
'jsonld.SyntaxError', {'value': nv},
code='invalid @nest value')
self._expand_object(
active_ctx, active_property, expanded_active_property,
active_ctx, path, expanded_active_property,
nv, expanded_parent, options,
inside_list=inside_list,
type_key=type_key,
Expand Down Expand Up @@ -3013,7 +3017,7 @@ def _from_rdf(self, dataset, options):

return result

def _process_context(self, active_ctx, local_ctx, options,
def _process_context(self, active_ctx, local_ctx, path, options,
override_protected=False,
propagate=True,
validate_scoped=True,
Expand Down Expand Up @@ -3046,7 +3050,7 @@ def _process_context(self, active_ctx, local_ctx, options,
return self._clone_active_context(active_ctx)

# resolve contexts
resolved = options['contextResolver'].resolve(active_ctx, local_ctx, options.get('base', ''))
resolved = options['contextResolver'].resolve(active_ctx, local_ctx, path, options.get('base', ''))

# override propagate if first resolved context has `@propagate`
if _is_object(resolved[0].document) and isinstance(resolved[0].document.get('@propagate'), bool):
Expand Down Expand Up @@ -3144,7 +3148,7 @@ def _process_context(self, active_ctx, local_ctx, options,
if '_uuid' not in active_ctx:
active_ctx['_uuid'] = str(uuid.uuid1())
resolved_import = options['contextResolver'].resolve(
active_ctx, value, options.get('base', ''))
active_ctx, value, path, options.get('base', ''))
if len(resolved_import) != 1:
raise JsonLdError(
'Invalid JSON-LD syntax; @import must reference a single context.',
Expand Down Expand Up @@ -3304,7 +3308,7 @@ def _process_context(self, active_ctx, local_ctx, options,
if process:
try:
self._process_context(
rval, key_ctx, options,
rval, key_ctx,[*path, k] ,options,
override_protected=True,
cycles=cycles)
except Exception as cause:
Expand Down Expand Up @@ -3385,7 +3389,7 @@ def _expand_language_map(self, active_ctx, language_map, direction):
rval.append(val)
return rval

def _expand_index_map(self, active_ctx, active_property, value, index_key, as_graph, property_index, options):
def _expand_index_map(self, active_ctx, path, value, index_key, as_graph, property_index, options):
"""
Expands in index, id or type map.

Expand All @@ -3396,18 +3400,19 @@ def _expand_index_map(self, active_ctx, active_property, value, index_key, as_gr
:param as_graph: contents should form a named graph
:param property_index: index is a property
"""
active_property = path[-1] if len(path) > 0 else None
rval = []
is_type_index = index_key == '@type'
for k, v in sorted(value.items()):
if is_type_index:
ctx = JsonLdProcessor.get_context_value(
active_ctx, k, '@context')
if ctx is not None:
active_ctx = self._process_context(active_ctx, ctx, options,
active_ctx = self._process_context(active_ctx, ctx, path, options,
propagate=False)

v = self._expand(
active_ctx, active_property,
active_ctx, path,
JsonLdProcessor.arrayify(v),
options,
inside_list=False,
Expand Down Expand Up @@ -5507,7 +5512,7 @@ def _expand_iri(

# resolve against base
rval = value
if base and '@base' in active_ctx:
if base != None and '@base' in active_ctx:
# The None case preserves rval as potentially relative
if active_ctx['@base'] is not None:
rval = prepend_base(prepend_base(base, active_ctx['@base']), rval)
Expand Down