<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Fernando Trias</title>
    <description>The latest articles on DEV Community by Fernando Trias (@ftrias).</description>
    <link>https://dev.to/ftrias</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F364305%2Fa51a6fb0-3472-4de0-922e-5c0cb5c6b73e.png</url>
      <title>DEV Community: Fernando Trias</title>
      <link>https://dev.to/ftrias</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ftrias"/>
    <language>en</language>
    <item>
      <title>Access JS &amp; DOM from Flask &amp; Bottle using Jyserver</title>
      <dc:creator>Fernando Trias</dc:creator>
      <pubDate>Wed, 15 Apr 2020 14:50:40 +0000</pubDate>
      <link>https://dev.to/ftrias/access-js-dom-from-flask-app-using-jyserver-23h9</link>
      <guid>https://dev.to/ftrias/access-js-dom-from-flask-app-using-jyserver-23h9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; jyserver allows access to Javascript and the DOM directly from Python and allows Javascript to call and access Python. It works seamlessly with Flask and other frameworks.&lt;/p&gt;

&lt;p&gt;For example, using jyserver, a server running Python can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"act"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Jump"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And it will automatically convert the expression to Javascript, send it to the browser and execute it causing the page to update. It can also work in reverse as in this HML snip:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.increment()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increase&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;When the button is clicked, &lt;code&gt;increment()&lt;/code&gt; is executed on the server. No additional code is needed. The framework provides the library that makes this possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zyW_nCQ2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/1%2AdxFmerJDNuvgBZtX-r0IaQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zyW_nCQ2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/1%2AdxFmerJDNuvgBZtX-r0IaQ.png" alt="HTML-&amp;gt;JS-&amp;gt;Python"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Keep it simple
&lt;/h1&gt;

&lt;p&gt;Traditionally, Python web frameworks like Flask or Django are a complicated interplay of HTML, CCS, Javascript and Python. Each page update involves some HTML, some Javascript, marshaling parameters, async communication to the server, some crunching in Python and a trip back to Javascript. Or some variation on that.&lt;/p&gt;

&lt;p&gt;Seems like a lot of work if you just want to create a simple a front end for an application. &lt;/p&gt;

&lt;p&gt;But what if all of that complexity was hidden and the language syntax dynamically provided the plumbing?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--USkt1PWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/1%2AsDf872SZI28X3DBUR6w5Fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--USkt1PWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/1%2AsDf872SZI28X3DBUR6w5Fw.png" alt="HTML &amp;lt;-&amp;gt; JS &amp;lt;-&amp;gt; Python"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example will illuminate. Let's say your page is very simple. You want to create a counter and a button to increase the count. You want everything to be controlled by the server. Your &lt;code&gt;index.html&lt;/code&gt; file would look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.increment()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increase&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9hioAgJ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2APK3hozxz6usEphnqXVw4cw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9hioAgJ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2APK3hozxz6usEphnqXVw4cw.png" alt="Increment app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your server needs to change the text for &lt;code&gt;count&lt;/code&gt; and respond to &lt;code&gt;increment()&lt;/code&gt;. Using jyserver, your server code would look like this for Flask:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jyserver.Flask&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;jsf&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;jsf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index_page&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'flask-simple.html'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In Bottle, this would be the code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from bottle import route, run

import jyserver.Bottle as jsb
import time

@jsb.use
class App:
    def __init__(self):
        self.count = 0
    def increment(self):
        self.count += 1
        self.js.document.getElementById("count").innerHTML = self.count

@route('/')
def index():
    return App.render(file='flask-simple.html')

run(host='localhost', port=8080)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That's all the code you need. &lt;code&gt;@jsf.use(app)&lt;/code&gt; connects the App class with your Flask application object &lt;code&gt;app&lt;/code&gt;. &lt;code&gt;@jsb.use&lt;/code&gt; does the same for Bottle. When the browser opens "/", the page will get rendered by &lt;code&gt;index_page()&lt;/code&gt;. &lt;code&gt;App.render()&lt;/code&gt; will add the appropriate Javascript. When the button is clicked on the browser, it calls &lt;code&gt;server.increment()&lt;/code&gt;, which causes &lt;code&gt;App.increment()&lt;/code&gt; to execute on the server, which then changes the DOM in real-time by updating &lt;code&gt;innerHTML&lt;/code&gt; for &lt;code&gt;count&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One of the principal benefits of this approach is that it makes it easy to put program logic in a single place. If you want the server to control things, you use the &lt;code&gt;self.js&lt;/code&gt; object to change the DOM and execute statements on the browser. On the other hand, if you want to control everything from the client, you can write the logic in Javascript and use the &lt;code&gt;server&lt;/code&gt; object to execute specific commands or query variables on the server.&lt;/p&gt;

&lt;p&gt;How is this accomplished? The secret sauce is in the &lt;code&gt;server&lt;/code&gt; object in the browser and the &lt;code&gt;self.js&lt;/code&gt; object in Python.&lt;/p&gt;

&lt;p&gt;This is what happens behind the scenes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;After starting, the server will listen for new http requests and forward special POST requests to &lt;code&gt;jyserver.Flask&lt;/code&gt; module. This is accomplished by the line &lt;code&gt;@jsf.use(app)&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When "/" is requested, jyserver will read &lt;code&gt;flask-simple.html&lt;/code&gt; and insert special Javascript code into the HTML that enables communication before sending it to the browser. This code creates the &lt;code&gt;server&lt;/code&gt; Proxy object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This injected code will cause the browser to send an asynchronous http request to the server asking for new commands for the browser to execute. Then it waits for a response in the background. This is used to transmit commands from the server to the browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the user clicks on the button &lt;code&gt;b1&lt;/code&gt;, the &lt;code&gt;server&lt;/code&gt; Proxy object is called. It will extract the method name--in this case &lt;code&gt;increment&lt;/code&gt;--and then make an http request to the server to execute that statement. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server will receive this http request, look at the App class, find a method with that name and execute it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The executed method &lt;code&gt;increment()&lt;/code&gt; first increases the variable &lt;code&gt;count&lt;/code&gt;. Then it begins building a Javascript command by using the special &lt;code&gt;self.js&lt;/code&gt; command. &lt;code&gt;self.js&lt;/code&gt; uses Python's dynamic language features &lt;code&gt;__getattr__&lt;/code&gt;, &lt;code&gt;__setattr__&lt;/code&gt;, etc. to build Javascript syntax on the fly. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When this "dynamic" statement get assigned a value (in our case &lt;code&gt;self.count&lt;/code&gt;), it will get converted to Javascript and sent to the browser, which has been waiting for new commands in step 3. The statement will look like: &lt;code&gt;document.getElementById("count").innerHTML = 1&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The browser will get the statement, evaluate it and return the results to the server. Then the browser will query for new commands in the background.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It seems complicated but this process usually takes less than a 0.01 seconds. If there are multiple statements to execute, they get queued and processed together, which cuts back on the back-and-forth chatter.&lt;/p&gt;

&lt;p&gt;As is typical in web applications, all communication is initiated by the browser, usually asynchronously. The server keeps a queue of pending commands and matches results as they are returned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--utZL0HEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AdEHjrnpV3UOT7FirXs-gMg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--utZL0HEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AdEHjrnpV3UOT7FirXs-gMg.png" alt="Flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The exception to asynchronous requests is when the browser initiates a server call. In that case, if there are no blocks, the browser waits for the server to respond when execution is complete. Often, this wait is not necessary, but it is used to make flow more predictable and avoid out-of-order execution.&lt;/p&gt;
&lt;h1&gt;
  
  
  The components
&lt;/h1&gt;

&lt;p&gt;There are three main parts to the system.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;HTTP server; in this case Flask&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Javascript "plumbing" and server object&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python "plumbing" and self.js object&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  The HTTP server
&lt;/h1&gt;

&lt;p&gt;The jyserver module must be configured to respond to POST requests to the page "/_process_srv0". All communication occurs through this URL.&lt;/p&gt;
&lt;h1&gt;
  
  
  The server object
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;server&lt;/code&gt; object lives in the browser and is used by Javascript to execute commands on the server. Basically, the &lt;code&gt;server&lt;/code&gt; object is a proxy for the Client app. It can call methods, query values and set values. For example, the following code will call &lt;code&gt;reset()&lt;/code&gt; on the server for every click.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.reset(0)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Zero&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In addition, setting a value on the server's Client object is possible:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.count=0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Zero&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You also can run methods and get return values.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getresult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;self.js&lt;/code&gt; object&lt;/p&gt;

&lt;p&gt;Python code uses the &lt;code&gt;self.js&lt;/code&gt; object to communicate with the browser. Let's say you have a function in Javascript on the browser.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.3&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;adjust&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This can be run from the Python server side using:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;adjust&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Factor is"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"2 x result is"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To change values, just set them in code.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.3&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;15.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;12.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The last statement will convert the structure to a Javascript dictionary. This data conversion is accomplished via the &lt;code&gt;json&lt;/code&gt; module in Python and the &lt;code&gt;JSON&lt;/code&gt; module in Javascript.&lt;/p&gt;

&lt;p&gt;Just to make life even easier, the &lt;code&gt;self.js&lt;/code&gt; object has a special shorthand for querying elements by id using the keyword &lt;code&gt;dom&lt;/code&gt;. These two statements are the same:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  A more complex example
&lt;/h1&gt;

&lt;p&gt;To illustrate a few more features, we'll create a stopwatch app. The design is to run a function on the server that updates the time on the HTML page every so often. We also provide two buttons: one to reset to zero and other to pause the updates.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"time"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;WHEN&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.reset()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Reset&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b2"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.stop()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Pause&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The class will need to define the reset() and the stop() methods. Just for kicks, we'll be dynamically changing the Pause callback.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jyserver.Flask&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;jsf&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;jsf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{:.1f}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Restart"&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restart&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Pause"&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Notice that when you click Stop, the &lt;code&gt;stop()&lt;/code&gt; method gets called, which changes the text and then modifies the &lt;code&gt;onclick&lt;/code&gt; callback of the button. The next click will then run &lt;code&gt;restart()&lt;/code&gt;, which will then change the text and callback.&lt;/p&gt;

&lt;p&gt;Next, we need a &lt;code&gt;main&lt;/code&gt; function that gets executed for every new session. In our case, the program runs for 1000 iterations and then terminates. When it ends, the server will also shut down. Naturally, you can convert this to an infinite loop and the program will never terminate. Or, if the function is omitted, then the server just listens for connections indefinitely.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;jsf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{:.1f}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Lastly, we start the server to handle page requests.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'clock.html'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MubYmN7A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ASJYr45CNqW6UNjwpuKNqzw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MubYmN7A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ASJYr45CNqW6UNjwpuKNqzw.png" alt="App"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Installation and source code
&lt;/h1&gt;

&lt;p&gt;jyserver is available in pip or conda.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;jyserver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The source code is found in the &lt;a href="https://github.com/ftrias/jyserver"&gt;Github repository jyserver&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qF2jUiUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-6a5bca60a4ebf959a6df7f08217acd07ac2bc285164fae041eacb8a148b1bab9.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ftrias"&gt;
        ftrias
      &lt;/a&gt; / &lt;a href="https://github.com/ftrias/jyserver"&gt;
        jyserver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Jyserver Web Framework with Pythonic Javascript Syntax
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h1&gt;
  
  
  Future directions
&lt;/h1&gt;

&lt;p&gt;Since jyserver's aim is to simplify the creation of web-based front ends for apps and kiosks. The plumbing to connect it to a framework is simple. &lt;/p&gt;

&lt;p&gt;Although jyserver itself is comples, the "glue" required to connect it to framework such as Flask or Django is not. Basically, you only need to reroute the "/_process_srv0" request. This is the entirety of the "glue" code that joins jyserver to Flask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, request
import json
import jyserver
import threading

def task(func):
    def wrapper(*args):
        server_thread = threading.Thread(target=func, args=args, daemon=True)
        server_thread.start()
    return wrapper

def use(flaskapp):
    def decorator(appClass):
        global context
        context = jyserver.ClientContext(appClass)

        @flaskapp.route('/_process_srv0', methods=['GET', 'POST'])
        def process():
            if request.method == 'POST':
                req = json.loads(request.data)
                result = context.processCommand(req)
                if result is None:
                    return ''
                return result
            else:
                return "GET reqeust not allowed"
        return context

    return decorator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, it's pretty simple to connect it to any other framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;Fernando "Fen" Trias is a serial entrepreneur, CEO of Vindor Music and an avid Python and C++ coder specializing in data science, embedded development and cybersecurity in the Boston areas. He is the author is jyserver, PyEmbedC, TeensyThreads and other open source projects.&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Hackers Exploit Two-factor Authentication to Steal Millions and How to Fix It</title>
      <dc:creator>Fernando Trias</dc:creator>
      <pubDate>Mon, 13 Apr 2020 21:41:54 +0000</pubDate>
      <link>https://dev.to/ftrias/hackers-exploit-two-factor-authentication-to-steal-millions-and-how-to-fix-it-59bl</link>
      <guid>https://dev.to/ftrias/hackers-exploit-two-factor-authentication-to-steal-millions-and-how-to-fix-it-59bl</guid>
      <description>&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Hackers hijack phone numbers to reset password and take over accounts, thereby stealing millions. Authenticator apps offer a better solution than using phone numbers for two-factor authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ao2BcALT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2A1ymQt0jD2n25zy5M.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ao2BcALT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2A1ymQt0jD2n25zy5M.jpg" alt="Hacker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you log into your bank, chances are it will send a code to your phone to confirm that it's really you and not some imposter. In addition, if you forget your password the bank will send you a code to confirm that it is you before letting you create a new password.&lt;/p&gt;

&lt;p&gt;This is called two-factor authentication. The first factor is your password. The second is you phone number. Since you control both, it's the double the security and is the basis of most current security systems on the web. It seems secure. Or is it?&lt;/p&gt;

&lt;h1&gt;
  
  
  SIM swapping
&lt;/h1&gt;

&lt;p&gt;The emerging threat known as SIM swapping puts this method at risk. In SIM swaps, hackers take over your phone number, either by physically stealing your phone's SIM card or by persuading your provider to assign your number to a new phone that they control. Once your number has been hijacked, they then proceed to visit your web sites and reset your passwords using the forgotten password link.&lt;/p&gt;

&lt;p&gt;To confirm it's really you, the web site sends your phone number a code, which will now go the hacker's new phone. The hacker enters the code and creates a new password. The web site will probably send you an email notifying you of this, but since your phone isn't connected to the network any more it won't receive the email.&lt;/p&gt;

&lt;p&gt;Stealing a SIM card--and thus a phone number--can be done in seconds. For AT&amp;amp;T, T-mobile and GSM-based providers, you phone number is tied to your SIM card, which is usually located in a small slide-out slot on the side of your phone, and thus easily accessible to anyone who is able to hold your phone for more than few seconds. Once they have the SIM card, they can insert into a new phone that will receive new text messages and calls.&lt;/p&gt;

&lt;p&gt;Another way to steal your number is to call your provider--AT&amp;amp;T, Verizon, T-mobile, Orange--and persuade them to transfer your phone number, perhaps by telling them your phone was stolen or lost. To do this you just need to know enough to answer some security question. But if you show up to a store pretending to be your target, you sometimes don't need to answer any questions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Losses mounting
&lt;/h1&gt;

&lt;p&gt;Financial accounts, social media and email are prime targets. In the most obvious cases, hackers reset your password in order to clean out your bank accounts and hold your other accounts for ransom, promising to disclose the new password only after being paid off.&lt;/p&gt;

&lt;p&gt;Crypocurrency accounts are particularly vulnerable because unlike with bank accounts, transfers are virtually untraceable and unrecoverable. For example, in a recent SIM swap heist, Michael Terpin, a successful cryptocurrency investor, lost $24 million in 2018. His number was hijacked not once, but twice. He recently won $75 million in a lawsuit against AT&amp;amp;T for enabling hacker to steal his phone number. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OFVHnwFE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/0%2Au52-DOpp20rTECd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OFVHnwFE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/0%2Au52-DOpp20rTECd4.png" alt="Terpin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Often, these crimes are perpetrated by criminal networks. For example, in May 2019, the US Justice Department filed charges against 9 AT&amp;amp;T and Verizon employees for providing criminals with private customer information that was then used to impersonate wealthy customers in order to perform the swap. One employee earned $3500 for information that enabled criminals to impersonate a single high-value customer.&lt;/p&gt;

&lt;p&gt;Hackers are even using the COVID-19 pandemic to extract information aimed at stealing your personal information, leading to SIM swapping. Read this &lt;a href="https://www.cnet.com/how-to/sim-swap-fraud-what-it-is-why-you-should-care-and-how-to-prevent-it/"&gt;CNet article&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;p&gt;In more elaborate cases, hackers may gather information about your associates and businesses in order to prepare for a larger scam. They add additional recovery information to your account so that they can easily regain access to your accounts at a later time. Then they transfer the phone back by returning your SIM card or telling the provider the undo the change--perhaps under the pretense that the lost phone has been found again. Unsuspecting victims might think they've merely forgotten their passwords when they try to log in again.&lt;/p&gt;

&lt;p&gt;For more chilling reading, &lt;a href="https://www.vice.com/en_us/article/vbqax3/hackers-sim-swapping-steal-phone-numbers-instagram-bitcoin"&gt;Vice wrote an expose&lt;/a&gt; that involved ordinary people:&lt;/p&gt;

&lt;p&gt;The problem has been growing for several years and may soon reach a critical point. In January 2020, six Senators sent a letter to the FCC, asking it to combat the rising danger of SIM swapping. &lt;/p&gt;

&lt;p&gt;To read even more, there is a &lt;a href="https://stopsimcrime.org/"&gt;web site dedicated to this problem&lt;/a&gt; where you can read about hundreds (or thousands) of hacks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;Granted, the problem is not necessarily using a phone number to perform two-factor authentication. Rather the problem lies in using a phone number to recover lost passwords. However, that distinction is lost in most cases. The majority of web sites implement both.&lt;/p&gt;

&lt;p&gt;You'd think providers would be more careful about swapping phone numbers, but that would be wishful thinking. AT&amp;amp;T and Verizon live and die by customer service. If a customer calls asking to transfer the phone number to an exciting new phone, they want to make the transition as smooth and hassle-free as possible.&lt;/p&gt;

&lt;p&gt;The other side of the problem is that it is common for people to have hundreds of passwords and so forgetting a password is a normal and frequent occurrence, exacerbating the problem because people want the least amount of hassle when resetting passwords, especially since they're already annoyed at having to remember so many passwords.&lt;/p&gt;

&lt;p&gt;A promising solution to this dilemma is the use of authentication apps such as Authy, Duo, Authenticator by Google and Microsoft Authenticator. To use these apps, you first unlock your phone and then confirm access, either by entering a code or via a direct connection to the web site. These apps use complex encryption to ensure that it's really your phone. In this scenario, the phone's locking mechanism ensures only you can access the app. Thus, the Authenticator app is only as secure as your phone's locking mechanism.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qH4Bfu4S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/0%2ANB0MKUQKkPKhwMNS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qH4Bfu4S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/0%2ANB0MKUQKkPKhwMNS.png" alt="Auth"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's well-known that older phone locking measures such as PIN codes and swipe patterns were susceptible to hacking. In one well-known hack, all that is required is angling the phone in order to observe the grease marks left on the screen and discern the last code entered on the phone. In addition, customers don't like them and don't turn them on.&lt;/p&gt;

&lt;p&gt;But with biometric identification such as fingerprint scanners and 3D facial recognition, people are now able to easily secure their phones against tampering with very little additional effort. Because of this, unlike hijacking a phone number, taking over a phone to access its apps is proving more challenging than ever.&lt;/p&gt;

&lt;p&gt;It's time to abandon the use of phone numbers and text codes. These techniques don't improve security very much and they have glaring shortcomings that are impossible to protect against. Web sites should use an authenticator app instead. It's about the same amount of effort for a user, but far more secure.&lt;/p&gt;

</description>
      <category>security</category>
    </item>
    <item>
      <title>Simple Kiosk Framework in Python</title>
      <dc:creator>Fernando Trias</dc:creator>
      <pubDate>Fri, 10 Apr 2020 16:53:26 +0000</pubDate>
      <link>https://dev.to/ftrias/simple-kiosk-framework-in-python-2ane</link>
      <guid>https://dev.to/ftrias/simple-kiosk-framework-in-python-2ane</guid>
      <description>&lt;p&gt;&lt;em&gt;Summary:&lt;/em&gt; jyserver creates HTML-based app front ends and kiosks where Python and Javascript seamlessly exchange data and execute functions. &lt;/p&gt;

&lt;p&gt;For example, using jyserver, a server running Python can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;act&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Jump&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And it will automatically convert the expression to Javascript, send it to the browser and execute it causing the page to update. It can also work in reverse as in this HML snip:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.increment()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increase&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When the button is clicked, &lt;code&gt;increment()&lt;/code&gt; is executed on the server. No additional code is needed. The framework provides the library that makes this possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F600%2F1%2AdxFmerJDNuvgBZtX-r0IaQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F600%2F1%2AdxFmerJDNuvgBZtX-r0IaQ.png" alt="HTML-&amp;gt;JS-&amp;gt;Python"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Keep it simple
&lt;/h1&gt;

&lt;p&gt;Traditionally, Python web frameworks like Flask or Django are a complicated interplay of HTML, CCS, Javascript and Python. Each page update involves some HTML, some Javascript, marshaling parameters, async communication to the server, some crunching in Python and a trip back to Javascript. Or some variation on that.&lt;/p&gt;

&lt;p&gt;Seems like a lot of work if you just want to create a simple a front end for an application. &lt;/p&gt;

&lt;p&gt;But what if all of that complexity was hidden and the language syntax dynamically provided the plumbing? Code Javascript in Python? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F600%2F1%2AsDf872SZI28X3DBUR6w5Fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F600%2F1%2AsDf872SZI28X3DBUR6w5Fw.png" alt="HTML &amp;lt;-&amp;gt; JS &amp;lt;-&amp;gt; Python"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What does that mean for your code? An example will illuminate. Let's say your page is very simple. You want to create a counter and a button to increase the count. You want everything to be controlled by the server. Your &lt;code&gt;index.html&lt;/code&gt; file would look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.increment()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increase&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2APK3hozxz6usEphnqXVw4cw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2APK3hozxz6usEphnqXVw4cw.png" alt="Increment app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your server needs to change the text for &lt;code&gt;count&lt;/code&gt; and respond to &lt;code&gt;increment()&lt;/code&gt;. Using jyserver, your server code would look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;jyserver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;
&lt;span class="n"&gt;httpd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;serving at port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;httpd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's all the code you need. When the browser calls &lt;code&gt;server.increment()&lt;/code&gt;, it causes &lt;code&gt;App.increment()&lt;/code&gt; to execute on the server, which then changes the DOM in real-time by updating &lt;code&gt;innerHTML&lt;/code&gt; for &lt;code&gt;count&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One of the principal benefits of this approach is that it makes it easy to put program logic in a single place. If you want the server to control things, you use the &lt;code&gt;self.js&lt;/code&gt; object to change the DOM and execute statements on the browser. On the other hand, if you want to control everything from the client, you can write the logic in Javascript and use the &lt;code&gt;server&lt;/code&gt; object to execute specific commands or query variables on the server.&lt;/p&gt;

&lt;p&gt;How is this accomplished? The secret sauce is in the &lt;code&gt;server&lt;/code&gt; object in the browser and the &lt;code&gt;self.js&lt;/code&gt; object in Python.&lt;/p&gt;

&lt;p&gt;This is what happens behind the scenes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;After calling &lt;code&gt;httpd.start()&lt;/code&gt;, the server will listen for new http requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When "/" is requested, jyserver will read &lt;code&gt;index.html&lt;/code&gt; and insert special Javascript code into the HTML that enables communication before sending it to the browser. This code creates the &lt;code&gt;server&lt;/code&gt; Proxy object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This injected code will cause the browser to send an asynchronous http request to the server asking for new commands for the browser to execute. Then it waits for a response in the background.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the user clicks on the button &lt;code&gt;b1&lt;/code&gt;, the &lt;code&gt;server&lt;/code&gt; Proxy object is called. It will extract the method name--in this case &lt;code&gt;increment&lt;/code&gt;--and then make an http request to the server to execute that statement. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server will receive this http request, look at the App class, find a method with that name and execute it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The executed method &lt;code&gt;increment()&lt;/code&gt; first increases the variable &lt;code&gt;count&lt;/code&gt;. Then it begins building a Javascript command by using the special &lt;code&gt;self.js&lt;/code&gt; command. &lt;code&gt;self.js&lt;/code&gt; uses Python's dynamic language features &lt;code&gt;__getattr__&lt;/code&gt;, &lt;code&gt;__setattr__&lt;/code&gt;, etc. to build Javascript syntax on the fly. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When this "dynamic" statement get assigned a value (in our case &lt;code&gt;self.count&lt;/code&gt;), it will get converted to Javascript and sent to the browser, which has been waiting for new commands in step 3. The statement will look like: &lt;code&gt;document.getElementById("count").innerHTML = 1&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The browser will get the statement, evaluate it and return the results to the server. Then the browser will query for new commands in the background.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It seems complicated but this process usually takes less than a 0.01 seconds. If there are multiple statements to execute, they get queued and processed together, which cuts back on the back-and-forth chatter.&lt;/p&gt;

&lt;p&gt;As is typical in web applications, all communication is initiated by the browser asynchronously. The server keeps a queue of pending commands and matches results as they are returned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AdEHjrnpV3UOT7FirXs-gMg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AdEHjrnpV3UOT7FirXs-gMg.png" alt="Flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The exception to asynchronous requests is when the browser initiates a server call. In that case, the browser waits for the server to respond when execution is complete. Often, this wait is not necessary, but it is used to make flow more predictable and avoid out-of-order execution.&lt;/p&gt;
&lt;h1&gt;
  
  
  The components
&lt;/h1&gt;

&lt;p&gt;There are three main parts to the system.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;HTTP server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Javascript "plumbing" and server object&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python "plumbing" and self.js object&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  The HTTP server
&lt;/h1&gt;

&lt;p&gt;The jyserver module leverages Python's &lt;code&gt;http.server.ThreadingTCPServer&lt;/code&gt; to service requests. On the plus side, this means it's pretty robust and there are no extra dependencies. On the negative side, this is a very simple server that is insecure out-of-the-box. jyserver adds some security by isolating instances of the Client application by means of a unique session id so that different sessions cannot access each other's data. But given the dynamic nature of the execution, it's still possible for malicious clients to cause havoc. However, since the main purpose of jyserver is to create application front ends in controlled environments, this is not a big problem.&lt;/p&gt;

&lt;p&gt;For added security, when the server starts, it will listen on a specific port and interface. This means you can restrict connections to only accept local connections and reject network connections. This makes it ideal for kiosks.&lt;/p&gt;

&lt;p&gt;When the server receives a web page request, it will first look for a matching method name in the Client application and execute it. If there is no match, it will look for a file with that name and send it to the browser. In this way, it works similarly to most web servers.&lt;/p&gt;

&lt;p&gt;In addition, the server will run a method named main if it is available. Otherwise, it will loop forever waiting for requests.&lt;/p&gt;
&lt;h1&gt;
  
  
  The server object
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;server&lt;/code&gt; object lives in the browser and is used by Javascript to execute commands on the server. Basically, the &lt;code&gt;server&lt;/code&gt; object is a proxy for the Client app. It can call methods, query values and set values. For example, the following code will call &lt;code&gt;reset()&lt;/code&gt; on the server for every click.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.reset(0)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Zero&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In addition, setting a value on the server's Client object is possible:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"b1"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"server.count=0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Zero&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You also can run methods and get return values.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getresult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;self.js&lt;/code&gt; object&lt;/p&gt;

&lt;p&gt;Python code uses the &lt;code&gt;self.js&lt;/code&gt; object to communicate with the browser. Let's say you have a function in Javascript on the browser.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.3&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;adjust&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This can be run from the Python server side using:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;adjust&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Factor is&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2 x result is&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To change values, just set them in code.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.3&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;15.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;12.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The last statement will convert the structure to a Javascript dictionary. This data conversion is accomplished via the &lt;code&gt;json&lt;/code&gt; module in Python and the &lt;code&gt;JSON&lt;/code&gt; module in Javascript.&lt;/p&gt;

&lt;p&gt;Just to make life even easier, the &lt;code&gt;self.js&lt;/code&gt; object has a special shorthand for querying elements by id using the keyword &lt;code&gt;dom&lt;/code&gt;. These two statements are the same:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  A more complex example
&lt;/h1&gt;

&lt;p&gt;To illustrate a few more features, we'll create a stopwatch app. The design is to run a function on the server that updates the time on the HTML page every so often. We also provide two buttons: one to reset to zero and other to pause the updates.&lt;/p&gt;

&lt;p&gt;The first thing to note is that instead of serving out an index.html file we embed the HTML in the file itself. That way there are no external dependencies.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;jyserver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
&amp;lt;p id=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;WHEN&amp;lt;/p&amp;gt;
&amp;lt;button id=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; onclick=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;server.reset()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;Reset&amp;lt;/button&amp;gt;
&amp;lt;button id=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; onclick=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;server.stop()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;Pause&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The class will need to define the reset() and the stop() methods. Just for kicks, we'll be dynamically changing the Pause callback.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{:.1f}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Restart&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restart&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pause&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notice that when you click Stop, the &lt;code&gt;stop()&lt;/code&gt; method gets called, which changes the text and then modifies the &lt;code&gt;onclick&lt;/code&gt; callback of the button. The next click will then run &lt;code&gt;restart()&lt;/code&gt;, which will then change the text and callback.&lt;/p&gt;

&lt;p&gt;Next, we need a &lt;code&gt;main&lt;/code&gt; function that gets executed for every new session. In our case, the program runs for 1000 iterations and then terminates. When it ends, the server will also shut down. Naturally, you can convert this to an infinite loop and the program will never terminate. Or, if the function is omitted, then the server just listens for connections indefinitely.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{:.1f}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Lastly, we start the server.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;httpd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;serving at port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;httpd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ASJYr45CNqW6UNjwpuKNqzw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ASJYr45CNqW6UNjwpuKNqzw.png" alt="App"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Installation and source code
&lt;/h1&gt;

&lt;p&gt;jyserver is available in pip or conda.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;jyserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The source code is found in the &lt;a href="https://github.com/ftrias/jyserver" rel="noopener noreferrer"&gt;Github repository jyserver&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ftrias" rel="noopener noreferrer"&gt;
        ftrias
      &lt;/a&gt; / &lt;a href="https://github.com/ftrias/jyserver" rel="noopener noreferrer"&gt;
        jyserver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Jyserver Web Framework with Pythonic Javascript Syntax
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h1&gt;
  
  
  Future directions
&lt;/h1&gt;

&lt;p&gt;Since jyserver's aim is to simplify the creation of web-based front ends for apps and kiosks, it lacks a lot of the bells and whistles found in more complex frameworks such as Flask or Django, which are aimed at creating web sites. Specifically, jyserver lacks user logins, templates, substitutions and many other features. This can be remedied in two ways. First, existing frameworks can use the dynamic programming tricks and techniques used by jyserver to further simplify their APIs. Or, jyserver can grow to encompass more functionality, while still retaining the philosophy of simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;Fernando "Fen" Trias is a serial entrepreneur, CEO of Vindor Music and an avid Python and C++ coder specializing in data science, embedded development and cybersecurity in the Boston areas. He is the author is jyserver, PyEmbedC, TeensyThreads and other open source projects.&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
