[Python-modules-commits] [python-pyld] 99/276: Fixes to comply with updates to the spec(s).
Wolfgang Borgert
debacle at moszumanska.debian.org
Wed Oct 8 23:47:58 UTC 2014
This is an automated email from the git hooks/post-receive script.
debacle pushed a commit to branch master
in repository python-pyld.
commit 4815d7876a9fcea95f8599ad56cf2eb640af7d6d
Author: Dave Longley <dlongley at digitalbazaar.com>
Date: Wed Sep 26 16:23:41 2012 -0400
Fixes to comply with updates to the spec(s).
- Add @vocab support.
- Convert native types in fromRDF().
- Use new canonical form for doubles in toRDF().
- Support xsd:string special cases.
- Keep going when JSON-LD exceptions occur in test runner.
---
lib/pyld/jsonld.py | 164 +++++++++++++++++++++++++++++++++++++++--------------
tests/runtests.py | 61 +++++++++++---------
2 files changed, 156 insertions(+), 69 deletions(-)
diff --git a/lib/pyld/jsonld.py b/lib/pyld/jsonld.py
index ec4350a..5fef612 100644
--- a/lib/pyld/jsonld.py
+++ b/lib/pyld/jsonld.py
@@ -31,6 +31,7 @@ from httplib import HTTPSConnection
XSD_BOOLEAN = 'http://www.w3.org/2001/XMLSchema#boolean'
XSD_DOUBLE = 'http://www.w3.org/2001/XMLSchema#double'
XSD_INTEGER = 'http://www.w3.org/2001/XMLSchema#integer'
+XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string'
# RDF constants
RDF_FIRST = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first'
@@ -53,7 +54,8 @@ KEYWORDS = [
'@preserve',
'@set',
'@type',
- '@value']
+ '@value',
+ '@vocab']
# Restraints
MAX_CONTEXT_URLS = 10
@@ -130,7 +132,9 @@ def from_rdf(input, options=None):
:param [options]: the options to use:
[format] the format if input is not an array:
'application/nquads' for N-Quads (default).
- [notType] true to use rdf:type, false to use @type (default).
+ [useRdfType] true to use rdf:type, false to use @type (default: False).
+ [useNativeTypes] true to convert XSD types into native types
+ (boolean, integer, double), false not to (default: True).
:return: the JSON-LD output.
"""
@@ -474,7 +478,8 @@ class JsonLdProcessor:
# set default options
options = options or {}
options.setdefault('format', 'application/nquads')
- options.setdefault('notType', False)
+ options.setdefault('useRdfType', False)
+ options.setdefault('useNativeTypes', True)
if not _is_array(statements):
# supported formats (processor-specific and global)
@@ -950,7 +955,7 @@ class JsonLdProcessor:
.replace('\r', '\\r')
.replace('\"', '\\"'))
quad += '"' + o['nominalValue'] + '"'
- if 'datatype' in o:
+ if 'datatype' in o and o['datatype']['nominalValue'] != XSD_STRING:
quad += '^^<' + o['datatype']['nominalValue'] + '>'
elif 'language' in o:
quad += '@' + o['language']
@@ -1208,7 +1213,7 @@ class JsonLdProcessor:
if _is_array(e) and property_is_list:
# lists of lists are illegal
raise JsonLdError(
- 'Invalid JSON-LD syntax lists of lists are not '
+ 'Invalid JSON-LD syntax; lists of lists are not '
'permitted.', 'jsonld.SyntaxError')
# drop None values
elif e is not None:
@@ -1242,7 +1247,7 @@ class JsonLdProcessor:
# syntax error if @id is not a string
if prop == '@id' and not _is_string(value):
raise JsonLdError(
- 'Invalid JSON-LD syntax "@id" value must a string.',
+ 'Invalid JSON-LD syntax; "@id" value must a string.',
'jsonld.SyntaxError', {'value': value})
# validate @type value
@@ -1253,7 +1258,7 @@ class JsonLdProcessor:
if (prop == '@graph' and not
(_is_object(value) or _is_array(value))):
raise JsonLdError(
- 'Invalid JSON-LD syntax "@value" value must not be an '
+ 'Invalid JSON-LD syntax; "@value" value must not be an '
'object or an array.',
'jsonld.SyntaxError', {'value': value})
@@ -1261,14 +1266,14 @@ class JsonLdProcessor:
if (prop == '@value' and
(_is_object(value) or _is_array(value))):
raise JsonLdError(
- 'Invalid JSON-LD syntax "@value" value must not be an '
+ 'Invalid JSON-LD syntax; "@value" value must not be an '
'object or an array.',
'jsonld.SyntaxError', {'value': value})
# @language must be a string
if (prop == '@language' and not _is_string(value)):
raise JsonLdError(
- 'Invalid JSON-LD syntax "@language" value must not be '
+ 'Invalid JSON-LD syntax; "@language" value must not be '
'a string.', 'jsonld.SyntaxError', {'value': value})
# recurse into @list or @set keeping active property
@@ -1277,7 +1282,7 @@ class JsonLdProcessor:
value = self._expand(ctx, property, value, options, is_list)
if is_list and _is_list(value):
raise JsonLdError(
- 'Invalid JSON-LD syntax lists of lists are not '
+ 'Invalid JSON-LD syntax; lists of lists are not '
'permitted.', 'jsonld.SyntaxError')
else:
# update active property and recursively expand value
@@ -1322,14 +1327,14 @@ class JsonLdProcessor:
if ((count == 2 and '@type' not in rval and
'@language' not in rval) or count > 2):
raise JsonLdError(
- 'Invalid JSON-LD syntax an element containing '
+ 'Invalid JSON-LD syntax; an element containing '
'"@value" must have at most one other property which '
'can be "@type" or "@language".',
'jsonld.SyntaxError', {'element': rval})
# value @type must be a string
if '@type' in rval and not _is_string(rval['@type']):
raise JsonLdError(
- 'Invalid JSON-LD syntax the "@type" value of an '
+ 'Invalid JSON-LD syntax; the "@type" value of an '
'element containing "@value" must be a string.',
'jsonld.SyntaxError', {'element': rval})
# drop None @values
@@ -1342,7 +1347,7 @@ class JsonLdProcessor:
elif '@set' in rval or '@list' in rval:
if count != 1:
raise JsonLdError(
- 'Invalid JSON-LD syntax if an element has the '
+ 'Invalid JSON-LD syntax; if an element has the '
'property "@set" or "@list", then it must be its '
'only property.',
'jsonld.SyntaxError', {'element': rval})
@@ -1520,7 +1525,8 @@ class JsonLdProcessor:
list_map = graph['listMap']
entry = list_map.setdefault(s, {})
# set object value
- entry['first'] = self._rdf_to_object(o)
+ entry['first'] = self._rdf_to_object(
+ o, options['useNativeTypes'])
continue
# handle other element in @list
@@ -1544,14 +1550,14 @@ class JsonLdProcessor:
# convert to @type unless options indicate to treat rdf:type as
# property
- if p == RDF_TYPE and not options['notType']:
+ if p == RDF_TYPE and not options['useRdfType']:
# add value of object as @type
JsonLdProcessor.add_value(
value, '@type', o['nominalValue'],
{'propertyIsArray': True})
else:
# add property to value as needed
- object = self._rdf_to_object(o)
+ object = self._rdf_to_object(o, options['useNativeTypes'])
JsonLdProcessor.add_value(
value, p, object, {'propertyIsArray': True})
@@ -1619,23 +1625,26 @@ class JsonLdProcessor:
value = 'true' if value else 'false'
datatype = datatype or XSD_BOOLEAN
elif _is_double(value):
- # printf('%1.15e') equivalent
- value = '%1.15e' % value
+ # canonical double representation
+ value = re.sub(r'(\d)0*E\+?0*(\d)', r'\1E\2',
+ ('%1.15E' % value))
datatype = datatype or XSD_DOUBLE
else:
value = str(value)
datatype = datatype or XSD_INTEGER
+
+ # default to xsd:string datatype
+ datatype = datatype or XSD_STRING
object = {
'nominalValue': value,
- 'interfaceName': 'LiteralNode'
- }
- if datatype is not None:
- object['datatype'] = {
+ 'interfaceName': 'LiteralNode',
+ 'datatype': {
'nominalValue': datatype,
'interfaceName': 'IRI'
}
- elif '@language' in element:
+ }
+ if '@language' in element and datatype == XSD_STRING:
object['language'] = element['@language']
# emit literal
statement = {
@@ -1766,7 +1775,7 @@ class JsonLdProcessor:
# context must be an object by now, all URLs resolved before this call
if not _is_object(ctx):
raise JsonLdError(
- 'Invalid JSON-LD syntax @context must be an object.',
+ 'Invalid JSON-LD syntax; @context must be an object.',
'jsonld.SyntaxError', {'context': ctx})
# define context mappings for keys in local context
@@ -1824,11 +1833,12 @@ class JsonLdProcessor:
return rval
- def _rdf_to_object(self, o):
+ def _rdf_to_object(self, o, use_native_types):
"""
Converts an RDF statement object to a JSON-LD object.
:param o: the RDF statement object to convert.
+ :param use_native_types: True to output native types, False not to.
:return: the JSON-LD object.
"""
@@ -1844,9 +1854,27 @@ class JsonLdProcessor:
rval = {'@value': o['nominalValue']}
# add datatype
if 'datatype' in o:
- rval['@type'] = o['datatype']['nominalValue']
+ type = o['datatype']['nominalValue']
+ # use native types for certain xsd types
+ if use_native_types:
+ if type == XSD_BOOLEAN:
+ if rval['@value'] == 'true':
+ rval['@value'] = True
+ elif rval['@value'] == 'false':
+ rval['@value'] = False
+ elif _is_numeric(rval['@value']):
+ if type == XSD_INTEGER:
+ if rval['@value'].isdigit():
+ rval['@value'] = int(rval['@value'])
+ elif type == XSD_DOUBLE:
+ rval['@value'] = float(rval['@value'])
+ # do not add xsd:string type
+ if type != XSD_STRING:
+ rval['@type'] = type
+ else:
+ rval['@type'] = type
# add language
- elif 'language' in o:
+ if 'language' in o:
rval['@language'] = o['language']
return rval
@@ -2245,7 +2273,7 @@ class JsonLdProcessor:
if (not _is_array(frame) or len(frame) != 1 or
not _is_object(frame[0])):
raise JsonLdError(
- 'Invalid JSON-LD syntax a JSON-LD frame must be a single '
+ 'Invalid JSON-LD syntax; a JSON-LD frame must be a single '
'object.', 'jsonld.SyntaxError', {'frame': frame})
def _filter_subjects(self, state, subjects, frame):
@@ -2574,6 +2602,17 @@ class JsonLdProcessor:
highest = rank
terms.append(term)
+ # no matching terms, use @vocab if available
+ if len(terms) == 0 and ctx.get('@vocab') is not None:
+ # determine if vocab is a prefix of the iri
+ vocab = ctx['@vocab']
+ if iri.startswith(vocab):
+ # use suffix as relative iri if it is not a term in the active
+ # context
+ suffix = iri[len(vocab):]
+ if suffix in ctx['mappings']:
+ return suffix
+
# no term matches, add possible CURIEs
if len(terms) == 0:
for term, entry in ctx['mappings'].items():
@@ -2635,15 +2674,34 @@ class JsonLdProcessor:
value = ctx[key]
if _is_keyword(key):
+ # support vocab
+ if key == '@vocab':
+ if value is not None and not _is_string(value):
+ raise JsonLdError(
+ 'Invalid JSON-LD syntax; the value of "@vocab" in a '
+ '@context must be a string or null.',
+ 'jsonld.SyntaxError', {'context': ctx})
+ if not _is_absolute_iri(value):
+ raise JsonLdError(
+ 'Invalid JSON-LD syntax; the value of "@vocab" in a '
+ '@context must be an absolute IRI.',
+ 'jsonld.SyntaxError', {'context': ctx})
+ if value is None:
+ del active_ctx['@vocab']
+ else:
+ active_ctx['@vocab'] = value
+ defined[key] = True
+ return
+
# only @language is permitted
if key != '@language':
raise JsonLdError(
- 'Invalid JSON-LD syntax keywords cannot be overridden.',
+ 'Invalid JSON-LD syntax; keywords cannot be overridden.',
'jsonld.SyntaxError', {'context': ctx})
if value is not None and not _is_string(value):
raise JsonLdError(
- 'Invalid JSON-LD syntax the value of "@language" in a ' +
+ 'Invalid JSON-LD syntax; the value of "@language" in a '
'@context must be a string or None.',
'jsonld.SyntaxError', {'context': ctx})
@@ -2672,7 +2730,7 @@ class JsonLdProcessor:
# disallow aliasing @context and @preserve
if value == '@context' or value == '@preserve':
raise JsonLdError(
- 'Invalid JSON-LD syntax @context and @preserve '
+ 'Invalid JSON-LD syntax; @context and @preserve '
'cannot be aliased.', 'jsonld.SyntaxError')
# uniquely add key as a keyword alias and resort
@@ -2692,7 +2750,7 @@ class JsonLdProcessor:
if not _is_object(value):
raise JsonLdError(
- 'Invalid JSON-LD syntax @context property values must be ' +
+ 'Invalid JSON-LD syntax; @context property values must be ' +
'strings or objects.',
'jsonld.SyntaxError', {'context': ctx})
@@ -2703,7 +2761,7 @@ class JsonLdProcessor:
id = value['@id']
if not _is_string(id):
raise JsonLdError(
- 'Invalid JSON-LD syntax @context @id values must be '
+ 'Invalid JSON-LD syntax; @context @id values must be '
'strings.', 'jsonld.SyntaxError', {'context': ctx})
# expand @id if it is not @type
if id != '@type':
@@ -2716,7 +2774,7 @@ class JsonLdProcessor:
# non-IRIs MUST define @ids
if prefix is None:
raise JsonLdError(
- 'Invalid JSON-LD syntax @context terms must define an @id.',
+ 'Invalid JSON-LD syntax; @context terms must define an @id.',
'jsonld.SyntaxError', {'context': ctx, 'key': key})
# set @id based on prefix parent
@@ -2731,7 +2789,7 @@ class JsonLdProcessor:
type = value['@type']
if not _is_string(type):
raise JsonLdError(
- 'Invalid JSON-LD syntax @context @type values must be '
+ 'Invalid JSON-LD syntax; @context @type values must be '
'strings.', 'jsonld.SyntaxError', {'context': ctx})
if type != '@id':
# expand @type to full IRI
@@ -2744,7 +2802,7 @@ class JsonLdProcessor:
container = value['@container']
if container != '@list' and container != '@set':
raise JsonLdError(
- 'Invalid JSON-LD syntax @context @container value '
+ 'Invalid JSON-LD syntax; @context @container value '
'must be "@list" or "@set".',
'jsonld.SyntaxError', {'context': ctx})
# add @container to mapping
@@ -2754,7 +2812,7 @@ class JsonLdProcessor:
language = value['@language']
if not (language is None or _is_string(language)):
raise JsonLdError(
- 'Invalid JSON-LD syntax @context @language value must be '
+ 'Invalid JSON-LD syntax; @context @language value must be '
'a string or None.',
'jsonld.SyntaxError', {'context': ctx})
# add @language to mapping
@@ -2819,13 +2877,17 @@ class JsonLdProcessor:
# consider value an absolute IRI
return value
+ #prepend vocab
+ if ctx.get('@vocab') is not None:
+ value = self._prepend_base(ctx['@vocab'], value)
# prepend base
- value = self._prepend_base(base, value)
+ else:
+ value = self._prepend_base(base, value)
# value must now be an absolute IRI
if not _is_absolute_iri(value):
raise JsonLdError(
- 'Invalid JSON-LD syntax a @context value does not expand to '
+ 'Invalid JSON-LD syntax; a @context value does not expand to '
'an absolute IRI.',
'jsonld.SyntaxError', {'context': ctx, 'value': value})
@@ -2871,8 +2933,13 @@ class JsonLdProcessor:
# consider term an absolute IRI
return term
+ if ctx.get('@vocab') is not None:
+ term = self._prepend_base(ctx['@vocab'], term)
# prepend base to term
- return self._prepend_base(base, term)
+ else:
+ term = self._prepend_base(base, term)
+
+ return term
def _find_context_urls(self, input, urls, replace):
"""
@@ -3257,7 +3324,7 @@ def _validate_type_value(v):
if not is_valid:
raise JsonLdError(
- 'Invalid JSON-LD syntax "@type" value must a string, '
+ 'Invalid JSON-LD syntax; "@type" value must a string, '
'an array of strings, or an empty object.',
'jsonld.SyntaxError', {'value': v})
@@ -3295,6 +3362,21 @@ def _is_double(v):
return not isinstance(v, Integral) and isinstance(v, Real)
+def _is_numeric(v):
+ """
+ Returns True if the given value is numeric.
+
+ :param v: the value to check.
+
+ :return: True if the value is numeric, False if not.
+ """
+ try:
+ float(v)
+ return True
+ except ValueError:
+ return False
+
+
def _is_subject(v):
"""
Returns True if the given value is a subject with properties.
diff --git a/tests/runtests.py b/tests/runtests.py
index 6430b41..dce41c8 100644
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -135,37 +135,42 @@ class TestRunner:
'base': 'http://json-ld.org/test-suite/tests/' +
test['input']}
- if 'jld:NormalizeTest' in test_type:
- options['format'] = 'application/nquads'
- result = jsonld.normalize(input, options)
- elif 'jld:ExpandTest' in test_type:
- result = jsonld.expand(input, options)
- elif 'jld:CompactTest' in test_type:
- ctx = json.load(open(join(test_dir, test['context'])))
- result = jsonld.compact(input, ctx, options)
- elif 'jld:FrameTest' in test_type:
- frame = json.load(open(join(test_dir, test['frame'])))
- result = jsonld.frame(input, frame, options)
- elif 'jld:FromRDFTest' in test_type:
- result = jsonld.from_rdf(input, options)
- elif 'jld:ToRDFTest' in test_type:
- options['format'] = 'application/nquads'
- result = jsonld.to_rdf(input, options)
-
- # check the expected value against the test result
- success = deep_compare(expect, result)
-
- if success:
- passed += 1
- print 'PASS'
- else:
+ try:
+ if 'jld:NormalizeTest' in test_type:
+ options['format'] = 'application/nquads'
+ result = jsonld.normalize(input, options)
+ elif 'jld:ExpandTest' in test_type:
+ result = jsonld.expand(input, options)
+ elif 'jld:CompactTest' in test_type:
+ ctx = json.load(open(join(test_dir, test['context'])))
+ result = jsonld.compact(input, ctx, options)
+ elif 'jld:FrameTest' in test_type:
+ frame = json.load(open(join(test_dir, test['frame'])))
+ result = jsonld.frame(input, frame, options)
+ elif 'jld:FromRDFTest' in test_type:
+ result = jsonld.from_rdf(input, options)
+ elif 'jld:ToRDFTest' in test_type:
+ options['format'] = 'application/nquads'
+ result = jsonld.to_rdf(input, options)
+
+ # check the expected value against the test result
+ success = deep_compare(expect, result)
+
+ if success:
+ passed += 1
+ print 'PASS'
+ else:
+ failed += 1
+ print 'FAIL'
+
+ if not success or self.options.verbose:
+ print 'Expect:', json.dumps(expect, indent=2)
+ print 'Result:', json.dumps(result, indent=2)
+ except jsonld.JsonLdError as e:
+ print '\nError: ', e
failed += 1
print 'FAIL'
- if not success or self.options.verbose:
- print 'Expect:', json.dumps(expect, indent=2)
- print 'Result:', json.dumps(result, indent=2)
-
print 'Done. Total:%d Passed:%d Failed:%d' % (total, passed, failed)
def deep_compare(expect, result):
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-pyld.git
More information about the Python-modules-commits
mailing list