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