How to use the handoff?

27 views
Skip to first unread message

jirikadlec2

unread,
Sep 18, 2015, 2:06:43 PM9/18/15
to Tethys Platform
Hi, 
I am looking at the handoff function in Tethys to launch my Tethys app from an external website:

I have trouble with the documentation:
1) Where in my app do I need to define my handoff handler? Do I define it inside a controller, or inside the app.py, or do I make a separate file named handoff.py?

2) What's the difference between using a controller and using a handoff handler?


Dan Ames

unread,
Sep 18, 2015, 3:29:53 PM9/18/15
to jirikadlec2, Tethys Platform
We've invited Scott Christensen to make a brief presentation about the handoff function at our lab meeting at 2:00 today. 

--
You received this message because you are subscribed to the Google Groups "Tethys Platform" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tethysplatfor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/tethysplatform/1d460ec4-06de-4d5f-a2c2-a2beefba3433%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nathan Swain

unread,
Sep 21, 2015, 10:36:55 AM9/21/15
to Tethys Platform
I just reviewed the documentation on handoff and noticed a few typos. To answer your questions:

1) Where in my app do I need to define my handoff handler? Do I define it inside a controller, or inside the app.py, or do I make a separate file named handoff.py?

There is no required location for handoff handlers. When you register the handoff handler in app.py, you provide the path to the file as the value of the "handler" argument. The example assumes that you have created a python module called "handoff.py" in the project directory of your app and defined a handoff handler function called "csv". Thus, the path to the handler is "handoff:csv"

Unfortunately, there is a typo in the documentation. The example handoff URL in the Execute a Handoff section should be:

http://www.example.com/handoff/hydrograph-plotter/plot-csv/?csv_url=http://www.another.com/url/to/file.csv
The query parameters (after the ?) of the URL must match the names of the arguments defined in the handoff handler or an error will be thrown (in this case csv_url).

2) What's the difference between using a controller and using a handoff handler?

The primary difference between a controller and a handoff handler is that a handoff handler cannot be used to render a page. It can only return a URL or controller name to be redirected to. The idea is that the handoff handler performs the job of retrieving any data associated with the handoff via the arguments provided and then redirects to a page that will known how to work with the preloaded data.

For example, one of the arguments that could be sent to the handoff handler is a HydroShare resource ID. The handoff handler could then use the HydroShare REST API with the resource ID to retrieve the data and save it in a temporary workspace. It would then redirect to a controller in the app that will know to look for data in the temporary workspace and load it. To the user, it will seem like they just pushed a HydroShare resource into a Tethys app, but in reality the Tethys app pulled the data from HydroShare. The pull mechanism is necessary to avoid same origin policy issues.

--
Nathan Swain, PhD
Aquaveo

sdc50

unread,
Sep 23, 2015, 1:54:24 PM9/23/15
to tethysp...@googlegroups.com
Nathan,

I have another question about handoff, and a feature request that I want to get your thoughts on.

Question: The HandoffHandler object seems very similar to the UrlMap object (at least in the data it's accepting for the __init__ method). This is a nice parallel, I think, but I'm a little confused why the 'controller' parameter of the UrlMap takes a dot separated path to the controller (i.e. 'app_name.controllers.controller_name') while the HandoffHandler takes something of the form 'handoff:handler_name'. Could you explain why these are different?

Feature request: When I was talking with Dr. Ames group someone (maybe Jiri) asked if there was a way to pass Python objects between apps. As I thought about it it seems like it wouldn't be too hard to have a module or object that can be imported by other apps with methods similar to a handoff handler, but that take a request and then Python parameters. Do you see any value in this type of internal or app-to-app handoff? I know you liked the idea of having the same solution for internal and external handoffs, but there may be some value in providing extra capabilities for internal handoffs. I can put in a feature request to GitHub if you think this is worth considering.

Jiří Kadlec

unread,
Sep 23, 2015, 3:07:13 PM9/23/15
to sdc50, Tethys Platform
Hi, 
just to clarify about Scott's second question.
I was not asking about passing a python object between 2 apps, but i needed to know how to pass a python object from my handoff handler to a controller inside of the same app.

-- Jiri

--
You received this message because you are subscribed to the Google Groups "Tethys Platform" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tethysplatfor...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Jiří Kadlec
Research Assistant
Brigham Young University
Provo, UT, USA

Nathan Swain

unread,
Sep 23, 2015, 4:05:18 PM9/23/15
to Jiří Kadlec, sdc50, Tethys Platform
Scott:

Question: I think the reason for the difference in path designation is that the UrlMap path is used by Django which expects it in that format. The other format with the colon was a pattern that I devised back in the CKAN days. I think the initializer parameter for persistent stores also uses the colon path. They do need to be normalized for consistency, but we need to decide which format to go with and be sure that it is backward compatible. I don't really have a preference.

Feature: I like the concept, but could you cite a few use cases? What things are importable that we could use? Classes? Functions? Actual instances of objects are a little trickier, though I suppose you could import those from a module that instantiates them. That seems a little goofy to me though. I guess you could import the actual handler function from the app... Can you clarify?

Jiri:

Passing python objects from the handler function to a controller is a kin to passing python objects between controllers. It can't be done directly, because each function is called on separate requests. Anything in memory at the completion of the handler function request will be lost before the controller request begins. Generally, if you want data to persist between requests (and be accessible by other requests) you need to write it out from memory to disk either as a file or in a database (this is how persistent stores got it's name).

One strategy is to create a persistent store with a PickleType field and store the Python object as a pickle in the database. Then you pass the ID of the database record with the desired Python object as either a URL parameter or query parameter of the redirect URL. The caveat is that not all Python objects are pickle-able.


For more options, visit https://groups.google.com/d/optout.
--
Nathan Swain

Scott Christensen

unread,
Sep 23, 2015, 6:36:01 PM9/23/15
to Nathan Swain, Jiří Kadlec, Tethys Platform
Thanks for the clarification Jiří; I'm sorry that I misunderstood what you were asking.  And thanks for the responding Nathan. That was more enlightening that what I was going to say. I'll just add that there is a request object that can get passed from one controller to another. It has an attributed called 'session' which is a dictionary that you can add things to.  However, anything that is passed in the session dictionary must be json serializable, so it can only handle basic Python objects (i.e. strings, numbers, or lists and dictionaries can only contain strings or numbers, etc.). Using persistent stores gives you more options.

Re Question: I've entered an issue to normalize that. We can discuss details on a scrum call at some point.

Re Feature: I can't think of a really compelling use case for passing Python parameters, but there may be some value from accessing the normal handoff handlers through Python rather than through the REST api. Here are some thoughts:

There could be a method on the app_base class that returns a HandoffManager object (similar to the JobManager). The HandoffManager would have a method that would list the handoff_capabilities similar to the way the REST endpoint does. It could also wrap all of the handoff handlers so that they could be called through the HandoffManager. 

So far this doesn't provide any extra capabilities beyond the REST interface that is already implemented. However, in an an app it may be more convenient to call handoff functions this way rather than constructing a url that conforms to the REST api. 

If we did end up finding a good use case for passing Python objects between apps then this implementation would easily allow for a second type of HandoffHandler to be listed in the HandoffManager: an internal or app_to_app HandoffHandler. This would allow registering handlers that can accept Python parameters. The InternalHandoffHandler could be a subclass of HandoffHandler, or we could just add an attribute (internal=True) to the existing class. 

Reply all
Reply to author
Forward
0 new messages