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.
Shortcut to run a script located in Working Copy's dir?
-
@bensaccount said
I'm guessing this only works if the script is located in Pythonista's directory.
I think that's true. Perhaps find a way to start a Pythonista script which it-self starts the script of Working Copy.
In Pythonista V3.3 we were able to start a script running in Python 2 which started a Python 3 interpreter like a wrench script does.
#!python2 # force this script to use Python 2 Interpreter so you can start # Python 3 Interpreter to run your iCloud script from objc_util import * import sys arg = sys.argv # this script = arg[0] script = arg[1] path = '/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/' + script arg = arg[2:] # other arguments I3=ObjCClass('PYK3Interpreter').sharedInterpreter() print(I3) # run a script like in wrench menu (path, args, reset env yes/no) #print(path,script) I3.runScriptAtPath_argv_resetEnvironment_(path, arg, True)
-
@bensaccount as we can't have two times the Pythonista Python 3 interpreter at the same time, I have tested with another thread. Here, an example with (I don't use Working Copy) starting via runScript another script in iCloud
import sys import threading class my_thread_(threading.Thread): def __init__(self,path,arg): threading.Thread.__init__(self) self.path = path self.arg = arg @on_main_thread def run(self): from objc_util import ObjCClass from time import sleep sleep(1) I3 = ObjCClass('PYK3Interpreter').sharedInterpreter() # run a script like in wrench menu (path, args, reset env yes/no) #print(path,script) I3.runScriptAtPath_argv_resetEnvironment_(self.path, self.arg, True) arg = sys.argv # this script = arg[0] script = arg[1] path = '/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/' + script arg = arg[2:] # other arguments my_thread = my_thread_(path,arg) my_thread.start()
Execute this shortcut
-
@cvp Thanks, having a launcher script in Pythonista's Documents dir fixes the issue! I think starting another interpreter may be unnecessary though, since I do want the script to run inside Pythonista, and using the same version of Python.
Here's what I ended up using for my launcher script:
dir = '/private/var/mobile/Containers/Shared/AppGroup/......' filename = 'app.py' import sys import os sys.path.append(dir) os.chdir(dir) with open(filename) as f: exec(f.read())
This seems to work fine. And of course this could be altered to take arguments for directory and filename.
I've run into a couple issues with Shortcuts now:
- If I use the Pythonista Run Script shortcut, I have to stop the shortcut manually afterwards, even if Pythonista is closed. Adding "Stop this shortcut" doesn't make a difference. It's not a huge deal, but it may be confusing for the client.
- Pythonista will happily run the script multiple times. Is there any way to tell Pythonista not to do this, or do I need to implement something manually, like a lock file? (Or is there a more reliable way to check if a script is running?)
edit: Ah, I've found TPO's AppSingleLaunch util. Looks like it handles the issues with lock files sticking around when the app doesn't shut down properly, so I may try that.
-
@bensaccount I didn't know this exec function.... Thanks for the info.
-
@bensaccount I have tried successfully a shortcut with unique action
-
@cvp That's handy. So a separate launcher script file isn't needed.
It can still launch multiple times though. I think I'll have to add TPO's util to my app to prevent that.
-
I'm running into two problems with @TPO's AppSingleLaunch:
- I'm using a NavigationView as my top-level view, which doesn't have a will_close function. It's immutable, so it won't let me monkey patch one in either. Is there another way to detect when the script is exiting?
- I don't think the forced garbage collection is working. If I close the Python script and re-open it (which doesn't delete the lock file due to issue #1), the id it stores- the NavigationView's id- still exists. Even if I wait a while, gc.collect() won't collect it.
-
Hm, if I add a
will_close
method to my root View, it never gets called, I guess that's only called when you use.close()
.The UIKit docs show a
viewWillDisappear
method for NavigationView, which does show up in__dir()__
for its objc object. Is there any way to set that via Python?My temporary workaround is
hide_close_button=True
, so the app can only shutdown properly. But there's still the problem I mentioned earlier of AppSingleLaunch not working due to the NavigationView not getting cleaned up after closing. (edit: Though it's not a problem if the script always closes down properly) -
@bensaccount try to put a close button to top view of NavigationView
import ui view = ui.View() navigationView = ui.NavigationView(view) # Add a close button view.left_button_items = [ui.ButtonItem(title="Close", action=lambda x: navigationView.close())] # Won't show the x-button navigationView.present("sheet", hide_title_bar=True)
-
@cvp Thanks, looks like we had the same idea. I had just removed the close button, but I have to admit that hiding the title bar is tempting to reclaim some vertical space.
-
@bensaccount so you can intercept the root view closing, like a will_close
If it is not sufficient, I think that, in Objective C, we could intercept the delegate should_pop of the UINavigationBar, but more complex of course