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,159 @@
1
+ """Immutable configuration and results for public database queries."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ from collections.abc import Iterable, Mapping
7
+ from dataclasses import dataclass
8
+ from typing import Any, cast
9
+
10
+ from dnakit.core import Provenance
11
+ from dnakit.core._json import FrozenDict, freeze_mapping, to_json_compatible
12
+ from dnakit.exceptions import ConfigurationError
13
+
14
+
15
+ @dataclass(frozen=True, slots=True)
16
+ class SearchConfig:
17
+ """Resource and contact settings shared by remote query adapters.
18
+
19
+ ``api_key`` is sent only to NCBI services. It is never included in a
20
+ ``QueryResult.request_url`` or serialized result.
21
+ """
22
+
23
+ timeout: float = 30.0
24
+ max_response_bytes: int = 20_000_000
25
+ max_records: int = 1_000
26
+ api_key: str | None = None
27
+ email: str | None = None
28
+ tool: str = "dnakit"
29
+
30
+ def __post_init__(self) -> None:
31
+ if (
32
+ isinstance(self.timeout, bool)
33
+ or not isinstance(self.timeout, (int, float))
34
+ or not math.isfinite(self.timeout)
35
+ or not 0 < self.timeout <= 300
36
+ ):
37
+ raise ConfigurationError(
38
+ "SearchConfig timeout must be in (0, 300].", code="INVALID_SEARCH_CONFIG"
39
+ )
40
+ for name, value, maximum in (
41
+ ("max_response_bytes", self.max_response_bytes, 100_000_000),
42
+ ("max_records", self.max_records, 10_000),
43
+ ):
44
+ if isinstance(value, bool) or not isinstance(value, int) or not 1 <= value <= maximum:
45
+ raise ConfigurationError(
46
+ f"SearchConfig {name} must be in [1, {maximum}].",
47
+ code="INVALID_SEARCH_CONFIG",
48
+ )
49
+ for name in ("api_key", "email"):
50
+ value = getattr(self, name)
51
+ if value is not None and (not isinstance(value, str) or not value.strip()):
52
+ raise ConfigurationError(
53
+ f"SearchConfig {name} must be None or non-empty text.",
54
+ code="INVALID_SEARCH_CONFIG",
55
+ )
56
+ if not isinstance(self.tool, str) or not self.tool.strip():
57
+ raise ConfigurationError(
58
+ "SearchConfig tool must be non-empty text.", code="INVALID_SEARCH_CONFIG"
59
+ )
60
+
61
+
62
+ @dataclass(frozen=True, slots=True)
63
+ class QueryProgress:
64
+ """One optional progress event emitted by a batch query."""
65
+
66
+ completed: int
67
+ total: int
68
+ item: str
69
+
70
+ def __post_init__(self) -> None:
71
+ if (
72
+ isinstance(self.completed, bool)
73
+ or not isinstance(self.completed, int)
74
+ or isinstance(self.total, bool)
75
+ or not isinstance(self.total, int)
76
+ or not 0 <= self.completed <= self.total
77
+ or self.total < 1
78
+ ):
79
+ raise ConfigurationError(
80
+ "QueryProgress counts are invalid.", code="INVALID_QUERY_PROGRESS"
81
+ )
82
+ if not isinstance(self.item, str) or not self.item:
83
+ raise ConfigurationError(
84
+ "QueryProgress item must be non-empty text.", code="INVALID_QUERY_PROGRESS"
85
+ )
86
+
87
+
88
+ @dataclass(frozen=True, init=False)
89
+ class QueryResult:
90
+ """Auditable, provider-neutral records returned by one logical query."""
91
+
92
+ query_type: str
93
+ provider: str
94
+ request_url: str
95
+ records: tuple[FrozenDict, ...]
96
+ total_count: int | None
97
+ next_page_token: str | None
98
+ metadata: FrozenDict
99
+ provenance: Provenance
100
+
101
+ def __init__(
102
+ self,
103
+ query_type: str,
104
+ provider: str,
105
+ request_url: str,
106
+ records: Iterable[Mapping[str, object]],
107
+ provenance: Provenance,
108
+ *,
109
+ total_count: int | None = None,
110
+ next_page_token: str | None = None,
111
+ metadata: Mapping[str, object] | None = None,
112
+ ) -> None:
113
+ for name, value in (
114
+ ("query_type", query_type),
115
+ ("provider", provider),
116
+ ("request_url", request_url),
117
+ ):
118
+ if not isinstance(value, str) or not value.strip():
119
+ raise ConfigurationError(
120
+ f"QueryResult {name} must be non-empty text.",
121
+ code="INVALID_QUERY_RESULT",
122
+ )
123
+ frozen_records = tuple(freeze_mapping(record) for record in records)
124
+ if total_count is not None and (
125
+ isinstance(total_count, bool)
126
+ or not isinstance(total_count, int)
127
+ or total_count < len(frozen_records)
128
+ ):
129
+ raise ConfigurationError(
130
+ "QueryResult total_count must be None or at least the returned record count.",
131
+ code="INVALID_QUERY_RESULT",
132
+ )
133
+ if next_page_token is not None and (
134
+ not isinstance(next_page_token, str) or not next_page_token.strip()
135
+ ):
136
+ raise ConfigurationError(
137
+ "QueryResult next_page_token must be None or non-empty text.",
138
+ code="INVALID_QUERY_RESULT",
139
+ )
140
+ if not isinstance(provenance, Provenance):
141
+ raise ConfigurationError(
142
+ "QueryResult provenance must be Provenance.", code="INVALID_QUERY_RESULT"
143
+ )
144
+ object.__setattr__(self, "query_type", query_type)
145
+ object.__setattr__(self, "provider", provider)
146
+ object.__setattr__(self, "request_url", request_url)
147
+ object.__setattr__(self, "records", frozen_records)
148
+ object.__setattr__(self, "total_count", total_count)
149
+ object.__setattr__(self, "next_page_token", next_page_token)
150
+ object.__setattr__(self, "metadata", freeze_mapping(metadata))
151
+ object.__setattr__(self, "provenance", provenance)
152
+
153
+ def to_dict(self) -> dict[str, Any]:
154
+ """Return a JSON-compatible result without credentials."""
155
+
156
+ return cast(dict[str, Any], to_json_compatible(self))
157
+
158
+
159
+ __all__ = ["QueryProgress", "QueryResult", "SearchConfig"]