Source code for octadist.src.scripting

# OctaDist  Copyright (C) 2019-2024  Rangsiman Ketkaew et al.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import tkinter as tk

import octadist


[docs] class ScriptingConsole: """ Start scripting interface for an interactive code. User can access to class variable (dynamic variable). +------------+ | Output box | +------------+ | Input box | +------------+ Parameters ---------- root : object Passing self object from another class to this class as root argument. See Also -------- settings : Program settings. Examples -------- >>> import tkinter as tk >>> master = tk.Tk() >>> console = ScriptingConsole(master) >>> console.scripting_start() """ def __init__(self, root): self.root = root self.wd = None self.history_command = []
[docs] def scripting_start(self): """ Start scripting console. """ self.wd = tk.Toplevel(self.root.master) if self.root.octadist_icon is not None: self.wd.wm_iconbitmap(self.root.octadist_icon) self.wd.title("OctaDist Scripting Interface") self.wd.bind("<Return>", self.script_execute) self.wd.resizable(0, 0) lbl = tk.Label(self.wd, text="Output:") lbl.grid(padx="5", pady="5", sticky=tk.W, row=0, column=0) self.box_script = tk.Text(self.wd, width=70, height=20) self.box_script.grid(padx="5", pady="5", row=1, column=0, columnspan=2) lbl = tk.Label(self.wd, text="Input:") lbl.grid(padx="5", pady="5", sticky=tk.W, row=2, column=0) self.entry_script = tk.Entry(self.wd, width=62) self.entry_script.grid(padx="5", pady="5", sticky=tk.W, row=3, column=0) btn_script = tk.Button(self.wd, text="Run") btn_script.bind("<Button-1>", self.script_execute) btn_script.grid(padx="5", pady="5", row=3, column=1) self.box_script.insert( tk.INSERT, "Welcome to OctaDist interactive scripting console\n" ) self.box_script.insert( tk.INSERT, "If you have no idea what to do about scripting, " 'type "help" to get started.\n\n', ) self.wd.mainloop()
[docs] def script_run_help(self): """ Show help messages. """ help_msg = f"""\ >>> Interactive code console for OctaDist. >>> This scripting interface supports built-in commands as follows: >>> >>> Command\t\tDescription >>> =======\t\t=========== >>> help\t\tShow this help info. >>> list\t\tList all commands. >>> info\t\tShow info of program. >>> doc\t\tShow docstring of this function. >>> show\t\tShow values of variables. >>> \t\tUsage: show var1 [var2] [var3] [...] >>> type\t\tShow type of variables. >>> \t\tUsage: type var1 [var2] [var3] [...] >>> set\t\tSet new value to variable. >>> \t\tUsage: set var value >>> clear\t\tClear stdout/stderr. >>> clean\t\tClear stdout/stderr and command history. >>> \t\thistory - Clean previous commands history. >>> \t\tmaster - Clean cache of OctaDist master class. >>> restore\t\tRestore program settings. >>> history\t\tCommand history. >>> >>> Rangsiman Ketkaew\t\t<rangsiman1993@gmail.com>\t\tOctaDist {octadist.__version__} """ self.box_script.insert(tk.INSERT, help_msg + "\n")
[docs] def script_run_list(self): """ Show list of commands in scripting run. """ all_command = ( "help, list, info, doc, show, type, set, " "clear, clean, restore, history, exit" ) self.box_script.insert(tk.INSERT, f">>> {all_command}\n")
[docs] def script_run_info(self): """ Show info of program. """ self.box_script.insert(tk.INSERT, f">>> {octadist.__description__}\n")
[docs] def script_run_doc(self): """ Show document of program. """ self.box_script.insert(tk.INSERT, f">>> {octadist.__doc__}\n")
[docs] def script_run_show(self, args): """ Show value of variable that user requests. Parameters ---------- args : str Arbitrary argument. """ if not args: self.box_script.insert( tk.INSERT, ">>> show command needs at least 1 parameter\n" ) return 1 first_arg = args[0].lower() if first_arg == "all" or first_arg == "*": for key in self.root.__dict__.keys(): value = self.root.__dict__[key] self.box_script.insert(tk.INSERT, f">>> {key} = {value}\n") return 0 for i in range(len(args)): try: key = args[i] value = self.root.__dict__[f"{key}"] self.box_script.insert(tk.INSERT, f">>> {key} = {value}\n") except KeyError: self.box_script.insert( tk.INSERT, f'>>> variable "{args[i]}" is not defined\n' )
[docs] def script_run_type(self, args): """ Show data type of variable. Parameters ---------- args : str Arbitrary argument. """ if not args: self.box_script.insert( tk.INSERT, '>>> "type" command needs at least 1 parameter\n' ) return 1 for i in range(len(args)): try: key = args[i] data_type = type(self.root.__dict__[f"{key}"]) self.box_script.insert(tk.INSERT, f">>> {key} : {data_type}\n") except KeyError: self.box_script.insert( tk.INSERT, f'>>> variable "{args[i]}" is not defined\n' )
[docs] def script_run_set(self, args): """ Set new value to variable. Parameters ---------- args : str Arbitrary argument. """ if len(args) != 2: self.box_script.insert(tk.INSERT, ">>> No variable specified\n") self.box_script.insert(tk.INSERT, ">>> set command needs 2 parameters\n") return 1 key = args[0] value = args[1] self.root.__dict__[f"{key}"] = value if f"key" not in self.root.__dict__: self.box_script.insert( tk.INSERT, f'>>> new dynamic variable "{key}" defined\n' ) self.box_script.insert(tk.INSERT, f">>> {key} = {value}\n")
[docs] def script_run_clear(self): """ Clear output box. """ self.box_script.delete(1.0, tk.END)
[docs] def script_run_clean(self, args): """ Clear output box and clean variable. """ if not args: # clean scripting console self.script_run_clear() elif args[0].lower() == "history": self.history_command = [] elif args[0].lower() == "master": # clean master windows self.root.clear_cache()
[docs] def script_run_restore(self): """ Restore all default settings. """ self.root.cutoff_metal_ligand = self.root.backup_cutoff_metal_ligand self.root.cutoff_global = self.root.backup_cutoff_global self.root.cutoff_hydrogen = self.root.backup_cutoff_hydrogen self.root.text_editor = self.root.backup_text_editor self.root.show_title = self.root.backup_show_title self.root.show_axis = self.root.backup_show_axis self.root.show_grid = self.root.backup_show_grid self.box_script.insert(tk.INSERT, f">>> Restore all settings\n") var_settings = ( "cutoff_metal_ligand", "cutoff_global", "cutoff_hydrogen", "text_editor", "show_title", "show_axis", "show_grid", ) for key in var_settings: value = self.root.__dict__[f"{key}"] self.box_script.insert(tk.INSERT, f">>> {key} = {value}\n")
[docs] def script_run_history(self): """ Show history of command. """ if not self.history_command: self.box_script.insert(tk.INSERT, f">>> no history\n") for item in self.history_command: self.box_script.insert(tk.INSERT, f">>> {item}\n")
[docs] def script_no_command(self, command): """ Show statement if command not found. Parameters ---------- command : str Command that user submits. """ self.box_script.insert(tk.INSERT, f'>>> Command "{command}" not found\n')
[docs] def script_execute(self, event): """ Execute input command scripting. Parameters ---------- event : object Object for button interaction """ user_command = self.entry_script.get().strip().split() self.entry_script.delete(0, tk.END) # print input command if user_command: res = " ".join([str(i) for i in user_command]) self.box_script.insert(tk.INSERT, f"{res}\n") # collect command to history list if res.lower() != "history": self.history_command.append(res) if len(user_command) == 0: self.box_script.insert(tk.INSERT, ">>> no command\n") self.box_script.see(tk.END) return 1 command = user_command[0].lower() args = user_command[1:] if command == "help": self.script_run_help() elif command == "list": self.script_run_list() elif command == "info": self.script_run_info() elif command == "doc": self.script_run_doc() elif command == "show": self.script_run_show(args) elif command == "type": self.script_run_type(args) elif command == "set": self.script_run_set(args) elif command == "clear": self.script_run_clear() elif command == "clean": self.script_run_clean(args) elif command == "restore": self.script_run_restore() elif command == "history": self.script_run_history() elif command == "exit" or command == "quit": self.wd.destroy() return 1 else: self.script_no_command(command) self.box_script.see(tk.END)