syncoder 0.0.6a0__tar.gz → 0.1.0a0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: syncoder
3
- Version: 0.0.6a0
3
+ Version: 0.1.0a0
4
4
  Summary: A codec for DNA data storage
5
5
  Project-URL: Homepage, https://example.com/TBD
6
6
  Project-URL: Issues, https://example.com/TBD/issues
@@ -0,0 +1,115 @@
1
+ import inspect
2
+ import warnings
3
+ from functools import wraps
4
+ import typing
5
+ from typing import Callable
6
+ import numpy as np
7
+
8
+ __all__ = ["reverse_complement", "_int_to_baseN", "_baseN_to_int", \
9
+ "_check_deprecated", "_is_pow_two", "eeleopard_available"]
10
+
11
+
12
+ def _is_pow_two(n: int):
13
+ """Returns if a number is a power of two."""
14
+ return (n > 0) and ((n & ( ~(n-1) )) == n)
15
+
16
+ def reverse_complement(dna_sequence: str) -> str:
17
+ """Returns the reverse complement of a DNA sequence."""
18
+ complement = {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C', 'a': 't', 't': 'a', 'c': 'g', 'g': 'c'}
19
+ reversed_sequence = dna_sequence[::-1]
20
+ reverse_complement_sequence = ''.join(complement[nucleotide] for nucleotide in reversed_sequence)
21
+ return reverse_complement_sequence
22
+
23
+ def _int_to_baseN(n:int,base:int,length:int=-1)->list[int]:
24
+ """Converts an integer to a base N number in little endian order.
25
+
26
+ Args:
27
+ n (int): The integer to be converted.
28
+ base (int): The base of the number system.
29
+ length (int, optional): If specified, the number will be zero padded to this length.
30
+
31
+ Returns:
32
+ list[int]: The list of digits representing the base N number.
33
+
34
+ """
35
+
36
+ digits = []
37
+ while n>0:
38
+ n,r = divmod(n,base)
39
+ digits.append(r)
40
+
41
+ #do zero padding
42
+ while len(digits)<length:
43
+ digits.append(0)
44
+ return digits
45
+
46
+ def _baseN_to_int(digits: list[int], base: int) -> int:
47
+ """
48
+ Converts a base N number to an integer using little endian order.
49
+
50
+ Args:
51
+ digits (list[int]): The list of digits representing the base N number.
52
+ base (int): The base of the number.
53
+
54
+ Returns:
55
+ int: The converted integer value.
56
+
57
+ """
58
+
59
+ n = 0
60
+ for d in reversed(digits):
61
+ n = n*base + d
62
+ return n
63
+
64
+
65
+ def _check_deprecated(func: Callable[..., typing.Any]) -> Callable[..., typing.Any]:
66
+ """Translate deprecated keyword arguments before calling ``func``."""
67
+ signature = inspect.signature(func)
68
+
69
+ @wraps(func)
70
+ def wrapper(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:
71
+ positional_arguments = signature.bind_partial(*args).arguments
72
+ replacements = (("words", "alphabet"),
73
+ ("alternate_words", "alternate_alphabet"))
74
+ for deprecated_name, current_name in replacements:
75
+ if deprecated_name not in kwargs:
76
+ continue
77
+ if current_name in kwargs or current_name in positional_arguments:
78
+ raise TypeError(
79
+ f"Cannot specify both '{current_name}' and '{deprecated_name}'"
80
+ )
81
+ kwargs[current_name] = kwargs.pop(deprecated_name)
82
+ warnings.warn(
83
+ f"The '{deprecated_name}' parameter is deprecated. Please use "
84
+ f"'{current_name}' instead.",
85
+ DeprecationWarning,
86
+ stacklevel=2,
87
+ )
88
+ return func(*args, **kwargs)
89
+
90
+ return wrapper
91
+
92
+
93
+ eeleopard_available = False
94
+ try:
95
+ import eeleopard
96
+ eeleopard_available = True
97
+ except ImportError:
98
+ pass
99
+
100
+ if eeleopard_available:
101
+ class WrappedLeopard(eeleopard.ReedSolomon): # pyright: ignore[reportPossiblyUnboundVariable] .. this is bound >:(
102
+ def encode(self, message: list[int]):
103
+ temp = super().encode(message)
104
+ ecc = temp[:-self.k]
105
+ data = temp[-self.k:]
106
+ return np.concatenate((data, ecc))
107
+
108
+ def decode(self, received, erasures = None,**kwargs): # pyright: ignore[reportIncompatibleMethodOverride] That's the point
109
+ data = received[:self.k ]
110
+ ecc = received[self.k:]
111
+ orig_codeword = np.concatenate((ecc,data))
112
+ dec_result = super().decode(orig_codeword, erasures,**kwargs)
113
+ return (dec_result.message, dec_result.num_errors,dec_result.error_positions)
114
+
115
+ __all__.append( "WrappedLeopard" )
@@ -3,4 +3,4 @@ from .codec import _default_b32_alphabet, _default_b32_alphabet_alt
3
3
  default_b32_alphabet = _default_b32_alphabet
4
4
  default_b32_alphabet_alt = _default_b32_alphabet_alt
5
5
 
6
- __version__ = "0.0.6a0"
6
+ __version__ = "0.1.0a0"