Skip to content

Commit

Permalink
add functionality to digest all assemblies in build with bespoke REs
Browse files Browse the repository at this point in the history
  • Loading branch information
hainesm6 committed Nov 2, 2021
1 parent 93e4891 commit 6dc3cd7
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 59 deletions.
1 change: 1 addition & 0 deletions basicsynbio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
BasicBuild,
BuildDecoder,
BuildEncoder,
build_digest,
new_part_resuspension,
export_echo_assembly,
pdf_instructions,
Expand Down
7 changes: 6 additions & 1 deletion basicsynbio/cam/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from .csv_export import export_csvs
from .echo_instructions import export_echo_assembly
from .pdf_instructions import pdf_instructions
from .csv_export import export_csvs
from .main import *
from .misc_funs import (
build_digest,
new_part_resuspension,
seqrecord_hexdigest,
)
61 changes: 4 additions & 57 deletions basicsynbio/cam/main.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,19 @@
"""Module contains a collection of objects for computer assisted manufacturing
within the BASIC DNA assembly framework."""
"""Module contains key objects for computer assisted manufacturing (CAM)
within the BASIC DNA assembly framework.
"""

from Bio.SeqUtils import molecular_weight
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
from basicsynbio.main import (
BasicAssembly,
BasicLinker,
BasicPart,
BasicUTRRBSLinker,
ClipReaction,
LinkerException,
)
import csv
from dataclasses import dataclass
from datetime import datetime
from collections import OrderedDict, Counter
import hashlib
import json
import os
from pathlib import Path
from typing import Union, Dict, Generator
from typing import Dict, Generator
import re
import zipfile


def new_part_resuspension(
part: BasicPart, mass: float, double_stranded: bool = True
) -> float:
"""Returns the volume of resuspension buffer (µL) required for a 75 nM
solution of part, equivalent to 75 fmol/µL.
Args:
part: BasicPart object.
mass: mass of synthesised part (ng).
double_stranded (optional): True (default) indicates part is dsDNA.
"""
return (
(mass * 10 ** -9)
/ molecular_weight(part.seq, double_stranded=double_stranded)
* 1
/ (75e-9)
* 10 ** 6
)


class BasicBuild:
Expand Down Expand Up @@ -448,27 +419,3 @@ def return_unique_linkers(dictionary):

class BuildException(Exception):
pass


def seqrecord_hexdigest(seqrecord_obj: Union[SeqRecord, BasicPart, BasicLinker]) -> str:
"""Returns an MD5 hash of a Bio.SeqRecord.SeqRecord-like object, using
relevant attributes.
Note:
Care should be taken when using the return value of this function as an identifier/hash for seqrecord_obj given these objects are mutable.
Args:
seqrecord_obj: Bio.SeqRecord.SeqRecord-like object, containing relevant
attributes
Returns:
MD5 hash
"""
seqrec_hash = hashlib.md5(str(seqrecord_obj.seq).encode("UTF-8"))
bytes_objs = [
getattr(seqrecord_obj, attribute).encode("UTF-8")
for attribute in ["name", "description"]
]
for element in bytes_objs:
seqrec_hash.update(element)
return seqrec_hash.hexdigest()
95 changes: 95 additions & 0 deletions basicsynbio/cam/misc_funs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""Module contains several small functions that support or utilise key cam
objects but each is not critical to the bsb workflow.
"""


from Bio.Restriction import BsaI
from Bio.SeqUtils import molecular_weight
from Bio.SeqRecord import SeqRecord
from Bio.Seq import Seq
from basicsynbio.main import BasicAssembly, BasicPart, BasicLinker
from .main import BasicBuild
from dataclasses import dataclass
import hashlib
from typing import Generator, Tuple, Union


@dataclass
class AssemblyDigest:
"""class to return data calculated by `build_digest` function."""

assembly: BasicAssembly
restriction_enzyme: str
sequences: Tuple[Seq, ...]
product_lengths: Tuple[int, ...]


def seqrecord_hexdigest(seqrecord_obj: Union[SeqRecord, BasicPart, BasicLinker]) -> str:
"""Returns an MD5 hash of a Bio.SeqRecord.SeqRecord-like object, using
relevant attributes.
Note:
Care should be taken when using the return value of this function as an identifier/hash for seqrecord_obj given these objects are mutable.
Args:
seqrecord_obj: Bio.SeqRecord.SeqRecord-like object, containing relevant
attributes
Returns:
MD5 hash
"""
seqrec_hash = hashlib.md5(str(seqrecord_obj.seq).encode("UTF-8"))
bytes_objs = [
getattr(seqrecord_obj, attribute).encode("UTF-8")
for attribute in ["name", "description"]
]
for element in bytes_objs:
seqrec_hash.update(element)
return seqrec_hash.hexdigest()


def new_part_resuspension(
part: BasicPart, mass: float, double_stranded: bool = True
) -> float:
"""Returns the volume of resuspension buffer (µL) required for a 75 nM
solution of part, equivalent to 75 fmol/µL.
Args:
part: BasicPart object.
mass: mass of synthesised part (ng).
double_stranded (optional): True (default) indicates part is dsDNA.
"""
return (
(mass * 10 ** -9)
/ molecular_weight(part.seq, double_stranded=double_stranded)
* 1
/ (75e-9)
* 10 ** 6
)


def build_digest(
build: BasicBuild,
restriction_enzyme: None = BsaI,
) -> Generator[AssemblyDigest, None, None]:
"""Conduct a diagnostic digest on basic_assemblies in build.
Function uses a single Bio.Restriction enzyme to digest all BasicAssembly objects
in build. The resulting AssemblyDigest dataclass contains data on sequences and
product lengths generated from digest.
Args:
build: BasicBuild object.
restriction_enzyme: A single restriction enzyme from Bio.Restriction
"""
for assembly in build.basic_assemblies:
assembly_digest = restriction_enzyme.catalyse(
assembly.return_part().seq, linear=False
)
yield AssemblyDigest(
assembly,
restriction_enzyme.__name__,
assembly_digest,
tuple(len(seq) for seq in assembly_digest),
)
13 changes: 13 additions & 0 deletions tests/test_cam.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,16 @@ def test_decoded_build(promoter_assemblies_build, promoter_assemblies_json):
)
== True
)


def test_build_digest(promoter_assemblies_build):
build_digest = tuple(bsb.build_digest(promoter_assemblies_build))
assert len(build_digest) == len(promoter_assemblies_build.basic_assemblies)
for assembly_digest in build_digest:
assert len(assembly_digest.sequences) == 2
promoter_assemblies_returned_parts = (
assembly.return_part()
for assembly in promoter_assemblies_build.basic_assemblies
)
for ind, part in enumerate(promoter_assemblies_returned_parts):
assert len(part.basic_slice()) + 6 in build_digest[ind].product_lengths
2 changes: 1 addition & 1 deletion tests/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def all_promoter_assemblies_build():
@pytest.fixture
def bb_linker():
from Bio.Seq import Seq
from basicsynbio.cam.main import seqrecord_hexdigest
from basicsynbio.cam import seqrecord_hexdigest

bb_linker = bsb.BasicLinker(
seq=Seq("GGCTCGGCCCACTTGTGTGTCTCGTACAATTCTGAGGTCCACACAGATAGTGTCC"),
Expand Down

0 comments on commit 6dc3cd7

Please sign in to comment.