Coverage for /opt/conda/envs/apienv/lib/python3.10/site-packages/daiquiri/core/metadata/ispyalchemy/sample.py: 73%
364 statements
« prev ^ index » next coverage.py v7.6.5, created at 2024-11-15 02:12 +0000
« prev ^ index » next coverage.py v7.6.5, created at 2024-11-15 02:12 +0000
1# -*- coding: utf-8 -*-
2from datetime import datetime
3import json
4import os
6from flask import g
7from PIL import Image
8import sqlalchemy
9from sqlalchemy import orm
10from sqlalchemy.sql.expression import cast, func, distinct, and_
12from daiquiri.core.metadata.ispyalchemy.handler import IspyalchemyHandler
15class SampleHandler(IspyalchemyHandler):
16 exported = [
17 "get_components",
18 "add_component",
19 "update_component",
20 "get_samples",
21 "add_sample",
22 "update_sample",
23 "queue_sample",
24 "unqueue_sample",
25 "get_subsamples",
26 "add_subsample",
27 "update_subsample",
28 "remove_subsample",
29 "queue_subsample",
30 "unqueue_subsample",
31 "get_sample_tags",
32 "get_sampleimages",
33 "add_sampleimage",
34 "add_container_inspection",
35 ]
37 def get_components(self, componentid=None, **kwargs):
38 with self.session_scope() as ses:
39 components = (
40 ses.query(
41 self.Protein.proteinid.label("componentid"),
42 self.Protein.name,
43 self.Protein.acronym,
44 self.Protein.description,
45 cast(self.Protein.molecularmass, sqlalchemy.Float).label(
46 "molecularmass"
47 ),
48 self.Protein.density,
49 self.Protein.sequence,
50 func.count(distinct(self.BLSample.blsampleid)).label("samples"),
51 func.count(distinct(self.DataCollection.datacollectionid)).label(
52 "datacollections"
53 ),
54 )
55 .outerjoin(
56 self.Crystal, self.Crystal.proteinid == self.Protein.proteinid
57 )
58 .outerjoin(self.BLSample)
59 .outerjoin(
60 self.DataCollectionGroup,
61 self.BLSample.blsampleid == self.DataCollectionGroup.blsampleid,
62 )
63 .outerjoin(
64 self.DataCollection,
65 self.DataCollectionGroup.datacollectiongroupid
66 == self.DataCollection.datacollectiongroupid,
67 )
68 .group_by(self.Protein.proteinid)
69 )
71 if not kwargs.get("no_context"):
72 components = components.filter(
73 self.Protein.proposalid == g.blsession.get("proposalid")
74 )
76 if kwargs.get("sampleid"):
77 components = components.filter(
78 self.BLSample.blsampleid == kwargs["sampleid"]
79 )
81 if componentid:
82 components = components.filter(self.Protein.proteinid == componentid)
83 component = components.first()
84 if component:
85 return component._asdict()
87 else:
88 components = [r._asdict() for r in components.all()]
89 return {"total": len(components), "rows": components}
91 def add_component(self, **kwargs):
92 with self.session_scope() as ses:
93 component = self.Protein(
94 proposalid=g.blsession.get("proposalid"),
95 name=kwargs.get("name"),
96 acronym=kwargs.get("acronym"),
97 molecularmass=kwargs.get("molecularmass"),
98 sequence=kwargs.get("sequence"),
99 density=kwargs.get("density"),
100 )
102 ses.add(component)
103 ses.commit()
105 return self.get_components(componentid=component.proteinid)
107 def update_component(self, componentid, **kwargs):
108 with self.session_scope() as ses:
109 chk = self.get_components(componentid=componentid)
110 if chk:
111 component = (
112 ses.query(self.Protein)
113 .filter(self.Protein.proteinid == componentid)
114 .first()
115 )
117 updatable = ["name", "acronym", "molecularmass", "density", "sequence"]
118 for k, v in kwargs.items():
119 if k in updatable:
120 setattr(component, k, v)
122 ses.commit()
124 return self.get_components(componentid=componentid)
126 def get_samples(self, sampleid=None, **kwargs):
127 with self.session_scope() as ses:
128 dc2 = orm.aliased(self.DataCollection)
129 samples = (
130 ses.query(
131 self.BLSample.blsampleid.label("sampleid"),
132 self.BLSample.name,
133 self.BLSample.comments,
134 self.BLSample.extrametadata,
135 self.Container.containerid,
136 cast(self.BLSample.location, sqlalchemy.Integer).label("location"),
137 cast(self.Position.posx, sqlalchemy.Integer).label("offsetx"),
138 cast(self.Position.posy, sqlalchemy.Integer).label("offsety"),
139 self.Protein.acronym.label("component"),
140 self.Protein.proteinid.label("componentid"),
141 func.count(distinct(self.BLSubSample.blsubsampleid)).label(
142 "subsamples"
143 ),
144 func.count(distinct(self.DataCollection.datacollectionid)).label(
145 "datacollections"
146 ),
147 func.IF(
148 func.count(self.ContainerQueueSample.containerqueuesampleid)
149 > func.count(dc2.datacollectionid),
150 True,
151 False,
152 ).label("queued"),
153 )
154 .join(self.Crystal, self.Crystal.crystalid == self.BLSample.crystalid)
155 .join(self.Protein)
156 .join(self.Proposal)
157 .join(self.Container)
158 .outerjoin(
159 self.Position, self.Position.positionid == self.BLSample.positionid
160 )
161 .outerjoin(
162 self.DataCollectionGroup,
163 self.DataCollectionGroup.blsampleid == self.BLSample.blsampleid,
164 )
165 .outerjoin(
166 self.DataCollection,
167 self.DataCollection.datacollectiongroupid
168 == self.DataCollectionGroup.datacollectiongroupid,
169 )
170 .outerjoin(
171 self.BLSubSample,
172 self.BLSubSample.blsampleid == self.BLSample.blsampleid,
173 )
174 .outerjoin(
175 self.ContainerQueueSample,
176 self.BLSample.blsampleid == self.ContainerQueueSample.blsampleid,
177 )
178 .outerjoin(
179 dc2,
180 self.ContainerQueueSample.datacollectionplanid
181 == dc2.datacollectionplanid,
182 )
183 .filter(
184 and_(
185 self.Container.beamlinelocation
186 == self._config["meta_beamline"],
187 self.Container.samplechangerlocation is not None,
188 self.Container.containerstatus == "processing",
189 )
190 )
191 .group_by(self.BLSample.blsampleid)
192 )
194 if not kwargs.get("no_context"):
195 samples = samples.filter(
196 self.Proposal.proposalid == g.blsession.get("proposalid")
197 )
199 if kwargs.get("containerid"):
200 samples = samples.filter(
201 self.Container.containerid == kwargs.get("containerid")
202 )
204 if sampleid:
205 samples = samples.filter(self.BLSample.blsampleid == sampleid)
206 sample = samples.first()
207 if sample:
208 return sample._asdict()
210 else:
211 samples = [r._asdict() for r in samples.all()]
212 return {"total": len(samples), "rows": samples}
214 def add_sample(self, **kwargs):
215 if kwargs.get("containerid") is None:
216 containerid = self._ensure_default_container()
217 else:
218 containerid = kwargs["containerid"]
220 if kwargs.get("componentid") is None:
221 proteinid = self._ensure_default_component()
222 chk = self.get_components(componentid=proteinid)
223 if not chk:
224 return
226 else:
227 proteinid = kwargs["componentid"]
229 samples = self.get_samples(containerid=containerid)["rows"]
230 max_loc = 0
231 for s in samples:
232 if s["location"] > max_loc:
233 max_loc = s["location"]
235 with self.session_scope() as ses:
236 pos = self.Position(posx=kwargs["offsetx"], posy=kwargs["offsety"])
237 ses.add(pos)
238 ses.commit()
240 crystal = self.Crystal(proteinid=proteinid)
242 ses.add(crystal)
243 ses.commit()
245 sample = self.BLSample(
246 containerid=containerid,
247 crystalid=crystal.crystalid,
248 location=max_loc + 1,
249 positionid=pos.positionid,
250 name=kwargs.get("name"),
251 comments=kwargs.get("comments"),
252 )
254 ses.add(sample)
255 ses.commit()
257 return self.get_samples(sampleid=sample.blsampleid)
259 def update_sample(self, sampleid, **kwargs):
260 with self.session_scope() as ses:
261 chk = self.get_samples(sampleid=sampleid)
262 if chk:
263 sample = (
264 ses.query(self.BLSample)
265 .filter(self.BLSample.blsampleid == sampleid)
266 .first()
267 )
269 updatable = ["name", "comments", "offsetx", "offsety", "extrametadata"]
270 for k, v in kwargs.items():
271 if k in updatable:
272 setattr(sample, k, v)
274 if "componentid" in kwargs:
275 crystal = (
276 ses.query(self.Crystal)
277 .filter(self.Crystal.crystalid == sample.crystalid)
278 .first()
279 )
281 crystal.proteinid = kwargs["componentid"]
283 ses.commit()
285 return self.get_samples(sampleid=sampleid)
287 def get_subsamples(self, subsampleid=None, **kwargs):
288 dc2 = orm.aliased(self.DataCollection)
289 position2 = orm.aliased(self.Position)
291 with self.session_scope() as ses:
292 subsamples = (
293 ses.query(
294 self.BLSubSample.blsubsampleid.label("subsampleid"),
295 self.BLSample.blsampleid.label("sampleid"),
296 self.BLSample.name.label("sample"),
297 self.BLSubSample.type,
298 self.BLSubSample.source,
299 self.BLSubSample.comments,
300 self.BLSubSample.extrametadata,
301 self.Container.containerid,
302 cast(self.Position.posx, sqlalchemy.Integer).label("x"),
303 cast(self.Position.posy, sqlalchemy.Integer).label("y"),
304 cast(position2.posx, sqlalchemy.Integer).label("x2"),
305 cast(position2.posy, sqlalchemy.Integer).label("y2"),
306 func.count(distinct(self.DataCollection.datacollectionid)).label(
307 "datacollections"
308 ),
309 func.IF(
310 func.count(self.ContainerQueueSample.containerqueuesampleid)
311 > func.count(dc2.datacollectionid),
312 True,
313 False,
314 ).label("queued"),
315 func.group_concat(
316 distinct(
317 func.concat(
318 self.Positioner.positioner, ":", self.Positioner.value
319 )
320 )
321 ).label("positions"),
322 )
323 .join(
324 self.BLSample,
325 self.BLSample.blsampleid == self.BLSubSample.blsampleid,
326 )
327 .join(self.Crystal)
328 .join(self.Protein)
329 .join(self.Proposal)
330 .join(self.Container)
331 .outerjoin(
332 self.Position,
333 self.Position.positionid == self.BLSubSample.positionid,
334 )
335 .outerjoin(
336 position2, position2.positionid == self.BLSubSample.position2id
337 )
338 .outerjoin(
339 self.DataCollection,
340 self.DataCollection.blsubsampleid == self.BLSubSample.blsubsampleid,
341 )
342 .outerjoin(
343 self.ContainerQueueSample,
344 self.BLSubSample.blsubsampleid
345 == self.ContainerQueueSample.blsubsampleid,
346 )
347 .outerjoin(
348 dc2,
349 self.ContainerQueueSample.datacollectionplanid
350 == dc2.datacollectionplanid,
351 )
352 .outerjoin(self.BLSubSample_has_Positioner)
353 .outerjoin(
354 self.Positioner,
355 self.BLSubSample_has_Positioner.positionerid
356 == self.Positioner.positionerid,
357 )
358 .group_by(self.BLSubSample.blsubsampleid)
359 )
361 if not kwargs.get("no_context"):
362 subsamples = subsamples.filter(
363 self.Proposal.proposalid == g.blsession.get("proposalid")
364 )
366 if kwargs.get("sampleid"):
367 subsamples = subsamples.filter(
368 self.BLSample.blsampleid == kwargs.get("sampleid")
369 )
371 if subsampleid:
372 subsamples = subsamples.filter(
373 self.BLSubSample.blsubsampleid == subsampleid
374 )
375 subsample = subsamples.first()
376 if subsample:
377 subs = subsample._asdict()
378 subs["positions"] = self._pos_to_dict(subs["positions"])
379 return subs
381 else:
382 subs = [r._asdict() for r in subsamples.all()]
384 for s in subs:
385 s["positions"] = self._pos_to_dict(s["positions"])
387 return {"total": len(subs), "rows": subs}
389 def _pos_to_dict(self, positions):
390 ps = {}
391 if positions:
392 for p in positions.split(","):
393 k, v = p.split(":")
394 ps[k] = v
396 return ps
398 def add_subsample(self, **kwargs):
399 with self.session_scope() as ses:
400 sample = self.get_samples(sampleid=kwargs["sampleid"])
401 if sample:
402 position = self.Position(posx=kwargs["x"], posy=kwargs["y"])
403 ses.add(position)
404 ses.commit()
406 position2 = None
407 if kwargs.get("x2"):
408 position2 = self.Position(posx=kwargs["x2"], posy=kwargs["y2"])
409 ses.add(position2)
410 ses.commit()
412 subsample = self.BLSubSample(
413 blsampleid=kwargs["sampleid"],
414 type=kwargs["type"],
415 comments=kwargs.get("comments"),
416 positionid=position.positionid,
417 position2id=position2.positionid if position2 else None,
418 )
420 ses.add(subsample)
421 ses.commit()
423 if kwargs.get("positions"):
424 for k, v in kwargs["positions"].items():
425 positioner = self.Positioner(positioner=k, value=v)
426 ses.add(positioner)
427 ses.commit()
429 blshaspos = self.BLSubSample_has_Positioner(
430 blsubsampleid=subsample.blsubsampleid,
431 positionerid=positioner.positionerid,
432 )
433 ses.add(blshaspos)
434 ses.commit()
436 return self.get_subsamples(subsampleid=subsample.blsubsampleid)
438 def update_subsample(self, subsampleid, **kwargs):
439 with self.session_scope() as ses:
440 chk = self.get_subsamples(subsampleid=subsampleid)
441 if chk:
442 position2 = orm.aliased(self.Position)
443 subsample, position, position2 = (
444 ses.query(self.BLSubSample, self.Position, position2)
445 .outerjoin(
446 self.Position,
447 self.Position.positionid == self.BLSubSample.positionid,
448 )
449 .outerjoin(
450 position2, position2.positionid == self.BLSubSample.position2id
451 )
452 .filter(self.BLSubSample.blsubsampleid == subsampleid)
453 .first()
454 )
456 additional = (
457 ses.query(self.Positioner)
458 .join(self.BLSubSample_has_Positioner)
459 .filter(
460 self.BLSubSample_has_Positioner.blsubsampleid == subsampleid
461 )
462 .all()
463 )
465 if kwargs.get("positions"):
466 for pos in additional:
467 if pos.positioner in kwargs["positions"]:
468 pos.value = kwargs["positions"][pos.positioner]
470 if subsample:
471 updatable = ["comments", "extrametadata"]
472 for k, v in kwargs.items():
473 if k in updatable:
474 setattr(subsample, k, v)
476 if kwargs.get("x"):
477 position.posx = kwargs["x"]
479 if kwargs.get("y"):
480 position.posy = kwargs["y"]
482 if position2:
483 if kwargs.get("x2"):
484 position2.posx = kwargs["x2"]
486 if kwargs.get("y2"):
487 position2.posy = kwargs["y2"]
489 ses.commit()
491 return self.get_subsamples(subsampleid=subsampleid)
493 def remove_subsample(self, subsampleid):
494 with self.session_scope() as ses:
495 chk = self.get_subsamples(subsampleid=subsampleid)
496 if chk:
497 positions = (
498 ses.query(self.Positioner)
499 .join(self.BLSubSample_has_Positioner)
500 .filter(
501 self.BLSubSample_has_Positioner.blsubsampleid == subsampleid
502 )
503 .all()
504 )
506 bls_has_pos = (
507 ses.query(self.BLSubSample_has_Positioner)
508 .filter(
509 self.BLSubSample_has_Positioner.blsubsampleid == subsampleid
510 )
511 .all()
512 )
513 for blp in bls_has_pos:
514 ses.delete(blp)
515 ses.commit()
517 for p in positions:
518 ses.delete(p)
519 ses.commit()
521 position2 = orm.aliased(self.Position)
522 subsample, position, position2 = (
523 ses.query(self.BLSubSample, self.Position, position2)
524 .outerjoin(
525 self.Position,
526 self.Position.positionid == self.BLSubSample.positionid,
527 )
528 .outerjoin(
529 position2, position2.positionid == self.BLSubSample.position2id
530 )
531 .filter(self.BLSubSample.blsubsampleid == subsampleid)
532 .first()
533 )
535 if subsample:
536 ses.delete(position)
538 if position2:
539 ses.delete(position2)
541 ses.delete(subsample)
543 ses.commit()
545 return True
547 def queue_subsample(self, subsampleid, datacollectionplanid=None, **kwargs):
548 with self.session_scope() as ses:
549 subsample = self.get_subsamples(subsampleid=subsampleid)
550 if subsample:
551 if not datacollectionplanid:
552 dp = self.add_datacollectionplan(no_context=True, **kwargs)
553 datacollectionplanid = dp["datacollectionplanid"]
555 cq = (
556 ses.query(self.ContainerQueue.containerqueueid)
557 .join(
558 self.BLSample,
559 self.BLSample.containerid == self.ContainerQueue.containerid,
560 )
561 .join(
562 self.BLSubSample,
563 self.BLSample.blsampleid == self.BLSubSample.blsampleid,
564 )
565 .filter(self.BLSubSample.blsubsampleid == subsampleid)
566 .first()
567 )
569 if not cq:
570 cq = self.ContainerQueue(
571 containerid=subsample["containerid"],
572 personid=g.user["personid"],
573 )
574 ses.add(cq)
575 ses.commit()
577 cqs = self.ContainerQueueSample(
578 containerqueueid=cq.containerqueueid,
579 datacollectionplanid=datacollectionplanid,
580 blsubsampleid=subsampleid,
581 )
583 ses.add(cqs)
584 ses.commit()
586 return cqs.containerqueuesampleid, datacollectionplanid
588 def unqueue_subsample(self, subsampleid, **kwargs):
589 with self.session_scope() as ses:
590 if not kwargs.get("containerqueuesampleid"):
591 raise AttributeError("missing containerqueuesampleid")
593 subsample = self.get_subsamples(subsampleid=subsampleid)
594 if subsample:
595 cqs, dp = (
596 ses.query(self.ContainerQueueSample, self.DiffractionPlan)
597 .filter(
598 self.ContainerQueueSample.datacollectionplanid
599 == self.DiffractionPlan.diffractionplanid
600 )
601 .filter(
602 self.ContainerQueueSample.containerqueuesampleid
603 == kwargs["containerqueuesampleid"]
604 )
605 .first()
606 )
608 if cqs:
609 ses.delete(cqs)
610 ses.commit()
612 if dp:
613 ses.delete(dp)
614 ses.commit()
616 return True
618 def queue_sample(self, sampleid, datacollectionplanid=None, **kwargs):
619 with self.session_scope() as ses:
620 sample = self.get_samples(sampleid=sampleid)
621 if sample:
622 if not datacollectionplanid:
623 dp = self.add_datacollectionplan(no_context=True, **kwargs)
624 datacollectionplanid = dp["datacollectionplanid"]
626 cq = (
627 ses.query(self.ContainerQueue.containerqueueid)
628 .join(
629 self.BLSample,
630 self.BLSample.containerid == self.ContainerQueue.containerid,
631 )
632 .filter(self.BLSample.blsampleid == sampleid)
633 .first()
634 )
636 if not cq:
637 cq = self.ContainerQueue(
638 containerid=sample["containerid"],
639 personid=g.user["personid"],
640 )
641 ses.add(cq)
642 ses.commit()
644 cqs = self.ContainerQueueSample(
645 containerqueueid=cq.containerqueueid,
646 datacollectionplanid=datacollectionplanid,
647 blsampleid=sampleid,
648 )
650 ses.add(cqs)
651 ses.commit()
653 return cqs.containerqueuesampleid, datacollectionplanid
655 def unqueue_sample(self, sampleid, **kwargs):
656 with self.session_scope() as ses:
657 if not kwargs.get("containerqueuesampleid"):
658 raise AttributeError("missing containerqueuesampleid")
660 sample = self.get_samples(
661 sampleid=sampleid, no_context=kwargs.get("no_context")
662 )
663 if sample:
664 cqs, dp = (
665 ses.query(self.ContainerQueueSample, self.DiffractionPlan)
666 .filter(
667 self.ContainerQueueSample.datacollectionplanid
668 == self.DiffractionPlan.diffractionplanid
669 )
670 .filter(
671 self.ContainerQueueSample.containerqueuesampleid
672 == kwargs["containerqueuesampleid"]
673 )
674 .first()
675 )
677 if cqs:
678 ses.delete(cqs)
679 ses.commit()
681 if dp:
682 sample_has_datacollectionplan = (
683 ses.query(self.BLSample_has_DataCollectionPlan)
684 .filter(
685 self.BLSample_has_DataCollectionPlan.datacollectionplanid
686 == dp.diffractionplanid,
687 )
688 .first()
689 )
691 # If this plan is associated to a sample it was created using the plans routes
692 # rather than automatically, unqueuing should preserve the plan
693 if not sample_has_datacollectionplan:
694 ses.delete(dp)
695 ses.commit()
697 return True
699 def get_sample_tags(self, type: str = None):
700 with self.session_scope() as ses:
701 sample_tags = []
702 print("sample tags", type)
703 if (type and type.value == "sample") or type is None:
704 sample_tags = (
705 ses.query(
706 func.json_extract(self.BLSample.extrametadata, "$.tags").label(
707 "tags"
708 )
709 )
710 .join(self.Crystal)
711 .join(self.Protein)
712 .join(self.Proposal)
713 .filter(self.Proposal.proposalid == g.blsession.get("proposalid"))
714 .group_by(self.BLSample.blsampleid)
715 )
716 sample_tags = [r._asdict() for r in sample_tags.all()]
718 subsample_tags = []
719 if (type and type.value == "subsample") or type is None:
720 subsample_tags = (
721 ses.query(
722 func.json_extract(
723 self.BLSubSample.extrametadata, "$.tags"
724 ).label("tags")
725 )
726 .join(
727 self.BLSample,
728 self.BLSample.blsampleid == self.BLSubSample.blsampleid,
729 )
730 .join(self.Crystal)
731 .join(self.Protein)
732 .join(self.Proposal)
733 .filter(self.Proposal.proposalid == g.blsession.get("proposalid"))
734 .group_by(self.BLSubSample.blsubsampleid)
735 )
737 subsample_tags = [r._asdict() for r in subsample_tags.all()]
739 tag_list = []
740 for tags in [sample_tags, subsample_tags]:
741 for tag in tags:
742 if tag["tags"]:
743 tag_list.extend(json.loads(tag["tags"]))
745 tag_list.sort()
746 return {"tags": list(set(tag_list))}
748 def get_sampleimages(self, sampleimageid=None, **kwargs):
749 with self.session_scope() as ses:
750 sampleimages = (
751 ses.query(
752 self.BLSampleImage.blsampleimageid.label("sampleimageid"),
753 self.BLSampleImage.imagefullpath.label("file"),
754 (self.BLSampleImage.micronsperpixelx * 1000).label("scalex"),
755 (self.BLSampleImage.micronsperpixely * 1000).label("scaley"),
756 self.BLSampleImage.offsetx,
757 (self.BLSampleImage.offsety * -1).label("offsety"),
758 func.concat(
759 f"/{self._base_url}/samples/images/",
760 self.BLSampleImage.blsampleimageid,
761 ).label("url"),
762 func.group_concat(
763 distinct(
764 func.concat(
765 self.Positioner.positioner, ":", self.Positioner.value
766 )
767 )
768 ).label("positions"),
769 )
770 .join(self.BLSample)
771 .join(self.Container)
772 .join(self.Crystal)
773 .join(self.Protein)
774 .outerjoin(self.BLSampleImage_has_Positioner)
775 .outerjoin(
776 self.Positioner,
777 self.BLSampleImage_has_Positioner.positionerid
778 == self.Positioner.positionerid,
779 )
780 .group_by(self.BLSampleImage.blsampleimageid)
781 )
783 if not kwargs.get("no_context"):
784 sampleimages = sampleimages.filter(
785 self.Protein.proposalid == g.blsession.get("proposalid")
786 )
788 if kwargs.get("containerid"):
789 sampleimages = sampleimages.filter(
790 self.Container.containerid == kwargs.get("containerid")
791 )
793 if kwargs.get("sampleid"):
794 sampleimages = sampleimages.filter(
795 self.BLSampleImage.blsampleid == kwargs.get("sampleid")
796 )
798 if sampleimageid:
799 sampleimages = sampleimages.filter(
800 self.BLSampleImage.blsampleimageid == sampleimageid
801 )
802 sampleimage = sampleimages.first()
803 if sampleimage:
804 si = sampleimage._asdict()
805 si["positions"] = self._pos_to_dict(si["positions"])
806 return si
808 else:
809 sampleimages = [r._asdict() for r in sampleimages.all()]
810 for s in sampleimages:
811 s["positions"] = self._pos_to_dict(s["positions"])
812 if os.path.exists(s["file"]):
813 image = Image.open(s["file"])
814 s["width"], s["height"] = image.size
816 return {"total": len(sampleimages), "rows": sampleimages}
818 def add_sampleimage(self, **kwargs):
819 with self.session_scope() as ses:
820 sample = self.get_samples(
821 sampleid=kwargs["sampleid"], no_context=kwargs.get("no_context")
822 )
823 if sample:
824 if "containerinspectionid" not in kwargs:
825 containerinspectionid = self._ensure_default_inspection(
826 sample["containerid"]
827 )
828 else:
829 containerinspectionid = kwargs["containerinspectionid"]
831 sampleimage = self.BLSampleImage(
832 blsampleid=kwargs.get("sampleid"),
833 bltimestamp=datetime.now(),
834 imagefullpath=kwargs.get("file"),
835 micronsperpixelx=kwargs.get("scalex") / 1000,
836 micronsperpixely=kwargs.get("scaley") / 1000,
837 offsetx=kwargs.get("offsetx"),
838 offsety=-1 * kwargs.get("offsety"),
839 containerinspectionid=containerinspectionid,
840 )
842 ses.add(sampleimage)
843 ses.commit()
845 if kwargs.get("positions"):
846 for k, v in kwargs["positions"].items():
847 positioner = self.Positioner(positioner=k, value=v)
848 ses.add(positioner)
849 ses.commit()
851 blshasimagepos = self.BLSampleImage_has_Positioner(
852 blsampleimageid=sampleimage.blsampleimageid,
853 positionerid=positioner.positionerid,
854 value=v,
855 )
856 ses.add(blshasimagepos)
857 ses.commit()
859 return self.get_sampleimages(
860 sampleimageid=sampleimage.blsampleimageid,
861 no_context=kwargs.get("no_context"),
862 )
864 def add_container_inspection(self, containerid):
865 with self.session_scope() as ses:
866 containerinspection = self.ContainerInspection(
867 containerid=containerid,
868 inspectiontypeid=1,
869 manual=1,
870 scheduledtimestamp=datetime.now(),
871 completedtimestamp=datetime.now(),
872 )
874 ses.add(containerinspection)
875 ses.commit()
877 return containerinspection.containerinspectionid
879 def _ensure_default_inspection(self, containerid):
880 with self.session_scope() as ses:
881 containerinspection = (
882 ses.query(self.ContainerInspection.containerinspectionid)
883 .filter(self.ContainerInspection.containerid == containerid)
884 .first()
885 )
887 if not containerinspection:
888 return self.add_container_inspection(containerid)
890 return containerinspection.containerinspectionid
892 def _ensure_default_container(self):
893 with self.session_scope() as ses:
894 shipment_name = g.blsession.get("session") + "_Shipment1"
895 shipment = (
896 ses.query(self.Shipping.shippingid)
897 .filter(self.Shipping.proposalid == g.blsession.get("proposalid"))
898 .filter(self.Shipping.shippingname == shipment_name)
899 .first()
900 )
902 if not shipment:
903 shipment = self.Shipping(
904 shippingname=shipment_name,
905 proposalid=g.blsession.get("proposalid"),
906 creationdate=datetime.now(),
907 )
909 ses.add(shipment)
910 ses.commit()
912 dewar_name = g.blsession.get("session") + "_Dewar1"
913 dewar = (
914 ses.query(self.Dewar.dewarid)
915 .filter(self.Dewar.shippingid == shipment.shippingid)
916 .filter(self.Dewar.code == dewar_name)
917 .first()
918 )
920 if not dewar:
921 dewar = self.Dewar(
922 shippingid=shipment.shippingid,
923 code=dewar_name,
924 dewarstatus="processing",
925 )
926 ses.add(dewar)
927 ses.commit()
929 container_name = g.blsession.get("session") + "_Container1"
930 container = (
931 ses.query(self.Container.containerid)
932 .filter(self.Container.dewarid == dewar.dewarid)
933 .filter(self.Container.code == container_name)
934 .first()
935 )
937 if not container:
938 container = self.Container(
939 dewarid=dewar.dewarid,
940 code=container_name,
941 containertype="Box",
942 capacity=self._config.get("meta_capacity", 25),
943 beamlinelocation=self._config["meta_beamline"],
944 samplechangerlocation=1,
945 bltimestamp=datetime.now(),
946 containerstatus="processing",
947 )
948 ses.add(container)
949 ses.commit()
951 containerhistory = self.ContainerHistory(
952 containerid=container.containerid,
953 status="processing",
954 location=1,
955 beamlinename=self._config["meta_beamline"],
956 )
958 ses.add(containerhistory)
959 ses.commit()
961 return container.containerid
963 def _ensure_default_component(self):
964 with self.session_scope() as ses:
965 component_name = g.blsession.get("session") + "_Component1"
966 component_acronym = g.blsession.get("session") + "_c1"
968 component = (
969 ses.query(self.Protein.proteinid)
970 .filter(self.Protein.proposalid == g.blsession.get("proposalid"))
971 .filter(self.Protein.name == component_name)
972 .first()
973 )
975 if not component:
976 component = self.Protein(
977 name=component_name,
978 acronym=component_acronym,
979 proposalid=g.blsession.get("proposalid"),
980 )
982 ses.add(component)
983 ses.commit()
985 return component.proteinid