pydna 5.5.0__py3-none-any.whl → 5.5.2__py3-none-any.whl

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.
pydna/__init__.py CHANGED
@@ -132,111 +132,104 @@ See this repository for a collection of
132
132
  """
133
133
 
134
134
 
135
- from pydna.utils import open_folder as _open_folder
136
- from pathlib import Path as _Path
135
+ # from pydna.utils import open_folder as _open_folder
136
+ # from pathlib import Path as _Path
137
137
  import os as _os
138
- import logging as _logging
139
- import logging.handlers as _handlers
140
- import appdirs as _appdirs
141
- import configparser as _configparser
142
- import tempfile as _tempfile
138
+
139
+ # import logging as _logging
140
+ # import logging.handlers as _handlers
141
+ # import appdirs as _appdirs
142
+ # import configparser as _configparser
143
+ # import tempfile as _tempfile
143
144
  from pydna._pretty import PrettyTable as _PrettyTable
144
145
 
145
146
 
146
147
  __author__ = "Björn Johansson"
147
- __copyright__ = "Copyright 2013 - 2021 Björn Johansson"
148
+ __copyright__ = "Copyright 2013 - 2023 Björn Johansson"
148
149
  __credits__ = ["Björn Johansson", "Mark Budde"]
149
150
  __license__ = "BSD"
150
151
  __maintainer__ = "Björn Johansson"
151
152
  __email__ = "bjorn_johansson@bio.uminho.pt"
152
153
  __status__ = "Development" # "Production" #"Prototype"
153
- __version__ = "5.5.0"
154
+ __version__ = "5.5.2"
154
155
 
155
156
 
156
- # create config directory
157
- _os.environ["pydna_config_dir"] = _os.getenv("pydna_config_dir", _appdirs.user_config_dir("pydna"))
158
- config_dir = _Path(_os.environ["pydna_config_dir"])
159
- config_dir.mkdir(parents=True, exist_ok=True)
157
+ # obtain config directory from env or appdirs
158
+ # _os.environ["pydna_config_dir"] = _os.getenv("pydna_config_dir", _appdirs.user_config_dir("pydna"))
159
+ # config_dir = _Path(_os.environ["pydna_config_dir"])
160
+ # config_dir.mkdir(parents=True, exist_ok=True)
160
161
 
161
162
  # set path for the pydna.ini file
162
- _ini_path = config_dir / "pydna.ini"
163
+ # _ini_path = config_dir / "pydna.ini"
163
164
 
164
165
  # define user_data_dir
165
- user_data_dir = _Path(_appdirs.user_data_dir("pydna"))
166
-
167
- default_ini = {
168
- "ape": "put/path/to/ape/here",
169
- "cached_funcs": "pydna.genbank.genbank.nucleotide",
170
- "data_dir": str(user_data_dir),
171
- "email": "someone@example.com",
172
- "enzymes": str(user_data_dir / "enzymes.md"),
173
- "log_dir": _appdirs.user_log_dir("pydna"),
174
- "loglevel": str(_logging.WARNING),
175
- "primers": str(user_data_dir / "primers.md"),
176
- "assembly_limit": str(10),
177
- }
166
+ # user_data_dir = _Path(_appdirs.user_data_dir("pydna"))
167
+
168
+ # default_ini = {
169
+ # "ape": "put/path/to/ape/here",
170
+ # "cached_funcs": "pydna.genbank.genbank.nucleotide",
171
+ # "data_dir": str(user_data_dir),
172
+ # "email": "someone@example.com",
173
+ # "enzymes": str(user_data_dir / "enzymes.md"),
174
+ # "log_dir": _appdirs.user_log_dir("pydna"),
175
+ # "loglevel": str(_logging.WARNING),
176
+ # "primers": str(user_data_dir / "primers.md"),
177
+ # "assembly_limit": str(10),
178
+ # }
179
+
180
+ # ini = default_ini.copy()
178
181
 
179
182
  # initiate a config parser instance
180
- _parser = _configparser.ConfigParser()
183
+ # _parser = _configparser.ConfigParser()
181
184
 
182
185
  # if a pydna.ini exists, it is read
183
- if _ini_path.exists():
184
- _parser.read(_ini_path)
185
- else: # otherwise it is created with default settings
186
- _parser["main"] = default_ini
187
- _temp_ini_file = _tempfile.NamedTemporaryFile(dir=_ini_path.parent, delete=False)
188
- _temp_ini_path = _Path(_temp_ini_file.name)
189
- try:
190
- _temp_ini_file.close()
191
- with _temp_ini_path.open("w", encoding="utf-8") as f: # TODO needs encoding?
192
- _parser.write(f)
193
- _temp_ini_path.replace(_ini_path)
194
- finally:
195
- _temp_ini_path.unlink(missing_ok=True)
196
-
186
+ # if _ini_path.exists():
187
+ # _parser.read(_ini_path)
197
188
  # pydna related environmental variables are set
198
189
  # from pydna.ini if they are not set already
199
- _main = _parser["main"]
190
+ # _main = _parser["main"]
191
+ # ini.update(_main)
200
192
 
201
- for key in default_ini:
202
- _os.environ[f"pydna_{key}"] = _os.getenv(f"pydna_{key}", _main.get(key, default_ini[key]))
203
193
 
204
- logdir = _Path(_os.environ["pydna_log_dir"])
194
+ # for key, value in ini.items():
195
+ # _os.environ[f"pydna_{key}"] = _os.getenv(f"pydna_{key}", value)
196
+
197
+ # logdir = _Path(_os.environ["pydna_log_dir"])
205
198
 
206
199
  # create log directory if not present
207
- logdir.mkdir(parents=True, exist_ok=True)
208
- _logmsg = "Log directory {}".format(logdir)
200
+ # logdir.mkdir(parents=True, exist_ok=True)
201
+ # _logmsg = "Log directory {}".format(logdir)
209
202
 
210
203
  # create logger
211
- _logger = _logging.getLogger("pydna")
212
- _logger.setLevel(int(_os.environ["pydna_loglevel"]))
213
- _hdlr = _handlers.RotatingFileHandler(
214
- logdir / "pydna.log",
215
- mode="a",
216
- maxBytes=10 * 1024 * 1024,
217
- backupCount=10,
218
- encoding="utf-8",
219
- )
220
-
221
- _formatter = _logging.Formatter(("%(asctime)s %(levelname)s" " %(funcName)s %(message)s"))
222
- _hdlr.setFormatter(_formatter)
223
- _logger.addHandler(_hdlr)
224
- _logger.info(_logmsg)
225
- _logger.info("Environmental variable pydna_ape = %s", _os.environ["pydna_ape"])
226
- _logger.info("Environmental variable pydna_cached_funcs = %s", _os.environ["pydna_cached_funcs"])
227
- _logger.info("Environmental variable pydna_data_dir = %s", _os.environ["pydna_data_dir"])
228
- _logger.info("Environmental variable pydna_email = %s", _os.environ["pydna_email"])
229
- _logger.info("Environmental variable pydna_log_dir = %s", _os.environ["pydna_log_dir"])
230
- _logger.info("Environmental variable pydna_loglevel = %s", _os.environ["pydna_loglevel"])
231
- _logger.info("Environmental variable pydna_primers = %s", _os.environ["pydna_primers"])
232
- _logger.info(
233
- "Environmental variable pydna_assembly_limit = %s",
234
- _os.environ["pydna_assembly_limit"],
235
- )
204
+ # _logger = _logging.getLogger("pydna")
205
+ # _logger.setLevel(int(_os.environ["pydna_loglevel"]))
206
+ # _hdlr = _handlers.RotatingFileHandler(
207
+ # logdir / "pydna.log",
208
+ # mode="a",
209
+ # maxBytes=10 * 1024 * 1024,
210
+ # backupCount=10,
211
+ # encoding="utf-8",
212
+ # )
213
+
214
+ # _formatter = _logging.Formatter(("%(asctime)s %(levelname)s" " %(funcName)s %(message)s"))
215
+ # _hdlr.setFormatter(_formatter)
216
+ # _logger.addHandler(_hdlr)
217
+ # _logger.info(_logmsg)
218
+ # _logger.info("Environmental variable pydna_ape = %s", _os.environ["pydna_ape"])
219
+ # _logger.info("Environmental variable pydna_cached_funcs = %s", _os.environ["pydna_cached_funcs"])
220
+ # _logger.info("Environmental variable pydna_data_dir = %s", _os.environ["pydna_data_dir"])
221
+ # _logger.info("Environmental variable pydna_email = %s", _os.environ["pydna_email"])
222
+ # _logger.info("Environmental variable pydna_log_dir = %s", _os.environ["pydna_log_dir"])
223
+ # _logger.info("Environmental variable pydna_loglevel = %s", _os.environ["pydna_loglevel"])
224
+ # _logger.info("Environmental variable pydna_primers = %s", _os.environ["pydna_primers"])
225
+ # _logger.info(
226
+ # "Environmental variable pydna_assembly_limit = %s",
227
+ # _os.environ["pydna_assembly_limit"],
228
+ # )
236
229
 
237
230
  # create cache directory if not present
238
231
 
239
- _Path(_os.environ["pydna_data_dir"]).mkdir(parents=True, exist_ok=True)
232
+ # _Path(_os.environ["pydna_data_dir"]).mkdir(parents=True, exist_ok=True)
240
233
 
241
234
  # find out if optional dependecies for gel module are in place
242
235
  #
@@ -264,7 +257,7 @@ _Path(_os.environ["pydna_data_dir"]).mkdir(parents=True, exist_ok=True)
264
257
  # _logger.info("gel simulation is available," " optional dependencies were found.")
265
258
  #
266
259
 
267
- _logger.info("__version__ = %s", __version__)
260
+ # _logger.info("__version__ = %s", __version__)
268
261
 
269
262
 
270
263
  class _PydnaWarning(Warning):
@@ -304,74 +297,74 @@ class _PydnaDeprecationWarning(_PydnaWarning):
304
297
  pass
305
298
 
306
299
 
307
- def open_current_folder():
308
- """Open the current working directory.
300
+ # def open_current_folder():
301
+ # """Open the current working directory.
309
302
 
310
- Opens in the default file manager. The location for this folder is
311
- given by the :func:`os.getcwd` function
312
- """
313
- return _open_folder(_os.getcwd())
303
+ # Opens in the default file manager. The location for this folder is
304
+ # given by the :func:`os.getcwd` function
305
+ # """
306
+ # return _open_folder(_os.getcwd())
314
307
 
315
308
 
316
- _logger.info("Current working directory = os.getcwd() = %s", _os.getcwd())
309
+ # _logger.info("Current working directory = os.getcwd() = %s", _os.getcwd())
317
310
 
318
311
 
319
- def open_cache_folder():
320
- """Open the pydna cache folder.
312
+ # def open_cache_folder():
313
+ # """Open the pydna cache folder.
321
314
 
322
- Opens in the default file manager. The location for this folder is stored
323
- in the *pydna_data_dir* environmental variable.
324
- """
325
- return _open_folder(_os.environ["pydna_data_dir"])
315
+ # Opens in the default file manager. The location for this folder is stored
316
+ # in the *pydna_data_dir* environmental variable.
317
+ # """
318
+ # return _open_folder(_os.environ["pydna_data_dir"])
326
319
 
327
320
 
328
- def open_config_folder():
329
- """Open the pydna configuration folder.
321
+ # def open_config_folder():
322
+ # """Open the pydna configuration folder.
330
323
 
331
- Opens in the default file manager. The location for this folder is stored
332
- in the *pydna_config_dir* environmental variable.
324
+ # Opens in the default file manager. The location for this folder is stored
325
+ # in the *pydna_config_dir* environmental variable.
333
326
 
334
- The `pydna.ini` file can be edited to make pydna quicker to use.
335
- See the documentation of the :class:configparser.ConfigParser´ class.
327
+ # The `pydna.ini` file can be edited to make pydna quicker to use.
328
+ # See the documentation of the :class:configparser.ConfigParser´ class.
336
329
 
337
- Below is the content of a typical `pydna.ini` file on a Linux
338
- system.
330
+ # Below is the content of a typical `pydna.ini` file on a Linux
331
+ # system.
339
332
 
340
- ::
333
+ # ::
341
334
 
342
- [main]
343
- loglevel=30
344
- email=myemail@example.org
345
- data_dir=/home/bjorn/.local/share/pydna
346
- log_dir=/home/bjorn/.cache/pydna/log
347
- ape=tclsh /home/bjorn/.ApE/AppMain.tcl
348
- cached_funcs=Genbank_nucleotide
349
- primers=/home/bjorn/Dropbox/wikidata/PRIMERS.txt
350
- enzymes=/home/bjorn/Dropbox/wikidata/RestrictionEnzymes.txt
335
+ # [main]
336
+ # loglevel=30
337
+ # email=myemail@example.org
338
+ # data_dir=/home/user/.local/share/pydna
339
+ # log_dir=/home/user/.cache/pydna/log
340
+ # ape=tclsh /path/to/ape/AppMain.tcl
341
+ # cached_funcs=Genbank_nucleotide
342
+ # primers=/path/to/primers/PRIMERS.txt
343
+ # enzymes=/path/to/enzymes/RestrictionEnzymes.txt
351
344
 
352
- The email address is set to someone@example.com by default. If you change
353
- this to you own address, the :func:`pydna.genbank.genbank` function can be
354
- used to download sequences from Genbank directly without having to
355
- explicitly add the email address.
345
+ # The email address is set to someone@example.com by default. If you change
346
+ # this to you own address, the :func:`pydna.genbank.genbank` function can be
347
+ # used to download sequences from Genbank directly without having to
348
+ # explicitly add the email address.
356
349
 
357
- Pydna can cache results from the following functions or methods:
350
+ # Pydna can cache results from the following functions or methods:
358
351
 
359
- - :func:`pydna.genbank.Genbank.nucleotide` Genbank_nucleotide
360
- - :func:`pydna.amplify.Anneal` amplify_Anneal
361
- - :func:`pydna.assembly.Assembly` assembly_Assembly
362
- - :func:`pydna.download.download_text` download.download_text
363
- - :func:`pydna.dseqrecord.Dseqrecord.synced` Dseqrecord_synced
352
+ # - :func:`pydna.genbank.Genbank.nucleotide` Genbank_nucleotide
353
+ # - :func:`pydna.amplify.Anneal` amplify_Anneal
354
+ # - :func:`pydna.assembly.Assembly` assembly_Assembly
355
+ # - :func:`pydna.download.download_text` download.download_text
356
+ # - :func:`pydna.dseqrecord.Dseqrecord.synced` Dseqrecord_synced
364
357
 
365
- These can be added separated by a comma to the cached_funcs entry
366
- in **pydna.ini** file or the pydna_cached_funcs environment variable.
358
+ # These can be added separated by a comma to the cached_funcs entry
359
+ # in **pydna.ini** file or the pydna_cached_funcs environment variable.
367
360
 
368
- """
369
- return _open_folder(_os.environ["pydna_config_dir"])
361
+ # """
362
+ # return _open_folder(_os.environ["pydna_config_dir"])
370
363
 
371
364
 
372
- def open_log_folder():
373
- """docstring."""
374
- return _open_folder(_os.environ["pydna_log_dir"])
365
+ # def open_log_folder():
366
+ # """docstring."""
367
+ # return _open_folder(_os.environ["pydna_log_dir"])
375
368
 
376
369
 
377
370
  def get_env():
@@ -403,14 +396,3 @@ def logo():
403
396
  f = Figlet()
404
397
  message = f.renderText(message)
405
398
  return _pretty_str(message)
406
-
407
-
408
- if __name__ == "__main__":
409
- import os as _os
410
-
411
- cached = _os.getenv("pydna_cached_funcs", "")
412
- _os.environ["pydna_cached_funcs"] = ""
413
- import doctest
414
-
415
- doctest.testmod(verbose=True, optionflags=doctest.ELLIPSIS)
416
- _os.environ["pydna_cached_funcs"] = cached
pydna/_pretty.py CHANGED
@@ -7,8 +7,7 @@ for for nicer string output in the IPython shell and Jupyter notebook.
7
7
  """
8
8
 
9
9
  from prettytable import PrettyTable as _Pt
10
- from prettytable import MARKDOWN as _md
11
-
10
+ from prettytable import TableStyle as _TableStyle
12
11
  from copy import copy as _copy
13
12
  from typing import List as _List
14
13
 
@@ -33,16 +32,5 @@ class PrettyTable(_Pt):
33
32
 
34
33
  def _repr_markdown_(self) -> pretty_str:
35
34
  c = _copy(self)
36
- c.set_style(_md)
35
+ c.set_style(_TableStyle.MARKDOWN)
37
36
  return pretty_str(c.get_string())
38
-
39
-
40
- if __name__ == "__main__":
41
- import os as _os
42
-
43
- cached = _os.getenv("pydna_cached_funcs", "")
44
- _os.environ["pydna_cached_funcs"] = ""
45
- import doctest
46
-
47
- doctest.testmod(verbose=True, optionflags=doctest.ELLIPSIS)
48
- _os.environ["pydna_cached_funcs"] = cached
pydna/all.py CHANGED
@@ -18,10 +18,8 @@ ttt
18
18
  Dseqrecord(-3)
19
19
  >>> from pydna.all import __all__
20
20
  >>> __all__
21
- ['Anneal', 'pcr', 'Assembly', 'genbank', 'Genbank', 'download_text\
22
- ', 'Dseqrecord', 'Dseq', 'read', 'read_primer', 'parse', 'parse_primers\
23
- ', 'ape', 'primer_design', 'assembly_fragments', 'circular_assembly_fragments\
24
- ', 'eq', 'gbtext_clean', 'PrimerList']
21
+ ['Anneal', 'pcr', 'Assembly', 'genbank', 'Genbank', 'download_text', 'Dseqrecord',
22
+ 'Dseq', 'read', 'read_primer', 'parse', 'parse_primers', 'primer_design', 'assembly_fragments', 'eq', 'gbtext_clean']
25
23
  >>>
26
24
  """
27
25
 
@@ -39,13 +37,13 @@ __all__ = [
39
37
  "read_primer",
40
38
  "parse",
41
39
  "parse_primers",
42
- "ape",
40
+ # "ape",
43
41
  "primer_design",
44
42
  "assembly_fragments",
45
- "circular_assembly_fragments",
43
+ # "circular_assembly_fragments",
46
44
  "eq",
47
45
  "gbtext_clean",
48
- "PrimerList",
46
+ # "PrimerList",
49
47
  ]
50
48
 
51
49
 
@@ -61,21 +59,13 @@ from pydna.readers import read
61
59
  from pydna.readers import read_primer
62
60
  from pydna.parsers import parse
63
61
  from pydna.parsers import parse_primers
64
- from pydna.editor import ape
62
+
63
+ # from pydna.editor import ape
65
64
  from pydna.design import primer_design
66
65
  from pydna.design import assembly_fragments
67
- from pydna.design import circular_assembly_fragments
66
+
67
+ # from pydna.design import circular_assembly_fragments
68
68
  from pydna.utils import eq
69
69
  from pydna.genbankfixer import gbtext_clean
70
- from pydna.myprimers import PrimerList
71
-
72
-
73
- if __name__ == "__main__":
74
- import os as _os
75
-
76
- cached = _os.getenv("pydna_cached_funcs", "")
77
- _os.environ["pydna_cached_funcs"] = ""
78
- import doctest
79
70
 
80
- doctest.testmod(verbose=True, optionflags=doctest.ELLIPSIS)
81
- _os.environ["pydna_cached_funcs"] = cached
71
+ # from pydna.myprimers import PrimerList
pydna/amplicon.py CHANGED
@@ -18,10 +18,11 @@ from pydna.dseqrecord import Dseqrecord as _Dseqrecord
18
18
  from pydna.seqrecord import SeqRecord as _SeqRecord
19
19
  import textwrap as _textwrap
20
20
  import copy as _copy
21
- import logging as _logging
22
21
 
22
+ # import logging as _logging
23
23
 
24
- _module_logger = _logging.getLogger("pydna." + __name__)
24
+
25
+ # _module_logger = _logging.getLogger("pydna." + __name__)
25
26
 
26
27
 
27
28
  class Amplicon(_Dseqrecord):
@@ -43,7 +44,15 @@ class Amplicon(_Dseqrecord):
43
44
 
44
45
  """
45
46
 
46
- def __init__(self, record, *args, template=None, forward_primer=None, reverse_primer=None, **kwargs):
47
+ def __init__(
48
+ self,
49
+ record,
50
+ *args,
51
+ template=None,
52
+ forward_primer=None,
53
+ reverse_primer=None,
54
+ **kwargs,
55
+ ):
47
56
  super().__init__(record, *args)
48
57
  self.template = template
49
58
  self.forward_primer = forward_primer
@@ -83,7 +92,10 @@ class Amplicon(_Dseqrecord):
83
92
  r.template = self.template.rc()
84
93
  r.forward_primer = _copy.copy(self.reverse_primer)
85
94
  r.reverse_primer = _copy.copy(self.forward_primer)
86
- r.forward_primer.position, r.reverse_primer.position = r.reverse_primer.position, r.forward_primer.position
95
+ r.forward_primer.position, r.reverse_primer.position = (
96
+ r.reverse_primer.position,
97
+ r.forward_primer.position,
98
+ )
87
99
  return r
88
100
 
89
101
  rc = reverse_complement
@@ -123,21 +135,25 @@ class Amplicon(_Dseqrecord):
123
135
  fzc = tp.seq.crick[::-1][fp.position - fp._fp : fp.position]
124
136
  rzc = tp.seq.crick[::-1][rp.position : rp.position + rp._fp]
125
137
  f = f"""
126
- {" " *ft}5{faz}...{raz}3
138
+ {" " * ft}5{faz}...{raz}3
127
139
  {sp3}{"|" * rp._fp}
128
140
  {sp3}3{rp.seq[::-1]}5
129
141
  5{fp.seq}3
130
- {"|" *fp._fp:>{len(fp)}}
131
- {" " *ft}3{fzc}...{rzc}5
142
+ {"|" * fp._fp:>{len(fp)}}
143
+ {" " * ft}3{fzc}...{rzc}5
132
144
  """
133
145
  # breakpoint()
134
146
  return _pretty_str(_textwrap.dedent(f).strip("\n"))
135
147
 
136
148
  def set_forward_primer_footprint(self, length):
137
- self.forward_primer = _Primer(self.forward_primer.tail + self.seq[:length], footprint=length)
149
+ self.forward_primer = _Primer(
150
+ self.forward_primer.tail + self.seq[:length], footprint=length
151
+ )
138
152
 
139
153
  def set_reverse_primer_footprint(self, length):
140
- self.reverse_primer = _Primer(self.reverse_primer.tail + self.seq[:length], footprint=length)
154
+ self.reverse_primer = _Primer(
155
+ self.reverse_primer.tail + self.seq[:length], footprint=length
156
+ )
141
157
 
142
158
  def program(self):
143
159
  return _program(self)
@@ -147,14 +163,3 @@ class Amplicon(_Dseqrecord):
147
163
 
148
164
  def primers(self):
149
165
  return self.forward_primer, self.reverse_primer
150
-
151
-
152
- if __name__ == "__main__":
153
- import os as _os
154
-
155
- cached = _os.getenv("pydna_cached_funcs", "")
156
- _os.environ["pydna_cached_funcs"] = ""
157
- import doctest
158
-
159
- doctest.testmod(verbose=True, optionflags=doctest.ELLIPSIS)
160
- _os.environ["pydna_cached_funcs"] = cached
pydna/amplify.py CHANGED
@@ -30,10 +30,12 @@ import itertools as _itertools
30
30
  import re as _re
31
31
  import copy as _copy
32
32
  import operator as _operator
33
- import os as _os
34
- import logging as _logging
35
33
 
36
- _module_logger = _logging.getLogger("pydna." + __name__)
34
+ # import os as _os
35
+
36
+ # import logging as _logging
37
+
38
+ # _module_logger = _logging.getLogger("pydna." + __name__)
37
39
 
38
40
  _table = { # IUPAC Ambiguity Codes for Nucleotide Degeneracy and U for Uracile
39
41
  "A": "A",
@@ -112,7 +114,9 @@ def _annealing_positions(primer, template, limit):
112
114
  results = []
113
115
  for match_start in positions:
114
116
  tm = template[match_start + limit : match_start + limit + length].lower()
115
- footprint = len(list(_itertools.takewhile(lambda x: x[0] == x[1], zip(tail, tm))))
117
+ footprint = len(
118
+ list(_itertools.takewhile(lambda x: x[0] == x[1], zip(tail, tm)))
119
+ )
116
120
  results.append((match_start, footprint + limit))
117
121
  return results
118
122
  return []
@@ -343,11 +347,19 @@ class Anneal(object): # ), metaclass=_Memoize):
343
347
  for rp in self.reverse_primers:
344
348
  if self.template.circular:
345
349
  shift = fp.position - fp._fp
346
- tpl = self.template.shifted(shift) # shift template so that it starts where the fp starts anneling
347
- fp.position = fp._fp # New position of fp becomes the footprint length
348
- rp.position = (rp.position - shift) % len(self.template) # Shift the rp position as well
350
+ tpl = self.template.shifted(
351
+ shift
352
+ ) # shift template so that it starts where the fp starts anneling
353
+ fp.position = (
354
+ fp._fp
355
+ ) # New position of fp becomes the footprint length
356
+ rp.position = (rp.position - shift) % len(
357
+ self.template
358
+ ) # Shift the rp position as well
349
359
  feats = tpl[: rp.position + rp._fp].features
350
- elif fp.position <= rp.position: # pcr products only formed if fp anneals forward of rp
360
+ elif (
361
+ fp.position <= rp.position
362
+ ): # pcr products only formed if fp anneals forward of rp
351
363
  feats = self.template[
352
364
  fp.position - fp._fp : rp.position + rp._fp
353
365
  ].features # Save features covered by primers
@@ -361,10 +373,16 @@ class Anneal(object): # ), metaclass=_Memoize):
361
373
  if tpl.circular and fp.position == rp.position:
362
374
  prd = _Dseqrecord(fp) + _Dseqrecord(rp).reverse_complement()
363
375
  else:
364
- prd = _Dseqrecord(fp) + tpl[fp.position : rp.position] + _Dseqrecord(rp).reverse_complement()
376
+ prd = (
377
+ _Dseqrecord(fp)
378
+ + tpl[fp.position : rp.position]
379
+ + _Dseqrecord(rp).reverse_complement()
380
+ )
365
381
  prd.features = feats
366
382
  full_tmpl_features = [
367
- f for f in self.template.features if f.location.start == 0 and f.location.end == len(self.template)
383
+ f
384
+ for f in self.template.features
385
+ if f.location.start == 0 and f.location.end == len(self.template)
368
386
  ]
369
387
  new_identifier = ""
370
388
  if full_tmpl_features:
@@ -383,10 +401,14 @@ class Anneal(object): # ), metaclass=_Memoize):
383
401
  or self.kwargs.get("name")
384
402
  or f"{len(prd)}bp_PCR_prod"[:16]
385
403
  )
386
- prd.id = _identifier_from_string(new_identifier)[:16] or self.kwargs.get("id") or f"{len(prd)}bp"[:16]
387
- prd.description = self.kwargs.get("description") or "pcr_product_{}_{}".format(
388
- fp.description, rp.description
404
+ prd.id = (
405
+ _identifier_from_string(new_identifier)[:16]
406
+ or self.kwargs.get("id")
407
+ or f"{len(prd)}bp"[:16]
389
408
  )
409
+ prd.description = self.kwargs.get(
410
+ "description"
411
+ ) or "pcr_product_{}_{}".format(fp.description, rp.description)
390
412
 
391
413
  amplicon = _Amplicon(
392
414
  prd,
@@ -405,7 +427,9 @@ class Anneal(object): # ), metaclass=_Memoize):
405
427
 
406
428
  def __repr__(self):
407
429
  """returns a short string representation"""
408
- return "Reaction(products = {})".format(len(self.forward_primers * len(self.reverse_primers)))
430
+ return "Reaction(products = {})".format(
431
+ len(self.forward_primers * len(self.reverse_primers))
432
+ )
409
433
 
410
434
  def __str__(self):
411
435
  """returns a short report describing if or where primer
@@ -419,13 +443,17 @@ class Anneal(object): # ), metaclass=_Memoize):
419
443
  )
420
444
  if self.forward_primers:
421
445
  for p in self.forward_primers:
422
- mystring += "{name} anneals forward (--->) at {pos}\n".format(name=p.name, pos=p.position)
446
+ mystring += "{name} anneals forward (--->) at {pos}\n".format(
447
+ name=p.name, pos=p.position
448
+ )
423
449
  else:
424
450
  mystring += "No forward primers anneal...\n"
425
451
  # mystring +="\n"
426
452
  if self.reverse_primers:
427
453
  for p in self.reverse_primers:
428
- mystring += "{name} anneals reverse (<---) at {pos}\n".format(name=p.name, pos=p.position)
454
+ mystring += "{name} anneals reverse (<---) at {pos}\n".format(
455
+ name=p.name, pos=p.position
456
+ )
429
457
  else:
430
458
  mystring += "No reverse primers anneal...\n"
431
459
  return _pretty_str(mystring.strip())
@@ -508,7 +536,8 @@ tatcgactgtatcatctgatagcac")
508
536
  pass
509
537
  else:
510
538
  raise TypeError(
511
- "arguments need to be a string, Bio.Seq, SeqRecord" ", Primer, Dseqrecord or Amplicon object"
539
+ "arguments need to be a string, Bio.Seq, SeqRecord"
540
+ ", Primer, Dseqrecord or Amplicon object"
512
541
  )
513
542
  new.append(s)
514
543
 
@@ -526,12 +555,3 @@ tatcgactgtatcatctgatagcac")
526
555
  elif len(anneal_primers.products) == 0:
527
556
  raise ValueError(f"No PCR product! {anneal_primers.report()}")
528
557
  raise ValueError(f"PCR not specific! {format(anneal_primers.report())}")
529
-
530
-
531
- if __name__ == "__main__":
532
- cached = _os.getenv("pydna_cached_funcs", "")
533
- _os.environ["pydna_cached_funcs"] = ""
534
- import doctest
535
-
536
- doctest.testmod(verbose=True, optionflags=doctest.ELLIPSIS)
537
- _os.environ["pydna_cached_funcs"] = cached