opencloning 0.2.6.1__tar.gz → 0.2.6.3__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.
Files changed (45) hide show
  1. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/PKG-INFO +10 -5
  2. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/README.md +6 -2
  3. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/pyproject.toml +5 -3
  4. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/pombe/index.html +2 -2
  5. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/pombe/pombe_clone.py +4 -4
  6. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json +6 -6
  7. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/dna_functions.py +2 -2
  8. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/endpoints/external_import.py +6 -6
  9. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/pydantic_models.py +11 -3
  10. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/LICENSE +0 -0
  11. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/__init__.py +0 -0
  12. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/api_config_utils.py +0 -0
  13. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/app_settings.py +0 -0
  14. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/assembly2.py +0 -0
  15. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/EBIC/__init__.py +0 -0
  16. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/EBIC/barcode.gb +0 -0
  17. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/EBIC/common_plasmid.gb +0 -0
  18. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/EBIC/example.py +0 -0
  19. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/EBIC/primer_design_settings.py +0 -0
  20. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/__init__.py +0 -0
  21. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/index.html +0 -0
  22. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/pombe/__init__.py +0 -0
  23. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/pombe/pombe_all.sh +0 -0
  24. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/pombe/pombe_gather.py +0 -0
  25. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/pombe/pombe_get_primers.py +0 -0
  26. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/pombe/pombe_summary.py +0 -0
  27. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/ziqiang_et_al2024/__init__.py +0 -0
  28. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/batch_cloning/ziqiang_et_al2024/index.html +0 -0
  29. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/dna_utils.py +0 -0
  30. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/ebic/__init__.py +0 -0
  31. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/ebic/primer_design.py +0 -0
  32. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/ebic/primer_design_settings.py +0 -0
  33. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/endpoints/annotation.py +0 -0
  34. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/endpoints/assembly.py +0 -0
  35. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/endpoints/no_assembly.py +0 -0
  36. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/endpoints/no_input.py +0 -0
  37. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/endpoints/other.py +0 -0
  38. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/endpoints/primer_design.py +0 -0
  39. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/gateway.py +0 -0
  40. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/get_router.py +0 -0
  41. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/main.py +0 -0
  42. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/ncbi_requests.py +0 -0
  43. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/primer_design.py +0 -0
  44. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/request_examples.py +0 -0
  45. {opencloning-0.2.6.1 → opencloning-0.2.6.3}/src/opencloning/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: opencloning
3
- Version: 0.2.6.1
3
+ Version: 0.2.6.3
4
4
  Summary: Backend of OpenCloning, a web application to generate molecular cloning strategies in json format, and share them with others.
5
5
  License: MIT
6
6
  Author: Manuel Lera-Ramirez
@@ -12,14 +12,15 @@ Classifier: Programming Language :: Python :: 3.11
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Dist: beautifulsoup4 (>=4.11.1,<5.0.0)
15
+ Requires-Dist: biopython (==1.84)
15
16
  Requires-Dist: fastapi
16
17
  Requires-Dist: httpx (>=0.25.0,<0.26.0)
17
- Requires-Dist: opencloning-linkml (==0.2.5.1a)
18
+ Requires-Dist: opencloning-linkml (==0.2.5.2a0)
18
19
  Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
19
20
  Requires-Dist: pandas (>=2.2.3,<3.0.0)
20
21
  Requires-Dist: primer3-py (>=2.0.3,<3.0.0)
21
22
  Requires-Dist: pydantic (>=2.7.1,<3.0.0)
22
- Requires-Dist: pydna (>=5.3,<6.0)
23
+ Requires-Dist: pydna (==5.5.0)
23
24
  Requires-Dist: python-multipart
24
25
  Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
25
26
  Requires-Dist: regex (>=2023.10.3,<2024.0.0)
@@ -41,7 +42,11 @@ This python API is built with [FastAPI](https://fastapi.tiangolo.com/) and is fo
41
42
 
42
43
  Read [main project readme](https://github.com/manulera/OpenCloning) first.
43
44
 
44
- This API provides a series of entry points. The API documentation can be accessed [here](https://OpenCloning.api.genestorian.org/docs). You can use the documentation page to try some request directly on the browser. Otherwise, the API is open for you to make requests from a python script or command line at: [https://opencloning.api.genestorian.org/](https://opencloning.api.genestorian.org/).
45
+ This API provides a series of entry points. The API documentation can be accessed [here](https://api.opencloning.org/docs). You can use the documentation page to try some request directly on the browser. Otherwise, the API is open for you to make requests from a python script or command line at: [https://api.opencloning.org/](https://api.opencloning.org/).
46
+
47
+ ## Scripting
48
+
49
+ The API functions can also be used to write python scripts to automate cloning. See the [scripting examples](examples/scripting) for more information.
45
50
 
46
51
  ## Getting started
47
52
 
@@ -103,7 +108,7 @@ docker run -d --name backendcontainer -p 8000:8000 manulera/opencloningbackend
103
108
 
104
109
  ```
105
110
 
106
- If you don't want to download the repository and build the image, you can fetch the latest image from dockerhub (same image that is used in [https://opencloning.api.genestorian.org/](https://opencloning.api.genestorian.org/))
111
+ If you don't want to download the repository and build the image, you can fetch the latest image from dockerhub (same image that is used in [https://api.opencloning.org/](https://api.opencloning.org/))
107
112
 
108
113
  ```bash
109
114
  docker pull manulera/opencloningbackend
@@ -11,7 +11,11 @@ This python API is built with [FastAPI](https://fastapi.tiangolo.com/) and is fo
11
11
 
12
12
  Read [main project readme](https://github.com/manulera/OpenCloning) first.
13
13
 
14
- This API provides a series of entry points. The API documentation can be accessed [here](https://OpenCloning.api.genestorian.org/docs). You can use the documentation page to try some request directly on the browser. Otherwise, the API is open for you to make requests from a python script or command line at: [https://opencloning.api.genestorian.org/](https://opencloning.api.genestorian.org/).
14
+ This API provides a series of entry points. The API documentation can be accessed [here](https://api.opencloning.org/docs). You can use the documentation page to try some request directly on the browser. Otherwise, the API is open for you to make requests from a python script or command line at: [https://api.opencloning.org/](https://api.opencloning.org/).
15
+
16
+ ## Scripting
17
+
18
+ The API functions can also be used to write python scripts to automate cloning. See the [scripting examples](examples/scripting) for more information.
15
19
 
16
20
  ## Getting started
17
21
 
@@ -73,7 +77,7 @@ docker run -d --name backendcontainer -p 8000:8000 manulera/opencloningbackend
73
77
 
74
78
  ```
75
79
 
76
- If you don't want to download the repository and build the image, you can fetch the latest image from dockerhub (same image that is used in [https://opencloning.api.genestorian.org/](https://opencloning.api.genestorian.org/))
80
+ If you don't want to download the repository and build the image, you can fetch the latest image from dockerhub (same image that is used in [https://api.opencloning.org/](https://api.opencloning.org/))
77
81
 
78
82
  ```bash
79
83
  docker pull manulera/opencloningbackend
@@ -3,7 +3,7 @@ authors = ["Manuel Lera-Ramirez <manulera14@gmail.com>"]
3
3
  description = "Backend of OpenCloning, a web application to generate molecular cloning strategies in json format, and share them with others."
4
4
  license = "MIT"
5
5
  name = "opencloning"
6
- version = "v0.2.6.1"
6
+ version = "v0.2.6.3"
7
7
  package-mode = true
8
8
  readme = "README.md"
9
9
  repository = "https://github.com/manulera/OpenCloning_backend"
@@ -15,15 +15,16 @@ httpx = "^0.25.0"
15
15
  python = "^3.11"
16
16
  python-multipart = "*"
17
17
  uvicorn = "*"
18
- pydna = "^5.3"
18
+ pydna = "5.5.0"
19
19
  requests = "^2.31.0"
20
20
  regex = "^2023.10.3"
21
21
  pydantic = "^2.7.1"
22
22
  pandas = "^2.2.3"
23
23
  openpyxl = "^3.1.5"
24
24
  pyyaml = "^6.0.2"
25
- opencloning-linkml = "0.2.5.1a"
25
+ opencloning-linkml = "0.2.5.2a0"
26
26
  primer3-py = "^2.0.3"
27
+ biopython = "1.84"
27
28
 
28
29
  [tool.poetry.group.dev.dependencies]
29
30
  autopep8 = "^2.0.4"
@@ -31,6 +32,7 @@ flake8-bugbear = "^24.2.6"
31
32
  black = "^24.2.0"
32
33
  pre-commit = "^3.6.2"
33
34
  watchfiles = "^0.21.0"
35
+ nbstripout = "^0.8.1"
34
36
 
35
37
  [tool.poetry.group.test.dependencies]
36
38
  pytest = "8.3.4"
@@ -51,7 +51,7 @@ SPBC15D4.01c</textarea><br>
51
51
  <div>
52
52
  <input type="radio" id="plasmid_addgene" name="plasmid_option" value="addgene" checked
53
53
  onchange="togglePlasmidInput()">
54
- <label for="plasmid_addgene">Provide AddGene Identifier</label>
54
+ <label for="plasmid_addgene">Provide Addgene Identifier</label>
55
55
 
56
56
  <br>
57
57
  <input type="radio" id="plasmid_file" name="plasmid_option" value="file" onchange="togglePlasmidInput()">
@@ -67,7 +67,7 @@ SPBC15D4.01c</textarea><br>
67
67
  </div>
68
68
 
69
69
  <div id="addgene_input">
70
- <label for="addgene_id">AddGene Identifier:</label><br>
70
+ <label for="addgene_id">Addgene Identifier:</label><br>
71
71
  <input value="19343" type="text" id="addgene_id" name="addgene_id"><br><br>
72
72
  </div>
73
73
 
@@ -4,7 +4,7 @@ from ...endpoints.assembly import pcr, homologous_recombination
4
4
  from ...pydantic_models import (
5
5
  GenomeCoordinatesSource,
6
6
  TextFileSequence,
7
- AddGeneIdSource,
7
+ AddgeneIdSource,
8
8
  PCRSource,
9
9
  PrimerModel,
10
10
  HomologousRecombinationSource,
@@ -81,13 +81,13 @@ async def main(
81
81
  plasmid_source: UploadedFileSource = UploadedFileSource.model_validate(resp['sources'][0])
82
82
  plasmid_source.output = 4
83
83
  else:
84
- addgene_source = AddGeneIdSource(
84
+ addgene_source = AddgeneIdSource(
85
85
  id=3,
86
86
  repository_id=plasmid,
87
87
  repository_name='addgene',
88
88
  )
89
89
  resp = await get_from_repository_id_addgene(addgene_source)
90
- plasmid_source: AddGeneIdSource = AddGeneIdSource.model_validate(resp['sources'][0])
90
+ plasmid_source: AddgeneIdSource = AddgeneIdSource.model_validate(resp['sources'][0])
91
91
  plasmid_source.output = 4
92
92
 
93
93
  plasmid_seq: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
@@ -175,7 +175,7 @@ if __name__ == '__main__':
175
175
  '--plasmid',
176
176
  type=str,
177
177
  default='19343',
178
- help='AddGene ID for the plasmid (default: 19343)',
178
+ help='Addgene ID for the plasmid (default: 19343)',
179
179
  )
180
180
 
181
181
  args = parser.parse_args()
@@ -78,7 +78,7 @@
78
78
  "id": 1,
79
79
  "input": [],
80
80
  "output": 2,
81
- "type": "AddGeneIdSource",
81
+ "type": "AddgeneIdSource",
82
82
  "output_name": null,
83
83
  "repository_id": "71287",
84
84
  "repository_name": "addgene",
@@ -89,7 +89,7 @@
89
89
  "id": 3,
90
90
  "input": [],
91
91
  "output": 4,
92
- "type": "AddGeneIdSource",
92
+ "type": "AddgeneIdSource",
93
93
  "output_name": null,
94
94
  "repository_id": "71287",
95
95
  "repository_name": "addgene",
@@ -100,7 +100,7 @@
100
100
  "id": 5,
101
101
  "input": [],
102
102
  "output": 6,
103
- "type": "AddGeneIdSource",
103
+ "type": "AddgeneIdSource",
104
104
  "output_name": null,
105
105
  "repository_id": "213912",
106
106
  "repository_name": "addgene",
@@ -111,7 +111,7 @@
111
111
  "id": 7,
112
112
  "input": [],
113
113
  "output": 8,
114
- "type": "AddGeneIdSource",
114
+ "type": "AddgeneIdSource",
115
115
  "output_name": null,
116
116
  "repository_id": "213913",
117
117
  "repository_name": "addgene",
@@ -122,7 +122,7 @@
122
122
  "id": 9,
123
123
  "input": [],
124
124
  "output": 10,
125
- "type": "AddGeneIdSource",
125
+ "type": "AddgeneIdSource",
126
126
  "output_name": null,
127
127
  "repository_id": "133748",
128
128
  "repository_name": "addgene",
@@ -236,7 +236,7 @@
236
236
  "id": 17,
237
237
  "input": [],
238
238
  "output": 18,
239
- "type": "AddGeneIdSource",
239
+ "type": "AddgeneIdSource",
240
240
  "output_name": null,
241
241
  "repository_id": "63143",
242
242
  "repository_name": "addgene",
@@ -4,7 +4,7 @@ from Bio.Restriction.Restriction import RestrictionBatch
4
4
  from Bio.Seq import reverse_complement
5
5
  from pydna.dseqrecord import Dseqrecord
6
6
  from pydna.dseq import Dseq
7
- from .pydantic_models import TextFileSequence, AddGeneIdSource, SequenceFileFormat, WekWikGeneIdSource, SEVASource
7
+ from .pydantic_models import TextFileSequence, AddgeneIdSource, SequenceFileFormat, WekWikGeneIdSource, SEVASource
8
8
  from opencloning_linkml.datamodel import PlannotateAnnotationReport
9
9
  from pydna.parsers import parse as pydna_parse
10
10
  import requests
@@ -93,7 +93,7 @@ def get_sequence_from_snagene_url(url: str) -> Dseqrecord:
93
93
  return Dseqrecord(parsed_seq, circular=circularize)
94
94
 
95
95
 
96
- async def request_from_addgene(source: AddGeneIdSource) -> tuple[Dseqrecord, AddGeneIdSource]:
96
+ async def request_from_addgene(source: AddgeneIdSource) -> tuple[Dseqrecord, AddgeneIdSource]:
97
97
 
98
98
  url = f'https://www.addgene.org/{source.repository_id}/sequences/'
99
99
  async with httpx.AsyncClient() as client:
@@ -13,7 +13,7 @@ from ..pydantic_models import (
13
13
  TextFileSequence,
14
14
  UploadedFileSource,
15
15
  RepositoryIdSource,
16
- AddGeneIdSource,
16
+ AddgeneIdSource,
17
17
  WekWikGeneIdSource,
18
18
  BenchlingUrlSource,
19
19
  SnapGenePlasmidSource,
@@ -179,7 +179,7 @@ def repository_id_http_error_handler(exception: HTTPError, source: RepositoryIdS
179
179
  'RepositoryIdResponse',
180
180
  sources=(
181
181
  list[RepositoryIdSource]
182
- | list[AddGeneIdSource]
182
+ | list[AddgeneIdSource]
183
183
  | list[BenchlingUrlSource]
184
184
  | list[EuroscarfSource]
185
185
  | list[WekWikGeneIdSource]
@@ -192,7 +192,7 @@ def repository_id_http_error_handler(exception: HTTPError, source: RepositoryIdS
192
192
  async def get_from_repository_id(
193
193
  source: (
194
194
  RepositoryIdSource
195
- | AddGeneIdSource
195
+ | AddgeneIdSource
196
196
  | BenchlingUrlSource
197
197
  | SnapGenePlasmidSource
198
198
  | EuroscarfSource
@@ -225,16 +225,16 @@ async def get_from_repository_id_genbank(source: RepositoryIdSource):
225
225
  @router.post(
226
226
  '/repository_id/addgene',
227
227
  response_model=create_model(
228
- 'AddgeneIdResponse', sources=(list[AddGeneIdSource], ...), sequences=(list[TextFileSequence], ...)
228
+ 'AddgeneIdResponse', sources=(list[AddgeneIdSource], ...), sequences=(list[TextFileSequence], ...)
229
229
  ),
230
230
  )
231
- async def get_from_repository_id_addgene(source: AddGeneIdSource):
231
+ async def get_from_repository_id_addgene(source: AddgeneIdSource):
232
232
  try:
233
233
  dseq, out_source = await request_from_addgene(source)
234
234
  except HTTPError as exception:
235
235
  repository_id_http_error_handler(exception, source)
236
236
  except httpx.ConnectError:
237
- raise HTTPException(504, 'unable to connect to AddGene')
237
+ raise HTTPException(504, 'unable to connect to Addgene')
238
238
 
239
239
  return {'sequences': [format_sequence_genbank(dseq, source.output_name)], 'sources': [out_source]}
240
240
 
@@ -1,5 +1,5 @@
1
1
  from pydantic import BaseModel, Field, model_validator
2
- from typing import Optional, List, Any
2
+ from typing import Optional, List
3
3
 
4
4
  from Bio.SeqFeature import (
5
5
  SeqFeature,
@@ -32,7 +32,7 @@ from opencloning_linkml.datamodel import (
32
32
  Primer as _Primer,
33
33
  AssemblyFragment as _AssemblyFragment,
34
34
  SimpleSequenceLocation as _SimpleSequenceLocation,
35
- AddGeneIdSource as _AddGeneIdSource,
35
+ AddgeneIdSource as _AddgeneIdSource,
36
36
  WekWikGeneIdSource as _WekWikGeneIdSource,
37
37
  BenchlingUrlSource as _BenchlingUrlSource,
38
38
  CloningStrategy as _CloningStrategy,
@@ -115,7 +115,7 @@ class RepositoryIdSource(SourceCommonClass, _RepositoryIdSource):
115
115
  pass
116
116
 
117
117
 
118
- class AddGeneIdSource(SourceCommonClass, _AddGeneIdSource):
118
+ class AddgeneIdSource(SourceCommonClass, _AddgeneIdSource):
119
119
  # TODO: add this to LinkML
120
120
  # repository_name: RepositoryName = RepositoryName('addgene')
121
121
  pass
@@ -405,6 +405,8 @@ class BaseCloningStrategy(_CloningStrategy):
405
405
  return max([p.id for p in self.primers], default=0) + 1
406
406
 
407
407
  def add_primer(self, primer: PrimerModel):
408
+ if primer in self.primers:
409
+ return
408
410
  primer.id = self.next_primer_id()
409
411
  self.primers.append(primer)
410
412
 
@@ -412,6 +414,12 @@ class BaseCloningStrategy(_CloningStrategy):
412
414
  return max([s.id for s in self.sources + self.sequences], default=0) + 1
413
415
 
414
416
  def add_source_and_sequence(self, source: SourceCommonClass, sequence: TextFileSequence):
417
+ if source in self.sources:
418
+ if sequence not in self.sequences:
419
+ raise ValueError(
420
+ f"Source {source.id} already exists in the cloning strategy, but sequence {sequence.id} it's not its output."
421
+ )
422
+ return
415
423
  source.id = self.next_node_id()
416
424
  self.sources.append(source)
417
425
  sequence.id = self.next_node_id()
File without changes