omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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.


    Correct way to call Pythonista script from within a Shortcuts workflow?

    Pythonista
    7
    38
    15954
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • cvp
      cvp @bosco last edited by cvp

      @bosco Thanks for him, and for me, so I don't have to test anymore.
      Do you know why the handler does not have a 2nd parameter (error) like described in Apple doc?

      1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by JonB

        @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)
        
        cvp 1 Reply Last reply Reply Quote 0
        • cvp
          cvp @mikeno last edited by

          @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)
          
          1 Reply Last reply Reply Quote 0
          • mikeno
            mikeno last edited by

            Hi everybody, thx for helping, I’ll buy Pyto and try.

            1 Reply Last reply Reply Quote 0
            • cvp
              cvp @JonB last edited by cvp

              @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)
              
              1 Reply Last reply Reply Quote 0
              • bosco
                bosco last edited by bosco

                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
                cvp 1 Reply Last reply Reply Quote 0
                • cvp
                  cvp @bosco last edited by

                  @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

                  1 Reply Last reply Reply Quote 0
                  • bosco
                    bosco last edited by

                    @cvp Correct. After my morning brain fog cleared, that is what you said in your last edit. :-)

                    cvp 1 Reply Last reply Reply Quote 0
                    • cvp
                      cvp @bosco last edited by

                      @bosco this, you bought Pyto and already tried...

                      1 Reply Last reply Reply Quote 0
                      • bosco
                        bosco last edited by

                        @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.

                        cvp 1 Reply Last reply Reply Quote 0
                        • cvp
                          cvp @bosco last edited by

                          @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.

                          1 Reply Last reply Reply Quote 0
                          • bosco
                            bosco last edited by

                            @cvp No problem. I thought maybe your question was intended for @mikeno.

                            1 Reply Last reply Reply Quote 0
                            • E
                              emildepp @cvp last edited by ccc

                              @cvp said in Correct way to call Pythonista script from within a Shortcuts workflow?:

                              TypeError: unhashable type: 'list'

                              The "TypeError: unhashable type: 'list'" error message in Python occurs when you try to use a mutable object (such as a list) as a key in a dictionary. Since dictionaries use keys to index values, keys must be hashable objects, meaning they must be immutable (i.e. their value cannot be changed). Lists are mutable, so they cannot be used as dictionary keys. To fix the error, use an immutable object like a tuple, string, or number as the dictionary key instead.

                              To resolve the TypeError: unhashable type: 'list' error, you need to use an immutable object as a key in a dictionary instead of a mutable one like a list. For example, you can use tuples, strings, or numbers as keys, which are all hashable objects.

                              d = {[1, 2, 3]: "list_key"} //Using a list as a key in a dictionary
                              
                              //This will raise the TypeError: unhashable type: 'list' error
                              
                              d = {(1, 2, 3): "tuple_key"} //Using a tuple as a key in a dictionary
                              
                              //This will work fine as tuples are hashable
                              
                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post
                              Powered by NodeBB Forums | Contributors