fanstatic / fanstatic /

Full commit
import webob

from fanstatic.config import convert_config
import fanstatic

CONTENT_TYPES = ['text/html', 'text/xml', 'application/xhtml+xml']

class Injector(object):
    """Fanstatic injector WSGI framework component.

    This WSGI component takes care of injecting the proper resource
    inclusions into HTML when needed.

    This WSGI component is used automatically by the
    :py:func:`Fanstatic` WSGI framework component, but can also be
    used independently if you need more control.

    :param app: The WSGI app to wrap with the injector.

    :param ``**config``: Optional keyword arguments. These are passed
      to :py:class:`NeededResources` when it is constructed. It also
      makes sure that when initialized, it isn't given any
      configuration parameters that cannot be passed to
    def __init__(self, app, **config): = app

        # this is just to give useful feedback early on

        self.config = config

    def __call__(self, environ, start_response):
        request = webob.Request(environ)
        # We only continue if the request method is appropriate.
        if not request.method in ['GET', 'POST']:
            return, start_response)

        # Initialize a needed resources object.
        # XXX this will set the needed on the thread local data, even
        # if the wrapped framework only gets the needed from the WSGI
        # environ.
        needed = fanstatic.init_needed(
            script_name=request.environ.get('SCRIPT_NAME'), **self.config)

        # Make sure the needed resource object is put in the WSGI
        # environment as well, for frameworks that choose to use it
        # from there.
        request.environ[fanstatic.NEEDED] = needed

        # Get the response from the wrapped application:
        response = request.get_response(

        # We only continue if the content-type is appropriate.
        if not (response.content_type and
                response.content_type.lower() in CONTENT_TYPES):
            # Clean up after our behinds.
            return response(environ, start_response)

        # The wrapped application may have `needed` resources.
        if needed.has_resources():
            # Can't use response.text because there might not be any
            # charset. body is not unicode.
            result = needed.render_topbottom_into_html(response.body)
            # Reset the body...
            response.body = b''
            # Write will propely unfolder the previous application and
            # call close. Setting response.text or response.body won't do it.

        # Clean up after our behinds.

        return response(environ, start_response)

def make_injector(app, global_config, **local_config):
    local_config = convert_config(local_config)
    return Injector(app, **local_config)