KubeRider :: events and signals with Pyqt5
Published: 2019-11-24 12:57:52

---
title: KubeRider :: events and signals with Pyqt5
published: true
date: 2019-07-28 15:04:02 UTC
tags: 
canonical_url: https://deskriders.dev/kuberider-events-and-signals-with-pyqt5/
---

 ![](https://deskriders.dev/media/posts/5/kuberider-display-contexts.png)

In this post, I'll go through the data flow in the KubeRider application. The application is still fairly small and I'm experimenting with few ideas as I add more features.

There are four main components in the application. 

- [UI Widgets](https://github.com/namuan/kube-rider/tree/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/ui)
- [Presenters](https://github.com/namuan/kube-rider/tree/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/presenters)
- [Interactors](https://github.com/namuan/kube-rider/tree/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/domain)
- [Data Storage](https://github.com/namuan/kube-rider/tree/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/entities)

I've found the using events to communicate between components makes it easy to decouple different parts of the application. However it comes with its own challenges which I'll try to cover in a separate post.

So taking an example usecase of loading the available contexts when the application starts up, here is a diagram showing the communication between the different components.

![](https://deskriders.dev/media/posts/5/kube-rider-components.jpeg)

And the code behind covering the implementation of this feature.

It starts with [KubeRiderMainPresenter](https://github.com/namuan/kube-rider/blob/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/presenters/kube_rider_main_presenter.py#L7) which is the presenter behind the main form. Its job is to initialise few things and then leave the rest of the use-cases to component specific presenters.

```
def after_window_loaded(self):
 if not self.initial_load:
 return

 self.initial_load = False
 self.contexts_loader.load_contexts()
 self.check_updates()
```

The context loader is an instance of [ContextsLoaderInteractor](https://github.com/namuan/kube-rider/blob/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/domain/contexts_interactor.py#L5) which handles the execution of kubectl command to load contexts. 

It runs the `kubectl config get-contexts --output='name'` command to get the list of contexts, [parses it](https://github.com/namuan/kube-rider/blob/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/domain/contexts_interactor.py#L14) and saves it in [application state](https://github.com/namuan/kube-rider/blob/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/entities/model.py#L11).

Then it [emits an event](https://github.com/namuan/kube-rider/blob/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/domain/contexts_interactor.py#L18) to notify that the contexts are successfully loaded.

```
app.data.signals.contexts_loaded.emit()
```

This event is then consumed in the [ToolbarPresenter](https://github.com/namuan/kube-rider/blob/a777b79d3693dedeb4ac070bb9f6edc1140b2b64/kuberider/presenters/toolbar_presenter.py#L19) to refresh the user interface in the toolbar.

```
app.data.signals.contexts_loaded.connect(self.on_contexts_loaded)
```

 Which then loads the contexts from state and populates the combo box.

```
def on_contexts_loaded(self):
 contexts_ui = self.__get_combox_box("Contexts")
 contexts_ui.clear()
 contexts = app.data.load_contexts()
 for ctx in contexts:
 contexts_ui.addItem(ctx)
```

The chain continues after that with loading the currently active context and then the namespaces based on that context but the general pattern follows the same principle as above.