Where to Discuss?

Local Group

Preface

Goal: Add common feature such as configuration, terminal interface, and web server

This is a multiparts article.


13: TOML Configuration

Instead of polluting our script with user configuration. We could put our variable in a configuration outside the script. The latest popular format is after the YAML era is TOML. This TOML syntax looks like INI, but support indentation.

Official Documentation

TOML Validation

Testing

Checking TOML validation can be done here:

TOML Configuration

Our configuration could be splitted, between development and production. With each has its own settings.

  1. spath
  2. spreadsheet file
  3. Websocket: IP address
  4. Websocket: Port

You can examine the complete config.toml for our project.

For example, we can set the mode:

# environment: "development" or "production"
environment  = "development"

Then we can set development configuration is as below, we use broadcast IP.

[development]
  [development.sheetGlobal]
    site = "0.0.0.0"
    port = "8765"
    path = "/home/epsi/awatch/code-02-enh"
    file = "test-c.xlsx"
  [development.sheetDaily]
    site = "0.0.0.0"
    port = "8767"
    path = "/home/epsi/awatch/code-02-enh"
    file = "test-d.xlsx"

Python: TOML Configuration: Development

While the production is as below:

[production]
  [production.sheetGlobal]
    site = "localhost"
    port = "8765"
    path = 'C:\Users\GK 35\Documents'
    file = "global.xlsx"
  [production.sheetDaily]
    site = "localhost"
    port = "8767"
    path = 'C:\Users\GK 35\Documents'
    file = "daily.xlsx"

Python: TOML Configuration: Production

Simple TOML Reader

The code is shorter than I thought.

import tomli
import pprint

sheet_ident = 'sheetGlobal'

with open('config.toml', 'rb') as file_obj:
  config_root  = tomli.load(file_obj)
  env          = config_root['environment']
  config_env   = config_root[env]
  config_sheet = config_env[sheet_ident]

  pprint.pprint(config_sheet)

With output as below dictionary:

Python: TOML Configuration: Simple Reader

Constructor Changes

Simplify Constructor Parameter

Since we can’t use -, consider, name our class to xl2web_24.py.

The simple reader above could be apply to our parent class.

import asyncio, websockets, json, os, tomli
from watchfiles import awatch

# Excel to Web, Base Class
class Xl2WebBase:
  def __init__(self, sheet_ident):
    with open('config.toml', 'rb') as file_obj:
      config_root  = tomli.load(file_obj)
      env          = config_root['environment']
      config_env   = config_root[env]
      config_sheet = config_env[sheet_ident]

      # save initial parameter
      self.filepath = config_sheet['path']
      self.filename = config_sheet['file']
      self.site = config_sheet['site']
      self.port = config_sheet['port']

    # websocket broadcast collection
    self.connections = set()

    # self.xlsx required in descendent class
    self.xlsx = None

Python: TOML Configuration: Simplify Constructor Parameter

Beside the constructor. The rest remain the same.

Python: TOML Configuration: Skeleton

We still have to alter our descendant class. But the idea is we can create class instance with something like:

example = Xl2Web_c('sheetGlobal')

or

example = Xl2Web_d('sheetDaily')

Instead of this long paramater argument.

example = Xl2Web_c(
  '/home/epsi/awatch/code-02-enh', 'test-c.xlsx',
  'localhost', 8765)

This way, for any changes, user does not need to alter the script directly.

Descendant Changes: First Sheet

Since we alter the parent class filename, we should also change the import statement.

import asyncio, openpyxl, time
import xl2web_24

from openpyxl import load_workbook

# Excel to Web, Example Class
class Xl2Web_c(xl2web_24.Xl2WebBase):
  ...

# Program Entry Point
example = Xl2Web_c('sheetGlobal')
...

Python: TOML Configuration: Descendant Brief

Descendant Changes: Second Sheet

And so does the other script for the second script.

import asyncio, openpyxl, time
import xl2web_24

from openpyxl import load_workbook

# Excel to Web, Example Class
class Xl2Web_d(xl2web_24.Xl2WebBase):
  ...

# Program Entry Point
example = Xl2Web_d('sheetDaily')
...

Python: TOML Configuration: Descendant Brief

Output in Terminal

Check in terminal, if everything work as usual.

Python: TOML Configuration: Output in Terminal


What is Next 🤔?

We are done with configuration. But we still have issue. The end user still have to run two script, and maybe web server. Three script at once is annoying.

This can be solved by running them into just one script. Each task in separate panel.

Consider continue reading [ Excel - Monitor - Dual Rich Panel ].