pydna 6.0.0a15__py3-none-any.whl → 6.0.0a25__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
@@ -149,7 +149,7 @@ __license__ = "BSD"
149
149
  __maintainer__ = "Björn Johansson"
150
150
  __email__ = "bjorn_johansson@bio.uminho.pt"
151
151
  __status__ = "Development" # "Production" #"Prototype"
152
- __version__ = "6.0.0-a.15"
152
+ __version__ = "6.0.0-a.25"
153
153
 
154
154
  # create config directory
155
155
  _os.environ["pydna_config_dir"] = _os.getenv("pydna_config_dir", _appdirs.user_config_dir("pydna"))
pydna/crispr.py ADDED
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Copyright 2013-2023 by Björn Johansson. All rights reserved.
5
+ # This code is part of the Python-dna distribution and governed by its
6
+ # license. Please see the LICENSE.txt file that should have been included
7
+ # as part of this package.
8
+ """Provides the Dseq class for handling double stranded DNA sequences.
9
+
10
+ Dseq is a subclass of :class:`Bio.Seq.Seq`. The Dseq class
11
+ is mostly useful as a part of the :class:`pydna.dseqrecord.Dseqrecord` class
12
+ which can hold more meta data.
13
+
14
+ The Dseq class support the notion of circular and linear DNA topology.
15
+ """
16
+
17
+ from abc import ABC, abstractmethod
18
+ import re
19
+ from pydna.utils import rc
20
+
21
+
22
+ class _cas(ABC):
23
+ scaffold = "ND"
24
+ pam = "ND"
25
+ size = 0
26
+ fst5 = 0
27
+ fst3 = 0
28
+
29
+ def __init__(self, protospacer):
30
+ self.protospacer = protospacer
31
+ self.compsite = re.compile(
32
+ f"(?=(?P<watson>{protospacer}{self.pam}))|(?=(?P<crick>{rc(self.pam)}{rc(protospacer)}))", re.UNICODE
33
+ )
34
+
35
+ @abstractmethod
36
+ def search(self, dna, linear=True):
37
+ """To override in subclass."""
38
+ pass
39
+
40
+ def __repr__(self):
41
+ return f"{type(self).__name__}({self.protospacer[:3]}..{self.protospacer[-3:]})"
42
+
43
+ @abstractmethod
44
+ def __str__(self):
45
+ """To override in subclass."""
46
+ pass
47
+
48
+
49
+ class cas9(_cas):
50
+ """docstring.
51
+
52
+ |----size----------|
53
+
54
+ ---protospacer------
55
+ -fst3
56
+ fst5 |-|
57
+ |--------------|
58
+ PAM
59
+ 5-NNGGAAGAGTAATACACTA-AAANGGNN-3
60
+ ||||||||||||||||||| ||||||||
61
+ 3-NNCCTTCTCATTATGTGAT-TTTNCCNN-5
62
+ ||||||||||||||||| |||
63
+ 5-GGAAGAGTAATACACTA-AAAg-u-a-a-g-g Scaffold
64
+ ---gRNA spacer--- u-a
65
+ u-a
66
+ u-a
67
+ u-a
68
+ a-u
69
+ g-u-g
70
+ a a
71
+ g-c-a
72
+ c-g
73
+ u-a
74
+ a-u
75
+ g a tetraloop
76
+ a-a
77
+ """
78
+
79
+ scaffold = "GTTTTAGAGCTAGAAATAGCAAGTTAAAATAAGG"
80
+ pam = ".GG"
81
+ size = 20
82
+ fst5 = 17
83
+ fst3 = -3
84
+ ovhg = fst5 - (size + fst3)
85
+
86
+ def search(self, dna, linear=True):
87
+ """docstring."""
88
+ dna = str(dna).upper()
89
+ if linear:
90
+ dna = dna
91
+ else:
92
+ dna = dna + dna[1 : self.size]
93
+ results = []
94
+ for mobj in self.compsite.finditer(dna):
95
+ w, c = mobj.groups()
96
+ if w:
97
+ results.append(mobj.start("watson") + 1 + self.fst5)
98
+ if c:
99
+ results.append(mobj.start("crick") + len(self.pam) + 1 - self.fst3)
100
+ return results
101
+
102
+ def __str__(self):
103
+ """docstring."""
104
+ return f">{type(self).__name__} protospacer scaffold\n{self.protospacer} {self.scaffold}"
105
+
106
+
107
+ def protospacer(guide_construct, cas=cas9):
108
+ """docstring."""
109
+ in_watson = [
110
+ mobj.group("ps")
111
+ for mobj in re.finditer(f"(?P<ps>.{{{cas.size}}})(?:{cas.scaffold})", str(guide_construct.seq).upper())
112
+ ]
113
+ in_crick = [
114
+ rc(mobj.group("ps"))
115
+ for mobj in re.finditer(f"(?:{rc(cas.scaffold)})(?P<ps>.{{{cas.size}}})", str(guide_construct.seq).upper())
116
+ ]
117
+ return in_watson + in_crick
118
+
119
+
120
+ if __name__ == "__main__":
121
+ import os as _os
122
+
123
+ cached = _os.getenv("pydna_cached_funcs", "")
124
+ _os.environ["pydna_cached_funcs"] = ""
125
+ import doctest
126
+
127
+ doctest.testmod(verbose=True, optionflags=doctest.ELLIPSIS)
128
+ _os.environ["pydna_cached_funcs"] = cached
pydna/ligate.py ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright 2013-2023 by Björn Johansson. All rights reserved.
4
+ # This code is part of the Python-dna distribution and governed by its
5
+ # license. Please see the LICENSE.txt file that should have been included
6
+ # as part of this package.
7
+ """docstring."""
8
+ from operator import add
9
+ from functools import reduce
10
+ import networkx as _nx
11
+ from itertools import permutations
12
+ import logging as _logging
13
+
14
+ _module_logger = _logging.getLogger("pydna." + __name__)
15
+
16
+
17
+ def ligate(fragments: list):
18
+ """docstring."""
19
+ G = _nx.DiGraph()
20
+ G.add_nodes_from(["begin", "end"])
21
+ fragments = fragments[:]
22
+
23
+ fragments.extend(f.rc() for f in fragments[1:])
24
+
25
+ for node in fragments:
26
+ G.add_edge("begin", node)
27
+ G.add_edge(node, "end")
28
+
29
+ for seq1, seq2 in permutations(fragments, 2):
30
+ try:
31
+ seq1 + seq2
32
+ except TypeError as err:
33
+ if str(err) != "sticky ends not compatible!":
34
+ raise
35
+ else:
36
+ if seq1.seq.three_prime_end() != (
37
+ "blunt",
38
+ "",
39
+ ) and seq2.seq.five_prime_end() != ("blunt", ""):
40
+ G.add_edge(seq1, seq2)
41
+ try:
42
+ G.remove_edge("begin", seq2)
43
+ except _nx.NetworkXError as err:
44
+ if "not in graph" not in str(err):
45
+ raise
46
+ try:
47
+ G.remove_edge(seq1, "end")
48
+ except _nx.NetworkXError as err:
49
+ if "not in graph" not in str(err):
50
+ raise
51
+
52
+ cpaths = [p for p in sorted(_nx.simple_cycles(G), key=len) if len(p) > 1]
53
+ csequences = [reduce(add, x).looped() for x in cpaths]
54
+ lpaths = [p for p in sorted(_nx.all_simple_paths(G, "begin", "end"), key=len) if len(p) > 3]
55
+ lsequences = [reduce(add, lp[1:-1]) for lp in lpaths]
56
+
57
+ return csequences, lsequences
58
+
59
+
60
+ if __name__ == "__main__":
61
+ import os as _os
62
+
63
+ cached = _os.getenv("pydna_cached_funcs", "")
64
+ _os.environ["pydna_cached_funcs"] = ""
65
+ import doctest
66
+
67
+ doctest.testmod(verbose=True, optionflags=doctest.ELLIPSIS)
68
+ _os.environ["pydna_cached_funcs"] = cached
pydna/myprimers.py CHANGED
@@ -135,8 +135,9 @@ class PrimerList(_UserList):
135
135
  i = oldstrs.index(str(p.seq).upper())
136
136
  except ValueError:
137
137
  i = no + len(new)
138
- suffix = p.id.split(str(i))[-1]
139
- suffix.lstrip("_")
138
+ # suffix = p.id.removeprefix(f"{str(i)}_") # use this after removing python 3.8
139
+ suffix = p.id[len(f"{str(i)}_") :] if p.id.startswith(f"{str(i)}_") else p.id
140
+ # suffix.lstrip("_")
140
141
  newprimer = _copy.copy(p)
141
142
  newprimer.id = f"{i}_{suffix}"
142
143
  new.append(newprimer)
@@ -144,7 +145,7 @@ class PrimerList(_UserList):
144
145
  found.append(self[i])
145
146
  new = new[::-1]
146
147
  newold = new + found
147
- return _pretty_str("\n".join([p.format("fasta") for p in newold]))
148
+ return _pretty_str("\n".join([p.format("primer") for p in newold]))
148
149
 
149
150
  def pydna_code_from_list(self, lst: list):
150
151
  """Pydna code for a list of primer objects."""
@@ -155,7 +156,7 @@ class PrimerList(_UserList):
155
156
  try:
156
157
  prstrs.index(str(p.seq).upper())
157
158
  except ValueError as e:
158
- print(f"{p.format('fasta')}")
159
+ print(f"{p.format('primer')}")
159
160
  err = e
160
161
  else:
161
162
  indices.append(self.data.index(p))
@@ -167,7 +168,7 @@ class PrimerList(_UserList):
167
168
  msg += f"{self.identifier} = {curly}\n\n"
168
169
  msg += ", ".join(f"{self.identifier}[{i}]" for i in indices)
169
170
  msg += " = parse_primers('''\n\n"
170
- msg += "\n".join(self[i].format("fasta") for i in indices)
171
+ msg += "\n".join(self[i].format("primer") for i in indices)
171
172
  msg += "\n''')"
172
173
  return _pretty_str(msg)
173
174
 
pydna/seqrecord.py CHANGED
@@ -615,6 +615,21 @@ class SeqRecord(_SeqRecord):
615
615
 
616
616
  def __format__(self, format):
617
617
  """docstring."""
618
+
619
+ def removeprefix(text, prefix):
620
+ """Until Python 3.8 is dropped, then use str.removeprefix."""
621
+ if text.startswith(prefix):
622
+ return text[len(prefix) :]
623
+ return text
624
+
625
+ if format == "pydnafasta":
626
+ return _pretty_str(
627
+ f">{self.id} {len(self)} bp {dict(((True,'circular'),(False,'linear')))[self.seq.circular]}\n{str(self.seq)}\n"
628
+ )
629
+ if format == "primer":
630
+ return _pretty_str(
631
+ f">{self.id} {len(self)}-mer{removeprefix(self.description, self.name).strip()}\n{str(self.seq)}\n"
632
+ )
618
633
  return _pretty_str(super().__format__(format))
619
634
 
620
635
  def __add__(self, other):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pydna
3
- Version: 6.0.0a15
3
+ Version: 6.0.0a25
4
4
  Summary: Representing double stranded DNA and functions for simulating cloning and homologous recombination between DNA molecules.
5
5
  Home-page: https://github.com/BjornFJohansson/pydna#-pydna
6
6
  License: BSD
@@ -1,4 +1,4 @@
1
- pydna/__init__.py,sha256=KGzllNGPhVhbJpaU-RElkF7czeeDt5c6cOz4GzV-5Q0,13035
1
+ pydna/__init__.py,sha256=s_mxJrApNHS7MAajAxc28BJ3oun19_7GU7GcUFxLXzw,13035
2
2
  pydna/_pretty.py,sha256=8X-YttddmNO6vd536opcbNMAIJz5wK7savZhpssQ75A,1102
3
3
  pydna/_thermodynamic_data.py,sha256=9_w-97DpkbsWbJGHVijscMvUS_SFt7GxzrxspMRPZSg,10903
4
4
  pydna/all.py,sha256=i2dR9cAccr3AdtAMMeH4jazpVjxWjfvu8LB3LD9hwgY,2099
@@ -9,6 +9,7 @@ pydna/codon.py,sha256=7UMhxpcdKl4lwqA_ucHwD0CTz0l7ScGS7LbP6uAwr40,2408
9
9
  pydna/common_sub_strings.py,sha256=sRxqEaSmDFMCnEVD5Hu5veVvbOBZUrhxKcK6zWJXRpc,11157
10
10
  pydna/conftest.py,sha256=T5-WmHWLZH3U3ifxnbxd_oOiIFibIrkYpwNacCHlvsY,999
11
11
  pydna/contig.py,sha256=aNKtXGaHY0c70tEEMHk_9lDMk9DQzjFRO6LK-GPtdwc,7991
12
+ pydna/crispr.py,sha256=n-QWU8aylK0oFEeHxsQWvketKeEfsER12L7EvDN4JHs,3697
12
13
  pydna/design.py,sha256=bmwT1v-h0pFEtzQ01ZLVhmgwl_OTUXLaVBaI5Q0bc2c,26442
13
14
  pydna/download.py,sha256=uFoAvWYXr1C30071p9OweMdemvKO-1F2pB5CHo2k31U,1307
14
15
  pydna/dseq.py,sha256=dhPDGbsnLq_W09WMucM5faexyQlns4djOHs5iDiTEwU,44975
@@ -23,18 +24,19 @@ pydna/genbankfixer.py,sha256=D2-I30fIPMndyefNzOaeAYbu6LGHC_SnOyjxJhhMfYw,20695
23
24
  pydna/genbankrecord.py,sha256=EWRQ9EB7xzIAVqk7ico0bL_JSjR92LXt0UTSQ0HztEI,5771
24
25
  pydna/goldengate.py,sha256=Fmkbb4kkau9h1o6I-MiQZ0rNHwmD4-1IK0BJaL1MblI,1774
25
26
  pydna/ladders.py,sha256=2SaTq7_Y8XLvEBK0UqgkB9aWePzG0g84cPiNtJfggx0,3574
27
+ pydna/ligate.py,sha256=41YYBcZxGl1PzABZoi-zkRlRcR6sYCzT4rp5HE45A9Q,2205
26
28
  pydna/myenzymes.py,sha256=gnD9jP-G2ERTpR5vkeOD1LDvlhwW-rsolz0Zoo8IfMs,1797
27
- pydna/myprimers.py,sha256=i8IylT_aZ6tgq7wTrVTvttUfTX-g75IOrJEo7qDTCL0,7215
29
+ pydna/myprimers.py,sha256=JtpdejRP6MkKplLv-p5NCMzxBTepYN0CVHSxxP3ms3Q,7362
28
30
  pydna/parsers.py,sha256=TUGRo-1Av3gRaHKHS4GM3Onou-X-Ai8IRICFvO8gDeo,7998
29
31
  pydna/primer.py,sha256=7AYWIhr1YbjG0Gak94bU6bTlsRUgWCIbKTndgsgWZ2M,2533
30
32
  pydna/readers.py,sha256=wgk4wBiCWZKqMIwof2YESGDzWOer6uAMgxUeJVOIQrM,1710
31
33
  pydna/seq.py,sha256=u_DX4awip98x0wBkFycEilpLY2wO8yqpcmVeCpVpDhA,4125
32
- pydna/seqrecord.py,sha256=zBO3kRIBd71ww8k_kRUKWEDJu3oiDrWlPJ7LujK0X9o,22129
34
+ pydna/seqrecord.py,sha256=shQk8oH1Aw13vo03BUR-ER32mYT0PjjlILDBXc4QXyM,22754
33
35
  pydna/sequence_picker.py,sha256=KMyyXAidvHerRAf8oiOfnGwsMYnzMztTWulpxPiER7M,1645
34
36
  pydna/threading_timer_decorator_exit.py,sha256=D91kqjKSavWDnXyc1Fo-CwPYtbmR2DjTXnBYSRXKmSA,2793
35
37
  pydna/tm.py,sha256=moILUFi6W5vOfCp0uj5Cd0ADQFqgzluMJ6d-ABEUNL4,9753
36
38
  pydna/utils.py,sha256=glw3diUAYdrcgEaSSLwq6tno9upmBc8yzTCQOrPRI5I,23443
37
- pydna-6.0.0a15.dist-info/LICENSE.txt,sha256=u8QfcsnNXZM0UCexerK_MvyA2lPWgeGyUtSYXvLG6Oc,6119
38
- pydna-6.0.0a15.dist-info/METADATA,sha256=XzFvRaPpDoiv0ztDWlEpAsj-N491zZih4Y3MrJGpKzk,17702
39
- pydna-6.0.0a15.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
40
- pydna-6.0.0a15.dist-info/RECORD,,
39
+ pydna-6.0.0a25.dist-info/LICENSE.txt,sha256=u8QfcsnNXZM0UCexerK_MvyA2lPWgeGyUtSYXvLG6Oc,6119
40
+ pydna-6.0.0a25.dist-info/METADATA,sha256=oxcA3Uj0ddBcQkPMnCdDkKPL2JGFOvI8DwinFj-eGDM,17702
41
+ pydna-6.0.0a25.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
42
+ pydna-6.0.0a25.dist-info/RECORD,,