Preface
Goal: Gather All The Stuff Together
This is a multiparts article.
We need to integrate all panel into just one script.
Separate task into its own class.
Combine all the different class.
Run them in concurrent fashioned,
and display each fancy output in its own rich
panel.
Terminal User Interface
Yay
I finally made with my first TUI Application.
Good job!
Preparation
$ pip install openpyxl websockets tomli watchfiles rich aiohttp jinja2 aiohttp_jinja2
21: Separate Class
Clean Up
I just realize that python logging library, display all the logs. Not just the web server, but also web socket, and watchfiles. I think I need to separate, the logging class, and the web server class.
Web Server
The web server class along with Jinja2
,
is turn out to be very short:
Nothing special. I just copy paste from official documentation. But for use with asynchronous.
from aiohttp import web
import jinja2, aiohttp_jinja2
@aiohttp_jinja2.template("index.jinja")
class HomeHandler(web.View):
async def get(self):
return {}
class AIOWeb:
async def task_web(self):
app = web.Application()
...
This works for python 3.10.
For python 3.11, be sure to upgrade aiohttp_jinja2
to 1.5.1
.
Logging
The rest is this hacky logging routine. You can obtain the python class here:
I also clean up the method name, to differ the private method access, as shown in skeleton below.
class Log2Panel:
def __init__(self,
def __get_lines(self):
def __capture(self, message):
def __split(self, line):
def __get_panel(self) -> Panel:
def __get_layout(self) -> Layout:
async def do_log(self):
Universal logging, can be set in constructor. Do not forget to also initialize, layout stuff.
def __init__(self,
ref_live, ref_layout, layout_name):
# rich: required in descendent class
self.live = ref_live
self.layout = ref_layout
self.layout_name = layout_name
...
logging.basicConfig(
stream=self.log_stream,
level=logging.INFO)
So we can display all result as below:
Panel above display application wide logging. Not just the web server information.
22: Gather Task
Concurrency
Manage multiple task is not scary, but however I still need to carefully manage the code.
Python Source Code
You can obtain the python class here:
Custom Package
We start with iporting our own custom module library.
import asyncio
import xl2web_25c, xl2web_25d
import log2panel_29, aioweb_29
from rich.live import Live
from rich.panel import Panel
from rich.layout import Layout
Skeleton
This script is basically a rich application. Here is the skeleton:
class MultiPanels:
def __make_layout(self):
def __get_layout_empty(self) -> Layout:
def __prepare_watcher(self):
async def main(self):
Empty Panel
No code intact. The same as previous code.
Triple Panel
How you manage your layout is up to yo. However, this is mine.
def __make_layout(self):
# Define the layout.
self.layout = Layout(name="root")
self.layout.split(
Layout(name="top"),
Layout(name="bottom"),
)
self.layout['top'].split_row(
Layout(name="left"),
Layout(name="right"),
)
Manage Task
Since we have many task, it is better to be well prepared.
Create each class instance, one by one.
def __prepare_watcher(self):
self.live = Live()
self.watch_left = xl2web_25c.Xl2Web_c(
'sheetGlobal', self.live, self.layout, 'left')
self.watch_right = xl2web_25d.Xl2Web_d(
'sheetDaily', self.live, self.layout, 'right')
self.watch_log = log2panel_29.Log2Panel(
self.live, self.layout, 'bottom')
Await All
Run baby, run…
async def main(self):
self.__make_layout()
self.__prepare_watcher()
with self.live:
self.live.update(self.__get_layout_empty())
task_web = aioweb_29.AIOWeb().task_web
task_left = asyncio.create_task(
self.watch_left.main())
task_right = asyncio.create_task(
self.watch_right.main())
task_log = asyncio.create_task(
self.watch_log.do_log())
Now you can run them all concurrently
await(task_web())
await(task_left)
await(task_right)
await(task_log)
Note that, the simple web server is not in made in create_task
,
so we should run it before other tasks.
You can manage the simple web server,
to be created in create_task
as well, if necessary.
Asynchronous Entry Point
Actually, it is just program entry point, in asynchronous fashioned.
class MultiPanels:
...
multi = MultiPanels()
try:
asyncio.run(multi.main())
except KeyboardInterrupt:
print('Goodbye!')
Terminal User Interface
Conclusion
Our journey is complete here. There is still also chart, and testing. But I’m still pretty busy these days. Maybe I’ll skip this time.
What do you think?