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

Source Code for Package omero.gateway

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