flask_rdf-0.2.0/0000755002352500234200000000000012664723106015246 5ustar hufmanDomain Users00000000000000flask_rdf-0.2.0/setup.py0000755002352500234200000000263512664721765017002 0ustar hufmanDomain Users00000000000000#!/usr/bin/env python from distutils.core import setup try: from setuptools import setup except: pass requirements = open('requirements.txt').read().split('\n') test_requirements = open('requirements.test.txt').read().split('\n') long_description = open('README.rst').read() setup(name='flask_rdf', version='0.2.0', description='Flask decorator to output RDF using content negotiation', author='Walter Huf', author_email='hufman@gmail.com', url='https://github.com/hufman/flask_rdf', packages=['flask_rdf'], install_requires=requirements, test_requires=requirements + test_requirements, long_description=long_description, classifiers=[ 'Development Status :: 4 - Beta', 'Framework :: Flask', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries', 'Topic :: Software Development :: Libraries :: Python Modules' ], license='BSD', platforms=['Any'] ) flask_rdf-0.2.0/PKG-INFO0000644002352500234200000001574112664723106016353 0ustar hufmanDomain Users00000000000000Metadata-Version: 1.1 Name: flask_rdf Version: 0.2.0 Summary: Flask decorator to output RDF using content negotiation Home-page: https://github.com/hufman/flask_rdf Author: Walter Huf Author-email: hufman@gmail.com License: BSD Description: Flask_rdf ========== A Flask or Bottle or WSGI decorator to output RDF using content negotiation. Apply the ``@flask_rdf`` or ``@bottle_rdf`` or ``@wsgi_rdf`` decorator to a view function and return an rdflib Graph object. Flask_rdf will automatically format it into an RDF output format, depending on what the request's Accept header says. If the view function returns something besides an rdflib graph, it will be passed through without modification. Custom formats can be registered easily. After registering the new serializer with rdflib's plugin support, use the ``add_format`` method to register a new mimetype request to use the new formatter. The functionality of this module can still help other web frameworks, even if there isn't a specific decorator yet. The ``format.decide`` function will return information about with ``Content-Type`` header to send and what serialization format to use with rdflib. The ``format.wants_rdf`` function can be used at a high level to determine whether the client even wants RDF. API --- - ``add_format(mimetype, serialize_format)``, ``format.add_format(mimetype, serialize_format)`` Registers a new format to be recognized for content negotiation. It accepts arguments ``mimetype``, ``serialize_format``, and is used to add any custom rdflib serializer plugins to be used for the content negotiation. A third argument, requires_context, will restrict this serializer to only be used by graphs that are ``context_aware``. - ``format.decide(accept, context_aware=False)`` Given an Accept header, return a (``mimetype``, ``format``) tuple that would best satisfy the client's request. If the Accept header is blank, default to RDF+XML If the Accept header can't be satisfied, returns (None, None) A second argument, context_aware, may be used to allow formats that require a ``context_aware`` graph. - ``FormatSelector()``, ``format.FormatSelector()`` Class to decide serialization formats. It supports using the module-level formats added with ``format.add_format``, but it has its own list of formats added with ``FormatSelector().add_format``. - ``wants_rdf(accept)``, ``format.wants_rdf(accept)``, ``FormatSelector.wants_rdf(accept)`` Returns whether the client's Accept header indicates that the client is prepared to receive RDF data. This can be used in the view to return a pretty HTML page for browsers, for example. - ``@flask_rdf``, ``@flask.returns_rdf`` Decorator for a Flask view function to use the Flask request's Accept header. It handles converting an rdflib Graph object to the proper Flask response, depending on the content negotiation. Other content is returned without modification. - ``flask.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. - ``@bottle_rdf``, ``@bottle.returns_rdf`` Decorator for a Bottle view function to use the Bottle request's Accept header. It handles converting an rdflib Graph object to the proper Bottle response, depending on the content negotiation. Other content is returned without modification. - ``bottle.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. - ``@wsgi_rdf``, ``@wsgi.returns_rdf`` Decorator for a WSGI app function to use the WSGI request's Accept header. It handles converting an rdflib Graph object to the proper Bottle response, depending on the content negotiation. Other content is returned without modification. Calls to WSGI's ``start_response`` will pass data through unchanged. Doing both a ``start_response`` and returning an RDF object will result in both outputs being returned, so don't do that. - ``wsgi.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. Example ------- .. code:: python #!/usr/bin/env python from rdflib import Graph, BNode, Literal, URIRef from rdflib.namespace import FOAF from flask import Flask from flask_rdf.flask import returns_rdf import random app = Flask(__name__) @app.route('/') @app.route('/') @returns_rdf def random_age(path=''): graph = Graph('IOMemory', BNode()) graph.add((URIRef(path), FOAF.age, Literal(random.randint(20, 50)))) return graph if __name__ == '__main__': app.run(host='0.0.0.0', debug=True) .. image:: https://travis-ci.org/hufman/flask_rdf.svg?branch=master :alt: Build Status :target: https://travis-ci.org/hufman/flask_rdf Platform: Any Classifier: Development Status :: 4 - Beta Classifier: Framework :: Flask Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules flask_rdf-0.2.0/README.rst0000644002352500234200000001210212664225413016727 0ustar hufmanDomain Users00000000000000Flask_rdf ========== A Flask or Bottle or WSGI decorator to output RDF using content negotiation. Apply the ``@flask_rdf`` or ``@bottle_rdf`` or ``@wsgi_rdf`` decorator to a view function and return an rdflib Graph object. Flask_rdf will automatically format it into an RDF output format, depending on what the request's Accept header says. If the view function returns something besides an rdflib graph, it will be passed through without modification. Custom formats can be registered easily. After registering the new serializer with rdflib's plugin support, use the ``add_format`` method to register a new mimetype request to use the new formatter. The functionality of this module can still help other web frameworks, even if there isn't a specific decorator yet. The ``format.decide`` function will return information about with ``Content-Type`` header to send and what serialization format to use with rdflib. The ``format.wants_rdf`` function can be used at a high level to determine whether the client even wants RDF. API --- - ``add_format(mimetype, serialize_format)``, ``format.add_format(mimetype, serialize_format)`` Registers a new format to be recognized for content negotiation. It accepts arguments ``mimetype``, ``serialize_format``, and is used to add any custom rdflib serializer plugins to be used for the content negotiation. A third argument, requires_context, will restrict this serializer to only be used by graphs that are ``context_aware``. - ``format.decide(accept, context_aware=False)`` Given an Accept header, return a (``mimetype``, ``format``) tuple that would best satisfy the client's request. If the Accept header is blank, default to RDF+XML If the Accept header can't be satisfied, returns (None, None) A second argument, context_aware, may be used to allow formats that require a ``context_aware`` graph. - ``FormatSelector()``, ``format.FormatSelector()`` Class to decide serialization formats. It supports using the module-level formats added with ``format.add_format``, but it has its own list of formats added with ``FormatSelector().add_format``. - ``wants_rdf(accept)``, ``format.wants_rdf(accept)``, ``FormatSelector.wants_rdf(accept)`` Returns whether the client's Accept header indicates that the client is prepared to receive RDF data. This can be used in the view to return a pretty HTML page for browsers, for example. - ``@flask_rdf``, ``@flask.returns_rdf`` Decorator for a Flask view function to use the Flask request's Accept header. It handles converting an rdflib Graph object to the proper Flask response, depending on the content negotiation. Other content is returned without modification. - ``flask.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. - ``@bottle_rdf``, ``@bottle.returns_rdf`` Decorator for a Bottle view function to use the Bottle request's Accept header. It handles converting an rdflib Graph object to the proper Bottle response, depending on the content negotiation. Other content is returned without modification. - ``bottle.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. - ``@wsgi_rdf``, ``@wsgi.returns_rdf`` Decorator for a WSGI app function to use the WSGI request's Accept header. It handles converting an rdflib Graph object to the proper Bottle response, depending on the content negotiation. Other content is returned without modification. Calls to WSGI's ``start_response`` will pass data through unchanged. Doing both a ``start_response`` and returning an RDF object will result in both outputs being returned, so don't do that. - ``wsgi.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. Example ------- .. code:: python #!/usr/bin/env python from rdflib import Graph, BNode, Literal, URIRef from rdflib.namespace import FOAF from flask import Flask from flask_rdf.flask import returns_rdf import random app = Flask(__name__) @app.route('/') @app.route('/') @returns_rdf def random_age(path=''): graph = Graph('IOMemory', BNode()) graph.add((URIRef(path), FOAF.age, Literal(random.randint(20, 50)))) return graph if __name__ == '__main__': app.run(host='0.0.0.0', debug=True) .. image:: https://travis-ci.org/hufman/flask_rdf.svg?branch=master :alt: Build Status :target: https://travis-ci.org/hufman/flask_rdf flask_rdf-0.2.0/flask_rdf/0000755002352500234200000000000012664723106017201 5ustar hufmanDomain Users00000000000000flask_rdf-0.2.0/flask_rdf/bottle.py0000644002352500234200000000126512663254310021043 0ustar hufmanDomain Users00000000000000from __future__ import absolute_import from .common_decorators import ViewDecorator from rdflib.graph import Graph class Decorator(ViewDecorator): @classmethod def make_new_response(cls, old_response, mimetype, serialized): import bottle bottle.response.content_type = mimetype return serialized @classmethod def make_406_response(cls): import bottle bottle.abort(406, '406 Not Acceptable') @classmethod def get_accept(cls): import bottle return bottle.request.headers.get('Accept', '') _implicit_instance = Decorator() def output(output, accepts): return _implicit_instance.output(output, accepts) def returns_rdf(view): return _implicit_instance.decorate(view) flask_rdf-0.2.0/flask_rdf/wsgi.py0000644002352500234200000000700112664237164020526 0ustar hufmanDomain Users00000000000000from __future__ import absolute_import from .format import decide, FormatSelector from rdflib.graph import Graph from six import BytesIO class Decorator(object): def __init__(self, format_selector=None): self.format_selector = format_selector if self.format_selector is None: self.format_selector = FormatSelector() @staticmethod def _is_graph(obj): return isinstance(obj, Graph) @staticmethod def _get_graph(output): """ Given a WSGI response, check for a rdflib Graph """ if Decorator._is_graph(output): # single graph object return output def output(self, output, accepts, set_http_code, set_content_type): """ Formats a response from a WSGI app to handle any RDF graphs If a view function returns a single RDF graph, serialize it based on Accept header If it's not an RDF graph, return it without any special handling """ graph = Decorator._get_graph(output) if graph is not None: # decide the format output_mimetype, output_format = self.format_selector.decide(accepts, graph.context_aware) # requested content couldn't find anything if output_mimetype is None: set_http_code("406 Not Acceptable") return ['406 Not Acceptable'.encode('utf-8')] # explicitly mark text mimetypes as utf-8 if 'text' in output_mimetype: output_mimetype = output_mimetype + '; charset=utf-8' # format the new response serialized = graph.serialize(format=output_format) set_content_type(output_mimetype) return [serialized] else: return output def decorate(self, app): """ Wraps a WSGI application to return formatted RDF graphs Uses content negotiation to serialize the graph to the client-preferred format Passes other content through unmodified """ from functools import wraps @wraps(app) def decorated(environ, start_response): # capture any start_response from the app app_response = {} app_response['status'] = "200 OK" app_response['headers'] = [] app_response['written'] = BytesIO() def custom_start_response(status, headers, *args, **kwargs): app_response['status'] = status app_response['headers'] = headers app_response['args'] = args app_response['kwargs'] = kwargs return app_response['written'].write returned = app(environ, custom_start_response) # callbacks from the serialization def set_http_code(status): app_response['status'] = str(status) def set_content_type(content_type): app_response['headers'] = [(h,v) for (h,v) in app_response['headers'] if h.lower() != 'content-type'] app_response['headers'].append(('Content-Type', content_type)) # do the serialization accept = environ.get('HTTP_ACCEPT', '') new_return = self.output(returned, accept, set_http_code, set_content_type) # pass on the result to the parent WSGI server parent_writer = start_response(app_response['status'], app_response['headers'], *app_response.get('args', []), **app_response.get('kwargs', {})) written = app_response['written'].getvalue() if len(written) > 0: parent_writer(written) return new_return return decorated def __call__(self, app): """ Enables this class to be used as the decorator directly """ return self.decorate(app) _implicit_instance = Decorator() def output(output, accepts, set_http_code, set_content_type): return _implicit_instance.output(output, accepts, set_http_code, set_content_type) def returns_rdf(view): return _implicit_instance.decorate(view) flask_rdf-0.2.0/flask_rdf/format.py0000644002352500234200000001240412663176414021047 0ustar hufmanDomain Users00000000000000import 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) flask_rdf-0.2.0/flask_rdf/common_decorators.py0000644002352500234200000000511412663253225023270 0ustar hufmanDomain Users00000000000000from __future__ import absolute_import from .format import decide, FormatSelector from rdflib.graph import Graph class ViewDecorator(object): def __init__(self, format_selector=None): self.format_selector = format_selector if self.format_selector is None: self.format_selector = FormatSelector() @classmethod def is_graph(cls, obj): """ Check whether this object is an rdflib Graph """ return isinstance(obj, Graph) @classmethod def get_graph(cls, response): """ Given a view response, find the rdflib Graph, or None """ if cls.is_graph(response): # single graph object return response @classmethod def replace_graph(cls, response, serialized): """ Replace the rdflib Graph in a view response """ if cls.is_graph(response): # single graph object return serialized return response @classmethod def make_new_response(cls, old_response, mimetype, serialized): """ Return a new framework-specific response with the seralized data """ raise NotImplementedError @classmethod def make_406_response(cls): """ Return the framework-specific HTTP 406 error """ raise NotImplementedError @classmethod def get_accept(cls): """ Load the framework-specific Accept header """ raise NotImplementedError def output(self, response, accepts): """ Formats a response from a view to handle any RDF graphs If a view function returns an RDF graph, serialize it based on Accept header If it's not an RDF graph, return it without any special handling """ graph = self.get_graph(response) if graph is not None: # decide the format mimetype, format = self.format_selector.decide(accepts, graph.context_aware) # requested content couldn't find anything if mimetype is None: return self.make_406_response() # explicitly mark text mimetypes as utf-8 if 'text' in mimetype: mimetype = mimetype + '; charset=utf-8' # format the new response serialized = graph.serialize(format=format) response = self.make_new_response(response, mimetype, serialized) return response else: return response def decorate(self, view): """ Wraps a view function to return formatted RDF graphs Uses content negotiation to serialize the graph to the client-preferred format Passes other content through unmodified """ from functools import wraps @wraps(view) def decorated(*args, **kwargs): response = view(*args, **kwargs) accept = self.get_accept() return self.output(response, accept) return decorated def __call__(self, view): """ Enables this class to be used as the decorator directly """ return self.decorate(view) flask_rdf-0.2.0/flask_rdf/flask.py0000644002352500234200000000275312664231076020662 0ustar hufmanDomain Users00000000000000from __future__ import absolute_import from .common_decorators import ViewDecorator from rdflib.graph import Graph class Decorator(ViewDecorator): @classmethod def get_graph(cls, response): """ Given a Flask response, find the rdflib Graph """ if cls.is_graph(response): # single graph object return response if hasattr(response, '__getitem__'): # indexable tuple if len(response) > 0 and \ cls.is_graph(response[0]): # graph object return response[0] @classmethod def replace_graph(cls, response, serialized): """ Replace the rdflib Graph in a Flask response """ if cls.is_graph(response): # single graph object return serialized if hasattr(response, '__getitem__'): # indexable tuple if len(response) > 0 and \ cls.is_graph(response[0]): # graph object return (serialized,) + response[1:] return response @classmethod def make_new_response(cls, old_response, mimetype, serialized): from flask import make_response final_output = cls.replace_graph(old_response, serialized) response = make_response(final_output) response.headers['Content-Type'] = mimetype return response @classmethod def make_406_response(cls): return '406 Not Acceptable', 406 @classmethod def get_accept(cls): from flask import request return request.headers.get('Accept', '') _implicit_instance = Decorator() def output(response, accepts): return _implicit_instance.output(response, accepts) def returns_rdf(view): return _implicit_instance.decorate(view) flask_rdf-0.2.0/flask_rdf/__init__.py0000644002352500234200000000041712646015715021314 0ustar hufmanDomain Users00000000000000from . import bottle from . import flask from . import wsgi from . import format from .format import add_format, FormatSelector, wants_rdf from .bottle import returns_rdf as bottle_rdf from .flask import returns_rdf as flask_rdf from .wsgi import returns_rdf as wsgi_rdf flask_rdf-0.2.0/requirements.txt0000644002352500234200000000003412664232567020535 0ustar hufmanDomain Users00000000000000python-mimeparse==0.1.4 six flask_rdf-0.2.0/MANIFEST.in0000644002352500234200000000005112663121527016776 0ustar hufmanDomain Users00000000000000include README.rst include requirements* flask_rdf-0.2.0/setup.cfg0000644002352500234200000000007312664723106017067 0ustar hufmanDomain Users00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 flask_rdf-0.2.0/flask_rdf.egg-info/0000755002352500234200000000000012664723106020673 5ustar hufmanDomain Users00000000000000flask_rdf-0.2.0/flask_rdf.egg-info/requires.txt0000644002352500234200000000003312664723100023261 0ustar hufmanDomain Users00000000000000python-mimeparse==0.1.4 sixflask_rdf-0.2.0/flask_rdf.egg-info/PKG-INFO0000644002352500234200000001574112664723100021772 0ustar hufmanDomain Users00000000000000Metadata-Version: 1.1 Name: flask-rdf Version: 0.2.0 Summary: Flask decorator to output RDF using content negotiation Home-page: https://github.com/hufman/flask_rdf Author: Walter Huf Author-email: hufman@gmail.com License: BSD Description: Flask_rdf ========== A Flask or Bottle or WSGI decorator to output RDF using content negotiation. Apply the ``@flask_rdf`` or ``@bottle_rdf`` or ``@wsgi_rdf`` decorator to a view function and return an rdflib Graph object. Flask_rdf will automatically format it into an RDF output format, depending on what the request's Accept header says. If the view function returns something besides an rdflib graph, it will be passed through without modification. Custom formats can be registered easily. After registering the new serializer with rdflib's plugin support, use the ``add_format`` method to register a new mimetype request to use the new formatter. The functionality of this module can still help other web frameworks, even if there isn't a specific decorator yet. The ``format.decide`` function will return information about with ``Content-Type`` header to send and what serialization format to use with rdflib. The ``format.wants_rdf`` function can be used at a high level to determine whether the client even wants RDF. API --- - ``add_format(mimetype, serialize_format)``, ``format.add_format(mimetype, serialize_format)`` Registers a new format to be recognized for content negotiation. It accepts arguments ``mimetype``, ``serialize_format``, and is used to add any custom rdflib serializer plugins to be used for the content negotiation. A third argument, requires_context, will restrict this serializer to only be used by graphs that are ``context_aware``. - ``format.decide(accept, context_aware=False)`` Given an Accept header, return a (``mimetype``, ``format``) tuple that would best satisfy the client's request. If the Accept header is blank, default to RDF+XML If the Accept header can't be satisfied, returns (None, None) A second argument, context_aware, may be used to allow formats that require a ``context_aware`` graph. - ``FormatSelector()``, ``format.FormatSelector()`` Class to decide serialization formats. It supports using the module-level formats added with ``format.add_format``, but it has its own list of formats added with ``FormatSelector().add_format``. - ``wants_rdf(accept)``, ``format.wants_rdf(accept)``, ``FormatSelector.wants_rdf(accept)`` Returns whether the client's Accept header indicates that the client is prepared to receive RDF data. This can be used in the view to return a pretty HTML page for browsers, for example. - ``@flask_rdf``, ``@flask.returns_rdf`` Decorator for a Flask view function to use the Flask request's Accept header. It handles converting an rdflib Graph object to the proper Flask response, depending on the content negotiation. Other content is returned without modification. - ``flask.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. - ``@bottle_rdf``, ``@bottle.returns_rdf`` Decorator for a Bottle view function to use the Bottle request's Accept header. It handles converting an rdflib Graph object to the proper Bottle response, depending on the content negotiation. Other content is returned without modification. - ``bottle.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. - ``@wsgi_rdf``, ``@wsgi.returns_rdf`` Decorator for a WSGI app function to use the WSGI request's Accept header. It handles converting an rdflib Graph object to the proper Bottle response, depending on the content negotiation. Other content is returned without modification. Calls to WSGI's ``start_response`` will pass data through unchanged. Doing both a ``start_response`` and returning an RDF object will result in both outputs being returned, so don't do that. - ``wsgi.Decorator`` Class to act as the decorator, in case some behavior needs to be overridden. The constructor accepts a FormatSelector object to do custom negotiation. The Decorator object itself can be used as the decorator, and it also supports the methods ``.output`` and ``.decorate``. Example ------- .. code:: python #!/usr/bin/env python from rdflib import Graph, BNode, Literal, URIRef from rdflib.namespace import FOAF from flask import Flask from flask_rdf.flask import returns_rdf import random app = Flask(__name__) @app.route('/') @app.route('/') @returns_rdf def random_age(path=''): graph = Graph('IOMemory', BNode()) graph.add((URIRef(path), FOAF.age, Literal(random.randint(20, 50)))) return graph if __name__ == '__main__': app.run(host='0.0.0.0', debug=True) .. image:: https://travis-ci.org/hufman/flask_rdf.svg?branch=master :alt: Build Status :target: https://travis-ci.org/hufman/flask_rdf Platform: Any Classifier: Development Status :: 4 - Beta Classifier: Framework :: Flask Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules flask_rdf-0.2.0/flask_rdf.egg-info/top_level.txt0000644002352500234200000000001212664723100023410 0ustar hufmanDomain Users00000000000000flask_rdf flask_rdf-0.2.0/flask_rdf.egg-info/dependency_links.txt0000644002352500234200000000000112664723100024733 0ustar hufmanDomain Users00000000000000 flask_rdf-0.2.0/flask_rdf.egg-info/SOURCES.txt0000644002352500234200000000055412664723105022562 0ustar hufmanDomain Users00000000000000MANIFEST.in README.rst requirements.test.txt requirements.txt setup.py flask_rdf/__init__.py flask_rdf/bottle.py flask_rdf/common_decorators.py flask_rdf/flask.py flask_rdf/format.py flask_rdf/wsgi.py flask_rdf.egg-info/PKG-INFO flask_rdf.egg-info/SOURCES.txt flask_rdf.egg-info/dependency_links.txt flask_rdf.egg-info/requires.txt flask_rdf.egg-info/top_level.txtflask_rdf-0.2.0/requirements.test.txt0000644002352500234200000000007112663121322021475 0ustar hufmanDomain Users00000000000000nose==1.3.3 WebTest==2.0.20 bottle Flask rdflib coverage