Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Emulate run button - run script from another script
-
Hi all,
did anyone know how to run a script from another script in the same way as Pythonista does? I mean, emulate Run button behavior?
First option is - URL scheme - but there's one drawback - This only works if no script is already running when the app is started.
Another option is
runpy.run_path
. But it looks like that there's some problem with globals, modules, paths, ... When I tried to bindCmd Shift S
...def launch_stash(): blackmamba.ide.run_script(os.path.expanduser('~/Documents/launch_stash.py')) register_key_command( 'S', UIKeyModifierCommand | UIKeyModifierShift, launch_stash, 'Launch StaSH...')
... to launch StaSh, it fails with
No module named ConfigParser
. Myrun_script
looks like:def run_script(file_path): runpy.run_path(file_path, run_name='__main__')
What's the recommended way to launch script from a script in the same way as Pythonista does with the Play button?
Thanks,
Zrzka -
Perhaps a Python 2/3 issue? The
ConfigParser
module has been renamed toconfigparser
(lowercase) in Python 3. I'd say thatrunpy
is the way to go. -
I don't know how to exactly emulate Pythonista's script running, but
runpy
should be pretty close. The only difference is that it doesn't clean the environment, but that shouldn't be an issue for most scripts.As @omz said, the reason why Stash isn't working is probably because you're trying to run it with Python 3, but it only works on Python 2.
-
Thanks to both of you. I realized this immediately after I did post this question. Anyway, it makes things little bit harder, because it forces me to make Black Mamba Python 2/3 compatible. But it will not probably solve my issue anyway, because I can't run Python 2 scripts from Python 3 and vice versa. Would be nice if editor (or any other module) has function like
run_script
which can issuerunpy.run_path
under correct interpreter, based on shebang line. -
I think @JonB (or someone else?) had success using the Python C API via
ctypes
for this kind of thing, not sure… -
If anyone wonders why I need this, check this comment in another thread. This is the last missing piece to make me happy :)
-
I solved it with URL scheme for now, but it's kinda limited. Anyway I'm interested in this Python C API hack to choose interpreter, ...
-
This thread might be useful. Things have changed a bit in recent versions, so i update my original discoveries below:
If you are trying to emulate play button, it eventually calls:
I3=ObjCClass('PYK3Interpreter').sharedInterpreter() I2=ObjCClass('PYK2Interpreter').sharedInterpreter() #pick which interpreter to run (I2 vs I3) and whether to reset environment I2.runScriptAtPath_argv_resetEnvironment_('/private/var/mobile/Containers/Shared/AppGroup/C534C622-2FDA-41F7-AE91-E3AAFE5FFC6B/Pythonista3/Documents/Untitled_150.py',['1', 'hello'], True)
(Wrench menu calls the same selector, just with resetEnvironment=False, and populating first argv with editor script name )
I believe there might be a limitation that if a script is running already, it might be ignored, but i am not sure if that is still true. Polling for
running()
to return 0 would work, if that was the case.Previously, a script had to be open in the editor, but that is no longer the case it seems.
For running python commands directly via the cpythonapi, see the above thread.
-
btw, if you go the runpy/cpythonapi route to try to run concurrently,
ObjCClass('PA3InterpreterWrapper').shebangVersionForScript_()
might be helpful to tell you which version to run. Then load proper cpythonapi (see the stash thread), then to emulate pythonista evironment reset, you could run the preflight script:
import os version =2 #or 3 preflight_script=os.path.join(os.path.split(os.__file__)[0],'../../Py{}Kit.framework/pykit_preflight.py'.format(version))
-
@JonB said:
I believe there might be a limitation that if a script is running already, it might be ignored, but i am not sure if that is still true. Polling for running() to return 0 would work, if that was the case.
You could in principle use the other interpreter like this, but trying to run a script in the current interpreter with this high-level API isn't possible.
-
@JonB thanks! Will try this.
-
@zrzka I don't think you'll get very far with this approach, to be honest.
-
@omz learn or die :) At least I'll learn more about Pythonista internals.