Correct way to call Pythonista script from within a Shortcuts workflow?
-
Hi —
I’m trying to call Pythonista for the first time from a Shortcuts workflow. I understand that I should be able to call the Python code, passing values into argv somehow, but that there isn’t a direct way to return values unless you use a workaround (e.g. store the output value in the clipboard from Python, then retrieve the clipboard when the shortcut picks up again).
I’m having trouble getting the Shortcut to actually find my Pythonista script. I’ve tried saving it both on iCloud and “on my iPad”.
I’m triggering Pythonista by adding the “Run Script” step to my workflow, and then providing the name of the script. I’ve trying various syntaxes:
- MyScript.py
- MyScript
- pythonista3://getPTEimg.py
- pythonista3://iCloud/getPTEimg.py
- pythonista3://iCloud/getPTEimg.py?action=run&root=iCloud
- pythonista3://iCloud/getPTEimg.py?action=run
The last one is the one that Pythonista seems to recommend, in that it is auto-generated when I select Wrench > Shortcuts... > Pythonista URL > Copy URL.
In all cases, the call fails a "The file [filename] cannot be found" dialog box in Pythonista.
Can someone confirm that I should, in fact, be using the "Run Script" command in Shortcuts for this, as well as the syntax to use and location the script needs to be at in order to be found?
Thanks in advance!
Ramon
-
@cvp, I think this one was correct:
@Block def handler(altitudeData:ObjCInstance, err:ObjCInstance) -> None: print(altitudeData)
But then pass
handler
directly to ObjC -- don't call ObjCBlock on it. ObjCBlock makes an Objc block callable by python, which isn't needed here.Or, to make no other changes:
@Block def handler_block(altitudeData:ObjCInstance, err:ObjCInstance) -> None: print(altitudeData)
-
@mikeno With the barometer module of @bosco, where print lines are commented, this script works and continues to log the pressure even if I close the iPad cover. Not tested during a day.
import background as bg import barometer with bg.BackgroundTask() as b: while True: result = barometer.get_pressure() l= f"{b.execution_time()}:{result}\n" with open("/private/var/mobile/Library/Mobile Documents/iCloud~is~workflow~my~workflows/Documents/bg.txt", mode='at') as fil: fil.write(l) #print(b.execution_time(), result) b.wait(5)
-
Hi everybody, thx for helping, I’ll buy Pyto and try.
-
@JonB said
But then pass handler directly to ObjC
how do I do that?
In the bosco solution, there is no @Block line
Édit: ok, understood, use the handler_block directly in
altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler)
Thanks for your explanations
Edit2: but I need
@Block def handler(altitudeData:ObjCInstance, err:ObjCInstance) -> None: print(ObjCInstance(altitudeData).pressure)
-
I dropped the 2nd parameter (error) because it caused an exception: "item 2 in argtypes has no from_param method", so I tried running without the error parameter.
After reading the last comment by @JonB I now understand the proper use of @Block witch can be called directly.
This works for me.
# coding: utf-8 from rubicon.objc import Block, ObjCClass, ObjCInstance, py_from_ns from rubicon.objc.runtime import objc_id pressure = None @Block def handler(altitudeData:ObjCInstance, err:ObjCInstance) -> None: nspressure = ObjCInstance(altitudeData).pressure global pressure pressure = py_from_ns(nspressure) """ def bhandler(_data) -> None: nspressure = ObjCInstance(_data).pressure global pressure pressure = py_from_ns(nspressure) handler_block = Block(bhandler, None, (objc_id)) """ def get_pressure(): CMAltimeter = ObjCClass('CMAltimeter') NSOperationQueue = ObjCClass('NSOperationQueue') if not CMAltimeter.isRelativeAltitudeAvailable(): print('This device has no barometer.') return altimeter = CMAltimeter.new() main_q = NSOperationQueue.mainQueue #altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler_block) altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler) print('Started altitude updates.') try: while pressure is None: pass finally: altimeter.stopRelativeAltitudeUpdates() print('Updates stopped.') return pressure if __name__ == '__main__': result = get_pressure() print(result) del pressure
-
@bosco said
After reading the last comment by @JonB I now understand the proper use of @Block witch can be called directly.
Yes, this is what I had also found and explained in my last post
-
@cvp Correct. After my morning brain fog cleared, that is what you said in your last edit. :-)
-
@bosco this, you bought Pyto and already tried...
-
@cvp I bought Pyto in 2019. I am currently running Pyto 17.1.1 I have tested barometer.py on iPhone 12 mini and iPad mini 4th gen.
-
@bosco I'm sincerely sorry, my "thus, you bought Pyto and already tried..." was erroneously for @mikeno. I guess that you, @bosco, you know Pyto because you have been part of the solution with @jonB.
-
last edited by