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.


    [Share Code] Implemented x-callback-url

    Pythonista
    x-callback url scheme
    10
    36
    30289
    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.
    • silverjam
      silverjam last edited by

      When trying to use this recipe and consequently swizzle.py I'm seeing the follow error:

      Traceback (most recent call last):
        File "_ctypes/callbacks.c", line 234, in 'calling callback function'
        File "/private/var/mobile/Containers/Shared/AppGroup/74CC34ED-493E-431F-9C45-5BD2EF3B2AE0/Pythonista3/Documents/firebaseapp/swizzle.py", line 146, in saveData
        File "/var/containers/Bundle/Application/71C9338F-1BD7-4D52-9DAD-EE24DDF5139E/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/objc_util.py", line 796, in __call__
          method_name, kwarg_order = resolve_instance_method(obj, self.name, args, kwargs)
        File "/var/containers/Bundle/Application/71C9338F-1BD7-4D52-9DAD-EE24DDF5139E/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/objc_util.py", line 403, in resolve_instance_method
          raise AttributeError('No method found for %s' % (name,))
      AttributeError: No method found for originalsaveData
      

      Any ideas how I can debug this?

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

        I posted a github comment -- basically the code was swizzling a subclass's method, but then is passed an instance of the parent class, which does not have the original method. Swizzling the parent class (somewhat manual in this case) resolves the issue

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

          was wanting to let you know that x_callback_url is no longer working with the most recent pythonista release woth python 3.6

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

            In what way? Are you getting exceptions?

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

              the callout works, the callback comes back to pythonista
              however the swizzled handler doesnt fire

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

                no exceptions are showing, and the print statements ive put into the callback dont get called indicating that the swizzel method is not getting called or has changed

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

                  When it comes back, is the app still running? I.e anything you had printed to the console is still there?

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

                    I see that API is depreciated, so likely needs to be updated to use application:openURL:options: instead.

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

                      ended up using
                      openPythonistaURL:
                      instead of
                      application:openURL:sourceApplication:annotation:

                      cheers D

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

                        @eddo888 what do you mean?
                        did you swizzle openPythonistaURL: instead of swizzling -[UIApplicationDelegate application:openURL:options:]?

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

                          here is my uodated and sligjtly modified x_callback_url.py

                          # coding: utf-8
                          import swizzle
                          from objc_util import *
                          import sys, re, os, argparse
                          import ctypes, json, urllib, uuid, urllib
                          import webbrowser 
                          
                          def argue():
                              parser = argparse.ArgumentParser()
                          
                              parser.add_argument('-v', '--verbose',  action='store_true',  help='verbose mode')
                              parser.add_argument('-t', '--test',    action='store_true',  help='run test')
                              
                              return parser.parse_args()
                          
                          def params(data):
                              if len(data) == 0:
                                  return ''
                              p = '&'.join(
                                  map(
                                      lambda x: 
                                          '%s=%s'%(x,urllib.quote(data[x])),
                                      data.keys()
                                  )
                              )
                              return '?%s'%p
                          
                          def reverse(url):
                              query = NSURLComponents.componentsWithURL_resolvingAgainstBaseURL_(nsurl(url), False)
                              parameters = dict()
                              if query.queryItems() is not None:
                                  for queryItem in query.queryItems():
                                      parameters[str(queryItem.name())] = str(queryItem.value())
                              return parameters
                          
                          def open_url(url, handler):
                              global _handler
                              global _requestID
                              _requestID = uuid.uuid1()
                              _handler = handler
                              x_success = urllib.quote('pythonista://?request=%s'%_requestID)
                              url_with_uuid = url.replace('?','?x-success=%s&'%x_success)
                              #sys.stderr.write('> %s\n'% url_with_uuid)
                              webbrowser.open(url_with_uuid)
                          
                          def openPythonistaURL_(_self, _sel, url):
                              url_str = str(ObjCInstance(url))
                              #sys.stderr.write('< %s\n'%url_str)
                              global _call_me, _handler, _requestID
                          
                              if '?request=%s'%_requestID in url_str:
                                  url_str = url_str.replace('?request=%s&'%_requestID, '?')
                                  parameters = reverse(url_str)
                                  if _handler:
                                      _handler(parameters)
                                  return True
                                  
                              elif _call_me in url_str:
                                  #print url_str
                                  parameters = reverse(url_str)
                                  x_parameters = dict()
                                  for x in [
                                      'x-source',
                                      'x-success',
                                      'x-error',
                                      'x-cancel',
                                      'x-script',
                                  ]:
                                      if x in parameters.keys():
                                          x_parameters[x] = parameters[x]
                                          del parameters[x]
                                  
                                  #print '%s\n%s'%(
                                  #    json.dumps(x_parameters),
                                  #    json.dumps(parameters)
                                  #)
                                  
                                  if 'x-script' not in x_parameters.keys():
                                      return
                                  
                                  try:
                                      import importlib
                                      mod = importlib.import_module(
                                          x_parameters['x-script']
                                      )
                                      res = str(mod.main(parameters))
                                      url=x_parameters['x-success']+'?args=%s'%urllib.quote(res)
                                  except:
                                      error=str(sys.exc_info()[0])
                                      url=x_parameters['x-error']+'?args=%s'%urllib.quote(error)
                                      
                                  #print url
                                  webbrowser.open(url)
                                  return True
                          
                              else:
                                  #print('original url=%s'%url_str)
                                  obj = ObjCInstance(_self)
                                  original_method = getattr(obj, 'original'+c.sel_getName(_sel), None)
                                  if original_method:
                                      _annotation = ObjCInstance(annotation) if annotation else None
                                      return original_method(
                                          ObjCInstance(app), 
                                          ObjCInstance(url), ObjCInstance(source_app), 
                                          _annotation
                                      )
                                  return
                          
                          def test():
                              data={
                                  'statement' : 'select * from MyTable'
                              }
                              
                              url='generaldb://x-callback-url/execute-select-statement' + params(data)
                              print url
                                  
                              def myhandler(parameters):
                                  print parameters
                                  for row in parameters['rows'].split('\n'):
                                      print row
                                  return
                              
                              open_url(url,myhandler)
                              
                          def setup():
                              global NSURLComponents, _call_me, _handler, _requestID
                              _call_me = 'pythonista://x-callback-url'
                              _handler = None
                              _requestID = None
                              NSURLComponents = ObjCClass('NSURLComponents')
                              appDelegate = UIApplication.sharedApplication().delegate()
                              
                              # Do the swizzling
                              cls = ObjCInstance(c.object_getClass(appDelegate.ptr))
                              swizzle.swizzle(
                                  cls, 
                                  'openPythonistaURL:', openPythonistaURL_
                              )
                              #print 'swizzled'
                              return
                          
                          def main():
                              setup()
                              args = argue()
                              if args.test : test(); return
                              print 'setup complete:'#, sys.argv
                              #webbrowser.open('workflow://')
                              return    
                          
                          if __name__ == '__main__': main()
                          
                          
                          1 Reply Last reply Reply Quote 0
                          • lukaskollmer
                            lukaskollmer last edited by

                            (fyi, you should wrap the code block with ```, to get proper syntax highlighting. reading the code w/out that is really difficult)

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

                              cheers thought i was in confluence not markdown :-)

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

                                def params(data):
                                    '?' + urllib.urlencode(data)
                                

                                https://docs.python.org/2/library/urllib.html#urllib.urlencode

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

                                  def params(data):
                                      if len(data) == 0:
                                          return ''
                                      p = '&'.join(
                                          map(
                                              lambda x: 
                                                  '%s=%s'%(x,urllib.quote(data[x])),
                                              data.keys()
                                          )
                                      )
                                      print data
                                      print urllib.urlencode(data)
                                      print p
                                      
                                      return '?%s'%p
                                  
                                  

                                  yields

                                  {'statement': 'select * from MyTable'}
                                  statement=select+%2A+from+MyTable
                                  statement=select%20%2A%20from%20MyTable
                                  

                                  the client receiving the params preferrs %20 to +

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

                                    @eddo888 In Python 3 you can do that using the quote_via parameter, like urllib.parse.urlencode({...}, quote_via=urllib.parse.quote). However in Python 2 the quote_via parameter doesn't exist yet. You can manually replace every + with %20, like urllib.parse.urlencode({...}).replace("+", "%20"). This should produce the same result and is much shorter than building the whole parameter string by hand.

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

                                      Thanks for taking the time to respond and guide, I hope you have a fun weekend. Cheers Dave

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

                                        How do I use this and get arguments from workflow?

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

                                          This awesome piece of code leads to the famous 404...

                                          https://github.com/lukaskollmer/pythonista-scripts/blob/master/x-callback-url/x_callback_url.py

                                          Someone stil has it available?

                                          I'm trying to load a file from IAwriter to process it in phytonista...

                                          cvp 2 Replies Last reply Reply Quote 0
                                          • cvp
                                            cvp @dc2 last edited by

                                            @dc2 see here a lot of Pythonista scripts, centralized by tdamdouni

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors