mafutils 0.2.1__tar.gz → 0.3.0__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.
Files changed (87) hide show
  1. mafutils-0.3.0/.github/workflows/tests.yml +28 -0
  2. {mafutils-0.2.1 → mafutils-0.3.0}/DEVELOPMENT.md +18 -1
  3. {mafutils-0.2.1 → mafutils-0.3.0}/PKG-INFO +2 -1
  4. {mafutils-0.2.1 → mafutils-0.3.0}/README.md +1 -0
  5. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/_version.py +3 -3
  6. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/fetch.py +53 -7
  7. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/PKG-INFO +2 -1
  8. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/SOURCES.txt +6 -0
  9. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/scm_file_list.json +6 -0
  10. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/scm_version.json +2 -2
  11. mafutils-0.3.0/tests/real-excerpt.maf +131 -0
  12. mafutils-0.3.0/tests/real-excerpt.maf.block.idx +9 -0
  13. mafutils-0.3.0/tests/real-excerpt.maf.scaffold.idx +2 -0
  14. {mafutils-0.2.1 → mafutils-0.3.0}/tests/test_fetch.py +61 -0
  15. mafutils-0.3.0/tests/test_real_data.py +115 -0
  16. mafutils-0.3.0/tests/test_stats.py +143 -0
  17. {mafutils-0.2.1 → mafutils-0.3.0}/.codex +0 -0
  18. {mafutils-0.2.1 → mafutils-0.3.0}/.github/workflows/publish-pypi.yml +0 -0
  19. {mafutils-0.2.1 → mafutils-0.3.0}/.gitignore +0 -0
  20. {mafutils-0.2.1 → mafutils-0.3.0}/AGENTS.md +0 -0
  21. {mafutils-0.2.1 → mafutils-0.3.0}/LICENSE +0 -0
  22. {mafutils-0.2.1 → mafutils-0.3.0}/THIRD_PARTY_LICENSES.md +0 -0
  23. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/README.md +0 -0
  24. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/Snakefile +0 -0
  25. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/baseline-manual-timings.txt +0 -0
  26. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/config.yaml +0 -0
  27. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/history.csv +0 -0
  28. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/notebook.ipynb +0 -0
  29. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/parse_benchmarks.py +0 -0
  30. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/profiles/slurm/config.yaml +0 -0
  31. {mafutils-0.2.1 → mafutils-0.3.0}/benchmarks/rulegraph.png +0 -0
  32. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/__init__.py +0 -0
  33. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/__main__.py +0 -0
  34. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/cli.py +0 -0
  35. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/gc.py +0 -0
  36. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/index.py +0 -0
  37. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/lib/__init__.py +0 -0
  38. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/lib/bgzf.py +0 -0
  39. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/lib/common.py +0 -0
  40. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/lib/loginit.py +0 -0
  41. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/stats.py +0 -0
  42. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils/validate.py +0 -0
  43. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/dependency_links.txt +0 -0
  44. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/entry_points.txt +0 -0
  45. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/requires.txt +0 -0
  46. {mafutils-0.2.1 → mafutils-0.3.0}/mafutils.egg-info/top_level.txt +0 -0
  47. {mafutils-0.2.1 → mafutils-0.3.0}/pyproject.toml +0 -0
  48. {mafutils-0.2.1 → mafutils-0.3.0}/setup.cfg +0 -0
  49. {mafutils-0.2.1 → mafutils-0.3.0}/tests/crossblocks-missing-species.bed +0 -0
  50. {mafutils-0.2.1 → mafutils-0.3.0}/tests/crossblocks.bed +0 -0
  51. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example-tabs.maf +0 -0
  52. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example-tabs.maf.block.idx +0 -0
  53. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example-tabs.maf.scaffold.idx +0 -0
  54. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.bed +0 -0
  55. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf +0 -0
  56. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.bgz +0 -0
  57. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.bgz.block.idx +0 -0
  58. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.bgz.scaffold.idx +0 -0
  59. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.block.idx +0 -0
  60. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.gz +0 -0
  61. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.gz.block.idx +0 -0
  62. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.gz.scaffold.idx +0 -0
  63. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.scaffold.idx +0 -0
  64. {mafutils-0.2.1 → mafutils-0.3.0}/tests/example.maf.scaffold.regenerated.idx +0 -0
  65. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/01-singleblock-gap.fa +0 -0
  66. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/02-truncatedblock.fa +0 -0
  67. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/03-crossblocks-missing.fa +0 -0
  68. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/04-singleblock.fa +0 -0
  69. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/05-crossblocks.fa +0 -0
  70. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/06-noalign.fa +0 -0
  71. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/07-negstrand.fa +0 -0
  72. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/08-span-multiple-gaps.fa +0 -0
  73. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/09-missingchrom.fa +0 -0
  74. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-fasta/10-crossblocks-missing-species.fa +0 -0
  75. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/01-singleblock-gap.maf +0 -0
  76. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/02-truncatedblock.maf +0 -0
  77. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/03-crossblocks-missing.maf +0 -0
  78. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/04-singleblock.maf +0 -0
  79. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/05-crossblocks.maf +0 -0
  80. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/06-noalign.maf +0 -0
  81. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/07-negstrand.maf +0 -0
  82. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/08-span-multiple-gaps.maf +0 -0
  83. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/09-missingchrom.maf +0 -0
  84. {mafutils-0.2.1 → mafutils-0.3.0}/tests/expected-maf/10-crossblocks-missing-species.maf +0 -0
  85. {mafutils-0.2.1 → mafutils-0.3.0}/tests/test_compression.py +0 -0
  86. {mafutils-0.2.1 → mafutils-0.3.0}/tests/test_gc.py +0 -0
  87. {mafutils-0.2.1 → mafutils-0.3.0}/tests/test_validate.py +0 -0
@@ -0,0 +1,28 @@
1
+ name: Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: pytest
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Check out source
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.11"
21
+
22
+ - name: Install package and pytest
23
+ run: |
24
+ python -m pip install --upgrade pip
25
+ pip install -e . pytest
26
+
27
+ - name: Run tests
28
+ run: pytest tests/ -v
@@ -187,7 +187,24 @@ pytest tests/
187
187
  per-command parallel/sequential/fallback logic) across all three compression
188
188
  types. `tests/test_validate.py` covers index integrity (size/mtime/hash
189
189
  header fields, `mafutils validate`'s three-way verdict, and `--verify-hash`
190
- on `fetch`/`stats`/`gc`).
190
+ on `fetch`/`stats`/`gc`). `tests/test_stats.py` checks `mafutils stats`'s
191
+ computed `overall.tsv`/`species.tsv` values against numbers hand-derived
192
+ directly from `tests/example.maf`'s raw content (not just "doesn't crash"),
193
+ including a regression guard that the sequential (`-p 1`, no
194
+ `ProcessPoolExecutor`) and real multi-worker (`-p 2`+) paths produce
195
+ identical output.
196
+
197
+ `tests/test_real_data.py` runs `stats`/`gc`/`fetch` against
198
+ `tests/real-excerpt.maf` -- 8 real, complete alignment blocks extracted
199
+ read-only from gwct's actual ~42GB production MAF
200
+ (`data/hamsters/uncompressed/...`), not hand-crafted. Unlike
201
+ `example.maf`-based tests (which verify exact hand-computed values),
202
+ these check plausibility/robustness on genuinely real data -- real
203
+ species-naming conventions, real gap patterns, real block-size
204
+ distribution -- since a hand-crafted fixture wouldn't think to include
205
+ whatever real data actually looks like. This is deliberately still a
206
+ tiny, committed fixture, not the real dataset itself: `data/hamsters/`
207
+ stays untouched and out of git (see the `.gitignore` `data/` entry).
191
208
 
192
209
  ## Releasing to PyPI
193
210
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mafutils
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Utilities for indexing, fetching, and summarizing MAFs.
5
5
  Author: Gregg Thomas
6
6
  License: MIT License
@@ -214,6 +214,7 @@ Options:
214
214
  | `--fasta-dedupe` | FASTA duplicate handling: `none` or `most-seq` |
215
215
  | `--processes`, `-p` | Number of worker processes (see Compression above — plain gzip always runs single-process) |
216
216
  | `--mode`, `-m` | Fetch mode: `block` or `scaffold` |
217
+ | `--scaffold-subdirs` | Group output files into subfolders named by reference scaffold (`<output>/<scaffold>/<basename>`) instead of one flat directory |
217
218
  | `--verbose` | Emit warning lines from each completed batch |
218
219
  | `--profile` | Log internal timing breakdowns |
219
220
  | `--verify-hash` | Verify the index's stored content hash against the MAF file (see Index Integrity above) |
@@ -177,6 +177,7 @@ Options:
177
177
  | `--fasta-dedupe` | FASTA duplicate handling: `none` or `most-seq` |
178
178
  | `--processes`, `-p` | Number of worker processes (see Compression above — plain gzip always runs single-process) |
179
179
  | `--mode`, `-m` | Fetch mode: `block` or `scaffold` |
180
+ | `--scaffold-subdirs` | Group output files into subfolders named by reference scaffold (`<output>/<scaffold>/<basename>`) instead of one flat directory |
180
181
  | `--verbose` | Emit warning lines from each completed batch |
181
182
  | `--profile` | Log internal timing breakdowns |
182
183
  | `--verify-hash` | Verify the index's stored content hash against the MAF file (see Index Integrity above) |
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.1'
22
- __version_tuple__ = version_tuple = (0, 2, 1)
21
+ __version__ = version = '0.3.0'
22
+ __version_tuple__ = version_tuple = (0, 3, 0)
23
23
 
24
- __commit_id__ = commit_id = 'g5c611ce9e'
24
+ __commit_id__ = commit_id = 'g694487dcd'
@@ -90,6 +90,7 @@ WORKER_MAF_COMPRESSION = None
90
90
  WORKER_INDEX = None
91
91
  WORKER_OUTPUT = None
92
92
  WORKER_SINGLE_OUTPUT = None
93
+ WORKER_SCAFFOLD_SUBDIRS = None
93
94
  WORKER_AS_FASTA = None
94
95
  WORKER_FASTA_HEADER = None
95
96
  WORKER_EXPECTED_SPECIES = None
@@ -174,6 +175,7 @@ def initBatchWorker(
174
175
  verbose,
175
176
  profile,
176
177
  prefetched_cache=None,
178
+ scaffold_subdirs=False,
177
179
  ):
178
180
  global WORKER_HEADER
179
181
  global WORKER_MAF_FILE
@@ -181,6 +183,7 @@ def initBatchWorker(
181
183
  global WORKER_INDEX
182
184
  global WORKER_OUTPUT
183
185
  global WORKER_SINGLE_OUTPUT
186
+ global WORKER_SCAFFOLD_SUBDIRS
184
187
  global WORKER_AS_FASTA
185
188
  global WORKER_FASTA_HEADER
186
189
  global WORKER_EXPECTED_SPECIES
@@ -196,6 +199,7 @@ def initBatchWorker(
196
199
  WORKER_INDEX = index
197
200
  WORKER_OUTPUT = output
198
201
  WORKER_SINGLE_OUTPUT = single_output
202
+ WORKER_SCAFFOLD_SUBDIRS = scaffold_subdirs
199
203
  WORKER_AS_FASTA = as_fasta
200
204
  WORKER_FASTA_HEADER = fasta_header
201
205
  WORKER_EXPECTED_SPECIES = expected_species
@@ -714,6 +718,20 @@ def trimMafBlock(block_text, bed_start, bed_end, BATCHLOG, verbose=False, warnin
714
718
 
715
719
  #############################################################################
716
720
 
721
+ def buildOutputPath(output_dir, scaffold, out_basename, ext, scaffold_subdirs):
722
+ """
723
+ Shared per-output-file path builder for block mode (fetchByRegion) and
724
+ scaffold mode (fetchByScaffold/fetchScaffoldsSequential). The scaffold
725
+ subdirectory itself is never created here -- callers must pre-create
726
+ every needed one upfront (see run_fetch) before any of these paths are
727
+ actually opened for writing.
728
+ """
729
+ if scaffold_subdirs:
730
+ return os.path.join(output_dir, scaffold, out_basename + ext)
731
+ return os.path.join(output_dir, out_basename + ext)
732
+
733
+ #############################################################################
734
+
717
735
  def fetchByRegion(
718
736
  region,
719
737
  header,
@@ -729,6 +747,7 @@ def fetchByRegion(
729
747
  verbose=False,
730
748
  warning_state=None,
731
749
  profile_state=None,
750
+ scaffold_subdirs=False,
732
751
  ):
733
752
  """
734
753
  Worker function to process a single BED region:
@@ -760,7 +779,7 @@ def fetchByRegion(
760
779
  fill_cache = {}
761
780
  # For fasta output, hold sequences per species
762
781
 
763
- output_filename = os.path.join(output, out_basename + (".fa" if as_fasta else ".maf"))
782
+ output_filename = buildOutputPath(output, scaffold, out_basename, ".fa" if as_fasta else ".maf", scaffold_subdirs)
764
783
  out_stream = None
765
784
 
766
785
  if single_output:
@@ -997,6 +1016,7 @@ def fetchByBatch(
997
1016
  verbose=WORKER_VERBOSE,
998
1017
  warning_state=warning_state,
999
1018
  profile_state=profile_state,
1019
+ scaffold_subdirs=WORKER_SCAFFOLD_SUBDIRS,
1000
1020
  )
1001
1021
  batch_results[result_idx] = region_result
1002
1022
  if not WORKER_SINGLE_OUTPUT:
@@ -1027,13 +1047,13 @@ def fetchByBatch(
1027
1047
 
1028
1048
  #############################################################################
1029
1049
 
1030
- def fetchByScaffold(scaffold, start_end, maf_file, maf_header, maf_compression, out_dir, LOG):
1050
+ def fetchByScaffold(scaffold, start_end, maf_file, maf_header, maf_compression, out_dir, LOG, scaffold_subdirs=False):
1031
1051
  """
1032
1052
  Worker function to extract one scaffold from the MAF file.
1033
1053
  start_end is a tuple (start_byte, end_byte).
1034
1054
  """
1035
1055
  start, end = start_end
1036
- output_path = os.path.join(out_dir, f"{scaffold}.maf")
1056
+ output_path = buildOutputPath(out_dir, scaffold, scaffold, ".maf", scaffold_subdirs)
1037
1057
 
1038
1058
  try:
1039
1059
  with COMMON.openMaf(maf_file, maf_compression, "rb") as mfp, open(output_path, "wb") as outfp:
@@ -1047,7 +1067,7 @@ def fetchByScaffold(scaffold, start_end, maf_file, maf_header, maf_compression,
1047
1067
  return f"{output_path}: Wrote {scaffold}";
1048
1068
 
1049
1069
 
1050
- def fetchScaffoldsSequential(ordered_scaffolds, index, maf_file, maf_header, maf_compression, out_dir, LOG):
1070
+ def fetchScaffoldsSequential(ordered_scaffolds, index, maf_file, maf_header, maf_compression, out_dir, LOG, scaffold_subdirs=False):
1051
1071
  """
1052
1072
  Extracts multiple scaffolds using a single open MAF handle, in the given
1053
1073
  (ascending file-offset) order. Used for gzip input: reusing one handle
@@ -1058,7 +1078,7 @@ def fetchScaffoldsSequential(ordered_scaffolds, index, maf_file, maf_header, maf
1058
1078
  with COMMON.openMaf(maf_file, maf_compression, "rb") as mfp:
1059
1079
  for scaffold in ordered_scaffolds:
1060
1080
  start, end = index[scaffold]
1061
- output_path = os.path.join(out_dir, f"{scaffold}.maf")
1081
+ output_path = buildOutputPath(out_dir, scaffold, scaffold, ".maf", scaffold_subdirs)
1062
1082
  try:
1063
1083
  LOG.info(f">>> Scaffold {scaffold}");
1064
1084
  data = COMMON.readMafBlockBytes(mfp, maf_compression, start, end)
@@ -1101,6 +1121,13 @@ def run_fetch(args, cmdline="mafutils fetch"):
1101
1121
  LOG.error(f"Invalid mode: '{args.mode}'. Must be 'block' or 'scaffold'.")
1102
1122
  sys.exit(1)
1103
1123
  # Validate mode
1124
+
1125
+ if args.scaffold_subdirs and args.single_output:
1126
+ LOG.error("--scaffold-subdirs cannot be used with --single-output.")
1127
+ sys.exit(1)
1128
+ # --single-output collects blocks into one combined file and never uses
1129
+ # per-region output_basename/output_filename at all, so it doesn't
1130
+ # compose with grouping per-region files into scaffold subfolders.
1104
1131
  # if args.max_no_overlap_regions < -1:
1105
1132
  # LOG.error("--max-no-overlap-regions must be >= -1.")
1106
1133
  # sys.exit(1)
@@ -1171,6 +1198,12 @@ def run_fetch(args, cmdline="mafutils fetch"):
1171
1198
  sys.exit(1)
1172
1199
  LOG.info(f"Extracting {len(scaffold_set)} scaffolds from scaffold index: {scaffold_set}");
1173
1200
 
1201
+ if args.scaffold_subdirs:
1202
+ # Pre-create upfront in the main process, same rationale as
1203
+ # block mode below -- avoids any per-worker/cross-process race.
1204
+ for scaffold in scaffold_set:
1205
+ os.makedirs(os.path.join(args.output, scaffold), exist_ok=True)
1206
+
1174
1207
  # Process scaffolds in ascending file-offset order; for gzip this is
1175
1208
  # what lets a single reused handle avoid ever seeking backward.
1176
1209
  ordered_scaffolds = sorted(scaffold_set, key=lambda s: index[s][0])
@@ -1182,7 +1215,7 @@ def run_fetch(args, cmdline="mafutils fetch"):
1182
1215
  "gzip-compressed files; --processes will be ignored. (Use a bgzip-compressed MAF "
1183
1216
  "for real parallel speedup on compressed input.)"
1184
1217
  )
1185
- for result in fetchScaffoldsSequential(ordered_scaffolds, index, args.maf_file, maf_header, maf_compression, args.output, LOG):
1218
+ for result in fetchScaffoldsSequential(ordered_scaffolds, index, args.maf_file, maf_header, maf_compression, args.output, LOG, scaffold_subdirs=args.scaffold_subdirs):
1186
1219
  LOG.info(result)
1187
1220
  else:
1188
1221
  # Extract from MAF using the region index for matching scaffolds
@@ -1198,7 +1231,8 @@ def run_fetch(args, cmdline="mafutils fetch"):
1198
1231
  maf_header,
1199
1232
  maf_compression,
1200
1233
  args.output,
1201
- LOG
1234
+ LOG,
1235
+ args.scaffold_subdirs,
1202
1236
  ))
1203
1237
  for future in futures:
1204
1238
  result = future.result()
@@ -1273,6 +1307,15 @@ def run_fetch(args, cmdline="mafutils fetch"):
1273
1307
  else: # basename_mode == "coords":
1274
1308
  region["output_basename"] = f"{scaffold}-{start}-{end}"
1275
1309
 
1310
+ if args.scaffold_subdirs:
1311
+ # Pre-create every needed scaffold subdirectory upfront, in the main
1312
+ # process, mirroring the single os.makedirs(args.output, ...) above --
1313
+ # block-mode writes happen inside ProcessPoolExecutor workers, and
1314
+ # nothing per-worker creates directories today, so doing this here
1315
+ # avoids needing any cross-process race handling at write time.
1316
+ for scaffold in {region["scaffold"] for region in regions}:
1317
+ os.makedirs(os.path.join(args.output, scaffold), exist_ok=True)
1318
+
1276
1319
  info_outfile = os.path.join(args.output, "maf_fetch_summary.tsv")
1277
1320
 
1278
1321
  # if args.fasta_header and not args.fasta:
@@ -1303,6 +1346,7 @@ def run_fetch(args, cmdline="mafutils fetch"):
1303
1346
  args.verbose,
1304
1347
  args.profile,
1305
1348
  prefetch_cache,
1349
+ args.scaffold_subdirs,
1306
1350
  ),
1307
1351
  ) as executor, open(info_outfile, "w") as info_out:
1308
1352
  summary_headers = ["scaffold", "start", "end", "basename", "n.overlapping.blocks", "block.lengths", "interblock.distances", "n.sequences"]
@@ -1462,6 +1506,7 @@ def fetch_command(
1462
1506
  fasta_dedupe: Annotated[FastaDedupeMode, typer.Option("--fasta-dedupe", help="When outputting FASTA, collapse duplicate species per block; 'most-seq' keeps the copy with most non-gap bases.")] = FastaDedupeMode.none,
1463
1507
  processes: Annotated[int, typer.Option("--processes", "-p", help="Number of parallel processes to use (default: 1)")] = 1,
1464
1508
  mode: Annotated[FetchMode, typer.Option("--mode", "-m", help="Mode: 'block' to trim by regions, 'scaffold' to extract whole scaffolds (default: block)")] = FetchMode.block,
1509
+ scaffold_subdirs: Annotated[bool, typer.Option("--scaffold-subdirs", help="Group output files into subfolders named by reference scaffold (<output>/<scaffold>/<basename>) instead of one flat directory.")] = False,
1465
1510
  single_output: Annotated[bool, typer.Option("--single-output", hidden=True)] = False,
1466
1511
  verbose: Annotated[bool, typer.Option("--verbose", help="Print every warning line after each batch completes.")] = False,
1467
1512
  profile: Annotated[bool, typer.Option("--profile", help="Log aggregate timing breakdowns for internal fetch steps.")] = False,
@@ -1480,6 +1525,7 @@ def fetch_command(
1480
1525
  fasta_dedupe=fasta_dedupe.value,
1481
1526
  processes=processes,
1482
1527
  mode=mode.value,
1528
+ scaffold_subdirs=scaffold_subdirs,
1483
1529
  single_output=single_output,
1484
1530
  verbose=verbose,
1485
1531
  profile=profile,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mafutils
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Utilities for indexing, fetching, and summarizing MAFs.
5
5
  Author: Gregg Thomas
6
6
  License: MIT License
@@ -214,6 +214,7 @@ Options:
214
214
  | `--fasta-dedupe` | FASTA duplicate handling: `none` or `most-seq` |
215
215
  | `--processes`, `-p` | Number of worker processes (see Compression above — plain gzip always runs single-process) |
216
216
  | `--mode`, `-m` | Fetch mode: `block` or `scaffold` |
217
+ | `--scaffold-subdirs` | Group output files into subfolders named by reference scaffold (`<output>/<scaffold>/<basename>`) instead of one flat directory |
217
218
  | `--verbose` | Emit warning lines from each completed batch |
218
219
  | `--profile` | Log internal timing breakdowns |
219
220
  | `--verify-hash` | Verify the index's stored content hash against the MAF file (see Index Integrity above) |
@@ -7,6 +7,7 @@ README.md
7
7
  THIRD_PARTY_LICENSES.md
8
8
  pyproject.toml
9
9
  .github/workflows/publish-pypi.yml
10
+ .github/workflows/tests.yml
10
11
  benchmarks/README.md
11
12
  benchmarks/Snakefile
12
13
  benchmarks/baseline-manual-timings.txt
@@ -53,9 +54,14 @@ tests/example.maf.gz.block.idx
53
54
  tests/example.maf.gz.scaffold.idx
54
55
  tests/example.maf.scaffold.idx
55
56
  tests/example.maf.scaffold.regenerated.idx
57
+ tests/real-excerpt.maf
58
+ tests/real-excerpt.maf.block.idx
59
+ tests/real-excerpt.maf.scaffold.idx
56
60
  tests/test_compression.py
57
61
  tests/test_fetch.py
58
62
  tests/test_gc.py
63
+ tests/test_real_data.py
64
+ tests/test_stats.py
59
65
  tests/test_validate.py
60
66
  tests/expected-fasta/01-singleblock-gap.fa
61
67
  tests/expected-fasta/02-truncatedblock.fa
@@ -17,6 +17,7 @@
17
17
  "benchmarks/notebook.ipynb",
18
18
  "benchmarks/config.yaml",
19
19
  "benchmarks/profiles/slurm/config.yaml",
20
+ ".github/workflows/tests.yml",
20
21
  ".github/workflows/publish-pypi.yml",
21
22
  "mafutils/validate.py",
22
23
  "mafutils/fetch.py",
@@ -30,9 +31,13 @@
30
31
  "mafutils/lib/loginit.py",
31
32
  "mafutils/lib/common.py",
32
33
  "mafutils/lib/__init__.py",
34
+ "tests/real-excerpt.maf.scaffold.idx",
35
+ "tests/test_stats.py",
33
36
  "tests/example.maf.gz",
34
37
  "tests/example.maf.bgz",
38
+ "tests/real-excerpt.maf",
35
39
  "tests/test_compression.py",
40
+ "tests/real-excerpt.maf.block.idx",
36
41
  "tests/test_validate.py",
37
42
  "tests/example.maf.block.idx",
38
43
  "tests/example.maf.gz.scaffold.idx",
@@ -40,6 +45,7 @@
40
45
  "tests/example-tabs.maf.block.idx",
41
46
  "tests/test_gc.py",
42
47
  "tests/example-tabs.maf.scaffold.idx",
48
+ "tests/test_real_data.py",
43
49
  "tests/test_fetch.py",
44
50
  "tests/crossblocks.bed",
45
51
  "tests/example-tabs.maf",
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.2.1",
2
+ "tag": "0.3.0",
3
3
  "distance": 0,
4
- "node": "g5c611ce9e5d735e4f0eec333e1c8b906eb815005",
4
+ "node": "g694487dcd86f14f29285ea1b51261b03fe3cc45d",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-07-21"
@@ -0,0 +1,131 @@
1
+ ##maf version=1
2
+
3
+ a
4
+ s Mus_musculus.CM000994.3 125888838 82 + 195154279 TCC-ATCTACTCAAACCTAATTCTTTACGATTCACTGAAGAAATCCCCTCCAGGAAGAAATCCTGATC-TTTGATTCTTCTTTC
5
+ s Phodopus_campbelli.chr12 18452278 5 - 32442325 T----------------------------------------------------------------------------TCCA---
6
+ s Phodopus_sungorus_new.chr12 17334137 5 - 31225933 T----------------------------------------------------------------------------TCCA---
7
+ s Phodopus_roborovskii.JAEOAF010000031.1 16485673 8 + 29770300 T----------------------------------------------------------------------------TACATCT
8
+ s Cricetus_cricetus.OZ199631.1 140166140 8 - 205530201 T----------------------------------------------------------------------------TTTTTTT
9
+ s Dicrostonyx_torquatus.JAQHUG010000071.1 6038229 4 - 8539717 A----------------------------------------------------------------------------TTT----
10
+ s Arvicola_amphibius.NC_052058.2 72668393 4 - 166747489 A----------------------------------------------------------------------------CTT----
11
+ s Microtus_pennsylvanicus.CM073176.1 20976023 4 + 113485825 A----------------------------------------------------------------------------cct----
12
+ s Microtus_arvalis.JAHRII010002323.1 111060626 4 + 200229077 A----------------------------------------------------------------------------CTT----
13
+ s Neotoma_floridana.CM113793.1 27921528 83 - 95303938 TCC-ATCTTCTCAAACCTAATACTTCAAGATTCACCTAAGAAATCACCTCCAGGAAGAAACCCTGATTACTTAATTCCTTTTTC
14
+ s Onychomys_torridus.LR877198.1 72220278 83 + 93020901 CCC-ACCTACTCAAACCTAATTCTTCAAGATTCATCTAAGAAATTATCTCTAGGAAGAAACTCTGATTACTTAATTCCTTTTTC
15
+ s Peromyscus_californicus.VALE03000237.1 12778336 84 + 80346014 TCCCATCTACTCAAACCTAATTCTTCAAGATTCACCTAAGAAATTACCTCCAGGAAGAAACCCTGATTACTTAATTCCTTTTTC
16
+ s Peromyscus_maniculatus_North.CM113205.1 35699024 84 + 104458120 TCCCATCTACTCAAACCTAATTCTTCAAGATTCACCTAAGAAATTACCTCCAGGAAGAAACCCTGATTACTTAATTCCTTTTTC
17
+
18
+
19
+ a
20
+ s Mus_musculus.CM000994.3 125888920 187 + 195154279 TTGGGAATCAAGTTGAGTGCTCAGTTTCAGTAGATACAGACAACCC-CCA---CC---C----AGCC--TTGTACTCAATATTCCATAATTGTGTCATATTTGTACTGTGTTTGGGATCTATTGT-----------CTTCCTA-GGACAATCGGAAGGGACAAAAGAAGGTAATAGCAACAAGGTCACCATCAGC----------T-CTCAGATCTCAGAGGA
21
+ s Phodopus_campbelli.chr12 18452286 180 - 32442325 TAAAGGA-------------------CCAGTGGTCACAGACAATCCTCCC---CC---CCAACACCCTTTTTTAGTCAATAGTCCATAA-------ACCTGTGTTCTATTCTTGGAATCCAATGGGAAATATCATACTTCCT-GGGACAACCAGAACTGGAAGAGGAGGATAATAGCAATG---TCACC------ATCAGCA-AAATCTTAAGTGCTGCGGGA
22
+ s Phodopus_sungorus_new.chr12 17334145 152 - 31225933 TAAAGGA-------------------CCAGTGGTCACAGACAATCCTCCA---CC---CCAACAGCCTTTTTTAGTCAATAGTCCATAA-------ACCTGTGTCCTATTCTTGGAATCCAATGTGAAATATCATACTTC-T-GGGACAACCAGAACTGGAAGAGTTGGATAATAGCAATG---TCACC----------------------------------
23
+ s Phodopus_roborovskii.JAEOAF010000031.1 16485768 182 + 29770300 TAAAGGA-------------------CCAGTGTTAACAGACAATCCTTTC---CTCCACCAACAGCC--TTTTAGTCAATATCCCATAA-------ACATTTGCCCTATACTTGGAATCCAATGTGAAAAATCATACTCCCT-GGAACAACCAGAGCAGGCAGAGTTGGATAATAGCAATG---TCACC------ATCAGCAGAAAACTTAAGTGCTGTGGGA
24
+ s Cricetus_cricetus.OZ199631.1 140166148 180 - 205530201 TAAAGGA-------------------TCAGTGATCACAGACAATCC-CCATGCCT---CCAGTAGCC--TTTTAGTCAATATTCCATAA-------GCATTCATCCTGTAGTTGGAATCCAATATGAAATATCATACTTCCT--GGACAACCAGAATGGGCAGAGTAGGATAATAGTAACA---TCACC------ACCAGCAGAAAACTTAAGTGTTATGGGA
25
+ s Neotoma_floridana.CM113793.1 27921611 174 - 95303938 TTAAGGA-------------------TCAGTGGTTCCAGACAATCCCCCA---CA---C----AGCC--TT-TAGTCAATATTCCATAA-------ACATTTGTCCTGTACTTGGAATCCAATATGAAATATCATACTTCCTG-GGATGACCAGAATGGTCAGAGGAAGATAATAGCAACA---TCACCATCAGC------AGAAAACTTAAGTGTTATGGGA
26
+ s Onychomys_torridus.LR877198.1 72220361 175 + 93020901 TTAAGGA-------------------TCAGTGGTCACAGACAATCCTCCA---CA---C----AGCCT-TT-TAGCCAATATCCCATAA-------ACATTTGTCCTGTACTGGGAACCTAATATGAAATATCATACTTCCTG-GGACAACCAGAATGGTCAGAGGAAGATAATAGCAGCA---TCACCATCAGC------AGAAAACTTAAAAGTTATGGGA
27
+ s Peromyscus_californicus.VALE03000237.1 12778420 175 + 80346014 TTAAGGA-------------------TCAGTGGTCACAGACAATCCTCCA---CA---C----AGCCT-TT-TAGCCAATATTCCATAA-------ACATTTGTCCTGTACTTGGAATCTAATATGAAATATCATCCTTCCTG-GGACAACCAGAATGGTCAGAGGAAGATAACAGCCACA---TCACCATCAGC------AGAAAACTTAAATGTTATGGGA
28
+ s Peromyscus_maniculatus_North.CM113205.1 35699108 175 + 104458120 TTAAGCA-------------------TCAGTGGTCACAGACAATCCTCCA---CA---C----AGCCT-TT-TAGCCAATATTCCATAA-------ACATTTGTCCTGTACTTGGAATCTAATATGAAATATCATCCTTCCTG-GGACAACCAGAATGGTCAGAGGAAGATAACAGCCACA---TCACCATCAGC------AGAAAACTTAAATGTTATGGGA
29
+
30
+
31
+ a
32
+ s Mus_musculus.CM000994.3 125889107 10 + 195154279 G---------------------GGGCATCTG
33
+ s Phodopus_campbelli.chr12 18452505 18 - 32442325 TT-------------TTGCAATGAtcatctc
34
+ s Phodopus_sungorus_new.chr12 17334315 18 - 31225933 TT-------------TTGCAATGATCATCTC
35
+ s Phodopus_roborovskii.JAEOAF010000031.1 16485989 18 + 29770300 TT-------------CTGCAATGATCATCTT
36
+ s Cricetus_cricetus.OZ199631.1 140166328 31 - 205530201 TTCTAGAAGAGGGGCTTGTAATGATCATCTG
37
+ s Neotoma_floridana.CM113793.1 27921822 18 - 95303938 TT-------------TTGCAATGATCATCTC
38
+ s Onychomys_torridus.LR877198.1 72220576 18 + 93020901 TT-------------TTGCAATGAACATCTC
39
+ s Peromyscus_californicus.VALE03000237.1 12778635 18 + 80346014 TT-------------TTGCAATGATCATCTC
40
+ s Peromyscus_maniculatus_North.CM113205.1 35699323 18 + 104458120 TT-------------TTGCAATGACCATCTC
41
+
42
+
43
+ a
44
+ s Mus_musculus.CM000994.3 125889117 440 + 195154279 CATGTCTGACAAAGCACTTGCT---TG---ACACAGGACAATAAAATTCTGTCATGAACTATCATGAAGT-ATGTGACAGGATGACAAAGCATGGGTGAAAAGGAAGTTG---TGTCACATTTGGGTGGCACTT-ATATGCTTCTGGTAATGATGGTGGC----------TCTT--TAAAGTTTCTTATGACTTCTTTGTAACTAGCGAGTAAGCTCTGTGGGCA--------TTGCAGGCTATCACCTTCCTCTTCATAACAGCACTGA-AGTTCATGTCtgtgaggctcaatctctgttgtcaaccagatggcattaagtctgtccatgaaaacagacctctgggg----------atgtctgtgatagaggttaggctatttaaagttgaaagacccaccctaa-tctgagtggtaccagttcatgggctggggttctag-act---gaaagaaagagagaaaggaagctgagccctagcctta
45
+ s Phodopus_campbelli.chr12 18452900 426 - 32442325 CA----------TGTACTTTCT---T----AC--AGGACAATAAAATCCTAGCATGGGCTATCATGAAGTTATGTGACAAGACGGTAAGGCATGGATGGAAAGGAGCCCATGTC---ATGTTCAGG-GGCACTT-ACATGCTGCTGGCA---------GTGATCGTTGAGTCTTTATAAAGTTTCTTGTGTTTTCTCTGTAACTAGCCTGTAAGCTCTGTGGGCAGGGATGCATTGCATGCTGTCCCCTCCCTACTCCAAACAGCACTAA-GCTTCATGTCTGTACGGCTTAATCGTGACTGTCAACCAGATGGGACAAAGTCTGTCTATGAAAACAA--------------------ATGTCTGTGAGGGATATCAGGCtaactgaggttggaagacccactctaaAtctgagtggcaccaatctatgggcttgtgagct-gGaat---aagcaaggagaa---agtaagctgagccccagcattc
46
+ s Phodopus_sungorus_new.chr12 17334333 426 - 31225933 CA----------AGTACTTACT---T----AC--AGGACAATAAAATCCTAGCATGGGCTATCATGAAGTTATGTGACATGACGATAAGGCATGGATGGAAAGGAGCCCATGTC---ATGTTCAGG-GGCACTT-ACATGCTGCTGGCA---------GTGATCGTTGAGTCTTTATAAAGTTTCTTGTGTTTTCTCTGTAACTAGCCTGTAAGCTCTGTGGGCAGAGATGCATTGCATGCTGTCCCCTTCCTACTCCAAACAGCACCAA-GCTTCATGTCTGTACGGCTTAATCGTGACTGTCAACCAGATGGGACAAAGTCTGTCTATGAAAACAA--------------------ATGTCTGTGAGGGACATCAGGCTAACTGAGGTTTGAAGACACACTCTAAATTTGAGTGGCACCAATCTATGGGCttgtgagct-gGaat---aagcaaggagaa---agtgagctgagccccagcattc
47
+ s Phodopus_roborovskii.JAEOAF010000031.1 16486007 437 + 29770300 CA----------AGTACTTACTTGAT----AC--AGGACAATAAAATCCTAGCATAGGCTATCATGAAGTTATGTGACAAGATGATAAAGCATGGGTGGAAAGGAG-CCATGTC---ATGTTCAGG-GGCATTT-ACATGCTGTTGGCA---------GTGATCGTTGAGTCTTTATAACGTTTCCTGTGTTTTCTCTGTAACTAGCCTGTAAGCTCTGTGGGCAGGAATCCATTGCATGCTGTCTCCTTCCTACTCCCAACAGCACCAA-GCTTCATGTCtgtaaggcttcatcgtgactgtcaaccagatggaataaagtctgtctatgaaaacaa----------ATATCTGGGGatgtctgtgagggacatcgggctaactgaggttggaagacccactctaaAtctaagtgacaccaatct-tgggcttgtgagct-gGaat---aaacaaggagaa---agtgagctgagccccagcattc
48
+ s Cricetus_cricetus.OZ199631.1 140166359 437 - 205530201 CA----------AGTACTTACT---T-GACAC--AGGACAATAAAATCCTAGCATGGACTATCATCCAGTTATGTGACAAGATGATAAGGTATGGGTGGAAAGGAACCCAAGTC---ATTTTCGGG-GACACTTAACATGCTATTGGTA---------GTGATTG-TGAGTCTT--TAAAGTTTCTCATGCCTTCTCTGTAACTAGCCTGTAAGCTCTGTGGGCAGGACTGCATTGCATGCTGTCTCCCTCCTACTCCTAACAGCACCAA-GCTTCCTGTCtgtgaggcttaatcatgactgtcaaccagacgggataaagtctgcctatgaaaacaa----------ATGTCTGGGCatgtctgtgagggacatcatgctaattgaggttggaaggcccaccctaaAtctgagtgacaccaatccatgtgctggtgtgct-gGaat---gaacaaagagga---agtgagctgagatccagcattc
49
+ s Cricetulus_griseus.NC_048598.1 130954973 1 - 193770019 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------c
50
+ s Dicrostonyx_torquatus.JAQHUG010000071.1 6038233 79 - 8539717 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------CTCTAAGCCTGAGTTAcaccaatccatgggctggtgtgct-aGaat---gaa---acaggagaaagtgagctgagctccagcattc
51
+ s Arvicola_amphibius.NC_052058.2 72668397 79 - 166747489 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ctctaaAcccgagttacaccaatccatgggctggtgtgct-gGaat---gag---aaaggagaaagtgagctgagccccagcagtc
52
+ s Microtus_pennsylvanicus.CM073176.1 20976027 78 + 113485825 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ccctaaAcctgagttacaccaatccatgagttggtgtgct-gGaat---gag---aa-ggagaaagtgagctgagccccagcatgc
53
+ s Microtus_arvalis.JAHRII010002323.1 111060630 76 + 200229077 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ctctaaAcctgagttacatcaatccatggactg---tgcc-gAaat---gag---aaaggagaaagtgagctgagccccagcatgc
54
+ s Neotoma_floridana.CM113793.1 27921840 432 - 95303938 CA----------AGCACTTACT---T----ACATAGGACAATCAAATCCTATCATGGACTATCATGAAGTTATATGACAAGATGATAAGGCATGGATGGAAAAGAGTCTGCATC---ATATTTTGG-GGCACTC-ACATGCTGCTGGTA---------GC----------TCTT--TAAATTTTCTTGTGTCTTCTCTGTAACTAGCCTGTAAGCTCTGTGGGCAGGACTGCATTGCATGCTGTCTCCTTCCTATTCCCAATAGCACCAA-GCTTCATGTCtgtgaggcttaatcttgactgtcatccagatgagataaagtctgtctgtgaaaacaaacgtctgggg----------atgcctgtgagggagatcaggctaatggaggatgggagacccgccctaaAtctgaagggcaccaatccatgggctgctctgct-gGaatATAgagaaaaaaccagaaagtgagctgagtcccagcattc
55
+ s Onychomys_torridus.LR877198.1 72220594 423 + 93020901 CA----------AGTACTTACT---T-G--ACATAGGACAATAAAATCCTATCATGGACTATCATGAAGTTATGTGACAAGATGATAAGGCATGGGTGGAAAGGAGT--G---T---ATATTTTGG-GGCCCT--AAATGCTGCTGGTA---------GC----------TCTT--TAAATTTCCTTGTGTCTTCTCTGTAACTAGCCTGTAAGCTCTGTCCTCAGGGCTGCCCTGCGTGCTGTCTCCTTCCTGCTCTCAAGGGCACCAA-GCTTCAGGTCtgtgaggcttaatcttgactgtcaacaagaagggataaagtctgtctatgcaaacaaacatctgggg----------atggctgtgagggagatcaggctaatggaggttggaggacctgccctaaAtctgagtggcaccattctatgggctggtgagct-gGaat---gaacaaaaaa-aggaagggagctgagccccagcattc
56
+ s Peromyscus_californicus.VALE03000237.1 12778653 427 + 80346014 CA----------AGTACTTACT---T-G--ACATAGGACAATAAAATCTTGTCATGGACTATCATGAAGTTATATGACAAGATGATAAGGCATGGATAGAAAGGAGTCTG---T---ATATTTTGG-GGCCCTT-ATATGCTGCTGGTA---------GC----------TCTT--TAAATTTCCT-GTGTCTTCTCTATAACTCGCCTGTAAGCTCTGTGGGCAGGCCTACATTACGTGCTGTCTCCTTCCTGCTCCCAAAAGCACCAAAGCTTCATGTCTGtgaggcttaatcttgactgtcaaccagaagggataaagtctgtctatgaaaacaaatgtctgagg----------atgtctgtgagggagatcaggctaatggaggttggaaggcctgccctaaAtctgagcggcaccattccatgggctggtgagct-gGaat---aaacaaaaaggagaaagtgagctgggtcccagtattc
57
+ s Peromyscus_maniculatus_North.CM113205.1 35699341 427 + 104458120 CA----------AGTACTTACT---T-G--ACATAGGACAATAAAATCCTATCATGGACTATCATGAAGTTATGTGACAAGGTGATAAGGCATGGATGGAAAGGAGTCTG---T---ATGTTTTGG-GGCCCTT-ACATGCTGCTGGTA---------GC----------TCTT--TCAATTTCCTTGTGTCTTCTCTGTCACTCGCCTGGAAGCTCTGTGAGCAGGGCTGCATTACGTGCTGTCTCCTTCCTGCTCCCCAAAGCACCGAACCTTCATGTCtgtgaggcttaatcttgactgtcaaccagaagggataaagtccgtctatgaaaacaaatgtctgagg----------atgtctgagagggagatcaggctaatggaggttggaaggcctgccctacAtctaagcggcaccactccatgggctggtgagct-g-aat---gaacaaaaaggagaaagtgagctgagtcccagtattc
58
+
59
+
60
+ a
61
+ s Mus_musculus.CM000994.3 125889557 280 + 195154279 gtt-ctgcctgcttcctgactgtggatgccaagtgaccagctgtctctcatgctggctgccatgccttcttcaggatgaactgtgtccctccagac--atgtgagt---------------------gcaaaac------------accctccctccctccct-ccctccctccctctcccttccttctttaggatgcttttcttag---c--ttttgttacagtattcagaaaagtgacAATTCATAGAGAGTCTTCAACAGGTCCTCACCAAGCA-----CTTATGGAATCATAGCAGGC------------T-AA-A-----------TG----GGCTAAAAATCCTCCTCCT
62
+ s Rattus_norvegicus.CM070403.1 39970935 170 + 109350286 -----------------------------------------------------------------------------------------------------------------------------------------------------ctcccttcctctttAttttccctccc---cccttcttcccttaggttgctttccttag---cCAttttgtcacagtaaccagaaaagtgacAACTCAC--AGAGTCTCCAACAGATCCTCACCAAGCG-----CCCATGGAATCACAGCAGGCAGAGGAGTCACTT-AA-A-----------AG----GGCTAAAAATCC-------
63
+ s Phodopus_campbelli.chr12 18453724 270 - 32442325 acaGctccctgcttcctggctgcggatggcatgtgaccagcttcctcctgttcttgctgccatgccctcctcatgatggactgtattcctttggaaCTctg--agtAAAGCAACAACCACAACAACAacaacaa------------g--c-----------------------------TCTTTGTCCTTTAAGTTGCTGA--GTCA-GCA--CTTTGTCCCTGTACTCAGAAAAGGGACA-TTCATAGTGAGTCTCCTTCGGGTCCTCACCAGGCA-----CACA--GGATTGTGGCGGGCAGGGGATTCACTT-AG-CT----------CC----TCCT-----CCG-------
64
+ s Phodopus_sungorus_new.chr12 17335144 282 - 31225933 acaGctccctgcttcctggctgcggatggcatgtgaccagcttcctcctgttcttgctgccatgccctcctcatgatggactgtatccctttggaaCTctg--agtAAAGCAACAACAACAACAACAacaacaaCAACAACAACAAg--c-----------------------------tctttgtcccttaagttgctta--gtCA-GTA--CTTTGTCACTGTACTCAGAAAAGGGACA-TTCATAGTGAGTCTCCTTCGGGTCCTCACCAGGCA-----CACA--GGATTGTGGCGGGCAGAGGATTCACTT-AA-CT----------CC----TCCT-----CCG-------
65
+ s Phodopus_roborovskii.JAEOAF010000031.1 16486444 261 + 29770300 attGctctctgcttcctggctgtggatggcccgtgaccagcttcc-cccattcttgctgccgtgtcctcctcctgatggactctatcactttggaa--ctg--agtAAAACAACAA-------CAAA-----aa------------g--c-----------------------------tctttgttccttaagttgcttt--gtca-GTa--ttttgtcactgtactcagaaaAGGGGCAGTTCATAGTGAGTCTCCTTCAGGTCCTCATCAGGTCCTCATCACA--GAATTGTGGCAGGTAGAGGATTCACTT-AA-AT----------CC----TCCT-----CCT-------
66
+ s Cricetus_cricetus.OZ199631.1 140166796 266 - 205530201 attGctctctgcttcctgattgtggatgccatgtgaccacctgcctcctattcttgctgctatgcctttcccatgatggactgtatccttttggaa--ctgtgatgT---AAAAAACA--AAGCAAAacaaaac------------a--c-----------------------------acttggtttcttaagttgcttt--gtga-GTa--gtttgtcactgtaatcagaaaagGGAGAGTTCATAGTGAGTCTCCGACAGGTCCTCACCAAGCA-----CACA--GAGCGGGGGCAGGGAGAGGATTCACTT-AA-AA----------CC----TCCT-----CCT-------
67
+ s Cricetulus_griseus.NC_048598.1 130954974 265 - 193770019 attGctctctgcttcctgactgtggatgccatgtgaccacctgcctcctattcttgctgccatgcctttcccatgatggactgtatccctttggaa--ctgtgaggTAAAAAC----A--AAACAAAacaaaac------------a--c-----------------------------actttgtttcttaagttgcatt--gtga-GTa--ttttgttactgtaatcagaaaagGGACAGTTCATAGTGAGTCTCCGACAGGTCCTCACCAAGCA-----CACA--GAGTGGTGGCAGGTAGAGGATTCACTT-AA-AA----------CC----TCCT-----CCT-------
68
+ s Dicrostonyx_torquatus.JAQHUG010000071.1 6038312 259 - 8539717 actGctctctgcttcctgactgtgg-tgccatgtgactagccagctcctactcttgctgctgtgccttccccatgacaaactgtgtccctctggaa--ctgtgagtTCAAAAACAG-------GAAAggaaaaa------------a--a-----------------------------ccttccctccttaaggttcttt--gccaGGTa--ttttgtcatggtagtcagaaaagtgacaattcATGGCAAGTCTCCATCAGGTCCTCACCAAGCA-----CACACGGAACTGTGACCGGT------------------AGAGGACATGC-C----TCCT-----TTT-------
69
+ s Arvicola_amphibius.NC_052058.2 72668476 265 - 166747489 actGctctctgcttcctgactgtgggtgccaagtgactagccagctcctactcttgctgtcatgccttccccatgacagactatatccccctaaga--ctgtgagtTCAAAAA----A--AAGAAAAggaaaaa------------a--c-----------------------------ccttccctccttaaggtccttt--gccaGGTa--ttttgtcatggtagtcagaaaagtgacAACTCATGGTGAGTCTCAATCAGGTCCTCACCAAGCA-----CACACAGAATCGTGGCAGGA------------------AGAGGATTCGC-TTAAGTCCT-----TTT-------
70
+ s Microtus_pennsylvanicus.CM073176.1 20976105 241 + 113485825 actGctctctgcttcctgactgtgggtgccatgtgaccagccagctcctactcttgctgtcatgccttccccatgacagacgatttccccctagaa--ctgtgagtTCAAAAAGAG-------AAATggaaaaa------------a--c-----------------------------ccttccctccttaaggtcgttt--gccaGGTa--ttttgtcacggcagttagaaaagtgacAGTTGATGGCAAGTCTCCATCAGGTCCTCACCAAGCA-----CACACAGAATTGTGGCAGGC------------------------------------------------------
71
+ s Microtus_arvalis.JAHRII010002323.1 111060706 260 + 200229077 actGctctctgcttcctgactgttggtgccatgtgaccagccagctcctactcttgctgctgtgctttccccatgacaaactgtgtccccctagga--ctgtgagtTCAAAAAAAG-------AAAAgaaaaaa------------a--c-----------------------------ccttgcctccttaaggtccttt--gccaGGTa--ttttgtcacggtagttagaaaAGTGACAGTTCATGGCAAGTCTCCATCAGGTCCTCACCAAGCA-----CACACAGAATTGTGACTGGT------------------AGAGGATATGC-C----TCCT-----CTT-------
72
+ s Neotoma_floridana.CM113793.1 27922272 255 - 95303938 attGctctctgcttcctgactgcagatgccgtgtgaccagct----------------gccacgccttccccatgatggactctatccctctggaa--ctgtgagtTCAAAAACAACA--AACAAACaaacaaa------------g--c-----------------------------ccttccttccttaagctgcctctgtcag-GTa--ctttacgactgtaaccagagaagTGATGGTTCATGGGGAGTCTCCA--AGGTTGTCCCCAAGCA-----CATACAGAATTGTGGCATGCAGTAGATTCACTTAAA-T-----------TC----TCCT-----CCT-------
73
+ s Onychomys_torridus.LR877198.1 72221017 244 + 93020901 attActctctgcttcctgactgtggaggccatgtgaccagctgcctcctactctttcagccatgccttccccatgatggactgcattcctgtggaa--ttg--agtCCCAAAACAGCA--AACAAACaaa---g---------------t-----------------------------ccttccttccttaagctgccttcatcag----------gtcactgtaaccagaaaagtgacGGTTCATGGGGAGTC---------------ACAAGCA-----CACATAGAATCATGGCAGGCAGAGGATTCACTT-AA-T-----------CC----TCCT-----CCT-------
74
+ s Peromyscus_californicus.VALE03000237.1 12779080 263 + 80346014 attActctctgcttcctgactgtggaggccatgggaccagctgcctcctgctctttcagccacgccctcctcatgatggactgtgtccctgtggaa--ctgtgagtTCAAAAACAACA--AACAGACaaaccaa---------------t-----------------------------ccttccttccttaagctgccttcgtcag----------gtcactgtaaccagaaGAGTGATGATTCATGGGGAGTCTCCA--AGGTCGTCCCCAAGCA-----CACACAGAATCATGGCAGGCAGAGGGTTCACTT-AAAT-----------CC----TCCT-----CCT-------
75
+ s Peromyscus_maniculatus_North.CM113205.1 35699768 259 + 104458120 attActctctgctacctgactgtggaggccacgtgaccagctgcctcctcctctttcggccacgccttccccatgatggattggatccctgtggaa--ctgtgagtCCACAAACAACA--AAGAAACaaacaaa---------------g--------------------------------tccttccttaagcggcctttgtcag----------gtcactgtcaccagaagagtGCTGATTCATGGGGAGTCTCCA--AGGTCGTCCCCAAGCA-----CACACAGAATCATGGCAGGCAGAGGATTCACTT-AA-A-----------CC----TCCT-----CCT-------
76
+
77
+
78
+ a
79
+ s Mus_musculus.CM000994.3 125889837 333 + 195154279 ACCCACATTTCCTTTCCTAAAGTGTATTCAGGTCAGCAATGAAAGTTCTCCAAAGGCAACTGCCTGGGGACAGAAAGACAGCAATGCACATGGATCCTCAGGATGCCACTGCAAACACAGGACCACCCTTTACTTGCATGTGGACCTGAGGAACCTTTGTAATTAATCACCCCTTAAGCTGAATGACTGATGTAGGAAACGCTAGACAGGGGTGAGAGCCTCAGGCCAGTCAGTTAATCACATCA-AGAAGAAATGGAGATAAATTCATCTTACCC-ACTTAGCAATTACCTCATTCACACTTGCCAAT-AAAAGAAACTAATTGTTCTGCCCTTT
80
+ s Rattus_norvegicus.CM070403.1 39971105 325 + 109350286 ACACACATTCCCTTTCCTTGTATGTGTTCAGGTCAGCAATGAAAGTTCTCCAAAGGCAATCACACAGGGACAGAAGGACAGCATGCC-CATGAGTCCTCAGGATGCCACCGCAAAGAAAGGATCCGCCTTTACTTGCATGTG-------GGATTCTTTATAATTAATCATACCTTATGGTAAATGACTGATGTAGCAAATTCTAGACAGGGGTGAGAGCCTCAGGCTACTCAGTTAATCACATCA-TGAAGAAATGGAGATAAATTCATCTTACCC-AGTTACCAATTACCTCTTTCACAGTTGCCAAT-AAAAGAAACTAATCGTTCTGCCCTTT
81
+ s Phodopus_campbelli.chr12 18453994 318 - 32442325 GC-CATGTTTCCTTTTCTTGAGTGTCTTCAGGTTAGTAATGAAAGCCCTGCAAAGACAATTACACCGGGACAGGAGGACAGAATACC-CGTGAATCCTCAGGATGCCCGGGCAAACATAGGGCCTCCTGTCACTTGCATGTGGGCCAAAGAAGCATTTGTAATTAATTGTACTTGATGGTGAATGACTAATGTAGCGAACTCTAGACAGGGGTGAGAGCTTCAGGCCAGC--------------AATGAAGCAATGGAGATAAATTCATCTTACTC-AGTTACCAATTACCTCTTTCATACTTGGCAAT-AAAATAAACTGATTGTTATGCCCTTT
82
+ s Phodopus_sungorus_new.chr12 17335426 318 - 31225933 GC-CGTGTTTCCTTTTCTTGAGTGTCTTCAGGTTAGCAATGAAAGCCCTGCAAAGACAATTACACCAGGACAGGAGGACAGAATACC-CGTGAATCCTCAGGATGCCCGGGCAAACATAGGGCCTCCTGTCACTTGCATGTGGGCCAAAGAAGCATTTGTAATTAATTGTACTTGATGGTGAATGACTAATGTAGCGAACTCTAGACAGGGGTGAGAACTTCAGGCCAGC--------------AATGAAGCAATGGAAATAAATTCATCTTACTC-AGTTACCAATTACCTCTTTCATACTTGGCAAT-AAAATAAACTGATTGTTATGCCCTTT
83
+ s Phodopus_roborovskii.JAEOAF010000031.1 16486705 319 + 29770300 GCACGTGTTTCCTTTTCTTGAGTGTCTTCAGGTTAGCAATGAAAGTCCTGCAAAGGCAATTACACCGGGACAGGAGGACAGAATACC-CGTGAATCCTCAGGATGCCTGGACAAACAAAGGGCCTCCCTTTACTTGCATGTGGGCCTAAGAAGCATTTGTAATTAATTGTACTTGATGGTGAATGACTAATGTAGCGAACTCTAGACAGGGGTGAGAGCTTTAGGCCAGC--------------AATGAAGCAATGGAGACAAATTCATCTTACTC-AGTTACCAATTACCTCTTTCATACTTGGCAAT-AAAATAAACTGATTGTTGTGCCCTTT
84
+ s Cricetus_cricetus.OZ199631.1 140167062 318 - 205530201 GTGCATGTTTCCTTTTCTTGTGTGCCTTCAGGTTAGCAATGAAAGTCCTGCAAAGGCAATTACA-CAGGACAGAAGGACAGAATACC-CACAAATCCTCAGGATGACAGTGCAAACAAATGGCCTCCCTTTACTTACATGTGGGCCTAAGAAGCATTTGTAATTAATTGCACTTGATGGTGAATGACTAATGTAGCAAACTCTAGACAGGGGTGAGAGCTTCAGGCCATC--------------AGTGAAGCAATGGAGATAAATTCATCTTACCC-AGTTACCAATTACCTCTTTCATACTTGGCAAT-AAAATAAACTGATTGTTCTGCCCTTT
85
+ s Cricetulus_griseus.NC_048598.1 130955239 319 - 193770019 GTGCATGTTTCCTTTTCTTGTGTGCCTTCAGGTTAGCAATGAAAGTCCCGAAAAGGCAATTACACAGGGACAGAAGGACAGAATACC-CACGAATCCTCAGGATGACAGTGCAAACAAATGGCCTCCCTTTACTTACATGTGGGCCTAAGAAGCATTTGTAATTAATTGCACTTGATGGTGAATGACTAATGTAGCAAACTCTAGACAGGGGTGAGAGCTTCAGGCCATC--------------AATGAAGCAATGGAGATAAATTCATCTTACCC-AGTTACCAATTACCTCTTTCATACTTGGCAAT-AAAATAAACTAATTGTTCTGCCCTTT
86
+ s Dicrostonyx_torquatus.JAQHUG010000071.1 6038571 314 - 8539717 GCACACATTTCCTTTCCTTGTGTGTCTTCAGGTT--------------------GGCAGTTACATAGGGACAGAAGGACAGCATAAC-CAAGAATCCTCAGGATAACACTGCAATCAAAGGGCCTCTCTTTATTTGTATGTGGGCCTAAGAAGCATTTGTAATTAATCACACCTGATGGCAAATGACTGATGTAGGAAACTCTAGGCAGGGGTGAGAGCTTCAGGCTAGCCAGTTAATCACAGCAATGAAGAAACAGAGATAAATTCATCTTACCC-AGTTACCAATCACCCCTCTCACACTTGGCGATAAAAAGGAACTGATTGTTCTGCCTGTT
87
+ s Arvicola_amphibius.NC_052058.2 72668744 313 - 166747489 ACACACATTTCTTCTCCTTGTGAGTCTTCAGGCT--------------------GGCAGTTACATAGGGACAGAAGGACAGCAGACC-CAAGAATCCTCAGGATACCACTGCTATCAAAGGGCCTCTCGTTGTTTGCATGTGGGCCTAAGAAGCATTTGTAATTAATCACACCTGATGGCAAATGACTGATGTAGCAAACTCTTGGCAGGGGTGAGAGCTTCAGGCCAGCCGGTTAATCACAGCAATGAAGAAACGGAGATGAATTCATCTTACCC-AGTTACCAATCACCTCGTTCACACTTGCCGAT-AAAAGAAACTGATTGTTCTGCCCTTT
88
+ s Microtus_pennsylvanicus.CM073176.1 20976356 287 + 113485825 --------------------TGAGTCTTCAGGTT--------------------GGCAGTTACATAGGGACAG-AGGACAGCAGACC-CAAGAATCCTCAGGATAG------GATCAAAGGGCCTCTCGTTATTTGCATGTGGGCCTAAGAAGCATTTGTAATTAATCACACCCCATGGCAAATGACTGATGTAGCAAACTCTAGGCAGGGGGGAGAGCTTCAGGCCAGCCAGTTAATCACAGCAATGAAGAAACAGAGATAAATTCATCTTACCCCAGTTACCAATCACCTCTTTCACACTTGGCAAT-AAAAGGAACTGATTGTTCTGCCTGTT
89
+ s Microtus_arvalis.JAHRII010002323.1 111060966 306 + 200229077 GCACACATTTCCTTTCCTTGTGAGTCTTCAGGTT--------------------GGCAGTTACATAGGGACAG-AGGACAGCAGACC-CAAGAATCCTCAGGATTG------GATCAAAGGGCCTCCCTTCATTTGCATGTGGGCCGAAGAAGCATTTGTAATTTATCACACCCAATGGCAAATGACTGATGTAGCAAACTCTAGGCAGGGGTGAGAGCTTCAGGTCAGCCAGTTAATCACAGCAATGAAGAAACGGAGATGAATTCATCTTACCC-AGGTACCAATCACCTCTTTCACACTTGGCAAT-AAAAGGAATTGATTGTTCTGcccatt
90
+ s Neotoma_floridana.CM113793.1 27922527 333 - 95303938 GCACACGCTGCCTTTTCTTGTGTGTCTTCACATCAGCAATGAAAGTCCTCCACAGGCAAATACATAGGGACAGAAGGACAGCATACT-CATGCATCCTTAGGATGCCAGTGCAATCTAAAGGCCCCCCTTTACCTGCAGGTGTACCTAAGAAGCATTTGCAATTAATCGCACCTGATGGTGAGTGACTGATGTAGCAAACTCTCGACAGGGGTGAGAGCTTCAGGCCGGGCAGTTAATCATGGCAATGAAGAAATGGAGATAAATTTATCTTACCC-AGTAACCAATTGCCTCTTTCACATTTGGCAAT-AAAAGAAACTGATTGCTCTGCCCTTT
91
+ s Onychomys_torridus.LR877198.1 72221261 332 + 93020901 GCACCTGTTGCCTTTTCTTGTGTGTCTCCAAGTCAGCAATGGACGTCCCCTACAGGTAATTACACAGGGACAGAGGAACAGCACAGC-CACACGACCTCAAGATGCCAGTACAAACTAAAGGCCTC-CTTGCCCTGCATATGTGCCTAAGAAGCATTTGTAATTAATCGCACCTGATGGTGAGTGACTGATGTAGCAAACTCTAGACAGGGGTgagagcttcaggccagccagttaatcacagcaAtgaagaaatggagacaaattcATCTTATCC-AGTTACCAATGGTGTCTTTCACACTTGGCAAT-AAAAGAAACTGATTGCTCTGCCCTTT
92
+ s Peromyscus_californicus.VALE03000237.1 12779343 332 + 80346014 ACACATGCTGCCTTTTCTTGTGTGTCTTCAAGTCAGCAATGAAAGTCCCCCACAGGCAATTGCACAGGGACAAAAGGACAGCGCAGC-CATGCATCCTCAAGATGCCGGTGCAAACTAAAGGCCTC-CTTTTCCTGCTTGTGTGCCTAAGAAGCATTTGTAATTAACCGCACCTGATGGTGAGTGACGGATGTAGCAAACTCCAGACAGGGGTGAGAGCTTCCGGCCAGCCagttaatcacagcaAtgaagaaatggagacaaattcaTCTTATCC-GGTTAGCAATGGCCTCTTTCACACTCGGCAAT-AAAAGCAACTGATTGCTCTGCCCTTT
93
+ s Peromyscus_maniculatus_North.CM113205.1 35700027 332 + 104458120 GTACACGCTGCCTTTTCTTGTGTGTCTTCAAGTCAGCAATGAAAATCCTCCACAGGCAATTGCACAGGGACAGAAGGACAGCGTAGC-CATGTATCCTCAAGATGCCGGTGCAAACTAAAGGCCTC-CTTTCCCTGCATGTGTGCCTAAGAAGCATTTGTAATTAACCACACCTGATGGTGAGTGACGGCTGGAGCCAACTCCAGACAGGGGTGAGAGCTTCCAGCCAGCCAGTTAATCACAGCAATGAAGAAATGGAGACAAATTCATCTTATCC-GGTTACCAATGGCTTCTTTCACACTCGGCCAT-AAAAGCAACTGATTGCTCTGCCCTTT
94
+
95
+
96
+ a
97
+ s Mus_musculus.CM000994.3 125890170 1154 + 195154279 ATCTTTTTAATATGAAAGTGATTTAAGACAACTGTAAAGCCAAGTTTTTTTTTTTTaaatgggctagggatgcagctctgtggtagagcactggcccagcaagcatgaggtcttgt-tttattctacagg-at----cacacatacacagaCCACACTCCCACAGCACACATAAGGCACACA-----------GTAGATCCACTGTAGACAACACATGGT------------------------GTGTACACAACAGATGAGCAGCAGGCACACAACAGATGTATACAACATAG-------------CACAGAAACAATGAATAAATGTAATAGACATATACATAACATGAacacaacacacata--tac-cattcacaccg-cacacactc-aagacattcattgtacacacaatatacacaacagataca--TATAACA--G--ATATTCAAC--AGAT--ATATAAC-ATACAATAAGTGTAGCACACACAAACAAAA---TTAGAAAAACACTCATATAAAAATTAC-----------------------ATAAATAAAACAAAATTACATATATAAAACAAAAACTA--CTGTGTACTCATATGTAAAG-ATCAAA-----AGCAAAGCACAAAGTCACTAGAAGAACTGTGACGTTTTAAAAATTAACTCAGGAATAGGGAAGCTTTTGGTTCAAAACAACTGGTGTTTGACCATTATAAAAATAAAACGTATACAAGCATGAACTTCCCATGTG-ATATCATAAGCAAATGGAGGTCCCTGCACGAAAAATGAAGG-AGGGGA-AATCCTCCCTAACTCTGAAGAGATTCTGGAAACCATGATGACACAGACTAACAAGACGAGTGAAAACTCAGTCAC------CAGCAGAAGGTTCACAGG--GAGGAATACAG-CCATCTCTGTGTACACATTTGAGGGTGG-TTCCAGAGATGA-----CTACATCGTCAGGACTCTGA-CCACTAAATCCTTTACTCCATTGATTGCCACATCACTGAAATAGATTATCAGGAAGTGGGAAAACTGAGGAAAAAGGGAGAAGATTGAAGGCAGTTGGTCAGCAGGT-A-GG-G-CGCACGCCCAAGGGCAATATCTTGCCCTTTCCTGTTGTGGCTCCTCTCTGCTCCATGCCTACCAAGATATGAGCT----CCTCTATTTG-----------TCTCCTCcatggactgaatcccctgaaaccaa-gagcaaagtcaatccattctccct-------------taagttgttcccattgg---------cta-tttc--gttacagGT--A
98
+ s Rattus_norvegicus.CM070403.1 39971430 1107 + 109350286 ATCTTTTTAATATGAAAGTGATTTAAGACAATTGCAAAGCCAAGTTTTTTTTTT---AATAggctagggaggcaactttgtggtagagcactcacccagcaagcatgagcccttgtGtttattctacagg-at----caca-atacacagatTACA--TCCACAGCATGCATAATGCACACA-----------ATAGATCCACTATAGACAACACACGAT------------------------GTATACATAACACCCATACCACAGATACACAACAGATGTATACAACATAGTTAACACAGAAACAGCAA----------------------------ACATAACATTCACACGAC--------------------------------------ACATTCAATATACACTCAACATACACAAAAGACACT--CATAACC--G--ATACAGAAC--AGAT--GTATAAC-ACACAACACTTGTAACAAACAC--ACAAAA---TT---AAAACACTCATACAA-AATTATTATTCTCACACAACACACAGCATATACACAAAACACA--TG--TCTGTAAGGCAAAAACTA--CTTTGCATTCCTATAAAAAG-ATAAAA-----TCCAAGGCACAAAGATTCTAGAAGAACTGTTAAGTTTTAAAAACTAACTCAGGAATAGGGCAAAGTTTGGTCTGAAACAGTTGGTGTTTGACCATGATAAAAATAAAACATGTACACGCATGAACTTCCTATGTG-ATGTCATAGGCAAATGGAGGTCCCTCTATGATACATGAAGG-AGGGGA-AACCCTTCCTGACTCTGAAGAGTTTATAGAAACTGTGATGACACAGACTAACAAGGCAAATGAAAACTCAGAGAC------CAAAAG-ATGTTCACAGA--GAGGAATACAG-CTACCTCTGTGTATATATTTGAGGGCGG-TTCTTGAGATGA-----C-ACATCATCAGGACTCTGA-CCACT-----CTTTACTCCATTGATGGACTCAGCACTGAAATAGATTATCAGGAAGTGGGGCCACTCGGGAAGATGGGAGCAGATTGAAGGTAACTGGTCAGCAGGT-A-AG-G-GGCACGCCCAACGGCAATATTTTGCCCTTTCCTGTTACGGCTCCACTCTGCTTCCTGCCTACCAAGATATGCgct----gctctatctg-----------tctcctccatgggctgaaacccctgaaaccat-gagcaaagtaaatctgttctccct-------------taagttgttcccattgg---------cta-tttt--gttacagGT--A
99
+ s Phodopus_campbelli.chr12 18454312 1133 - 32442325 ATCTTTTTAATATGAAAGTGATTTAAGACAActgca--------------------------------g------cccagtggtagagcatttacccagcGAGTATGAGGCCGTAGGTTTATTCTACAGT-AT----CACACATACACAGGAAACACACCCAC---------AA--CACACATAAGACATGCAATAGACATACTGCAGACAACATGTGAC------------------------ATGTACACAACA-----------ATCATACAACAGATATACACAACATAGACAACAC-AAAGCAGTAGAAACAACAGACGTACATACCAGACATATatgtaacatgcacacaacaca----CAtaa-cattcacacaa-cacatacta-gagaaatATAATACACATAGAACATATACAACAGA--CACATATAATA--G--ATACAGAAC--AGAT--ATATAAC-ACACAACACTTGCAACAGACAC--ACACAAAACCC---AAAACA----TACAATAATCACAGCTCTCATACAATATATAGCACACATAAAATACACA--TACATACCCAG--GAAAAATTA--CTTTGTATTTATATATAAAG-ATAAAA-----CCTAAAGCACAAAGATACTAGGAGAATTATGGAACTTTATAAATTAATTTGCGAATAGAAGAGAGTTTGGTCAGAAGTAATCGATGTTTGACCATTATAAAAATAAAACATACACAAACAAGAACTTCTCATGTA-AAGTCATAGGCAAATGGAAACCCCTGTATGGCAAATGAAGG-AGGGAATAACCCTCCCTGACTGTGAAGAATTTATTGAAACTCTGATGACAAAGACTAACAAGGC-AGTGCAA--------ACAGTCACCAGCAGAAGGTTCATAGACACAGGCACGCAGGCCACGTCTGTGTGCACCTGTGAGGGAGG-TTCCAGCGATGA-----CGACATC-TCAGGACTC-GAGCCAGTGGAAGGTTTACTCTACTGACTGACTCAGCATTGGAACAGATTACTGGGAAGTGACAGAACTGGAGATAATGGAACCAGATTGGAGGTAGCTGGTC-GGGGGT-A-AG-GGGACATGCCTACGGGCAGTATCTTG----------TTAGGGTTCCACTCTCCTTCCTGCTAACCATGATATGAGCT----GCTCTATCTGCCAGACCCTCACCTCCTTCATGGTCTGAAACCTCTAAAACCAT-GAGCAAAGTAAATACATTCTCCTTTAAGTTGTTCACAT-------------TAG---------CTA-TTTTT-GTCACAGGTGCA
100
+ s Phodopus_sungorus_new.chr12 17335744 1130 - 31225933 ATCTTTTTAATATGAAAGTGATTTAAGACAactgca--------------------------------g------ctcagtggtagagcatttacccagcaagtatgaggccgtagGtttattctacagt-at----cacacatacacaggaaacacacccac---------aa--cacacaTAAGACATGCAatagacatactgcagacaacatgtgac------------------------atgtacacaaca-----------ggcatacaacagatatacacaacatagACAACAC-AGAGCaatagaaacaacagacatacataccagacatatatgtaacatgcacacaacaca------taa-cattcacacaa-cacatacta-GAGACATATAATACACACAGAACATATACAACAGA--CA--TATAATA--G--ATACAGAAC--AGGT--ATATAAC-ACACAACACTTGCAACAGACAC--ACACAAAACCC---AAAACA----TACAATAATTACAGCTCTCATACAATATATAGCACACATAAGATACACA--CACATACCCAG--GAAAAATTA--CTTTGTATTTATGTATAAAG-ATAAAA-----CCTAAAGCACAAAGACACTAGGAGAATTATGGAACTTTATAAATTAATTTGCGAATAGAGGAGAATTTGGTCAGAAGTAATCGATGTTTGACCATTATAAAAATAAAACATACACAAACAAGAACTTTACATGTA-AAGTCATAGGCAAATGGAAACCCCTGCATGACAAATGAAGG-AGGGAATAACCCTCCCTGACTGTGAAGAATTTATTGAAACTCTGATGACAAAGACTAACAAGGC-AGTGCAA--------ACAGTCACCAGCAGAAGGTTCATAGACACAGGCACGCAGGCCACGTCTGTGTGCACCTGTGAGGGAGG-TTCCAGAGATGA-----CGACATC-TCAGGACTC-GAGCCAGTGGAAGGTTTACTCTACTGACTGACTCAGCATTGGAACAGATTACTGGGAAGTGACAGAACTGGAGATAATGGAACCAGATTGGAGGTAGCTGGTC-GGGGGT-A-AG-GGGACATGCCTACGGGCAGCATCTTG----------TTAGGGTTCCACTCTCCTTCCTGCTAACCATGATATGAGCT----GCTCTATCTGCCAGACCCTCACCTCCATCatggtctgaaacctctgaaaccat-gagcaaagtaaatacattctccttTAAGTTGTTCACAt-------------tag---------ctt-ttttTTGTCACAGGTGCA
101
+ s Phodopus_roborovskii.JAEOAF010000031.1 16487024 1036 + 29770300 ATCTTCTTAATATGAAAGTGATTTAAGACAACTGCAAAGGCAATT-----------------GTTGAG------------------------------------ATGAGGCCGTGTGTTTATTCTACAAT-AT----catacatacacaggaaacacatccac---------aacacacacaCAAGATATGCAatagacacactgtagacaacatgtgac------------------------atgtagacaata-----------ggcatacaacagatatacacagcatagATAACAC-AAAGCaacagaaataacaga-atacataccagatatacatgtaacatgcacacaacaca----CAtaa-cattcacctaa-cacatacta-gagacatataatatacacacaacatatacagcaga--c----ataata--g--atacagaac--agat--atataac-actca-------------acac--acacaaAACcc---aaaaca----tacaataatcaaAGCTCTCCTACATTATACAGCATacataagatacaca--tacatacccaG--GAAAAATTA--CTTTGCATTTATATATAAAG-ATAAAA-----CCTAAAGCACAGAGATAGTAGGAGAATTGTGAAACTTTATAAATTAATTTGTGAATAGAGGAGAGTTTGGTCAGAAACAATTGATGTTTGACCATCATAAAAATAAAACATACACAAACATGAACTCCACATGTA-ATGTCACAGGCAAATGGAAAGCCCTGTATGACAAATGAAGG-AGGGAATAAGCCTCCCTGACTGTGAAGAACTTATTGAAACTGTGATGACAAAGAATAATAAGGCAAGTGGAAACCCAATGACAGTCACCAGCAGAAGGTTCATAGACATAGGCATACAGGCCACATGTGTGTGCAT-----------------------------------------------------------------------CTGGCTGACTCAGCATTGGAATATATTGCTGGGAAGTTGGAGAAGTGGAGATAACGGGACCAGATTGGACGTAGCTGGTCAGGGGGT-A-AG-GGGACATGCCTAAAGGCAGTGTCTTG----------TTAGGGTGCCACTCCCCTTTCTGCTAACCATGATATGAGCT----GCTCTATCTGCCAGACCCTCACctccttcatggtctgaaacctctgaaaccat-gagcaaagtaaatagtctctcctt-------------t-------------tag---------cta-ttttT-gtcaCCAGTGCA
102
+ s Cricetus_cricetus.OZ199631.1 140167380 1129 - 205530201 ATCTTTTTAATATGAAAGTGATTTAAgccaactgcaaagccagct-----------------gctgggggtacagctcagtggtagagcacttgtccagcaagcatgaggcagtgtAtttattctacaat-at----ctcacacacacagaaaacacacccac---------aagacatgca-----------atagacacattgttgacaatacatgac------------------------atgtacacaata-----------ggcatataacagttatacacgacatagATAACAC-AAAGCaacagaaactacagacctacataccagacatatatgtaacatgcatacaacacacacaCAcaa-cattcacacaaCcacatatga-gagacttataatatacacagaacatatacagcagacaca--tataata--g--atacagaac--agat--atgtaaa-atgcaacacttgcaacagacac--acaagAAACCA---AAAACA----TACAATAACCACAGCTCTCATACAATATACAGAATACATATAATGTATG--TACATACACAG--CAAAAA-TA--CTTTGCATTTATGTATAAAG-ATAAAA-----TCTAAAGCACAAAGATACTAGGAGAATTATGAAACTTTATCAATTCATTTGGGAAAAGAAGAGATTTTAGTCAGAATTAATTGATGTTTGGCCATTACAAAAATAAAACATACACAAACATGAACTCCACCTGTA-ATGTCATGGGCAAATG--------------ACAAATGAAGG-AGGAAA-ACCCCTCCTTGACTCTGAAGAGCTTATGGAAACCGTGATGACAAAGACTAACAAGGAAAGTGAAAACTCAGTGATAGTCACCAGCAGAAGGTTCATAGACATAGCGATACAGGCCACCTCTGTGTGCACCTATGAAGGTGG-TTCCAGAGTTGA-----TGACATCATCAGGACTCTGAGCCAGTAAAAGGTTTACTCTATGGATTGACTCAACACTGGAATAGATTACCAGGAAGTGAGAGAACTGGGGATGATGGAACCAGATTGGAGGTAGTTGGTCAGGAGGT-A-GG-GTGGCATGCCTAGGGGTAATATCT---------------------------CCTTCCTGTCTACCATGATATGAGCT----GCTCTATCTGATAGACCCTTGcctccatcatggtctgaaacctctgtaaccat-gagcaaagaaaatactttctccct-------------taagtttttcacattag---------ctg-ttttT-gtcacaggtGCa
103
+ s Cricetulus_griseus.NC_048598.1 130955558 1135 - 193770019 ATCTTTTTAATATGAAAGTGATTTAAGCCAACTGCAAAGCCAACT-----------------gctgggggtacagctctgtggtagagcacttgcccagaaagcatgaggcagtgtAtttattctacaat-atCACAcacacacacacagaaaacacacccac---------aagacatgca-----------atagatacattgttgacaatacatgac------------------------atgtacacaata-----------ggcatataacagttatacacaacatagATAACAC-AAAGCaacagaaactacagacctacataccagacatatatgtaacatgcatacaacacacacaCGtaa-cattcacacaa-cacatatga-gagacttataatatacacagaccatatacaacagacaca--tataata--gATatacagaac--agat--atataaa-acgcaacacttgcaacagacac--acaaaaAACca---aaaaca----tacaataatcacAGCTCTCATACAATATACAGAGTacatataatgtata--tacatacatag--CAAAAATTA--CTTTGCATTTATATATAAAG-ATAAAA-----CCTAAAGCACAAAGATACTAGGAGAGTTATGAAACTTTATAAATTAATTTGGGAAAAGAAGAGATTTTAGTCAGAAATAATTGATGTTTGACCATTACAAAAATAAAACATACACAAACATGAACTCCACTTGTA-ATGTCATAGGCAAATG--------------ACAAATGGAGG-AGGAAA-ACCCCTCCCTGACTCTGAAGAGCTTATGGAAACTGTGATGACAAAGACTAACAAGGAAAGTGAAAACTCAGTGACAGTTACCAGCAGAAGGTTCATAGACATAGGCATACAGGCCACCTCTGTGTGTACCTATGAAGGCGG-TTCCAGAGATGA-----TGACATCATCAGGACTCTGAGCCAGTAAAAGGTTTACTCTATCGATTGACTCAACACTGGAATAGATTACCAGGAAGTGAGAGAACTGGGGATGATGGAACCAGATTGGAGGTAGTTGGTCAGGAGGC-A-GG-GTGGCATGCCTAGGGGTAATATCT---------------------------CCTTCCTGCCTACCATGATATGAGCT----GCTCTAGCTGATAGACCCTTGCCTCCatcatggtctgaaacctctgtaaccat-gagcaaagaaaatactttctcctt-------------taagtttttcacattag---------ctg-ttttT-gtcacagGTGCA
104
+ s Dicrostonyx_torquatus.JAQHUG010000071.1 6038885 1118 - 8539717 ATCTTTTTAATATGAAAGTGATTTACGGCAACTGCAAAACCAGCT-----------------GC-ggggatgcagctcagaggtagagcacttgctcagtgagcatgaggctttctGtttattctacaat-at----cacacataaacagacaacacacccgc---------agcacataca-----------atagagacattatggacaatacatgac------------------------at-----------------------------------atacacaacatagATAACACAAAAAGaacagaaaaaacagacatacataacaga-atatatgtaacatacacacaacacatacaCAtaa-catttacacaa-cacatacga-gagacatataatatacacagaacatatacaacagatgca--tataata--g--atatacaac--aaat--atgtaac-atacatcacttgcaacagacat--aaataaAACtc---aaagcacttacacaataatcatAGCTCTCATACAATATATAGCATacatataagacaca--tgtatacacag--caaatatta--ctttgtattcatatataaat-ataaaa-----cctaaagcacaaaggcacaaggagaattatgaaactttataaattaacttgGGAATAGAGAAGATTTTGGTCAGGAATAATTGATGTTTGGCCATTATAAAAATTAAACAAACACAAACATAAACTCCACATGTGGACATCATAGGCAGATGGAAATCCCTGCATG-CAAATGAAGG-AGGGA----CCCTACTTGACTCTGAAGAGCTTATGCAAACTGTGATGACAAAGACTAACAAGGCAAGTGAGAACTCAGTGACAGTTACCAGCAGAAGGCTCACAGATACAGGCATACAGGCCACCTCCGTGTGCATCTGTGAGGGTGG-TTCCAGAGACGA-----TGGCACCATCAGGACCCTGAGCCAGTAAAAGGTTTACTCCACTGATCGACTCAAGATTAGAACAGATTACCAGTGAGTTTGAGAACTGGGGAAGATGGGACCAGATTGGAAACAGTGGTTCAGGGCAT-G-GC-GGGGCATGCCTAGGGGCAAAATCTGA----------TCAGGGCTCCACTCTGTTTCCTGCCTACCA-GATATGAgct----gctctatc--TT-----CCAGcctccttcatggact---------gaaaccat-gagcaaagtaaattctttctccct-------------cgagtttttcacagtgg---------ctg-tttt--gtcacagggGCa
105
+ s Arvicola_amphibius.NC_052058.2 72669057 1139 - 166747489 ATCTTTTT-ATATGAACGTGATCGAGGAGAACTGCAAAACCAACG-----------------GC-ggggatgctgctcagaggtagagcacttgctcagtgagcatgaggccttgtGtttattctacaat-at----cacacataaacagacagcgcacccac---------agcacatgca-----------atagacacactgtggacaatacatgacATATATACAACAGGCACAACACAGat-----------------------------------atatacaacatagATAGCACAAAAACaacagaaaccacagacatacataacaga-atgtatgtaacatacacacaacacacaca--taa-cattcatacaa-cacatacaa-gacacatataacatacacagaacatatacaacagatgca--tattata--g--acataca----agat--atataac-atacattacttg-aacagacat--acacaaAATtc---aaaa-acccatacaataatcatAGCTCTCATATAATATACAGCATgcatataacacaca--tgtatacacag--caaaaatta--ctttgtattcatatataaatAaaAAAA-----CCTAAAGCACAAAGTCACTAGGAGAATTATGAAGCTTTATAAATTAACTTGGGAATAAGGGAGATTTTGGTCAGGAATAATTGATGTTTGACCATTACAGAAATTAAACATACACAAACATAAACTCCACGTGTGGATATCATAGGCAGATGGAAATCCCTGTATGACAAATGAAGG-AGGGA----CCCTCCTTGACTCTGAAGAGCTTATGCAAACTGTGATGACAAAGACCAACAAGGCAAGTGAGAACTCAgtgacAGTCACcagcagaaggctcacagaCAcacgcatacagGccacctctgtgtgcacctgtgagGGTGG-TTCCAGAGATGA-----TGGCATCATCAGGACCCGGAGCCAGTAAAAGGGTTACTCCAATGATCGACTCAAGATTAGAACAGATTACCAGGAAGTTTGAGAA-CAGGGAAGATGGGACCAGATTGGAGATAGTGGTTCAGGGGGTGG-GGGGGGGCATGCCTAGGGGCAAAATCTGG----------TCAGGGCTTCGCTCTGCTTCCTGCCTACCA-GATATGAACT----GCTCTATC--CT-----CCAGCCTCCTTCATGGACT---------GAAACCATGGAGCAAAGTAAATTCTTTCTCTCG-------------CGAGCTTTTCACAGTGG---------CTG-TTTT--GTCACGAGTGCa
106
+ s Microtus_pennsylvanicus.CM073176.1 20976643 1100 + 113485825 ATCTTTTTAATATGAAAGTGATCTAGGATAACTGCAAAACCAGCT-----------------gc-ggggatgcagctcagaggtagagcacttgctcagcgagcatgaggccttgtGtttattctacaat-at----cacacataaacagacaacacacccac---------agtgcataca-----------acat-caca-tgtggacaatacatgac------------------------at-----------------------------------atacacaacacagATAACACAAAAACaacagaaacaacagacatacatagcgga-atatatgtaacatacacacaacacacaca--taa-cattca------------------cacatgtaatatacacagaacatatacaacatatgca--tatgata--g--atatacaacATatat--atataat-atatatcacttgcaacagacat--acataaAACtc---aaagcacttgtacaataatcatAGCTCTCATACAATATATAGCACacatataacagaca--tgtatacacaG--CAAAAATTA--CTTTGTGTTCATATATAAAT-ATAATA-----CCTAAAACACAAAGGCACTTGGAGAATTAGGAAGCCTTATAAATTAACTTGGGAATAGGGGAGATTTTGGTCAGGAATAATTGATGTTTGACCATTATAAAAATTAAAGATACACAAACATAAACTCTACATGTGCATATCATAGGCAAGTAGAAATCCCTGAATGACAAATGAAGG-AGGGA----CCCTCCTTGA--CTGAAGAGTTTATGCAAACTGTGATGACAAAGACTAAAAAGGCAAGTGAGAACTCAGTGACAGTCACCAGCAGAAGGCTCACAGACACAGGCATACAGGTCACCTCTGTGTGCACCTGGGAGGGTGG-TTCCAGAGACGA-----TGGCATCATCAGGACCCAGAGCCAGTAAAGGGGTTACTCCACTAATCGACTCAAGATTAGAACAGATTACCAGGAAGTTTGAGAACCAGGGAAGATGGGACCAGATTGGAGACAGTGGTTCAGGGGGT-A-GGAGGGGCAAGCCTAGGGGAAAAATCTGG----------TCAGGAATTCActctgcttcctacctatca-gatgtgaact----gctctatc--CT-----CCAGcctccttcatggact---------gaaaccat-gagctaagtaaattctttctccct-------------cgagtttttcacagtgg---------ctg-tttt--atcacaAGTGCA
107
+ s Microtus_arvalis.JAHRII010002323.1 111061327 1117 + 200229077 atctttttaatatgaaagtgatctaggataactgcaaaaccagct-----------------gc-agggatgcagctcagaggtagagcatttgctcagtgagcttgaggccttgtGtttattctacaat-at----tacacataaacagacaacatacccac---------agtacataca-----------acat-caca-tgtggacaatacatgac------------------------at-----------------------------------atacacaacatagATAACACAAAAACaacagaaacaacagacatacataacaga-atatatgtaacatatacacaacacacata--taa-cattcacacaa-cacatacaa-gagacatataatatacacagaacatatacaacagatgca--tatgata--g--atatacaacATatatGTatataac-atatatcacttgcaacagacat--acataaAACtc---aaagcacttatacaataatcatAGCTCTCATACAATATATAGCACacatataacagaca--tgtaTACACAG--CAAAAATTA--CTTTGTGTTCATATATAAAT-AAA-TA-----CCTAAAACACAAAGGCACTAGGAGAATTATGAAGCCTTATAAATTAACTTGGGAATAGGGGAGATTTTGGTCAGGAATAATTGATGtttgaccattataaaaattaaagatacacaaacataaactCCACATGTGCTTATCATAGGGAAATGGAAATCCCTGTATGACAAATGAATG-AGGGA----CCCTCCTTGA--CTGAAGAGTTTATGCAAACTGTGATGACAAAGACTAAAAAGGCAAGTGAGAACTCAGTGACAGTCACCAGCAGAAGGCTCACAGACACAGGCATACAGGTCACCTCTGTGTGCACCTGTGAGGGTGG-TTCCAGAGACGA-----TGGCATCATCAGGACCCGGAGCCAGTAAAAGGGTTACTCCACTGATCGACTCAAGATTAGAACAGATTACCAGGAAGTTTGAGAACCAGGGAAGATGGGACCAGATTGGAGACAGTGGTTCAGGGGGT-A-GGAGGGGCATGCCTAGGGGAAAAATCTGG----------TCAGGGATTCActctgcttcctacctatca-gatgtgaact----gctctatc--CT-----CCAGcctccttcatggact---------gaaaccat-gagcaaagtaaattctttctccct-------------cgagtttttcacagtgg---------ctg-tttt--atcacaAGTGCA
108
+ s Neotoma_floridana.CM113793.1 27922860 1142 - 95303938 ATCTTTTTAATATGAAAGTGATTTAAGACAACTGCAAAgctagct-----------------gctggggatgcagctcagtggtagagcacttgcctggcaagcatgaggccttgtGtttattccacaat-at----cacatatacacagacaacacacccacagcatacacaagac-----------------------------------------------------------------------acacaaaa-----------ggcatacaacagatatacataacatagATAACACAAAAACaacag-aaaaacagacatacataacagacatatatgtaacatgcacacaacacacaca--taa-catttacacaa-cacatacta-aagacatataatatacacagaacatctacaacaaacata--taat--a--g--atacacaac--agat--atatcac-atacaacacttgcaacagacac--atacaaAACtc---aaaacactcatacaacaatcacAGCTCTTACACAACATACAGCATacacataatataca--tgcacacacag--caaaaatta--ctttacattcatatgtacag-ataaaa-----ctcaaagtacaaagacacTAGGAGAATTATGAAGCTTTATAAATTAACATGGGAATAGGGGAGATTTTGGTCAGAGTTAATTGATGTTTGACCATTATAAAAATAAAACATCCACAAACATTAACTCCACATGAGGGTGTCATAGGCAAGTGGAAATCCCTGTATGACAAATGAAGATGGGAAA-CCCCCTCCCTGACTCTGAAGAGTTTACGGAAACTGTAATGACAGAGACTAACAAGGCAAGTGAAAACTCTGTGACAGTCACCAGCAGAAGGTTCACAGACACAGGCACACAGGCCACCTCTGTGTGCACCTGTGAGGGTGG-TTCCAGAGATGA-----AGACATCATCAGGACTCTGAGCCAGCAAAAGGTTTACACCACTGATTGACTCAT---TGGAATAGATTACCAGGAAGTGGGAGAGCTGGGGAGGATGGGATCAGATTGGAGGTAGTTCGTCAGGGGTTGAGGG-GGGGCACACCTAGAGGCACTATCTTG----------TTAGAGTTCCGctctccttcctgcctaccatgatgtgagct----gctctatctaCCTGATCCTTGcctccttcatggactcaaacctctgaaaccat-gagcaaagtaaatactttctccct-------------taagtttttcacattggCTATTTTGTcta-tttt--gtcacaggtGCa
109
+ s Onychomys_torridus.LR877198.1 72221593 1147 + 93020901 ATCTTTTTAATATGAAAGTGAttgaagacaacctcaaagctagat-----------------gctggggatgcagctcagtggtagagcacttgcccagcaagcctgaggccttatGtttattcttcaac-at----cacacatacacagataacacacccatagcatacataagacacata-----------atagacatattgtagacaacacatg--ACATGT----------------------acacaaca-----------ggcatacaacagttaaacacaacatagATACCAC-AAAACaactgaaataacagacatacataacagacatatatgtaacatgcacacaactcatgca--taa-cattcacacaa-cacacactaGaagacaaataatatacacagaacatacacaacaaacaca--tata--a--t--ata---------------------Aacacaacacctgcaacagacac--atacaaAACtc---aaa-cactcatacaacaatcacAGCTCTTATACAACATACAGCATacacataatataca--tgcatacacag--CAAAAATTA--CTTTGCATTCATATATAAAG-ATAAAATAAAACCCCAGGTACAAAGACACTAGGAGAATTATGAAGCTTTATATATTAACTTGGGAATAGGGGAGATTTTGGTCAAAGTTAATTGATGTTTGATCACTAGAAAAATGAAACATACACAAACATGAACTCCACAATAGGATGTCACAGACAAGTGGAAATCC-AGTGTGACAAAAGAAGA-AGGAAA-ACCCCTCCCTGACTCTGAAGAGTTTATGGAAACTGTAATGTCAAA-ACTGACAAGGCAAGTGAAAACTCTGTGACCGTCACCAGCAGAAGGTTCACAGACACAGGCCTAGAGGCCACCT--GTGTGCACCTGTGAGG--GG-TTCCAGAGATAA-----TGACATCATCAGGACTCTGAGCCAGTAACGAGTTTACTCCACTGATTGACTCAC---TGGAACAGATTACCAGGAAGTGGGAGAACTGGGCAAGATGGGACCAGATTGGAGGT-------CAGGGAGC-AGGG-GGAGCATGCCTACCAGCAATATCTTG----------TTAGGGTTCTGctctccttcctgcctatcatgatatgagctAGCTgctctagctaACTGACCCTCAcctccttcatggactcagacctctgaaactat-gagcaaattaaatactttctccct-------------tgaggttttcacagtgg---------cca-tctt--atcacaggcGCa
110
+ s Peromyscus_californicus.VALE03000237.1 12779675 1153 + 80346014 ATCTTTTTAATATGAAAATgatttaagacacccgcaaagctagct-----------------gctggggacgcagcccagtggtagagcacttgcccagcaagcacgaggccttgtGtttcttctacagtTat----cacacatacacagacaacacacccacagcatacataagacatgcg-----------atagacacattgtagacaacacatg--GCATGT----------------------acacagca-----------ggcatacaacagacatacacaacatagATACCACAGAAACaacagaaataacaga-------------catatatgtaacatgcacacaacacacaca--taa-cattcacacaa-cacatacta-gagatatataatatacacagaacatatacaacaaataca--tgta--aTAg--aaacacaac--agat--atataacAacacaacatttgcaacagacac--acaaaaAACtc---aaaacactcatacaacaatcacAGCTCTTACTCAACATACAGCATacacataatataca--tgcatacacag--GAAAAAATA--CTTCGCATTCATATATAAAG-ATAAAA-----CCCAAAGTACAAAGACACTGGGAGAATTATGAAGCTTGATACATTAACCTGGGAACAGGCGAGATTTCGGTCAGAGATAACTGATGTTTGAACATTATAAAAATGAAACATGCACAAACGTGAACTCCACATGAGGATGTCACAGGCAAGTGGAAATCCCAGTATGACAGAAGAAGA-AGGAAA-ACCCCTCCCTGACTCTGAAGAGTATATGGAAACTGTAATGACAAAGACTAACAAGGCAAGTGAAAACTCTGTGAACGTCATCAGCAG---GTTCACAGACACAGGCATCCAGGCCACCT--GTGAGCACCTGGGAGG--GGGTTCCAGAGATGA-----CGACATCATGAGGACTCTGAGCCAGTAACAGCTTTACTCCACTGATTGACTCAG---TGGAACAGAGTACCAGGAATTGGGAGAACTGGGCAAGATGGAACCAGATTGGAGGTAGTTGGTCAGGGGGC-AGAG-GGGA-ATGTCTACTGGCAATATCTTG----------TTAGGGTTCTGctctccttcctgcctatcatgatatgagct----gctctatctaCATGACCCTCAcctccttcacggactcaaacctctgaaactat-gagcaaattaaatactttcttcct-------------taaggttttcacattgg---------ctaCtttt--atcacaggtGCa
111
+ s Peromyscus_maniculatus_North.CM113205.1 35700359 1160 + 104458120 ATCTTTTTAATATGAAAGTGATTTAAGACACCCGCAAAGCTCGCt-----------------gctggggatgcagctcagtggtagagcacttgcccagcaagcacgaggccttgtGtttcttctacaatGat----cacacatacacagacaacacactcacagcatacataagacacgcg-----------atagacacattgtagacaacacatg--ACATGT----------------------acagagga-----------ggcatacaacagacatacacaacatagATACCACAAAAACaacagaaataacagagatatgtaacagacatatatgtaacatgcacacaacacacaca--taaAtattcacacaa-cacatacta-gaaatatataatatacacagaaca---------aacaca--taca--aTAg--aaacacaac--agat--atataacAacacaacatttgcaacagacac--ataaaaAACtc---aaaacactcatacaacaatcacAGCTCTTACACAACATACAGCATacacataatataca--tgcatacacCG--AAAAAAAAAACCTTCGCATTCATGTATAAAG-ATAAAA-----CCCAAAGTACAAAGACACTGGGAGAATTATGAAGCTTTATACATTAACTTGGGAATAGGGGAGATTTTGGTCAGAGTTAACTGATGTTTGACCATTATAAAAATGAAACATGCACAAACATGAACTCCACATGAGGATGTCATAGGCAAGTGGAAATCCCCGTGTGAGAAAAGAAGA-AGGAAA-ACCCCTCCCTGACTCTGAAGAGTTTGTGGAAACTGTAATGACAAAGACTAACAAGGTGAGTGAAAACTCTGTGACCGTCACCAGCAG---GCTCACAGACACAGGCATCCAGGCCACCT--GTGTGCACCTGTGGGG--GG-TTCCAGAGATGACGACATGACATCATCAGGACTCTGCGCCAGTAAC-AGGTTACTCCACTGATTGACTCAG---TGGAACAGGGTACCAGGAAGTGAGAGAACTGGGCAAGATGGGACCAGACTGGAGGTAGTTGGTCACGGGGC-AGGG-GGGGCGTGGCTATTGGCAATATCTTG----------TTAGGGTTCCGCTCTCCTTCCAGCCTAGCAT---ATGAGCT----GCTCTATCtaCTGGACTCTCAcctccttcatggactcaaacctctgaaaccat-gagcaaattaaatactttcttccc-------------taaggttttcacattgg---------ctg-tttt--atcacaggtGCa
112
+
113
+
114
+ a
115
+ s Mus_musculus.CM000994.3 125891324 34 + 195154279 CACAGTCACCAAGTACTTCATGGTCTTGGATGAG
116
+ s Rattus_norvegicus.CM070403.1 39972568 30 + 109350286 CAAAATCACCAAG----TAATGGTCTTGGATAAA
117
+ s Phodopus_campbelli.chr12 18455457 34 - 32442325 CACAATAACCAAGTTCTGAATggtcctggatgac
118
+ s Phodopus_sungorus_new.chr12 17336886 34 - 31225933 CACAATAACCAAGTTCTGAATGgtcctggatgac
119
+ s Phodopus_roborovskii.JAEOAF010000031.1 16488072 34 + 29770300 CACAATGACCAAGTTCTGAATGGTCCTGGATGAC
120
+ s Cricetus_cricetus.OZ199631.1 140168521 34 - 205530201 CACAATCACCAAGTTCTTAATGATCCTGGATGAT
121
+ s Cricetulus_griseus.NC_048598.1 130956705 34 - 193770019 CACAATCACCAAGTTCTTAATGATCCTGGATGAT
122
+ s Dicrostonyx_torquatus.JAQHUG010000071.1 6040015 34 - 8539717 CACAAACATCAAGTTCTTAATGATcctgggtgac
123
+ s Arvicola_amphibius.NC_052058.2 72670208 31 - 166747489 cacaatca-caagttcttagtga-tccgggtga-
124
+ s Microtus_pennsylvanicus.CM073176.1 20977755 34 + 113485825 CACAACCATCAAGTTCTTAATGATTCTGGATGac
125
+ s Microtus_arvalis.JAHRII010002323.1 111062456 34 + 200229077 CACAACCATCAAGTTCTTAATGATTCTGGATGAC
126
+ s Neotoma_floridana.CM113793.1 27924014 34 - 95303938 CACAATCACCAAATTCTTAATggtcctggatgac
127
+ s Onychomys_torridus.LR877198.1 72222752 28 + 93020901 CACAATCACCAAGTTCTTAATGGTCCTG------
128
+ s Peromyscus_californicus.VALE03000237.1 12780840 34 + 80346014 cacaatcaccaagttcttaatggtcctggatgac
129
+ s Peromyscus_maniculatus_North.CM113205.1 35701531 34 + 104458120 cacaatcaccaagttcttcatggtcctgggtgac
130
+
131
+
@@ -0,0 +1,9 @@
1
+ # mafutils-index format=2 maf=real-excerpt.maf compression=none size=47241 mtime=1784644433.0 hash=md5:7146e0c45ac589e8998a3fe232ca5ad7
2
+ CM000994.3 125888838 82 84 135 13 17 1874
3
+ CM000994.3 125888920 187 223 275 9 1874 4416
4
+ CM000994.3 125889107 10 31 82 9 4416 5221
5
+ CM000994.3 125889117 440 487 539 14 5221 12879
6
+ CM000994.3 125889557 280 356 408 15 12879 19122
7
+ CM000994.3 125889837 333 336 388 15 19122 25065
8
+ CM000994.3 125890170 1154 1324 1377 15 25065 45843
9
+ CM000994.3 125891324 34 34 85 15 45843 47241
@@ -0,0 +1,2 @@
1
+ # mafutils-index format=2 maf=real-excerpt.maf compression=none size=47241 mtime=1784644433.0 hash=md5:7146e0c45ac589e8998a3fe232ca5ad7
2
+ CM000994.3 17 47241
@@ -118,3 +118,64 @@ def test_maf_fetch_fasta_region(chrom, start, end, region_id, tmp_path):
118
118
  expected = expected.rstrip('\n')
119
119
 
120
120
  assert got == expected, f"FASTA output for region {region_id} does not match expected"
121
+
122
+
123
+ def test_scaffold_subdirs_groups_output_by_scaffold(tmp_path):
124
+ """
125
+ --scaffold-subdirs groups per-region output files into
126
+ <outdir>/<scaffold>/<basename>.maf instead of a flat <outdir>/. Runs
127
+ with -p 2 (real multi-worker ProcessPoolExecutor dispatch, matching how
128
+ block-mode writes actually happen) across regions spanning multiple
129
+ scaffolds, including two scaffolds (chr1, chr4) with multiple regions
130
+ each, to confirm they land in the same subdirectory without any
131
+ cross-worker race (directories are pre-created upfront, see fetch.py).
132
+ """
133
+ out_dir = str(tmp_path)
134
+ cmd = [
135
+ sys.executable, "-m", "mafutils", "fetch",
136
+ MAF_FILE, BED_FILE,
137
+ "--index", INDEX_FILE,
138
+ "-b", "id",
139
+ "-o", out_dir,
140
+ "--scaffold-subdirs",
141
+ "-p", "2",
142
+ ]
143
+ result = subprocess.run(cmd, check=False, cwd=REPO_ROOT, capture_output=True, text=True)
144
+ assert result.returncode == 0, f"Unexpected non-zero exit: {result.stderr}"
145
+
146
+ # chr1 has 3 regions with real output (06-noalign has no overlap, so no
147
+ # file); chr4 has 2; chr2/chr3/chrX have 1 each. chrZ (09-missingchrom)
148
+ # never gets that far (unknown scaffold errors before any writes).
149
+ assert sorted(os.listdir(os.path.join(out_dir, "chr1"))) == [
150
+ "01-singleblock-gap.maf",
151
+ "02-truncatedblock.maf",
152
+ "03-crossblocks-missing.maf",
153
+ ]
154
+ assert os.listdir(os.path.join(out_dir, "chr2")) == ["04-singleblock.maf"]
155
+ assert os.listdir(os.path.join(out_dir, "chr3")) == ["05-crossblocks.maf"]
156
+ assert os.listdir(os.path.join(out_dir, "chrX")) == ["07-negstrand.maf"]
157
+ assert sorted(os.listdir(os.path.join(out_dir, "chr4"))) == [
158
+ "08-span-multiple-gaps.maf",
159
+ "10-crossblocks-missing-species.maf",
160
+ ]
161
+
162
+ # Content should be identical to the flat-layout output for the same region.
163
+ with open(os.path.join(out_dir, "chr2", "04-singleblock.maf")) as fp:
164
+ got = fp.read().rstrip("\n")
165
+ with open(os.path.join(EXPECTED_MAF_DIR, "04-singleblock.maf")) as fp:
166
+ expected = fp.read().rstrip("\n")
167
+ assert got == expected
168
+
169
+
170
+ def test_scaffold_subdirs_rejected_with_single_output(tmp_path):
171
+ cmd = [
172
+ sys.executable, "-m", "mafutils", "fetch",
173
+ MAF_FILE, BED_FILE,
174
+ "--index", INDEX_FILE,
175
+ "--scaffold-subdirs",
176
+ "--single-output",
177
+ "-o", os.path.join(str(tmp_path), "out.maf"),
178
+ ]
179
+ result = subprocess.run(cmd, check=False, cwd=REPO_ROOT, capture_output=True, text=True)
180
+ assert result.returncode != 0
181
+ assert "--scaffold-subdirs cannot be used with --single-output" in result.stderr
@@ -0,0 +1,115 @@
1
+ import csv
2
+ import os
3
+ import subprocess
4
+ import sys
5
+
6
+ TEST_DIR = os.path.dirname(__file__)
7
+ REPO_ROOT = os.path.abspath(os.path.join(TEST_DIR, ".."))
8
+
9
+ MAF_FILE = os.path.join(TEST_DIR, "real-excerpt.maf")
10
+ INDEX_FILE = os.path.join(TEST_DIR, "real-excerpt.maf.block.idx")
11
+
12
+ # 8 real, complete alignment blocks, extracted read-only from gwct's real
13
+ # ~42GB production MAF (data/hamsters/uncompressed/...), a couple GB in to
14
+ # skip past the initial all-N region. Unlike example.maf (hand-crafted, used
15
+ # to independently verify exact output values in test_stats.py/test_gc.py),
16
+ # this fixture exists to catch real-world-data surprises a hand-crafted
17
+ # fixture wouldn't think to include (real species-naming conventions, real
18
+ # gap patterns, real block-size distribution) -- so these tests check
19
+ # plausibility/robustness/"does it run cleanly on real data", not exact
20
+ # hand-computed values.
21
+ EXPECTED_SPECIES = {
22
+ "Phodopus_sungorus_new",
23
+ "Phodopus_campbelli",
24
+ "Phodopus_roborovskii",
25
+ "Cricetulus_griseus",
26
+ "Cricetus_cricetus",
27
+ "Dicrostonyx_torquatus",
28
+ "Peromyscus_maniculatus_North",
29
+ "Microtus_arvalis",
30
+ "Microtus_pennsylvanicus",
31
+ "Arvicola_amphibius",
32
+ "Neotoma_floridana",
33
+ "Mus_musculus",
34
+ "Rattus_norvegicus",
35
+ "Peromyscus_californicus",
36
+ "Onychomys_torridus",
37
+ }
38
+
39
+ # All 8 blocks are on the same real reference scaffold/coordinate range.
40
+ REAL_SCAFFOLD = "CM000994.3"
41
+ REAL_START = 125888838
42
+ REAL_END = 125891358 # last block's start (125891324) + size (34)
43
+
44
+
45
+ def run(cmd_args):
46
+ cmd = [sys.executable, "-m", "mafutils"] + cmd_args
47
+ return subprocess.run(cmd, check=False, cwd=REPO_ROOT, capture_output=True, text=True)
48
+
49
+
50
+ def read_overall(path):
51
+ with open(path, "r", encoding="utf-8") as fp:
52
+ lines = fp.readlines()[1:]
53
+ return dict(line.rstrip("\n").split("\t") for line in lines)
54
+
55
+
56
+ def test_stats_runs_cleanly_on_real_data(tmp_path):
57
+ out_prefix = os.path.join(str(tmp_path), "out")
58
+ result = run(["stats", MAF_FILE, INDEX_FILE, "-o", out_prefix])
59
+ assert result.returncode == 0, result.stderr
60
+
61
+ overall = read_overall(out_prefix + ".overall.tsv")
62
+ assert int(overall["total_blocks"]) == 8
63
+ assert int(overall["total_species"]) == 15
64
+ assert int(overall["total_parse_errors"]) == 0
65
+ assert int(overall["blocks_with_zero_parsed_seq_lines_but_index_nonzero"]) == 0
66
+
67
+
68
+ def test_stats_species_list_matches_known_species(tmp_path):
69
+ out_prefix = os.path.join(str(tmp_path), "out")
70
+ result = run(["stats", MAF_FILE, INDEX_FILE, "-o", out_prefix])
71
+ assert result.returncode == 0, result.stderr
72
+
73
+ with open(out_prefix + ".species.tsv", "r", encoding="utf-8") as fp:
74
+ reader = csv.DictReader(fp, delimiter="\t")
75
+ got_species = {row["species"] for row in reader}
76
+ assert got_species == EXPECTED_SPECIES
77
+
78
+
79
+ def test_gc_runs_cleanly_and_plausibly_on_real_data(tmp_path):
80
+ out_prefix = os.path.join(str(tmp_path), "out")
81
+ result = run(["gc", MAF_FILE, INDEX_FILE, "-o", out_prefix])
82
+ assert result.returncode == 0, result.stderr
83
+
84
+ with open(out_prefix + ".gc.csv", "r", encoding="utf-8") as fp:
85
+ reader = csv.DictReader(fp)
86
+ gc_values = {row["species"]: float(row["gc"]) for row in reader}
87
+
88
+ assert gc_values.keys() == EXPECTED_SPECIES
89
+ for species, gc in gc_values.items():
90
+ # Real rodent genomic GC content clusters tightly around 0.40-0.45 in
91
+ # this fixture; 0.30-0.55 gives real margin without being so loose it
92
+ # would miss a genuine encoding/parsing bug (e.g. counting gaps as GC).
93
+ assert 0.30 <= gc <= 0.55, f"{species}: implausible GC content {gc}"
94
+
95
+
96
+ def test_fetch_runs_cleanly_on_real_data(tmp_path):
97
+ bed_path = os.path.join(str(tmp_path), "region.bed")
98
+ with open(bed_path, "w", encoding="utf-8") as fp:
99
+ fp.write(f"{REAL_SCAFFOLD}\t{REAL_START}\t{REAL_END}\tregion1\n")
100
+
101
+ out_dir = str(tmp_path)
102
+ result = run([
103
+ "fetch", MAF_FILE, bed_path,
104
+ "--index", INDEX_FILE,
105
+ "-b", "id",
106
+ "-o", out_dir,
107
+ ])
108
+ assert result.returncode == 0, result.stderr
109
+
110
+ output_file = os.path.join(out_dir, "region1.maf")
111
+ assert os.path.isfile(output_file), "Expected fetch output file was not created"
112
+ with open(output_file, "r", encoding="utf-8") as fp:
113
+ content = fp.read()
114
+ assert content.count("\na") + content.startswith("a") >= 1, "Expected at least one alignment block in fetch output"
115
+ assert "Mus_musculus" in content
@@ -0,0 +1,143 @@
1
+ import csv
2
+ import os
3
+ import subprocess
4
+ import sys
5
+
6
+ import pytest
7
+
8
+ TEST_DIR = os.path.dirname(__file__)
9
+ REPO_ROOT = os.path.abspath(os.path.join(TEST_DIR, ".."))
10
+
11
+ MAF_FILE = os.path.join(TEST_DIR, "example.maf")
12
+ INDEX_FILE = os.path.join(TEST_DIR, "example.maf.block.idx")
13
+
14
+ # Hand-verified directly against tests/example.maf's raw content (10 blocks;
15
+ # human present in all 10, chimp in 8 [blocks 1,2,3,4,5,6,8,10], gorilla in 2
16
+ # [blocks 7,9]). Every block has exactly 2 taxa, so parsimony-informative
17
+ # sites (requiring >=2 states each seen >=2 times) are structurally
18
+ # impossible; variable sites occur only in block 3 (6 columns) and block 4
19
+ # (1 column), the only two blocks where both taxa have different non-gap
20
+ # bases in the same column.
21
+ EXPECTED_OVERALL = {
22
+ "total_blocks": 10,
23
+ "total_species": 3,
24
+ "total_alignment_columns": 61,
25
+ "total_sequence_lines": 20,
26
+ "all_gap_sites": 0,
27
+ "variable_sites": 7,
28
+ "invariant_sites": 54,
29
+ "parsimony_informative_sites": 0,
30
+ "total_parse_errors": 0,
31
+ "blocks_with_zero_parsed_seq_lines_but_index_nonzero": 0,
32
+ }
33
+
34
+ # blocks_present / gaps_total / nongaps_total per species, hand-counted
35
+ # directly from each block's raw sequence strings.
36
+ EXPECTED_SPECIES_RAW = {
37
+ "human": {"blocks_present": 10, "gaps_total": 3, "nongaps_total": 58},
38
+ "chimp": {"blocks_present": 8, "gaps_total": 11, "nongaps_total": 41},
39
+ "gorilla": {"blocks_present": 2, "gaps_total": 1, "nongaps_total": 8},
40
+ }
41
+
42
+
43
+ def run_stats(args):
44
+ cmd = [sys.executable, "-m", "mafutils", "stats"] + args
45
+ result = subprocess.run(cmd, check=False, cwd=REPO_ROOT, capture_output=True, text=True)
46
+ assert result.returncode == 0, f"stats failed (exit {result.returncode}):\n{result.stderr}"
47
+ return result
48
+
49
+
50
+ def read_overall(path):
51
+ with open(path, "r", encoding="utf-8") as fp:
52
+ lines = fp.readlines()[1:]
53
+ return dict(line.rstrip("\n").split("\t") for line in lines)
54
+
55
+
56
+ def read_species(path):
57
+ with open(path, "r", encoding="utf-8") as fp:
58
+ reader = csv.DictReader(fp, delimiter="\t")
59
+ return {row["species"]: row for row in reader}
60
+
61
+
62
+ def assert_overall_matches(overall):
63
+ for key, expected in EXPECTED_OVERALL.items():
64
+ assert int(overall[key]) == expected, f"{key}: expected {expected}, got {overall[key]}"
65
+
66
+
67
+ def assert_species_matches(species):
68
+ assert species.keys() == EXPECTED_SPECIES_RAW.keys()
69
+ for sp, expected in EXPECTED_SPECIES_RAW.items():
70
+ row = species[sp]
71
+ assert int(row["blocks_present"]) == expected["blocks_present"], sp
72
+ assert int(row["gaps_total"]) == expected["gaps_total"], sp
73
+ assert int(row["nongaps_total"]) == expected["nongaps_total"], sp
74
+
75
+ # Derived ratios computed from the hand-verified raw counts above,
76
+ # not hardcoded floats -- still an independent check of the formula
77
+ # application, without risking manual 8-decimal arithmetic errors.
78
+ blocks_present = expected["blocks_present"]
79
+ blocks_missing = 10 - blocks_present
80
+ total_cells = expected["gaps_total"] + expected["nongaps_total"]
81
+ assert int(row["blocks_missing"]) == blocks_missing, sp
82
+ assert float(row["presence_fraction"]) == pytest.approx(blocks_present / 10, abs=1e-6), sp
83
+ assert float(row["gap_fraction_cells"]) == pytest.approx(expected["gaps_total"] / total_cells, abs=1e-6), sp
84
+ assert float(row["avg_gaps_per_present_block"]) == pytest.approx(
85
+ expected["gaps_total"] / blocks_present, abs=1e-6
86
+ ), sp
87
+
88
+
89
+ def test_overall_stats_match_hand_verified_values(tmp_path):
90
+ out_prefix = os.path.join(str(tmp_path), "out")
91
+ run_stats([MAF_FILE, INDEX_FILE, "-o", out_prefix])
92
+ assert_overall_matches(read_overall(out_prefix + ".overall.tsv"))
93
+
94
+
95
+ def test_species_stats_match_hand_verified_values(tmp_path):
96
+ out_prefix = os.path.join(str(tmp_path), "out")
97
+ run_stats([MAF_FILE, INDEX_FILE, "-o", out_prefix])
98
+ assert_species_matches(read_species(out_prefix + ".species.tsv"))
99
+
100
+
101
+ def test_no_block_table_omits_block_file(tmp_path):
102
+ out_prefix = os.path.join(str(tmp_path), "out")
103
+ run_stats([MAF_FILE, INDEX_FILE, "-o", out_prefix, "--no-block-table"])
104
+ assert not os.path.exists(out_prefix + ".block.tsv")
105
+
106
+
107
+ def test_block_table_present_by_default(tmp_path):
108
+ out_prefix = os.path.join(str(tmp_path), "out")
109
+ run_stats([MAF_FILE, INDEX_FILE, "-o", out_prefix])
110
+ assert os.path.isfile(out_prefix + ".block.tsv")
111
+
112
+
113
+ def test_sequential_and_parallel_paths_produce_identical_output(tmp_path):
114
+ """
115
+ Regression guard for the processes=1 ProcessPoolExecutor-skip fix: the
116
+ direct in-process call (-p 1) and the real multi-worker pool path
117
+ (-p 2, forced into multiple chunks via a small --chunk-size) must
118
+ produce identical overall/species output, not just "doesn't crash".
119
+ """
120
+ seq_prefix = os.path.join(str(tmp_path), "seq")
121
+ par_prefix = os.path.join(str(tmp_path), "par")
122
+ run_stats([MAF_FILE, INDEX_FILE, "-o", seq_prefix, "-p", "1"])
123
+ run_stats([MAF_FILE, INDEX_FILE, "-o", par_prefix, "-p", "2", "--chunk-size", "3"])
124
+
125
+ assert read_overall(seq_prefix + ".overall.tsv") == read_overall(par_prefix + ".overall.tsv")
126
+ assert read_species(seq_prefix + ".species.tsv") == read_species(par_prefix + ".species.tsv")
127
+
128
+
129
+ def test_expected_species_file_reports_missing_species(tmp_path):
130
+ species_file = os.path.join(str(tmp_path), "species.txt")
131
+ with open(species_file, "w", encoding="utf-8") as fp:
132
+ fp.write("human\nchimp\ngorilla\norangutan\n")
133
+
134
+ out_prefix = os.path.join(str(tmp_path), "out")
135
+ run_stats([MAF_FILE, INDEX_FILE, "-o", out_prefix, "--expected-species-file", species_file])
136
+
137
+ overall = read_overall(out_prefix + ".overall.tsv")
138
+ assert int(overall["total_species"]) == 4 # 3 observed + 1 expected-but-absent
139
+
140
+ species = read_species(out_prefix + ".species.tsv")
141
+ assert "orangutan" in species
142
+ assert int(species["orangutan"]["blocks_present"]) == 0
143
+ assert int(species["orangutan"]["blocks_missing"]) == 10
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes