1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
import mimeparse
DEFAULT_MIMETYPE = 'application/rdf+xml' # default mimetype to return
WILDCARD = 'INVALID/MATCH' # matches Accept:*/*
WILDCARD_MIMETYPE = 'application/rdf+xml' # mimetype for wildcard
# What formats we support for serialization
formats = {
'application/x-turtle': 'turtle',
'text/turtle': 'turtle',
'application/rdf+xml': 'xml',
'application/trix': 'trix',
'application/n-quads': 'nquads',
'application/n-triples': 'nt',
'text/n-triples': 'nt',
'text/rdf+nt': 'nt',
'application/n3': 'n3',
'text/n3': 'n3',
'text/rdf+n3': 'n3'
}
# the list of any mimetypes, unlocked if we have a context
all_mimetypes = list(formats.keys())
# the list of mimetypes that don't require a context
ctxless_mimetypes = [m for m in all_mimetypes if 'n-quads' not in m]
class FormatSelector(object):
def __init__(self):
# any extra formats that we support
self.formats = {}
# the list of any mimetypes, unlocked if we have a context
self.all_mimetypes = []
# the list of mimetypes that don't require a context
self.ctxless_mimetypes = []
# the default mimetype to use
self.default_mimetype = None
# the wildcard mimetype to use
self.wildcard_mimetype = None
def add_format(self, mimetype, format, requires_context=False):
""" Registers a new format to be used in a graph's serialize call
If you've installed an rdflib serializer plugin, use this
to add it to the content negotiation system
Set requires_context=True if this format requires a context-aware graph
"""
self.formats[mimetype] = format
if not requires_context:
self.ctxless_mimetypes.append(mimetype)
self.all_mimetypes.append(mimetype)
def get_default_mimetype(self):
""" Returns the default mimetype """
mimetype = self.default_mimetype
if mimetype is None: # class inherits from module default
mimetype = DEFAULT_MIMETYPE
if mimetype is None: # module is set to None?
mimetype = 'application/rdf+xml'
return mimetype
def get_wildcard_mimetype(self):
""" Returns the mimetype if the client sends */* """
mimetype = self.wildcard_mimetype
if mimetype is None: # class inherits from module default
mimetype = WILDCARD_MIMETYPE
if mimetype is None: # module is set to None?
mimetype = 'application/rdf+xml'
return mimetype
def decide_mimetype(self, accepts, context_aware = False):
""" Returns what mimetype the client wants to receive
Parses the given Accept header and returns the best one that
we know how to output
An empty Accept will default to application/rdf+xml
An Accept with */* use rdf+xml unless a better match is found
An Accept that doesn't match anything will return None
"""
mimetype = None
# If the client didn't request a thing, use default
if accepts is None or accepts.strip() == '':
mimetype = self.get_default_mimetype()
return mimetype
# pick the mimetype
if context_aware:
mimetype = mimeparse.best_match(all_mimetypes + self.all_mimetypes + [WILDCARD], accepts)
else:
mimetype = mimeparse.best_match(ctxless_mimetypes + self.ctxless_mimetypes + [WILDCARD], accepts)
if mimetype == '':
mimetype = None
# if browser sent */*
if mimetype == WILDCARD:
mimetype = self.get_wildcard_mimetype()
return mimetype
def get_serialize_format(self, mimetype):
""" Get the serialization format for the given mimetype """
format = self.formats.get(mimetype, None)
if format is None:
format = formats.get(mimetype, None)
return format
def decide(self, accepts, context_aware=False):
""" Returns what (mimetype,format) the client wants to receive
Parses the given Accept header and picks the best one that
we know how to output
Returns (mimetype, format)
An empty Accept will default to rdf+xml
An Accept with */* use rdf+xml unless a better match is found
An Accept that doesn't match anything will return (None,None)
context_aware=True will allow nquad serialization
"""
mimetype = self.decide_mimetype(accepts, context_aware)
# return what format to serialize as
if mimetype is not None:
return (mimetype, self.get_serialize_format(mimetype))
else:
# couldn't find a matching mimetype for the Accepts header
return (None, None)
def wants_rdf(self, accepts):
""" Returns whether this client's Accept header indicates
that the client wants to receive RDF
"""
mimetype = mimeparse.best_match(all_mimetypes + self.all_mimetypes + [WILDCARD], accepts)
return mimetype and mimetype != WILDCARD
_implicit_instance = FormatSelector()
def add_format(mimetype, format, requires_context=False):
""" Registers a new format to be used in a graph's serialize call
If you've installed an rdflib serializer plugin, use this
to add it to the content negotiation system
Set requires_context=True if this format requires a context-aware graph
"""
global formats
global ctxless_mimetypes
global all_mimetypes
formats[mimetype] = format
if not requires_context:
ctxless_mimetypes.append(mimetype)
all_mimetypes.append(mimetype)
def decide(accepts, context_aware=False):
return _implicit_instance.decide(accepts, context_aware)
def wants_rdf(accepts):
""" Returns whether this client's Accept header indicates
that the client wants to receive RDF
"""
return _implicit_instance.wants_rdf(accepts)
|