synbio-buildcompiler 0.0b1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- synbio_buildcompiler-0.0b1/LICENSE +21 -0
- synbio_buildcompiler-0.0b1/PKG-INFO +79 -0
- synbio_buildcompiler-0.0b1/README.md +56 -0
- synbio_buildcompiler-0.0b1/pyproject.toml +45 -0
- synbio_buildcompiler-0.0b1/setup.cfg +4 -0
- synbio_buildcompiler-0.0b1/src/buildcompiler/__init__.py +1 -0
- synbio_buildcompiler-0.0b1/src/buildcompiler/abstract_translator.py +346 -0
- synbio_buildcompiler-0.0b1/src/buildcompiler/buildcompiler.py +49 -0
- synbio_buildcompiler-0.0b1/src/buildcompiler/constants.py +15 -0
- synbio_buildcompiler-0.0b1/src/buildcompiler/robotutils.py +151 -0
- synbio_buildcompiler-0.0b1/src/buildcompiler/sbol2build.py +1110 -0
- synbio_buildcompiler-0.0b1/src/synbio_buildcompiler.egg-info/PKG-INFO +79 -0
- synbio_buildcompiler-0.0b1/src/synbio_buildcompiler.egg-info/SOURCES.txt +17 -0
- synbio_buildcompiler-0.0b1/src/synbio_buildcompiler.egg-info/dependency_links.txt +1 -0
- synbio_buildcompiler-0.0b1/src/synbio_buildcompiler.egg-info/requires.txt +7 -0
- synbio_buildcompiler-0.0b1/src/synbio_buildcompiler.egg-info/top_level.txt +1 -0
- synbio_buildcompiler-0.0b1/tests/test_abstract.py +146 -0
- synbio_buildcompiler-0.0b1/tests/test_core.py +339 -0
- synbio_buildcompiler-0.0b1/tests/test_helpers.py +91 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Genetic Logic Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: synbio_buildcompiler
|
|
3
|
+
Version: 0.0b1
|
|
4
|
+
Summary: BuildCompiler is a package to decouple the design and build stages
|
|
5
|
+
Author-email: Gonzalo Vidal <gonzalo.vidalpena@colorado.edu>, Ryan Greer <ryan.greer@colorado.edu>
|
|
6
|
+
Maintainer-email: Ryan Greer <ryan.greer@colorado.edu>
|
|
7
|
+
Project-URL: Homepage, https://github.com/MyersResearchGroup/BuildCompiler
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/MyersResearchGroup/BuildCompiler/issues
|
|
9
|
+
Keywords: SBOL,genetic,automation,build,synthetic biology
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: sbol2
|
|
17
|
+
Requires-Dist: biopython
|
|
18
|
+
Requires-Dist: pydna
|
|
19
|
+
Provides-Extra: test
|
|
20
|
+
Requires-Dist: pytest<5.0.0; extra == "test"
|
|
21
|
+
Requires-Dist: pytest-cov[all]; extra == "test"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# BuildCompiler
|
|
25
|
+
BuildCompiler is an open-source tool that bridges the Design and Build stages of the DBTL cycle by compiling SBOL-encoded genetic designs into executable DNA assembly and transformation workflows.
|
|
26
|
+
|
|
27
|
+
It was developed to support build functionality in comand line and cloud workflows in [SynBioSuite](https://synbiosuite.org), based off the [SBOL Best Practices](https://github.com/SynBioDex/SBOL-examples/tree/main/SBOL/best-practices/BP011/).
|
|
28
|
+
|
|
29
|
+
<img src="https://github.com/MyersResearchGroup/BuildCompiler/blob/main/images/buildcompiler_logo.png#gh-light-mode-only" alt="BuildCompiler light logo" width="300"/>
|
|
30
|
+
<img src="https://github.com/MyersResearchGroup/BuildCompiler/blob/main/images/buildcompiler_logo.png#gh-dark-mode-only" alt="BuildCompiler night logo" width="300"/>
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
[](https://sbol2build.readthedocs.io/en/latest/?badge=latest)
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
## Installing BuildCompiler:
|
|
39
|
+
```pip install buildcompiler```
|
|
40
|
+
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
Please visit the documentation with API reference and tutorials at Read the Docs: [sbol2build.rtfd.io](https://sbol2build.readthedocs.io)
|
|
44
|
+
|
|
45
|
+
## Environment Setup
|
|
46
|
+
|
|
47
|
+
If you are interested in contributing to **BuildCompiler**, please set up your local development environment with the same tools used in CI and linting.
|
|
48
|
+
|
|
49
|
+
### 1. Install [uv](https://docs.astral.sh/uv/)
|
|
50
|
+
|
|
51
|
+
`uv` manages all Python dependencies (including dev tools) with a lockfile for reproducibility.
|
|
52
|
+
|
|
53
|
+
#### Linux/Bash
|
|
54
|
+
```bash
|
|
55
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
56
|
+
```
|
|
57
|
+
#### Mac OSX with Homebrew
|
|
58
|
+
```bash
|
|
59
|
+
brew install uv
|
|
60
|
+
```
|
|
61
|
+
### 2. Sync dependencies
|
|
62
|
+
```bash
|
|
63
|
+
uv sync --all-groups
|
|
64
|
+
```
|
|
65
|
+
This will create a virtual environment with the dependiencies. Activate using:
|
|
66
|
+
```bash
|
|
67
|
+
source .venv/bin/activate
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3. Install pre-commit hooks
|
|
71
|
+
We use pre-commit to automatically run the Ruff linter before every commit.
|
|
72
|
+
Install and enable the hooks with:
|
|
73
|
+
```bash
|
|
74
|
+
uv run pre-commit install
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
#### Running tests:
|
|
79
|
+
`uv run python -m unittest discover -s tests`
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# BuildCompiler
|
|
2
|
+
BuildCompiler is an open-source tool that bridges the Design and Build stages of the DBTL cycle by compiling SBOL-encoded genetic designs into executable DNA assembly and transformation workflows.
|
|
3
|
+
|
|
4
|
+
It was developed to support build functionality in comand line and cloud workflows in [SynBioSuite](https://synbiosuite.org), based off the [SBOL Best Practices](https://github.com/SynBioDex/SBOL-examples/tree/main/SBOL/best-practices/BP011/).
|
|
5
|
+
|
|
6
|
+
<img src="https://github.com/MyersResearchGroup/BuildCompiler/blob/main/images/buildcompiler_logo.png#gh-light-mode-only" alt="BuildCompiler light logo" width="300"/>
|
|
7
|
+
<img src="https://github.com/MyersResearchGroup/BuildCompiler/blob/main/images/buildcompiler_logo.png#gh-dark-mode-only" alt="BuildCompiler night logo" width="300"/>
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
[](https://sbol2build.readthedocs.io/en/latest/?badge=latest)
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
## Installing BuildCompiler:
|
|
16
|
+
```pip install buildcompiler```
|
|
17
|
+
|
|
18
|
+
## Documentation
|
|
19
|
+
|
|
20
|
+
Please visit the documentation with API reference and tutorials at Read the Docs: [sbol2build.rtfd.io](https://sbol2build.readthedocs.io)
|
|
21
|
+
|
|
22
|
+
## Environment Setup
|
|
23
|
+
|
|
24
|
+
If you are interested in contributing to **BuildCompiler**, please set up your local development environment with the same tools used in CI and linting.
|
|
25
|
+
|
|
26
|
+
### 1. Install [uv](https://docs.astral.sh/uv/)
|
|
27
|
+
|
|
28
|
+
`uv` manages all Python dependencies (including dev tools) with a lockfile for reproducibility.
|
|
29
|
+
|
|
30
|
+
#### Linux/Bash
|
|
31
|
+
```bash
|
|
32
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
33
|
+
```
|
|
34
|
+
#### Mac OSX with Homebrew
|
|
35
|
+
```bash
|
|
36
|
+
brew install uv
|
|
37
|
+
```
|
|
38
|
+
### 2. Sync dependencies
|
|
39
|
+
```bash
|
|
40
|
+
uv sync --all-groups
|
|
41
|
+
```
|
|
42
|
+
This will create a virtual environment with the dependiencies. Activate using:
|
|
43
|
+
```bash
|
|
44
|
+
source .venv/bin/activate
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Install pre-commit hooks
|
|
48
|
+
We use pre-commit to automatically run the Ruff linter before every commit.
|
|
49
|
+
Install and enable the hooks with:
|
|
50
|
+
```bash
|
|
51
|
+
uv run pre-commit install
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
#### Running tests:
|
|
56
|
+
`uv run python -m unittest discover -s tests`
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "synbio_buildcompiler"
|
|
7
|
+
version = "0.0.b1"
|
|
8
|
+
description = "BuildCompiler is a package to decouple the design and build stages"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {file = "LICENSE.md"}
|
|
12
|
+
keywords = ["SBOL", "genetic", "automation", "build", "synthetic biology"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name="Gonzalo Vidal", email="gonzalo.vidalpena@colorado.edu" },
|
|
15
|
+
{ name="Ryan Greer", email="ryan.greer@colorado.edu" }
|
|
16
|
+
]
|
|
17
|
+
maintainers = [
|
|
18
|
+
{ name = "Ryan Greer", email = "ryan.greer@colorado.edu" }
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
dependencies = [
|
|
27
|
+
"sbol2",
|
|
28
|
+
"biopython",
|
|
29
|
+
"pydna"
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
test = [
|
|
34
|
+
"pytest < 5.0.0",
|
|
35
|
+
"pytest-cov[all]"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
"Homepage" = "https://github.com/MyersResearchGroup/BuildCompiler"
|
|
40
|
+
"Bug Tracker" = "https://github.com/MyersResearchGroup/BuildCompiler/issues"
|
|
41
|
+
|
|
42
|
+
[dependency-groups]
|
|
43
|
+
dev = [
|
|
44
|
+
"ruff>=0.14.0",
|
|
45
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .sbol2build import * # noqa: F403
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import sbol2
|
|
2
|
+
import itertools
|
|
3
|
+
from typing import Dict, List, Union
|
|
4
|
+
from .constants import FUSION_SITES
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MocloPlasmid:
|
|
8
|
+
def __init__(
|
|
9
|
+
self, name: str, definition: sbol2.ComponentDefinition, doc: sbol2.document
|
|
10
|
+
):
|
|
11
|
+
self.definition = definition
|
|
12
|
+
self.fusion_sites = self.match_fusion_sites(doc)
|
|
13
|
+
self.name = name + "".join(f"_{s}" for s in self.fusion_sites)
|
|
14
|
+
|
|
15
|
+
def match_fusion_sites(self, doc: sbol2.document) -> List[str]:
|
|
16
|
+
fusion_site_definitions = extract_fusion_sites(self.definition, doc)
|
|
17
|
+
fusion_sites = []
|
|
18
|
+
for site in fusion_site_definitions:
|
|
19
|
+
sequence_obj = doc.getSequence(site.sequences[0])
|
|
20
|
+
sequence = sequence_obj.elements
|
|
21
|
+
|
|
22
|
+
for key, seq in FUSION_SITES.items():
|
|
23
|
+
if seq == sequence.upper():
|
|
24
|
+
fusion_sites.append(key)
|
|
25
|
+
|
|
26
|
+
fusion_sites.sort()
|
|
27
|
+
return fusion_sites
|
|
28
|
+
|
|
29
|
+
def __repr__(self) -> str:
|
|
30
|
+
return (
|
|
31
|
+
f"MocloPlasmid:\n"
|
|
32
|
+
f" Name: {self.name}\n"
|
|
33
|
+
f" Definition: {self.definition.identity}\n"
|
|
34
|
+
f" Fusion Sites: {self.fusion_sites or 'Not found'}"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def __eq__(self, other):
|
|
38
|
+
if not isinstance(other, MocloPlasmid):
|
|
39
|
+
return False
|
|
40
|
+
return self.definition == other.definition
|
|
41
|
+
|
|
42
|
+
def __hash__(self):
|
|
43
|
+
return hash(self.definition)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def extract_fusion_sites(
|
|
47
|
+
plasmid: sbol2.ComponentDefinition, doc: sbol2.Document
|
|
48
|
+
) -> List[sbol2.ComponentDefinition]:
|
|
49
|
+
"""
|
|
50
|
+
Returns all fusion site component definitions from a plasmid.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
plasmid: :class:`sbol2.ComponentDefinition` representing the plasmid.
|
|
54
|
+
doc: :class:`sbol2.Document` containing component definitions.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
A list of fusion site component definitions.
|
|
58
|
+
"""
|
|
59
|
+
fusion_sites = []
|
|
60
|
+
for component in plasmid.components:
|
|
61
|
+
definition = doc.getComponentDefinition(component.definition)
|
|
62
|
+
if "http://identifiers.org/so/SO:0001953" in definition.roles:
|
|
63
|
+
fusion_sites.append(definition)
|
|
64
|
+
|
|
65
|
+
return fusion_sites
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def extract_design_parts(
|
|
69
|
+
design: sbol2.ComponentDefinition, doc: sbol2.Document
|
|
70
|
+
) -> List[sbol2.ComponentDefinition]:
|
|
71
|
+
"""
|
|
72
|
+
Returns definitions of parts in a design in sequential order.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
design: :class:`sbol2.ComponentDefinition` to extract parts from.
|
|
76
|
+
doc: :class:`sbol2.Document` containing all component definitions.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
A list of component definitions in sequential order.
|
|
80
|
+
"""
|
|
81
|
+
component_list = [c for c in design.getInSequentialOrder()]
|
|
82
|
+
return [
|
|
83
|
+
doc.getComponentDefinition(component.definition) for component in component_list
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def copy_sequences(component_definition, target_doc, collection_doc):
|
|
88
|
+
"""Copy all sequences referenced by a ComponentDefinition into target_doc."""
|
|
89
|
+
subdefinitions = extract_design_parts(component_definition, collection_doc)
|
|
90
|
+
|
|
91
|
+
for seq_uri in component_definition.sequences:
|
|
92
|
+
seq_obj = component_definition.doc.find(seq_uri)
|
|
93
|
+
if seq_obj is not None:
|
|
94
|
+
seq_obj.copy(target_doc)
|
|
95
|
+
|
|
96
|
+
for subdefinition in subdefinitions:
|
|
97
|
+
print(subdefinition.displayId)
|
|
98
|
+
subdefinition.copy(target_doc)
|
|
99
|
+
for seq_uri in subdefinition.sequences:
|
|
100
|
+
seq_obj = component_definition.doc.find(seq_uri)
|
|
101
|
+
if seq_obj is not None:
|
|
102
|
+
seq_obj.copy(target_doc)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def extract_combinatorial_design_parts(
|
|
106
|
+
design: sbol2.ComponentDefinition, doc: sbol2.Document, plasmid_doc
|
|
107
|
+
) -> Dict[str, List[sbol2.ComponentDefinition]]:
|
|
108
|
+
"""
|
|
109
|
+
Extracts and returns a mapping of component definitions from a combinatorial design, in order.
|
|
110
|
+
Variants of combinatinatorial components are entered in a list corresponding to the URI of the component in the abstract design.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
design:
|
|
114
|
+
The :class:`sbol2.ComponentDefinition` representing the top-level design
|
|
115
|
+
from which to extract parts.
|
|
116
|
+
doc:
|
|
117
|
+
The primary :class:`sbol2.Document` containing the base component definitions
|
|
118
|
+
and combinatorial derivations.
|
|
119
|
+
plasmid_doc:
|
|
120
|
+
An additional :class:`sbol2.Document` used to resolve component variants
|
|
121
|
+
(plasmid-specific variants referenced by combinatorial derivations).
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Dict[str, List[sbol2.ComponentDefinition]]:
|
|
125
|
+
A dictionary mapping component identities to lists
|
|
126
|
+
of variable component definitions.
|
|
127
|
+
|
|
128
|
+
- Sequential design components map to lists containing a single definition.
|
|
129
|
+
- Combinatorial variable components map to lists of variant definitions.
|
|
130
|
+
"""
|
|
131
|
+
component_list = [c for c in design.getInSequentialOrder()]
|
|
132
|
+
component_dict = {
|
|
133
|
+
component.identity: [doc.getComponentDefinition(component.definition)]
|
|
134
|
+
for component in component_list
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for deriv in doc.combinatorialderivations:
|
|
138
|
+
for component in deriv.variableComponents:
|
|
139
|
+
component_dict[component.variable] = [
|
|
140
|
+
plasmid_doc.getComponentDefinition(var) for var in component.variants
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
return component_dict
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def extract_toplevel_definition(doc: sbol2.Document) -> sbol2.ComponentDefinition:
|
|
147
|
+
return doc.componentDefinitions[0]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def enumerate_design_variants(component_dict):
|
|
151
|
+
"""
|
|
152
|
+
Given a dict mapping variable component identities to lists of ComponentDefinitions,
|
|
153
|
+
generate all possible design combinations as lists of ComponentDefinitions
|
|
154
|
+
(in consistent order of keys).
|
|
155
|
+
"""
|
|
156
|
+
keys = list(component_dict.keys())
|
|
157
|
+
variant_lists = [component_dict[k] for k in keys]
|
|
158
|
+
|
|
159
|
+
# Cartesian product across all variant lists
|
|
160
|
+
all_variants = list(itertools.product(*variant_lists))
|
|
161
|
+
|
|
162
|
+
all_variants = [list(combo) for combo in all_variants]
|
|
163
|
+
|
|
164
|
+
return all_variants
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def construct_plasmid_dict(
|
|
168
|
+
part_list: List[sbol2.ComponentDefinition], plasmid_collection: sbol2.Document
|
|
169
|
+
) -> Dict[str, List[MocloPlasmid]]:
|
|
170
|
+
"""
|
|
171
|
+
Builds a mapping from part display IDs to lists of compatible MoCloPlasmid objects.
|
|
172
|
+
|
|
173
|
+
For each part in the given list, this function searches the provided plasmid
|
|
174
|
+
collection for plasmids that contain the part as a component.
|
|
175
|
+
Each matching plasmid is wrapped in a `MocloPlasmid` object and added to the
|
|
176
|
+
dictionary under the part's display ID.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
part_list:
|
|
180
|
+
List of :class:`sbol2.ComponentDefinition` objects representing
|
|
181
|
+
the parts to match.
|
|
182
|
+
plasmid_collection:
|
|
183
|
+
The :class:`sbol2.Document` containing plasmids to search through.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
Dict[str, List[MocloPlasmid]]:
|
|
187
|
+
A dictionary mapping each part display ID to a list of corresponding
|
|
188
|
+
`MocloPlasmid` objects found in the collection.
|
|
189
|
+
"""
|
|
190
|
+
plasmid_dict = {}
|
|
191
|
+
for part in part_list:
|
|
192
|
+
for plasmid in plasmid_collection.componentDefinitions:
|
|
193
|
+
if "http://identifiers.org/so/SO:0000637" in plasmid.roles:
|
|
194
|
+
for component in plasmid.components:
|
|
195
|
+
if (
|
|
196
|
+
component.definition == str(part)
|
|
197
|
+
): # TODO make sure this is not a composite plasmid, i.e. plasmid just contains singular part of interest
|
|
198
|
+
fusion_sites = [
|
|
199
|
+
site.name
|
|
200
|
+
for site in extract_fusion_sites(
|
|
201
|
+
plasmid, plasmid_collection
|
|
202
|
+
)
|
|
203
|
+
]
|
|
204
|
+
print(
|
|
205
|
+
f"found: {component.definition} in {plasmid} with {fusion_sites}"
|
|
206
|
+
) # TODO switch to logger for backend tracing?
|
|
207
|
+
plasmid_dict.setdefault(part.displayId, [])
|
|
208
|
+
|
|
209
|
+
componentName = plasmid_collection.getComponentDefinition(
|
|
210
|
+
component.definition
|
|
211
|
+
).name
|
|
212
|
+
|
|
213
|
+
plasmid_dict[part.displayId].append(
|
|
214
|
+
MocloPlasmid(componentName, plasmid, plasmid_collection)
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
return plasmid_dict
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def get_compatible_plasmids(
|
|
221
|
+
plasmid_dict: Dict[str, List[MocloPlasmid]], backbone: MocloPlasmid
|
|
222
|
+
) -> List[MocloPlasmid]:
|
|
223
|
+
"""
|
|
224
|
+
Returns a list of MocloPlasmid objects that can form a compatible assembly
|
|
225
|
+
with the given backbone plasmid. The function selects one plasmid from each
|
|
226
|
+
entry in the dictionary, ensuring that adjacent plasmids have matching MoClo fusion sites,
|
|
227
|
+
and that the first and last plasmids are compatible with the backbone.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
plasmid_dict: A dictionary mapping assembly positions or categories to lists
|
|
231
|
+
of MocloPlasmid objects.
|
|
232
|
+
backbone: The backbone MocloPlasmid whose fusion sites define compatibility.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
A list of compatible MocloPlasmid objects forming a sequential assembly.
|
|
236
|
+
"""
|
|
237
|
+
selected_plasmids = []
|
|
238
|
+
match_to = backbone
|
|
239
|
+
match_idx = 0
|
|
240
|
+
|
|
241
|
+
for i, key in enumerate(plasmid_dict):
|
|
242
|
+
for plasmid in plasmid_dict[key]:
|
|
243
|
+
if (
|
|
244
|
+
i == len(plasmid_dict) - 1
|
|
245
|
+
and plasmid.fusion_sites[0] == match_to.fusion_sites[match_idx]
|
|
246
|
+
and plasmid.fusion_sites[1] == backbone.fusion_sites[1]
|
|
247
|
+
):
|
|
248
|
+
print(
|
|
249
|
+
f"matched final component {plasmid.name} with {match_to.name} and {backbone.name} on fusion sites ({plasmid.fusion_sites[0]}, {plasmid.fusion_sites[1]})!"
|
|
250
|
+
)
|
|
251
|
+
selected_plasmids.append(plasmid)
|
|
252
|
+
break
|
|
253
|
+
elif (
|
|
254
|
+
i < len(plasmid_dict) - 1
|
|
255
|
+
and plasmid.fusion_sites[0] == match_to.fusion_sites[match_idx]
|
|
256
|
+
): # TODO add error handling if no compatible plasmid found
|
|
257
|
+
print(
|
|
258
|
+
f"matched {plasmid.name} with {match_to.name} on fusion site {plasmid.fusion_sites[0]}!"
|
|
259
|
+
)
|
|
260
|
+
selected_plasmids.append(plasmid)
|
|
261
|
+
match_to = plasmid
|
|
262
|
+
match_idx = 1
|
|
263
|
+
break
|
|
264
|
+
# TODO edge case where second fusion site does not match terminator fusion site will not be caught by current logic
|
|
265
|
+
# 10/14: rethink implementation, will likely need to be different for combinatorial designs
|
|
266
|
+
|
|
267
|
+
return selected_plasmids
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def translate_abstract_to_plasmids(
|
|
271
|
+
abstract_design: Union[sbol2.ComponentDefinition, sbol2.CombinatorialDerivation],
|
|
272
|
+
plasmid_collection: sbol2.Collection,
|
|
273
|
+
acceptor_backbone: sbol2.Document,
|
|
274
|
+
) -> List[MocloPlasmid]:
|
|
275
|
+
"""
|
|
276
|
+
Translates an abstract SBOLCanvas design into a set of compatible MoClo plasmid assemblies.
|
|
277
|
+
|
|
278
|
+
Takes an abstract design, identifies the appropriate component
|
|
279
|
+
definitions and combinatorial derivations, and produces all possible plasmid
|
|
280
|
+
combinations that can be assembled using the provided backbone and plasmid
|
|
281
|
+
collection.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
abstract_design_doc:
|
|
285
|
+
The :class:`sbol2.Document` representing the abstract genetic design.
|
|
286
|
+
May include either a single component definition (generic design) or
|
|
287
|
+
one or more combinatorial derivations (combinatorial design).
|
|
288
|
+
plasmid_collection:
|
|
289
|
+
The :class:`sbol2.Document` containing the available MoClo plasmid
|
|
290
|
+
components used for matching and assembly.
|
|
291
|
+
backbone_doc:
|
|
292
|
+
The :class:`sbol2.Document` defining the backbone plasmid into which
|
|
293
|
+
parts are assembled.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
List[MocloPlasmid]:
|
|
297
|
+
- For combinatorial designs: a list of unique compatible plasmids
|
|
298
|
+
(`MocloPlasmid` objects) representing all enumerated design variants.
|
|
299
|
+
- For generic designs: a list of compatible plasmids for the single
|
|
300
|
+
design instance.
|
|
301
|
+
"""
|
|
302
|
+
backbone_def = extract_toplevel_definition(acceptor_backbone)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
backbone_plasmid = MocloPlasmid(backbone_def.displayId, backbone_def, acceptor_backbone)
|
|
306
|
+
|
|
307
|
+
# combinatorial design
|
|
308
|
+
if len(abstract_design.combinatorialderivations) > 0:
|
|
309
|
+
abstract_design_def = abstract_design.getComponentDefinition(
|
|
310
|
+
abstract_design.combinatorialderivations[0].masterTemplate
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
combinatorial_part_dict = extract_combinatorial_design_parts(
|
|
314
|
+
abstract_design_def, abstract_design , plasmid_collection
|
|
315
|
+
)
|
|
316
|
+
enumerated_part_list = enumerate_design_variants(combinatorial_part_dict)
|
|
317
|
+
|
|
318
|
+
seen = set()
|
|
319
|
+
ordered_unique_plasmids = []
|
|
320
|
+
|
|
321
|
+
for design in enumerated_part_list:
|
|
322
|
+
plasmid_dict = construct_plasmid_dict(design, plasmid_collection)
|
|
323
|
+
compatible_plasmids = get_compatible_plasmids(
|
|
324
|
+
plasmid_dict, backbone_plasmid
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
for plasmid in compatible_plasmids:
|
|
328
|
+
if plasmid not in seen:
|
|
329
|
+
seen.add(plasmid)
|
|
330
|
+
ordered_unique_plasmids.append(plasmid)
|
|
331
|
+
|
|
332
|
+
return ordered_unique_plasmids
|
|
333
|
+
|
|
334
|
+
# generic design
|
|
335
|
+
else:
|
|
336
|
+
abstract_design_def = extract_toplevel_definition(abstract_design)
|
|
337
|
+
|
|
338
|
+
ordered_part_definitions = extract_design_parts(
|
|
339
|
+
abstract_design_def, abstract_design
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
plasmid_dict = construct_plasmid_dict(
|
|
343
|
+
ordered_part_definitions, plasmid_collection
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
return get_compatible_plasmids(plasmid_dict, backbone_plasmid)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import sbol2
|
|
2
|
+
from typing import Union, List
|
|
3
|
+
import zipfile
|
|
4
|
+
from buildcompiler.abstract_translator import translate_abstract_to_plasmids
|
|
5
|
+
from buildcompiler.sbol2build import golden_gate_assembly_plan
|
|
6
|
+
from buildcompiler.robotutils import assembly_plan_RDF_to_JSON, run_opentrons_script_with_json_to_zip
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# function which input is an abstract design and output build specifications by creating an assembly plan, and a zip file with a run_sbol2assembly.py, an automated_assembly_log.txt, assemblyplan_output.JSON, and assembly_protocol.xlsx
|
|
10
|
+
|
|
11
|
+
def assembly_compiler(document: sbol2.Document,
|
|
12
|
+
abstract_design: str,
|
|
13
|
+
plasmids_collection: str,
|
|
14
|
+
plasmid_acceptor_backbone: str,
|
|
15
|
+
files_path: str) -> zipfile.ZipFile:
|
|
16
|
+
"""
|
|
17
|
+
Compiles an abstract design into build specifications.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
abstract_design (Union[sbol2.Component, sbol2.CombinatorialDerivation]): The abstract design to be compiled.
|
|
21
|
+
specifications (sbol2.Component): The component to store the build specifications.
|
|
22
|
+
Returns:
|
|
23
|
+
zipfile.ZipFile: A zip file containing the build specifications and assembly plan.
|
|
24
|
+
"""
|
|
25
|
+
restriction_enzyme = "BsaI"
|
|
26
|
+
# Translate abstract design to plasmids
|
|
27
|
+
list_of_plasmids = translate_abstract_to_plasmids(abstract_design_doc = abstract_design,
|
|
28
|
+
plasmid_collection = plasmids_collection,
|
|
29
|
+
backbone_doc= plasmid_acceptor_backbone)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Create assembly plan
|
|
34
|
+
assembly_plan = golden_gate_assembly_plan(name = "Assembly_Plan",
|
|
35
|
+
parts_in_backbone= list_of_plasmids,
|
|
36
|
+
plasmid_acceptor_backbone= plasmid_acceptor_backbone,
|
|
37
|
+
restriction_enzyme= restriction_enzyme,
|
|
38
|
+
document= document)
|
|
39
|
+
|
|
40
|
+
# Generate build specifications JSON
|
|
41
|
+
build_specs_JSON = assembly_plan_RDF_to_JSON(assembly_plan)
|
|
42
|
+
|
|
43
|
+
# Create zip file with required files
|
|
44
|
+
zip_file = run_opentrons_script_with_json_to_zip(opentrons_script_path= files_path + "/run_sbol2assembly_libre.py",
|
|
45
|
+
json_file_path= files_path + "/assemblyplan_output.json",
|
|
46
|
+
zip_name= "buildcompiler.zip",
|
|
47
|
+
overwrite= True)
|
|
48
|
+
|
|
49
|
+
return assembly_plan, zip_file
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
FUSION_SITES = {
|
|
2
|
+
"A": "GGAG",
|
|
3
|
+
"B": "TACT",
|
|
4
|
+
"C": "AATG",
|
|
5
|
+
"D": "AGGT",
|
|
6
|
+
"E": "GCTT",
|
|
7
|
+
"F": "CGCT",
|
|
8
|
+
"G": "TGCC",
|
|
9
|
+
"H": "ACTA",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
DNA_TYPES = { # TODO see about restricting dna types to only accept dna
|
|
13
|
+
"http://www.biopax.org/release/biopax-level3.owl#Dna",
|
|
14
|
+
"http://www.biopax.org/release/biopax-level3.owl#DnaRegion",
|
|
15
|
+
}
|