Skip to content
Open
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
69 changes: 43 additions & 26 deletions lib/pyld/jsonld.py
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,6 @@ def to_rdf(self, input_, options):
issuer = IdentifierIssuer('_:b')
node_map = {'@default': {}}
self._create_node_map(expanded, node_map, '@default', issuer)

# output RDF dataset
dataset = {}
for graph_name, graph in sorted(node_map.items()):
Expand Down Expand Up @@ -1149,18 +1148,31 @@ def has_value(subject, property, value):

:return: True if the value exists, False if not.
"""
# Localize the method lookup to avoids repeated class-attribute resolution in the loop/logic and increase performance
compare = JsonLdProcessor.compare_values

if JsonLdProcessor.has_property(subject, property):
val = subject[property]
is_list = _is_list(val)
if _is_array(val) or is_list:
if is_list:
val = val['@list']
for v in val:
if JsonLdProcessor.compare_values(value, v):
return True

# 1. Normalize @list objects
# Avoid double checking if val is a list.
# If val is a list, then we treat is as an array (i.e. if value occurs in the list, has_value returns true)
if _is_list(val):
val = val['@list']

# 2. Handle Collection (Array/List)
if _is_array(val):
# 'any' with a localized function is the fastest way to loop in Python
return any(compare(value, v) for v in val)

# 3. Handle Single Value
# avoid matching the set of values with an array value parameter
elif not _is_array(value):
return JsonLdProcessor.compare_values(value, val)
# TODO: If the parameter 'value' is an array, there will be no comparison at all if `value` is an array and
# we default to False. Hence, has_value usually returns False unless comparing against another array
# (which is rare here). Is this desirable behavior?
if not _is_array(value):
return compare(value, val)

return False

@staticmethod
Expand Down Expand Up @@ -1282,28 +1294,33 @@ def compare_values(v1, v2):

:return: True if v1 and v2 are considered equal, False if not.
"""
# 1. equal primitives
if not _is_object(v1) and not _is_object(v2) and v1 == v2:
if isinstance(v1, bool) or isinstance(v2, bool):
return type(v1) is type(v2)
# 0. Quick identity check (Performance boost)
if v1 is v2:
return True

# Helper for strict type checking (prevents 1 == True)
def _strict_eq(a, b):
return a == b and (type(a) is type(b) if isinstance(a, bool) or isinstance(b, bool) else True)

# 1. equal primitives
if not _is_object(v1) and not _is_object(v2):
return _strict_eq(v1, v2)

# 2. equal @values
if (_is_value(v1) and _is_value(v2) and
v1['@value'] == v2['@value'] and
v1.get('@type') == v2.get('@type') and
v1.get('@language') == v2.get('@language') and
v1.get('@index') == v2.get('@index')):

if isinstance(v1['@value'], bool) or isinstance(v2['@value'], bool):
return type(v1['@value']) is type(v2['@value'])
return True
if _is_value(v1) and _is_value(v2):
# Using tuples is faster than using and
t1 = (v1.get('@type'), v1.get('@language'), v1.get('@index'))
t2 = (v2.get('@type'), v2.get('@language'), v2.get('@index'))

return t1 == t2 and _strict_eq(v1['@value'], v2['@value'])

# 3. equal @ids
if (_is_object(v1) and '@id' in v1 and
_is_object(v2) and '@id' in v2):
return v1['@id'] == v2['@id']
if _is_object(v1) and _is_object(v2):
# If both are objects, try to get the @id
id1, id2 = v1.get('@id'), v2.get('@id')
return id1 == id2 if id1 is not None else False

# The two values are not the same.
return False

@staticmethod
Expand Down