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