IBM / tnz

Tn3270 to Z Python library
https://ibm.github.io/tnz/
Apache License 2.0
56 stars 13 forks source link

(Request) Adding ZTI Commands #125

Open john-craig opened 3 weeks ago

john-craig commented 3 weeks ago

It would be nice if there were a way to add user-defined commands or macros to ZTI.

For example, a directory somewhere that a user can just drop-in a Python file, like myfunc.py, and then have that Python script invoked when a user runs the myfunc command in the ZTI REPL.

najohnsn commented 5 days ago

I think that what is described for this issue is a good idea.

I'll call that an informal way to run scripts.

There is currently a formal way that is not yet documented. Put something like this in your pyproject.toml:

[project.entry-points."zti.commands"]
myfunc = "mymodule:myfunc"

The target function (myfunc() in the above example) should accept a single argument of a command-line string. The function can use the tnz.ati module functions to perform the desired actions.

There are ways other than pyproject.toml to supply entry-points. Any way should do. But that is a requirement to use this formal mechanism.

john-craig commented 4 days ago

Okay. I've done a bit of research into this. I won't have time to take a crack at it until the holidays. Here's my basic idea for a design:

The default path for user macros will be something like ~/.zti-macros.d, and this can be overriden with the ZTI_MACROS_DIR environment variable.

When the Zti class loads, it will check if the user macros directory exists, and if it does, it will iterate over each file located inside with a .py extension.

These files will be expected to each contain a function with the same name which can accept two arguments, a self and an arg. So, if I had a file mymacro.py, it should contain at least one function with a method signature such as:

def mymacro(self, arg):
  print(arg)

For each Python file in the user macros directory, Zti will import its contents. There's a couple of ways to do this. My preferred approach would be using execfile since it's simple, although it's got some drawbacks. This function just executes the contents of the file unconditionally, so if there was some malicious code in there it would get executed as well. Although I argue that malicious code getting into a user defined macro is an inherent danger of user defined macros.

Anyways once the mymacro function has been imported, Zti will need to make it into a bound method of its own class instance with a name like do_mymacro so that the Cmd class that it uses displays it as an available command in the REPL. This should be doable based on this StackOverflow answer.