Skip to content

Instantly share code, notes, and snippets.

@kporangehat
Created August 4, 2012 01:23
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kporangehat/3253287 to your computer and use it in GitHub Desktop.
Save kporangehat/3253287 to your computer and use it in GitHub Desktop.
Example: Handling Shotgun ActionMenuItem calls
#!/usr/bin/env python
# encoding: utf-8
# ---------------------------------------------------------------------------------------------
# Description
# ---------------------------------------------------------------------------------------------
"""
The values sent by the Action Menu Item are in the form of a GET request that is similar to the
format: myCoolProtocol://doSomethingCool?user_id=24&user_login=shotgun&title=All%20Versions&...
In a more human-readable state that would translate to something like this:
{
'project_name': 'Demo Project',
'user_id': '24',
'title': 'All Versions',
'user_login': 'shotgun',
'sort_column': 'created_at',
'entity_type': 'Version',
'cols': 'created_at',
'ids': '5,2',
'selected_ids': '2,5',
'sort_direction': 'desc',
'project_id': '4',
'session_uuid': 'd8592bd6-fc41-11e1-b2c5-000c297a5f50',
'column_display_names':
[
'Version Name',
'Thumbnail',
'Link',
'Artist',
'Description',
'Status',
'Path to frames',
'QT',
'Date Created'
]
}
This simple class parses the url into easy to access types variables from the parameters,
action, and protocol sections of the url. This example url
myCoolProtocol://doSomethingCool?user_id=123&user_login=miled&title=All%20Versions&...
would be parsed like this:
(string) protocol: myCoolProtocol
(string) action: doSomethingCool
(dict) params: user_id=123&user_login=miled&title=All%20Versions&...
The parameters variable will be returned as a dictionary of string key/value pairs. Here's
how to instantiate:
sa = ShotgunAction(sys.argv[1]) # sys.argv[1]
sa.params['user_login'] # returns 'miled'
sa.params['user_id'] # returns 123
sa.protocol # returns 'myCoolProtocol'
"""
# ---------------------------------------------------------------------------------------------
# Imports
# ---------------------------------------------------------------------------------------------
import sys, os
import urllib
import logging as logger
from pprint import pprint
# ---------------------------------------------------------------------------------------------
# Variables
# ---------------------------------------------------------------------------------------------
# location to write logfile for this script
# logging is a bit of overkill for this class, but can still be useful.
logfile = os.path.dirname(sys.argv[0])+"/shotgun_action.log"
# ----------------------------------------------
# Generic ShotgunAction Exception Class
# ----------------------------------------------
class ShotgunActionException(Exception):
pass
# ----------------------------------------------
# ShotgunAction Class to manage ActionMenuItem call
# ----------------------------------------------
class ShotgunAction():
def __init__(self, url):
self.logger = self._init_log(logfile)
self.url = url
self.protocol, self.action, self.params = self._parse_url()
# entity type that the page was displaying
self.entity_type = self.params['entity_type']
# Project info (if the ActionMenuItem was launched from a page not belonging
# to a Project (Global Page, My Page, etc.), this will be blank
if 'project_id' in self.params:
self.project = { 'id':int(self.params['project_id']), 'name':self.params['project_name'] }
else:
self.project = None
# Internal column names currently displayed on the page
self.columns = self.params['cols']
# Human readable names of the columns currently displayed on the page
self.column_display_names = self.params['column_display_names']
# All ids of the entities returned by the query (not just those visible on the page)
self.ids = []
if len(self.params['ids']) > 0:
ids = self.params['ids'].split(',')
self.ids = [int(id) for id in ids]
# All ids of the entities returned by the query in filter format ready
# to use in a find() query
self.ids_filter = self._convert_ids_to_filter(self.ids)
# ids of entities that were currently selected
self.selected_ids = []
if len(self.params['selected_ids']) > 0:
sids = self.params['selected_ids'].split(',')
self.selected_ids = [int(id) for id in sids]
# All selected ids of the entities returned by the query in filter format ready
# to use in a find() query
self.selected_ids_filter = self._convert_ids_to_filter(self.selected_ids)
# sort values for the page
# (we don't allow no sort anymore, but not sure if there's legacy here)
if 'sort_column' in self.params:
self.sort = { 'column':self.params['sort_column'], 'direction':self.params['sort_direction'] }
else:
self.sort = None
# title of the page
self.title = self.params['title']
# user info who launched the ActionMenuItem
self.user = { 'id':self.params['user_id'], 'login':self.params['user_login']}
# session_uuid
self.session_uuid = self.params['session_uuid']
# ----------------------------------------------
# Set up logging
# ----------------------------------------------
def _init_log(self, filename="shotgun_action.log"):
try:
logger.basicConfig(level=logger.DEBUG,
format='%(asctime)s %(levelname)-8s %(message)s',
datefmt='%Y-%b-%d %H:%M:%S',
filename=filename,
filemode='w+')
except IOError, e:
raise ShotgunActionException ("Unable to open logfile for writing: %s" % e)
logger.info("ShotgunAction logging started.")
return logger
# ----------------------------------------------
# Parse ActionMenuItem call into protocol, action and params
# ----------------------------------------------
def _parse_url(self):
logger.info("Parsing full url received: %s" % self.url)
# get the protocol used
protocol, path = self.url.split(":", 1)
logger.info("protocol: %s" % protocol)
# extract the action
action, params = path.split("?", 1)
action = action.strip("/")
logger.info("action: %s" % action)
# extract the parameters
# 'column_display_names' and 'cols' occurs once for each column displayed so we store it as a list
params = params.split("&")
p = {'column_display_names':[], 'cols':[]}
for arg in params:
key, value = map(urllib.unquote, arg.split("=", 1))
if key == 'column_display_names' or key == 'cols' :
p[key].append(value)
else:
p[key] = value
params = p
logger.info("params: %s" % params)
return (protocol, action, params)
# ----------------------------------------------
# Convert IDs to filter format to us in find() queries
# ----------------------------------------------
def _convert_ids_to_filter(self, ids):
filter = []
for id in ids:
filter.append(['id','is',id])
logger.debug("parsed ids into: %s" % filter)
return filter
# ----------------------------------------------
# Main Block
# ----------------------------------------------
if __name__ == "__main__":
try:
sa = ShotgunAction(sys.argv[1])
logger.info("ShotgunAction: Firing... %s" % (sys.argv[1]) )
except IndexError, e:
raise ShotgunActionException("Missing GET arguments")
logger.info("ShotgunAction process finished.")
@kporangehat
Copy link
Author

added session_uuid handling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment