dnakit 0.1.0.dev0__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.
Files changed (210) hide show
  1. dnakit/__init__.py +108 -0
  2. dnakit/_version.py +5 -0
  3. dnakit/alignment/__init__.py +6 -0
  4. dnakit/alignment/pairwise.py +512 -0
  5. dnakit/alignment/results.py +188 -0
  6. dnakit/backends/__init__.py +80 -0
  7. dnakit/backends/external.py +517 -0
  8. dnakit/backends/registry.py +207 -0
  9. dnakit/batch.py +452 -0
  10. dnakit/cache/__init__.py +5 -0
  11. dnakit/cache/store.py +424 -0
  12. dnakit/chunking.py +920 -0
  13. dnakit/cli/__init__.py +5 -0
  14. dnakit/cli/__main__.py +6 -0
  15. dnakit/cli/app.py +814 -0
  16. dnakit/cli/workflow.py +94 -0
  17. dnakit/config/__init__.py +5 -0
  18. dnakit/config/loader.py +381 -0
  19. dnakit/core/__init__.py +80 -0
  20. dnakit/core/_json.py +206 -0
  21. dnakit/core/backend_info.py +70 -0
  22. dnakit/core/collection.py +163 -0
  23. dnakit/core/coordinates.py +295 -0
  24. dnakit/core/enums.py +95 -0
  25. dnakit/core/facade.py +719 -0
  26. dnakit/core/feature.py +90 -0
  27. dnakit/core/gap.py +82 -0
  28. dnakit/core/issues.py +62 -0
  29. dnakit/core/provenance.py +305 -0
  30. dnakit/core/record.py +161 -0
  31. dnakit/core/results.py +134 -0
  32. dnakit/core/sequence.py +327 -0
  33. dnakit/datasets/__init__.py +100 -0
  34. dnakit/datasets/_advanced_shared.py +198 -0
  35. dnakit/datasets/_metadata.py +33 -0
  36. dnakit/datasets/advanced_deduplicate.py +183 -0
  37. dnakit/datasets/advanced_split.py +302 -0
  38. dnakit/datasets/clustering.py +286 -0
  39. dnakit/datasets/config.py +531 -0
  40. dnakit/datasets/deduplicate.py +303 -0
  41. dnakit/datasets/evaluation.py +244 -0
  42. dnakit/datasets/filter.py +135 -0
  43. dnakit/datasets/neural_clustering.py +221 -0
  44. dnakit/datasets/results.py +520 -0
  45. dnakit/datasets/split.py +450 -0
  46. dnakit/descriptors/__init__.py +102 -0
  47. dnakit/descriptors/_dinucleotide.py +345 -0
  48. dnakit/descriptors/_shared.py +180 -0
  49. dnakit/descriptors/all.py +917 -0
  50. dnakit/descriptors/basic.py +193 -0
  51. dnakit/descriptors/codon.py +195 -0
  52. dnakit/descriptors/complexity.py +201 -0
  53. dnakit/descriptors/entropy.py +101 -0
  54. dnakit/descriptors/homopolymer.py +105 -0
  55. dnakit/descriptors/kmer.py +88 -0
  56. dnakit/descriptors/results.py +286 -0
  57. dnakit/descriptors/schema.py +414 -0
  58. dnakit/descriptors/window.py +203 -0
  59. dnakit/download/__init__.py +54 -0
  60. dnakit/download/catalogs.py +166 -0
  61. dnakit/download/ena.py +131 -0
  62. dnakit/download/encode.py +103 -0
  63. dnakit/download/files.py +469 -0
  64. dnakit/download/indexes.py +233 -0
  65. dnakit/download/metadata.py +164 -0
  66. dnakit/download/models.py +227 -0
  67. dnakit/download/ncbi.py +333 -0
  68. dnakit/download/sequence.py +133 -0
  69. dnakit/download/ucsc.py +99 -0
  70. dnakit/evaluation/__init__.py +81 -0
  71. dnakit/evaluation/_shared.py +288 -0
  72. dnakit/evaluation/collection.py +270 -0
  73. dnakit/evaluation/config.py +591 -0
  74. dnakit/evaluation/distribution.py +287 -0
  75. dnakit/evaluation/frechet.py +223 -0
  76. dnakit/evaluation/generative.py +381 -0
  77. dnakit/evaluation/reference.py +409 -0
  78. dnakit/evaluation/results.py +137 -0
  79. dnakit/evaluation/scorecard.py +211 -0
  80. dnakit/evaluation/sequence.py +403 -0
  81. dnakit/evaluation/synthesis.py +249 -0
  82. dnakit/exceptions.py +189 -0
  83. dnakit/fingerprints/__init__.py +109 -0
  84. dnakit/fingerprints/_shared.py +116 -0
  85. dnakit/fingerprints/advanced.py +829 -0
  86. dnakit/fingerprints/bit.py +229 -0
  87. dnakit/fingerprints/encoding.py +351 -0
  88. dnakit/fingerprints/kmer.py +170 -0
  89. dnakit/fingerprints/results.py +531 -0
  90. dnakit/fingerprints/sketch.py +246 -0
  91. dnakit/io/__init__.py +112 -0
  92. dnakit/io/_advanced_common.py +105 -0
  93. dnakit/io/_formats.py +994 -0
  94. dnakit/io/annotations.py +1179 -0
  95. dnakit/io/api.py +759 -0
  96. dnakit/io/config.py +315 -0
  97. dnakit/io/genbank.py +523 -0
  98. dnakit/io/indexed.py +1146 -0
  99. dnakit/io/metadata.py +452 -0
  100. dnakit/io/parquet.py +56 -0
  101. dnakit/io/results.py +131 -0
  102. dnakit/io/source.py +138 -0
  103. dnakit/io/tables.py +1237 -0
  104. dnakit/molbio/__init__.py +101 -0
  105. dnakit/molbio/_shared.py +266 -0
  106. dnakit/molbio/assembly.py +279 -0
  107. dnakit/molbio/crispr.py +181 -0
  108. dnakit/molbio/optimization.py +897 -0
  109. dnakit/molbio/primer3_design.py +667 -0
  110. dnakit/molbio/primers.py +899 -0
  111. dnakit/molbio/restriction.py +573 -0
  112. dnakit/molbio/results.py +583 -0
  113. dnakit/ops/__init__.py +588 -0
  114. dnakit/ops/_common.py +201 -0
  115. dnakit/ops/circular.py +193 -0
  116. dnakit/ops/concat.py +204 -0
  117. dnakit/ops/direction.py +27 -0
  118. dnakit/ops/edit.py +443 -0
  119. dnakit/ops/evolution.py +991 -0
  120. dnakit/ops/mutation.py +151 -0
  121. dnakit/ops/records.py +1012 -0
  122. dnakit/ops/translation.py +257 -0
  123. dnakit/patterns/__init__.py +81 -0
  124. dnakit/patterns/_shared.py +282 -0
  125. dnakit/patterns/coding.py +360 -0
  126. dnakit/patterns/crispr.py +337 -0
  127. dnakit/patterns/motif.py +721 -0
  128. dnakit/patterns/regions.py +341 -0
  129. dnakit/patterns/repeats.py +480 -0
  130. dnakit/patterns/restriction.py +281 -0
  131. dnakit/patterns/results.py +411 -0
  132. dnakit/py.typed +1 -0
  133. dnakit/references/__init__.py +27 -0
  134. dnakit/references/models.py +155 -0
  135. dnakit/references/ncbi.py +785 -0
  136. dnakit/representations/__init__.py +29 -0
  137. dnakit/representations/backends.py +928 -0
  138. dnakit/representations/checkpoints.py +356 -0
  139. dnakit/representations/extraction.py +220 -0
  140. dnakit/representations/models.py +395 -0
  141. dnakit/representations/results.py +79 -0
  142. dnakit/search/__init__.py +132 -0
  143. dnakit/search/_http.py +271 -0
  144. dnakit/search/_shared.py +108 -0
  145. dnakit/search/blast.py +516 -0
  146. dnakit/search/ena.py +245 -0
  147. dnakit/search/encode.py +102 -0
  148. dnakit/search/ensembl.py +874 -0
  149. dnakit/search/models.py +159 -0
  150. dnakit/search/ncbi.py +756 -0
  151. dnakit/search/ucsc.py +388 -0
  152. dnakit/secondary_structure/__init__.py +38 -0
  153. dnakit/secondary_structure/dotbracket.py +410 -0
  154. dnakit/secondary_structure/nupack.py +589 -0
  155. dnakit/secondary_structure/results.py +142 -0
  156. dnakit/similarity/__init__.py +125 -0
  157. dnakit/similarity/_shared.py +152 -0
  158. dnakit/similarity/approximate.py +258 -0
  159. dnakit/similarity/compare.py +162 -0
  160. dnakit/similarity/dashing.py +936 -0
  161. dnakit/similarity/distance.py +279 -0
  162. dnakit/similarity/index.py +365 -0
  163. dnakit/similarity/matrix.py +254 -0
  164. dnakit/similarity/results.py +676 -0
  165. dnakit/similarity/search.py +286 -0
  166. dnakit/similarity/sketch.py +96 -0
  167. dnakit/similarity/vector.py +662 -0
  168. dnakit/standardize/__init__.py +77 -0
  169. dnakit/standardize/_shared.py +100 -0
  170. dnakit/standardize/config.py +411 -0
  171. dnakit/standardize/gaps.py +1060 -0
  172. dnakit/standardize/normalize.py +565 -0
  173. dnakit/standardize/results.py +247 -0
  174. dnakit/standardize/validate.py +487 -0
  175. dnakit/structure3d/__init__.py +47 -0
  176. dnakit/structure3d/_shared.py +47 -0
  177. dnakit/structure3d/geometry.py +773 -0
  178. dnakit/structure3d/pdb.py +253 -0
  179. dnakit/structure3d/results.py +233 -0
  180. dnakit/structure3d/threedna.py +174 -0
  181. dnakit/thermodynamics/__init__.py +112 -0
  182. dnakit/thermodynamics/_shared.py +92 -0
  183. dnakit/thermodynamics/backends.py +653 -0
  184. dnakit/thermodynamics/calculations.py +837 -0
  185. dnakit/thermodynamics/config.py +175 -0
  186. dnakit/thermodynamics/equilibrium.py +340 -0
  187. dnakit/thermodynamics/optics.py +385 -0
  188. dnakit/thermodynamics/parameters.py +79 -0
  189. dnakit/thermodynamics/results.py +445 -0
  190. dnakit/visualization/__init__.py +43 -0
  191. dnakit/visualization/_svg.py +185 -0
  192. dnakit/visualization/advanced.py +314 -0
  193. dnakit/visualization/config.py +255 -0
  194. dnakit/visualization/export.py +349 -0
  195. dnakit/visualization/matrix.py +279 -0
  196. dnakit/visualization/report.py +431 -0
  197. dnakit/visualization/results.py +236 -0
  198. dnakit/visualization/sequence.py +459 -0
  199. dnakit/workflows/__init__.py +45 -0
  200. dnakit/workflows/manifest.py +365 -0
  201. dnakit/workflows/runner.py +1548 -0
  202. dnakit/workflows/schema.py +898 -0
  203. dnakit-0.1.0.dev0.dist-info/METADATA +126 -0
  204. dnakit-0.1.0.dev0.dist-info/RECORD +210 -0
  205. dnakit-0.1.0.dev0.dist-info/WHEEL +5 -0
  206. dnakit-0.1.0.dev0.dist-info/entry_points.txt +2 -0
  207. dnakit-0.1.0.dev0.dist-info/licenses/DISCLAIMER.md +26 -0
  208. dnakit-0.1.0.dev0.dist-info/licenses/LICENSE +21 -0
  209. dnakit-0.1.0.dev0.dist-info/licenses/THIRD_PARTY_NOTICES.md +73 -0
  210. dnakit-0.1.0.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,27 @@
1
+ """Reference-genome resolution and download adapters."""
2
+
3
+ from dnakit.references.models import DownloadProgress, GenomeAssembly, GenomeDownloadResult
4
+ from dnakit.references.ncbi import (
5
+ DEFAULT_CHUNK_SIZE,
6
+ DEFAULT_MAX_DOWNLOAD_BYTES,
7
+ DEFAULT_NCBI_API_BASE_URL,
8
+ DEFAULT_TIMEOUT,
9
+ ProgressCallback,
10
+ download_genome,
11
+ resolve_genome_assembly,
12
+ supported_genome_aliases,
13
+ )
14
+
15
+ __all__ = [
16
+ "DEFAULT_CHUNK_SIZE",
17
+ "DEFAULT_MAX_DOWNLOAD_BYTES",
18
+ "DEFAULT_NCBI_API_BASE_URL",
19
+ "DEFAULT_TIMEOUT",
20
+ "DownloadProgress",
21
+ "GenomeAssembly",
22
+ "GenomeDownloadResult",
23
+ "ProgressCallback",
24
+ "download_genome",
25
+ "resolve_genome_assembly",
26
+ "supported_genome_aliases",
27
+ ]
@@ -0,0 +1,155 @@
1
+ """Value objects returned by reference-genome download adapters."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from dataclasses import dataclass
7
+ from typing import Any, Literal, cast
8
+
9
+ from dnakit.core._json import to_json_compatible
10
+ from dnakit.core.provenance import Provenance
11
+ from dnakit.exceptions import ConfigurationError
12
+
13
+ DownloadPhase = Literal["resolve", "download", "extract"]
14
+ _MD5 = re.compile(r"^[0-9a-f]{32}$")
15
+ _SHA256 = re.compile(r"^[0-9a-f]{64}$")
16
+ _ASSEMBLY_ACCESSION = re.compile(r"^GC[AF]_\d+\.\d+$", flags=re.IGNORECASE)
17
+
18
+
19
+ def _require_text(value: object, name: str) -> str:
20
+ if not isinstance(value, str) or not value.strip():
21
+ raise ConfigurationError(
22
+ f"{name} must be a non-empty string.", code="INVALID_DOWNLOAD_RESULT"
23
+ )
24
+ return value
25
+
26
+
27
+ @dataclass(frozen=True, slots=True)
28
+ class GenomeAssembly:
29
+ """Resolved NCBI genome assembly identity."""
30
+
31
+ query: str
32
+ accession: str
33
+ organism: str | None = None
34
+ assembly_name: str | None = None
35
+ source_database: str | None = None
36
+
37
+ def __post_init__(self) -> None:
38
+ _require_text(self.query, "GenomeAssembly query")
39
+ accession = _require_text(self.accession, "GenomeAssembly accession")
40
+ if _ASSEMBLY_ACCESSION.fullmatch(accession) is None:
41
+ raise ConfigurationError(
42
+ "GenomeAssembly accession must be a versioned GCA_ or GCF_ assembly accession.",
43
+ code="INVALID_ASSEMBLY_ACCESSION",
44
+ )
45
+ for name in ("organism", "assembly_name", "source_database"):
46
+ value = getattr(self, name)
47
+ if value is not None:
48
+ _require_text(value, f"GenomeAssembly {name}")
49
+ object.__setattr__(self, "accession", accession.upper())
50
+
51
+
52
+ @dataclass(frozen=True, slots=True)
53
+ class DownloadProgress:
54
+ """One progress event emitted by a reference-data download."""
55
+
56
+ phase: DownloadPhase
57
+ query: str
58
+ accession: str
59
+ bytes_completed: int
60
+ total_bytes: int | None = None
61
+ current_file: str | None = None
62
+
63
+ def __post_init__(self) -> None:
64
+ if self.phase not in {"resolve", "download", "extract"}:
65
+ raise ConfigurationError(
66
+ "DownloadProgress phase is invalid.", code="INVALID_DOWNLOAD_PROGRESS"
67
+ )
68
+ _require_text(self.query, "DownloadProgress query")
69
+ _require_text(self.accession, "DownloadProgress accession")
70
+ for name, value in (
71
+ ("bytes_completed", self.bytes_completed),
72
+ ("total_bytes", self.total_bytes),
73
+ ):
74
+ if value is not None and (
75
+ isinstance(value, bool) or not isinstance(value, int) or value < 0
76
+ ):
77
+ raise ConfigurationError(
78
+ f"DownloadProgress {name} must be a non-negative integer or None.",
79
+ code="INVALID_DOWNLOAD_PROGRESS",
80
+ )
81
+ if self.total_bytes is not None and self.bytes_completed > self.total_bytes:
82
+ raise ConfigurationError(
83
+ "DownloadProgress bytes_completed cannot exceed total_bytes.",
84
+ code="INVALID_DOWNLOAD_PROGRESS",
85
+ )
86
+ if self.current_file is not None:
87
+ _require_text(self.current_file, "DownloadProgress current_file")
88
+
89
+
90
+ @dataclass(frozen=True, slots=True)
91
+ class GenomeDownloadResult:
92
+ """Auditable files and checksums produced by a genome download."""
93
+
94
+ query: str
95
+ accession: str
96
+ organism: str | None
97
+ assembly_name: str | None
98
+ output_directory: str
99
+ fasta_path: str
100
+ metadata_path: str
101
+ checksum_path: str
102
+ package_path: str | None
103
+ download_url: str
104
+ downloaded_bytes: int
105
+ package_sha256: str
106
+ fasta_sha256: str
107
+ fasta_md5: str
108
+ provenance: Provenance
109
+
110
+ def __post_init__(self) -> None:
111
+ for name in (
112
+ "query",
113
+ "accession",
114
+ "output_directory",
115
+ "fasta_path",
116
+ "metadata_path",
117
+ "checksum_path",
118
+ "download_url",
119
+ ):
120
+ _require_text(getattr(self, name), f"GenomeDownloadResult {name}")
121
+ for name in ("organism", "assembly_name", "package_path"):
122
+ value = getattr(self, name)
123
+ if value is not None:
124
+ _require_text(value, f"GenomeDownloadResult {name}")
125
+ for name in ("package_sha256", "fasta_sha256", "fasta_md5"):
126
+ value = _require_text(getattr(self, name), f"GenomeDownloadResult {name}").lower()
127
+ pattern = _MD5 if name == "fasta_md5" else _SHA256
128
+ if pattern.fullmatch(value) is None:
129
+ raise ConfigurationError(
130
+ f"GenomeDownloadResult {name} must be a lowercase hexadecimal hash.",
131
+ code="INVALID_DOWNLOAD_RESULT",
132
+ )
133
+ object.__setattr__(self, name, value)
134
+ if (
135
+ isinstance(self.downloaded_bytes, bool)
136
+ or not isinstance(self.downloaded_bytes, int)
137
+ or self.downloaded_bytes < 1
138
+ ):
139
+ raise ConfigurationError(
140
+ "GenomeDownloadResult downloaded_bytes must be positive.",
141
+ code="INVALID_DOWNLOAD_RESULT",
142
+ )
143
+ if not isinstance(self.provenance, Provenance):
144
+ raise ConfigurationError(
145
+ "GenomeDownloadResult provenance must be Provenance.",
146
+ code="INVALID_DOWNLOAD_RESULT",
147
+ )
148
+
149
+ def to_dict(self) -> dict[str, Any]:
150
+ """Return a JSON-compatible download manifest."""
151
+
152
+ return cast(dict[str, Any], to_json_compatible(self))
153
+
154
+
155
+ __all__ = ["DownloadPhase", "DownloadProgress", "GenomeAssembly", "GenomeDownloadResult"]