Search code examples
pythonweb-worker

Run python script in background or web worker


I would like to run a python code to solve some equations in the browser. I currently do this with javascript in a web worker. This does not interact with the DOM at all, it just receives some input, does some calculations, and then returns the output. I would love to able to use python in the same way. Is this possible?


Solution

  • I don't think you'd be able to get the client's browser execute any Python code. You'll have to figure out some sort of protocol to communicate back and forth with Python. A common way to do this is to have a Python process running somewhere that acts as an HTTP(s) server. You can have the client's browser make an API call (some form of HTTP request) to the Python server and that separate piece of Python code running will catch that call and send back data. This could be as simple as a <frame> tag or some Javascript code that makes the request and interprets the response in the browser.

    Try this, go into a new directory and create two files.

    server.py (built on python3):

    #!/usr/bin/env python
    
    import http.server
    import logging
    
    IP = '127.0.0.1'
    PORT = 8001
    
    class MyHandler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
            url = self.path
            headers = self.headers
            print('received request:', url)
    
            numbers = url.split('/')
            print('parsed numbers:', numbers)
            try:
                sumTotal = 0
                for num in numbers:
                    if num == '':
                        continue
                    sumTotal += int(num)
                self.respond(sumTotal)
            except ValueError as ex:
                logging.error('unable to parse value: %s' % num)
                self.respond(-1)
    
        def respond(self, sumTotal):
            # Send response status code
            self.send_response(200)
    
            # Send headers
            self.send_header('Content-type','text/html')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
    
            # Send message back to client
            message = str(sumTotal)
            # Write content as utf-8 data
            self.wfile.write(bytes(message, 'utf8'))
            return
    
    def main():
        address = (IP, PORT)
        httpd = http.server.HTTPServer(address, MyHandler)
        httpd.serve_forever()
    
    if __name__ == '__main__':
        main()
    

    test.html:

    <!DOCTYPE HTML>
    <html lang="en-us">
    <head>
      <title>Python Linking Demo</title>
      <script type="text/javascript">
    
        function addNumbers(a, b) {
          var url = 'http://localhost:8001/' + a + '/' + b;
          var xhr = new XMLHttpRequest();
          xhr.onreadystatechange = function() {
            if (xhr.readyState == XMLHttpRequest.DONE) {
              var data = xhr.responseText;
              var el = document.getElementById('data-div');
              if (!el) {
                return;
              }
              el.innerHTML = data;
            }
          }
          xhr.open('GET', url, true);
          xhr.send(null);
        };
    
        setTimeout(function(){addNumbers(7, 13);}, 1000);
    
      </script>
    </head>
    <body>
      <h1>With some luck, this will populate below:</h1>
      <div id="data-div">{{number}}</div>
    </body>
    </html>
    

    Now, first start the server for the Python process:

    $ python server.py
    

    While that is running, also start the web server to serve the html (also python3):

    $ python -m http.server 8000
    

    Then try navigating a browser to http://localhost:8000/test.html and you should see test.html make a request to http://localhost:8001/7/13 which will invoke the Python method MyHandler.do_GET() which sends back an HTTP response containing the sum of the numbers, 20. Credit goes to this website which I basically copy-pasted from: https://daanlenaerts.com/blog/2015/06/03/create-a-simple-http-server-with-python-3/ .

    This is as simple and raw as it gets, it will work great for a function or two but if you find yourself exporting lots of functionality to Python, it'd be worthwhile to upgrade to more advanced libraries and frameworks (both on the client/Javascript side and the server/Python side) that intend to be more robust and feature-complete for doing this type of thing.