Forum › Forums › antiX-development › Development › antiX Diagnostic Suite For Hardware Testing (proposal) › Reply To: antiX Diagnostic Suite For Hardware Testing (proposal)
I am not sure how much time I could dedicate to this project above occasional “mentoring”.
IMHO, the start should be at least a basic idea of strategy for the modular framework.
First, consider a single tool (ST) workflow:
ST.1) Detect presence of a tool:
ST.1.A) a package name – may change over time; parsing output of subprocess.call(), ‘apt-cache policy’ or ‘dpkg -l’ or use python3-apt* as a dependency?
ST.1.B) a command – shutil.which() is not None
ST.1.C) a binary file – os.path.isfile()
If a tool is missing, is there a plan to enable initiating installation from within the tool?
What if the tool is not in repository – provide a link?
ST.2) Collect switches|options for the tool.
This should most likely be version aware.
In case of GUI, combination of several types of widgets – verbosity (spinbox?), feature on|off (checkbuttons)
ST.3) Call the tool with appropriate switches – subprocess.call()?
Handle errors, root privileges required.
‘lshw’ works without root but it provides less information.
Is that OK? Should there be a switch to select or require full-run by default?
Some tools may run for a long time, need to repeatedly insert the root password! (Is there a safe workaround?)
ST.4) Parse the output.
What if there is no dedicated output file for the tool (and no option to specify one) – suitable redirection or or store in Python’s ‘*.stdout’ attribute directly?
ST.5) Create a corresponding block of a report.
The above leads me to propose the following for consideration – there should be a configuration table (a CSV file?) matching a tool (command or full-path binary) to a package and its output file, i.e.
A) tool = command|binary file
B) package in repository (if available),
C) (package|program) version (parsing program version could get tricky, package is easier but beware of both Debian and antiX-specific naming suffices),
D) output files where the info is stored (if empty, redirect STDOUT + STDERR to a temporary file or files such as ‘/tmp/aux_hw_test_<tool name>_$(date +%Y-%m-%d).tmp’ or store in Python’s ‘*.stdout’ attribute directly?)
D) Beware of Debian 13+ (Trixie and possibly ongoing) on low-RAM systems https://www.debian.org/releases/trixie/release-notes/issues.html#the-temporary-files-directory-tmp-is-now-stored-in-a-tmpfs
If I were to write it, here’s how I (think I) would proceed:
Each tool a single Python file-name script (or even one file for each version of a given tool) and the overall “master” script.
# Global variables in this script may partially replace the "configuration" script
class SingleTool():
""" Single class for a single tool; if version specific, then consider reducing code duplication using inheritance """
def __init__():
def compose_command(<object containing collected switches>):
def parse_output():
def partial_report() -> str:
def does_all_that() -> str:
""" Composes the above functions """
TOOL_MAP: dict[str, Any] = {
'ToolName':<SingleToolClass>, # This might be duplicated if the string ToolName includes version
}
class OverAllStuff():
""" OverAll stuff """
def __init__():
partial_report: str = '' # Can be a HTML tree instead
self.tool_set: dict[str, Any] = {} # To store tool "configuration"|switches
def detect_tools():
""" Iterate over the tool-table """
def ask_to_install_missing_tools():
""" It may not be needed """
def build_display_or_gui_based_on_tools():
def collect_settings_for_each_tool():
""" Get current values of widgets - fills the 'self.tool_set' """
def initiate_dummy_html():
""" Start an empty report, e.g. HTML """
def finalise_report():
""" Properly end the report, e.g. HTML """
def iterate_over_tools():
for ToolName, <object containing collected switches> in self.tool_set.items():
partial_report += TOOL_MAP[ToolName].does_all_that(<object containing collected switches>)
def does_all_that():
""" Composes all the above functions """
EDIT:
The configuration object for each tool could be a list-valued dictionary:
BIN_TOOL: str = <path to the binary file OR command calling the tool>
DAT_TOOL: dict[str, list] = {
<text label (of the tool in the GUI|TUI>:[<cli option text>, <unitialised widget>, <a dummy value>]
}
Once the GUI is built from the individual DAT_TOOLs, the widget is initialised and its value can be set in the GUI.
When calling the individual tool, one simply passes the set values instead of individual widgets, i.e.
dat_tool: dict[str, list[str]] = {<text label (of the tool in the GUI|TUI>:[<str: cli option text>, <str: value set to the widget>, , <str: a dummy value as a string>]}
When composing the command, a general approach is to build it up from the ‘dat_tool’ acquired from the GUI
cmd_runs: list[str] = [BIN_TOOL]
for val_item in dat_tool.values():
if val_item[-2] != val_item[-1]:
cmd_runs += val_item[:-1]
Iterations in code (and there will be many) are said to be slow but expecting that running the tools will take significantly more time.
Somehow, I believe that this could actually be reinventing the wheel…
- This reply was modified 12 months ago by sybok. Reason: Dictionary based object describing CLI-options for a given tool suggested
- This reply was modified 12 months ago by sybok.