Source code for moclo.core.parts
# coding: utf-8
"""Moclo part classes.
"""
import typing
from Bio.Seq import Seq
from .._utils import isabstract
from .modules import AbstractModule
from .vectors import AbstractVector
from ._structured import StructuredRecord
from ._utils import cutter_check
if typing.TYPE_CHECKING:
from typing import Union # noqa: F401
from Bio.SeqRecord import SeqRecord # noqa: F401
__all__ = ["AbstractPart"]
[docs]class AbstractPart(StructuredRecord):
"""An abstract modular cloning part.
Parts can be either modules or vectors, but are determined by their
flanking overhangs sequences, declared in the ``signature`` class
attribute. The part structure is derived from the part class (module
of vector), signature, and restriction enzyme.
Example:
>>> class ExamplePart(AbstractPart, Entry):
... cutter = BsaI
... signature = ('ATGC', 'ATTC')
...
>>> ExamplePart.structure()
'GGTCTCN(ATGC)(NN*N)(ATTC)NGAGACC'
"""
cutter = NotImplemented
signature = NotImplemented
def __new__(cls, *args, **kwargs):
cutter_check(cls.cutter, name=cls.__name__)
return super(AbstractPart, cls).__new__(cls)
[docs] @classmethod
def structure(cls):
# type: () -> Text
"""Get the part structure, as a DNA regex pattern.
The structure of most parts can be obtained automatically from the
part signature and the restriction enzyme used in the Golden Gate
assembly.
Warning:
If overloading this method, the returned pattern must include 3
capture groups to capture the following features:
1. The upstream (5') overhang sequence
2. The vector placeholder sequence
3. The downstream (3') overhang sequence
"""
if cls.signature is NotImplemented:
raise NotImplementedError("no signature defined")
up = cls.cutter.elucidate()
down = str(Seq(up).reverse_complement())
ovhg = cls.cutter.ovhgseq
upsig, downsig = cls.signature
if cls.cutter.is_5overhang():
upsite = "^{}_".format(ovhg)
downsite = "_{}^".format(Seq(ovhg).reverse_complement())
else:
upsite = "_{}^".format(ovhg)
downsite = "^{}_".format(Seq(ovhg).reverse_complement())
if issubclass(cls, AbstractModule):
return "".join(
[
up.replace(upsite, "({})(".format(upsig)),
"N*",
down.replace(downsite, ")({})".format(downsig)),
]
)
elif issubclass(cls, AbstractVector):
return "".join(
[
down.replace(downsite, "({})(".format(downsig)),
"N*",
up.replace(upsite, ")({})".format(upsig)),
]
)
else:
raise RuntimeError("Part must be either a module or a vector!")
[docs] @classmethod
def characterize(cls, record):
"""Load the record in a concrete subclass of this type.
"""
classes = list(cls.__subclasses__())
if not isabstract(cls):
classes.append(cls)
for subclass in classes:
entity = subclass(record)
if entity.is_valid():
return entity
raise RuntimeError("could not find the type for '{}'".format(record.id))