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