Package intermine :: Package lists :: Module listmanager
[hide private]
[frames] | no frames]

Source Code for Module intermine.lists.listmanager

  1  import weakref 
  2   
  3  # Use core json for 2.6+, simplejson for <=2.5 
  4  try: 
  5      import json 
  6  except ImportError: 
  7      import simplejson as json 
  8   
  9  import urllib 
 10  import codecs 
 11   
 12  from intermine.lists.list import List 
13 14 -class ListManager(object):
15 """ 16 A Class for Managing List Content and Operations 17 ================================================ 18 19 This class serves as a delegate for the intermine.webservice.Service class, 20 managing list content and operations. 21 22 This class is not meant to be called itself, but rather for its 23 methods to be called by the service object. 24 """ 25 26 DEFAULT_LIST_NAME = "my_list_" 27 DEFAULT_DESCRIPTION = "List created with Python client library" 28 29 INTERSECTION_PATH = '/lists/intersect/json' 30 UNION_PATH = '/lists/union/json' 31 DIFFERENCE_PATH = '/lists/diff/json' 32 SUBTRACTION_PATH = '/lists/subtract/json' 33
34 - def __init__(self, service):
35 self.service = weakref.proxy(service) 36 self.lists = None 37 self._temp_lists = set()
38
39 - def refresh_lists(self):
40 """Update the list information with the latest details from the server""" 41 self.lists = {} 42 url = self.service.root + self.service.LIST_PATH 43 sock = self.service.opener.open(url) 44 data = sock.read() 45 sock.close() 46 list_info = json.loads(data) 47 if not list_info.get("wasSuccessful"): 48 raise ListServiceError(list_info.get("error")) 49 for l in list_info["lists"]: 50 l = ListManager.safe_dict(l) # Workaround for python 2.6 unicode key issues 51 self.lists[l["name"]] = List(service=self.service, manager=self, **l)
52 53 @staticmethod
54 - def safe_dict(d):
55 """Recursively clone json structure with UTF-8 dictionary keys""" 56 if isinstance(d, dict): 57 return dict([(k.encode('utf-8'), v) for k,v in d.iteritems()]) 58 else: 59 return d
60
61 - def get_list(self, name):
62 """Return a list from the service by name, if it exists""" 63 if self.lists is None: 64 self.refresh_lists() 65 return self.lists.get(name)
66
67 - def l(self, name):
68 """Alias for get_list""" 69 return self.get_list(name)
70
71 - def get_all_lists(self):
72 """Get all the lists on a webservice""" 73 if self.lists is None: 74 self.refresh_lists() 75 return self.lists.values()
76
77 - def get_all_list_names(self):
78 """Get all the names of the lists in a particular webservice""" 79 if self.lists is None: 80 self.refresh_lists() 81 return self.lists.keys()
82
83 - def get_list_count(self):
84 """ 85 Return the number of lists accessible at the given webservice. 86 This number will vary depending on who you are authenticated as. 87 """ 88 return len(self.get_all_list_names())
89
90 - def get_unused_list_name(self):
91 """Get a list name that does not conflict with any lists you have access to""" 92 list_names = self.get_all_list_names() 93 counter = 1 94 name = self.DEFAULT_LIST_NAME + str(counter) 95 while name in list_names: 96 counter += 1 97 name = self.DEFAULT_LIST_NAME + str(counter) 98 self._temp_lists.add(name) 99 return name
100
101 - def create_list(self, content, list_type="", name=None, description=None, tags=[]):
102 """ 103 Create a new list in the webservice 104 =================================== 105 106 If no name is given, the list will be considered to be a temporary 107 list, and will be automatically deleted when the program ends. To prevent 108 this happening, give the list a name, either on creation, or by renaming it. 109 110 @rtype: intermine.lists.List 111 """ 112 if description is None: 113 description = self.DEFAULT_DESCRIPTION 114 115 if name is None: 116 name = self.get_unused_list_name() 117 118 try: 119 ids = open(content).read() 120 except (TypeError, IOError): 121 if isinstance(content, basestring): 122 ids = content 123 else: 124 try: 125 ids = "\n".join(map(lambda x: '"' + x + '"', iter(content))) 126 except TypeError: 127 try: 128 uri = content.get_list_upload_uri() 129 except: 130 content = content.to_query() 131 uri = content.get_list_upload_uri() 132 params = content.to_query_params() 133 params["listName"] = name 134 params["description"] = description 135 form = urllib.urlencode(params) 136 resp = self.service.opener.open(uri, form) 137 data = resp.read() 138 resp.close() 139 return self.parse_list_upload_response(data) 140 141 uri = self.service.root + self.service.LIST_CREATION_PATH 142 query_form = {'name': name, 'type': list_type, 'description': description, 'tags': ";".join(tags)} 143 uri += "?" + urllib.urlencode(query_form) 144 data = self.service.opener.post_plain_text(uri, ids) 145 return self.parse_list_upload_response(data)
146
147 - def parse_list_upload_response(self, response):
148 """ 149 Intepret the response from the webserver to a list request, and return the List it describes 150 """ 151 try: 152 response_data = json.loads(response) 153 except ValueError: 154 raise ListServiceError("Error parsing response: " + response) 155 if not response_data.get("wasSuccessful"): 156 raise ListServiceError(response_data.get("error")) 157 self.refresh_lists() 158 new_list = self.get_list(response_data["listName"]) 159 failed_matches = response_data.get("unmatchedIdentifiers") 160 new_list._add_failed_matches(failed_matches) 161 return new_list
162
163 - def delete_lists(self, lists):
164 """Delete the given lists from the webserver""" 165 for l in lists: 166 if isinstance(l, List): 167 name = l.name 168 else: 169 name = str(l) 170 if name not in self.get_all_list_names(): 171 continue 172 uri = self.service.root + self.service.LIST_PATH 173 query_form = {'name': name} 174 uri += "?" + urllib.urlencode(query_form) 175 response = self.service.opener.delete(uri) 176 response_data = json.loads(response) 177 if not response_data.get("wasSuccessful"): 178 raise ListServiceError(response_data.get("error")) 179 self.refresh_lists()
180
181 - def delete_temporary_lists(self):
182 """Delete all the lists considered temporary (those created without names)""" 183 self.delete_lists(self._temp_lists) 184 self._temp_lists = set()
185
186 - def intersect(self, lists, name=None, description=None, tags=[]):
187 """Calculate the intersection of a given set of lists, and return the list representing the result""" 188 return self._do_operation(self.INTERSECTION_PATH, "Intersection", lists, name, description, tags)
189
190 - def union(self, lists, name=None, description=None, tags=[]):
191 """Calculate the union of a given set of lists, and return the list representing the result""" 192 return self._do_operation(self.UNION_PATH, "Union", lists, name, description, tags)
193
194 - def xor(self, lists, name=None, description=None, tags=[]):
195 """Calculate the symmetric difference of a given set of lists, and return the list representing the result""" 196 return self._do_operation(self.DIFFERENCE_PATH, "Difference", lists, name, description, tags)
197
198 - def subtract(self, lefts, rights, name=None, description=None, tags=[]):
199 """Calculate the subtraction of rights from lefts, and return the list representing the result""" 200 left_names = self.make_list_names(lefts) 201 right_names = self.make_list_names(rights) 202 if description is None: 203 description = "Subtraction of " + ' and '.join(right_names) + " from " + ' and '.join(left_names) 204 if name is None: 205 name = self.get_unused_list_name() 206 uri = self.service.root + self.SUBTRACTION_PATH 207 uri += '?' + urllib.urlencode({ 208 "name": name, 209 "description": description, 210 "references": ';'.join(left_names), 211 "subtract": ';'.join(right_names), 212 "tags": ";".join(tags) 213 }) 214 resp = self.service.opener.open(uri) 215 data = resp.read() 216 resp.close() 217 return self.parse_list_upload_response(data)
218
219 - def _do_operation(self, path, operation, lists, name, description, tags):
220 list_names = self.make_list_names(lists) 221 if description is None: 222 description = operation + " of " + ' and '.join(list_names) 223 if name is None: 224 name = self.get_unused_list_name() 225 uri = self.service.root + path 226 uri += '?' + urllib.urlencode({ 227 "name": name, 228 "lists": ';'.join(list_names), 229 "description": description, 230 "tags": ";".join(tags) 231 }) 232 resp = self.service.opener.open(uri) 233 data = resp.read() 234 resp.close() 235 return self.parse_list_upload_response(data)
236 237
238 - def make_list_names(self, lists):
239 """Turn a list of things into a list of list names""" 240 list_names = [] 241 for l in lists: 242 try: 243 t = l.list_type 244 list_names.append(l.name) 245 except AttributeError: 246 try: 247 m = l.model 248 list_names.append(self.create_list(l).name) 249 except AttributeError: 250 list_names.append(str(l)) 251 252 return list_names
253
254 -class ListServiceError(IOError):
255 """Errors thrown when something goes wrong with list requests""" 256 pass
257