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

Source Code for Module intermine.lists.list

  1  import weakref 
  2  import urllib 
  3   
  4  from intermine.results import JSONIterator, EnrichmentLine 
  5  from intermine.model import ConstraintNode 
  6  from intermine.errors import ServiceError 
7 8 -class List(object):
9 """ 10 Class for representing a List on an InterMine Webservice 11 ======================================================== 12 13 Lists represent stored collections of data and saved result 14 sets in an InterMine data warehouse. This class is an abstraction 15 of this information, and provides mechanisms for managing the 16 data. 17 18 SYNOPSIS 19 -------- 20 21 example:: 22 23 >>> from intermine.webservice import Service 24 >>> 25 >>> flymine = Service("www.flymine.org/query", "SOMETOKEN") 26 >>> new_list = flymine.create_list(["h", "zen", "eve", "bib"], "Gene", name="My New List") 27 >>> 28 >>> another_list = flymine.get_list("Some other list") 29 >>> combined_list = new_list | another_list # Same syntax as for sets 30 >>> combined_list.name = "Union of the other lists" 31 >>> 32 >>> print "The combination of the two lists has %d elements" % combined_list.size 33 >>> print "The combination of the two lists has %d elements" % len(combined_list) 34 >>> 35 >>> for row in combined_list: 36 ... print row 37 38 OVERVIEW 39 -------- 40 41 Lists are created from a webservice, and can be manipulated in various ways. 42 The operations are:: 43 * Union: this | that 44 * Intersection: this & that 45 * Symmetric Difference: this ^ that 46 * Asymmetric Difference (subtraction): this - that 47 * Appending: this += that 48 49 Lists can be created from a list of identifiers that could be:: 50 * stored in a file 51 * held in a list or set 52 * contained in a string 53 In all these cases the syntax is the same: 54 55 >>> new_list = service.create_list(content, type, name="Some name", description="Some description", tags=["some", "tags"]) 56 57 Lists can also be created from a query's result with the exact 58 same syntax. In the case of queries, the type is not required, 59 but the query should have just one view, and it should be an id. 60 61 >>> query = service.new_query() 62 >>> query.add_view("Gene.id") 63 >>> query.add_constraint("Gene.length", "<", 100) 64 >>> new_list = service.create_list(query, name="Short Genes") 65 66 """ 67
68 - def __init__(self, **args):
69 """ 70 Constructor 71 =========== 72 73 Do not construct these objects yourself. They should be 74 fetched from a service or constructed using the "create_list" 75 method. 76 """ 77 try: 78 self._service = args["service"] 79 self._manager = weakref.proxy(args["manager"]) 80 self._name = args["name"] 81 self._title = args["title"] 82 self._description = args.get("description") 83 self._list_type = args["type"] 84 self._size = int(args["size"]) 85 self._date_created = args.get("dateCreated") 86 self._is_authorized = args.get("authorized") 87 self._status = args.get("status") 88 89 if self._is_authorized is None: self._is_authorized = True 90 91 if "tags" in args: 92 tags = args["tags"] 93 else: 94 tags = [] 95 96 self._tags = frozenset(tags) 97 except KeyError: 98 raise ValueError("Missing argument") 99 self.unmatched_identifiers = set([])
100 101 @property
102 - def date_created(self):
103 """When this list was originally created""" 104 return self._date_created
105 106 @property
107 - def tags(self):
108 """The tags associated with this list""" 109 return self._tags
110 111 @property
112 - def description(self):
113 """The human readable description of this list""" 114 return self._description
115 116 @property
117 - def title(self):
118 """The fixed title of this list""" 119 return self._title
120 121 @property
122 - def status(self):
123 """The upgrade status of this list""" 124 return self._status
125 126 @property
127 - def is_authorized(self):
128 """Whether or not the current user is authorised to make changes to this list""" 129 return self._is_authorized
130 131 @property
132 - def list_type(self):
133 """The type of the InterMine objects this list can contain""" 134 return self._list_type
135
136 - def get_name(self):
137 """The name of the list used to access it programmatically""" 138 return self._name
139
140 - def set_name(self, new_name):
141 """ 142 Set the name of the list 143 ======================== 144 145 Setting the list's name causes the list's name to be updated on the server. 146 """ 147 if self._name == new_name: 148 return 149 uri = self._service.root + self._service.LIST_RENAME_PATH 150 params = { 151 "oldname": self._name, 152 "newname": new_name 153 } 154 uri += "?" + urllib.urlencode(params) 155 resp = self._service.opener.open(uri) 156 data = resp.read() 157 resp.close() 158 new_list = self._manager.parse_list_upload_response(data) 159 self._name = new_name
160
161 - def del_name(self):
162 """Raises an error - lists must always have a name""" 163 raise AttributeError("List names cannot be deleted, only changed")
164 165 @property
166 - def size(self):
167 """Return the number of elements in the list. Also available as len(obj)""" 168 return self._size
169 170 @property
171 - def count(self):
172 """Alias for obj.size. Also available as len(obj)""" 173 return self.size
174
175 - def __len__(self):
176 """Returns the number of elements in the object""" 177 return self.size
178 179 name = property(get_name, set_name, del_name, "The name of this list") 180
181 - def _add_failed_matches(self, ids):
182 if ids is not None: 183 self.unmatched_identifiers.update(ids)
184
185 - def __str__(self):
186 string = self.name + " (" + str(self.size) + " " + self.list_type + ")" 187 if self.date_created: 188 string += " " + self.date_created 189 if self.description: 190 string += " " + self.description 191 return string
192
193 - def delete(self):
194 """ 195 Delete this list from the webservice 196 ==================================== 197 198 Calls the webservice to delete this list immediately. This 199 object should not be used after this method is called - attempts 200 to do so will raise errors. 201 """ 202 self._manager.delete_lists([self])
203
204 - def to_query(self):
205 """ 206 Construct a query to fetch the items in this list 207 ================================================= 208 209 Return a new query constrained to the objects in this list, 210 and with a single view column of the objects ids. 211 212 @rtype: intermine.query.Query 213 """ 214 q = self._service.new_query(self.list_type) 215 q.add_constraint(self.list_type, "IN", self.name) 216 return q
217
218 - def make_list_constraint(self, path, op):
219 """ 220 Implementation of trait that allows use of these objects in list constraints 221 """ 222 return ConstraintNode(path, op, self.name)
223
224 - def __iter__(self):
225 """Return an iterator over the objects in this list, with all attributes selected for output""" 226 return iter(self.to_query())
227
228 - def __getitem__(self, index):
229 """Get a member of this list by index""" 230 if not isinstance(index, int): 231 raise IndexError("Expected an integer key - got %s" % (index)) 232 if index < 0: # handle negative indices. 233 i = self.size + index 234 else: 235 i = index 236 237 if i not in range(self.size): 238 raise IndexError("%d is not a valid index for a list of size %d" % (index, self.size)) 239 240 return self.to_query().first(start=i, row="jsonobjects")
241
242 - def __and__(self, other):
243 """ 244 Intersect this list and another 245 """ 246 return self._manager.intersect([self, other])
247
248 - def __iand__(self, other):
249 """ 250 Intersect this list and another, and replace this list with the result of the 251 intersection 252 """ 253 intersection = self._manager.intersect([self, other], description=self.description, tags=self.tags) 254 self.delete() 255 intersection.name = self.name 256 return intersection
257
258 - def __or__(self, other):
259 """ 260 Return the union of this list and another 261 """ 262 return self._manager.union([self, other])
263
264 - def __add__(self, other):
265 """ 266 Return the union of this list and another 267 """ 268 return self._manager.union([self, other])
269
270 - def __iadd__(self, other):
271 """ 272 Append other to this list. 273 """ 274 return self.append(other)
275
276 - def _do_append(self, content):
277 name = self.name 278 data = None 279 280 try: 281 ids = open(content).read() 282 except (TypeError, IOError): 283 if isinstance(content, basestring): 284 ids = content 285 else: 286 try: 287 ids = "\n".join(map(lambda x: '"' + x + '"', iter(content))) 288 except TypeError: 289 content = self._manager._get_listable_query(content) 290 uri = content.get_list_append_uri() 291 params = content.to_query_params() 292 params["listName"] = name 293 params["path"] = None 294 form = urllib.urlencode(params) 295 resp = self._service.opener.open(uri, form) 296 data = resp.read() 297 298 if data is None: 299 uri = self._service.root + self._service.LIST_APPENDING_PATH 300 query_form = {'name': name} 301 uri += "?" + urllib.urlencode(query_form) 302 data = self._service.opener.post_plain_text(uri, ids) 303 304 new_list = self._manager.parse_list_upload_response(data) 305 self.unmatched_identifiers.update(new_list.unmatched_identifiers) 306 self._size = new_list.size 307 return self
308
309 - def append(self, appendix):
310 """Append the arguments to this list""" 311 try: 312 return self._do_append(self._manager.union(appendix)) 313 except: 314 return self._do_append(appendix)
315
316 - def calculate_enrichment(self, widget, background = None, correction = "Holm-Bonferroni", maxp = 0.05, filter = ''):
317 """ 318 Perform an enrichment calculation on this list 319 ============================================== 320 321 example:: 322 323 >>> for item in service.get_list("some list").calculate_enrichment("thingy_enrichment"): 324 ... print item.identifier, item.p_value 325 326 Gets an iterator over the rows for an enrichment calculation. Each row represents 327 a record with the following properties: 328 * identifier {str} 329 * p-value {float} 330 * matches {int} 331 * description {str} 332 333 The enrichment row object may be treated as an object with property access, or as 334 a dictionary, supporting key lookup with the [] operator: 335 336 >>> p_value = row['p-value'] 337 338 """ 339 if self._service.version < 8: 340 raise ServiceError("This service does not support enrichment requests") 341 params = dict(list = self.name, widget = widget, correction = correction, maxp = maxp, filter = filter) 342 if background is not None: 343 if self._service.version < 11: 344 raise ServiceError("This service does not support custom background populations") 345 params["population"] = background 346 form = urllib.urlencode(params) 347 uri = self._service.root + self._service.LIST_ENRICHMENT_PATH 348 resp = self._service.opener.open(uri, form) 349 return JSONIterator(resp, EnrichmentLine)
350
351 - def __xor__(self, other):
352 """Calculate the symmetric difference of this list and another""" 353 return self._manager.xor([self, other])
354
355 - def __ixor__(self, other):
356 """Calculate the symmetric difference of this list and another and replace this list with the result""" 357 diff = self._manager.xor([self, other], description=self.description, tags=self.tags) 358 self.delete() 359 diff.name = self.name 360 return diff
361
362 - def __sub__(self, other):
363 """Subtract the other from this list""" 364 return self._manager.subtract([self], [other])
365
366 - def __isub__(self, other):
367 """Replace this list with the subtraction of the other from this list""" 368 subtr = self._manager.subtract([self], [other], description=self.description, tags=self.tags) 369 self.delete() 370 subtr.name = self.name 371 return subtr
372
373 - def add_tags(self, *tags):
374 """ 375 Tag this list with one or more categories 376 ========================================= 377 378 Calls the server to add these tags, and updates this lists tags. 379 """ 380 self._tags = frozenset(self._manager.add_tags(self, tags))
381
382 - def remove_tags(self, *tags):
383 """ 384 Remove tags associated with this list. 385 ====================================== 386 387 Calls the server to remove these tags, and updates this lists tags. 388 """ 389 self._tags = frozenset(self._manager.remove_tags(self, tags))
390
391 - def update_tags(self, *tags):
392 """ 393 Remove tags associated with this list. 394 ====================================== 395 396 Calls the server to remove these tags, and updates this lists tags. 397 """ 398 self._tags = frozenset(self._manager.get_tags(self))
399