From ec2c2d226b55d890040be8a5fd856fa773a23588 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Mon, 16 Dec 2024 22:32:57 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=8D=B1=20Create=20the=20Biologic=20re?= =?UTF-8?q?gistry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ogic_biologic_artifactbiologic_biologic.py | 191 ++++++++++++++++++ wetlab/models.py | 78 +++++++ 2 files changed, 269 insertions(+) create mode 100644 wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py diff --git a/wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py b/wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py new file mode 100644 index 0000000..6794118 --- /dev/null +++ b/wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py @@ -0,0 +1,191 @@ +# Generated by Django 5.1.3 on 2024-12-16 21:32 + +import django.db.models.deletion +import lnschema_core.fields +import lnschema_core.ids +import lnschema_core.models +import lnschema_core.users +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("bionty", "0041_squashed"), + ("lnschema_core", "0069_squashed"), + ("wetlab", "0028_remove_combinationperturbation_compounds_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="ArtifactBiologic", + fields=[ + ( + "created_at", + lnschema_core.fields.DateTimeField( + auto_now_add=True, db_index=True + ), + ), + ("id", models.BigAutoField(primary_key=True, serialize=False)), + ( + "label_ref_is_name", + lnschema_core.fields.BooleanField( + blank=True, default=None, null=True + ), + ), + ( + "feature_ref_is_name", + lnschema_core.fields.BooleanField( + blank=True, default=None, null=True + ), + ), + ( + "artifact", + lnschema_core.fields.ForeignKey( + blank=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="links_biologic", + to="lnschema_core.artifact", + ), + ), + ( + "created_by", + lnschema_core.fields.ForeignKey( + blank=True, + default=lnschema_core.users.current_user_id, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="lnschema_core.user", + ), + ), + ( + "feature", + lnschema_core.fields.ForeignKey( + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="links_artifactbiologic", + to="lnschema_core.feature", + ), + ), + ( + "run", + lnschema_core.fields.ForeignKey( + blank=True, + default=lnschema_core.models.current_run, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="lnschema_core.run", + ), + ), + ], + options={ + "abstract": False, + }, + bases=(lnschema_core.models.LinkORM, models.Model), + ), + migrations.CreateModel( + name="Biologic", + fields=[ + ( + "created_at", + lnschema_core.fields.DateTimeField( + auto_now_add=True, db_index=True + ), + ), + ( + "updated_at", + lnschema_core.fields.DateTimeField(auto_now=True, db_index=True), + ), + ("id", models.AutoField(primary_key=True, serialize=False)), + ( + "uid", + lnschema_core.fields.CharField( + blank=True, + default=lnschema_core.ids.base62_12, + max_length=12, + unique=True, + ), + ), + ( + "name", + lnschema_core.fields.CharField( + blank=True, db_index=True, default=None, max_length=256 + ), + ), + ( + "abbr", + lnschema_core.fields.CharField( + blank=True, + db_index=True, + default=None, + max_length=32, + null=True, + unique=True, + ), + ), + ( + "synonyms", + lnschema_core.fields.TextField(blank=True, default=None, null=True), + ), + ( + "description", + lnschema_core.fields.TextField(blank=True, default=None, null=True), + ), + ( + "_previous_runs", + models.ManyToManyField(related_name="+", to="lnschema_core.run"), + ), + ( + "artifacts", + models.ManyToManyField( + related_name="biologics", + through="wetlab.ArtifactBiologic", + to="lnschema_core.artifact", + ), + ), + ( + "created_by", + lnschema_core.fields.ForeignKey( + blank=True, + default=lnschema_core.users.current_user_id, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="lnschema_core.user", + ), + ), + ( + "proteins", + models.ManyToManyField( + related_name="biologics", to="bionty.protein" + ), + ), + ( + "run", + lnschema_core.fields.ForeignKey( + blank=True, + default=lnschema_core.models.current_run, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="lnschema_core.run", + ), + ), + ], + options={ + "abstract": False, + }, + bases=(lnschema_core.models.CanCurate, models.Model), + ), + migrations.AddField( + model_name="artifactbiologic", + name="biologic", + field=lnschema_core.fields.ForeignKey( + blank=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="links_artifact", + to="wetlab.biologic", + ), + ), + ] diff --git a/wetlab/models.py b/wetlab/models.py index 35a3aa3..274cc5f 100644 --- a/wetlab/models.py +++ b/wetlab/models.py @@ -55,6 +55,84 @@ # return "" +class Biologic(CanCurate, TracksRun, TracksUpdates): + """Proteins, peptides, antibodies, enzymes, growth factors, viral infections. + + - Proteins + - Peptides + - Antibodies + - Enzymes + - Growth factors + - Viral infections (they're biological agents causing direct perturbation, different from viral vector which belongs to genetic perturbagen) + + Examples: + >>> biologic = wl.Biologic( + ... name="IFNG", + ... ).save() + """ + + class Meta(BioRecord.Meta, TracksRun.Meta, TracksUpdates.Meta): + abstract = False + + _name_field: str = "name" + + id: int = models.AutoField(primary_key=True) + """Internal id, valid only in one DB instance.""" + uid: str = CharField(unique=True, max_length=12, default=ids.base62_12) + """A universal id (hash of selected field).""" + name: str = CharField(max_length=256, db_index=True) + """Name of the compound.""" + abbr: str | None = CharField( + max_length=32, db_index=True, unique=True, null=True, default=None + ) + """A unique abbreviation.""" + synonyms: str | None = TextField(null=True, default=None) + """Bar-separated (|) synonyms that correspond to this compound.""" + description: str | None = TextField(null=True, default=None) + """Description of the compound.""" + proteins: Protein = models.ManyToManyField( + "bionty.Protein", related_name="biologics" + ) + """Proteins associated with this biologic.""" + artifacts: Artifact = models.ManyToManyField( + Artifact, through="ArtifactBiologic", related_name="biologics" + ) + """Artifacts linked to the compound.""" + + @overload + def __init__( + self, + name: str, + abbr: str | None, + synonyms: str | None, + description: str | None, + ): ... + + @overload + def __init__( + self, + *db_args, + ): ... + + def __init__( + self, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + + +class ArtifactBiologic(Record, LinkORM, TracksRun): + id: int = models.BigAutoField(primary_key=True) + artifact: Artifact = ForeignKey(Artifact, CASCADE, related_name="links_biologic") + biologic: Biologic = ForeignKey(Biologic, PROTECT, related_name="links_artifact") + feature: Feature = ForeignKey( + Feature, PROTECT, null=True, default=None, related_name="links_artifactbiologic" + ) + label_ref_is_name: bool | None = BooleanField(null=True, default=None) + feature_ref_is_name: bool | None = BooleanField(null=True, default=None) + + class Compound(BioRecord, TracksRun, TracksUpdates): """Models a (chemical) compound such as a drug. From 6858d753910698f7aa035b743ec3194c80ba6e26 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Mon, 16 Dec 2024 22:50:05 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=8E=A8=20Add=20a=20type=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wetlab/__init__.py | 13 +- ...ogic_biologic_artifactbiologic_biologic.py | 20 ++- wetlab/models.py | 158 +++++++++--------- wetlab/types.py | 12 ++ 4 files changed, 119 insertions(+), 84 deletions(-) diff --git a/wetlab/__init__.py b/wetlab/__init__.py index 79cfbaf..69f2af4 100644 --- a/wetlab/__init__.py +++ b/wetlab/__init__.py @@ -11,8 +11,8 @@ Create records: ->>> compound_perturbation = wl.CompoundPerturbation( -... name="Aspirin treatment day 1", +>>> biosample = wl.Biosample( +... name="Sample 1", ... ).save() Registries: @@ -30,7 +30,14 @@ EnvironmentalPerturbation GeneticPerturbation PerturbationTarget + +Types: + +.. autosummary:: + :toctree: . + GeneticPerturbationSystem + BiologicType """ @@ -62,7 +69,7 @@ def __getattr__(name): Techsample, Well, ) - from .types import GeneticPerturbationSystem + from .types import BiologicType, GeneticPerturbationSystem # backwards compatibility CombinationTreatment = CombinationPerturbation diff --git a/wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py b/wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py index 6794118..e2ecce9 100644 --- a/wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py +++ b/wetlab/migrations/0029_artifactbiologic_biologic_artifactbiologic_biologic.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2024-12-16 21:32 +# Generated by Django 5.1.3 on 2024-12-16 21:49 import django.db.models.deletion import lnschema_core.fields @@ -111,7 +111,17 @@ class Migration(migrations.Migration): ( "name", lnschema_core.fields.CharField( - blank=True, db_index=True, default=None, max_length=256 + blank=True, + db_index=True, + default=None, + max_length=255, + unique=True, + ), + ), + ( + "type", + lnschema_core.fields.CharField( + blank=True, db_index=True, default=None, max_length=32 ), ), ( @@ -172,6 +182,12 @@ class Migration(migrations.Migration): to="lnschema_core.run", ), ), + ( + "targets", + models.ManyToManyField( + related_name="biologic_targets", to="wetlab.perturbationtarget" + ), + ), ], options={ "abstract": False, diff --git a/wetlab/models.py b/wetlab/models.py index 274cc5f..76575bd 100644 --- a/wetlab/models.py +++ b/wetlab/models.py @@ -41,7 +41,7 @@ TracksUpdates, ) -from .types import GeneticPerturbationSystem # noqa +from .types import BiologicType, GeneticPerturbationSystem # noqa # def _get_related_repr(instance, related_name: str) -> str: # try: @@ -55,84 +55,6 @@ # return "" -class Biologic(CanCurate, TracksRun, TracksUpdates): - """Proteins, peptides, antibodies, enzymes, growth factors, viral infections. - - - Proteins - - Peptides - - Antibodies - - Enzymes - - Growth factors - - Viral infections (they're biological agents causing direct perturbation, different from viral vector which belongs to genetic perturbagen) - - Examples: - >>> biologic = wl.Biologic( - ... name="IFNG", - ... ).save() - """ - - class Meta(BioRecord.Meta, TracksRun.Meta, TracksUpdates.Meta): - abstract = False - - _name_field: str = "name" - - id: int = models.AutoField(primary_key=True) - """Internal id, valid only in one DB instance.""" - uid: str = CharField(unique=True, max_length=12, default=ids.base62_12) - """A universal id (hash of selected field).""" - name: str = CharField(max_length=256, db_index=True) - """Name of the compound.""" - abbr: str | None = CharField( - max_length=32, db_index=True, unique=True, null=True, default=None - ) - """A unique abbreviation.""" - synonyms: str | None = TextField(null=True, default=None) - """Bar-separated (|) synonyms that correspond to this compound.""" - description: str | None = TextField(null=True, default=None) - """Description of the compound.""" - proteins: Protein = models.ManyToManyField( - "bionty.Protein", related_name="biologics" - ) - """Proteins associated with this biologic.""" - artifacts: Artifact = models.ManyToManyField( - Artifact, through="ArtifactBiologic", related_name="biologics" - ) - """Artifacts linked to the compound.""" - - @overload - def __init__( - self, - name: str, - abbr: str | None, - synonyms: str | None, - description: str | None, - ): ... - - @overload - def __init__( - self, - *db_args, - ): ... - - def __init__( - self, - *args, - **kwargs, - ): - super().__init__(*args, **kwargs) - - -class ArtifactBiologic(Record, LinkORM, TracksRun): - id: int = models.BigAutoField(primary_key=True) - artifact: Artifact = ForeignKey(Artifact, CASCADE, related_name="links_biologic") - biologic: Biologic = ForeignKey(Biologic, PROTECT, related_name="links_artifact") - feature: Feature = ForeignKey( - Feature, PROTECT, null=True, default=None, related_name="links_artifactbiologic" - ) - label_ref_is_name: bool | None = BooleanField(null=True, default=None) - feature_ref_is_name: bool | None = BooleanField(null=True, default=None) - - class Compound(BioRecord, TracksRun, TracksUpdates): """Models a (chemical) compound such as a drug. @@ -467,6 +389,84 @@ class ArtifactGeneticPerturbation(Record, LinkORM, TracksRun): feature_ref_is_name: bool | None = BooleanField(null=True, default=None) +class Biologic(CanCurate, TracksRun, TracksUpdates): + """Proteins, peptides, antibodies, enzymes, growth factors, etc. + + Examples: + >>> biologic = wl.Biologic( + ... name="IFNG", + ... type="cytokine", + ... ).save() + """ + + class Meta(BioRecord.Meta, TracksRun.Meta, TracksUpdates.Meta): + abstract = False + + _name_field: str = "name" + + id: int = models.AutoField(primary_key=True) + """Internal id, valid only in one DB instance.""" + uid: str = CharField(unique=True, max_length=12, default=ids.base62_12) + """A universal id (hash of selected field).""" + name: str = CharField(unique=True, db_index=True) + """Name of the compound.""" + type: BiologicType = CharField(max_length=32, db_index=True, default=None) + """The type.""" + abbr: str | None = CharField( + max_length=32, db_index=True, unique=True, null=True, default=None + ) + """A unique abbreviation.""" + synonyms: str | None = TextField(null=True, default=None) + """Bar-separated (|) synonyms that correspond to this compound.""" + description: str | None = TextField(null=True, default=None) + """Description of the compound.""" + proteins: Protein = models.ManyToManyField( + "bionty.Protein", related_name="biologics" + ) + """Proteins associated with this biologic.""" + targets: PerturbationTarget = models.ManyToManyField( + PerturbationTarget, related_name="biologic_targets" + ) + """Targets of the perturbation.""" + artifacts: Artifact = models.ManyToManyField( + Artifact, through="ArtifactBiologic", related_name="biologics" + ) + """Artifacts linked to the compound.""" + + @overload + def __init__( + self, + name: str, + abbr: str | None, + synonyms: str | None, + description: str | None, + ): ... + + @overload + def __init__( + self, + *db_args, + ): ... + + def __init__( + self, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + + +class ArtifactBiologic(Record, LinkORM, TracksRun): + id: int = models.BigAutoField(primary_key=True) + artifact: Artifact = ForeignKey(Artifact, CASCADE, related_name="links_biologic") + biologic: Biologic = ForeignKey(Biologic, PROTECT, related_name="links_artifact") + feature: Feature = ForeignKey( + Feature, PROTECT, null=True, default=None, related_name="links_artifactbiologic" + ) + label_ref_is_name: bool | None = BooleanField(null=True, default=None) + feature_ref_is_name: bool | None = BooleanField(null=True, default=None) + + class CompoundPerturbation(Record, CanCurate, TracksRun, TracksUpdates): """Models compound perturbations such as drugs. diff --git a/wetlab/types.py b/wetlab/types.py index dfa0f0e..01c18a7 100644 --- a/wetlab/types.py +++ b/wetlab/types.py @@ -9,3 +9,15 @@ "transgene", "transient-transfection", ] + +BiologicType = Literal[ + "protein", + "peptide", + "antibody", + "enzyme", + "growth-factor", + "cytokine", + "hormone", + "vaccine", + "oligonucleotide", +] From 8e92bd2feeca956b424e67680d1503070e6ec684 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Mon, 16 Dec 2024 22:56:06 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=92=9A=20Fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wetlab/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wetlab/models.py b/wetlab/models.py index 76575bd..6f96903 100644 --- a/wetlab/models.py +++ b/wetlab/models.py @@ -389,7 +389,7 @@ class ArtifactGeneticPerturbation(Record, LinkORM, TracksRun): feature_ref_is_name: bool | None = BooleanField(null=True, default=None) -class Biologic(CanCurate, TracksRun, TracksUpdates): +class Biologic(Record, CanCurate, TracksRun, TracksUpdates): """Proteins, peptides, antibodies, enzymes, growth factors, etc. Examples: