Quantcast
Viewing latest article 25
Browse Latest Browse All 31

Answer by luke for How can I load a Python flask app into a gtk webview (Webkit)

I've ended up finding a solution to this myself (but open to better ones).

The first thing, loading a page, was pretty easy. Flask provides a way to test apps which mainly just sets up all the things for WSGI to be able to process a request. This is just what I needed so I used this like so:

from flask import Flaskclass WebViewFlask(Flask):"""    Adds the ability to load a uri without the    need of a HTTP server."""    def load_from_uri(self, uri):"""        Loads a uri without a running HTTP server."""        with self.test_client() as c:            response = c.get(uri)            return response.data, response.mimetype

The second part, overriding "when the user clicks a link", is a bit more trickier.

import osimport webkitclass FlaskAppView(webkit.WebView):"""    Loads pages for flask apps into a WebView."""    def __init__(self, flask_app, *args, **kwargs):        # Protocol for flask app, by default file:// is used        # so a protocol is defined here to prevent that.        self.PROTOCOL = 'flask://'        super(webkit.WebView, self).__init__(*args, **kwargs)        self._flask_app = flask_app        # Register new navigation handler.        self.connect("navigation-policy-decision-requested",            self._nav_request        )        # For navigation handler.        self.prev_uri = None        # Redefine open like this as when using super        # an error like this occurs:        #   AttributeError: 'super' object has no attribute 'open'        self._open = self.open        self.open = self.open_    def _nav_request(self, view, frame, net_req, nav_act, pol_dec):"""        WebView navigation handler for Flask apps."""        # Get the uri        uri = net_req.get_uri()        # In order for flask apps to use relative links        # the protocol is removed and it is made into an absolute        # path.        if uri.startswith(self.PROTOCOL):            # In this case it is not relative but            # it needs to have it's protocol removed            uri = uri[len(self.PROTOCOL):]        elif not self.prev_uri.endswith(uri):            # It is relative and self.prev_uri needs to            # be appended.            uri = os.path.normpath(os.path.join(self.prev_uri, uri))        # This is used to prevent an infinite recursive loop due        # to view.load_string running this function with the same        # input.        if uri == self.prev_uri:            return False        self.prev_uri = uri        # Create response from Flask app.        response = app.load_from_uri(uri) + ('utf-8', uri)        # Load response.        view.load_string(*response)        # Return False to prevent additional        # handlers from running.        return False    def open_(self, uri):"""        Prepends protocol to uri for webkit.WebView.open."""        self._open(self.PROTOCOL + uri)

Basically a new navigation event handler is registered with some code to allow for successful recursion and support for relative paths.

Anyway, with that code above by just replacing Flask with WebViewFlask and WebView with FlaskAppView everything pretty much just works.

And the result:Image may be NSFW.
Clik here to view.
result

Which is a flask app being loaded in a webkit.WebView without any sort of server. The best thing about it is by just switching app back to an instance of Flask instead of WebViewFlask It's a plain webapp again.


Viewing latest article 25
Browse Latest Browse All 31

Trending Articles