traitlets
traitlets copied to clipboard
programmatic invocation of a sub-application from another sub-application
I desire to invoke one sub-application from another sub-application.
To do so is cumbersome, because I must construct a command-line and then
invoke the subcommand via subprocess like so:
cmdline = f'python main-app.py greet --greeting {file_name} --name {file_size}'.split()
subprocess.run(cmdline)
Instead of constructing a command-line, I wish to make a method call from the
start() method of one sub-application to invoke the other sub-application
like so:
arg = dict(greeting=file_name, name=file_size)
greet_app = Greeting(**arg)
greet_app.launch_instance()
but calling launch_instance() leads to the following error:
traitlets.config.configurable.MultipleInstanceError:
An incompatible sibling of 'Greeting' is already
instanciated as singleton: File
So, to remedy this problem, if one could replace the current singleton-sub-application with another programmatically, then one would not have to resort to making shell calls to do so.
So, the request is a method like replace_instance() or exec_instance
that gets around the singleton issue.
Source code to replicate the error
https://github.com/metaperl/traitlets-lab/tree/main/tds-variation
Do you really need to launch a new singleton application? Most likely you can just call greet_app.initialize(); greet_app.start() directly which will run the same behavior except it won't have the side effect of setting a global instance. If you really need to, you could try to make use of .clear_instance(). See for example https://github.com/ipython/traitlets/issues/474
Do you really need to launch a new singleton application?
in my case, something has to be done. i have a sub-application that looks for zip files matching a pattern. When it finds them, it unpacks the files and then invokes another sub-application to process the unpacked files. We can call these file-scan and file-process sub-applications. They do fit the definition of being standalone applications because they are separate processes that do a particular thing. They do actually work well as standalone applications. I brought up the possibility of invoking the one sub-application from another because I received criticism from a colleague about one python program running another one instead of one python program calling methods of another class.
In reflection, regarding the toy application that I provided as an example, instead of one application calling the 2nd sub-application via subprocess.run() we can use shell programming to capture the output of one sub-command and pass it to the 2nd.
i.e. instead of:
shell> python cli_apps.py file --File.file README.md --File.as_greeting True
Where the file sub-command takes its output and calls the greeting subcommand we can do something like:
shell> GREETING=`python cli_apps.py file --File.file README.md` && python cli-apps.py greeting --greeting $GREETING
@metaperl, I think you misunderstood what I wrote. To be clear, it seems to me like you should replace
greet_app = Greeting(**arg)
greet_app.launch_instance()
(note anyway that .launch_instance() is a classmethod, so even if it could work it wouldn't have used your greet_app instance) by
greet_app = Greeting(**arg)
# greet_app.initialize(argv) # if you are intending to parse some command-line args again
greet_app.start()
(You can see that .launch_instance() is a very thin wrapper around getting a singleton, and calling .initialize() and .start() on it. In your toy example, it doesn't seem to me that there is any advantage to trying to deal with singletons.)
Added a mention in docs, feel free to submit a PR to improve docs if you encounter anything missing.