### Tkinter and Asyncio

###### Thu 18 February 2021
Asynchronous process results waiting (Photo credit: Wikipedia)

Graphical interfaces are typically the kind of object that can take advantage of asynchrounous programming as a GUI spend lot of time waiting for user input.

Tkinter <https://docs.python.org/3/library/tkinter.html#module-tkinter>_ is a kind of standard for graphical interface on python. It was designed long before python3.5 and the introduction of asyncio in the standard library. Thus, it heavily rely on threading to allow non-blocking operations.

## Asyncio refresh

This is a quick refresh on how asyncio works in python. This is not meant to be a tutorial.

Concurrent programming can be handled with threads. This mechanism works well in many compiled languages (such as C). In python (and in many other languages such as Ruby), only one thread can be executed simultaneously. More precisely, only one thread can hold the GIL and only a thread holding the GIL can execute python code.

When using thread, the system decides when a thread is interrupted and if another one is allow to run some python code before resuming. Thus, even if you have only one python thread running at a time, a global variable can be modified between python instructions (and you will always be unlucky if you don't use synchronisation mechanism such as mutex, semaphores, ...)

On the other hand, asyncio runs an event loop into which are put tasks. I won't go into the differences between awaitable, tasks, coroutines and futures. A tasks explicitly states when it can be interrupted waiting for the result of another tasks or operation (keyword await). The event loop decides which task is the next to run. To do so, it keeps a list of tasks with their respective states (pending and ready to run, sleeping and waiting for an external resources --usually an IO--, finished with the returned value or an error code, cancelled, and running)

A simple example is provided by the official documentation. It uses asyncio.sleep() to simulate the wait for an external resource that takes ate least the indicated delay.

import asyncio
import time

async def say_after(delay, what):
await asyncio.sleep(delay)  # interrupt the task here waiting the result of asyncio.sleep()
print(what)

async def main(delay, what):
print(f"started at {time.strftime('%X')}")
await say_after(1, "hello")  # interrupt the task here waiting for the result of "say_after"
await say_after(2, "world")
print(f"finished at {time.strftime('%X')}")

asyncio.run(main())  # start the event loop putting main() inside


To add a bit of complexity and randomness, we can use faker to decide what to say and random.randint to fix delays.

To fix the arguments of say_after:

from random import randint

import faker

word_generator = faker.Faker()
words = word_generator.words(7)
arguments = [(randint(0, 5), word) for word in words]


And now let's create and run tasks:

tasks = [
for delay, what in arguments
]


## Tkinter refresh

Tkinter uses Frames and a new window can be build using tk.Toplevel(). I have few experience with this library, thus I decided to use a very limited set of widgets. For instance, I use tk.Button() just to display text on an area:

import tkinter as tk

class EmptyFrame(tk.Frame):
def __init__(self, parent, message):
super().__init__(parent)
self.root = parent
self.message = message
self.create_entry()
self.pack()

def create_entry(self):
self.area = tk.Button(self, text=self.message)
print("Message: ", self.message)
self.area.pack()


To create a new window with a message:

parent = tk.Toplevel(self.master)
EmptyFrame(parent, msg)


## All together

The solution I found to use asyncio with Tkinter is to start a thread in charge of running the asyncio event loop. The other thread (the first one started by python) is here only to display the first window and start the asyncio thread.

To do so, I added lots of levels of indirections. I coded the following methods:

• async_process(): the main asyncio process (equivalent to the main() in the example above).
• run(): start the asyncio loop, calling async_process()
• action(): handles the thread running the asyncio loop. Its main job is to call run()

Putting all together (a file is available here)

import asyncio
import tkinter as tk
from datetime import datetime
from random import randint

import faker

class Application(tk.Frame):
"""main frame"""

def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()

word_generator = faker.Faker()
words = word_generator.words(5)
self.messages = [(randint(0, 5), word) for word in words]
print(self.messages)

"""Add button to start the action
"""
self.btn = tk.Button(self, text="Big button", command=self.action)
self.btn.pack()

def action(self):

def run(self):
"""start asyncio loop"""
asyncio.run(self.async_process())

async def async_process(self):
self.start_time = datetime.now()
self.new_area = tk.Button(
self,
text="\n".join(
"\t".join((str(delay), message)) for delay, message in self.messages
),
)
self.new_area.pack()
for delay, what in self.messages
]

async def display_after(self, delay, what):
await asyncio.sleep(delay)
now = datetime.now()
msg = f"{now} \t {what}"
parent = tk.Toplevel(self.master)
EmptyFrame(parent, msg)

class EmptyFrame(tk.Frame):
def __init__(self, parent, message):
super().__init__(parent)
self.root = parent
self.message = message
self.create_entry()
self.pack()

def create_entry(self):
self.area = tk.Button(self, text=self.message)
print("Message: ", self.message)
self.area.pack()

if __name__ == "__main__":
root = tk.Tk()
app = Application(master=root)
app.mainloop()


This is not the cleanest way of doing it, neither the minimal one, but it works and cover most of the cases I want.

Category: howto Tagged: python asyncio

### Latex generator using Jinja

###### Wed 11 November 2020

The goal is to generate a PDF file using python. I decided to generate $$\LaTeX$$.

## Pipeline

I decided to use jinja as its documentation mention it.

\begin{equation*} \boxed{\text{Jinja template}} \xrightarrow[\text{python}]{} \boxed{\LaTeX} \xrightarrow[\text{pdflatex}]{} \boxed{\text{PDF}} \end{equation*}

The …

Category: LaTeX Tagged: python LaTeX Jinja

### HTTP to HTTPS

###### Fri 24 July 2020
Public key (Photo credit: Michael Drummond)

The goal was to migrate from HTTP to HTTPS

## HTTPS overview

The HTTPS protocol rely on TLS (previously SSL) to ensure data integrity (data cannot be modified unnoticed), confidentiality (requested URL and content are only known by end points) and authentication (end points are …

Category: network security Tagged: Unix Debian tools how to network security

### Wikipedia crawling (part II)

###### Thu 11 June 2020
Crawling (Photo credit: Wikipedia)

Wikipedia has specific infobox templates. This is the normalized way to enter specification inside wikipedia articles. It provides templates with already defined fields. For example the planet template has fields such as periapsis or …

Category: how to Tagged: python wikipedia html data retrieval

### Travis setup

###### Tue 12 May 2020
One job in continuous integration pipeline (Photo credit: Wikipedia)

The goal is to setup a CI pipeline based on Travis with external dependencies integrated to a Github repository

## Travis basics

To enable Travis integration in Github, one must edit ./.travis.yml file.

I won't go into detail. The setup is …

Category: how to Tagged: travis ci how to

### Wikidata crawling

###### Sun 26 April 2020
Graph database representation (Photo credit: Wikipedia)

I wish to have reliable data about vehicles. I decided to rely on one large source, namely Wikipedia. I chose it because it is reviewable and most of the time reviewed, and regularly updated and completed.

## Wikipedia - Wikidata relationship

Wikidata items are made to …

Category: how to Tagged: python wikipedia wikidata html

### Differential equation in python

###### Sat 04 April 2020
Second order differential equation (Photo credit: Wikipedia)

In python, differential equations can be numerically solved thanks to scipy [1]. Is usage is not as intuitive as I expected.

## Simple equation

Let's start small. The first equation will be really simple:

\begin{equation*} \frac{\partial{f}}{\partial{t}} = a \times f …

Category: maths Tagged: python maths equation

### Zombie propagation

###### Sat 21 March 2020
Zombie favorite food warning (Photo credit: wikipedia)

I recently read a paper [1] trying to model a disease propagation. I wanted to play with this model.

## The model

The model is know as "SIR" as it divide the population into 3 groups:

• S: suceptible to become a zombie
• I: infected …

Category: maths Tagged: python maths zombie