Package omero :: Package gateway
[hide private]
[frames] | no frames]

Source Code for Package omero.gateway

   1  # -*- coding: utf-8 -*- 
   2  # 
   3  # blitz_gateway - python bindings and wrappers to access an OMERO blitz server 
   4  #  
   5  # Copyright (c) 2007, 2010 Glencoe Software, Inc. All rights reserved. 
   6  #  
   7  # This software is distributed under the terms described by the LICENCE file 
   8  # you can find at the root of the distribution bundle, which states you are 
   9  # free to use it only for non commercial purposes. 
  10  # If the file is missing please request a copy by contacting 
  11  # jason@glencoesoftware.com. 
  12   
  13  # Set up the python include paths 
  14  import os,sys 
  15  THISPATH = os.path.dirname(os.path.abspath(__file__)) 
  16   
  17  import shutil 
  18  import tempfile 
  19  from types import IntType, LongType, UnicodeType, ListType, TupleType, StringType, StringTypes 
  20  from datetime import datetime 
  21  from cStringIO import StringIO 
  22  import ConfigParser 
  23   
  24  import omero 
  25  import omero.clients 
  26  from omero.util.decorators import timeit, TimeIt 
  27  import Ice 
  28  import Glacier2 
  29   
  30  import traceback 
  31  import time 
  32  import array 
  33  import math 
  34   
  35  import logging 
  36  logger = logging.getLogger('blitz_gateway') 
  37   
  38  try: 
  39      import Image, ImageDraw, ImageFont 
  40  except: #pragma: nocover 
  41      try: 
  42          from PIL import Image, ImageDraw, ImageFont 
  43      except: 
  44          logger.error('No PIL installed, line plots and split channel will fail!') 
  45  from cStringIO import StringIO 
  46  from math import sqrt 
  47   
  48  import omero_Constants_ice   
  49  import omero_ROMIO_ice 
  50  from omero.rtypes import rstring, rint, rlong, rbool, rtime, rlist, rdouble, unwrap 
51 52 -def omero_type(val):
53 """ 54 Converts rtypes from static factory methods: 55 - StringType to rstring 56 - UnicodeType to rstring 57 - IntType to rint 58 - LongType to rlong 59 elswere return the argument itself 60 61 @param val: value 62 @rtype: omero.rtype 63 @return: matched RType or value 64 """ 65 66 if isinstance(val, StringType): 67 return rstring(val) 68 elif isinstance(val, UnicodeType): 69 return rstring(val.encode('utf-8')) 70 elif isinstance(val, IntType): 71 return rint(val) 72 elif isinstance(val, LongType): 73 return rlong(val) 74 else: 75 return val
76
77 -def fileread (fin, fsize, bufsize):
78 """ 79 Reads everything from fin, in chunks of bufsize. 80 81 82 @type fin: file 83 @param fin: filelike readable object 84 @type fsize: int 85 @param fsize: total number of bytes to read 86 @type bufsize: int 87 @param fsize: size of each chunk of data read from fin 88 @rtype: string 89 @return: string buffer holding the contents read from the file 90 """ 91 # Read it all in one go 92 p = 0 93 rv = '' 94 while p < fsize: 95 s = min(bufsize, fsize-p) 96 rv += fin.read(p,s) 97 p += s 98 fin.close() 99 return rv
100
101 102 -def fileread_gen (fin, fsize, bufsize):
103 """ 104 Generator helper function that yields chunks of the file of size fsize. 105 106 @type fin: file 107 @param fin: filelike readable object 108 @type fsize: int 109 @param fsize: total number of bytes to read 110 @type bufsize: int 111 @param fsize: size of each chunk of data read from fin that gets yielded 112 @rtype: generator 113 @return: generator of string buffers of size up to bufsize read from fin 114 """ 115 p = 0 116 while p < fsize: 117 s = min(bufsize, fsize-p) 118 yield fin.read(p,s) 119 p += s 120 fin.close()
121
122 -class BlitzObjectWrapper (object):
123 """ 124 Object wrapper class which provides various methods for hierarchy traversing, 125 saving, handling permissions etc. 126 This is the 'abstract' super class which is subclassed by 127 E.g. _ProjectWrapper, _DatasetWrapper etc. 128 All ojbects have a reference to the L{BlitzGateway} connection, and therefore all services are 129 available for handling calls on the object wrapper. E.g listChildren() uses queryservice etc. 130 """ 131 132 OMERO_CLASS = None # E.g. 'Project', 'Dataset', 'Experimenter' etc. 133 LINK_CLASS = None 134 LINK_CHILD = 'child' 135 CHILD_WRAPPER_CLASS = None 136 PARENT_WRAPPER_CLASS = None 137 138 @staticmethod 141
142 - def __init__ (self, conn=None, obj=None, cache=None, **kwargs):
143 """ 144 Initialises the wrapper object, setting the various class variables etc 145 146 @param conn: The L{omero.gateway.BlitzGateway} connection. 147 @type conn: L{omero.gateway.BlitzGateway} 148 @param obj: The object to wrap. E.g. omero.model.Image 149 @type obj: omero.model object 150 @param cache: Cache which is passed to new child wrappers 151 """ 152 self.__bstrap__() 153 self._obj = obj 154 self._cache = cache 155 if self._cache is None: 156 self._cache = {} 157 self._conn = conn 158 self._creationDate = None 159 if conn is None: 160 return 161 if hasattr(obj, 'id') and obj.id is not None: 162 self._oid = obj.id.val 163 if not self._obj.loaded: 164 self._obj = self._conn.getQueryService().get(self._obj.__class__.__name__, self._oid) 165 self.__prepare__ (**kwargs)
166
167 - def __eq__ (self, a):
168 """ 169 Returns true if the object is of the same type and has same id and name 170 171 @param a: The object to compare to this one 172 @return: True if objects are same - see above 173 @rtype: Boolean 174 """ 175 return type(a) == type(self) and self._obj.id == a._obj.id and self.getName() == a.getName()
176
177 - def __bstrap__ (self):
178 """ Initialisation method which is implemented by subclasses to set their class variables etc. """ 179 pass
180
181 - def __prepare__ (self, **kwargs):
182 """ Initialisation method which is implemented by subclasses to handle various init tasks """ 183 pass
184
185 - def __repr__ (self):
186 """ 187 Returns a String representation of the Object, including ID if set. 188 189 @return: String E.g. '<DatasetWrapper id=123>' 190 @rtype: String 191 """ 192 if hasattr(self, '_oid'): 193 return '<%s id=%s>' % (self.__class__.__name__, str(self._oid)) 194 return super(BlitzObjectWrapper, self).__repr__()
195
196 - def _getQueryString(self):
197 """ 198 Used for building queries in generic methods such as getObjects("Project") 199 """ 200 return "select obj from %s obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 201 "join fetch obj.details.creationEvent" % self.OMERO_CLASS
202
203 - def _getChildWrapper (self):
204 """ 205 Returns the wrapper class of children of this object. 206 Checks that this is one of the Wrapper objects in the L{omero.gateway} module 207 Raises NotImplementedError if this is not true or class is not defined (None) 208 This is used internally by the L{listChildren} and L{countChildren} methods. 209 210 @return: The child wrapper class. E.g. omero.gateway.DatasetWrapper.__class__ 211 @rtype: class 212 """ 213 if self.CHILD_WRAPPER_CLASS is None: 214 raise NotImplementedError('%s has no child wrapper defined' % self.__class__) 215 if type(self.CHILD_WRAPPER_CLASS) is type(''): 216 # resolve class 217 if hasattr(omero.gateway, self.CHILD_WRAPPER_CLASS): 218 self.__class__.CHILD_WRAPPER_CLASS = self.CHILD_WRAPPER_CLASS = getattr(omero.gateway, self.CHILD_WRAPPER_CLASS) 219 else: #pragma: no cover 220 raise NotImplementedError 221 return self.CHILD_WRAPPER_CLASS
222
223 - def _getParentWrappers (self):
224 """ 225 Returns the wrapper classes of the parent of this object. 226 This is used internally by the L{listParents} method. 227 228 @return: List of parent wrapper classes. E.g. omero.gateway.DatasetWrapper.__class__ 229 @rtype: class 230 """ 231 if self.PARENT_WRAPPER_CLASS is None: 232 raise NotImplementedError 233 pwc = self.PARENT_WRAPPER_CLASS 234 if not isinstance(pwc, ListType): 235 pwc = [pwc,] 236 for i in range(len(pwc)): 237 if isinstance(pwc[i], StringTypes): 238 # resolve class 239 g = globals() 240 if not g.has_key(pwc[i]): #pragma: no cover 241 raise NotImplementedError 242 pwc[i] = g[pwc[i]] 243 244 #if type(self.PARENT_WRAPPER_CLASS) is type(''): 245 # # resolve class 246 # g = globals() 247 # if not g.has_key(self.PARENT_WRAPPER_CLASS): #pragma: no cover 248 # raise NotImplementedError 249 # self.__class__.PARENT_WRAPPER_CLASS = self.PARENT_WRAPPER_CLASS = g[self.PARENT_WRAPPER_CLASS] 250 #return self.PARENT_WRAPPER_CLASS 251 if pwc != self.PARENT_WRAPPER_CLASS or pwc != self.__class__.PARENT_WRAPPER_CLASS: 252 self.__class__.PARENT_WRAPPER_CLASS = self.PARENT_WRAPPER_CLASS = pwc 253 return self.PARENT_WRAPPER_CLASS
254
255 - def __loadedHotSwap__ (self):
256 """ 257 Loads the object that is wrapped by this class. This includes linked objects. 258 This method can be overwritten by subclasses that want to specify how/which linked objects 259 are loaded. 260 """ 261 self._obj = self._conn.getContainerService().loadContainerHierarchy(self.OMERO_CLASS, (self._oid,), None)[0]
262 285
286 - def findChildByName (self, name, description=None):
287 """ 288 Find the first child object with a matching name, and description if specified. 289 290 @param name: The name which must match the child name 291 @param description: If specified, child description must match too 292 @return: The wrapped child object 293 @rtype: L{BlitzObjectWrapper} 294 """ 295 for c in self.listChildren(): 296 if c.getName() == name: 297 if description is None or omero_type(description) == omero_type(c.getDescription()): 298 return c 299 return None
300
301 - def getDetails (self):
302 """ 303 Gets the details of the wrapped object 304 305 @return: L{omero.gateway.DetailsWrapper} or None if object not loaded 306 @rtype: L{DetailsWrapper} 307 """ 308 if self._obj.loaded: 309 return omero.gateway.DetailsWrapper (self._conn, self._obj.getDetails()) 310 return None
311 312
313 - def getDate(self):
314 """ 315 Returns the object's acquisitionDate, or creation date (details.creationEvent.time) 316 317 @return: A L{datetime.datetime} object 318 @rtype: datetime 319 """ 320 321 try: 322 if self._obj.acquisitionDate.val is not None and self._obj.acquisitionDate.val > 0: 323 t = self._obj.acquisitionDate.val 324 return datetime.fromtimestamp(t/1000) 325 except: 326 # object doesn't have acquisitionDate 327 pass 328 329 return self.creationEventDate()
330 331
332 - def save (self):
333 """ 334 Uses the updateService to save the wrapped object. 335 336 @rtype: None 337 """ 338 self._obj = self._conn.getUpdateService().saveAndReturnObject(self._obj)
339
340 - def saveAs (self, details):
341 """ 342 Save this object, keeping the object owner the same as the one on provided details 343 If the current user is an admin but is NOT the owner specified in 'details', 344 then create a new connection for that owner, clone the current object under that 345 connection and save. 346 Otherwise, simply save. 347 348 @param details: The Details specifying owner to save to 349 @type details: L{DetailsWrapper} 350 @return: None 351 """ 352 if self._conn.isAdmin(): 353 d = self.getDetails() 354 if d.getOwner() and \ 355 d.getOwner().omeName == details.getOwner().omeName and \ 356 d.getGroup().name == details.getGroup().name: 357 return self.save() 358 else: 359 newConn = self._conn.suConn(details.getOwner().omeName, details.getGroup().name) 360 #p = omero.sys.Principal() 361 #p.name = details.getOwner().omeName 362 #p.group = details.getGroup().name 363 #p.eventType = "User" 364 #newConnId = self._conn.getSessionService().createSessionWithTimeout(p, 60000) 365 #newConn = self._conn.clone() 366 #newConn.connect(sUuid=newConnId.getUuid().val) 367 clone = self.__class__(newConn, self._obj) 368 clone.save() 369 self._obj = clone._obj 370 return 371 else: 372 return self.save()
373
374 - def canWrite (self):
375 """ 376 Delegates to the connection L{BlitzGateway.canWrite} method 377 378 @rtype: Boolean 379 """ 380 return self._conn.canWrite(self._obj)
381
382 - def canOwnerWrite (self):
383 """ 384 Returns isUserWrite() from the object's permissions 385 386 @rtype: Boolean 387 @return: True if the objects's permissions allow user to write 388 """ 389 return self._obj.details.permissions.isUserWrite()
390
391 - def canDelete(self):
392 """ 393 Determines whether the current user can delete this object. 394 Returns True if the object L{isOwned} by the current user or L{isLeaded} 395 (current user is leader of this the group that this object belongs to) 396 397 @rtype: Boolean 398 @return: see above 399 """ 400 return self.isOwned() or self.isLeaded()
401
402 - def isOwned(self):
403 """ 404 Returns True if the object owner is the same user specified in the connection's Event Context 405 406 @rtype: Boolean 407 @return: True if current user owns this object 408 """ 409 return (self._obj.details.owner.id.val == self._conn.getEventContext().userId)
410
411 - def isLeaded(self):
412 """ 413 Returns True if the group that this object belongs to is lead by the currently logged-in user 414 415 @rtype: Boolean 416 @return: see above 417 """ 418 if self._obj.details.group.id.val in self._conn.getEventContext().leaderOfGroups: 419 return True 420 return False
421
422 - def isEditable(self):
423 """ 424 Determines whether the current user can edit this object. 425 Returns True if the object L{isOwned} by the current user 426 Also True if object is not L{private<isPrivate>} AND not L{readOnly<isReadOnly>} 427 428 @rtype: Boolean 429 @return: see above 430 """ 431 return self.isOwned() or (not self.isPrivate() and not self.isReadOnly())
432
433 - def isPublic(self):
434 """ 435 Determines if the object permissions are world readable, ie permissions.isWorldRead() 436 437 @rtype: Boolean 438 @return: see above 439 """ 440 return self._obj.details.permissions.isWorldRead()
441
442 - def isShared(self):
443 """ 444 Determines if the object is sharable between groups (but not public) 445 446 @rtype: Boolean 447 @return: True if the object is not L{public<isPublic>} AND the 448 object permissions allow group read. 449 """ 450 if not self.isPublic(): 451 return self._obj.details.permissions.isGroupRead() 452 return False
453
454 - def isPrivate(self):
455 """ 456 Determines if the object is private 457 458 @rtype: Boolean 459 @return: True if the object is not L{public<isPublic>} and not L{shared<isShared>} and 460 permissions allow user to read. 461 """ 462 if not self.isPublic() and not self.isShared(): 463 return self._obj.details.permissions.isUserRead() 464 return False
465
466 - def isReadOnly(self):
467 """ 468 Determines if the object is visible but not writeable 469 470 @rtype: Boolean 471 @return: True if public but not world writable 472 True if shared but not group writable 473 True if private but not user writable 474 """ 475 if self.isPublic() and not self._obj.details.permissions.isWorldWrite(): 476 return True 477 elif self.isShared() and not self._obj.details.permissions.isGroupWrite(): 478 return True 479 elif self.isPrivate() and not self._obj.details.permissions.isUserWrite(): 480 return True 481 return False
482
483 - def countChildren (self):
484 """ 485 Counts available number of child objects. 486 487 @return: The number of child objects available 488 @rtype: Long 489 """ 490 491 childw = self._getChildWrapper() 492 klass = "%sLinks" % childw().OMERO_CLASS.lower() 493 #self._cached_countChildren = len(self._conn.getQueryService().findAllByQuery("from %s as c where c.parent.id=%i" % (self.LINK_CLASS, self._oid), None)) 494 self._cached_countChildren = self._conn.getContainerService().getCollectionCount(self.OMERO_CLASS, klass, [self._oid], None)[self._oid] 495 return self._cached_countChildren
496
497 - def countChildren_cached (self):
498 """ 499 countChildren, but caching the first result, useful if you need to call this multiple times in 500 a single sequence, but have no way of storing the value between them. 501 It is actually a hack to support django template's lack of break in for loops 502 503 @return: The number of child objects available 504 @rtype: Long 505 """ 506 507 if not hasattr(self, '_cached_countChildren'): 508 return self.countChildren() 509 return self._cached_countChildren
510
511 - def _listChildren (self, ns=None, val=None, params=None):
512 """ 513 Lists available child objects. 514 515 @rtype: generator of Ice client proxy objects for the child nodes 516 @return: child objects. 517 """ 518 if not params: 519 params = omero.sys.Parameters() 520 if not params.map: 521 params.map = {} 522 params.map["dsid"] = omero_type(self._oid) 523 query = "select c from %s as c" % self.LINK_CLASS 524 if ns is not None: 525 params.map["ns"] = omero_type(ns) 526 query += """ join fetch c.child as ch 527 left outer join fetch ch.annotationLinks as ial 528 left outer join fetch ial.child as a """ 529 query += " where c.parent.id=:dsid" 530 if ns is not None: 531 query += " and a.ns=:ns" 532 if val is not None: 533 if isinstance(val, StringTypes): 534 params.map["val"] = omero_type(val) 535 query +=" and a.textValue=:val" 536 query += " order by c.child.name" 537 for child in ( x.child for x in self._conn.getQueryService().findAllByQuery(query, params) ): 538 yield child
539
540 - def listChildren (self, ns=None, val=None, params=None):
541 """ 542 Lists available child objects. 543 544 @rtype: generator of L{BlitzObjectWrapper} objs 545 @return: child objects. 546 """ 547 childw = self._getChildWrapper() 548 for child in self._listChildren(ns=ns, val=val, params=params): 549 yield childw(self._conn, child, self._cache)
550
551 - def getParent (self, withlinks=False):
552 """ 553 List a single parent, if available. 554 555 While the model suports many to many relationships between most objects, there are 556 implementations that assume a single project per dataset, a single dataset per image, 557 etc. This is just a shortcut method to return a single parent object. 558 559 @type withlinks: Boolean 560 @param withlinks: if true result will be a tuple of (linkobj, obj) 561 @rtype: L{BlitzObjectWrapper} ( or tuple(L{BlitzObjectWrapper}, L{BlitzObjectWrapper}) ) 562 @return: the parent object with or without the link depending on args 563 """ 564 565 rv = self.listParents(withlinks=withlinks) 566 return len(rv) and rv[0] or None
567
568 - def listParents (self, withlinks=False):
569 """ 570 Lists available parent objects. 571 572 @type withlinks: Boolean 573 @param withlinks: if true each yielded result will be a tuple of (linkobj, obj) 574 @rtype: list of L{BlitzObjectWrapper} ( or tuple(L{BlitzObjectWrapper}, L{BlitzObjectWrapper}) ) 575 @return: the parent objects, with or without the links depending on args 576 """ 577 if self.PARENT_WRAPPER_CLASS is None: 578 return () 579 parentw = self._getParentWrappers() 580 param = omero.sys.Parameters() # TODO: What can I use this for? 581 parentnodes = [] 582 for pwc in parentw: 583 pwck = pwc() 584 if withlinks: 585 parentnodes.extend([(pwc(self._conn, pwck.LINK_PARENT(x), self._cache), BlitzObjectWrapper(self._conn, x)) for x in self._conn.getQueryService().findAllByQuery("from %s as c where c.%s.id=%i" % (pwck.LINK_CLASS, pwck.LINK_CHILD, self._oid), param)]) 586 else: 587 parentnodes.extend([pwc(self._conn, pwck.LINK_PARENT(x), self._cache) for x in self._conn.getQueryService().findAllByQuery("from %s as c where c.%s.id=%i" % (pwck.LINK_CLASS, pwck.LINK_CHILD, self._oid), param)]) 588 return parentnodes
589
590 - def getAncestry (self):
591 """ 592 Get a list of Ancestors. First in list is parent of this object. 593 TODO: Assumes getParent() returns a single parent. 594 595 @rtype: List of L{BlitzObjectWrapper} 596 @return: List of Ancestor objects 597 """ 598 rv = [] 599 p = self.getParent() 600 while p: 601 rv.append(p) 602 p = p.getParent() 603 return rv
604 639 664 676 677 # _listAnnotationLinks 693 694
695 - def unlinkAnnotations (self, ns):
696 """ 697 Uses updateService to unlink annotations, with specified ns 698 699 @param ns: Namespace 700 @type ns: String 701 """ 702 for al in self._getAnnotationLinks(ns=ns): 703 update = self._conn.getUpdateService() 704 update.deleteObject(al) 705 self._obj.unloadAnnotationLinks()
706
707 - def removeAnnotations (self, ns):
708 """ 709 Uses updateService to delete annotations, with specified ns, and their links on the object 710 711 @param ns: Namespace 712 @type ns: String 713 """ 714 for al in self._getAnnotationLinks(ns=ns): 715 a = al.child 716 update = self._conn.getUpdateService() 717 update.deleteObject(al) 718 update.deleteObject(a) 719 self._obj.unloadAnnotationLinks()
720 721 # findAnnotations(self, ns=[])
722 - def getAnnotation (self, ns=None):
723 """ 724 Gets the first annotation on the object, filtered by ns if specified 725 726 @param ns: Namespace 727 @type ns: String 728 @return: L{AnnotationWrapper} or None 729 """ 730 rv = self._getAnnotationLinks(ns) 731 if len(rv): 732 return AnnotationWrapper._wrap(self._conn, rv[0].child, link=rv[0]) 733 return None
734
735 - def listAnnotations (self, ns=None):
736 """ 737 List annotations in the ns namespace, linked to this object 738 739 @return: Generator yielding L{AnnotationWrapper} 740 @rtype: L{AnnotationWrapper} generator 741 """ 742 for ann in self._getAnnotationLinks(ns): 743 yield AnnotationWrapper._wrap(self._conn, ann.child, link=ann)
744
745 - def listOrphanedAnnotations(self, eid=None, ns=None, anntype=None):
746 """ 747 Retrieve all Annotations not linked to the given Project, Dataset, Image, 748 Screen, Plate, Well ID controlled by the security system. 749 750 @param o_type: type of Object 751 @type o_type: String 752 @param oid: Object ID 753 @type oid: Long 754 @return: Generator yielding Tags 755 @rtype: L{AnnotationWrapper} generator 756 """ 757 758 if anntype is not None: 759 if anntype.title() not in ('Text', 'Tag', 'File', 'Long', 'Boolean'): 760 raise AttributeError('It only retrieves: Text, Tag, File, Long, Boolean') 761 sql = "select an from %sAnnotation as an " % anntype.title() 762 else: 763 sql = "select an from Annotation as an " \ 764 765 if anntype.title() == "File": 766 sql += " join fetch an.file " 767 768 sql += "where not exists ( select obal from %sAnnotationLink as obal "\ 769 "where obal.child=an.id and obal.parent.id=:oid) " % self.OMERO_CLASS 770 771 q = self._conn.getQueryService() 772 p = omero.sys.Parameters() 773 p.map = {} 774 p.map["oid"] = rlong(self._oid) 775 if ns is None: 776 sql += " and an.ns is null" 777 else: 778 p.map["ns"] = rlist([rstring(n) for n in ns]) 779 sql += " and (an.ns not in (:ns) or an.ns is null)" 780 if eid is not None: 781 sql += " and an.details.owner.id=:eid" 782 p.map["eid"] = rlong(eid) 783 784 for e in q.findAllByQuery(sql,p): 785 yield AnnotationWrapper._wrap(self._conn, e)
786
787 - def _linkAnnotation (self, ann):
788 """ 789 Saves the annotation to DB if needed - setting the permissions manually. 790 Creates the annotation link and saves it, setting permissions manually. 791 TODO: Can't set permissions manually in 4.2 - Assumes world & group writable 792 793 @param ann: The annotation object 794 @type ann: L{AnnotationWrapper} 795 """ 796 if not ann.getId(): 797 # Not yet in db, save it 798 ann = ann.__class__(self._conn, self._conn.getUpdateService().saveAndReturnObject(ann._obj)) 799 #else: 800 # ann.save() 801 lnktype = "%sAnnotationLinkI" % self.OMERO_CLASS 802 lnk = getattr(omero.model, lnktype)() 803 lnk.setParent(self._obj.__class__(self._obj.id, False)) 804 lnk.setChild(ann._obj.__class__(ann._obj.id, False)) 805 self._conn.getUpdateService().saveObject(lnk) 806 return ann
807 808
809 - def linkAnnotation (self, ann, sameOwner=True):
810 """ 811 Link the annotation to this object. 812 813 @param ann: The Annotation object 814 @type ann: L{AnnotationWrapper} 815 @param sameOwner: If True, try to make sure that the link is created by the object owner 816 @type sameOwner: Boolean 817 @return: The annotation 818 @rtype: L{AnnotationWrapper} 819 """ 820 821 """ 822 My notes (will) to try and work out what's going on! 823 If sameOwner: 824 if current user is admin AND they are not the object owner, 825 if the object owner and annotation owner are the same: 826 use the Annotation connection to do the linking 827 else use a new connection for the object owner (?same owner as ann?) 828 do linking 829 else: 830 try to switch the current group of this object to the group of the annotation - do linking 831 else - just do linking 832 833 """ 834 if sameOwner: 835 d = self.getDetails() 836 ad = ann.getDetails() 837 if self._conn.isAdmin() and self._conn._userid != d.getOwner().id: 838 # Keep the annotation owner the same as the linked of object's 839 if ad.getOwner() and d.getOwner().omeName == ad.getOwner().omeName and d.getGroup().name == ad.getGroup().name: 840 newConn = ann._conn 841 else: 842 #p = omero.sys.Principal() 843 #p.name = d.getOwner().omeName 844 group = None 845 if d.getGroup(): 846 group = d.getGroup().name 847 # TODO: Do you know that the object owner is same as ann owner?? 848 newConn = self._conn.suConn(d.getOwner().omeName, group) 849 #p.eventType = "User" 850 #newConnId = self._conn.getSessionService().createSessionWithTimeout(p, 60000) 851 #newConn = self._conn.clone() 852 #newConn.connect(sUuid=newConnId.getUuid().val) 853 clone = self.__class__(newConn, self._obj) 854 ann = clone._linkAnnotation(ann) 855 if newConn != self._conn: 856 newConn.seppuku() 857 elif d.getGroup(): 858 # Try to match group 859 # TODO: Should switch session of this object to use group from annotation (ad) not this object (d) ? 860 self._conn.setGroupForSession(d.getGroup().getId()) 861 ann = self._linkAnnotation(ann) 862 self._conn.revertGroupForSession() 863 else: 864 ann = self._linkAnnotation(ann) 865 else: 866 ann = self._linkAnnotation(ann) 867 self.unloadAnnotationLinks() 868 return ann
869 870
871 - def simpleMarshal (self, xtra=None, parents=False):
872 """ 873 Creates a dict representation of this object. 874 E.g. for Image: {'description': '', 'author': 'Will Moore', 'date': 1286332557.0, 875 'type': 'Image', 'id': 3841L, 'name': 'cb_4_w500_t03_z01.tif'} 876 877 @param xtra: A dict of extra keys to include. E.g. 'childCount' 878 @type xtra: Dict 879 @param parents: If True, include a list of ancestors (in simpleMarshal form) as 'parents' 880 @type parents: Boolean 881 @return: A dict representation of this object 882 @rtype: Dict 883 """ 884 rv = {'type': self.OMERO_CLASS, 885 'id': self.getId(), 886 'name': self.getName(), 887 'description': self.getDescription(), 888 } 889 if hasattr(self, '_attrs'): 890 # 'key' -> key = _obj[key] 891 # '#key' -> key = _obj[key].value.val 892 # 'key;title' -> title = _obj[key] 893 # 'key|wrapper' -> key = omero.gateway.wrapper(_obj[key]).simpleMarshal 894 for k in self._attrs: 895 if ';' in k: 896 s = k.split(';') 897 k = s[0] 898 rk = ';'.join(s[1:]) 899 else: 900 rk = k 901 rk = rk.replace('#', '') 902 if '|' in k: 903 s = k.split('|') 904 k2 = s[0] 905 w = '|'.join(s[1:]) 906 if rk == k: 907 rk = k2 908 k = k2 909 v = getattr(self, k) 910 if v is not None: 911 v = getattr(omero.gateway, w)(self._conn, v).simpleMarshal() 912 else: 913 if k.startswith('#'): 914 v = getattr(self, k[1:]) 915 if v is not None: 916 v = v._value 917 else: 918 v = getattr(self, k) 919 if hasattr(v, 'val'): 920 v = v.val 921 rv[rk] = v 922 if xtra: # TODO check if this can be moved to a more specific place 923 if xtra.has_key('childCount'): 924 rv['child_count'] = self.countChildren() 925 if parents: 926 rv['parents'] = map(lambda x: x.simpleMarshal(), self.getAncestry()) 927 return rv
928 929 #def __str__ (self): 930 # if hasattr(self._obj, 'value'): 931 # return str(self.value) 932 # return str(self._obj) 933
934 - def __getattr__ (self, attr):
935 """ 936 Attempts to return the named attribute of this object. E.g. image.__getattr__('name') or 'getName' 937 In cases where the attribute E.g. 'getImmersion' should return an enumeration, this is specified by the 938 attr name starting with '#' #immersion. 939 In cases where the attribute E.g. 'getLightSource' should return a wrapped object, this is handled 940 by the parent encoding the wrapper in the attribute name. E.g 'lightSource|LightSourceWrapper' 941 In both cases this returns a method that will return the object. 942 In addition, lookup of methods that return an rtype are wrapped to the method instead returns a primitive type. 943 E.g. image.getArchived() will return a boolean instead of rbool. 944 945 @param attr: The name of the attribute to get 946 @type attr: String 947 @return: The named attribute. 948 @rtype: method, value (string, long etc) 949 """ 950 951 # handle lookup of 'get' methods, using '_attrs' dict to define how we wrap returned objects. 952 if attr != 'get' and attr.startswith('get') and hasattr(self, '_attrs'): 953 tattr = attr[3].lower() + attr[4:] # 'getName' -> 'name' 954 attrs = filter(lambda x: tattr in x, self._attrs) # find attr with 'name' 955 for a in attrs: 956 if a.startswith('#') and a[1:] == tattr: 957 v = getattr(self, tattr) 958 if v is not None: 959 v = v._value 960 def wrap (): 961 return v
962 return wrap 963 if len(a) > len(tattr) and a[len(tattr)] == '|': # E.g. a = lightSource|LightSourceWrapper 964 def wrap (): # E.g. method returns a LightSourceWrapper(omero.model.lightSource) 965 return getattr(omero.gateway, a[len(tattr)+1:])(self._conn, getattr(self, tattr))
966 return wrap 967 968 # handle lookup of 'get' methods when we don't have '_attrs' on the object, E.g. image.getAcquisitionDate 969 if attr != 'get' and attr.startswith('get'): 970 attrName = attr[3].lower() + attr[4:] # E.g. getAcquisitionDate -> acquisitionDate 971 if hasattr(self._obj, attrName): 972 def wrap(): 973 rv = getattr(self._obj, attrName) 974 if hasattr(rv, 'val'): 975 return isinstance(rv.val, StringType) and rv.val.decode('utf8') or rv.val 976 elif isinstance(rv, omero.model.IObject): 977 return BlitzObjectWrapper(self._conn, rv) 978 return rv 979 return wrap 980 981 # handle direct access of attributes. E.g. image.acquisitionDate 982 # also handles access to other methods E.g. image.unloadPixels() 983 if not hasattr(self._obj, attr) and hasattr(self._obj, '_'+attr): 984 attr = '_' + attr 985 if hasattr(self._obj, attr): 986 rv = getattr(self._obj, attr) 987 if hasattr(rv, 'val'): # unwrap rtypes 988 return isinstance(rv.val, StringType) and rv.val.decode('utf8') or rv.val 989 return rv 990 raise AttributeError("'%s' object has no attribute '%s'" % (self._obj.__class__.__name__, attr)) 991 992 993 # some methods are accessors in _obj and return and omero:: type. The obvious ones we wrap to return a python type 994
995 - def getId (self):
996 """ 997 Gets this object ID 998 999 @return: Long or None 1000 """ 1001 oid = self._obj.getId() 1002 if oid is not None: 1003 return oid.val 1004 return None
1005
1006 - def getName (self):
1007 """ 1008 Gets this object name 1009 1010 @return: String or None 1011 """ 1012 if hasattr(self._obj, 'name'): 1013 if hasattr(self._obj.name, 'val'): 1014 return self._obj.getName().val 1015 else: 1016 return self._obj.getName() 1017 else: 1018 return None
1019
1020 - def getDescription (self):
1021 """ 1022 Gets this object description 1023 1024 @return: String 1025 """ 1026 rv = hasattr(self._obj, 'description') and self._obj.getDescription() or None 1027 return rv and rv.val or ''
1028
1029 - def getOwner (self):
1030 """ 1031 Gets user who is the owner of this object. 1032 1033 @return: _ExperimenterWrapper 1034 """ 1035 return self.getDetails().getOwner()
1036
1037 - def getOwnerFullName (self):
1038 """ 1039 Gets full name of the owner of this object. 1040 1041 @return: String or None 1042 """ 1043 try: 1044 lastName = self.getDetails().getOwner().lastName 1045 firstName = self.getDetails().getOwner().firstName 1046 middleName = self.getDetails().getOwner().middleName 1047 1048 if middleName is not None and middleName != '': 1049 name = "%s %s. %s" % (firstName, middleName, lastName) 1050 else: 1051 name = "%s %s" % (firstName, lastName) 1052 return name 1053 except: 1054 logger.error(traceback.format_exc()) 1055 return None
1056
1057 - def getOwnerOmeName (self):
1058 """ 1059 Gets omeName of the owner of this object. 1060 1061 @return: String 1062 """ 1063 return self.getDetails().getOwner().omeName
1064 1065
1066 - def creationEventDate(self):
1067 """ 1068 Gets event time in timestamp format (yyyy-mm-dd hh:mm:ss.fffffff) when object was created. 1069 1070 @return: The datetime for object creation 1071 @rtype: datetime.datetime 1072 """ 1073 1074 if self._creationDate is not None: 1075 return datetime.fromtimestamp(self._creationDate/1000) 1076 1077 try: 1078 if self._obj.details.creationEvent._time is not None: 1079 self._creationDate = self._obj.details.creationEvent._time.val 1080 else: 1081 self._creationDate = self._conn.getQueryService().get("Event", self._obj.details.creationEvent.id.val).time.val 1082 except: 1083 self._creationDate = self._conn.getQueryService().get("Event", self._obj.details.creationEvent.id.val).time.val 1084 return datetime.fromtimestamp(self._creationDate/1000)
1085 1086
1087 - def updateEventDate(self):
1088 """ 1089 Gets event time in timestamp format (yyyy-mm-dd hh:mm:ss.fffffff) when object was updated. 1090 1091 @return: The datetime for object update 1092 @rtype: datetime.datetime 1093 """ 1094 1095 try: 1096 if self._obj.details.updateEvent.time is not None: 1097 t = self._obj.details.updateEvent.time.val 1098 else: 1099 t = self._conn.getQueryService().get("Event", self._obj.details.updateEvent.id.val).time.val 1100 except: 1101 t = self._conn.getQueryService().get("Event", self._obj.details.updateEvent.id.val).time.val 1102 return datetime.fromtimestamp(t/1000)
1103 1104 1105 # setters are also provided 1106
1107 - def setName (self, value):
1108 """ 1109 Sets the name of the object 1110 1111 @param value: New name 1112 @type value: String 1113 """ 1114 self._obj.setName(omero_type(value))
1115
1116 - def setDescription (self, value):
1117 """ 1118 Sets the description of the object 1119 1120 @param value: New description 1121 @type value: String 1122 """ 1123 self._obj.setDescription(omero_type(value))
1124
1125 ## BASIC ## 1126 1127 -class NoProxies (object):
1128 """ A dummy placeholder to indicate that proxies haven't been created """
1129 - def __getitem__ (self, k):
1130 raise Ice.ConnectionLostException
1131
1132 -class _BlitzGateway (object):
1133 """ 1134 Connection wrapper. Handles connecting and keeping the session alive, creation of various services, 1135 context switching, security privilidges etc. 1136 """ 1137 1138 CONFIG = {} 1139 """ 1140 Holder for class wide configuration properties: 1141 - IMG_RDEFNS: a namespace for annotations linked on images holding the default rendering 1142 settings object id. 1143 - IMG_ROPTSNS: a namespace for annotations linked on images holding default rendering options 1144 that don't get saved in the rendering settings. 1145 One good place to define this is on the extending class' connect() method. 1146 """ 1147 ICE_CONFIG = None 1148 """ 1149 ICE_CONFIG - Defines the path to the Ice configuration 1150 """ 1151 # def __init__ (self, username, passwd, server, port, client_obj=None, group=None, clone=False): 1152
1153 - def __init__ (self, username=None, passwd=None, client_obj=None, group=None, clone=False, try_super=False, host=None, port=None, extra_config=None, secure=False, anonymous=True, useragent=None):
1154 """ 1155 Create the connection wrapper. Does not attempt to connect at this stage 1156 Initialises the omero.client 1157 1158 @param username: User name. If not specified, use 'omero.gateway.anon_user' 1159 @type username: String 1160 @param passwd: Password. 1161 @type passwd: String 1162 @param client_obj: omero.client 1163 @param group: name of group to try to connect to 1164 @type group: String 1165 @param clone: If True, overwrite anonymous with False 1166 @type clone: Boolean 1167 @param try_super: Try to log on as super user ('system' group) 1168 @type try_super: Boolean 1169 @param host: Omero server host. 1170 @type host: String 1171 @param port: Omero server port. 1172 @type port: Integer 1173 @param extra_config: Dictionary of extra configuration 1174 @type extra_config: Dict 1175 @param secure: Initial underlying omero.client connection type (True=SSL/False=insecure) 1176 @type secure: Boolean 1177 @param anonymous: 1178 @type anonymous: Boolean 1179 @param useragent: Log which python clients use this connection. E.g. 'OMERO.webadmin' 1180 @type useragent: String 1181 """ 1182 1183 if extra_config is None: extra_config = [] 1184 super(_BlitzGateway, self).__init__() 1185 self.c = client_obj 1186 if not type(extra_config) in (type(()), type([])): 1187 extra_config=[extra_config] 1188 self.extra_config = extra_config 1189 self.ice_config = [self.ICE_CONFIG] 1190 self.ice_config.extend(extra_config) 1191 self.ice_config = map(lambda x: str(x), filter(None, self.ice_config)) 1192 1193 self.host = host 1194 self.port = port 1195 self.secure = secure 1196 self.useragent = useragent 1197 1198 self._sessionUuid = None 1199 self._session_cb = None 1200 self._session = None 1201 self._lastGroupId = None 1202 self._anonymous = anonymous 1203 1204 self._connected = False 1205 self._user = None 1206 self._userid = None 1207 self._proxies = NoProxies() 1208 if self.c is None: 1209 self._resetOmeroClient() 1210 else: 1211 # if we already have client initialised, we can go ahead and create our services. 1212 self._connected = True 1213 self._createProxies() 1214 if not username: 1215 username = self.c.ic.getProperties().getProperty('omero.gateway.anon_user') 1216 passwd = self.c.ic.getProperties().getProperty('omero.gateway.anon_pass') 1217 #logger.debug('super: %s %s %s' % (try_super, str(group), self.c.ic.getProperties().getProperty('omero.gateway.admin_group'))) 1218 if try_super: 1219 self.group = 'system' #self.c.ic.getProperties().getProperty('omero.gateway.admin_group') 1220 else: 1221 self.group = group and group or None 1222 1223 # The properties we are setting through the interface 1224 self.setIdentity(username, passwd, not clone)
1225
1226 - def isAnonymous (self):
1227 """ 1228 Returns the anonymous flag 1229 1230 @return: Anonymous 1231 @rtype: Boolean 1232 """ 1233 return not not self._anonymous
1234
1235 - def getProperty(self, k):
1236 """ 1237 Returns named property of the wrapped omero.client 1238 1239 @return: named client property 1240 """ 1241 return self.c.getProperty(k)
1242
1243 - def clone (self):
1244 """ 1245 Returns a new instance of this class, with all matching properties. 1246 TODO: Add anonymous and userAgent parameters? 1247 1248 @return: Clone of this connection wrapper 1249 @rtype: L{_BlitzGateway} 1250 """ 1251 return self.__class__(self._ic_props[omero.constants.USERNAME], 1252 self._ic_props[omero.constants.PASSWORD], 1253 host = self.host, 1254 port = self.port, 1255 extra_config=self.extra_config, 1256 clone=True, 1257 secure=self.secure, 1258 anonymous=self._anonymous, 1259 useragent=self.useragent)
1260 #self.server, self.port, clone=True) 1261
1262 - def setIdentity (self, username, passwd, _internal=False):
1263 """ 1264 Saves the username and password for later use, creating session etc 1265 1266 @param username: User name. 1267 @type username: String 1268 @param passwd: Password. 1269 @type passwd: String 1270 @param _internal: If False, set _anonymous = False 1271 @type _internal: Booelan 1272 """ 1273 self._ic_props = {omero.constants.USERNAME: username, 1274 omero.constants.PASSWORD: passwd} 1275 if not _internal: 1276 self._anonymous = False
1277
1278 - def suConn (self, username, group=None, ttl=60000):
1279 """ 1280 If current user isAdmin, return new connection owned by 'username' 1281 1282 @param username: Username for new connection 1283 @type username: String 1284 @param group: If specified, try to log in to this group 1285 @type group: String 1286 @param ttl: Timeout for new session 1287 @type ttl: Int 1288 @return: Clone of this connection, with username's new Session 1289 @rtype: L{_BlitzGateway} or None if not admin or username unknown 1290 """ 1291 if self.isAdmin(): 1292 if group is None: 1293 e = self.getObject("Experimenter", attributes={'omeName': username}) 1294 if e is None: 1295 return 1296 group = e._obj._groupExperimenterMapSeq[0].parent.name.val 1297 p = omero.sys.Principal() 1298 p.name = username 1299 p.group = group 1300 p.eventType = "User" 1301 newConnId = self.getSessionService().createSessionWithTimeout(p, ttl) 1302 newConn = self.clone() 1303 newConn.connect(sUuid=newConnId.getUuid().val) 1304 return newConn
1305
1306 - def keepAlive (self):
1307 """ 1308 Keeps service alive. 1309 Returns True if connected. If connection was lost, reconnecting. 1310 If connection failed, returns False and error is logged. 1311 1312 @return: True if connection alive. 1313 @rtype: Boolean 1314 """ 1315 1316 try: 1317 if self.c.sf is None: #pragma: no cover 1318 logger.debug('... c.sf is None, reconnecting') 1319 return self.connect() 1320 return self.c.sf.keepAlive(self._proxies['admin']._obj) 1321 except Ice.ObjectNotExistException: #pragma: no cover 1322 # The connection is there, but it has been reset, because the proxy no longer exists... 1323 logger.debug(traceback.format_exc()) 1324 logger.debug("... reset, not reconnecting") 1325 return False 1326 except Ice.ConnectionLostException: #pragma: no cover 1327 # The connection was lost. This shouldn't happen, as we keep pinging it, but does so... 1328 logger.debug(traceback.format_exc()) 1329 logger.debug("... lost, reconnecting") 1330 #return self.connect() 1331 return False 1332 except Ice.ConnectionRefusedException: #pragma: no cover 1333 # The connection was refused. We lost contact with glacier2router... 1334 logger.debug(traceback.format_exc()) 1335 logger.debug("... refused, not reconnecting") 1336 return False 1337 except omero.SessionTimeoutException: #pragma: no cover 1338 # The connection is there, but it has been reset, because the proxy no longer exists... 1339 logger.debug(traceback.format_exc()) 1340 logger.debug("... reset, not reconnecting") 1341 return False 1342 except omero.RemovedSessionException: #pragma: no cover 1343 # Session died on us 1344 logger.debug(traceback.format_exc()) 1345 logger.debug("... session has left the building, not reconnecting") 1346 return False 1347 except Ice.UnknownException, x: #pragma: no cover 1348 # Probably a wrapped RemovedSession 1349 logger.debug(traceback.format_exc()) 1350 logger.debug('Ice.UnknownException: %s' % str(x)) 1351 logger.debug("... ice says something bad happened, not reconnecting") 1352 return False 1353 except: 1354 # Something else happened 1355 logger.debug(traceback.format_exc()) 1356 logger.debug("... error not reconnecting") 1357 return False
1358
1359 - def seppuku (self, softclose=False): #pragma: no cover
1360 """ 1361 Terminates connection with killSession(). If softclose is False, the session is really 1362 terminate disregarding its connection refcount. 1363 1364 @param softclose: Boolean 1365 """ 1366 self._connected = False 1367 if softclose: 1368 try: 1369 r = self.c.sf.getSessionService().getReferenceCount(self._sessionUuid) 1370 self.c.closeSession() 1371 if r < 2: 1372 self._session_cb and self._session_cb.close(self) 1373 except Ice.OperationNotExistException: 1374 self.c.closeSession() 1375 else: 1376 self._closeSession() 1377 self._proxies = NoProxies() 1378 logger.info("closed connecion (uuid=%s)" % str(self._sessionUuid))
1379 1380 # def __del__ (self): 1381 # logger.debug("##GARBAGE COLLECTOR KICK IN") 1382
1383 - def _createProxies (self):
1384 """ 1385 Creates proxies to the server services. Called on connection or security switch. 1386 Doesn't actually create any services themselves. Created if/when needed. 1387 If proxies have been created already, they are resynced and reused. 1388 """ 1389 1390 if not isinstance(self._proxies, NoProxies): 1391 logger.debug("## Reusing proxies") 1392 for k, p in self._proxies.items(): 1393 p._resyncConn(self) 1394 else: 1395 logger.debug("## Creating proxies") 1396 self._proxies = {} 1397 self._proxies['admin'] = ProxyObjectWrapper(self, 'getAdminService') 1398 self._proxies['config'] = ProxyObjectWrapper(self, 'getConfigService') 1399 self._proxies['container'] = ProxyObjectWrapper(self, 'getContainerService') 1400 self._proxies['delete'] = ProxyObjectWrapper(self, 'getDeleteService') 1401 self._proxies['export'] = ProxyObjectWrapper(self, 'createExporter') 1402 self._proxies['ldap'] = ProxyObjectWrapper(self, 'getLdapService') 1403 self._proxies['metadata'] = ProxyObjectWrapper(self, 'getMetadataService') 1404 self._proxies['query'] = ProxyObjectWrapper(self, 'getQueryService') 1405 self._proxies['pixel'] = ProxyObjectWrapper(self, 'getPixelsService') 1406 self._proxies['projection'] = ProxyObjectWrapper(self, 'getProjectionService') 1407 self._proxies['rawpixels'] = ProxyObjectWrapper(self, 'createRawPixelsStore') 1408 self._proxies['rendering'] = ProxyObjectWrapper(self, 'createRenderingEngine') 1409 self._proxies['rendsettings'] = ProxyObjectWrapper(self, 'getRenderingSettingsService') 1410 self._proxies['thumbs'] = ProxyObjectWrapper(self, 'createThumbnailStore') 1411 self._proxies['rawfile'] = ProxyObjectWrapper(self, 'createRawFileStore') 1412 self._proxies['repository'] = ProxyObjectWrapper(self, 'getRepositoryInfoService') 1413 self._proxies['roi'] = ProxyObjectWrapper(self, 'getRoiService') 1414 self._proxies['script'] = ProxyObjectWrapper(self, 'getScriptService') 1415 self._proxies['search'] = ProxyObjectWrapper(self, 'createSearchService') 1416 self._proxies['session'] = ProxyObjectWrapper(self, 'getSessionService') 1417 self._proxies['share'] = ProxyObjectWrapper(self, 'getShareService') 1418 self._proxies['sharedres'] = ProxyObjectWrapper(self, 'sharedResources') 1419 self._proxies['timeline'] = ProxyObjectWrapper(self, 'getTimelineService') 1420 self._proxies['types'] = ProxyObjectWrapper(self, 'getTypesService') 1421 self._proxies['update'] = ProxyObjectWrapper(self, 'getUpdateService') 1422 self._ctx = self._proxies['admin'].getEventContext() 1423 if self._ctx is not None: 1424 self._userid = self._ctx.userId 1425 # "guest" user has no access that method. 1426 self._user = self._ctx.userName!="guest" and self.getObject("Experimenter", self._userid) or None 1427 else: 1428 self._userid = None 1429 self._user = None 1430 1431 if self._session_cb: #pragma: no cover 1432 if self._was_join: 1433 self._session_cb.join(self) 1434 else: 1435 self._session_cb.create(self)
1436
1437 - def setSecure (self, secure=True):
1438 """ 1439 Switches between SSL and insecure (faster) connections to Blitz. 1440 The gateway must already be connected. 1441 1442 @param secure: If False, use an insecure connection 1443 @type secure: Boolean 1444 """ 1445 if hasattr(self.c, 'createClient') and (secure ^ self.c.isSecure()): 1446 oldC = self.c 1447 self.c = oldC.createClient(secure=secure) 1448 oldC.__del__() # only needs to be called if previous doesn't throw 1449 self.c = self.c.createClient(secure=secure) 1450 self._createProxies() 1451 self.secure = secure
1452
1453 - def isSecure (self):
1454 """ Returns 'True' if the underlying omero.clients.BaseClient is connected using SSL """ 1455 return hasattr(self.c, 'isSecure') and self.c.isSecure() or False
1456
1457 - def _getSessionId (self):
1458 return self.c.getSessionId()
1459
1460 - def _createSession (self):
1461 """ 1462 Creates a new session for the principal given in the constructor. 1463 Used during L{connect} method 1464 """ 1465 s = self.c.createSession(self._ic_props[omero.constants.USERNAME], 1466 self._ic_props[omero.constants.PASSWORD]) 1467 self._sessionUuid = self._getSessionId() 1468 ss = self.c.sf.getSessionService() 1469 self._session = ss.getSession(self._sessionUuid) 1470 self._lastGroupId = None 1471 s.detachOnDestroy() 1472 self._was_join = False 1473 if self.group is not None: 1474 # try something that fails if the user don't have permissions on the group 1475 self.c.sf.getAdminService().getEventContext() 1476 self.setSecure(self.secure)
1477
1478 - def _closeSession (self):
1479 """ 1480 Close session. 1481 """ 1482 self._session_cb and self._session_cb.close(self) 1483 try: 1484 self.c.killSession() 1485 except Glacier2.SessionNotExistException: #pragma: no cover 1486 pass 1487 except: 1488 logger.warn(traceback.format_exc())
1489
1490 - def _resetOmeroClient (self):
1491 """ 1492 Creates new omero.client object using self.host or self.ice_config (if host is None) 1493 Also tries to setAgent for the client 1494 """ 1495 if self.host is not None: 1496 if self.port is not None: 1497 self.c = omero.client(host=str(self.host), port=int(self.port))#, pmap=['--Ice.Config='+','.join(self.ice_config)]) 1498 else: 1499 self.c = omero.client(host=str(self.host)) 1500 else: 1501 self.c = omero.client(pmap=['--Ice.Config='+','.join(self.ice_config)]) 1502 1503 if hasattr(self.c, "setAgent"): 1504 if self.useragent is not None: 1505 self.c.setAgent(self.useragent) 1506 else: 1507 self.c.setAgent("OMERO.py.gateway")
1508
1509 - def connect (self, sUuid=None):
1510 """ 1511 Creates or retrieves connection for the given sessionUuid. 1512 Returns True if connected. 1513 1514 @param sUuid: omero_model_SessionI 1515 @return: Boolean 1516 """ 1517 1518 logger.debug("Connect attempt, sUuid=%s, group=%s, self.sUuid=%s" % (str(sUuid), str(self.group), self._sessionUuid)) 1519 if not self.c: #pragma: no cover 1520 self._connected = False 1521 logger.debug("Ooops. no self._c") 1522 return False 1523 try: 1524 if self._sessionUuid is None and sUuid: 1525 self._sessionUuid = sUuid 1526 if self._sessionUuid is not None: 1527 try: 1528 logger.debug('connected? %s' % str(self._connected)) 1529 if self._connected: 1530 self._connected = False 1531 logger.debug("was connected, creating new omero.client") 1532 self._resetOmeroClient() 1533 s = self.c.joinSession(self._sessionUuid) # timeout to allow this is $ omero config set omero.sessions.timeout 3600000 1534 s.detachOnDestroy() 1535 logger.debug('Joined Session OK with Uuid: %s and timeToIdle: %s, timeToLive: %s' % (self._sessionUuid, self.getSession().timeToIdle.val, self.getSession().timeToLive.val)) 1536 self._was_join = True 1537 except Ice.SyscallException: #pragma: no cover 1538 raise 1539 except Exception, x: #pragma: no cover 1540 logger.debug("Error: " + str(x)) 1541 self._sessionUuid = None 1542 if sUuid: 1543 return False 1544 if self._sessionUuid is None: 1545 if sUuid: #pragma: no cover 1546 logger.debug("Uncaptured sUuid failure!") 1547 if self._connected: 1548 self._connected = False 1549 try: 1550 logger.debug("Closing previous connection...creating new client") 1551 #args = self.c._ic_args 1552 #logger.debug(str(args)) 1553 self._closeSession() 1554 self._resetOmeroClient() 1555 #self.c = omero.client(*args) 1556 except Glacier2.SessionNotExistException: #pragma: no cover 1557 pass 1558 setprop = self.c.ic.getProperties().setProperty 1559 map(lambda x: setprop(x[0],str(x[1])), self._ic_props.items()) 1560 if self._anonymous: 1561 self.c.ic.getImplicitContext().put(omero.constants.EVENT, 'Internal') 1562 if self.group is not None: 1563 self.c.ic.getImplicitContext().put(omero.constants.GROUP, self.group) 1564 try: 1565 logger.debug("Creating Session...") 1566 self._createSession() 1567 logger.debug("Session created with timeout: %s & timeToLive: %s" % (self.getSession().timeToIdle.val, self.getSession().timeToLive.val)) 1568 except omero.SecurityViolation: 1569 if self.group is not None: 1570 # User don't have access to group 1571 logger.debug("## User not in '%s' group" % self.group) 1572 self.group = None 1573 self._closeSession() 1574 self._sessionUuid = None 1575 self._connected=True 1576 return self.connect() 1577 else: #pragma: no cover 1578 logger.debug("BlitzGateway.connect().createSession(): " + traceback.format_exc()) 1579 logger.info('first create session threw SecurityViolation, retry (but only once)') 1580 #time.sleep(10) 1581 try: 1582 self._createSession() 1583 except omero.SecurityViolation: 1584 if self.group is not None: 1585 # User don't have access to group 1586 logger.debug("## User not in '%s' group" % self.group) 1587 self.group = None 1588 self._connected=True 1589 return self.connect() 1590 else: 1591 raise 1592 except Ice.SyscallException: #pragma: no cover 1593 raise 1594 except: 1595 logger.info("BlitzGateway.connect().createSession(): " + traceback.format_exc()) 1596 #time.sleep(10) 1597 self._createSession() 1598 1599 self._last_error = None 1600 self._createProxies() 1601 self._connected = True 1602 logger.info('created connection (uuid=%s)' % str(self._sessionUuid)) 1603 except Ice.SyscallException: #pragma: no cover 1604 logger.debug('This one is a SyscallException') 1605 raise 1606 except Ice.LocalException, x: #pragma: no cover 1607 logger.debug("connect(): " + traceback.format_exc()) 1608 self._last_error = x 1609 return False 1610 except Exception, x: #pragma: no cover 1611 logger.debug("connect(): " + traceback.format_exc()) 1612 self._last_error = x 1613 return False 1614 logger.debug(".. connected!") 1615 return True
1616
1617 - def getLastError (self): #pragma: no cover
1618 """ 1619 Returns error if thrown by _BlitzGateway.connect connect. 1620 1621 @return: String 1622 """ 1623 1624 return self._last_error 1625
1626 - def isConnected (self):
1627 """ 1628 Returns last status of connection. 1629 1630 @return: Boolean 1631 """ 1632 1633 return self._connected
1634 1635 ###################### 1636 ## Connection Stuff ## 1637
1638 - def getEventContext (self):
1639 """ 1640 Returns omero_System_ice.EventContext. 1641 It containes:: 1642 shareId, sessionId, sessionUuid, userId, userName, 1643 groupId, groupName, isAdmin, isReadOnly, 1644 eventId, eventType, eventType, 1645 memberOfGroups, leaderOfGroups 1646 Also saves context to self._ctx 1647 1648 @return: Event Context from admin service. 1649 @rtype: L{omero.sys.EventContext} 1650 """ 1651 if self._ctx is None: 1652 self._ctx = self._proxies['admin'].getEventContext() 1653 return self._ctx
1654
1655 - def getUser (self):
1656 """ 1657 Returns current Experimenter. 1658 1659 @return: Current Experimenter 1660 @rtype: L{ExperimenterWrapper} 1661 """ 1662 1663 return self._user
1664
1665 - def getGroupFromContext(self):
1666 """ 1667 Returns current omero_model_ExperimenterGroupI. 1668 1669 @return: omero.model.ExperimenterGroupI 1670 """ 1671 admin_service = self.getAdminService() 1672 group = admin_service.getGroup(self.getEventContext().groupId) 1673 return ExperimenterGroupWrapper(self, group)
1674
1675 - def isAdmin (self):
1676 """ 1677 Checks if a user has administration privileges. 1678 1679 @return: Boolean 1680 """ 1681 1682 return self.getEventContext().isAdmin
1683
1684 - def canBeAdmin (self):
1685 """ 1686 Checks if a user is in system group, i.e. can have administration privileges. 1687 1688 @return: Boolean 1689 """ 1690 return 0 in self.getEventContext().memberOfGroups
1691
1692 - def isOwner (self, gid=None):
1693 """ 1694 Checks if a user has owner privileges of a particular group 1695 or any group if gid is not specified. 1696 1697 @param gid: ID of group to check for ownership 1698 @type gid: Long 1699 @return: True if gid specified and owner belongs to that group 1700 Otherwise True if owner belongs to any group 1701 """ 1702 if gid is not None: 1703 if not isinstance(gid, LongType) or not isinstance(gid, IntType): 1704 gid = long(gid) 1705 for gem in self._user.copyGroupExperimenterMap(): 1706 if gem.parent.id.val == gid and gem.owner.val == True: 1707 return True 1708 else: 1709 for gem in self._user.copyGroupExperimenterMap(): 1710 if gem.owner.val == True: 1711 return True 1712 return False
1713
1714 - def canWrite (self, obj):
1715 """ 1716 Checks if a user has write privileges to the given object. 1717 1718 @param obj: Given object 1719 @return: Boolean 1720 """ 1721 1722 return self.isAdmin() or (self._userid == obj.details.owner.id.val and obj.details.permissions.isUserWrite())
1723
1724 - def getSession (self):
1725 """ 1726 Returns the existing session, or creates a new one if needed 1727 1728 @return: The session from session service 1729 @rtype: L{omero.model.session} 1730 """ 1731 if self._session is None: 1732 ss = self.c.sf.getSessionService() 1733 self._session = ss.getSession(self._sessionUuid) 1734 return self._session
1735 1736 # def setDefaultPermissionsForSession (self, permissions): 1737 # self.getSession() 1738 # self._session.setDefaultPermissions(rstring(permissions)) 1739 # self._session.setTimeToIdle(None) 1740 # self.getSessionService().updateSession(self._session) 1741
1742 - def setGroupNameForSession (self, group):
1743 """ 1744 Looks up the group by name, then delegates to L{setGroupForSession}, returning the result 1745 1746 @param group: Group name 1747 @type group: String 1748 @return: True if group set successfully 1749 @rtype: Boolean 1750 """ 1751 a = self.getAdminService() 1752 g = a.lookupGroup(group) 1753 return self.setGroupForSession(g.getId().val)
1754
1755 - def setGroupForSession (self, groupid):
1756 """ 1757 Sets the security context of this connection to the specified group 1758 1759 @param groupid: The ID of the group to switch to 1760 @type groupid: Long 1761 @rtype: Boolean 1762 @return: True if the group was switched successfully 1763 """ 1764 if self.getEventContext().groupId == groupid: 1765 return True 1766 if groupid not in self._ctx.memberOfGroups: 1767 return False 1768 self._lastGroupId = self._ctx.groupId 1769 if hasattr(self.c.sf, 'setSecurityContext'): 1770 # Beta4.2 1771 self.c.sf.setSecurityContext(omero.model.ExperimenterGroupI(groupid, False)) 1772 else: 1773 self.getSession() 1774 self._session.getDetails().setGroup(omero.model.ExperimenterGroupI(groupid, False)) 1775 self._session.setTimeToIdle(None) 1776 self.getSessionService().updateSession(self._session) 1777 return True
1778 1779 1780 # def setGroupForSession (self, group): 1781 # self.getSession() 1782 # if self._session.getDetails().getGroup().getId().val == group.getId(): 1783 # # Already correct 1784 # return 1785 # a = self.getAdminService() 1786 # if not group.name in [x.name.val for x in a.containedGroups(self._userid)]: 1787 # # User not in this group 1788 # return 1789 # self._lastGroup = self._session.getDetails().getGroup() 1790 # self._session.getDetails().setGroup(group._obj) 1791 # self._session.setTimeToIdle(None) 1792 # self.getSessionService().updateSession(self._session) 1793 #
1794 - def revertGroupForSession (self):
1795 """ Switches the group to the previous group """ 1796 if self._lastGroupId is not None: 1797 self.setGroupForSession(self._lastGroupId) 1798 self._lastGroupId = None
1799 1800 ############## 1801 ## Services ## 1802
1803 - def getAdminService (self):
1804 """ 1805 Gets reference to the admin service from ProxyObjectWrapper. 1806 1807 @return: omero.gateway.ProxyObjectWrapper 1808 """ 1809 1810 return self._proxies['admin']
1811
1812 - def getQueryService (self):
1813 """ 1814 Gets reference to the query service from ProxyObjectWrapper. 1815 1816 @return: omero.gateway.ProxyObjectWrapper 1817 """ 1818 return self._proxies['query']
1819
1820 - def getContainerService (self):
1821 """ 1822 Gets reference to the container service from ProxyObjectWrapper. 1823 1824 @return: omero.gateway.ProxyObjectWrapper 1825 """ 1826 1827 return self._proxies['container']
1828
1829 - def getPixelsService (self):
1830 """ 1831 Gets reference to the pixels service from ProxyObjectWrapper. 1832 1833 @return: omero.gateway.ProxyObjectWrapper 1834 """ 1835 1836 return self._proxies['pixel']
1837
1838 - def getMetadataService (self):
1839 """ 1840 Gets reference to the metadata service from ProxyObjectWrapper. 1841 1842 @return: omero.gateway.ProxyObjectWrapper 1843 """ 1844 1845 return self._proxies['metadata']
1846
1847 - def getRoiService (self):
1848 """ 1849 Gets ROI service. 1850 1851 @return: omero.gateway.ProxyObjectWrapper 1852 """ 1853 1854 return self._proxies['roi']
1855
1856 - def getScriptService (self):
1857 """ 1858 Gets script service. 1859 1860 @return: omero.gateway.ProxyObjectWrapper 1861 """ 1862 1863 return self._proxies['script']
1864
1865 - def createRawFileStore (self):
1866 """ 1867 Creates a new raw file store. 1868 This service is special in that it does not get cached inside BlitzGateway so every call to this function 1869 returns a new object, avoiding unexpected inherited states. 1870 1871 @return: omero.gateway.ProxyObjectWrapper 1872 """ 1873 1874 return self._proxies['rawfile']
1875
1876 - def getRepositoryInfoService (self):
1877 """ 1878 Gets reference to the repository info service from ProxyObjectWrapper. 1879 1880 @return: omero.gateway.ProxyObjectWrapper 1881 """ 1882 1883 return self._proxies['repository']
1884
1885 - def getShareService(self):
1886 """ 1887 Gets reference to the share service from ProxyObjectWrapper. 1888 1889 @return: omero.gateway.ProxyObjectWrapper 1890 """ 1891 1892 return self._proxies['share']
1893
1894 - def getSharedResources(self):
1895 """ 1896 Gets reference to the sharedresources from ProxyObjectWrapper. 1897 1898 @return: omero.gateway.ProxyObjectWrapper 1899 """ 1900 1901 return self._proxies['sharedres']
1902
1903 - def getTimelineService (self):
1904 """ 1905 Gets reference to the timeline service from ProxyObjectWrapper. 1906 1907 @return: omero.gateway.ProxyObjectWrapper 1908 """ 1909 1910 return self._proxies['timeline']
1911
1912 - def getTypesService(self):
1913 """ 1914 Gets reference to the types service from ProxyObjectWrapper. 1915 1916 @return: omero.gateway.ProxyObjectWrapper 1917 """ 1918 1919 return self._proxies['types']
1920
1921 - def getConfigService (self):
1922 """ 1923 Gets reference to the config service from ProxyObjectWrapper. 1924 1925 @return: omero.gateway.ProxyObjectWrapper 1926 """ 1927 1928 return self._proxies['config']
1929
1930 - def createRenderingEngine (self):
1931 """ 1932 Creates a new rendering engine. 1933 This service is special in that it does not get cached inside BlitzGateway so every call to this function 1934 returns a new object, avoiding unexpected inherited states. 1935 1936 @return: omero.gateway.ProxyObjectWrapper 1937 """ 1938 1939 rv = self._proxies['rendering'] 1940 if rv._tainted: 1941 rv = self._proxies['rendering'] = rv.clone() 1942 rv.taint() 1943 return rv
1944
1945 - def getRenderingSettingsService (self):
1946 """ 1947 Gets reference to the rendering settings service from ProxyObjectWrapper. 1948 1949 @return: omero.gateway.ProxyObjectWrapper 1950 """ 1951 1952 return self._proxies['rendsettings']
1953
1954 - def createRawPixelsStore (self):
1955 """ 1956 Creates a new raw pixels store. 1957 This service is special in that it does not get cached inside BlitzGateway so every call to this function 1958 returns a new object, avoiding unexpected inherited states. 1959 1960 @return: omero.gateway.ProxyObjectWrapper 1961 """ 1962 1963 return self._proxies['rawpixels']
1964
1965 - def createThumbnailStore (self):
1966 """ 1967 Gets a reference to the thumbnail store on this connection object or creates a new one 1968 if none exists. 1969 1970 @rtype: omero.gateway.ProxyObjectWrapper 1971 @return: The proxy wrapper of the thumbnail store 1972 """ 1973 1974 return self._proxies['thumbs']
1975
1976 - def createSearchService (self):
1977 """ 1978 Gets a reference to the searching service on this connection object or creates a new one 1979 if none exists. 1980 1981 @return: omero.gateway.ProxyObjectWrapper 1982 """ 1983 return self._proxies['search']
1984
1985 - def getUpdateService (self):
1986 """ 1987 Gets reference to the update service from ProxyObjectWrapper. 1988 1989 @return: omero.gateway.ProxyObjectWrapper 1990 """ 1991 return self._proxies['update']
1992
1993 - def getDeleteService (self):
1994 """ 1995 Gets reference to the delete service from ProxyObjectWrapper. 1996 1997 @return: omero.gateway.ProxyObjectWrapper 1998 """ 1999 return self._proxies['delete']
2000
2001 - def getSessionService (self):
2002 """ 2003 Gets reference to the session service from ProxyObjectWrapper. 2004 2005 @return: omero.gateway.ProxyObjectWrapper 2006 """ 2007 return self._proxies['session']
2008
2009 - def createExporter (self):
2010 """ 2011 New instance of non cached Exporter, wrapped in ProxyObjectWrapper. 2012 2013 @return: omero.gateway.ProxyObjectWrapper 2014 """ 2015 2016 return self._proxies['export']
2017 2018 ############################# 2019 # Top level object fetchers # 2020
2021 - def listProjects (self, eid=None, only_owned=False):
2022 """ 2023 List every Project controlled by the security system. 2024 2025 @param eid: Filters Projects by owner ID 2026 @param only_owned: Short-cut for filtering Projects by current user 2027 @rtype: L{ProjectWrapper} list 2028 """ 2029 2030 params = omero.sys.Parameters() 2031 params.theFilter = omero.sys.Filter() 2032 if only_owned: 2033 params.theFilter.ownerId = rlong(self._userid) 2034 elif eid is not None: 2035 params.theFilter.ownerId = rlong(eid) 2036 2037 return self.getObjects("Project", params=params)
2038
2039 - def listScreens(self, eid=None, only_owned=False):
2040 """ 2041 List every Screens controlled by the security system. 2042 2043 @param eid: Filters Screens by owner ID 2044 @param only_owned: Short-cut for filtering Screens by current user 2045 @rtype: L{ProjectWrapper} list 2046 """ 2047 2048 params = omero.sys.Parameters() 2049 params.theFilter = omero.sys.Filter() 2050 if only_owned: 2051 params.theFilter.ownerId = rlong(self._userid) 2052 elif eid is not None: 2053 params.theFilter.ownerId = rlong(eid) 2054 2055 return self.getObjects("Screen", params=params)
2056 2057 ################################################# 2058 ## IAdmin 2059 2060 # GROUPS 2061
2062 - def listGroups(self):
2063 """ 2064 Look up all experimenters and related groups. 2065 Groups are also loaded 2066 2067 @return: All experimenters 2068 @rtype: L{ExperimenterWrapper} generator 2069 """ 2070 2071 admin_serv = self.getAdminService() 2072 for exp in admin_serv.lookupGroups(): 2073 yield ExperimenterGroupWrapper(self, exp)
2074
2075 - def getDefaultGroup(self, eid):
2076 """ 2077 Retrieve the default group for the given user id. 2078 2079 @param eid: Experimenter ID 2080 @type eid: Long 2081 @return: The default group for user 2082 @rtype: L{ExperimenterGroupWrapper} 2083 """ 2084 2085 admin_serv = self.getAdminService() 2086 dgr = admin_serv.getDefaultGroup(long(eid)) 2087 return ExperimenterGroupWrapper(self, dgr)
2088
2089 - def getOtherGroups(self, eid):
2090 """ 2091 Fetch all groups of which the given user is a member. 2092 The returned groups will have all fields filled in and all collections unloaded. 2093 2094 @param eid: Experimenter ID 2095 @type eid: Long 2096 @return: Generator of groups for user 2097 @rtype: L{ExperimenterGroupWrapper} generator 2098 """ 2099 2100 admin_serv = self.getAdminService() 2101 for gr in admin_serv.containedGroups(long(eid)): 2102 yield ExperimenterGroupWrapper(self, gr)
2103
2104 - def getGroupsLeaderOf(self):
2105 """ 2106 Look up Groups where current user is a leader of. 2107 2108 @return: Groups that current user leads 2109 @rtype: L{ExperimenterGroupWrapper} generator 2110 """ 2111 2112 q = self.getQueryService() 2113 p = omero.sys.Parameters() 2114 p.map = {} 2115 p.map["ids"] = rlist([rlong(a) for a in self.getEventContext().leaderOfGroups]) 2116 sql = "select e from ExperimenterGroup as e where e.id in (:ids)" 2117 for e in q.findAllByQuery(sql, p): 2118 yield ExperimenterGroupWrapper(self, e)
2119
2120 - def getGroupsMemberOf(self):
2121 """ 2122 Look up Groups where current user is a member of (except "user" group). 2123 2124 @return: Current users groups 2125 @rtype: L{ExperimenterGroupWrapper} generator 2126 """ 2127 2128 q = self.getQueryService() 2129 p = omero.sys.Parameters() 2130 p.map = {} 2131 p.map["ids"] = rlist([rlong(a) for a in self.getEventContext().memberOfGroups]) 2132 sql = "select e from ExperimenterGroup as e where e.id in (:ids)" 2133 for e in q.findAllByQuery(sql, p): 2134 if e.name.val == "user": 2135 pass 2136 else: 2137 yield ExperimenterGroupWrapper(self, e)
2138 2139 # EXPERIMENTERS 2140
2141 - def findExperimenters (self, start=''):
2142 """ 2143 Return a generator for all Experimenters whose omeName starts with 'start'. 2144 Experimenters ordered by omeName. 2145 2146 @param start: omeName must start with these letters 2147 @type start: String 2148 @return: Generator of experimenters 2149 @rtype: L{ExperimenterWrapper} generator 2150 """ 2151 2152 if isinstance(start, UnicodeType): 2153 start = start.encode('utf8') 2154 params = omero.sys.Parameters() 2155 params.map = {'start': rstring('%s%%' % start.lower())} 2156 q = self.getQueryService() 2157 rv = q.findAllByQuery("from Experimenter e where lower(e.omeName) like :start", params) 2158 rv.sort(lambda x,y: cmp(x.omeName.val,y.omeName.val)) 2159 for e in rv: 2160 yield ExperimenterWrapper(self, e)
2161
2162 - def containedExperimenters(self, gid):
2163 """ 2164 Fetch all users contained in this group. 2165 The returned users will have all fields filled in and all collections unloaded. 2166 2167 @param gid: Group ID 2168 @type gid: Long 2169 @return: Generator of experimenters 2170 @rtype: L{ExperimenterWrapper} generator 2171 """ 2172 2173 admin_serv = self.getAdminService() 2174 for exp in admin_serv.containedExperimenters(long(gid)): 2175 yield ExperimenterWrapper(self, exp)
2176
2177 - def listColleagues(self):
2178 """ 2179 Look up users who are a member of the current user active group. 2180 Returns None if the group is private and isn't lead by the current user 2181 2182 @return: Generator of Experimenters or None 2183 @rtype: L{ExperimenterWrapper} generator 2184 """ 2185 2186 default = self.getObject("ExperimenterGroup", self.getEventContext().groupId) 2187 if not default.isPrivate() or default.isLeader(): 2188 for d in default.copyGroupExperimenterMap(): 2189 if d.child.id.val != self.getEventContext().userId: 2190 yield ExperimenterWrapper(self, d.child)
2191
2192 - def listStaffs(self):
2193 """ 2194 Look up users who are members of groups lead by the current user. 2195 2196 @return: Members of groups lead by current user 2197 @rtype: L{ExperimenterWrapper} generator 2198 """ 2199 2200 q = self.getQueryService() 2201 p = omero.sys.Parameters() 2202 p.map = {} 2203 p.map["gids"] = rlist([rlong(a) for a in set(self.getEventContext().leaderOfGroups)]) 2204 sql = "select e from Experimenter as e where " \ 2205 "exists ( select gem from GroupExperimenterMap as gem where gem.child = e.id " \ 2206 "and gem.parent.id in (:gids)) order by e.omeName" 2207 for e in q.findAllByQuery(sql, p): 2208 if e.id.val != self.getEventContext().userId: 2209 yield ExperimenterWrapper(self, e)
2210
2211 - def listOwnedGroups(self):
2212 """ 2213 Looks up owned groups for the logged user. 2214 2215 @return: Groups owned by current user 2216 @rtype: L{ExperimenterGroupWrapper} generator 2217 """ 2218 2219 exp = self.getUser() 2220 for gem in exp.copyGroupExperimenterMap(): 2221 if gem.owner.val: 2222 yield ExperimenterGroupWrapper(self, gem.parent)
2223
2224 - def getFreeSpace(self):
2225 """ 2226 Returns the free or available space on this file system 2227 including nested subdirectories. 2228 2229 @return: Free space in bytes 2230 @rtype: Int 2231 """ 2232 2233 rep_serv = self.getRepositoryInfoService() 2234 return rep_serv.getFreeSpaceInKilobytes() * 1024
2235 2236 ############################ 2237 # Timeline service getters # 2238
2239 - def timelineListImages (self, tfrom=None, tto=None, limit=10, only_owned=True):
2240 """ 2241 List images based on their creation times. 2242 If both tfrom and tto are None, grab the most recent batch. 2243 2244 @param tfrom: milliseconds since the epoch for start date 2245 @param tto: milliseconds since the epoch for end date 2246 @param limit: maximum number of results 2247 @param only_owned: Only owned by the logged user. Boolean. 2248 @return: Generator yielding _ImageWrapper 2249 @rtype: L{ImageWrapper} generator 2250 """ 2251 2252 tm = self.getTimelineService() 2253 p = omero.sys.Parameters() 2254 f = omero.sys.Filter() 2255 if only_owned: 2256 f.ownerId = rlong(self.getEventContext().userId) 2257 f.groupId = rlong(self.getEventContext().groupId) 2258 else: 2259 f.ownerId = rlong(-1) 2260 f.groupId = None 2261 f.limit = rint(limit) 2262 p.theFilter = f 2263 if tfrom is None and tto is None: 2264 for e in tm.getMostRecentObjects(['Image'], p, False)["Image"]: 2265 yield ImageWrapper(self, e) 2266 else: 2267 if tfrom is None: 2268 tfrom = 0 2269 if tto is None: 2270 tto = time.time() * 1000 2271 for e in tm.getByPeriod(['Image'], rtime(long(tfrom)), rtime(long(tto)), p, False)['Image']: 2272 yield ImageWrapper(self, e)
2273 2274 2275 ########################### 2276 # Specific Object Getters # 2277
2278 - def getObject (self, obj_type, oid=None, params=None, attributes=None):
2279 """ 2280 Retrieve single Object by type E.g. "Image" or None if not found. 2281 If more than one object found, raises ome.conditions.ApiUsageException 2282 See L{getObjects} for more info. 2283 2284 @param obj_type: Object type. E.g. "Project" see above 2285 @type obj_type: String 2286 @param ids: object IDs 2287 @type ids: List of Long 2288 @param params: omero.sys.Parameters, can be used for pagination, filtering etc. 2289 @param attributes: Map of key-value pairs to filter results by. Key must be attribute of obj_type. E.g. 'name', 'ns' 2290 @return: 2291 """ 2292 oids = (oid!=None) and [oid] or None 2293 query, params, wrapper = self.buildQuery(obj_type, oids, params, attributes) 2294 result = self.getQueryService().findByQuery(query, params) 2295 if result is not None: 2296 return wrapper(self, result)
2297
2298 - def getObjects (self, obj_type, ids=None, params=None, attributes=None):
2299 """ 2300 Retrieve Objects by type E.g. "Image" 2301 Returns generator of appropriate L{BlitzObjectWrapper} type. E.g. L{ImageWrapper}. 2302 If ids is None, all available objects will be returned. i.e. listObjects() 2303 Filter objects by attributes. E.g. attributes={'name':name} 2304 2305 @param obj_type: Object type. E.g. "Project" see above 2306 @type obj_type: String 2307 @param ids: object IDs 2308 @type ids: List of Long 2309 @param params: omero.sys.Parameters, can be used for pagination, filtering etc. 2310 @param attributes: Map of key-value pairs to filter results by. Key must be attribute of obj_type. E.g. 'name', 'ns' 2311 @return: Generator of L{BlitzObjectWrapper} subclasses 2312 """ 2313 query, params, wrapper = self.buildQuery(obj_type, ids, params, attributes) 2314 result = self.getQueryService().findAllByQuery(query, params) 2315 for r in result: 2316 yield wrapper(self, r)
2317
2318 - def buildQuery (self, obj_type, ids=None, params=None, attributes=None):
2319 """ 2320 Prepares a query for iQuery. Also prepares params and determines appropriate wrapper for result 2321 Returns (query, params, wrapper) which can be used with the appropriate query method. 2322 Used by L{getObjects} and L{getObject} above. 2323 2324 @param obj_type: Object type. E.g. "Project" see above 2325 @type obj_type: String 2326 @param ids: object IDs 2327 @type ids: List of Long 2328 @param params: omero.sys.Parameters, can be used for pagination, filtering etc. 2329 @param attributes: Map of key-value pairs to filter results by. Key must be attribute of obj_type. E.g. 'name', 'ns' 2330 @return: (query, params, wrapper) 2331 """ 2332 2333 if type(obj_type) is type(''): 2334 wrapper = KNOWN_WRAPPERS.get(obj_type.lower(), None) 2335 if wrapper is None: 2336 raise KeyError("obj_type of %s not supported by getOjbects(). E.g. use 'Image' etc" % obj_type) 2337 else: 2338 raise AttributeError("getObjects uses a string to define obj_type, E.g. 'Image'") 2339 2340 q = self.getQueryService() 2341 if params is None: 2342 params = omero.sys.Parameters() 2343 if params.map is None: 2344 params.map = {} 2345 2346 # get the base query from the instantiated object itself. E.g "select obj Project as obj" 2347 query = wrapper()._getQueryString() 2348 2349 clauses = [] 2350 # getting object by ids 2351 if ids != None: 2352 clauses.append("obj.id in (:ids)") 2353 params.map["ids"] = rlist([rlong(a) for a in ids]) 2354 2355 # support filtering by owner (not for some object types) 2356 if params.theFilter and params.theFilter.ownerId and obj_type.lower() not in ["experimentergroup", "experimenter"]: 2357 clauses.append("owner.id = (:eid)") 2358 params.map["eid"] = params.theFilter.ownerId 2359 2360 # finding by attributes 2361 if attributes != None: 2362 for k,v in attributes.items(): 2363 clauses.append('obj.%s=:%s' % (k, k) ) 2364 params.map[k] = omero_type(v) 2365 2366 if clauses: 2367 query += " where " + (" and ".join(clauses)) 2368 2369 return (query, params, wrapper)
2370 2371
2372 - def listFileAnnotations (self, eid=None, toInclude=[], toExclude=[]):
2373 """ 2374 Lists FileAnnotations created by users, filtering by namespaces if specified. 2375 If NO namespaces are specified, then 'known' namespaces are excluded by default, 2376 such as original files and companion files etc. 2377 File objects are loaded so E.g. file name is available without lazy loading. 2378 2379 @param eid: Filter results by this owner Id 2380 @param toInclude: Only return annotations with these namespaces. List of strings. 2381 @param toExclude: Don't return annotations with these namespaces. List of strings. 2382 @return: Generator of L{FileAnnotationWrapper}s - with files loaded. 2383 """ 2384 2385 params = omero.sys.Parameters() 2386 params.theFilter = omero.sys.Filter() 2387 if eid is not None: 2388 params.theFilter.ownerId = rlong(eid) 2389 2390 if len(toInclude) == 0 and len(toExclude) == 0: 2391 toExclude.append(omero.constants.namespaces.NSCOMPANIONFILE) 2392 toExclude.append(omero.constants.annotation.file.ORIGINALMETADATA) 2393 toExclude.append(omero.constants.namespaces.NSEXPERIMENTERPHOTO) 2394 toExclude.append(omero.constants.analysis.flim.NSFLIM) 2395 2396 anns = self.getMetadataService().loadSpecifiedAnnotations("FileAnnotation", toInclude, toExclude, params) 2397 2398 for a in anns: 2399 yield(FileAnnotationWrapper(self, a))
2400 2401 2453 2454
2455 - def createImageFromNumpySeq (self, zctPlanes, imageName, sizeZ=1, sizeC=1, sizeT=1, description=None, dataset=None):
2456 """ 2457 Creates a new multi-dimensional image from the sequence of 2D numpy arrays in zctPlanes. 2458 zctPlanes should be a generator of numpy 2D arrays of shape (sizeY, sizeX) ordered 2459 to iterate through T first, then C then Z. 2460 Example usage: 2461 original = conn.getObject("Image", 1) 2462 sizeZ = original.getSizeZ() 2463 sizeC = original.getSizeC() 2464 sizeT = original.getSizeT() 2465 zctList = [] 2466 for z in range(sizeZ): 2467 for c in range(sizeC): 2468 for t in range(sizeT): 2469 zctList.append( (z,c,t) ) 2470 def planeGen(): 2471 planes = original.getPrimaryPixels().getPlanes(zctList) 2472 for p in planes: 2473 # perform some manipulation on each plane 2474 yield p 2475 createImageFromNumpySeq (planeGen(), imageName, sizeZ=sizeZ, sizeC=sizeC, sizeT=sizeT 2476 2477 @param session An OMERO service factory or equivalent with getQueryService() etc. 2478 @param zctPlanes A generator of numpy 2D arrays, corresponding to Z-planes of new image. 2479 @param imageName Name of new image 2480 @param description Description for the new image 2481 @param dataset If specified, put the image in this dataset. omero.model.Dataset object 2482 2483 @return The new OMERO image: omero.model.ImageI 2484 """ 2485 queryService = self.getQueryService() 2486 pixelsService = self.getPixelsService() 2487 rawPixelsStore = self.c.sf.createRawPixelsStore() # Make sure we don't get an existing rpStore 2488 #renderingEngine = self.createRenderingEngine() 2489 containerService = self.getContainerService() 2490 updateService = self.getUpdateService() 2491 2492 def createImage(firstPlane): 2493 """ Create our new Image once we have the first plane in hand """ 2494 # need to map numpy pixel types to omero - don't handle: bool_, character, int_, int64, object_ 2495 pTypes = {'int8':'int8', 'int16':'int16', 'uint16':'uint16', 'int32':'int32', 'float_':'float', 'float8':'float', 2496 'float16':'float', 'float32':'float', 'float64':'double', 'complex_':'complex', 'complex64':'complex'} 2497 dType = firstPlane.dtype.name 2498 if dType not in pTypes: # try to look up any not named above 2499 pType = dType 2500 else: 2501 pType = pTypes[dType] 2502 pixelsType = queryService.findByQuery("from PixelsType as p where p.value='%s'" % pType, None) # omero::model::PixelsType 2503 if pixelsType is None: 2504 raise Exception("Cannot create an image in omero from numpy array with dtype: %s" % dType) 2505 sizeY, sizeX = firstPlane.shape 2506 channelList = range(1, sizeC+1) 2507 iId = pixelsService.createImage(sizeX, sizeY, sizeZ, sizeT, channelList, pixelsType, imageName, description) 2508 imageId = iId.getValue() 2509 return containerService.getImages("Image", [imageId], None)[0]
2510 2511 def uploadPlane(plane, z, c, t): 2512 byteSwappedPlane = plane.byteswap(); 2513 convertedPlane = byteSwappedPlane.tostring(); 2514 rawPixelsStore.setPlane(convertedPlane, z, c, t) 2515 2516 image = None 2517 channelsMinMax = [] 2518 exc = None 2519 try: 2520 for theZ in range(sizeZ): 2521 for theC in range(sizeC): 2522 for theT in range(sizeT): 2523 plane = zctPlanes.next() 2524 if image == None: # use the first plane to create image. 2525 image = createImage(plane) 2526 pixelsId = image.getPrimaryPixels().getId().getValue() 2527 rawPixelsStore.setPixelsId(pixelsId, True) 2528 uploadPlane(plane, theZ, theC, theT) 2529 # init or update min and max for this channel 2530 minValue = plane.min() 2531 maxValue = plane.max() 2532 if len(channelsMinMax) < (theC +1): # first plane of each channel 2533 channelsMinMax.append( [minValue, maxValue] ) 2534 else: 2535 channelsMinMax[theC][0] = min(channelsMinMax[theC][0], minValue) 2536 channelsMinMax[theC][1] = max(channelsMinMax[theC][1], maxValue) 2537 except Exception, e: 2538 logger.error("Failed to setPlane() on rawPixelsStore while creating Image", exc_info=True) 2539 exc = e 2540 try: 2541 rawPixelsStore.close() 2542 except Exception, e: 2543 logger.error("Failed to close rawPixelsStore", exc_info=True) 2544 if exc is None: 2545 exc = e 2546 if exc is not None: 2547 raise exc 2548 2549 try: # simply completing the generator - to avoid a GeneratorExit error. 2550 zctPlanes.next() 2551 except StopIteration: 2552 pass 2553 2554 for theC, mm in enumerate(channelsMinMax): 2555 pixelsService.setChannelGlobalMinMax(pixelsId, theC, float(mm[0]), float(mm[1])) 2556 #resetRenderingSettings(renderingEngine, pixelsId, theC, mm[0], mm[1]) 2557 2558 # put the image in dataset, if specified. 2559 if dataset: 2560 link = omero.model.DatasetImageLinkI() 2561 link.parent = omero.model.DatasetI(dataset.getId(), False) 2562 link.child = omero.model.ImageI(image.id.val, False) 2563 updateService.saveObject(link) 2564 2565 return ImageWrapper(self, image) 2566 2567
2568 - def createFileAnnfromLocalFile (self, localPath, origFilePathAndName=None, mimetype=None, ns=None, desc=None):
2569 """ 2570 Class method to create a L{FileAnnotationWrapper} from a local file. 2571 File is uploaded to create an omero.model.OriginalFileI referenced from this File Annotation. 2572 Returns a new L{FileAnnotationWrapper} 2573 2574 @param conn: Blitz connection 2575 @param localPath: Location to find the local file to upload 2576 @param origFilePathAndName: Provides the 'path' and 'name' of the OriginalFile. If None, use localPath 2577 @param mimetype: The mimetype of the file. String. E.g. 'text/plain' 2578 @return: New L{FileAnnotationWrapper} 2579 """ 2580 updateService = self.getUpdateService() 2581 rawFileStore = self.createRawFileStore() 2582 2583 # create original file, set name, path, mimetype 2584 if origFilePathAndName is None: 2585 origFilePathAndName = localPath 2586 originalFile = omero.model.OriginalFileI() 2587 path, name = os.path.split(origFilePathAndName) 2588 originalFile.setName(rstring(name)) 2589 originalFile.setPath(rstring(path)) 2590 if mimetype: 2591 originalFile.mimetype = rstring(mimetype) 2592 fileSize = os.path.getsize(localPath) 2593 originalFile.setSize(rlong(fileSize)) 2594 # set sha1 2595 try: 2596 import hashlib 2597 hash_sha1 = hashlib.sha1 2598 except: 2599 import sha 2600 hash_sha1 = sha.new 2601 fileHandle = open(localPath) 2602 h = hash_sha1() 2603 h.update(fileHandle.read()) 2604 shaHast = h.hexdigest() 2605 fileHandle.close() 2606 originalFile.setSha1(rstring(shaHast)) 2607 originalFile = updateService.saveAndReturnObject(originalFile) 2608 2609 # upload file 2610 rawFileStore.setFileId(originalFile.getId().getValue()) 2611 fileHandle = open(localPath, 'rb') 2612 buf = 10000 2613 for pos in range(0,long(fileSize),buf): 2614 block = None 2615 if fileSize-pos < buf: 2616 blockSize = fileSize-pos 2617 else: 2618 blockSize = buf 2619 fileHandle.seek(pos) 2620 block = fileHandle.read(blockSize) 2621 rawFileStore.write(block, pos, blockSize) 2622 fileHandle.close() 2623 2624 # create FileAnnotation, set ns & description and return wrapped obj 2625 fa = omero.model.FileAnnotationI() 2626 fa.setFile(originalFile) 2627 if desc: 2628 fa.setDescription(rstring(desc)) 2629 if ns: 2630 fa.setNs(rstring(ns)) 2631 fa = updateService.saveAndReturnObject(fa) 2632 return FileAnnotationWrapper(self, fa)
2633
2634 - def getObjectsByAnnotations(self, obj_type, annids):
2635 """ 2636 Retrieve objects linked to the given annotation IDs 2637 controlled by the security system. 2638 2639 @param annids: Annotation IDs 2640 @type annids: L{Long} 2641 @return: Generator yielding Objects 2642 @rtype: L{BlitzObjectWrapper} generator 2643 """ 2644 2645 wrapper = KNOWN_WRAPPERS.get(obj_type.lower(), None) 2646 if not wrapper: 2647 raise AttributeError("Don't know how to handle '%s'" % obj_type) 2648 2649 sql = "select ob from %s ob " \ 2650 "left outer join fetch ob.annotationLinks obal " \ 2651 "left outer join fetch obal.child ann " \ 2652 "where ann.id in (:oids)" % wrapper().OMERO_CLASS 2653 2654 q = self.getQueryService() 2655 p = omero.sys.Parameters() 2656 p.map = {} 2657 p.map["oids"] = rlist([rlong(o) for o in set(annids)]) 2658 for e in q.findAllByQuery(sql,p): 2659 kwargs = {'link': BlitzObjectWrapper(self, e.copyAnnotationLinks()[0])} 2660 yield wrapper(self, e)
2661 2662 2663 ################ 2664 # Enumerations # 2665
2666 - def getEnumerationEntries(self, klass):
2667 """ 2668 Get all enumerations by class 2669 2670 @param klass: Class 2671 @type klass: Class or string 2672 @return: Generator of Enumerations 2673 @rtype: L{EnumerationWrapper} generator 2674 """ 2675 2676 types = self.getTypesService() 2677 for e in types.allEnumerations(str(klass)): 2678 yield EnumerationWrapper(self, e)
2679
2680 - def getEnumeration(self, klass, string):
2681 """ 2682 Get enumeration by class and value 2683 2684 @param klass: Class 2685 @type klass: Class or string 2686 @param string: Enum value 2687 @type string: String 2688 @return: Enumeration or None 2689 @rtype: L{EnumerationWrapper} 2690 """ 2691 2692 types = self.getTypesService() 2693 obj = types.getEnumeration(str(klass), str(string)) 2694 if obj is not None: 2695 return EnumerationWrapper(self, obj) 2696 else: 2697 return None
2698
2699 - def getEnumerationById(self, klass, eid):
2700 """ 2701 Get enumeration by class and ID 2702 2703 @param klass: Class 2704 @type klass: Class or string 2705 @param eid: Enum ID 2706 @type eid: Long 2707 @return: Enumeration or None 2708 @rtype: L{EnumerationWrapper} 2709 """ 2710 2711 query_serv = self.getQueryService() 2712 obj = query_serv.find(klass, long(eid)) 2713 if obj is not None: 2714 return EnumerationWrapper(self, obj) 2715 else: 2716 return None
2717
2718 - def getOriginalEnumerations(self):
2719 """ 2720 Gets original enumerations. Returns a dictionary of enumeration class: list of Enumerations 2721 2722 @return: Original enums 2723 @rtype: Dict of <string: L{EnumerationWrapper} list > 2724 """ 2725 2726 types = self.getTypesService() 2727 rv = dict() 2728 for e in types.getOriginalEnumerations(): 2729 if rv.get(e.__class__.__name__) is None: 2730 rv[e.__class__.__name__] = list() 2731 rv[e.__class__.__name__].append(EnumerationWrapper(self, e)) 2732 return rv
2733
2734 - def getEnumerations(self):
2735 """ 2736 Gets list of enumeration types 2737 2738 @return: List of enum types 2739 @rtype: List of Strings 2740 """ 2741 2742 types = self.getTypesService() 2743 return types.getEnumerationTypes()
2744
2745 - def getEnumerationsWithEntries(self):
2746 """ 2747 Get enumeration types, with lists of Enum entries 2748 2749 @return: Dictionary of type: entries 2750 @rtype: Dict of <string: L{EnumerationWrapper} list > 2751 """ 2752 2753 types = self.getTypesService() 2754 rv = dict() 2755 for key, value in types.getEnumerationsWithEntries().items(): 2756 r = list() 2757 for e in value: 2758 r.append(EnumerationWrapper(self, e)) 2759 rv[key+"I"] = r 2760 return rv
2761
2762 - def deleteEnumeration(self, obj):
2763 """ 2764 Deletes an enumeration object 2765 2766 @param obj: Enumeration object 2767 @type obj: omero.model.IObject 2768 """ 2769 2770 types = self.getTypesService() 2771 types.deleteEnumeration(obj)
2772
2773 - def createEnumeration(self, obj):
2774 """ 2775 Create an enumeration with given object 2776 2777 @param obj: Object 2778 @type obj: omero.model.IObject 2779 """ 2780 2781 types = self.getTypesService() 2782 types.createEnumeration(obj)
2783
2784 - def resetEnumerations(self, klass):
2785 """ 2786 Resets the enumerations by type 2787 2788 @param klass: Type of enum to reset 2789 @type klass: String 2790 """ 2791 2792 types = self.getTypesService() 2793 types.resetEnumerations(klass)
2794
2795 - def updateEnumerations(self, new_entries):
2796 """ 2797 Updates enumerations with new entries 2798 2799 @param new_entries: List of objects 2800 @type new_entries: List of omero.model.IObject 2801 """ 2802 2803 types = self.getTypesService() 2804 types.updateEnumerations(new_entries)
2805 2806 ################### 2807 # Delete # 2808
2809 - def deleteObjectDirect(self, obj):
2810 """ 2811 Directly Delete object (removes row from database). 2812 This may fail with various constraint violations if the object is linked to others in the database 2813 2814 @param obj: Object to delete 2815 @type obj: IObject""" 2816 2817 u = self.getUpdateService() 2818 u.deleteObject(obj)
2819
2820 - def deleteObjects(self, obj_type, obj_ids, deleteAnns=False, deleteChildren=False):
2821 """ 2822 Generic method for deleting using the delete queue. 2823 Supports deletion of 'Project', 'Dataset', 'Image', 'Screen', 'Plate', 'Well', 'Annotation'. 2824 Options allow to delete 'independent' Annotations (Tag, Term, File) and to delete child objects. 2825 2826 @param obj_type: String to indicate 'Project', 'Image' etc. 2827 @param obj_ids: List of IDs for the objects to delete 2828 @param deleteAnns: If true, delete linked Tag, Term and File annotations 2829 @param deleteChildren: If true, delete children. E.g. Delete Project AND it's Datasets & Images. 2830 @return: Delete handle 2831 @rtype: L{omero.api.delete.DeleteHandle} 2832 """ 2833 2834 if not isinstance(obj_ids, list) and len(obj_ids) < 1: 2835 raise AttributeError('Must be a list of object IDs') 2836 2837 op = dict() 2838 if not deleteAnns and obj_type not in ["Annotation", "TagAnnotation"]: 2839 op["/TagAnnotation"] = "KEEP" 2840 op["/TermAnnotation"] = "KEEP" 2841 op["/FileAnnotation"] = "KEEP" 2842 2843 childTypes = {'Project':['/Dataset', '/Image'], 2844 'Dataset':['/Image'], 2845 'Image':[], 2846 'Screen':['/Plate'], 2847 'Plate':['/Image'], 2848 'Well':[], 2849 'Annotation':[] } 2850 2851 obj_type = obj_type.title() 2852 if obj_type not in childTypes: 2853 m = """%s is not an object type. Must be: Project, Dataset, Image, Screen, Plate, Well, Annotation""" % obj_type 2854 raise AttributeError(m) 2855 if not deleteChildren: 2856 for c in childTypes[obj_type]: 2857 op[c] = "KEEP" 2858 2859 #return self.simpleDelete(obj_type, obj_ids, op) 2860 dcs = list() 2861 logger.debug('Deleting %s [%s]. Options: %s' % (obj_type, str(obj_ids), op)) 2862 for oid in obj_ids: 2863 dcs.append(omero.api.delete.DeleteCommand("/%s" % obj_type, long(oid), op)) 2864 handle = self.getDeleteService().queueDelete(dcs) 2865 return handle
2866 2867 2868 ################### 2869 # Searching stuff # 2870
2871 - def searchObjects(self, obj_types, text, created=None):
2872 """ 2873 Search objects of type "Project", "Dataset", "Image", "Screen", "Plate" 2874 Returns a list of results 2875 2876 @param obj_types: E.g. ["Dataset", "Image"] 2877 @param text: The text to search for 2878 @param created: L{omero.rtime} list or tuple (start, stop) 2879 @return: List of Object wrappers. E.g. L{ImageWrapper} 2880 """ 2881 if not text: 2882 return [] 2883 if isinstance(text, UnicodeType): 2884 text = text.encode('utf8') 2885 if obj_types is None: 2886 types = (ProjectWrapper, DatasetWrapper, ImageWrapper) 2887 else: 2888 def getWrapper(obj_type): 2889 if obj_type.lower() not in ["project", "dataset", "image", "screen", "plate", "well"]: 2890 raise AttributeError("%s not recognised. Can only search for 'Project', 'Dataset', 'Image', 'Screen', 'Plate', 'Well'" % obj_type) 2891 return KNOWN_WRAPPERS.get(obj_type.lower(), None)
2892 types = [getWrapper(o) for o in obj_types] 2893 search = self.createSearchService() 2894 if created: 2895 search.onlyCreatedBetween(created[0], created[1]); 2896 if text[0] in ('?','*'): 2897 search.setAllowLeadingWildcard(True) 2898 rv = [] 2899 for t in types: 2900 def actualSearch (): 2901 search.onlyType(t().OMERO_CLASS) 2902 search.byFullText(text) 2903 timeit(actualSearch)() 2904 if search.hasNext(): 2905 def searchProcessing (): 2906 rv.extend(map(lambda x: t(self, x), search.results())) 2907 timeit(searchProcessing)() 2908 search.close() 2909 return rv 2910
2911 2912 -class OmeroGatewaySafeCallWrapper(object): #pragma: no cover
2913 """ 2914 Function or method wrapper that handles certain types of server side 2915 exceptions and debugging of errors. 2916 """ 2917
2918 - def __init__(self, proxyObjectWrapper, attr, f):
2919 """ 2920 Initialises the function call wrapper. 2921 2922 @param attr: Function name 2923 @type attr: String 2924 @param f: Function to wrap 2925 @type f: Function 2926 """ 2927 self.proxyObjectWrapper = proxyObjectWrapper 2928 self.attr = attr 2929 self.f = f 2930 try: 2931 self.__f__name = f.im_self.ice_getIdentity().name 2932 except: 2933 self.__f__name = "unknown"
2934
2935 - def debug(self, exc_class, args, kwargs):
2936 logger.warn("%s on %s to <%s> %s(%r, %r)", 2937 exc_class, self.__class__, self.__f__name, self.attr, 2938 args, kwargs, exc_info=True)
2939
2940 - def handle_exception(self, e, *args, **kwargs):
2941 """ 2942 Exception handler that is expected to be overridden by sub-classes. 2943 The expected behaviour is either to handle a type of exception and 2944 return the server side result or to raise the already thrown 2945 exception. The calling context is an except block and the original 2946 *args and **kwargs from the wrapped function or method are provided 2947 to allow re-execution of the original. 2948 2949 @param e: The exception that has already been raised. 2950 @type e: Exception 2951 """ 2952 raise
2953
2954 - def __call__(self, *args, **kwargs):
2955 try: 2956 return self.f(*args, **kwargs) 2957 except Exception, e: 2958 self.debug(e.__class__.__name__, args, kwargs) 2959 return self.handle_exception(e, *args, **kwargs)
2960 2961 # Extension point for API users who want to customise the semantics of 2962 # safe call wrap. (See #6365) 2963 # 2964 # Since: OMERO Beta-4.3.2 (Tue 2 Aug 2011 09:59:47 BST) 2965 SafeCallWrapper = OmeroGatewaySafeCallWrapper 2966 2967 BlitzGateway = _BlitzGateway
2968 2969 2970 -def splitHTMLColor (color):
2971 """ splits an hex stream of characters into an array of bytes in format (R,G,B,A). 2972 - abc -> (0xAA, 0xBB, 0xCC, 0xFF) 2973 - abcd -> (0xAA, 0xBB, 0xCC, 0xDD) 2974 - abbccd -> (0xAB, 0xBC, 0xCD, 0xFF) 2975 - abbccdde -> (0xAB, 0xBC, 0xCD, 0xDE) 2976 2977 @param color: Characters to split. 2978 @return: rgba 2979 @rtype: list of Ints 2980 """ 2981 try: 2982 out = [] 2983 if len(color) in (3,4): 2984 c = color 2985 color = '' 2986 for e in c: 2987 color += e + e 2988 if len(color) == 6: 2989 color += 'FF' 2990 if len(color) == 8: 2991 for i in range(0, 8, 2): 2992 out.append(int(color[i:i+2], 16)) 2993 return out 2994 except: 2995 pass 2996 return None
2997
2998 2999 -class ProxyObjectWrapper (object):
3000 """ 3001 Wrapper for services. E.g. Admin Service, Delete Service etc. 3002 Maintains reference to connection. 3003 Handles creation of service when requested. 3004 """ 3005
3006 - def __init__ (self, conn, func_str):
3007 """ 3008 Initialisation of proxy object wrapper. 3009 3010 @param conn: The L{BlitzGateway} connection 3011 @type conn: L{BlitzGateway} 3012 @param func_str: The name of the service creation method. E.g 'getAdminService' 3013 @type func_str: String 3014 """ 3015 self._obj = None 3016 self._func_str = func_str 3017 self._resyncConn(conn) 3018 self._tainted = False
3019
3020 - def clone (self):
3021 """ 3022 Creates and returns a new L{ProxyObjectWrapper} with the same connection 3023 and service creation method name as this one. 3024 3025 @return: Cloned service wrapper 3026 @rtype: L{ProxyObjectWrapper} 3027 """ 3028 3029 return ProxyObjectWrapper(self._conn, self._func_str)
3030
3031 - def _connect (self, forcejoin=False): #pragma: no cover
3032 """ 3033 Returns True if connected. If connection OK, wrapped service is also created. 3034 3035 @param forcejoin: if True forces the connection to only succeed if we can 3036 rejoin the current sessionid 3037 @type forcejoin: Boolean 3038 3039 @return: True if connection OK 3040 @rtype: Boolean 3041 """ 3042 logger.debug("proxy_connect: a"); 3043 if forcejoin: 3044 sUuid = self._conn._sessionUuid 3045 else: 3046 sUuid = None 3047 if not self._conn.connect(sUuid=sUuid): 3048 logger.debug('connect failed') 3049 logger.debug('/n'.join(traceback.format_stack())) 3050 return False 3051 logger.debug("proxy_connect: b"); 3052 self._resyncConn(self._conn) 3053 logger.debug("proxy_connect: c"); 3054 self._obj = self._create_func() 3055 logger.debug("proxy_connect: d"); 3056 return True
3057
3058 - def taint (self):
3059 """ Sets the tainted flag to True """ 3060 self._tainted = True
3061
3062 - def untaint (self):
3063 """ Sets the tainted flag to False """ 3064 self._tainted = False
3065
3066 - def close (self):
3067 """ 3068 Closes the underlaying service, so next call to the proxy will create a new 3069 instance of it. 3070 """ 3071 3072 if self._obj and isinstance(self._obj, omero.api.StatefulServiceInterfacePrx): 3073 self._obj.close() 3074 self._obj = None
3075
3076 - def _resyncConn (self, conn):
3077 """ 3078 Reset refs to connection and session factory. Resets session creation function. 3079 Attempts to reload the wrapped service - if already created (doesn't create service) 3080 3081 @param conn: Connection 3082 @type conn: L{BlitzGateway} 3083 """ 3084 3085 self._conn = conn 3086 self._sf = conn.c.sf 3087 self._create_func = getattr(self._sf, self._func_str) 3088 if self._obj is not None: 3089 try: 3090 logger.debug("## - refreshing %s" % (self._func_str)) 3091 obj = conn.c.ic.stringToProxy(str(self._obj)) 3092 self._obj = self._obj.checkedCast(obj) 3093 except Ice.ObjectNotExistException: 3094 self._obj = None
3095
3096 - def _getObj (self):
3097 """ 3098 Returns the wrapped service. If it is None, service is created. 3099 3100 @return: The wrapped service 3101 @rtype: omero.api.ServiceInterface subclass 3102 """ 3103 3104 if not self._obj: 3105 try: 3106 self._obj = self._create_func() 3107 except Ice.ConnectionLostException: 3108 logger.debug('... lost, reconnecting (_getObj)') 3109 self._connect() 3110 #self._obj = self._create_func() 3111 else: 3112 self._ping() 3113 return self._obj
3114
3115 - def _ping (self): #pragma: no cover
3116 """ 3117 For some reason, it seems that keepAlive doesn't, so every so often I need to recreate the objects. 3118 Calls serviceFactory.keepAlive(service). If this returns false, attempt to create service. 3119 3120 @return: True if no exception thrown 3121 @rtype: Boolean 3122 """ 3123 3124 try: 3125 if not self._sf.keepAlive(self._obj): 3126 logger.debug("... died, recreating ...") 3127 self._obj = self._create_func() 3128 except Ice.ObjectNotExistException: 3129 # The connection is there, but it has been reset, because the proxy no longer exists... 3130 logger.debug("... reset, reconnecting") 3131 self._connect() 3132 return False 3133 except Ice.ConnectionLostException: 3134 # The connection was lost. This shouldn't happen, as we keep pinging it, but does so... 3135 logger.debug(traceback.format_stack()) 3136 logger.debug("... lost, reconnecting (_ping)") 3137 self._conn._connected = False 3138 self._connect() 3139 return False 3140 except Ice.ConnectionRefusedException: 3141 # The connection was refused. We lost contact with glacier2router... 3142 logger.debug(traceback.format_stack()) 3143 logger.debug("... refused, reconnecting") 3144 self._connect() 3145 return False 3146 except omero.RemovedSessionException: 3147 # Session died on us 3148 logger.debug(traceback.format_stack()) 3149 logger.debug("... session has left the building, reconnecting") 3150 self._connect() 3151 return False 3152 except Ice.UnknownException: 3153 # Probably a wrapped RemovedSession 3154 logger.debug(traceback.format_stack()) 3155 logger.debug("... ice says something bad happened, reconnecting") 3156 self._connect() 3157 return False 3158 return True 3159
3160 - def __getattr__ (self, attr):
3161 """ 3162 Returns named attribute of the wrapped service. 3163 If attribute is a method, the method is wrapped to handle exceptions, connection etc. 3164 3165 @param attr: Attribute name 3166 @type attr: String 3167 @return: Attribute or wrapped method 3168 """ 3169 # safe call wrapper 3170 obj = self._obj or self._getObj() 3171 rv = getattr(obj, attr) 3172 if callable(rv): 3173 rv = SafeCallWrapper(self, attr, rv) 3174 #self._conn.updateTimeout() 3175 return rv
3176
3177 -class AnnotationWrapper (BlitzObjectWrapper):
3178 """ 3179 omero_model_AnnotationI class wrapper extends BlitzObjectWrapper. 3180 """ 3181 registry = {} # class dict for type:wrapper E.g. DoubleAnnotationI : DoubleAnnotationWrapper 3182 OMERO_TYPE = None 3183
3184 - def __init__ (self, *args, **kwargs):
3185 """ 3186 Initialises the Annotation wrapper and 'link' if in kwargs 3187 """ 3188 super(AnnotationWrapper, self).__init__(*args, **kwargs) 3189 self.link = kwargs.has_key('link') and kwargs['link'] or None 3190 if self._obj is None and self.OMERO_TYPE is not None: 3191 self._obj = self.OMERO_TYPE()
3192
3193 - def __eq__ (self, a):
3194 """ 3195 Returns true if type, id, value and ns are equal 3196 3197 @param a: The annotation to compare 3198 @return: True if annotations are the same - see above 3199 @rtype: Boolean 3200 """ 3201 return type(a) == type(self) and self._obj.id == a._obj.id and self.getValue() == a.getValue() and self.getNs() == a.getNs()
3202
3203 - def _getQueryString(self):
3204 """ 3205 Used for building queries in generic methods such as getObjects("Annotation") 3206 """ 3207 return "select obj from Annotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3208 "join fetch obj.details.creationEvent"
3209 3210 @classmethod
3211 - def _register (klass, regklass):
3212 """ 3213 Adds the AnnotationWrapper regklass to class registry 3214 @param regklass: The wrapper class, E.g. L{DoubleAnnotationWrapper} 3215 @type regklass: L{AnnotationWrapper} subclass 3216 """ 3217 3218 klass.registry[regklass.OMERO_TYPE] = regklass
3219 3220 @classmethod
3221 - def _wrap (klass, conn=None, obj=None, link=None):
3222 """ 3223 Class method for creating L{AnnotationWrapper} subclasses based on the type of 3224 annotation object, using previously registered mapping between OMERO types and wrapper classes 3225 3226 @param conn: The L{BlitzGateway} connection 3227 @type conn: L{BlitzGateway} 3228 @param obj: The OMERO annotation object. E.g. omero.model.DoubleAnnotation 3229 @type obj: L{omero.model.Annotation} subclass 3230 @param link: The link for this annotation 3231 @type link: E.g. omero.model.DatasetAnnotationLink 3232 @return: Wrapped AnnotationWrapper object or None if obj.__class__ not registered 3233 @rtype: L{AnnotationWrapper} subclass 3234 """ 3235 if obj is None: 3236 return AnnotationWrapper() 3237 if obj.__class__ in klass.registry: 3238 kwargs = dict() 3239 if link is not None: 3240 kwargs['link'] = BlitzObjectWrapper(conn, link) 3241 return klass.registry[obj.__class__](conn, obj, **kwargs) 3242 else: #pragma: no cover 3243 return None
3244 3245 @classmethod 3263
3264 - def getNs (self):
3265 """ 3266 Gets annotation namespace 3267 3268 @return: Namespace or None 3269 @rtype: String 3270 """ 3271 3272 return self._obj.ns is not None and self._obj.ns.val or None
3273
3274 - def setNs (self, val):
3275 """ 3276 Sets annotation namespace 3277 3278 @param val: Namespace value 3279 @type val: String 3280 """ 3281 3282 self._obj.ns = omero_type(val)
3283
3284 - def getValue (self): #pragma: no cover
3285 """ Needs to be implemented by subclasses """ 3286 raise NotImplementedError
3287
3288 - def setValue (self, val): #pragma: no cover
3289 """ Needs to be implemented by subclasses """ 3290 raise NotImplementedError 3291 3293 ptype = ptype.lower() 3294 if not ptype in ('project', 'dataset', 'image', 'screen', 'plate', 'well'): 3295 AttributeError('Annotation can be linked only to: project, dataset, image, screen, plate, well') 3296 p = omero.sys.Parameters() 3297 p.map = {} 3298 p.map["aid"] = rlong(self.id) 3299 sql = "select oal from %sAnnotationLink as oal left outer join fetch oal.child as ch " \ 3300 "left outer join fetch oal.parent as pa " \ 3301 "where ch.id=:aid " % (ptype.title()) 3302 if pids is not None: 3303 p.map["pids"] = rlist([rlong(ob) for ob in pids]) 3304 sql+=" and pa.id in (:pids)" 3305 3306 for al in self._conn.getQueryService().findAllByQuery(sql, p): 3307 yield AnnotationLinkWrapper(self, al) 3308 3316 3317 AnnotationLinkWrapper = _AnnotationLinkWrapper 3318 3319 from omero_model_FileAnnotationI import FileAnnotationI
3320 3321 -class FileAnnotationWrapper (AnnotationWrapper):
3322 """ 3323 omero_model_FileAnnotatio class wrapper extends AnnotationWrapper. 3324 """ 3325 3326 OMERO_TYPE = FileAnnotationI 3327 3328 _attrs = ('file|OriginalFileWrapper',) 3329
3330 - def _getQueryString(self):
3331 """ 3332 Used for building queries in generic methods such as getObjects("FileAnnotation") 3333 """ 3334 return "select obj from FileAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3335 "join fetch obj.details.creationEvent join fetch obj.file"
3336
3337 - def getValue (self):
3338 """ Not implemented """ 3339 pass
3340
3341 - def setValue (self, val):
3342 """ Not implemented """ 3343 pass
3344
3345 - def isOriginalMetadata(self):
3346 """ 3347 Checks if this file annotation is an 'original_metadata' file 3348 3349 @return: True if namespace and file name follow metadata convention 3350 @rtype: Boolean 3351 """ 3352 3353 try: 3354 if self._obj.ns is not None and self._obj.ns.val == omero.constants.namespaces.NSCOMPANIONFILE and self._obj.file.name.val.startswith("original_metadata"): 3355 return True 3356 except: 3357 logger.info(traceback.format_exc()) 3358 return False
3359
3360 - def getFileSize(self):
3361 """ 3362 Looks up the size of the file in bytes 3363 3364 @return: File size (bytes) 3365 @rtype: Long 3366 """ 3367 return self.getFile().size
3368
3369 - def getFileName(self):
3370 """ 3371 Gets the file name 3372 3373 @return: File name 3374 @rtype: String 3375 """ 3376 3377 return self.getFile().name
3378
3379 - def getFileInChunks(self):
3380 """ 3381 Returns a generator yielding chunks of the file data. 3382 3383 @return: Data from file in chunks 3384 @rtype: Generator 3385 """ 3386 3387 return self.getFile().getFileInChunks();
3388 3389 AnnotationWrapper._register(FileAnnotationWrapper)
3390 3391 3392 -class _OriginalFileWrapper (BlitzObjectWrapper):
3393 """ 3394 omero_model_OriginalFileI class wrapper extends BlitzObjectWrapper. 3395 """ 3396
3397 - def __bstrap__ (self):
3398 self.OMERO_CLASS = 'OriginalFile'
3399
3400 - def getFileInChunks(self, buf=2621440):
3401 """ 3402 Returns a generator yielding chunks of the file data. 3403 3404 @return: Data from file in chunks 3405 @rtype: Generator 3406 """ 3407 3408 store = self._conn.createRawFileStore() 3409 store.setFileId(self._obj.id.val) 3410 size = self._obj.size.val 3411 if size <= buf: 3412 yield store.read(0,long(size)) 3413 else: 3414 for pos in range(0,long(size),buf): 3415 data = None 3416 if size-pos < buf: 3417 data = store.read(pos, size-pos) 3418 else: 3419 data = store.read(pos, buf) 3420 yield data 3421 store.close()
3422 3423 3424 OriginalFileWrapper = _OriginalFileWrapper 3425 3426 3427 from omero_model_TimestampAnnotationI import TimestampAnnotationI
3428 3429 -class TimestampAnnotationWrapper (AnnotationWrapper):
3430 """ 3431 omero_model_TimestampAnnotatio class wrapper extends AnnotationWrapper. 3432 """ 3433 3434 OMERO_TYPE = TimestampAnnotationI 3435
3436 - def _getQueryString(self):
3437 """ 3438 Used for building queries in generic methods such as getObjects("TimestampAnnotation") 3439 """ 3440 return "select obj from TimestampAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3441 "join fetch obj.details.creationEvent"
3442
3443 - def getValue (self):
3444 """ 3445 Returns a datetime object of the timestamp in seconds 3446 3447 @return: Timestamp value 3448 @rtype: L{datetime} 3449 """ 3450 3451 return datetime.fromtimestamp(self._obj.timeValue.val / 1000.0)
3452
3453 - def setValue (self, val):
3454 """ 3455 Sets the timestamp value 3456 3457 @param val: Timestamp value 3458 @type param: L{datetime} OR L{omero.RTime} OR Long 3459 """ 3460 3461 if isinstance(val, datetime): 3462 self._obj.timeValue = rtime(long(time.mktime(val.timetuple())*1000)) 3463 elif isinstance(val, omero.RTime): 3464 self._obj.timeValue = val 3465 else: 3466 self._obj.timeValue = rtime(long(val * 1000))
3467 3468 AnnotationWrapper._register(TimestampAnnotationWrapper) 3469 3470 from omero_model_BooleanAnnotationI import BooleanAnnotationI
3471 3472 -class BooleanAnnotationWrapper (AnnotationWrapper):
3473 """ 3474 omero_model_BooleanAnnotationI class wrapper extends AnnotationWrapper. 3475 """ 3476 3477 OMERO_TYPE = BooleanAnnotationI 3478
3479 - def _getQueryString(self):
3480 """ 3481 Used for building queries in generic methods such as getObjects("BooleanAnnotation") 3482 """ 3483 return "select obj from BooleanAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3484 "join fetch obj.details.creationEvent"
3485
3486 - def getValue (self):
3487 """ 3488 Gets boolean value 3489 3490 @return: Value 3491 @rtype: Boolean 3492 """ 3493 return self._obj.boolValue.val
3494
3495 - def setValue (self, val):
3496 """ 3497 Sets boolean value 3498 3499 @param val: Value 3500 @type val: Boolean 3501 """ 3502 3503 self._obj.boolValue = rbool(not not val)
3504 3505 AnnotationWrapper._register(BooleanAnnotationWrapper) 3506 3507 from omero_model_TagAnnotationI import TagAnnotationI
3508 3509 -class TagAnnotationWrapper (AnnotationWrapper):
3510 """ 3511 omero_model_BooleanAnnotationI class wrapper extends AnnotationWrapper. 3512 """ 3513 3514 OMERO_TYPE = TagAnnotationI 3515
3516 - def countTagsInTagset(self):
3517 # temp solution waiting for #5785 3518 if self.ns in (omero.constants.metadata.NSINSIGHTTAGSET): 3519 params = omero.sys.Parameters() 3520 params.map = {} 3521 params.map['tid'] = self._obj.id 3522 sql = "select tg from TagAnnotation tg "\ 3523 "where exists ( select aal from AnnotationAnnotationLink as aal where aal.child=tg.id and aal.parent.id=:tid) " 3524 3525 res = self._conn.getQueryService().findAllByQuery(sql, params) 3526 return res is not None and len(res) or 0
3527
3528 - def listTagsInTagset(self):
3529 # temp solution waiting for #5785 3530 if self.ns in (omero.constants.metadata.NSINSIGHTTAGSET): 3531 params = omero.sys.Parameters() 3532 params.map = {} 3533 params.map["tid"] = rlong(self._obj.id) 3534 3535 sql = "select tg from TagAnnotation tg "\ 3536 "where exists ( select aal from AnnotationAnnotationLink as aal where aal.child.id=tg.id and aal.parent.id=:tid) " 3537 3538 q = self._conn.getQueryService() 3539 for ann in q.findAllByQuery(sql, params): 3540 yield TagAnnotationWrapper(self._conn, ann)
3541
3542 - def _getQueryString(self):
3543 """ 3544 Used for building queries in generic methods such as getObjects("TagAnnotation") 3545 """ 3546 return "select obj from TagAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3547 "join fetch obj.details.creationEvent"
3548
3549 - def getValue (self):
3550 """ 3551 Gets the value of the Tag 3552 3553 @return: Value 3554 @type: String 3555 """ 3556 3557 return self._obj.textValue.val
3558
3559 - def setValue (self, val):
3560 """ 3561 Sets Tag value 3562 3563 @param val: Tag text value 3564 @type val: String 3565 """ 3566 3567 self._obj.textValue = omero_type(val)
3568 3569 AnnotationWrapper._register(TagAnnotationWrapper) 3570 3571 from omero_model_CommentAnnotationI import CommentAnnotationI
3572 3573 -class CommentAnnotationWrapper (AnnotationWrapper):
3574 """ 3575 omero_model_CommentAnnotationI class wrapper extends AnnotationWrapper. 3576 """ 3577 3578 OMERO_TYPE = CommentAnnotationI 3579
3580 - def _getQueryString(self):
3581 """ 3582 Used for building queries in generic methods such as getObjects("CommentAnnotation") 3583 """ 3584 return "select obj from CommentAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3585 "join fetch obj.details.creationEvent"
3586
3587 - def getValue (self):
3588 """ 3589 Gets the value of the Comment 3590 3591 @return: Value 3592 @type: String 3593 """ 3594 3595 return self._obj.textValue.val
3596
3597 - def setValue (self, val):
3598 """ 3599 Sets comment text value 3600 3601 @param val: Value 3602 @type val: String 3603 """ 3604 3605 self._obj.textValue = omero_type(val)
3606 3607 AnnotationWrapper._register(CommentAnnotationWrapper) 3608 3609 from omero_model_LongAnnotationI import LongAnnotationI
3610 3611 -class LongAnnotationWrapper (AnnotationWrapper):
3612 """ 3613 omero_model_LongAnnotationI class wrapper extends AnnotationWrapper. 3614 """ 3615 OMERO_TYPE = LongAnnotationI 3616
3617 - def _getQueryString(self):
3618 """ 3619 Used for building queries in generic methods such as getObjects("LongAnnotation") 3620 """ 3621 return "select obj from LongAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3622 "join fetch obj.details.creationEvent"
3623
3624 - def getValue (self):
3625 """ 3626 Gets the value of the Long annotation 3627 3628 @return: Value 3629 @type: Long 3630 """ 3631 3632 return self._obj.longValue and self._obj.longValue.val or None
3633
3634 - def setValue (self, val):
3635 """ 3636 Sets long annotation value 3637 3638 @param val: Value 3639 @type val: Long 3640 """ 3641 3642 self._obj.longValue = rlong(val)
3643 3644 AnnotationWrapper._register(LongAnnotationWrapper) 3645 3646 from omero_model_DoubleAnnotationI import DoubleAnnotationI
3647 3648 -class DoubleAnnotationWrapper (AnnotationWrapper):
3649 """ 3650 omero_model_DoubleAnnotationI class wrapper extends AnnotationWrapper. 3651 """ 3652 OMERO_TYPE = DoubleAnnotationI 3653
3654 - def _getQueryString(self):
3655 """ 3656 Used for building queries in generic methods such as getObjects("DoubleAnnotation") 3657 """ 3658 return "select obj from DoubleAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3659 "join fetch obj.details.creationEvent"
3660
3661 - def getValue (self):
3662 """ 3663 Gets the value of the Double Annotation 3664 3665 @return: Value 3666 @type: Double 3667 """ 3668 3669 return self._obj.doubleValue.val
3670
3671 - def setValue (self, val):
3672 """ 3673 Sets Double annotation value 3674 3675 @param val: Value 3676 @type val: Double 3677 """ 3678 3679 self._obj.doubleValue = rdouble(val)
3680 3681 AnnotationWrapper._register(DoubleAnnotationWrapper) 3682 3683 from omero_model_TermAnnotationI import TermAnnotationI
3684 3685 -class TermAnnotationWrapper (AnnotationWrapper):
3686 """ 3687 omero_model_TermAnnotationI class wrapper extends AnnotationWrapper. 3688 3689 only in 4.2+ 3690 """ 3691 OMERO_TYPE = TermAnnotationI 3692
3693 - def _getQueryString(self):
3694 """ 3695 Used for building queries in generic methods such as getObjects("TermAnnotation") 3696 """ 3697 return "select obj from TermAnnotation obj join fetch obj.details.owner as owner join fetch obj.details.group "\ 3698 "join fetch obj.details.creationEvent"
3699
3700 - def getValue (self):
3701 """ 3702 Gets the value of the Term 3703 3704 @return: Value 3705 @type: String 3706 """ 3707 3708 return self._obj.termValue.val
3709
3710 - def setValue (self, val):
3711 """ 3712 Sets term value 3713 3714 @param val: Value 3715 @type val: String 3716 """ 3717 3718 self._obj.termValue = rstring(val)
3719 3720 AnnotationWrapper._register(TermAnnotationWrapper) 3721 3722 from omero_model_XmlAnnotationI import XmlAnnotationI
3723 3724 -class XmlAnnotationWrapper (CommentAnnotationWrapper):
3725 """ 3726 omero_model_XmlAnnotationI class wrapper extends CommentAnnotationWrapper. 3727 """ 3728 OMERO_TYPE = XmlAnnotationI
3729 3730 AnnotationWrapper._register(XmlAnnotationWrapper)
3731 3732 -class _EnumerationWrapper (BlitzObjectWrapper):
3733
3734 - def getType(self):
3735 """ 3736 Gets the type (class) of the Enumeration 3737 3738 @return: The omero class 3739 @type: Class 3740 """ 3741 3742 return self._obj.__class__
3743 3744 EnumerationWrapper = _EnumerationWrapper
3745 3746 -class _ExperimenterWrapper (BlitzObjectWrapper):
3747 """ 3748 omero_model_ExperimenterI class wrapper extends BlitzObjectWrapper. 3749 """ 3750
3751 - def __bstrap__ (self):
3752 self.OMERO_CLASS = 'Experimenter' 3753 self.LINK_CLASS = "GroupExperimenterMap" 3754 self.CHILD_WRAPPER_CLASS = None 3755 self.PARENT_WRAPPER_CLASS = 'ExperimenterGroupWrapper'
3756
3757 - def simpleMarshal (self, xtra=None, parents=False):
3758 rv = super(_ExperimenterWrapper, self).simpleMarshal(xtra=xtra, parents=parents) 3759 rv.update({'firstName': self.firstName, 3760 'middleName': self.middleName, 3761 'lastName': self.lastName, 3762 'email': self.email, 3763 'isAdmin': len(filter(lambda x: x.name.val == 'system', self._conn.getAdminService().containedGroups(self.getId()))) == 1, 3764 }) 3765 return rv
3766
3767 - def _getQueryString(self):
3768 """ 3769 Returns string for building queries, loading Experimenters only. 3770 """ 3771 return "select distinct obj from Experimenter as obj left outer join fetch obj.groupExperimenterMap " \ 3772 "as map left outer join fetch map.parent g"
3773
3774 - def getRawPreferences (self):
3775 """ 3776 Returns the experimenter's preferences annotation contents, as a ConfigParser instance 3777 3778 @return: See above 3779 @rtype: ConfigParser 3780 """ 3781 3782 self._obj.unloadAnnotationLinks() 3783 cp = ConfigParser.SafeConfigParser() 3784 prefs = self.getAnnotation('TODO.changeme.preferences') 3785 if prefs is not None: 3786 prefs = prefs.getValue() 3787 if prefs is not None: 3788 cp.readfp(StringIO(prefs)) 3789 return cp
3790
3791 - def setRawPreferences (self, prefs):
3792 """ 3793 Sets the experimenter's preferences annotation contents, passed in as a ConfigParser instance 3794 3795 @param prefs: ConfigParser of preferences 3796 @type prefs: ConfigParser 3797 """ 3798 3799 ann = self.getAnnotation('TODO.changeme.preferences') 3800 t = StringIO() 3801 prefs.write(t) 3802 if ann is None: 3803 ann = CommentAnnotationWrapper() 3804 ann.setNs('TODO.changeme.preferences') 3805 ann.setValue(t.getvalue()) 3806 self.linkAnnotation(ann) 3807 else: 3808 ann.setValue(t.getvalue()) 3809 ann.save() 3810 self._obj.unloadAnnotationLinks()
3811
3812 - def getPreference (self, key, default='', section=None):
3813 """ 3814 Gets a preference for the experimenter 3815 3816 @param key: Preference key 3817 @param default: Default value to return 3818 @param section: Preferences section 3819 @return: Preference value 3820 """ 3821 3822 if section is None: 3823 section = 'DEFAULT' 3824 try: 3825 return self.getRawPreferences().get(section, key) 3826 except ConfigParser.Error: 3827 return default 3828 return default
3829
3830 - def getPreferences (self, section=None):
3831 """ 3832 Gets all preferences for section 3833 3834 @param section: Preferences section 3835 @return: Dict of preferences 3836 """ 3837 3838 if section is None: 3839 section = 'DEFAULT' 3840 prefs = self.getRawPreferences() 3841 if prefs.has_section(section) or section == 'DEFAULT': 3842 return dict(prefs.items(section)) 3843 return {}
3844
3845 - def setPreference (self, key, value, section=None):
3846 """ 3847 Sets a preference for the experimenter 3848 3849 @param key: Preference key 3850 @param value: Value to set 3851 @param section: Preferences section - created if needed 3852 """ 3853 3854 if section is None: 3855 section = 'DEFAULT' 3856 prefs = self.getRawPreferences() 3857 if not section in prefs.sections(): 3858 prefs.add_section(section) 3859 prefs.set(section, key, value) 3860 self.setRawPreferences(prefs)
3861
3862 - def getDetails (self):
3863 """ 3864 Make sure we have correct details for this experimenter and return them 3865 3866 @return: Experimenter Details 3867 @rtype: L{DetailsWrapper} 3868 """ 3869 3870 if not self._obj.details.owner: 3871 details = omero.model.DetailsI() 3872 details.owner = self._obj 3873 self._obj._details = details 3874 return DetailsWrapper(self._conn, self._obj.details)
3875
3876 - def getName (self):
3877 """ 3878 Returns Experimenter's omeName 3879 3880 @return: Name 3881 @rtype: String 3882 """ 3883 3884 return self.omeName
3885
3886 - def getDescription (self):
3887 """ 3888 Returns Experimenter's Full Name 3889 3890 @return: Full Name or None 3891 @rtype: String 3892 """ 3893 3894 return self.getFullName()
3895
3896 - def getFullName (self):
3897 """ 3898 Gets full name of this experimenter. E.g. 'William James. Moore' or 'William Moore' if no middle name 3899 3900 @return: Full Name or None 3901 @rtype: String 3902 """ 3903 3904 try: 3905 lastName = self.lastName 3906 firstName = self.firstName 3907 middleName = self.middleName 3908 3909 if middleName is not None and middleName != '': 3910 name = "%s %s. %s" % (firstName, middleName, lastName) 3911 else: 3912 name = "%s %s" % (firstName, lastName) 3913 return name 3914 except: 3915 logger.error(traceback.format_exc()) 3916 return None
3917
3918 - def getNameWithInitial(self):
3919 """ 3920 Returns first initial and Last name. E.g. 'W. Moore' 3921 3922 @return: Initial and last name 3923 @rtype: String 3924 """ 3925 3926 try: 3927 if self.firstName is not None and self.lastName is not None: 3928 name = "%s. %s" % (self.firstName[:1], self.lastName) 3929 else: 3930 name = self.omeName 3931 return name 3932 except: 3933 logger.error(traceback.format_exc()) 3934 return _("Unknown name")
3935
3936 - def isAdmin(self):
3937 """ 3938 Returns true if Experimenter is Admin (if they are in any group named 'system') 3939 3940 @return: True if experimenter is Admin 3941 @rtype: Boolean 3942 """ 3943 3944 for ob in self._obj.copyGroupExperimenterMap(): 3945 if ob.parent.name.val == "system": 3946 return True 3947 return False
3948
3949 - def isActive(self):
3950 """ 3951 Returns true if Experimenter is Active (if they are in any group named 'user') 3952 3953 @return: True if experimenter is Active 3954 @rtype: Boolean 3955 """ 3956 3957 for ob in self._obj.copyGroupExperimenterMap(): 3958 if ob.parent.name.val == "user": 3959 return True 3960 return False
3961
3962 - def isGuest(self):
3963 """ 3964 Returns true if Experimenter is Guest (if they are in any group named 'guest') 3965 3966 @return: True if experimenter is Admin 3967 @rtype: Boolean 3968 """ 3969 3970 for ob in self._obj.copyGroupExperimenterMap(): 3971 if ob.parent.name.val == "guest": 3972 return True 3973 return False
3974 3975 ExperimenterWrapper = _ExperimenterWrapper
3976 3977 -class _ExperimenterGroupWrapper (BlitzObjectWrapper):
3978 """ 3979 omero_model_ExperimenterGroupI class wrapper extends BlitzObjectWrapper. 3980 """ 3981
3982 - def __bstrap__ (self):
3983 self.OMERO_CLASS = 'ExperimenterGroup' 3984 self.LINK_CLASS = "GroupExperimenterMap" 3985 self.CHILD_WRAPPER_CLASS = 'ExperimenterWrapper' 3986 self.PARENT_WRAPPER_CLASS = None
3987
3988 - def isLeader(self):
3989 """ 3990 Is the current group led by the current user? 3991 3992 @return: True if user leads the current group 3993 @rtype: Boolean 3994 """ 3995 if self._conn.getEventContext().groupId in self._conn.getEventContext().leaderOfGroups: 3996 return True 3997 return False
3998
3999 - def _getQueryString(self):
4000 """ 4001 Returns string for building queries, loading Experimenters for each group. 4002 """ 4003 query = "select distinct obj from ExperimenterGroup as obj left outer join fetch obj.groupExperimenterMap " \ 4004 "as map left outer join fetch map.child e" 4005 return query
4006 4007 4008 ExperimenterGroupWrapper = _ExperimenterGroupWrapper
4009 4010 -class DetailsWrapper (BlitzObjectWrapper):
4011 """ 4012 omero_model_DetailsI class wrapper extends BlitzObjectWrapper. 4013 """ 4014
4015 - def __init__ (self, *args, **kwargs):
4016 super(DetailsWrapper, self).__init__ (*args, **kwargs) 4017 owner = self._obj.getOwner() 4018 group = self._obj.getGroup() 4019 self._owner = owner and ExperimenterWrapper(self._conn, self._obj.getOwner()) or None 4020 self._group = group and ExperimenterGroupWrapper(self._conn, self._obj.getGroup()) or None
4021
4022 - def getOwner (self):
4023 """ 4024 Returns the Owner of the object that these details apply to 4025 4026 @return: Owner 4027 @rtype: L{ExperimenterWrapper} 4028 """ 4029 4030 return self._owner
4031
4032 - def getGroup (self):
4033 """ 4034 Returns the Group that these details refer to 4035 4036 @return: Group 4037 @rtype: L{ExperimenterGroupWrapper} 4038 """ 4039 4040 return self._group
4041
4042 -class _DatasetWrapper (BlitzObjectWrapper):
4043 """ 4044 omero_model_DatasetI class wrapper extends BlitzObjectWrapper. 4045 """ 4046
4047 - def __bstrap__ (self):
4048 self.OMERO_CLASS = 'Dataset' 4049 self.LINK_CLASS = "DatasetImageLink" 4050 self.CHILD_WRAPPER_CLASS = 'ImageWrapper' 4051 self.PARENT_WRAPPER_CLASS = 'ProjectWrapper'
4052
4053 - def __loadedHotSwap__ (self):
4054 """ In addition to loading the Dataset, this method also loads the Images """ 4055 4056 super(_DatasetWrapper, self).__loadedHotSwap__() 4057 if not self._obj.isImageLinksLoaded(): 4058 links = self._conn.getQueryService().findAllByQuery("select l from DatasetImageLink as l join fetch l.child as a where l.parent.id=%i" % (self._oid), None) 4059 self._obj._imageLinksLoaded = True 4060 self._obj._imageLinksSeq = links
4061 4062 DatasetWrapper = _DatasetWrapper
4063 4064 -class _ProjectWrapper (BlitzObjectWrapper):
4065 """ 4066 omero_model_ProjectI class wrapper extends BlitzObjectWrapper. 4067 """ 4068
4069 - def __bstrap__ (self):
4070 self.OMERO_CLASS = 'Project' 4071 self.LINK_CLASS = "ProjectDatasetLink" 4072 self.CHILD_WRAPPER_CLASS = 'DatasetWrapper' 4073 self.PARENT_WRAPPER_CLASS = None
4074 4075 ProjectWrapper = _ProjectWrapper
4076 4077 -class _ScreenWrapper (BlitzObjectWrapper):
4078 """ 4079 omero_model_ScreenI class wrapper extends BlitzObjectWrapper. 4080 """ 4081
4082 - def __bstrap__ (self):
4083 self.OMERO_CLASS = 'Screen' 4084 self.LINK_CLASS = "ScreenPlateLink" 4085 self.CHILD_WRAPPER_CLASS = 'PlateWrapper' 4086 self.PARENT_WRAPPER_CLASS = None
4087 4088 @timeit
4089 - def getNumberOfFields (self):
4090 """ 4091 Iterates all wells on all plates for this screen and returns highest well sample count 4092 """ 4093 q = self._conn.getQueryService() 4094 query = "select p.id, maxindex(p.wells.wellSamples)+1" 4095 query += " from ScreenPlateLink spl join spl.parent s join spl.child p" 4096 query += " where s.id=%d group by p.id" % self.getId() 4097 return dict(unwrap(q.projection(query, None)))
4098 4099 4100 ScreenWrapper = _ScreenWrapper
4101 4102 -def _letterGridLabel (i):
4103 """ Convert number to letter label. E.g. 0 -> 'A' and 100 -> 'CW' """ 4104 r = chr(ord('A') + i%26) 4105 i = i/26 4106 while i > 0: 4107 i -= 1 4108 r = chr(ord('A') + i%26) + r 4109 i = i/26 4110 return r
4111
4112 -class _PlateWrapper (BlitzObjectWrapper):
4113 """ 4114 omero_model_PlateI class wrapper extends BlitzObjectWrapper. 4115 """ 4116
4117 - def __bstrap__ (self):
4118 self.OMERO_CLASS = 'Plate' 4119 self.LINK_CLASS = None 4120 self.CHILD_WRAPPER_CLASS = 'WellWrapper' 4121 self.PARENT_WRAPPER_CLASS = 'ScreenWrapper'
4122
4123 - def __prepare__ (self):
4124 self.__reset__()
4125
4126 - def __reset__ (self):
4127 """ 4128 Clears child cache, so next _listChildren will query the server 4129 """ 4130 self._childcache = None 4131 self._gridSize = None
4132
4133 - def _listChildren (self, **kwargs):
4134 """ 4135 Lists Wells in this plate, not sorted. Saves wells to _childcache map, where key is (row, column). 4136 _ 4137 @rtype: list of omero.model.WellI objects 4138 @return: child objects. 4139 """ 4140 if self._childcache is None: 4141 q = self._conn.getQueryService() 4142 params = omero.sys.Parameters() 4143 params.map = {} 4144 params.map["oid"] = omero_type(self.getId()) 4145 query = "select well from Well as well "\ 4146 "join fetch well.details.creationEvent "\ 4147 "join fetch well.details.owner join fetch well.details.group " \ 4148 "left outer join fetch well.plate as pt "\ 4149 "left outer join fetch well.wellSamples as ws " \ 4150 "left outer join fetch ws.image as img "\ 4151 "where well.plate.id = :oid" 4152 4153 #index = index is None and 0 or index 4154 kwargs = {'index': self.defaultSample or 0} 4155 childw = self._getChildWrapper() 4156 self._childcache = {} 4157 for well in q.findAllByQuery(query, params): 4158 self._childcache[(well.row.val, well.column.val)] = well 4159 return self._childcache.values()
4160
4161 - def countChildren (self):
4162 return len(self._listChildren())
4163
4164 - def setGridSizeConstraints(self, row, col):
4165 """ 4166 Makes sure the grid side count is the exact power of two of row and col arguments, 4167 keeping their ratio, that fits the existing well count. 4168 """ 4169 gs = self.getGridSize() 4170 mul = 0 4171 while gs['rows'] > (row*(2**mul)) or gs['columns'] > (col*(2**mul)): 4172 mul += 1 4173 self._gridSize['rows'] = row * (2**mul) 4174 self._gridSize['columns'] = col * (2**mul)
4175
4176 - def getGridSize (self):
4177 """ 4178 Iterates all wells on plate to retrieve grid size as {'rows': rSize, 'columns':cSize} dict. 4179 4180 @rtype: dict of {'rows': rSize, 'columns':cSize} 4181 """ 4182 if self._gridSize is None: 4183 r,c = 0,0 4184 for child in self._listChildren(): 4185 r,c = max(child.row.val, r), max(child.column.val, c) 4186 self._gridSize = {'rows': r+1, 'columns': c+1} 4187 return self._gridSize
4188
4189 - def getWellGrid (self, index=0):
4190 """ 4191 Returns a grid of WellWrapper objects, indexed by [row][col]. 4192 4193 @rtype: 2D array of L{WellWrapper}s. Empty well positions are None 4194 """ 4195 grid = self.getGridSize() 4196 childw = self._getChildWrapper() 4197 rv = [[None]*grid['columns'] for x in range(grid['rows'])] 4198 for child in self._listChildren(): 4199 rv[child.row.val][child.column.val] = childw(self._conn, child, index=index) 4200 return rv
4201
4202 - def getColumnLabels (self):
4203 """ 4204 Returns a list of labels for the columns on this plate. E.g. [1, 2, 3...] or ['A', 'B', 'C'...] etc 4205 """ 4206 if self.columnNamingConvention is not None and self.columnNamingConvention.lower()=='number': 4207 return range(1, self.getGridSize()['columns']+1) 4208 else: 4209 # this should simply be precalculated! 4210 return [_letterGridLabel(x) for x in range(self.getGridSize()['columns'])]
4211
4212 - def getRowLabels (self):
4213 """ 4214 Returns a list of labels for the rows on this plate. E.g. [1, 2, 3...] or ['A', 'B', 'C'...] etc 4215 """ 4216 if self.rowNamingConvention is not None and self.rowNamingConvention.lower()=='number': 4217 return range(1, self.getGridSize()['rows']+1) 4218 else: 4219 # this should simply be precalculated! 4220 return [_letterGridLabel(x) for x in range(self.getGridSize()['rows'])]
4221 4222 @timeit
4223 - def getNumberOfFields (self):
4224 """ 4225 Iterates all wells on plate and returns highest well sample count 4226 """ 4227 q = self._conn.getQueryService() 4228 query = "select maxindex(p.wells.wellSamples)+1" 4229 query += " from Plate p" 4230 query += " where p.id=%d group by p.id" % self.getId() 4231 return unwrap(q.projection(query, None))[0][0]
4232 4233 # if self._childcache is None: 4234 # q = self._conn.getQueryService() 4235 # params = omero.sys.Parameters() 4236 # params.map = {} 4237 # params.map["oid"] = omero_type(self.getId()) 4238 # query = "select well from Well as well "\ 4239 # "left outer join fetch well.wellSamples as ws " \ 4240 # "where well.plate.id = :oid" 4241 # children = q.findAllByQuery(query, params) 4242 # else: 4243 # children = self._listChildren() 4244 # f = 0 4245 # for child in children: 4246 # f = max(len(child._wellSamplesSeq), f) 4247 # return f 4248
4249 - def exportOmeTiff (self):
4250 """ 4251 Make sure full project export doesn't pick up wellsample images 4252 TODO: do we want to support this at all? 4253 """ 4254 return None
4255
4256 - def _getQueryString(self):
4257 """ 4258 Returns a query string for constructing custom queries, loading the screen for each plate. 4259 """ 4260 query = "select obj from Plate as obj " \ 4261 "join fetch obj.details.owner join fetch obj.details.group "\ 4262 "join fetch obj.details.creationEvent "\ 4263 "left outer join fetch obj.screenLinks spl " \ 4264 "left outer join fetch spl.parent sc" 4265 return query
4266 4267 4268 PlateWrapper = _PlateWrapper
4269 4270 -class _WellWrapper (BlitzObjectWrapper):
4271 """ 4272 omero_model_WellI class wrapper extends BlitzObjectWrapper. 4273 """ 4274
4275 - def __bstrap__ (self):
4276 self.OMERO_CLASS = 'Well' 4277 self.LINK_CLASS = None 4278 self.CHILD_WRAPPER_CLASS = 'WellSampleWrapper' 4279 self.PARENT_WRAPPER_CLASS = 'PlateWrapper'
4280
4281 - def __prepare__ (self, **kwargs):
4282 try: 4283 self.index = int(kwargs['index']) 4284 except: 4285 self.index = 0 4286 self.__reset__()
4287
4288 - def __reset__ (self):
4289 """ 4290 Clears child cache, so next _listChildren will query the server 4291 """ 4292 self._childcache = None
4293
4294 - def __loadedHotSwap__ (self):
4295 query = "select well from Well as well "\ 4296 "join fetch well.details.creationEvent "\ 4297 "join fetch well.details.owner join fetch well.details.group " \ 4298 "left outer join fetch well.wellSamples as ws " \ 4299 "left outer join fetch ws.image as img "\ 4300 "where well.id = %d" % self.getId() 4301 4302 self._obj = self._conn.getQueryService().findByQuery(query, None)
4303
4304 - def _listChildren (self, **kwargs):
4305 if self._childcache is None: 4306 if not self.isWellSamplesLoaded(): 4307 self.__loadedHotSwap__() 4308 if self.isWellSamplesLoaded(): 4309 self._childcache = self.copyWellSamples() 4310 return self._childcache
4311
4312 - def simpleMarshal (self, xtra=None, parents=False):
4313 rv = self.getImage().simpleMarshal(xtra=xtra) 4314 plate = self.getParent() 4315 rv['wellPos'] = "%s%s" % (plate.getRowLabels()[self.row],plate.getColumnLabels()[self.column]) 4316 rv['plateId'] = plate.getId() 4317 rv['wellId'] = self.getId() 4318 return rv
4319
4320 - def listParents (self, withlinks=False):
4321 """ 4322 Because wells are direct children of plates, with no links in between, 4323 a special listParents is needed 4324 """ 4325 rv = self._conn.getObject('Plate', self.plate.id.val) 4326 if withlinks: 4327 return [(rv, None)] 4328 return [rv]
4329
4330 - def getScreens (self):
4331 """ returns the screens that link to plates that link to this well """ 4332 params = omero.sys.Parameters() 4333 params.map = {'id': omero_type(self.getId())} 4334 query = """select s from Well w 4335 left outer join w.plate p 4336 left outer join p.screenLinks spl 4337 left outer join spl.parent s 4338 where spl.parent.id=s.id and spl.child.id=p.id and w.plate.id=p.id 4339 and w.id=:id""" 4340 return [omero.gateway.ScreenWrapper(self._conn, x) for x in \ 4341 self._conn.getQueryService().findAllByQuery(query, params)]
4342 4343
4344 - def isWellSample (self):
4345 """ 4346 Return True if well samples exist (loaded) 4347 4348 @return: True if well samples loaded 4349 @rtype: Boolean 4350 """ 4351 4352 if self.isWellSamplesLoaded(): 4353 childnodes = self.copyWellSamples() 4354 logger.debug('listChildren for %s %d: already loaded, %d samples' % (self.OMERO_CLASS, self.getId(), len(childnodes))) 4355 if len(childnodes) > 0: 4356 return True 4357 return False
4358
4359 - def countWellSample (self):
4360 """ 4361 Return the number of well samples loaded 4362 4363 @return: well sample count 4364 @rtype: Int 4365 """ 4366 return len(self._listChildren())
4367
4368 - def getWellSample (self, index=None):
4369 """ 4370 Return the well sample at the specified index. If index is ommited, 4371 the currently selected index is used instead (self.index) and if 4372 that is not defined, the first one (index 0) is returned. 4373 4374 @param index: the well sample index 4375 @type index: integer 4376 @return: The Well Sample 4377 @rtype: L{WellSampleWrapper} 4378 """ 4379 if index is None: 4380 index = self.index 4381 if index is None: 4382 index = 0 4383 index = int(index) 4384 childnodes = self._listChildren() 4385 if len(childnodes) > index: 4386 return self._getChildWrapper()(self._conn, childnodes[index]) 4387 return None
4388
4389 - def getImage (self, index=None):
4390 """ 4391 Return the image at the specified well sample index. If index is ommited, 4392 the currently selected index is used instead (self.index) and if 4393 that is not defined, the first one (index 0) is returned. 4394 4395 @param index: the well sample index 4396 @type index: integer 4397 @return: The Image 4398 @rtype: L{ImageWrapper} 4399 """ 4400 wellsample = self.getWellSample(index) 4401 if wellsample: 4402 return wellsample.getImage() 4403 return None
4404
4405 - def selectedWellSample (self):
4406 """ 4407 Return the well sample at the current index (0 if not set) 4408 4409 @return: The Well Sample wrapper 4410 @rtype: L{WellSampleWrapper} 4411 4412 """ 4413 return self.getWellSample()
4414 4415 # def loadWellSamples (self): 4416 # """ 4417 # Return a generator yielding child objects 4418 # 4419 # @return: Well Samples 4420 # @rtype: L{WellSampleWrapper} generator 4421 # """ 4422 # 4423 # if getattr(self, 'isWellSamplesLoaded')(): 4424 # childnodes = getattr(self, 'copyWellSamples')() 4425 # logger.debug('listChildren for %s %d: already loaded, %d samples' % (self.OMERO_CLASS, self.getId(), len(childnodes))) 4426 # for ch in childnodes: 4427 # yield WellSampleWrapper(self._conn, ch) 4428 # 4429 # def plate(self): 4430 # """ 4431 # Gets the Plate. 4432 # 4433 # @return: The Plate 4434 # @rtype: L{PlateWrapper} 4435 # """ 4436 # 4437 # return PlateWrapper(self._conn, self._obj.plate) 4438 4439 WellWrapper = _WellWrapper
4440 4441 -class _WellSampleWrapper (BlitzObjectWrapper):
4442 """ 4443 omero_model_WellSampleI class wrapper extends BlitzObjectWrapper. 4444 """ 4445
4446 - def __bstrap__ (self):
4447 self.OMERO_CLASS = 'WellSample' 4448 self.CHILD_WRAPPER_CLASS = 'ImageWrapper' 4449 self.PARENT_WRAPPER_CLASS = 'WellWrapper' 4450 self.LINK_CLASS = 'WellSample' 4451 self.LINK_PARENT = lambda x: x 4452 self.LINK_CHILD = 'image'
4453
4454 - def listParents (self, withlinks=False):
4455 """ 4456 Because wellsamples are direct children of wells, with no links in between, 4457 a special listParents is needed 4458 """ 4459 rv = self._conn.getQueryService().findAllByQuery("""select w from Well w 4460 left outer join fetch w.wellSamples as ws 4461 where ws.id=%d""" % self.getId(), None) 4462 if not len(rv): 4463 rv = [None] 4464 #rv = self._conn.getObject('Plate', self.plate.id.val) 4465 pwc = self._getParentWrappers() 4466 if withlinks: 4467 return [(pwc[0](self._conn, x), None) for x in rv] 4468 return [pwc[0](self._conn, x) for x in rv]
4469
4470 - def getImage (self):
4471 """ 4472 Gets the Image for this well sample. 4473 4474 @return: The Image 4475 @rtype: L{ImageWrapper} 4476 """ 4477 return self._getChildWrapper()(self._conn, self._obj.image)
4478
4479 - def image(self):
4480 """ 4481 Gets the Image for this well sample. 4482 4483 @return: The Image 4484 @rtype: L{ImageWrapper} 4485 """ 4486 return self.getImage()
4487 4488 WellSampleWrapper = _WellSampleWrapper
4489 4490 #class CategoryWrapper (BlitzObjectWrapper): 4491 # def __bstrap__ (self): 4492 # self.LINK_CLASS = "CategoryImageLink" 4493 # self.CHILD_WRAPPER_CLASS = ImageWrapper 4494 # self.PARENT_WRAPPER_CLASS= 'CategoryGroupWrapper' 4495 # 4496 #class CategoryGroupWrapper (BlitzObjectWrapper): 4497 # def __bstrap__ (self): 4498 # self.LINK_CLASS = "CategoryGroupCategoryLink" 4499 # self.CHILD_WRAPPER_CLASS = CategoryWrapper 4500 # self.PARENT_WRAPPER_CLASS = None 4501 4502 ## IMAGE ## 4503 4504 -class ColorHolder (object):
4505 """ 4506 Stores color internally as (R,G,B,A) and allows setting and getting in multiple formats 4507 """ 4508 4509 _color = {'red': 0, 'green': 0, 'blue': 0, 'alpha': 255} 4510
4511 - def __init__ (self, colorname=None):
4512 """ 4513 If colorname is 'red', 'green' or 'blue', set color accordingly - Otherwise black 4514 4515 @param colorname: 'red', 'green' or 'blue' 4516 @type colorname: String 4517 """ 4518 4519 self._color = {'red': 0, 'green': 0, 'blue': 0, 'alpha': 255} 4520 if colorname and colorname.lower() in self._color.keys(): 4521 self._color[colorname.lower()] = 255
4522 4523 @classmethod
4524 - def fromRGBA(klass,r,g,b,a):
4525 """ 4526 Class method for creating a ColorHolder from r,g,b,a values 4527 4528 @param r: red 0 - 255 4529 @type r: int 4530 @param g: green 0 - 255 4531 @type g: int 4532 @param b: blue 0 - 255 4533 @type b: int 4534 @param a: alpha 0 - 255 4535 @type a: int 4536 @return: new Color object 4537 @rtype: L{ColorHolder} 4538 """ 4539 4540 rv = klass() 4541 rv.setRed(r) 4542 rv.setGreen(g) 4543 rv.setBlue(b) 4544 rv.setAlpha(a) 4545 return rv
4546
4547 - def getRed (self):
4548 """ 4549 Gets the Red component 4550 4551 @return: red 4552 @rtype: int 4553 """ 4554 4555 return self._color['red']
4556
4557 - def setRed (self, val):
4558 """ 4559 Set red, as int 0..255 4560 4561 @param val: value of Red. 4562 @type val: Int 4563 """ 4564 4565 self._color['red'] = max(min(255, int(val)), 0)
4566
4567 - def getGreen (self):
4568 """ 4569 Gets the Green component 4570 4571 @return: green 4572 @rtype: int 4573 """ 4574 4575 return self._color['green']
4576
4577 - def setGreen (self, val):
4578 """ 4579 Set green, as int 0..255 4580 4581 @param val: value of Green. 4582 @type val: Int 4583 """ 4584 4585 self._color['green'] = max(min(255, int(val)), 0)
4586
4587 - def getBlue (self):
4588 """ 4589 Gets the Blue component 4590 4591 @return: blue 4592 @rtype: int 4593 """ 4594 4595 return self._color['blue']
4596
4597 - def setBlue (self, val):
4598 """ 4599 Set Blue, as int 0..255 4600 4601 @param val: value of Blue. 4602 @type val: Int 4603 """ 4604 4605 self._color['blue'] = max(min(255, int(val)), 0)
4606
4607 - def getAlpha (self):
4608 """ 4609 Gets the Alpha component 4610 4611 @return: alpha 4612 @rtype: int 4613 """ 4614 4615 return self._color['alpha']
4616
4617 - def setAlpha (self, val):
4618 """ 4619 Set alpha, as int 0..255. 4620 @param val: value of alpha. 4621 """ 4622 4623 self._color['alpha'] = max(min(255, int(val)), 0)
4624
4625 - def getHtml (self):
4626 """ 4627 Gets the html usable color. Dumps the alpha information. E.g. 'FF0000' 4628 4629 @return: html color 4630 @rtype: String 4631 """ 4632 4633 return "%(red)0.2X%(green)0.2X%(blue)0.2X" % (self._color)
4634
4635 - def getCss (self):
4636 """ 4637 Gets the css string: rgba(r,g,b,a) 4638 4639 @return: css color 4640 @rtype: String 4641 """ 4642 4643 c = self._color.copy() 4644 c['alpha'] /= 255.0 4645 return "rgba(%(red)i,%(green)i,%(blue)i,%(alpha)0.3f)" % (c)
4646
4647 - def getRGB (self):
4648 """ 4649 Gets the (r,g,b) as a tuple. 4650 4651 @return: Tuple of (r,g,b) values 4652 @rtype: tuple of ints 4653 """ 4654 4655 return (self._color['red'], self._color['green'], self._color['blue'])
4656
4657 -class _LogicalChannelWrapper (BlitzObjectWrapper):
4658 """ 4659 omero_model_LogicalChannelI class wrapper extends BlitzObjectWrapper. 4660 Specifies a number of _attrs for the channel metadata. 4661 """ 4662 _attrs = ('name', 4663 'pinHoleSize', 4664 '#illumination', 4665 'contrastMethod', 4666 'excitationWave', 4667 'emissionWave', 4668 'fluor', 4669 'ndFilter', 4670 'otf', 4671 'detectorSettings|DetectorSettingsWrapper', 4672 'lightSourceSettings|LightSettingsWrapper', 4673 'filterSet|FilterSetWrapper', 4674 'secondaryEmissionFilter|FilterWrapper', 4675 'secondaryExcitationFilter', 4676 'samplesPerPixel', 4677 '#photometricInterpretation', 4678 'mode', 4679 'pockelCellSetting', 4680 'shapes', 4681 'version') 4682
4683 - def __loadedHotSwap__ (self):
4684 """ Loads the logical channel using the metadata service """ 4685 if self._obj is not None: 4686 self._obj = self._conn.getMetadataService().loadChannelAcquisitionData([self._obj.id.val])[0]
4687
4688 - def getLightPath(self):
4689 """ Make sure we have the channel fully loaded, then return L{LightPathWrapper}""" 4690 self.__loadedHotSwap__() 4691 if self._obj.lightPath is not None: 4692 return LightPathWrapper(self._conn, self._obj.lightPath)
4693 4694 LogicalChannelWrapper = _LogicalChannelWrapper
4695 4696 -class _LightPathWrapper (BlitzObjectWrapper):
4697 """ 4698 base Light Source class wrapper, extends BlitzObjectWrapper. 4699 """ 4700 _attrs = ('dichroic|DichroicWrapper',) 4701
4702 - def __bstrap__ (self):
4703 self.OMERO_CLASS = 'LightPath'
4704
4705 - def copyExcitationFilters(self):
4706 """ Returns list of excitation L{FilterWrapper}s """ 4707 return [FilterWrapper(self._conn, link.child) for link in self.copyExcitationFilterLink()]
4708
4709 - def copyEmissionFilters(self):
4710 """ Returns list of emission L{FilterWrapper}s """ 4711 return [FilterWrapper(self._conn, link.child) for link in self.copyEmissionFilterLink()]
4712 4713 LightPathWrapper = _LightPathWrapper
4714 4715 -class _PixelsWrapper (BlitzObjectWrapper):
4716 """ 4717 omero_model_PixelsI class wrapper extends BlitzObjectWrapper. 4718 """ 4719
4720 - def __bstrap__ (self):
4721 self.OMERO_CLASS = 'Pixels'
4722
4723 - def _prepareRawPixelsStore(self):
4724 """ 4725 Creates RawPixelsStore and sets the id etc 4726 """ 4727 ps = self._conn.createRawPixelsStore() 4728 ps.setPixelsId(self._obj.id.val, True) 4729 return ps
4730
4731 - def getPixelsType (self):
4732 """ 4733 This simply wraps the PixelsType object in a BlitzObjectWrapper. 4734 Shouldn't be needed when this is done automatically 4735 """ 4736 return BlitzObjectWrapper(self._conn, self._obj.getPixelsType())
4737
4738 - def copyPlaneInfo (self, theC=None, theT=None, theZ=None):
4739 """ 4740 Loads plane infos and returns sequence of omero.model.PlaneInfo objects wrapped in BlitzObjectWrappers 4741 ordered by planeInfo.deltaT. 4742 Set of plane infos can be filtered by C, T or Z 4743 4744 @param theC: Filter plane infos by Channel index 4745 @param theT: Filter plane infos by Time index 4746 @param theZ: Filter plane infos by Z index 4747 """ 4748 4749 params = omero.sys.Parameters() 4750 params.map = {} 4751 params.map["pid"] = rlong(self._obj.id) 4752 query = "select info from PlaneInfo as info where pixels.id=:pid" 4753 if theC != None: 4754 params.map["theC"] = rint(theC) 4755 query += " and info.theC=:theC" 4756 if theT != None: 4757 params.map["theT"] = rint(theT) 4758 query += " and info.theT=:theT" 4759 if theZ != None: 4760 params.map["theZ"] = rint(theZ) 4761 query += " and info.theZ=:theZ" 4762 query += " order by info.deltaT" 4763 queryService = self._conn.getQueryService() 4764 result = queryService.findAllByQuery(query, params) 4765 for pi in result: 4766 yield BlitzObjectWrapper(self._conn, pi)
4767
4768 - def getPlanes (self, zctList):
4769 """ 4770 Returns generator of numpy 2D planes from this set of pixels for a list of Z, C, T indexes. 4771 4772 @param zctList: A list of indexes: [(z,c,t), ] 4773 """ 4774 4775 zctTileList = [] 4776 for zct in zctList: 4777 z,c,t = zct 4778 zctTileList.append((z,c,t, None)) 4779 return self.getTiles(zctTileList)
4780
4781 - def getPlane (self, theZ=0, theC=0, theT=0):
4782 """ 4783 Gets the specified plane as a 2D numpy array by calling L{getPlanes} 4784 If a range of planes are required, L{getPlanes} is approximately 30% faster. 4785 """ 4786 planeList = list( self.getPlanes([(theZ, theC, theT)]) ) 4787 return planeList[0]
4788
4789 - def getTiles (self, zctTileList):
4790 """ 4791 Returns generator of numpy 2D planes from this set of pixels for a list of (Z, C, T, tile) 4792 where tile is (x, y, width, height) or None if you want the whole plane. 4793 4794 @param zctrList: A list of indexes: [(z,c,t, region), ] 4795 """ 4796 4797 import numpy 4798 from struct import unpack 4799 4800 pixelTypes = {"int8":['b',numpy.int8], 4801 "uint8":['B',numpy.uint8], 4802 "int16":['h',numpy.int16], 4803 "uint16":['H',numpy.uint16], 4804 "int32":['i',numpy.int32], 4805 "uint32":['I',numpy.uint32], 4806 "float":['f',numpy.float], 4807 "double":['d', numpy.double]} 4808 4809 rawPixelsStore = self._prepareRawPixelsStore() 4810 sizeX = self.sizeX 4811 sizeY = self.sizeY 4812 pixelType = self.getPixelsType().value 4813 numpyType = pixelTypes[pixelType][1] 4814 exc = None 4815 try: 4816 for zctTile in zctTileList: 4817 z,c,t,tile = zctTile 4818 if tile is None: 4819 rawPlane = rawPixelsStore.getPlane(z, c, t) 4820 planeY = sizeY 4821 planeX = sizeX 4822 else: 4823 x, y, width, height = tile 4824 rawPlane = rawPixelsStore.getTile(z, c, t, x, y, width, height) 4825 planeY = height 4826 planeX = width 4827 convertType ='>%d%s' % ((planeY*planeX), pixelTypes[pixelType][0]) #+str(sizeX*sizeY)+pythonTypes[pixelType] 4828 convertedPlane = unpack(convertType, rawPlane) 4829 remappedPlane = numpy.array(convertedPlane, numpyType) 4830 remappedPlane.resize(planeY, planeX) 4831 yield remappedPlane 4832 except Exception, e: 4833 logger.error("Failed to getPlane() or getTile() from rawPixelsStore", exc_info=True) 4834 exc = e 4835 try: 4836 rawPixelsStore.close() 4837 except Exception, e: 4838 logger.error("Failed to close rawPixelsStore", exc_info=True) 4839 if exc is None: 4840 exc = e 4841 if exc is not None: 4842 raise exc
4843
4844 - def getTile (self, theZ=0, theC=0, theT=0, tile=None):
4845 """ 4846 Gets the specified plane as a 2D numpy array by calling L{getPlanes} 4847 If a range of tile are required, L{getTiles} is approximately 30% faster. 4848 """ 4849 tileList = list( self.getTiles([(theZ, theC, theT, tile)]) ) 4850 return tileList[0]
4851 4852 PixelsWrapper = _PixelsWrapper
4853 4854 4855 -class _ChannelWrapper (BlitzObjectWrapper):
4856 """ 4857 omero_model_ChannelI class wrapper extends BlitzObjectWrapper. 4858 """ 4859 4860 BLUE_MIN = 400 4861 BLUE_MAX = 500 4862 GREEN_MIN = 501 4863 GREEN_MAX = 600 4864 RED_MIN = 601 4865 RED_MAX = 700 4866 COLOR_MAP = ((BLUE_MIN, BLUE_MAX, ColorHolder('Blue')), 4867 (GREEN_MIN, GREEN_MAX, ColorHolder('Green')), 4868 (RED_MIN, RED_MAX, ColorHolder('Red')), 4869 ) 4870
4871 - def __bstrap__ (self):
4872 self.OMERO_CLASS = 'Channel'
4873
4874 - def __prepare__ (self, idx=-1, re=None, img=None):
4875 """ 4876 Sets values of idx, re and img 4877 """ 4878 self._re = re 4879 self._idx = idx 4880 self._img = img
4881
4882 - def save (self):
4883 """ 4884 Extends the superclass save method to save Pixels. Returns result of saving superclass (TODO: currently this is None) 4885 """ 4886 4887 self._obj.setPixels(omero.model.PixelsI(self._obj.getPixels().getId(), False)) 4888 return super(_ChannelWrapper, self).save()
4889
4890 - def isActive (self):
4891 """ 4892 Returns True if the channel is active (turned on in rendering settings) 4893 4894 @return: True if Channel is Active 4895 @rtype: Boolean 4896 """ 4897 4898 if self._re is None: 4899 return False 4900 return self._re.isActive(self._idx)
4901
4902 - def getLogicalChannel (self):
4903 """ 4904 Returns the logical channel 4905 4906 @return: Logical Channel 4907 @rtype: L{LogicalChannelWrapper} 4908 """ 4909 4910 if self._obj.logicalChannel is not None: 4911 return LogicalChannelWrapper(self._conn, self._obj.logicalChannel)
4912
4913 - def getLabel (self):
4914 """ 4915 Returns the logical channel name, emission wave or index. The first that is not null 4916 in the described order. 4917 4918 @return: The logical channel string representation 4919 @rtype: String 4920 """ 4921 4922 lc = self.getLogicalChannel() 4923 rv = lc.name 4924 if rv is None: 4925 rv = lc.emissionWave 4926 if rv is None: 4927 rv = self._idx 4928 return unicode(rv)
4929 4930
4931 - def getName (self):
4932 """ 4933 Returns the logical channel name or None 4934 4935 @return: The logical channel string representation 4936 @rtype: String 4937 """ 4938 4939 lc = self.getLogicalChannel() 4940 rv = lc.name 4941 if rv is not None: 4942 return unicode(rv)
4943 4944
4945 - def getEmissionWave (self):
4946 """ 4947 Returns the emission wave or None. 4948 4949 @return: Emission wavelength or None 4950 @rtype: int 4951 """ 4952 4953 lc = self.getLogicalChannel() 4954 return lc.emissionWave
4955
4956 - def getExcitationWave (self):
4957 """ 4958 Returns the excitation wave or None. 4959 4960 @return: Excitation wavelength or None 4961 @rtype: int 4962 """ 4963 4964 lc = self.getLogicalChannel() 4965 return lc.excitationWave
4966
4967 - def getColor (self):
4968 """ 4969 Returns the rendering settings color of this channel 4970 4971 @return: Channel color 4972 @rtype: L{ColorHolder} 4973 """ 4974 4975 if self._re is None: 4976 return None 4977 return ColorHolder.fromRGBA(*self._re.getRGBA(self._idx))
4978
4979 - def getWindowStart (self):
4980 """ 4981 Returns the rendering settings window-start of this channel 4982 4983 @return: Window start 4984 @rtype: int 4985 """ 4986 4987 return int(self._re.getChannelWindowStart(self._idx))
4988
4989 - def setWindowStart (self, val):
4990 self.setWindow(val, self.getWindowEnd())
4991
4992 - def getWindowEnd (self):
4993 """ 4994 Returns the rendering settings window-end of this channel 4995 4996 @return: Window end 4997 @rtype: int 4998 """ 4999 5000 return int(self._re.getChannelWindowEnd(self._idx))
5001
5002 - def setWindowEnd (self, val):
5003 self.setWindow(self.getWindowStart(), val)
5004
5005 - def setWindow (self, minval, maxval):
5006 self._re.setChannelWindow(self._idx, float(minval), float(maxval))
5007
5008 - def getWindowMin (self):
5009 """ 5010 Returns the minimum pixel value of the channel 5011 5012 @return: Min pixel value 5013 @rtype: double 5014 """ 5015 5016 return self._obj.getStatsInfo().getGlobalMin().val
5017
5018 - def getWindowMax (self):
5019 """ 5020 Returns the maximum pixel value of the channel 5021 5022 @return: Min pixel value 5023 @rtype: double 5024 """ 5025 5026 return self._obj.getStatsInfo().getGlobalMax().val
5027 5028 ChannelWrapper = _ChannelWrapper
5029 5030 -class assert_re (object):
5031 """ 5032 Function decorator to make sure that rendering engine is prepared before 5033 call. Is configurable by various options. 5034 """ 5035
5036 - def __init__(self, onPrepareFailureReturnNone=True, ignoreExceptions=None):
5037 """ 5038 Initialises the decorator. 5039 5040 @param onPrepareFailureReturnNone: Whether or not on a failure to 5041 prepare the rendering engine the decorator should return 'None' or 5042 allow the execution of the decorated function or method. Defaults to 5043 'True'. 5044 @type onPrepareFailureReturnNone: Boolean 5045 @param ignoreExceptions: A set of exceptions thrown during the 5046 preparation of the rendering engine for whith the decorator should 5047 ignore and allow the execution of the decorated function or method. 5048 Defaults to 'None'. 5049 @type ignoreExceptions: Set 5050 """ 5051 self.onPrepareFailureReturnNone = onPrepareFailureReturnNone 5052 self.ignoreExceptions = ignoreExceptions
5053
5054 - def __call__(ctx, f):
5055 """ 5056 Tries to prepare rendering engine, then calls function and return the 5057 result. 5058 """ 5059 def wrapped(self, *args, **kwargs): 5060 try: 5061 if not self._prepareRenderingEngine() \ 5062 and ctx.onPrepareFailureReturnNone: 5063 logger.debug('Preparation of rendering engine failed, ' \ 5064 'returning None for %r!' % f) 5065 return None 5066 except ctx.ignoreExceptions, e: 5067 logger.debug('Ignoring exception thrown during preparation ' \ 5068 'of rendering engine for %r!' % f, exc_info=True) 5069 pass 5070 return f(self, *args, **kwargs)
5071 return wrapped
5072
5073 -def assert_pixels (func):
5074 """ 5075 Function decorator to make sure that pixels are loaded before call 5076 5077 @param func: Function 5078 @type func: Function 5079 @return: Decorated function 5080 @rtype: Function 5081 """ 5082 5083 def wrapped (self, *args, **kwargs): 5084 """ Tries to load pixels, then call function and return the result""" 5085 5086 if not self._loadPixels(): 5087 return None 5088 return func(self, *args, **kwargs)
5089 return wrapped 5090
5091 5092 -class _ImageWrapper (BlitzObjectWrapper):
5093 """ 5094 omero_model_ImageI class wrapper extends BlitzObjectWrapper. 5095 """ 5096 5097 _re = None 5098 _pd = None 5099 _rm = {} 5100 _pixels = None 5101 _archivedFileCount = None 5102 5103 _pr = None # projection 5104 5105 _invertedAxis = False 5106 5107 PROJECTIONS = { 5108 'normal': -1, 5109 'intmax': omero.constants.projection.ProjectionType.MAXIMUMINTENSITY, 5110 'intmean': omero.constants.projection.ProjectionType.MEANINTENSITY, 5111 'intsum': omero.constants.projection.ProjectionType.SUMINTENSITY, 5112 } 5113 5114 PLANEDEF = omero.romio.XY 5115 5116 @classmethod
5117 - def fromPixelsId (self, conn, pid):
5118 """ 5119 Creates a new Image wrapper with the image specified by pixels ID 5120 5121 @param conn: The connection 5122 @type conn: L{BlitzGateway} 5123 @param pid: Pixles ID 5124 @type pid: Long 5125 @return: New Image wrapper 5126 @rtype: L{ImageWrapper} 5127 """ 5128 5129 q = conn.getQueryService() 5130 p = q.find('Pixels', pid) 5131 if p is None: 5132 return None 5133 return ImageWrapper(conn, p.image)
5134
5135 - def __bstrap__ (self):
5136 self.OMERO_CLASS = 'Image' 5137 self.LINK_CLASS = None 5138 self.CHILD_WRAPPER_CLASS = None 5139 self.PARENT_WRAPPER_CLASS = ['DatasetWrapper', 'WellSampleWrapper']
5140
5141 - def __del__ (self):
5142 self._re and self._re.untaint()
5143
5144 - def __loadedHotSwap__ (self):
5145 self._obj = self._conn.getContainerService().getImages(self.OMERO_CLASS, (self._oid,), None)[0]
5146
5147 - def getInstrument (self):
5148 """ 5149 Returns the Instrument for this image (or None) making sure the instrument is loaded. 5150 5151 @return: Instrument (microscope) 5152 @rtype: L{InstrumentWrapper} 5153 """ 5154 5155 i = self._obj.instrument 5156 if i is None: 5157 return None 5158 if not i.loaded: 5159 meta_serv = self._conn.getMetadataService() 5160 i = self._obj.instrument = meta_serv.loadInstrument(i.id.val) 5161 return InstrumentWrapper(self._conn, i)
5162
5163 - def _loadPixels (self):
5164 """ 5165 Checks that pixels are loaded 5166 5167 @return: True if loaded 5168 @rtype: Boolean 5169 """ 5170 5171 if not self._obj.pixelsLoaded: 5172 self.__loadedHotSwap__() 5173 return self._obj.sizeOfPixels() > 0
5174 5175
5176 - def _getRDef (self, pid):
5177 """ 5178 Return a rendering def ID based on custom logic. 5179 5180 @param pid: Pixels ID 5181 @type pid: Long 5182 @return: Rendering definition ID or None if no custom 5183 logic has found a rendering definition. 5184 """ 5185 rdefns = self._conn.CONFIG.get('IMG_RDEFNS', None) 5186 if rdefns is None: 5187 return 5188 rdid = ann.getValue() 5189 if rdid is None: 5190 return 5191 logger.debug('_getRDef: %s, %s' % (str(pid), str(rdid))) 5192 logger.debug('now load render options: %s' % str(self._loadRenderOptions())) 5193 self.loadRenderOptions() 5194 return rdid
5195
5196 - def _onResetDefaults(self, pid, rdid):
5197 """ 5198 Called whenever a reset defaults is called by the preparation of 5199 the rendering engine or the thumbnail bean. 5200 5201 @param pid: Pixels ID 5202 @type pid: Long 5203 @param pid: Current Rendering Def ID 5204 @type pid: Long 5205 """ 5206 rdefns = self._conn.CONFIG.get('IMG_RDEFNS', None) 5207 if rdefns is None: 5208 return 5209 ann = self.getAnnotation(rdefns) 5210 if ann is None: 5211 a = LongAnnotationWrapper(self) 5212 a.setNs(rdefns) 5213 a.setValue(rdid) 5214 self.linkAnnotation(a, sameOwner=False)
5215
5216 - def _prepareRE (self):
5217 """ 5218 Prepare the rendering engine with pixels ID and existing or new rendering def. 5219 5220 @return: The Rendering Engine service 5221 @rtype: L{ProxyObjectWrapper} 5222 """ 5223 5224 pid = self.getPrimaryPixels().id 5225 re = self._conn.createRenderingEngine() 5226 re.lookupPixels(pid) 5227 rdid = self._getRDef(pid) 5228 if rdid is None: 5229 if not re.lookupRenderingDef(pid): 5230 re.resetDefaults() 5231 re.lookupRenderingDef(pid) 5232 self._onResetDefaults(pid, re.getRenderingDefId()) 5233 else: 5234 re.loadRenderingDef(rdid) 5235 re.load() 5236 return re
5237
5238 - def _prepareRenderingEngine (self):
5239 """ 5240 Checks that the rendering engine is prepared, calling L{_prepareRE} if needed. 5241 Used by the L{assert_re} method to wrap calls requiring rendering engine 5242 5243 @return: True if rendering engine is created 5244 @rtype: Boolean 5245 """ 5246 5247 self._loadPixels() 5248 if self._re is None: 5249 if self._obj.sizeOfPixels() < 1: 5250 return False 5251 if self._pd is None: 5252 self._pd = omero.romio.PlaneDef(self.PLANEDEF) 5253 self._re = self._prepareRE() 5254 return self._re is not None
5255
5256 - def resetRDefs (self):
5257 logger.debug('resetRDefs') 5258 if self.canWrite(): 5259 self._conn.getDeleteService().deleteSettings(self.getId()) 5260 return True 5261 return False
5262
5263 - def simpleMarshal (self, xtra=None, parents=False):
5264 """ 5265 Creates a dict representation of the Image, including author and date info. 5266 5267 @return: Dict 5268 @rtype: Dict 5269 """ 5270 5271 rv = super(_ImageWrapper, self).simpleMarshal(xtra=xtra, parents=parents) 5272 rv.update({'author': self.getAuthor(), 5273 'date': time.mktime(self.getDate().timetuple()),}) 5274 if xtra: 5275 if xtra.has_key('thumbUrlPrefix'): 5276 if callable(xtra['thumbUrlPrefix']): 5277 rv['thumb_url'] = xtra['thumbUrlPrefix'](str(self.id)) 5278 else: 5279 rv['thumb_url'] = xtra['thumbUrlPrefix'] + str(self.id) + '/' 5280 return rv
5281
5282 - def getStageLabel (self):
5283 """ 5284 Returns the stage label or None 5285 5286 @return: Stage label 5287 @rtype: L{ImageStageLabelWrapper} 5288 """ 5289 5290 if self._obj.stageLabel is None: 5291 return None 5292 else: 5293 return ImageStageLabelWrapper(self._conn, self._obj.stageLabel)
5294
5295 - def shortname(self, length=20, hist=5):
5296 """ 5297 Provides a truncated name of the image. E.g. ...catedNameOfTheImage.tiff 5298 5299 @param length: The ideal length to return. If truncated, will be ...length 5300 @type length: Int 5301 @param hist: The amount of leeway allowed before trunction (avoid truncating 1 or 2 letters) 5302 @type hist: Int 5303 @return: Truncated ...name 5304 @type: String 5305 """ 5306 5307 name = self.name 5308 if not name: 5309 return "" 5310 l = len(name) 5311 if l < length+hist: 5312 return name 5313 return "..." + name[l - length:]
5314
5315 - def getAuthor(self):
5316 """ 5317 Returns 'Firstname Lastname' of image owner 5318 5319 @return: Image owner 5320 @rtype: String 5321 """ 5322 5323 q = self._conn.getQueryService() 5324 e = q.findByQuery("select e from Experimenter e where e.id = %i" % self._obj.details.owner.id.val,None) 5325 self._author = e.firstName.val + " " + e.lastName.val 5326 return self._author
5327
5328 - def getDataset(self):
5329 """ 5330 XXX: Deprecated since 4.3.2, use listParents(). (See #6660) 5331 Gets the Dataset that image is in, or None. 5332 Returns None if Image is in more than one Dataset. 5333 5334 @return: Dataset 5335 @rtype: L{DatasetWrapper} 5336 """ 5337 5338 try: 5339 q = """ 5340 select ds from Image i join i.datasetLinks dl join dl.parent ds 5341 where i.id = %i 5342 """ % self._obj.id.val 5343 query = self._conn.getQueryService() 5344 ds = query.findByQuery(q,None) 5345 return ds and DatasetWrapper(self._conn, ds) or None 5346 except: #pragma: no cover 5347 logger.debug('on getDataset') 5348 logger.debug(traceback.format_exc()) 5349 return None
5350
5351 - def getProject(self):
5352 """ 5353 Gets the Project that image is in, or None. TODO: Assumes image is in only 1 Project. Why not use getAncestory()[-1] 5354 Returns None if Image is in more than one Dataset & Project. 5355 5356 @return: Project 5357 @rtype: L{ProjectWrapper} 5358 """ 5359 5360 try: 5361 q = """ 5362 select p from Image i join i.datasetLinks dl join dl.parent ds join ds.projectLinks pl join pl.parent p 5363 where i.id = %i 5364 """ % self._obj.id.val 5365 query = self._conn.getQueryService() 5366 prj = query.findByQuery(q,None) 5367 return prj and ProjectWrapper(self._conn, prj) or None 5368 except: #pragma: no cover 5369 logger.debug('on getProject') 5370 logger.debug(traceback.format_exc()) 5371 return None
5372
5373 - def getObjectiveSettings (self):
5374 """ 5375 Gets the Ojbective Settings of the Image, or None 5376 5377 @return: Objective Settings 5378 @rtype: L{ObjectiveSettingsWrapper} 5379 """ 5380 5381 rv = self.objectiveSettings 5382 if self.objectiveSettings is not None: 5383 rv = ObjectiveSettingsWrapper(self._conn, self.objectiveSettings) 5384 if not self.objectiveSettings.loaded: 5385 self.objectiveSettings = rv._obj 5386 return rv
5387
5388 - def getImagingEnvironment (self):
5389 """ 5390 Gets the Imaging Environment of the Image, or None 5391 5392 @return: Imaging Environment 5393 @rtype: L{ImagingEnvironmentWrapper} 5394 """ 5395 5396 rv = self.imagingEnvironment 5397 if self.imagingEnvironment is not None: 5398 rv = ImagingEnvironmentWrapper(self._conn, self.imagingEnvironment) 5399 if not self.imagingEnvironment.loaded: 5400 self.imagingEnvironment = rv._obj 5401 return rv
5402 5403 @assert_pixels
5404 - def getPixelsId (self):
5405 """ 5406 Returns the Primary Pixels ID for the image. 5407 5408 @return: Pixels ID 5409 @rtype: Long 5410 """ 5411 5412 return self._obj.getPrimaryPixels().getId().val
5413
5414 - def _prepareTB (self, _r=False):
5415 """ 5416 Prepares Thumbnail Store for the image. 5417 5418 @param _r: If True, don't reset default rendering (return None if no rDef exists) 5419 @type _r: Boolean 5420 @return: Thumbnail Store or None 5421 @rtype: L{ProxyObjectWrapper} 5422 """ 5423 5424 pid = self.getPrimaryPixels().id 5425 tb = self._conn.createThumbnailStore() 5426 rdid = self._getRDef(pid) 5427 has_rendering_settings = tb.setPixelsId(pid) 5428 if rdid is None: 5429 if not has_rendering_settings: 5430 try: 5431 tb.resetDefaults() # E.g. May throw Missing Pyramid Exception 5432 except omero.ConcurrencyException, ce: 5433 logger.info( "ConcurrencyException: resetDefaults() failed in _prepareTB with backOff: %s" % ce.backOff) 5434 return tb 5435 tb.setPixelsId(pid) 5436 try: 5437 rdid = tb.getRenderingDefId() 5438 except omero.ApiUsageException: # E.g. No rendering def (because of missing pyramid!) 5439 logger.info( "ApiUsageException: getRenderingDefId() failed in _prepareTB") 5440 return tb 5441 self._onResetDefaults(pid, rdid) 5442 else: 5443 tb.setRenderingDefId(rdid) 5444 return tb
5445
5446 - def loadOriginalMetadata(self):
5447 """ 5448 Gets original metadata from the file annotation. 5449 Returns the File Annotation, list of Global Metadata, list of Series Metadata in a tuple. 5450 Metadata lists are lists of (key, value) tuples. 5451 5452 @return: Tuple of (file-annotation, global-metadata, series-metadata) 5453 @rtype: Tuple (L{FileAnnotationWrapper}, [], []) 5454 """ 5455 5456 global_metadata = list() 5457 series_metadata = list() 5458 if self is not None: 5459 for a in self.listAnnotations(): 5460 if isinstance(a._obj, FileAnnotationI) and a.isOriginalMetadata(): 5461 t_file = list() 5462 for piece in a.getFileInChunks(): 5463 t_file.append(piece) 5464 temp_file = "".join(t_file).split('\n') 5465 flag = None 5466 for l in temp_file: 5467 if l.startswith("[GlobalMetadata]"): 5468 flag = 1 5469 elif l.startswith("[SeriesMetadata]"): 5470 flag = 2 5471 else: 5472 if len(l) < 1: 5473 l = None 5474 else: 5475 l = tuple(l.split("=")) 5476 if l is not None: 5477 if flag == 1: 5478 global_metadata.append(l) 5479 elif flag == 2: 5480 series_metadata.append(l) 5481 return (a, (global_metadata), (series_metadata)) 5482 return None
5483 5484 @assert_re()
5485 - def _getProjectedThumbnail (self, size, pos):
5486 """ 5487 Returns a string holding a rendered JPEG of the projected image, sized to mimic a thumbnail. 5488 This is an 'internal' method of this class, used to generate a thumbnail from a full-sized 5489 projected image (since thumbnails don't support projection). SetProjection should be called 5490 before this method is called, so that this returns a projected, scaled image. 5491 5492 @param size: The length of the longest size, in a list or tuple. E.g. (100,) 5493 @type size: list or tuple 5494 @param pos: The (z, t) position 5495 @type pos: Tuple (z,t) 5496 """ 5497 5498 if pos is None: 5499 t = z = 0 5500 else: 5501 z, t = pos 5502 img = self.renderImage(z,t) 5503 if len(size) == 1: 5504 w = self.getSizeX() 5505 h = self.getSizeY() 5506 ratio = float(w) / h 5507 if ratio > 1: 5508 h = h * size[0] / w 5509 w = size[0] 5510 else: 5511 w = w * size[0] / h 5512 h = size[0] 5513 img = img.resize((w,h), Image.NEAREST) 5514 rv = StringIO() 5515 img.save(rv, 'jpeg', quality=70) 5516 return rv.getvalue()
5517
5518 - def getThumbnail (self, size=(64,64), z=None, t=None):
5519 """ 5520 Returns a string holding a rendered JPEG of the thumbnail. 5521 5522 @type size: tuple or number 5523 @param size: A tuple with one or two ints, or an integer. If a tuple holding a single int, 5524 or a single int is passed as param, then that will be used as the longest size 5525 on the rendered thumb, and image aspect ratio is kept. 5526 If two ints are passed in a tuple, they set the width and height of the 5527 rendered thumb. 5528 @type z: number 5529 @param z: the Z position to use for rendering the thumbnail. If not provided default is used. 5530 @type t: number 5531 @param t: the T position to use for rendering the thumbnail. If not provided default is used. 5532 @rtype: string or None 5533 @return: the rendered JPEG, or None if there was an error. 5534 """ 5535 tb = None 5536 try: 5537 tb = self._prepareTB() 5538 if tb is None: 5539 return None 5540 if isinstance(size, IntType): 5541 size = (size,) 5542 if z is not None and t is not None: 5543 pos = z,t 5544 else: 5545 pos = None 5546 # The following was commented out in the context of 5547 # omero:#5191. Preparing the rendering engine has the 5548 # potential to cause the raising of ConcurrencyException's 5549 # which prevent OMERO.web from executing the thumbnail methods 5550 # below and consequently showing "in-progress" thumbnails. 5551 # Tue 24 May 2011 10:42:47 BST -- cxallan 5552 #re = self._prepareRE() 5553 #if re: 5554 # if z is None: 5555 # z = re.getDefaultZ() 5556 # if t is None: 5557 # t = re.getDefaultT() 5558 # pos = z,t 5559 #else: 5560 # pos = None 5561 if self.getProjection() != 'normal': 5562 return self._getProjectedThumbnail(size, pos) 5563 if len(size) == 1: 5564 if pos is None: 5565 thumb = tb.getThumbnailByLongestSideDirect 5566 else: 5567 thumb = tb.getThumbnailForSectionByLongestSideDirect 5568 else: 5569 if pos is None: 5570 thumb = tb.getThumbnailDirect 5571 else: 5572 thumb = tb.getThumbnailForSectionDirect 5573 args = map(lambda x: rint(x), size) 5574 if pos is not None: 5575 args = list(pos) + args 5576 rv = thumb(*args) 5577 tb.close() # close every time to prevent stale state 5578 return rv 5579 except Exception: #pragma: no cover 5580 logger.error(traceback.format_exc()) 5581 if tb is not None: 5582 tb.close() 5583 return None
5584 5585 @assert_pixels
5586 - def getPixelRange (self):
5587 """ 5588 Returns (min, max) values for the pixels type of this image. 5589 TODO: Does not handle floats correctly, though. 5590 5591 @return: Tuple (min, max) 5592 """ 5593 5594 pixels_id = self._obj.getPrimaryPixels().getId().val 5595 rp = self._conn.createRawPixelsStore() 5596 rp.setPixelsId(pixels_id, True) 5597 pmax = 2 ** (8 * rp.getByteWidth()) 5598 if rp.isSigned(): 5599 return (-(pmax / 2), pmax / 2 - 1) 5600 else: 5601 return (0, pmax-1)
5602 5603 @assert_pixels
5604 - def getPrimaryPixels (self):
5605 """ 5606 Loads pixels and returns object in a L{PixelsWrapper} 5607 """ 5608 return PixelsWrapper(self._conn, self._obj.getPrimaryPixels())
5609 5610 @assert_re(ignoreExceptions=(omero.ConcurrencyException))
5611 - def getChannels (self):
5612 """ 5613 Returns a list of Channels, each initialised with rendering engine 5614 5615 @return: Channels 5616 @rtype: List of L{ChannelWrapper} 5617 """ 5618 if self._re is not None: 5619 return [ChannelWrapper(self._conn, c, idx=n, re=self._re, img=self) for n,c in enumerate(self._re.getPixels().iterateChannels())] 5620 else: # E.g. ConcurrencyException (no rendering engine): load channels by hand, use pixels to order channels 5621 pid = self.getPixelsId() 5622 params = omero.sys.Parameters() 5623 params.map = {"pid": rlong(pid)} 5624 query = "select p from Pixels p join fetch p.channels as c join fetch c.logicalChannel as lc where p.id=:pid" 5625 pixels = self._conn.getQueryService().findByQuery(query, params) 5626 return [ChannelWrapper(self._conn, c, idx=n, re=self._re, img=self) for n,c in enumerate(pixels.iterateChannels())]
5627
5628 - def setActiveChannels(self, channels, windows=None, colors=None):
5629 """ 5630 Sets the active channels on the rendering engine. 5631 Also sets rendering windows and channel colors (for channels that are active) 5632 5633 @param channels: List of active channel indexes ** 1-based index ** 5634 @type channels: List of int 5635 @param windows: Start and stop values for active channel rendering settings 5636 @type windows: List of tuples. [(20, 300), (None, None), (50, 500)]. Must be tuples for all channels 5637 @param colors: List of colors. ['F00', None, '00FF00']. Must be item for each channel 5638 """ 5639 5640 for c in range(len(self.getChannels())): 5641 self._re.setActive(c, (c+1) in channels) 5642 if (c+1) in channels: 5643 if windows is not None and windows[c][0] is not None and windows[c][1] is not None: 5644 self._re.setChannelWindow(c, *windows[c]) 5645 if colors is not None and colors[c]: 5646 rgba = splitHTMLColor(colors[c]) 5647 if rgba: 5648 self._re.setRGBA(c, *rgba) 5649 return True
5650
5651 - def getProjections (self):
5652 """ 5653 Returns list of available keys for projection. E.g. ['intmax', 'intmean'] 5654 5655 @return: Projection options 5656 @rtype: List of strings 5657 """ 5658 5659 return self.PROJECTIONS.keys()
5660
5661 - def getProjection (self):
5662 """ 5663 Returns the current projection option (checking it is valid). 5664 5665 @return: Projection key. E.g. 'intmax' 5666 @rtype: String 5667 """ 5668 5669 if self._pr in self.PROJECTIONS.keys(): 5670 return self._pr 5671 return 'normal'
5672
5673 - def setProjection (self, proj):
5674 """ 5675 Sets the current projection option. 5676 5677 @param proj: Projection Option. E.g. 'intmax' or 'normal' 5678 @type proj: String 5679 """ 5680 5681 self._pr = proj
5682
5683 - def isInvertedAxis (self):
5684 """ 5685 Returns the inverted axis flag 5686 5687 @return: Inverted Axis 5688 @rtype: Boolean 5689 """ 5690 5691 return self._invertedAxis
5692
5693 - def setInvertedAxis (self, inverted):
5694 """ 5695 Sets the inverted axis flag 5696 5697 @param inverted: Inverted Axis 5698 @type inverted: Boolean 5699 """ 5700 5701 self._invertedAxis = inverted
5702 5703 LINE_PLOT_DTYPES = { 5704 (4, True, True): 'f', # signed float 5705 (2, False, False): 'H', # unsigned short 5706 (2, False, True): 'h', # signed short 5707 (1, False, False): 'B', # unsigned char 5708 (1, False, True): 'b', # signed char 5709 } 5710
5711 - def getPixelLine (self, z, t, pos, axis, channels=None, range=None):
5712 """ 5713 Grab a horizontal or vertical line from the image pixel data, for the specified channels 5714 (or 'active' if not specified) and using the specified range (or 1:1 relative to the image size). 5715 Axis may be 'h' or 'v', for horizontal or vertical respectively. 5716 5717 @param z: Z index 5718 @param t: T index 5719 @param pos: X or Y position 5720 @param axis: Axis 'h' or 'v' 5721 @param channels: map of {index: L{ChannelWrapper} } 5722 @param range: height of scale (use image height (or width) by default) 5723 @return: rv List of lists (one per channel) 5724 """ 5725 5726 if not self._loadPixels(): 5727 logger.debug( "No pixels!") 5728 return None 5729 axis = axis.lower()[:1] 5730 if channels is None: 5731 channels = map(lambda x: x._idx, filter(lambda x: x.isActive(), self.getChannels())) 5732 if range is None: 5733 range = axis == 'h' and self.getSizeY() or self.getSizeX() 5734 if not isinstance(channels, (TupleType, ListType)): 5735 channels = (channels,) 5736 chw = map(lambda x: (x.getWindowMin(), x.getWindowMax()), self.getChannels()) 5737 rv = [] 5738 pixels_id = self._obj.getPrimaryPixels().getId().val 5739 rp = self._conn.createRawPixelsStore() 5740 rp.setPixelsId(pixels_id, True) 5741 for c in channels: 5742 bw = rp.getByteWidth() 5743 key = self.LINE_PLOT_DTYPES.get((bw, rp.isFloat(), rp.isSigned()), None) 5744 if key is None: 5745 logger.error("Unknown data type: " + str((bw, rp.isFloat(), rp.isSigned()))) 5746 plot = array.array(key, axis == 'h' and rp.getRow(pos, z, c, t) or rp.getCol(pos, z, c, t)) 5747 plot.byteswap() # TODO: Assuming ours is a little endian system 5748 # now move data into the windowMin..windowMax range 5749 offset = -chw[c][0] 5750 if offset != 0: 5751 plot = map(lambda x: x+offset, plot) 5752 normalize = 1.0/chw[c][1]*(range-1) 5753 if normalize != 1.0: 5754 plot = map(lambda x: x*normalize, plot) 5755 if isinstance(plot, array.array): 5756 plot = plot.tolist() 5757 rv.append(plot) 5758 return rv
5759 5760
5761 - def getRow (self, z, t, y, channels=None, range=None):
5762 """ 5763 Grab a horizontal line from the image pixel data, for the specified channels (or active ones) 5764 5765 @param z: Z index 5766 @param t: T index 5767 @param y: Y position of row 5768 @param channels: map of {index: L{ChannelWrapper} } 5769 @param range: height of scale (use image height by default) 5770 @return: rv List of lists (one per channel) 5771 """ 5772 5773 return self.getPixelLine(z,t,y,'h',channels,range)
5774
5775 - def getCol (self, z, t, x, channels=None, range=None):
5776 """ 5777 Grab a horizontal line from the image pixel data, for the specified channels (or active ones) 5778 5779 @param z: Z index 5780 @param t: T index 5781 @param x: X position of column 5782 @param channels: map of {index: L{ChannelWrapper} } 5783 @param range: height of scale (use image width by default) 5784 @return: rv List of lists (one per channel) 5785 """ 5786 5787 return self.getPixelLine(z,t,x,'v',channels,range)
5788 5789 @assert_re()
5790 - def getRenderingModels (self):
5791 """ 5792 Gets a list of available rendering models. 5793 5794 @return: Rendering models 5795 @rtype: List of L{BlitzObjectWrapper} 5796 """ 5797 5798 if not len(self._rm): 5799 for m in [BlitzObjectWrapper(self._conn, m) for m in self._re.getAvailableModels()]: 5800 self._rm[m.value.lower()] = m 5801 return self._rm.values()
5802 5803 @assert_re()
5804 - def getRenderingModel (self):
5805 """ 5806 Get the current rendering model. 5807 5808 @return: Rendering model 5809 @rtype: L{BlitzObjectWrapper} 5810 """ 5811 5812 return BlitzObjectWrapper(self._conn, self._re.getModel())
5813
5814 - def setGreyscaleRenderingModel (self):
5815 """ 5816 Sets the Greyscale rendering model on this image's current renderer 5817 """ 5818 5819 rm = self.getRenderingModels() 5820 self._re.setModel(self._rm.get('greyscale', rm[0])._obj)
5821
5822 - def setColorRenderingModel (self):
5823 """ 5824 Sets the HSB rendering model on this image's current renderer 5825 """ 5826 5827 rm = self.getRenderingModels() 5828 self._re.setModel(self._rm.get('rgb', rm[0])._obj)
5829
5830 - def isGreyscaleRenderingModel (self):
5831 """ 5832 Returns True if the current rendering model is 'greyscale' 5833 5834 @return: isGreyscale 5835 @rtype: Boolean 5836 """ 5837 return self.getRenderingModel().value.lower() == 'greyscale'
5838 5839 @assert_re()
5840 - def renderBirdsEyeView (self, size):
5841 """ 5842 Returns the data from rendering the bird's eye view of the image. 5843 5844 @param size: Maximum size of the longest side of the resulting bird's eye view. 5845 @return: Data containing a bird's eye view jpeg 5846 """ 5847 # Prepare the rendering engine parameters on the ImageWrapper. 5848 re = self._prepareRE() 5849 z = re.getDefaultZ() 5850 t = re.getDefaultT() 5851 x = 0 5852 y = 0 5853 size_x = self.getSizeX() 5854 size_y = self.getSizeY() 5855 tile_width, tile_height = re.getTileSize() 5856 tiles_wide = math.ceil(float(size_x) / tile_width) 5857 tiles_high = math.ceil(float(size_y) / tile_height) 5858 # Since the JPEG 2000 algorithm is iterative and rounds pixel counts 5859 # at each resolution level we're doing the resulting tile size 5860 # calculations in a loop. Also, since the image is physically tiled 5861 # the resulting size is a multiple of the tile size and not the iterative 5862 # quotient of a 2**(resolutionLevels - 1). 5863 for i in range(1, re.getResolutionLevels()): 5864 tile_width = round(tile_width / 2.0) 5865 tile_height = round(tile_height / 2.0) 5866 width = int(tiles_wide * tile_width) 5867 height = int(tiles_high * tile_height) 5868 jpeg_data = self.renderJpegRegion(z, t, x, y, width, height, level=0) 5869 if size is None: 5870 return jpeg_data 5871 # We've been asked to scale the image by its longest side so we'll 5872 # perform that operation until the server has the capability of 5873 # doing so. 5874 ratio = float(size) / max(width, height) 5875 if width > height: 5876 size = (int(size), int(height * ratio)) 5877 else: 5878 size = (int(width * ratio), int(size)) 5879 jpeg_data = Image.open(StringIO(jpeg_data)) 5880 jpeg_data.thumbnail(size, Image.ANTIALIAS) 5881 ImageDraw.Draw(jpeg_data) 5882 f = StringIO() 5883 jpeg_data.save(f, "JPEG") 5884 f.seek(0) 5885 return f.read()
5886 5887 @assert_re()
5888 - def renderJpegRegion (self, z, t, x, y, width, height, level=None, compression=0.9):
5889 """ 5890 Return the data from rendering a region of an image plane. 5891 NB. Projection not supported by the API currently. 5892 5893 @param z: The Z index. Ignored if projecting image. 5894 @param t: The T index. 5895 @param x: The x coordinate of region (int) 5896 @param y: The y coordinate of region (int) 5897 @param width: The width of region (int) 5898 @param height: The height of region (int) 5899 @param compression: Compression level for jpeg 5900 @type compression: Float 5901 """ 5902 5903 self._pd.z = long(z) 5904 self._pd.t = long(t) 5905 5906 regionDef = omero.romio.RegionDef() 5907 regionDef.x = x 5908 regionDef.y = y 5909 regionDef.width = width 5910 regionDef.height = height 5911 self._pd.region = regionDef 5912 try: 5913 if level is not None: 5914 self._re.setResolutionLevel(level) 5915 if compression is not None: 5916 try: 5917 self._re.setCompressionLevel(float(compression)) 5918 except omero.SecurityViolation: #pragma: no cover 5919 self._obj.clearPixels() 5920 self._obj.pixelsLoaded = False 5921 self._re = None 5922 return self.renderJpeg(z,t,None) 5923 rv = self._re.renderCompressed(self._pd) 5924 return rv 5925 except omero.InternalException: #pragma: no cover 5926 logger.debug('On renderJpegRegion'); 5927 logger.debug(traceback.format_exc()) 5928 return None 5929 except Ice.MemoryLimitException: #pragma: no cover 5930 # Make sure renderCompressed isn't called again on this re, as it hangs 5931 self._obj.clearPixels() 5932 self._obj.pixelsLoaded = False 5933 self._re = None 5934 raise
5935 5936 5937 @assert_re()
5938 - def renderJpeg (self, z, t, compression=0.9):
5939 """ 5940 Return the data from rendering image, compressed (and projected). 5941 Projection (or not) is specified by calling L{setProjection} before renderJpeg. 5942 5943 @param z: The Z index. Ignored if projecting image. 5944 @param t: The T index. 5945 @param compression: Compression level for jpeg 5946 @type compression: Float 5947 """ 5948 5949 self._pd.z = long(z) 5950 self._pd.t = long(t) 5951 try: 5952 if compression is not None: 5953 try: 5954 self._re.setCompressionLevel(float(compression)) 5955 except omero.SecurityViolation: #pragma: no cover 5956 self._obj.clearPixels() 5957 self._obj.pixelsLoaded = False 5958 self._re = None 5959 return self.renderJpeg(z,t,None) 5960 projection = self.PROJECTIONS.get(self._pr, -1) 5961 if not isinstance(projection, omero.constants.projection.ProjectionType): 5962 rv = self._re.renderCompressed(self._pd) 5963 else: 5964 rv = self._re.renderProjectedCompressed(projection, self._pd.t, 1, 0, self.getSizeZ()-1) 5965 return rv 5966 except omero.InternalException: #pragma: no cover 5967 logger.debug('On renderJpeg'); 5968 logger.debug(traceback.format_exc()) 5969 return None 5970 except Ice.MemoryLimitException: #pragma: no cover 5971 # Make sure renderCompressed isn't called again on this re, as it hangs 5972 self._obj.clearPixels() 5973 self._obj.pixelsLoaded = False 5974 self._re = None 5975 raise
5976
5977 - def exportOmeTiff (self, bufsize=0):
5978 """ 5979 Exports the OME-TIFF representation of this image. 5980 5981 @type bufsize: int or tuple 5982 @param bufsize: if 0 return a single string buffer with the whole OME-TIFF 5983 if >0 return a tuple holding total size and generator of chunks 5984 (string buffers) of bufsize bytes each 5985 @return: OME-TIFF file data 5986 @rtype: String or (size, data generator) 5987 """ 5988 5989 e = self._conn.createExporter() 5990 e.addImage(self.getId()) 5991 size = e.generateTiff() 5992 if bufsize==0: 5993 # Read it all in one go 5994 return fileread(e, size, 65536) 5995 else: 5996 # generator using bufsize 5997 return (size, fileread_gen(e, size, bufsize))
5998
5999 - def _wordwrap (self, width, text, font):
6000 """ 6001 Wraps text into lines that are less than a certain width (when rendered 6002 in specified font) 6003 6004 @param width: The max width to wrap text (pixels) 6005 @type width: Int 6006 @param text: The text to wrap 6007 @type text: String 6008 @param font: Font to use. 6009 @type font: E.g. PIL ImageFont 6010 @return: List of text lines 6011 @rtype: List of Strings 6012 """ 6013 6014 rv = [] 6015 tokens = filter(None, text.split(' ')) 6016 while len(tokens) > 1: 6017 p1 = 0 6018 p2 = 1 6019 while p2 <= len(tokens) and font.getsize(' '.join(tokens[p1:p2]))[0] < width: 6020 p2 += 1 6021 rv.append(' '.join(tokens[p1:p2-1])) 6022 tokens = tokens[p2-1:] 6023 if len(tokens): 6024 rv.append(' '.join(tokens)) 6025 logger.debug(rv) 6026 return rv
6027 6028 @assert_re()
6029 - def createMovie (self, outpath, zstart, zend, tstart, tend, opts=None):
6030 """ 6031 Creates a movie file from this image. 6032 TODO: makemovie import is commented out in 4.2+ 6033 6034 @type outpath: string 6035 @type zstart: int 6036 @type zend: int 6037 @type tstart: int 6038 @type tend: int 6039 @type opts: dict 6040 @param opts: dictionary of extra options. Currently processed options are: 6041 - watermark:string: path to image to use as watermark 6042 - slides:tuple: tuple of tuples with slides to prefix video with 6043 in format (secs:int, topline:text[, middleline:text[, bottomline:text]]) 6044 - fps:int: frames per second 6045 - minsize: tuple of (minwidth, minheight, bgcolor) 6046 - format:string: one of video/mpeg or video/quicktime 6047 6048 @return: Tuple of (file-ext, format) 6049 @rtype: (String, String) 6050 """ 6051 logger.warning('createMovie support is currently disabled.') 6052 logger.warning(' - see https://trac.openmicroscopy.org.uk/ome/ticket/3857') 6053 return None, None 6054 if opts is None: opts = {} 6055 slides = opts.get('slides', None) 6056 minsize = opts.get('minsize', None) 6057 w, h = self.getSizeX(), self.getSizeY() 6058 watermark = opts.get('watermark', None) 6059 if watermark: 6060 watermark = Image.open(watermark) 6061 if minsize is not None: 6062 ratio = min(float(w) / minsize[0], float(h) / minsize[1]) 6063 if ratio > 1: 6064 watermark = watermark.resize(map(lambda x: x*ratio, watermark.size), Image.ANTIALIAS) 6065 ww, wh = watermark.size 6066 else: 6067 ww, wh = 0, 0 6068 if minsize is not None and (w < minsize[0] or h < minsize[1]): 6069 w = max(w, minsize[0]) 6070 h = max(h, minsize[1]) 6071 else: 6072 minsize = None 6073 wmpos = 0, h - wh 6074 fps = opts.get('fps', 4) 6075 def recb (*args): 6076 return self._re
6077 fsizes = (8,8,12,18,24,32,32,40,48,56,56,64) 6078 fsize = fsizes[max(min(int(w / 256)-1, len(fsizes)), 1) - 1] 6079 scalebars = (1,1,2,2,5,5,5,5,10,10,10,10) 6080 scalebar = scalebars[max(min(int(w / 256)-1, len(scalebars)), 1) - 1] 6081 font = ImageFont.load('%s/pilfonts/B%0.2d.pil' % (THISPATH, fsize) ) 6082 def introcb (pixels, commandArgs): 6083 for t in slides: 6084 slide = Image.new("RGBA", (w,h)) 6085 for i, line in enumerate(t[1:4]): 6086 line = line.decode('utf8').encode('iso8859-1') 6087 wwline = self._wordwrap(w, line, font) 6088 for j, line in enumerate(wwline): 6089 tsize = font.getsize(line) 6090 draw = ImageDraw.Draw(slide) 6091 if i == 0: 6092 y = 10+j*tsize[1] 6093 elif i == 1: 6094 y = h / 2 - ((len(wwline)-j)*tsize[1]) + (len(wwline)*tsize[1])/2 6095 else: 6096 y = h - (len(wwline) - j)*tsize[1] - 10 6097 draw.text((w/2-tsize[0]/2,y), line, font=font) 6098 for i in range(t[0]*fps): 6099 yield slide
6100 if minsize is not None: 6101 bg = Image.new("RGBA", (w, h), minsize[2]) 6102 ovlpos = (w-self.getSizeX()) / 2, (h-self.getSizeY()) / 2 6103 def resize (image): 6104 img = bg.copy() 6105 img.paste(image, ovlpos, image) 6106 return img 6107 else: 6108 def resize (image): 6109 return image 6110 def imgcb (z, t, pixels, image, commandArgs, frameNo): 6111 image = resize(image) 6112 if watermark: 6113 image.paste(watermark, wmpos, watermark) 6114 return image 6115 d = tempfile.mkdtemp() 6116 orig = os.getcwd() 6117 os.chdir(d) 6118 ca = makemovie.buildCommandArgs(self.getId(), scalebar=scalebar) 6119 ca['imageCB'] = imgcb 6120 if slides: 6121 ca['introCB'] = introcb 6122 ca['fps'] = fps 6123 ca['format'] = opts.get('format', 'video/quicktime') 6124 ca['zStart'] = int(zstart) 6125 ca['zEnd'] = int(zend) 6126 ca['tStart'] = int(tstart) 6127 ca['tEnd'] = int(tend) 6128 ca['font'] = font 6129 logger.debug(ca) 6130 try: 6131 fn = os.path.abspath(makemovie.buildMovie(ca, self._conn.c.getSession(), self, self.getPrimaryPixels()._obj, recb)) 6132 except: 6133 logger.error(traceback.format_exc()) 6134 raise 6135 os.chdir(orig) 6136 shutil.move(fn, outpath) 6137 shutil.rmtree(d) 6138 return os.path.splitext(fn)[-1], ca['format'] 6139
6140 - def renderImage (self, z, t, compression=0.9):
6141 """ 6142 Render the Image, (projected) and compressed. 6143 For projection, call L{setProjection} before renderImage. 6144 6145 @param z: Z index 6146 @param t: T index 6147 @compression: Image compression level 6148 @return: A PIL Image or None 6149 @rtype: PIL Image. 6150 """ 6151 6152 rv = self.renderJpeg(z,t,compression) 6153 if rv is not None: 6154 i = StringIO(rv) 6155 rv = Image.open(i) 6156 return rv
6157
6158 - def renderSplitChannel (self, z, t, compression=0.9, border=2):
6159 """ 6160 Prepares a jpeg representation of a 2d grid holding a render of each channel, 6161 along with one for all channels at the set Z and T points. 6162 6163 @param z: Z index 6164 @param t: T index 6165 @param compression: Image compression level 6166 @param border: 6167 @return: value 6168 """ 6169 6170 img = self.renderSplitChannelImage(z,t,compression, border) 6171 rv = StringIO() 6172 img.save(rv, 'jpeg', quality=int(compression*100)) 6173 return rv.getvalue()
6174
6175 - def splitChannelDims (self, border=2):
6176 """ 6177 Returns a dict of layout parameters for generating split channel image. 6178 E.g. row count, column count etc. for greyscale and color layouts. 6179 6180 @param border: spacing between panels 6181 @type border: int 6182 @return: Dict of parameters 6183 @rtype: Dict 6184 """ 6185 6186 c = self.getSizeC() 6187 # Greyscale, no channel overlayed image 6188 x = sqrt(c) 6189 y = int(round(x)) 6190 if x > y: 6191 x = y+1 6192 else: 6193 x = y 6194 rv = {'g':{'width': self.getSizeX()*x + border*(x+1), 6195 'height': self.getSizeY()*y+border*(y+1), 6196 'border': border, 6197 'gridx': x, 6198 'gridy': y,} 6199 } 6200 # Color, one extra image with all channels overlayed 6201 c += 1 6202 x = sqrt(c) 6203 y = int(round(x)) 6204 if x > y: 6205 x = y+1 6206 else: 6207 x = y 6208 rv['c'] = {'width': self.getSizeX()*x + border*(x+1), 6209 'height': self.getSizeY()*y+border*(y+1), 6210 'border': border, 6211 'gridx': x, 6212 'gridy': y,} 6213 return rv
6214
6215 - def _renderSplit_channelLabel (self, channel):
6216 return str(channel.getEmissionWave())
6217
6218 - def renderSplitChannelImage (self, z, t, compression=0.9, border=2):
6219 """ 6220 Prepares a PIL Image with a 2d grid holding a render of each channel, 6221 along with one for all channels at the set Z and T points. 6222 6223 @param z: Z index 6224 @param t: T index 6225 @param compression: Compression level 6226 @param border: space around each panel (int) 6227 @return: canvas 6228 @rtype: PIL Image 6229 """ 6230 6231 dims = self.splitChannelDims(border=border)[self.isGreyscaleRenderingModel() and 'g' or 'c'] 6232 canvas = Image.new('RGBA', (dims['width'], dims['height']), '#fff') 6233 cmap = [ch.isActive() and i+1 or 0 for i,ch in enumerate(self.getChannels())] 6234 c = self.getSizeC() 6235 pxc = 0 6236 px = dims['border'] 6237 py = dims['border'] 6238 6239 # Font sizes depends on image width 6240 w = self.getSizeX() 6241 if w >= 640: 6242 fsize = (int((w-640)/128)*8) + 24 6243 if fsize > 64: 6244 fsize = 64 6245 elif w >= 512: 6246 fsize = 24 6247 elif w >= 384: #pragma: no cover 6248 fsize = 18 6249 elif w >= 298: #pragma: no cover 6250 fsize = 14 6251 elif w >= 256: #pragma: no cover 6252 fsize = 12 6253 elif w >= 213: #pragma: no cover 6254 fsize = 10 6255 elif w >= 96: #pragma: no cover 6256 fsize = 8 6257 else: #pragma: no cover 6258 fsize = 0 6259 if fsize > 0: 6260 font = ImageFont.load('%s/pilfonts/B%0.2d.pil' % (THISPATH, fsize) ) 6261 6262 6263 for i in range(c): 6264 if cmap[i]: 6265 self.setActiveChannels((i+1,)) 6266 img = self.renderImage(z,t, compression) 6267 if fsize > 0: 6268 draw = ImageDraw.ImageDraw(img) 6269 draw.text((2,2), "%s" % (self._renderSplit_channelLabel(self.getChannels()[i])), font=font, fill="#fff") 6270 canvas.paste(img, (px, py)) 6271 pxc += 1 6272 if pxc < dims['gridx']: 6273 px += self.getSizeX() + border 6274 else: 6275 pxc = 0 6276 px = border 6277 py += self.getSizeY() + border 6278 if not self.isGreyscaleRenderingModel(): 6279 self.setActiveChannels(cmap) 6280 img = self.renderImage(z,t, compression) 6281 if fsize > 0: 6282 draw = ImageDraw.ImageDraw(img) 6283 draw.text((2,2), "merged", font=font, fill="#fff") 6284 canvas.paste(img, (px, py)) 6285 return canvas
6286 6287 LP_PALLETE = [0,0,0,0,0,0,255,255,255] 6288 LP_TRANSPARENT = 0 # Some color 6289 LP_BGCOLOR = 1 # Black 6290 LP_FGCOLOR = 2 # white
6291 - def prepareLinePlotCanvas (self):
6292 """ 6293 Common part of horizontal and vertical line plot rendering. 6294 6295 @returns: (Image, width, height). 6296 """ 6297 channels = filter(lambda x: x.isActive(), self.getChannels()) 6298 width = self.getSizeX() 6299 height = self.getSizeY() 6300 6301 pal = list(self.LP_PALLETE) 6302 # Prepare the palette taking channel colors in consideration 6303 for channel in channels: 6304 pal.extend(channel.getColor().getRGB()) 6305 6306 # Prepare the PIL classes we'll be using 6307 im = Image.new('P', (width, height)) 6308 im.putpalette(pal) 6309 return im, width, height
6310 6311 6312 @assert_re()
6313 - def renderRowLinePlotGif (self, z, t, y, linewidth=1):
6314 """ 6315 Draws the Row plot as a gif file. Returns gif data. 6316 6317 @param z: Z index 6318 @param t: T index 6319 @param y: Y position 6320 @param linewidth: Width of plot line 6321 @return: gif data as String 6322 @rtype: String 6323 """ 6324 6325 self._pd.z = long(z) 6326 self._pd.t = long(t) 6327 6328 im, width, height = self.prepareLinePlotCanvas() 6329 base = height - 1 6330 6331 draw = ImageDraw.ImageDraw(im) 6332 # On your marks, get set... go! 6333 draw.rectangle([0, 0, width-1, base], fill=self.LP_TRANSPARENT, outline=self.LP_TRANSPARENT) 6334 draw.line(((0,y),(width, y)), fill=self.LP_FGCOLOR, width=linewidth) 6335 6336 # Grab row data 6337 rows = self.getRow(z,t,y) 6338 6339 for r in range(len(rows)): 6340 chrow = rows[r] 6341 color = r + self.LP_FGCOLOR + 1 6342 last_point = base-chrow[0] 6343 for i in range(len(chrow)): 6344 draw.line(((i, last_point), (i, base-chrow[i])), fill=color, width=linewidth) 6345 last_point = base-chrow[i] 6346 del draw 6347 out = StringIO() 6348 im.save(out, format="gif", transparency=0) 6349 return out.getvalue()
6350 6351 @assert_re()
6352 - def renderColLinePlotGif (self, z, t, x, linewidth=1):
6353 """ 6354 Draws the Column plot as a gif file. Returns gif data. 6355 6356 @param z: Z index 6357 @param t: T index 6358 @param x: X position 6359 @param linewidth: Width of plot line 6360 @return: gif data as String 6361 @rtype: String 6362 """ 6363 6364 self._pd.z = long(z) 6365 self._pd.t = long(t) 6366 6367 im, width, height = self.prepareLinePlotCanvas() 6368 6369 draw = ImageDraw.ImageDraw(im) 6370 # On your marks, get set... go! 6371 draw.rectangle([0, 0, width-1, height-1], fill=self.LP_TRANSPARENT, outline=self.LP_TRANSPARENT) 6372 draw.line(((x,0),(x, height)), fill=self.LP_FGCOLOR, width=linewidth) 6373 6374 # Grab col data 6375 cols = self.getCol(z,t,x) 6376 6377 for r in range(len(cols)): 6378 chcol = cols[r] 6379 color = r + self.LP_FGCOLOR + 1 6380 last_point = chcol[0] 6381 for i in range(len(chcol)): 6382 draw.line(((last_point, i), (chcol[i], i)), fill=color, width=linewidth) 6383 last_point = chcol[i] 6384 del draw 6385 out = StringIO() 6386 im.save(out, format="gif", transparency=0) 6387 return out.getvalue()
6388 6389 @assert_re()
6390 - def getZ (self):
6391 """ 6392 Returns the last used value of Z (E.g. for renderingJpeg or line plot) 6393 Returns 0 if these methods not been used yet. 6394 TODO: How to get default-Z? 6395 6396 @return: current Z index 6397 @rtype: int 6398 """ 6399 6400 return self._pd.z
6401 6402 @assert_re()
6403 - def getT (self):
6404 """ 6405 Returns the last used value of T (E.g. for renderingJpeg or line plot) 6406 Returns 0 if these methods not been used yet. 6407 TODO: How to get default-T? 6408 6409 @return: current T index 6410 @rtype: int 6411 """ 6412 6413 return self._pd.t
6414 6415 @assert_re()
6416 - def getDefaultZ(self):
6417 """ 6418 Gets the default Z index from the rendering engine 6419 """ 6420 return self._re.getDefaultZ()
6421 6422 @assert_re()
6423 - def getDefaultT(self):
6424 """ 6425 Gets the default T index from the rendering engine 6426 """ 6427 return self._re.getDefaultT()
6428 6429 @assert_pixels
6430 - def getPixelsType (self):
6431 """ 6432 Gets the physical size X of pixels in microns 6433 6434 @return: Size of pixel in x or O 6435 @rtype: float 6436 """ 6437 rv = self._obj.getPrimaryPixels().getPixelsType().value 6438 return rv is not None and rv.val or 'unknown'
6439 6440 @assert_pixels
6441 - def getPixelSizeX (self):
6442 """ 6443 Gets the physical size X of pixels in microns 6444 6445 @return: Size of pixel in x or O 6446 @rtype: float 6447 """ 6448 rv = self._obj.getPrimaryPixels().getPhysicalSizeX() 6449 return rv is not None and rv.val or 0
6450 6451 @assert_pixels
6452 - def getPixelSizeY (self):
6453 """ 6454 Gets the physical size Y of pixels in microns 6455 6456 @return: Size of pixel in y or O 6457 @rtype: float 6458 """ 6459 6460 rv = self._obj.getPrimaryPixels().getPhysicalSizeY() 6461 return rv is not None and rv.val or 0
6462 6463 @assert_pixels
6464 - def getPixelSizeZ (self):
6465 """ 6466 Gets the physical size Z of pixels in microns 6467 6468 @return: Size of pixel in z or O 6469 @rtype: float 6470 """ 6471 6472 rv = self._obj.getPrimaryPixels().getPhysicalSizeZ() 6473 return rv is not None and rv.val or 0
6474 6475 @assert_pixels
6476 - def getSizeX (self):
6477 """ 6478 Gets width (size X) of the image (in pixels) 6479 6480 @return: width 6481 @rtype: int 6482 """ 6483 6484 return self._obj.getPrimaryPixels().getSizeX().val
6485 6486 @assert_pixels
6487 - def getSizeY (self):
6488 """ 6489 Gets height (size Y) of the image (in pixels) 6490 6491 @return: height 6492 @rtype: int 6493 """ 6494 6495 return self._obj.getPrimaryPixels().getSizeY().val
6496 6497 @assert_pixels
6498 - def getSizeZ (self):
6499 """ 6500 Gets Z count of the image 6501 6502 @return: size Z 6503 @rtype: int 6504 """ 6505 6506 if self.isInvertedAxis(): 6507 return self._obj.getPrimaryPixels().getSizeT().val 6508 else: 6509 return self._obj.getPrimaryPixels().getSizeZ().val
6510 6511 @assert_pixels
6512 - def getSizeT (self):
6513 """ 6514 Gets T count of the image 6515 6516 @return: size T 6517 @rtype: int 6518 """ 6519 6520 if self.isInvertedAxis(): 6521 return self._obj.getPrimaryPixels().getSizeZ().val 6522 else: 6523 return self._obj.getPrimaryPixels().getSizeT().val
6524 6525 @assert_pixels
6526 - def getSizeC (self):
6527 """ 6528 Gets C count of the image (number of channels) 6529 6530 @return: size C 6531 @rtype: int 6532 """ 6533 6534 return self._obj.getPrimaryPixels().getSizeC().val
6535
6536 - def clearDefaults (self):
6537 """ 6538 Removes specific color settings from channels 6539 6540 @return: True if allowed to do this 6541 @rtype: Boolean 6542 """ 6543 6544 if not self.canWrite(): 6545 return False 6546 for c in self.getChannels(): 6547 c.unloadRed() 6548 c.unloadGreen() 6549 c.unloadBlue() 6550 c.unloadAlpha() 6551 c.save() 6552 self._conn.getDeleteService().deleteSettings(self.getId()) 6553 return True
6554
6555 - def _collectRenderOptions (self):
6556 """ 6557 Returns a map of rendering options not stored in rendering settings. 6558 - 'p' : projection 6559 - 'ia' : inverted axis (swap Z and T) 6560 6561 @return: Dict of render options 6562 @rtype: Dict 6563 """ 6564 6565 rv = {} 6566 rv['p'] = self.getProjection() 6567 rv['ia'] = self.isInvertedAxis() and "1" or "0" 6568 return rv
6569
6570 - def _loadRenderOptions (self):
6571 """ 6572 Loads rendering options from an Annotation on the Image. 6573 6574 @return: Dict of rendering options 6575 @rtype: Dict 6576 """ 6577 ns = self._conn.CONFIG.get('IMG_ROPTSNS', None) 6578 if ns: 6579 ann = self.getAnnotation(ns) 6580 if ann is not None: 6581 opts = dict([x.split('=') for x in ann.getValue().split('&')]) 6582 return opts 6583 return {}
6584
6585 - def loadRenderOptions (self):
6586 """ 6587 Loads rendering options from an Annotation on the Image and applies them 6588 to the Image. 6589 6590 @return: True! TODO: Always True?? 6591 """ 6592 opts = self._loadRenderOptions() 6593 self.setProjection(opts.get('p', None)) 6594 self.setInvertedAxis(opts.get('ia', "0") == "1") 6595 return True
6596 6597 @assert_re()
6598 - def saveDefaults (self):
6599 """ 6600 Limited support for saving the current prepared image rendering defs. 6601 Right now only channel colors are saved back. 6602 6603 @return: Boolean 6604 """ 6605 6606 if not self.isEditable(): 6607 return False 6608 ns = self._conn.CONFIG.get('IMG_ROPTSNS', None) 6609 if ns: 6610 opts = self._collectRenderOptions() 6611 self.removeAnnotations(ns) 6612 ann = omero.gateway.CommentAnnotationWrapper() 6613 ann.setNs(ns) 6614 ann.setValue('&'.join(['='.join(map(str, x)) for x in opts.items()])) 6615 self.linkAnnotation(ann) 6616 self._re.saveCurrentSettings() 6617 return True
6618
6619 - def countArchivedFiles (self):
6620 """ Returns the number of Original 'archived' Files linked to primary pixels. Value is cached """ 6621 6622 if self._archivedFileCount is None: 6623 pid = self.getPixelsId() 6624 params = omero.sys.Parameters() 6625 params.map = {"pid": rlong(pid)} 6626 query = "select count(link.id) from PixelsOriginalFileMap as link where link.child.id=:pid" 6627 count = self._conn.getQueryService().projection(query, params) 6628 self._archivedFileCount = count[0][0]._val 6629 return self._archivedFileCount
6630
6631 - def getArchivedFiles (self):
6632 """ 6633 Returns a generator of L{OriginalFileWrapper}s corresponding to the archived files linked to primary pixels 6634 """ 6635 6636 pid = self.getPixelsId() 6637 params = omero.sys.Parameters() 6638 params.map = {"pid": rlong(pid)} 6639 query = "select link from PixelsOriginalFileMap link join fetch link.parent as p where link.child.id=:pid" 6640 links = self._conn.getQueryService().findAllByQuery(query, params) 6641 6642 for l in links: 6643 yield OriginalFileWrapper(self._conn, l.parent)
6644 6645 ImageWrapper = _ImageWrapper
6646 6647 ## INSTRUMENT AND ACQUISITION ## 6648 6649 -class _ImageStageLabelWrapper (BlitzObjectWrapper):
6650 """ 6651 omero_model_StageLabelI class wrapper extends BlitzObjectWrapper. 6652 """ 6653 pass
6654 6655 ImageStageLabelWrapper = _ImageStageLabelWrapper
6656 6657 -class _ImagingEnvironmentWrapper(BlitzObjectWrapper):
6658 """ 6659 omero_model_ImagingEnvironment class wrapper extends BlitzObjectWrapper. 6660 """ 6661 pass
6662 6663 ImagingEnvironmentWrapper = _ImagingEnvironmentWrapper
6664 6665 -class _ImagingEnviromentWrapper (BlitzObjectWrapper):
6666 """ 6667 omero_model_ImagingEnvironmentI class wrapper extends BlitzObjectWrapper. 6668 """ 6669 _attrs = ('temperature', 6670 'airPressure', 6671 'humidity', 6672 'co2percent', 6673 'version') 6674
6675 - def __bstrap__ (self):
6676 self.OMERO_CLASS = 'ImagingEnvironment'
6677 6678 ImagingEnviromentWrapper = _ImagingEnviromentWrapper
6679 6680 -class _TransmittanceRangeWrapper (BlitzObjectWrapper):
6681 """ 6682 omero_model_TransmittanceRangeI class wrapper extends BlitzObjectWrapper. 6683 """ 6684 _attrs = ('cutIn', 6685 'cutOut', 6686 'cutInTolerance', 6687 'cutOutTolerance', 6688 'transmittance', 6689 'version') 6690
6691 - def __bstrap__ (self):
6692 self.OMERO_CLASS = 'TransmittanceRange'
6693 6694 TransmittanceRangeWrapper = _TransmittanceRangeWrapper
6695 6696 -class _DetectorSettingsWrapper (BlitzObjectWrapper):
6697 """ 6698 omero_model_DetectorSettingsI class wrapper extends BlitzObjectWrapper. 6699 """ 6700 _attrs = ('voltage', 6701 'gain', 6702 'offsetValue', 6703 'readOutRate', 6704 'binning|BinningWrapper', 6705 'detector|DetectorWrapper', 6706 'version') 6707
6708 - def __bstrap__ (self):
6709 self.OMERO_CLASS = 'DetectorSettings'
6710 6711 DetectorSettingsWrapper = _DetectorSettingsWrapper
6712 6713 -class _BinningWrapper (BlitzObjectWrapper):
6714 """ 6715 omero_model_BinningI class wrapper extends BlitzObjectWrapper. 6716 """ 6717
6718 - def __bstrap__ (self):
6719 self.OMERO_CLASS = 'Binning'
6720 6721 BinningWrapper = _BinningWrapper
6722 6723 -class _DetectorWrapper (BlitzObjectWrapper):
6724 """ 6725 omero_model_DetectorI class wrapper extends BlitzObjectWrapper. 6726 """ 6727 _attrs = ('manufacturer', 6728 'model', 6729 'serialNumber', 6730 'voltage', 6731 'gain', 6732 'offsetValue', 6733 'zoom', 6734 'amplificationGain', 6735 '#type;detectorType', 6736 'version') 6737
6738 - def __bstrap__ (self):
6739 self.OMERO_CLASS = 'Detector'
6740
6741 - def getDetectorType(self):
6742 """ 6743 The type of detector (enum value) 6744 6745 @return: Detector type 6746 @rtype: L{EnumerationWrapper} 6747 """ 6748 6749 rv = self.type 6750 if self.type is not None: 6751 rv = EnumerationWrapper(self._conn, self.type) 6752 if not self.type.loaded: 6753 self.type = rv._obj 6754 return rv
6755 6756 DetectorWrapper = _DetectorWrapper
6757 6758 -class _ObjectiveWrapper (BlitzObjectWrapper):
6759 """ 6760 omero_model_ObjectiveI class wrapper extends BlitzObjectWrapper. 6761 """ 6762 _attrs = ('manufacturer', 6763 'model', 6764 'serialNumber', 6765 'nominalMagnification', 6766 'calibratedMagnification', 6767 'lensNA', 6768 '#immersion', 6769 '#correction', 6770 'workingDistance', 6771 'iris', 6772 'version') 6773
6774 - def __bstrap__ (self):
6775 self.OMERO_CLASS = 'Objective'
6776
6777 - def getImmersion(self):
6778 """ 6779 The type of immersion for this objective (enum value) 6780 6781 @return: Immersion type, or None 6782 @rtype: L{EnumerationWrapper} 6783 """ 6784 6785 rv = self.immersion 6786 if self.immersion is not None: 6787 rv = EnumerationWrapper(self._conn, self.immersion) 6788 if not self.immersion.loaded: 6789 self.immersion = rv._obj 6790 return rv
6791
6792 - def getCorrection(self):
6793 """ 6794 The type of Correction for this objective (enum value) 6795 6796 @return: Correction type, or None 6797 @rtype: L{EnumerationWrapper} 6798 """ 6799 6800 rv = self.correction 6801 if self.correction is not None: 6802 rv = EnumerationWrapper(self._conn, self.correction) 6803 if not self.correction.loaded: 6804 self.correction = rv._obj 6805 return rv
6806
6807 - def getIris(self):
6808 """ 6809 The type of Iris for this objective (enum value) 6810 6811 @return: Iris type 6812 @rtype: L{EnumerationWrapper} 6813 """ 6814 6815 rv = self.iris 6816 if self.iris is not None: 6817 rv = EnumerationWrapper(self._conn, self.iris) 6818 if not self.iris.loaded: 6819 self.iris = rv._obj 6820 return rv
6821 6822 ObjectiveWrapper = _ObjectiveWrapper
6823 6824 -class _ObjectiveSettingsWrapper (BlitzObjectWrapper):
6825 """ 6826 omero_model_ObjectiveSettingsI class wrapper extends BlitzObjectWrapper. 6827 """ 6828 _attrs = ('correctionCollar', 6829 '#medium', 6830 'refractiveIndex', 6831 'objective|ObjectiveWrapper', 6832 'version') 6833
6834 - def __bstrap__ (self):
6835 self.OMERO_CLASS = 'ObjectiveSettings'
6836
6837 - def getObjective (self):
6838 """ 6839 Gets the Objective that these settings refer to 6840 6841 @return: Objective 6842 @rtype: L{ObjectiveWrapper} 6843 """ 6844 6845 rv = self.objective 6846 if self.objective is not None: 6847 rv = ObjectiveWrapper(self._conn, self.objective) 6848 if not self.objective.loaded: 6849 self.objective = rv._obj 6850 return rv
6851
6852 - def getMedium(self):
6853 """ 6854 Gets the Medium type that these settings refer to (enum value) 6855 6856 @return: Medium 6857 @rtype: L{EnumerationWrapper} 6858 """ 6859 6860 rv = self.medium 6861 if self.medium is not None: 6862 rv = EnumerationWrapper(self._conn, self.medium) 6863 if not self.medium.loaded: 6864 self.medium = rv._obj 6865 return rv
6866 6867 ObjectiveSettingsWrapper = _ObjectiveSettingsWrapper
6868 6869 6870 -class _FilterWrapper (BlitzObjectWrapper):
6871 """ 6872 omero_model_FilterI class wrapper extends BlitzObjectWrapper. 6873 """ 6874 _attrs = ('manufacturer', 6875 'model', 6876 'lotNumber', 6877 'filterWheel', 6878 '#type;filterType', 6879 'transmittanceRange|TransmittanceRangeWrapper', 6880 'version') 6881
6882 - def __bstrap__ (self):
6883 self.OMERO_CLASS = 'Filter'
6884
6885 - def getFilterType(self):
6886 """ 6887 Gets the Filter type for this filter (enum value) 6888 6889 @return: Filter type 6890 @rtype: L{EnumerationWrapper} 6891 """ 6892 6893 rv = self.type 6894 if self.type is not None: 6895 rv = EnumerationWrapper(self._conn, self.type) 6896 if not self.type.loaded: 6897 self.type = rv._obj 6898 return rv
6899 6900 FilterWrapper = _FilterWrapper
6901 6902 -class _DichroicWrapper (BlitzObjectWrapper):
6903 """ 6904 omero_model_DichroicI class wrapper extends BlitzObjectWrapper. 6905 """ 6906 _attrs = ('manufacturer', 6907 'model', 6908 'lotNumber', 6909 'version') 6910
6911 - def __bstrap__ (self):
6912 self.OMERO_CLASS = 'Dichroic'
6913 6914 DichroicWrapper = _DichroicWrapper
6915 6916 -class _FilterSetWrapper (BlitzObjectWrapper):
6917 """ 6918 omero_model_FilterSetI class wrapper extends BlitzObjectWrapper. 6919 """ 6920 _attrs = ('manufacturer', 6921 'model', 6922 'lotNumber', 6923 'dichroic|DichroicWrapper', 6924 'version') 6925
6926 - def __bstrap__ (self):
6927 self.OMERO_CLASS = 'FilterSet'
6928
6929 - def copyEmissionFilters(self):
6930 """ TODO: not implemented """ 6931 pass
6932
6933 - def copyExcitationFilters(self):
6934 """ TODO: not implemented """ 6935 pass
6936 6937 FilterSetWrapper = _FilterSetWrapper
6938 6939 -class _OTFWrapper (BlitzObjectWrapper):
6940 """ 6941 omero_model_OTFI class wrapper extends BlitzObjectWrapper. 6942 """ 6943 _attrs = ('sizeX', 6944 'sizeY', 6945 'opticalAxisAveraged' 6946 'pixelsType', 6947 'path', 6948 'filterSet|FilterSetWrapper', 6949 'objective|ObjectiveWrapper', 6950 'version') 6951
6952 - def __bstrap__ (self):
6953 self.OMERO_CLASS = 'OTF'
6954 6955 OTFWrapper = _OTFWrapper
6956 6957 -class _LightSettingsWrapper (BlitzObjectWrapper):
6958 """ 6959 base Light Source class wrapper, extends BlitzObjectWrapper. 6960 """ 6961 _attrs = ('attenuation', 6962 'wavelength', 6963 #'lightSource|LightSourceWrapper', 6964 'microbeamManipulation', 6965 'version') 6966
6967 - def __bstrap__ (self):
6968 self.OMERO_CLASS = 'LightSettings'
6969
6970 - def getLightSource(self):
6971 if self._obj.lightSource is None: 6972 return None 6973 if not self._obj.lightSource.isLoaded(): # see #5742 6974 lid = self._obj.lightSource.id.val 6975 params = omero.sys.Parameters() 6976 params.map = {"id": rlong(lid)} 6977 query = "select l from Laser as l left outer join fetch l.type " \ 6978 "left outer join fetch l.laserMedium " \ 6979 "left outer join fetch l.pulse as pulse " \ 6980 "left outer join fetch l.pump as pump " \ 6981 "left outer join fetch pump.type as pt " \ 6982 "where l.id = :id" 6983 self._obj.lightSource = self._conn.getQueryService().findByQuery(query, params) 6984 return LightSourceWrapper(self._conn, self._obj.lightSource)
6985 6986 LightSettingsWrapper = _LightSettingsWrapper
6987 6988 -class _LightSourceWrapper (BlitzObjectWrapper):
6989 """ 6990 base Light Source class wrapper, extends BlitzObjectWrapper. 6991 """ 6992 _attrs = ('manufacturer', 6993 'model', 6994 'power', 6995 'serialNumber', 6996 '#type;lightSourceType', 6997 'version') 6998
6999 - def getLightSourceType(self):
7000 """ 7001 Gets the Light Source type for this light source (enum value) 7002 7003 @return: Light Source type 7004 @rtype: L{EnumerationWrapper} 7005 """ 7006 7007 rv = self.type 7008 if self.type is not None: 7009 rv = EnumerationWrapper(self._conn, self.type) 7010 if not self.type.loaded: 7011 self.type = rv._obj 7012 return rv
7013 7014 # map of light source gateway classes to omero model objects. E.g. omero.model.Arc : 'ArcWrapper' 7015 _LightSourceClasses = {}
7016 -def LightSourceWrapper (conn, obj, **kwargs):
7017 """ 7018 Creates wrapper instances for omero.model light source objects 7019 7020 @param conn: L{BlitzGateway} connection 7021 @param obj: omero.model object 7022 @return: L{_LightSourceWrapper} subclass 7023 """ 7024 for k, v in _LightSourceClasses.items(): 7025 if isinstance(obj, k): 7026 return getattr(omero.gateway, v)(conn, obj, **kwargs) 7027 return None
7028
7029 -class _FilamentWrapper (_LightSourceWrapper):
7030 """ 7031 omero_model_FilamentI class wrapper extends LightSourceWrapper. 7032 """ 7033
7034 - def __bstrap__ (self):
7035 super(_FilamentWrapper, self).__bstrap__() 7036 self.OMERO_CLASS = 'Filament'
7037 7038 FilamentWrapper = _FilamentWrapper 7039 _LightSourceClasses[omero.model.FilamentI] = 'FilamentWrapper'
7040 7041 -class _ArcWrapper (_FilamentWrapper):
7042 """ 7043 omero_model_ArcI class wrapper extends FilamentWrapper. 7044 """
7045 - def __bstrap__ (self):
7046 super(_ArcWrapper, self).__bstrap__() 7047 self.OMERO_CLASS = 'Arc'
7048 7049 ArcWrapper = _ArcWrapper 7050 _LightSourceClasses[omero.model.ArcI] = 'ArcWrapper'
7051 7052 -class _LaserWrapper (_LightSourceWrapper):
7053 """ 7054 omero_model_LaserI class wrapper extends LightSourceWrapper. 7055 """
7056 - def __bstrap__ (self):
7057 super(_LaserWrapper, self).__bstrap__() 7058 self.OMERO_CLASS = 'Laser' 7059 self._attrs += ( 7060 '#laserMedium', 7061 'frequencyMultiplication', 7062 'tuneable', 7063 'pulse', 7064 'wavelength', 7065 'pockelCell', 7066 'pump', 7067 'repetitionRate')
7068
7069 - def getLaserMedium(self):
7070 """ 7071 Gets the laser medium type for this Laser (enum value) 7072 7073 @return: Laser medium type 7074 @rtype: L{EnumerationWrapper} 7075 """ 7076 7077 rv = self.laserMedium 7078 if self.laserMedium is not None: 7079 rv = EnumerationWrapper(self._conn, self.laserMedium) 7080 if not self.laserMedium.loaded: 7081 self.laserMedium = rv._obj 7082 return rv
7083 7084 LaserWrapper = _LaserWrapper 7085 _LightSourceClasses[omero.model.LaserI] = 'LaserWrapper'
7086 7087 -class _LightEmittingDiodeWrapper (_LightSourceWrapper):
7088 """ 7089 omero_model_LightEmittingDiodeI class wrapper extends LightSourceWrapper. 7090 """
7091 - def __bstrap__ (self):
7092 super(_LightEmittingDiodeWrapper, self).__bstrap__() 7093 self.OMERO_CLASS = 'LightEmittingDiode'
7094 7095 LightEmittingDiodeWrapper = _LightEmittingDiodeWrapper 7096 _LightSourceClasses[omero.model.LightEmittingDiodeI] = 'LightEmittingDiodeWrapper'
7097 7098 -class _MicroscopeWrapper (BlitzObjectWrapper):
7099 """ 7100 omero_model_MicroscopeI class wrapper extends BlitzObjectWrapper. 7101 """ 7102 _attrs = ('manufacturer', 7103 'model', 7104 'serialNumber', 7105 '#type;microscopeType', 7106 'version') 7107
7108 - def __bstrap__ (self):
7109 self.OMERO_CLASS = 'Microscope'
7110
7111 - def getMicroscopeType(self):
7112 """ 7113 Returns the 'type' of microscope this is. 7114 7115 @return: Microscope type. 7116 @rtype: L{EnumerationWrapper} 7117 """ 7118 7119 rv = self.type 7120 if self.type is not None: 7121 rv = EnumerationWrapper(self._conn, self.type) 7122 if not self.type.loaded: 7123 self.type = rv._obj 7124 return rv
7125 7126 MicroscopeWrapper = _MicroscopeWrapper
7127 7128 -class _InstrumentWrapper (BlitzObjectWrapper):
7129 """ 7130 omero_model_InstrumentI class wrapper extends BlitzObjectWrapper. 7131 """ 7132 7133 # TODO: wrap version 7134 7135 _attrs = ('microscope|MicroscopeWrapper',) 7136
7137 - def __bstrap__ (self):
7138 self.OMERO_CLASS = 'Instrument'
7139
7140 - def getMicroscope (self):
7141 """ 7142 Returns the microscope component of the Instrument. 7143 7144 @return: Microscope 7145 @rtype: omero.model.Microscope 7146 """ 7147 7148 if self._obj.microscope is not None: 7149 return MicroscopeWrapper(self._conn, self._obj.microscope) 7150 return None
7151
7152 - def getDetectors (self):
7153 """ 7154 Gets the Instrument detectors. 7155 7156 @return: List of Detectors 7157 @rtype: L{DetectorWrapper} list 7158 """ 7159 7160 return [DetectorWrapper(self._conn, x) for x in self._detectorSeq]
7161
7162 - def getObjectives (self):
7163 """ 7164 Gets the Instrument Objectives. 7165 7166 @return: List of Objectives 7167 @rtype: L{ObjectiveWrapper} list 7168 """ 7169 7170 return [ObjectiveWrapper(self._conn, x) for x in self._objectiveSeq]
7171
7172 - def getFilters (self):
7173 """ 7174 Gets the Instrument Filters. 7175 7176 @return: List of Filters 7177 @rtype: L{FilterWrapper} list 7178 """ 7179 7180 return [FilterWrapper(self._conn, x) for x in self._filterSeq]
7181
7182 - def getDichroics (self):
7183 """ 7184 Gets the Instrument Dichroics. 7185 7186 @return: List of Dichroics 7187 @rtype: L{DichroicWrapper} list 7188 """ 7189 7190 return [DichroicWrapper(self._conn, x) for x in self._dichroicSeq]
7191
7192 - def getFilterSets (self):
7193 """ 7194 Gets the Instrument FilterSets. 7195 7196 @return: List of FilterSets 7197 @rtype: L{FilterSetWrapper} list 7198 """ 7199 7200 return [FilterSetWrapper(self._conn, x) for x in self._filterSetSeq]
7201
7202 - def getOTFs (self):
7203 """ 7204 Gets the Instrument OTFs. 7205 7206 @return: List of OTFs 7207 @rtype: L{OTFWrapper} list 7208 """ 7209 7210 return [OTFWrapper(self._conn, x) for x in self._otfSeq]
7211
7212 - def getLightSources (self):
7213 """ 7214 Gets the Instrument LightSources. 7215 7216 @return: List of LightSources 7217 @rtype: L{LightSourceWrapper} list 7218 """ 7219 7220 return [LightSourceWrapper(self._conn, x) for x in self._lightSourceSeq]
7221 7222
7223 - def simpleMarshal (self):
7224 if self._obj: 7225 rv = super(_InstrumentWrapper, self).simpleMarshal(parents=False) 7226 rv['detectors'] = [x.simpleMarshal() for x in self.getDetectors()] 7227 rv['objectives'] = [x.simpleMarshal() for x in self.getObjectives()] 7228 rv['filters'] = [x.simpleMarshal() for x in self.getFilters()] 7229 rv['dichroics'] = [x.simpleMarshal() for x in self.getDichroics()] 7230 rv['filterSets'] = [x.simpleMarshal() for x in self.getFilterSets()] 7231 rv['otfs'] = [x.simpleMarshal() for x in self.getOTFs()] 7232 rv['lightsources'] = [x.simpleMarshal() for x in self.getLightSources()] 7233 else: 7234 rv = {} 7235 return rv
7236 7237 InstrumentWrapper = _InstrumentWrapper 7238 7239 KNOWN_WRAPPERS = {}
7240 7241 -def refreshWrappers ():
7242 """ 7243 this needs to be called by modules that extend the base wrappers 7244 """ 7245 KNOWN_WRAPPERS.update({"project":ProjectWrapper, 7246 "dataset":DatasetWrapper, 7247 "image":ImageWrapper, 7248 "screen":ScreenWrapper, 7249 "plate":PlateWrapper, 7250 "well":WellWrapper, 7251 "experimenter":ExperimenterWrapper, 7252 "experimentergroup":ExperimenterGroupWrapper, 7253 "originalfile":OriginalFileWrapper, 7254 "commentannotation":CommentAnnotationWrapper, 7255 "tagannotation":TagAnnotationWrapper, 7256 "longannotation":LongAnnotationWrapper, 7257 "booleanannotation":BooleanAnnotationWrapper, 7258 "fileannotation":FileAnnotationWrapper, 7259 "doubleannotation":DoubleAnnotationWrapper, 7260 "termannotation":TermAnnotationWrapper, 7261 "timestampannotation":TimestampAnnotationWrapper, 7262 "annotation":AnnotationWrapper._wrap}) # allows for getObjects("Annotation", ids)
7263 7264 refreshWrappers() 7265