Pre-reagent/submission association update.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
## 202312.01
|
## 202312.01
|
||||||
|
|
||||||
|
- Control samples info now available in plate map.
|
||||||
- Backups will now create an regenerated xlsx file.
|
- Backups will now create an regenerated xlsx file.
|
||||||
- Report generator now does sums automatically.
|
- Report generator now does sums automatically.
|
||||||
|
|
||||||
|
|||||||
2
TODO.md
2
TODO.md
@@ -27,7 +27,7 @@
|
|||||||
- Should be used when coming in to parser and when leaving form. NO OTHER PLACES.
|
- Should be used when coming in to parser and when leaving form. NO OTHER PLACES.
|
||||||
- [x] Change 'check_is_power_user' to decorator.
|
- [x] Change 'check_is_power_user' to decorator.
|
||||||
- [x] Drag and drop files into submission form area?
|
- [x] Drag and drop files into submission form area?
|
||||||
- [ ] Get info for controls into their sample hitpicks.
|
- [x] Get info for controls into their sample hitpicks.
|
||||||
- [x] Move submission-type specific parser functions into class methods in their respective models.
|
- [x] Move submission-type specific parser functions into class methods in their respective models.
|
||||||
- [x] Improve function results reporting.
|
- [x] Improve function results reporting.
|
||||||
- Maybe make it a list until it gets to the reporter?
|
- Maybe make it a list until it gets to the reporter?
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne
|
|||||||
|
|
||||||
; sqlalchemy.url = sqlite:///L:\Robotics Laboratory Support\Submissions\submissions.db
|
; sqlalchemy.url = sqlite:///L:\Robotics Laboratory Support\Submissions\submissions.db
|
||||||
; sqlalchemy.url = sqlite:///C:\Users\lwark\Documents\Archives\Submissions_app_backups\DB_backups\submissions-new.db
|
; sqlalchemy.url = sqlite:///C:\Users\lwark\Documents\Archives\Submissions_app_backups\DB_backups\submissions-new.db
|
||||||
; sqlalchemy.url = sqlite:///C:\Users\lwark\Documents\python\submissions\tests\test_assets\submissions-test.db
|
sqlalchemy.url = sqlite:///C:\Users\lwark\Documents\python\submissions\tests\test_assets\submissions-test.db
|
||||||
|
|
||||||
|
|
||||||
[post_write_hooks]
|
[post_write_hooks]
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
"""link controls with Bacterial Culture Samples
|
||||||
|
|
||||||
|
Revision ID: 2684f065037c
|
||||||
|
Revises: 7e7b6eeca468
|
||||||
|
Create Date: 2023-12-05 10:29:31.126732
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '2684f065037c'
|
||||||
|
down_revision = '7e7b6eeca468'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('_control_samples', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('sample_id', sa.INTEGER(), nullable=True))
|
||||||
|
batch_op.create_foreign_key('cont_BCS_id', '_samples', ['sample_id'], ['id'], ondelete='SET NULL')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('_control_samples', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint('cont_BCS_id', type_='foreignkey')
|
||||||
|
batch_op.drop_column('sample_id')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@@ -71,6 +71,8 @@ class Control(BaseClass):
|
|||||||
refseq_version = Column(String(16)) #: version of refseq used in fastq parsing
|
refseq_version = Column(String(16)) #: version of refseq used in fastq parsing
|
||||||
kraken2_version = Column(String(16)) #: version of kraken2 used in fastq parsing
|
kraken2_version = Column(String(16)) #: version of kraken2 used in fastq parsing
|
||||||
kraken2_db_version = Column(String(32)) #: folder name of kraken2 db
|
kraken2_db_version = Column(String(32)) #: folder name of kraken2 db
|
||||||
|
sample = relationship("BacterialCultureSample", back_populates="control")
|
||||||
|
sample_id = Column(INTEGER, ForeignKey("_samples.id", ondelete="SET NULL", name="cont_BCS_id"))
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Control({self.name})>"
|
return f"<Control({self.name})>"
|
||||||
@@ -243,3 +245,8 @@ class Control(BaseClass):
|
|||||||
case _:
|
case _:
|
||||||
pass
|
pass
|
||||||
return query_return(query=query, limit=limit)
|
return query_return(query=query, limit=limit)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self.__database_session__.add(self)
|
||||||
|
self.__database_session__.commit()
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class BasicSubmission(BaseClass):
|
|||||||
run_cost = Column(FLOAT(2)) #: total cost of running the plate. Set from constant and mutable kit costs at time of creation.
|
run_cost = Column(FLOAT(2)) #: total cost of running the plate. Set from constant and mutable kit costs at time of creation.
|
||||||
uploaded_by = Column(String(32)) #: user name of person who submitted the submission to the database.
|
uploaded_by = Column(String(32)) #: user name of person who submitted the submission to the database.
|
||||||
comment = Column(JSON) #: user notes
|
comment = Column(JSON) #: user notes
|
||||||
submission_category = Column(String(64)) #: ["Research", "Diagnostic", "Surveillance"], else defaults to submission_type_name
|
submission_category = Column(String(64)) #: ["Research", "Diagnostic", "Surveillance", "Validation"], else defaults to submission_type_name
|
||||||
|
|
||||||
submission_sample_associations = relationship(
|
submission_sample_associations = relationship(
|
||||||
"SubmissionSampleAssociation",
|
"SubmissionSampleAssociation",
|
||||||
@@ -1483,6 +1483,7 @@ class BacterialCultureSample(BasicSample):
|
|||||||
# id = Column(INTEGER, ForeignKey('basicsample.id'), primary_key=True)
|
# id = Column(INTEGER, ForeignKey('basicsample.id'), primary_key=True)
|
||||||
organism = Column(String(64)) #: bacterial specimen
|
organism = Column(String(64)) #: bacterial specimen
|
||||||
concentration = Column(String(16)) #: sample concentration
|
concentration = Column(String(16)) #: sample concentration
|
||||||
|
control = relationship("Control", back_populates="sample", uselist=False)
|
||||||
__mapper_args__ = {"polymorphic_identity": "Bacterial Culture Sample", "polymorphic_load": "inline"}
|
__mapper_args__ = {"polymorphic_identity": "Bacterial Culture Sample", "polymorphic_load": "inline"}
|
||||||
|
|
||||||
def to_sub_dict(self, submission_rsl:str) -> dict:
|
def to_sub_dict(self, submission_rsl:str) -> dict:
|
||||||
@@ -1496,6 +1497,13 @@ class BacterialCultureSample(BasicSample):
|
|||||||
sample['name'] = f"{self.submitter_id} - ({self.organism})"
|
sample['name'] = f"{self.submitter_id} - ({self.organism})"
|
||||||
return sample
|
return sample
|
||||||
|
|
||||||
|
def to_hitpick(self, submission_rsl: str | None = None) -> dict | None:
|
||||||
|
sample = super().to_hitpick(submission_rsl)
|
||||||
|
if self.control != None:
|
||||||
|
sample['colour'] = [0,128,0]
|
||||||
|
sample['tooltip'] += f"<br>- Control: {self.control.controltype.name} - {self.control.controltype.targets}"
|
||||||
|
return sample
|
||||||
|
|
||||||
# Submission to Sample Associations
|
# Submission to Sample Associations
|
||||||
|
|
||||||
class SubmissionSampleAssociation(BaseClass):
|
class SubmissionSampleAssociation(BaseClass):
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ class PydSubmission(BaseModel, extra='allow'):
|
|||||||
@field_validator("submission_category")
|
@field_validator("submission_category")
|
||||||
@classmethod
|
@classmethod
|
||||||
def rescue_category(cls, value, values):
|
def rescue_category(cls, value, values):
|
||||||
if value['value'] not in ["Research", "Diagnostic", "Surveillance"]:
|
if value['value'] not in ["Research", "Diagnostic", "Surveillance", "Validation"]:
|
||||||
value['value'] = values.data['submission_type']['value']
|
value['value'] = values.data['submission_type']['value']
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,14 @@ def make_plate_map(sample_list:list) -> Image:
|
|||||||
# Go through samples and change its row/column to red if positive, else blue
|
# Go through samples and change its row/column to red if positive, else blue
|
||||||
for sample in sample_list:
|
for sample in sample_list:
|
||||||
logger.debug(f"sample keys: {list(sample.keys())}")
|
logger.debug(f"sample keys: {list(sample.keys())}")
|
||||||
|
# set color of square
|
||||||
if sample['positive']:
|
if sample['positive']:
|
||||||
colour = [255,0,0]
|
colour = [255,0,0]
|
||||||
else:
|
else:
|
||||||
colour = [0,0,255]
|
if 'colour' in sample.keys():
|
||||||
|
colour = sample['colour']
|
||||||
|
else:
|
||||||
|
colour = [0,0,255]
|
||||||
grid[int(sample['row'])-1][int(sample['column'])-1] = colour
|
grid[int(sample['row'])-1][int(sample['column'])-1] = colour
|
||||||
# Create pixel image from the grid and enlarge
|
# Create pixel image from the grid and enlarge
|
||||||
img = Image.fromarray(grid).resize((1200, 800), resample=Image.NEAREST)
|
img = Image.fromarray(grid).resize((1200, 800), resample=Image.NEAREST)
|
||||||
@@ -99,7 +103,10 @@ def make_plate_map_html(sample_list:list, plate_rows:int=8, plate_columns=12) ->
|
|||||||
if sample['positive']:
|
if sample['positive']:
|
||||||
sample['background_color'] = "#f10f07"
|
sample['background_color'] = "#f10f07"
|
||||||
else:
|
else:
|
||||||
sample['background_color'] = "#80cbc4"
|
if "colour" in sample.keys():
|
||||||
|
sample['background_color'] = "#69d84f"
|
||||||
|
else:
|
||||||
|
sample['background_color'] = "#80cbc4"
|
||||||
output_samples = []
|
output_samples = []
|
||||||
for column in range(1, plate_columns+1):
|
for column in range(1, plate_columns+1):
|
||||||
for row in range(1, plate_rows+1):
|
for row in range(1, plate_rows+1):
|
||||||
|
|||||||
Reference in New Issue
Block a user