pytransdecoder 0.3.0__tar.gz → 0.4.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.
- {pytransdecoder-0.3.0/pytransdecoder.egg-info → pytransdecoder-0.4.0}/PKG-INFO +5 -3
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/README.md +4 -2
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pyproject.toml +1 -1
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/__init__.py +1 -1
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/cli.py +10 -4
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/writers.py +11 -11
- pytransdecoder-0.4.0/pytransdecoder/longorfs.py +247 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0/pytransdecoder.egg-info}/PKG-INFO +5 -3
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder.egg-info/SOURCES.txt +1 -0
- pytransdecoder-0.4.0/tests/test_longorfs_parallel.py +85 -0
- pytransdecoder-0.3.0/pytransdecoder/longorfs.py +0 -180
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/LICENSE +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/__main__.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/__init__.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/base_freqs.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/decoys.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/fasta.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/gene_model.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/gff3_parser.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/homology_starts.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/kozak.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/markov_fast.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/models.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/orf_finder.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/parallel.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/presets.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/prng.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/pwm.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/sequence.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/core/translator.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/genome.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/predict.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/hexamer.scores.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/kozak.tsv +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/preset.json +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/thresholds.tsv.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/training_orfs.cds.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/hexamer.scores.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/kozak.tsv +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/preset.json +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/thresholds.tsv.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/training_orfs.cds.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/hexamer.scores.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/kozak.tsv +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/preset.json +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/thresholds.tsv.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/training_orfs.cds.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/hexamer.scores.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/kozak.tsv +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/preset.json +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/thresholds.tsv.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/training_orfs.cds.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/hexamer.scores.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/kozak.tsv +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/preset.json +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/thresholds.tsv.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/training_orfs.cds.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/hexamer.scores.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/kozak.tsv +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/preset.json +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/thresholds.tsv.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/training_orfs.cds.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/hexamer.scores.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/kozak.tsv +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/preset.json +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/thresholds.tsv.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/training_orfs.cds.gz +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder.egg-info/dependency_links.txt +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder.egg-info/entry_points.txt +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder.egg-info/requires.txt +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder.egg-info/top_level.txt +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/setup.cfg +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/setup.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_basic.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_decoys.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_fasta.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_genome_bed.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_homology_starts.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_markov_fast.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_parallel.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_qvalue_modes.py +0 -0
- {pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/tests/test_translator_memo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytransdecoder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: TransDecoder, the original Perl version ported to Python by AI/LLMs with new features integrated
|
|
5
5
|
Author: Brian Haas, ported to python by AI/LLMs
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -81,6 +81,7 @@ This creates a directory `transcripts.fasta.transdecoder_dir/` with:
|
|
|
81
81
|
-O, --output-dir PATH Output directory
|
|
82
82
|
--gene-trans-map PATH Gene-to-transcript mapping file
|
|
83
83
|
--complete-orfs-only Only output complete ORFs
|
|
84
|
+
--cpu INT Worker processes (default: 1); the output does not depend on it
|
|
84
85
|
-v, --verbose Verbose output
|
|
85
86
|
```
|
|
86
87
|
|
|
@@ -179,8 +180,9 @@ pyTransdecoder -t transcripts.fasta --pfam-search-db Pfam-A.hmm
|
|
|
179
180
|
--decoy-seed INT Seed of the decoy shuffles (default: 42)
|
|
180
181
|
--preset NAME|DIR Models and thresholds from a preset instead of the input
|
|
181
182
|
(recommended below ~1,000 transcripts or for mostly partial sets)
|
|
182
|
-
--cpu INT Worker processes for scoring candidate and decoy ORFs
|
|
183
|
-
(default: 1); the output does
|
|
183
|
+
--cpu INT Worker processes for scoring candidate and decoy ORFs, and in
|
|
184
|
+
pyTransdecoder also for LongOrfs (default: 1); the output does
|
|
185
|
+
not depend on it
|
|
184
186
|
-G, --genetic-code TEXT Genetic code (default: Standard)
|
|
185
187
|
-v, --verbose Verbose output
|
|
186
188
|
```
|
|
@@ -60,6 +60,7 @@ This creates a directory `transcripts.fasta.transdecoder_dir/` with:
|
|
|
60
60
|
-O, --output-dir PATH Output directory
|
|
61
61
|
--gene-trans-map PATH Gene-to-transcript mapping file
|
|
62
62
|
--complete-orfs-only Only output complete ORFs
|
|
63
|
+
--cpu INT Worker processes (default: 1); the output does not depend on it
|
|
63
64
|
-v, --verbose Verbose output
|
|
64
65
|
```
|
|
65
66
|
|
|
@@ -158,8 +159,9 @@ pyTransdecoder -t transcripts.fasta --pfam-search-db Pfam-A.hmm
|
|
|
158
159
|
--decoy-seed INT Seed of the decoy shuffles (default: 42)
|
|
159
160
|
--preset NAME|DIR Models and thresholds from a preset instead of the input
|
|
160
161
|
(recommended below ~1,000 transcripts or for mostly partial sets)
|
|
161
|
-
--cpu INT Worker processes for scoring candidate and decoy ORFs
|
|
162
|
-
(default: 1); the output does
|
|
162
|
+
--cpu INT Worker processes for scoring candidate and decoy ORFs, and in
|
|
163
|
+
pyTransdecoder also for LongOrfs (default: 1); the output does
|
|
164
|
+
not depend on it
|
|
163
165
|
-G, --genetic-code TEXT Genetic code (default: Standard)
|
|
164
166
|
-v, --verbose Verbose output
|
|
165
167
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pytransdecoder"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "TransDecoder, the original Perl version ported to Python by AI/LLMs with new features integrated"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -80,6 +80,10 @@ Example:
|
|
|
80
80
|
help='Show version and exit'
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
+
parser.add_argument('--cpu', type=int, default=1, dest='cpu',
|
|
84
|
+
help="Worker processes for ORF extraction; the output does not depend on it "
|
|
85
|
+
"(default: %(default)s)")
|
|
86
|
+
|
|
83
87
|
parser.set_defaults(func=longorfs_cmd)
|
|
84
88
|
return parser
|
|
85
89
|
|
|
@@ -107,8 +111,8 @@ def _add_selection_args(parser):
|
|
|
107
111
|
parser.add_argument('--decoy-seed', type=int, default=DEFAULT_DECOY_SEED, dest='decoy_seed',
|
|
108
112
|
help="Seed of the decoy shuffles (default: %(default)s)")
|
|
109
113
|
parser.add_argument('--cpu', type=int, default=1, dest='cpu',
|
|
110
|
-
help="Worker processes for scoring candidate and decoy ORFs
|
|
111
|
-
"on it (default: %(default)s)")
|
|
114
|
+
help="Worker processes for scoring candidate and decoy ORFs (pyTransdecoder: also for "
|
|
115
|
+
"extracting ORFs); results do not depend on it (default: %(default)s)")
|
|
112
116
|
from .core.presets import bundled_presets
|
|
113
117
|
parser.add_argument('--preset', default=None,
|
|
114
118
|
help="Use a preset's coding model, start model and q-value thresholds instead of "
|
|
@@ -279,7 +283,8 @@ def longorfs_cmd(args):
|
|
|
279
283
|
output_dir=args.output_dir,
|
|
280
284
|
gene_trans_map_file=args.gene_trans_map,
|
|
281
285
|
complete_orfs_only=args.complete_orfs_only,
|
|
282
|
-
verbose=args.verbose
|
|
286
|
+
verbose=args.verbose,
|
|
287
|
+
cpu=args.cpu
|
|
283
288
|
)
|
|
284
289
|
except Exception as e:
|
|
285
290
|
print(f"Error: {e}", file=sys.stderr)
|
|
@@ -496,7 +501,8 @@ def pipeline_cmd(args):
|
|
|
496
501
|
output_dir=args.output_dir,
|
|
497
502
|
gene_trans_map_file=args.gene_trans_map,
|
|
498
503
|
complete_orfs_only=args.complete_orfs_only,
|
|
499
|
-
verbose=args.verbose
|
|
504
|
+
verbose=args.verbose,
|
|
505
|
+
cpu=args.cpu
|
|
500
506
|
)
|
|
501
507
|
except Exception as e:
|
|
502
508
|
print(f"Error during LongOrfs phase: {e}", file=sys.stderr)
|
|
@@ -56,14 +56,14 @@ class FastaWriter:
|
|
|
56
56
|
sequence: Sequence string
|
|
57
57
|
wrap: Line width for wrapping (0 = no wrap)
|
|
58
58
|
"""
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
self.file.write(fasta_entry(header, sequence, wrap))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def fasta_entry(header: str, sequence: str, wrap: int = 60) -> str:
|
|
63
|
+
"""One FASTA record as text: header line (a '>' is added if missing), then the sequence
|
|
64
|
+
in lines of `wrap` characters (0 = one line)."""
|
|
65
|
+
if not header.startswith('>'):
|
|
66
|
+
header = '>' + header
|
|
67
|
+
if wrap > 0:
|
|
68
|
+
return header + '\n' + ''.join(sequence[i:i + wrap] + '\n' for i in range(0, len(sequence), wrap))
|
|
69
|
+
return header + '\n' + sequence + '\n'
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TransDecoder.LongOrfs - Extract long ORFs from transcript sequences
|
|
3
|
+
|
|
4
|
+
Phase 1 of TransDecoder pipeline.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, Dict
|
|
10
|
+
from .core.fasta import read_fasta
|
|
11
|
+
from tqdm import tqdm
|
|
12
|
+
|
|
13
|
+
from .core.orf_finder import ORFFinder
|
|
14
|
+
from .core.writers import fasta_entry
|
|
15
|
+
from .core.base_freqs import write_base_frequencies
|
|
16
|
+
|
|
17
|
+
# Minimum ORF length (aa). Predict's decoy q-values (stratified by ORF length) decide how much coding
|
|
18
|
+
# evidence short ORFs need.
|
|
19
|
+
DEFAULT_MIN_PROTEIN_LENGTH = 50
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def run_longorfs(
|
|
23
|
+
transcripts_file: Path,
|
|
24
|
+
min_protein_length: int = DEFAULT_MIN_PROTEIN_LENGTH,
|
|
25
|
+
genetic_code: str = "universal",
|
|
26
|
+
strand_specific: bool = False,
|
|
27
|
+
output_dir: Optional[Path] = None,
|
|
28
|
+
gene_trans_map_file: Optional[Path] = None,
|
|
29
|
+
complete_orfs_only: bool = False,
|
|
30
|
+
verbose: bool = False,
|
|
31
|
+
cpu: int = 1
|
|
32
|
+
):
|
|
33
|
+
"""
|
|
34
|
+
Extract long ORFs from transcripts (Phase 1).
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
transcripts_file: Input FASTA file
|
|
38
|
+
min_protein_length: Minimum protein length in amino acids
|
|
39
|
+
genetic_code: Genetic code name
|
|
40
|
+
strand_specific: Only analyze top strand
|
|
41
|
+
output_dir: Output directory
|
|
42
|
+
gene_trans_map_file: Gene to transcript mapping file
|
|
43
|
+
complete_orfs_only: Only output complete ORFs
|
|
44
|
+
verbose: Verbose output
|
|
45
|
+
cpu: Worker processes for ORF extraction (output does not depend on it)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# Set up output directory
|
|
49
|
+
if output_dir is None:
|
|
50
|
+
output_dir = Path.cwd()
|
|
51
|
+
output_dir = Path(output_dir)
|
|
52
|
+
|
|
53
|
+
# Create transdecoder_dir
|
|
54
|
+
workdir = output_dir / f"{transcripts_file.name}.transdecoder_dir"
|
|
55
|
+
workdir.mkdir(parents=True, exist_ok=True)
|
|
56
|
+
|
|
57
|
+
if verbose:
|
|
58
|
+
print(f"Output directory: {workdir}", file=sys.stderr)
|
|
59
|
+
|
|
60
|
+
# Load gene-transcript mapping if provided
|
|
61
|
+
gene_trans_map = {}
|
|
62
|
+
if gene_trans_map_file:
|
|
63
|
+
with open(gene_trans_map_file) as f:
|
|
64
|
+
for line in f:
|
|
65
|
+
parts = line.strip().split('\t')
|
|
66
|
+
if len(parts) >= 2:
|
|
67
|
+
gene_id, trans_id = parts[0], parts[1]
|
|
68
|
+
gene_trans_map[trans_id] = gene_id
|
|
69
|
+
|
|
70
|
+
# LongOrfs settings, for Predict's decoy ORFs (same finder settings on shuffled transcripts)
|
|
71
|
+
import json
|
|
72
|
+
with open(workdir / "longorfs.params.json", "w") as fh:
|
|
73
|
+
json.dump({"min_protein_length": min_protein_length, "genetic_code": genetic_code,
|
|
74
|
+
"strand_specific": bool(strand_specific),
|
|
75
|
+
"complete_orfs_only": bool(complete_orfs_only)}, fh, indent=1)
|
|
76
|
+
|
|
77
|
+
# Output files
|
|
78
|
+
prefix = workdir / "longest_orfs"
|
|
79
|
+
cds_file = prefix.with_suffix('.cds')
|
|
80
|
+
gff3_file = prefix.with_suffix('.gff3')
|
|
81
|
+
pep_file = prefix.with_suffix('.pep')
|
|
82
|
+
|
|
83
|
+
finder_args = dict(
|
|
84
|
+
min_protein_length=min_protein_length,
|
|
85
|
+
allow_5prime_partial=not complete_orfs_only,
|
|
86
|
+
allow_3prime_partial=not complete_orfs_only,
|
|
87
|
+
forward_strand=True,
|
|
88
|
+
reverse_strand=not strand_specific,
|
|
89
|
+
genetic_code=genetic_code,
|
|
90
|
+
complete_orfs_only=complete_orfs_only
|
|
91
|
+
)
|
|
92
|
+
settings = (finder_args, gene_trans_map, genetic_code, strand_specific)
|
|
93
|
+
cpu = max(1, int(cpu))
|
|
94
|
+
|
|
95
|
+
if verbose:
|
|
96
|
+
print("\n\n- extracting ORFs from transcripts.\n", file=sys.stderr)
|
|
97
|
+
|
|
98
|
+
if cpu == 1:
|
|
99
|
+
# one pass over the input, streamed (a counting pass for the progress bar only when verbose)
|
|
100
|
+
total_transcripts = sum(1 for _ in read_fasta(transcripts_file)) if verbose else None
|
|
101
|
+
chunks = _batches(((r.id, str(r.seq)) for r in read_fasta(transcripts_file)), SERIAL_BATCH)
|
|
102
|
+
else:
|
|
103
|
+
records = [(r.id, str(r.seq)) for r in read_fasta(transcripts_file)]
|
|
104
|
+
total_transcripts = len(records)
|
|
105
|
+
# Model IDs are <acc>.p1, .p2, ... numbered within a transcript; IDs of different accessions
|
|
106
|
+
# never coincide (the last '.p' of an ID starts its numeric suffix), so chunks can be numbered
|
|
107
|
+
# independently. A repeated accession continues the numbering of its earlier copy, so inputs
|
|
108
|
+
# with repeated accessions are processed in one chunk.
|
|
109
|
+
n_repeated = total_transcripts - len({acc for acc, _ in records})
|
|
110
|
+
if n_repeated:
|
|
111
|
+
print(f"Warning: {n_repeated} repeated transcript accessions; extracting ORFs in a single "
|
|
112
|
+
f"process", file=sys.stderr)
|
|
113
|
+
chunks, cpu = [records], 1
|
|
114
|
+
else:
|
|
115
|
+
chunks = _chunks_by_size(records, cpu * 16)
|
|
116
|
+
del records
|
|
117
|
+
|
|
118
|
+
if verbose:
|
|
119
|
+
print(f"-total transcripts to examine: {total_transcripts}\n", file=sys.stderr)
|
|
120
|
+
|
|
121
|
+
base_counts = {base: 0 for base in 'ACGT'}
|
|
122
|
+
progress = tqdm(total=total_transcripts, desc="Processing transcripts", disable=not verbose,
|
|
123
|
+
file=sys.stderr)
|
|
124
|
+
with open(gff3_file, 'w') as gff_fh, open(cds_file, 'w') as cds_fh, open(pep_file, 'w') as pep_fh:
|
|
125
|
+
gff_fh.write("##gff-version 3\n")
|
|
126
|
+
for n, counts, gff, cds, pep in _map_chunks(chunks, settings, cpu):
|
|
127
|
+
for base in 'ACGT':
|
|
128
|
+
base_counts[base] += counts[base]
|
|
129
|
+
gff_fh.write(gff)
|
|
130
|
+
cds_fh.write(cds)
|
|
131
|
+
pep_fh.write(pep)
|
|
132
|
+
progress.update(n)
|
|
133
|
+
progress.close()
|
|
134
|
+
|
|
135
|
+
# Base frequencies (the per-chunk counts are integers, so their sum is exact)
|
|
136
|
+
write_base_frequencies(base_counts, str(workdir / "base_freqs.dat"))
|
|
137
|
+
|
|
138
|
+
# Print summary
|
|
139
|
+
if verbose:
|
|
140
|
+
print(f"\n\n#################################", file=sys.stderr)
|
|
141
|
+
print(f"### Done preparing long ORFs ###", file=sys.stderr)
|
|
142
|
+
print(f"##################################", file=sys.stderr)
|
|
143
|
+
print(f"\n\tUse file: {pep_file} for Pfam and/or BlastP searches to enable homology-based coding region identification.\n\n", file=sys.stderr)
|
|
144
|
+
print(f"\tThen, run TransDecoder.Predict\n\n", file=sys.stderr)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# -- ORF extraction of chunks of transcripts (in this process or in worker processes) -------------
|
|
148
|
+
|
|
149
|
+
_SETTINGS = None
|
|
150
|
+
_SEEN_PROT_IDS: set = set()
|
|
151
|
+
SERIAL_BATCH = 2000 # transcripts per batch when streaming with --cpu 1
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _init_worker(settings):
|
|
155
|
+
"""Settings, and one set of issued model IDs per process for the whole run."""
|
|
156
|
+
global _SETTINGS, _SEEN_PROT_IDS
|
|
157
|
+
_SETTINGS = settings
|
|
158
|
+
_SEEN_PROT_IDS = set()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _extract_chunk(records):
|
|
162
|
+
"""(n transcripts, base counts, gff3 text, cds text, pep text) of an iterable of (acc, sequence),
|
|
163
|
+
numbering model IDs as the original single loop does."""
|
|
164
|
+
finder_args, gene_trans_map, genetic_code, strand_specific = _SETTINGS
|
|
165
|
+
orf_finder = ORFFinder(**finder_args)
|
|
166
|
+
complement = {'A': 'T', 'T': 'A', 'G': 'C', 'C': 'G'}
|
|
167
|
+
counts = {base: 0 for base in 'ACGT'}
|
|
168
|
+
gff, cds, pep = [], [], []
|
|
169
|
+
seen_prot_ids = _SEEN_PROT_IDS
|
|
170
|
+
n = 0
|
|
171
|
+
for acc, sequence in records:
|
|
172
|
+
n += 1
|
|
173
|
+
# base counts, as core.base_freqs.compute_base_counts
|
|
174
|
+
useq = sequence.upper()
|
|
175
|
+
for base in 'ACGT':
|
|
176
|
+
k = useq.count(base)
|
|
177
|
+
counts[base] += k
|
|
178
|
+
if not strand_specific:
|
|
179
|
+
counts[complement[base]] += k
|
|
180
|
+
|
|
181
|
+
for orf in orf_finder.find_all_orfs(sequence, acc):
|
|
182
|
+
# Generate unique model ID
|
|
183
|
+
pcounter = 1
|
|
184
|
+
model_id = f"{acc}.p{pcounter}"
|
|
185
|
+
while model_id in seen_prot_ids:
|
|
186
|
+
pcounter += 1
|
|
187
|
+
model_id = f"{acc}.p{pcounter}"
|
|
188
|
+
seen_prot_ids.add(model_id)
|
|
189
|
+
|
|
190
|
+
gene_id = gene_trans_map.get(acc, f"GENE.{acc}")
|
|
191
|
+
gene_id = f"{gene_id}~~{model_id}"
|
|
192
|
+
|
|
193
|
+
orf.model_id = model_id
|
|
194
|
+
orf.gene_id = gene_id
|
|
195
|
+
orf.description = f"ORF type:{orf.orf_type} ({orf.strand})"
|
|
196
|
+
|
|
197
|
+
gff.append(orf.to_gff3() + "\n")
|
|
198
|
+
cds.append(fasta_entry(
|
|
199
|
+
f">{model_id} type:{orf.orf_type} {acc}:{orf.start}-{orf.end}({orf.strand})", orf.sequence))
|
|
200
|
+
pep.append(fasta_entry(
|
|
201
|
+
f">{model_id} type:{orf.orf_type} gc:{genetic_code} {acc}:{orf.start}-{orf.end}({orf.strand})",
|
|
202
|
+
orf.protein))
|
|
203
|
+
return n, counts, "".join(gff), "".join(cds), "".join(pep)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _batches(it, size):
|
|
207
|
+
"""Consecutive lists of up to `size` items of an iterator."""
|
|
208
|
+
from itertools import islice
|
|
209
|
+
while True:
|
|
210
|
+
b = list(islice(it, size))
|
|
211
|
+
if not b:
|
|
212
|
+
return
|
|
213
|
+
yield b
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _chunks_by_size(records, n_chunks):
|
|
217
|
+
"""Consecutive chunks of roughly equal total sequence length (order preserved)."""
|
|
218
|
+
total = sum(len(s) for _, s in records) or 1
|
|
219
|
+
target = total / n_chunks
|
|
220
|
+
chunks, cur, acc = [], [], 0
|
|
221
|
+
for rec in records:
|
|
222
|
+
cur.append(rec)
|
|
223
|
+
acc += len(rec[1])
|
|
224
|
+
if acc >= target:
|
|
225
|
+
chunks.append(cur)
|
|
226
|
+
cur, acc = [], 0
|
|
227
|
+
if cur:
|
|
228
|
+
chunks.append(cur)
|
|
229
|
+
return chunks
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _map_chunks(chunks, settings, cpu):
|
|
233
|
+
"""_extract_chunk results in chunk order."""
|
|
234
|
+
if cpu <= 1:
|
|
235
|
+
_init_worker(settings)
|
|
236
|
+
try:
|
|
237
|
+
for c in chunks:
|
|
238
|
+
yield _extract_chunk(c)
|
|
239
|
+
finally:
|
|
240
|
+
_init_worker(None) # release the ID set
|
|
241
|
+
return
|
|
242
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
243
|
+
import multiprocessing as mp
|
|
244
|
+
ctx = mp.get_context("fork") if "fork" in mp.get_all_start_methods() else None
|
|
245
|
+
with ProcessPoolExecutor(max_workers=cpu, mp_context=ctx, initializer=_init_worker,
|
|
246
|
+
initargs=(settings,)) as ex:
|
|
247
|
+
yield from ex.map(_extract_chunk, chunks)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytransdecoder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: TransDecoder, the original Perl version ported to Python by AI/LLMs with new features integrated
|
|
5
5
|
Author: Brian Haas, ported to python by AI/LLMs
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -81,6 +81,7 @@ This creates a directory `transcripts.fasta.transdecoder_dir/` with:
|
|
|
81
81
|
-O, --output-dir PATH Output directory
|
|
82
82
|
--gene-trans-map PATH Gene-to-transcript mapping file
|
|
83
83
|
--complete-orfs-only Only output complete ORFs
|
|
84
|
+
--cpu INT Worker processes (default: 1); the output does not depend on it
|
|
84
85
|
-v, --verbose Verbose output
|
|
85
86
|
```
|
|
86
87
|
|
|
@@ -179,8 +180,9 @@ pyTransdecoder -t transcripts.fasta --pfam-search-db Pfam-A.hmm
|
|
|
179
180
|
--decoy-seed INT Seed of the decoy shuffles (default: 42)
|
|
180
181
|
--preset NAME|DIR Models and thresholds from a preset instead of the input
|
|
181
182
|
(recommended below ~1,000 transcripts or for mostly partial sets)
|
|
182
|
-
--cpu INT Worker processes for scoring candidate and decoy ORFs
|
|
183
|
-
(default: 1); the output does
|
|
183
|
+
--cpu INT Worker processes for scoring candidate and decoy ORFs, and in
|
|
184
|
+
pyTransdecoder also for LongOrfs (default: 1); the output does
|
|
185
|
+
not depend on it
|
|
184
186
|
-G, --genetic-code TEXT Genetic code (default: Standard)
|
|
185
187
|
-v, --verbose Verbose output
|
|
186
188
|
```
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""LongOrfs --cpu: output files identical to the single-process run."""
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from pytransdecoder.longorfs import run_longorfs
|
|
9
|
+
|
|
10
|
+
FILES = ["longest_orfs.gff3", "longest_orfs.cds", "longest_orfs.pep", "base_freqs.dat",
|
|
11
|
+
"longorfs.params.json"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _random_fasta(path: Path, ids, seed=7):
|
|
15
|
+
rng = random.Random(seed)
|
|
16
|
+
with open(path, "w") as fh:
|
|
17
|
+
for i, acc in enumerate(ids):
|
|
18
|
+
n = rng.randint(100, 3000)
|
|
19
|
+
# coding-like stretches (no in-frame stop) mixed with random sequence, some IUPAC / lowercase
|
|
20
|
+
seq = "".join(rng.choice("ACGT") for _ in range(n))
|
|
21
|
+
if i % 3 == 0:
|
|
22
|
+
body = "".join(rng.choice(["GCT", "AAA", "CTG", "GAG", "TCC", "ATG"]) for _ in range(150))
|
|
23
|
+
seq = seq[:50] + "ATG" + body + "TAA" + seq[50:]
|
|
24
|
+
if i % 5 == 0:
|
|
25
|
+
seq = seq[:30] + "N" + seq[31:]
|
|
26
|
+
if i % 7 == 0:
|
|
27
|
+
seq = seq.lower()
|
|
28
|
+
fh.write(f">{acc} desc {i}\n")
|
|
29
|
+
for k in range(0, len(seq), 70):
|
|
30
|
+
fh.write(seq[k:k + 70] + "\n")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _run(tmp_path, name, fasta, cpu, **kw):
|
|
34
|
+
out = tmp_path / name
|
|
35
|
+
out.mkdir()
|
|
36
|
+
run_longorfs(fasta, output_dir=out, cpu=cpu, **kw)
|
|
37
|
+
d = out / f"{fasta.name}.transdecoder_dir"
|
|
38
|
+
return {f: (d / f).read_bytes() for f in FILES}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.mark.parametrize("strand_specific", [False, True])
|
|
42
|
+
@pytest.mark.parametrize("genetic_code", ["universal", "Tetrahymena"])
|
|
43
|
+
def test_cpu_parity(tmp_path, strand_specific, genetic_code):
|
|
44
|
+
ids = [f"tx{i}" for i in range(120)] + ["A", "A.p1", "A.p1.p", "B.p2"] # IDs that look like model IDs
|
|
45
|
+
fasta = tmp_path / "t.fa"
|
|
46
|
+
_random_fasta(fasta, ids)
|
|
47
|
+
kw = dict(strand_specific=strand_specific, genetic_code=genetic_code, min_protein_length=30)
|
|
48
|
+
one = _run(tmp_path, "c1", fasta, 1, **kw)
|
|
49
|
+
assert one["longest_orfs.pep"].count(b">") > 50
|
|
50
|
+
import pytransdecoder.longorfs as lo
|
|
51
|
+
lo.SERIAL_BATCH, keep = 7, lo.SERIAL_BATCH
|
|
52
|
+
try:
|
|
53
|
+
assert _run(tmp_path, "c1b", fasta, 1, **kw) == one
|
|
54
|
+
finally:
|
|
55
|
+
lo.SERIAL_BATCH = keep
|
|
56
|
+
for cpu in (2, 3, 8):
|
|
57
|
+
assert _run(tmp_path, f"c{cpu}", fasta, cpu, **kw) == one
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.parametrize("batch", [2000, 3])
|
|
61
|
+
def test_repeated_accessions(tmp_path, monkeypatch, batch):
|
|
62
|
+
"""A repeated accession continues the .pN numbering of its earlier copy, at any --cpu and
|
|
63
|
+
across the batches of the streamed single-process run."""
|
|
64
|
+
import pytransdecoder.longorfs as lo
|
|
65
|
+
monkeypatch.setattr(lo, "SERIAL_BATCH", batch)
|
|
66
|
+
ids = [f"tx{i}" for i in range(40)] + ["tx3", "tx0", "tx3"]
|
|
67
|
+
fasta = tmp_path / "t.fa"
|
|
68
|
+
_random_fasta(fasta, ids)
|
|
69
|
+
one = _run(tmp_path, "c1", fasta, 1, min_protein_length=30)
|
|
70
|
+
assert _run(tmp_path, "c4", fasta, 4, min_protein_length=30) == one
|
|
71
|
+
pep = one["longest_orfs.pep"].decode()
|
|
72
|
+
tx3 = [l.split()[0] for l in pep.splitlines() if l.startswith(">tx3.p")]
|
|
73
|
+
assert len(tx3) == len(set(tx3)) > 1
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_gene_trans_map_and_complete_only(tmp_path):
|
|
77
|
+
ids = [f"tx{i}" for i in range(60)]
|
|
78
|
+
fasta = tmp_path / "t.fa"
|
|
79
|
+
_random_fasta(fasta, ids)
|
|
80
|
+
gtm = tmp_path / "gtm.tsv"
|
|
81
|
+
gtm.write_text("".join(f"gene{i // 2}\ttx{i}\n" for i in range(0, 60, 3)))
|
|
82
|
+
for kw in (dict(gene_trans_map_file=gtm), dict(complete_orfs_only=True)):
|
|
83
|
+
kw["min_protein_length"] = 30
|
|
84
|
+
one = _run(tmp_path, f"c1_{len(kw)}_{'g' if 'gene_trans_map_file' in kw else 'c'}", fasta, 1, **kw)
|
|
85
|
+
assert _run(tmp_path, f"c3_{'g' if 'gene_trans_map_file' in kw else 'c'}", fasta, 3, **kw) == one
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
TransDecoder.LongOrfs - Extract long ORFs from transcript sequences
|
|
3
|
-
|
|
4
|
-
Phase 1 of TransDecoder pipeline.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import sys
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from typing import Optional, Dict
|
|
10
|
-
from collections import defaultdict
|
|
11
|
-
from .core.fasta import read_fasta
|
|
12
|
-
from tqdm import tqdm
|
|
13
|
-
|
|
14
|
-
from .core.orf_finder import ORFFinder
|
|
15
|
-
from .core.models import ORF
|
|
16
|
-
from .core.writers import GFF3Writer, FastaWriter
|
|
17
|
-
from .core.base_freqs import compute_base_counts, write_base_frequencies
|
|
18
|
-
|
|
19
|
-
# Minimum ORF length (aa). Predict's decoy q-values (stratified by ORF length) decide how much coding
|
|
20
|
-
# evidence short ORFs need.
|
|
21
|
-
DEFAULT_MIN_PROTEIN_LENGTH = 50
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def run_longorfs(
|
|
25
|
-
transcripts_file: Path,
|
|
26
|
-
min_protein_length: int = DEFAULT_MIN_PROTEIN_LENGTH,
|
|
27
|
-
genetic_code: str = "universal",
|
|
28
|
-
strand_specific: bool = False,
|
|
29
|
-
output_dir: Optional[Path] = None,
|
|
30
|
-
gene_trans_map_file: Optional[Path] = None,
|
|
31
|
-
complete_orfs_only: bool = False,
|
|
32
|
-
verbose: bool = False
|
|
33
|
-
):
|
|
34
|
-
"""
|
|
35
|
-
Extract long ORFs from transcripts (Phase 1).
|
|
36
|
-
|
|
37
|
-
Args:
|
|
38
|
-
transcripts_file: Input FASTA file
|
|
39
|
-
min_protein_length: Minimum protein length in amino acids
|
|
40
|
-
genetic_code: Genetic code name
|
|
41
|
-
strand_specific: Only analyze top strand
|
|
42
|
-
output_dir: Output directory
|
|
43
|
-
gene_trans_map_file: Gene to transcript mapping file
|
|
44
|
-
complete_orfs_only: Only output complete ORFs
|
|
45
|
-
verbose: Verbose output
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
# Set up output directory
|
|
49
|
-
if output_dir is None:
|
|
50
|
-
output_dir = Path.cwd()
|
|
51
|
-
output_dir = Path(output_dir)
|
|
52
|
-
|
|
53
|
-
# Create transdecoder_dir
|
|
54
|
-
workdir = output_dir / f"{transcripts_file.name}.transdecoder_dir"
|
|
55
|
-
workdir.mkdir(parents=True, exist_ok=True)
|
|
56
|
-
|
|
57
|
-
if verbose:
|
|
58
|
-
print(f"Output directory: {workdir}", file=sys.stderr)
|
|
59
|
-
|
|
60
|
-
# Load gene-transcript mapping if provided
|
|
61
|
-
gene_trans_map = {}
|
|
62
|
-
if gene_trans_map_file:
|
|
63
|
-
with open(gene_trans_map_file) as f:
|
|
64
|
-
for line in f:
|
|
65
|
-
parts = line.strip().split('\t')
|
|
66
|
-
if len(parts) >= 2:
|
|
67
|
-
gene_id, trans_id = parts[0], parts[1]
|
|
68
|
-
gene_trans_map[trans_id] = gene_id
|
|
69
|
-
|
|
70
|
-
# LongOrfs settings, for Predict's decoy ORFs (same finder settings on shuffled transcripts)
|
|
71
|
-
import json
|
|
72
|
-
with open(workdir / "longorfs.params.json", "w") as fh:
|
|
73
|
-
json.dump({"min_protein_length": min_protein_length, "genetic_code": genetic_code,
|
|
74
|
-
"strand_specific": bool(strand_specific),
|
|
75
|
-
"complete_orfs_only": bool(complete_orfs_only)}, fh, indent=1)
|
|
76
|
-
|
|
77
|
-
# Step 1: Compute base frequencies
|
|
78
|
-
if verbose:
|
|
79
|
-
print("\n\n-first extracting base frequencies, we'll need them later.\n", file=sys.stderr)
|
|
80
|
-
|
|
81
|
-
base_freqs_file = workdir / "base_freqs.dat"
|
|
82
|
-
base_counts = compute_base_counts(str(transcripts_file), strand_specific)
|
|
83
|
-
write_base_frequencies(base_counts, str(base_freqs_file))
|
|
84
|
-
|
|
85
|
-
# Step 2: Extract ORFs
|
|
86
|
-
if verbose:
|
|
87
|
-
print("\n\n- extracting ORFs from transcripts.\n", file=sys.stderr)
|
|
88
|
-
|
|
89
|
-
# Initialize ORF finder
|
|
90
|
-
orf_finder = ORFFinder(
|
|
91
|
-
min_protein_length=min_protein_length,
|
|
92
|
-
allow_5prime_partial=not complete_orfs_only,
|
|
93
|
-
allow_3prime_partial=not complete_orfs_only,
|
|
94
|
-
forward_strand=True,
|
|
95
|
-
reverse_strand=not strand_specific,
|
|
96
|
-
genetic_code=genetic_code,
|
|
97
|
-
complete_orfs_only=complete_orfs_only
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
# Output files
|
|
101
|
-
prefix = workdir / "longest_orfs"
|
|
102
|
-
cds_file = prefix.with_suffix('.cds')
|
|
103
|
-
gff3_file = prefix.with_suffix('.gff3')
|
|
104
|
-
pep_file = prefix.with_suffix('.pep')
|
|
105
|
-
|
|
106
|
-
# Count total transcripts for progress bar
|
|
107
|
-
total_transcripts = sum(1 for _ in read_fasta(transcripts_file))
|
|
108
|
-
|
|
109
|
-
if verbose:
|
|
110
|
-
print(f"-total transcripts to examine: {total_transcripts}\n", file=sys.stderr)
|
|
111
|
-
|
|
112
|
-
# Process transcripts
|
|
113
|
-
model_counter = 0
|
|
114
|
-
trans_counter = 0
|
|
115
|
-
seen_prot_ids = set()
|
|
116
|
-
|
|
117
|
-
with GFF3Writer(gff3_file) as gff_writer, \
|
|
118
|
-
FastaWriter(cds_file) as cds_writer, \
|
|
119
|
-
FastaWriter(pep_file) as pep_writer:
|
|
120
|
-
|
|
121
|
-
progress = tqdm(
|
|
122
|
-
read_fasta(transcripts_file),
|
|
123
|
-
total=total_transcripts,
|
|
124
|
-
desc="Processing transcripts",
|
|
125
|
-
disable=not verbose,
|
|
126
|
-
file=sys.stderr
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
for record in progress:
|
|
130
|
-
trans_counter += 1
|
|
131
|
-
|
|
132
|
-
acc = record.id
|
|
133
|
-
sequence = str(record.seq)
|
|
134
|
-
|
|
135
|
-
# Find all ORFs
|
|
136
|
-
orfs = orf_finder.find_all_orfs(sequence, acc)
|
|
137
|
-
|
|
138
|
-
# Process each ORF
|
|
139
|
-
for orf in orfs:
|
|
140
|
-
model_counter += 1
|
|
141
|
-
|
|
142
|
-
# Generate unique model ID
|
|
143
|
-
pcounter = 1
|
|
144
|
-
model_id = f"{acc}.p{pcounter}"
|
|
145
|
-
while model_id in seen_prot_ids:
|
|
146
|
-
pcounter += 1
|
|
147
|
-
model_id = f"{acc}.p{pcounter}"
|
|
148
|
-
seen_prot_ids.add(model_id)
|
|
149
|
-
|
|
150
|
-
# Generate gene ID
|
|
151
|
-
if acc in gene_trans_map:
|
|
152
|
-
gene_id = gene_trans_map[acc]
|
|
153
|
-
else:
|
|
154
|
-
gene_id = f"GENE.{acc}"
|
|
155
|
-
|
|
156
|
-
gene_id = f"{gene_id}~~{model_id}"
|
|
157
|
-
|
|
158
|
-
# Update ORF with IDs
|
|
159
|
-
orf.model_id = model_id
|
|
160
|
-
orf.gene_id = gene_id
|
|
161
|
-
orf.description = f"ORF type:{orf.orf_type} ({orf.strand})"
|
|
162
|
-
|
|
163
|
-
# Write outputs
|
|
164
|
-
gff_writer.write_orf(orf)
|
|
165
|
-
|
|
166
|
-
# Write CDS
|
|
167
|
-
cds_header = f">{model_id} type:{orf.orf_type} {acc}:{orf.start}-{orf.end}({orf.strand})"
|
|
168
|
-
cds_writer.write_sequence(cds_header, orf.sequence)
|
|
169
|
-
|
|
170
|
-
# Write protein
|
|
171
|
-
pep_header = f">{model_id} type:{orf.orf_type} gc:{genetic_code} {acc}:{orf.start}-{orf.end}({orf.strand})"
|
|
172
|
-
pep_writer.write_sequence(pep_header, orf.protein)
|
|
173
|
-
|
|
174
|
-
# Print summary
|
|
175
|
-
if verbose:
|
|
176
|
-
print(f"\n\n#################################", file=sys.stderr)
|
|
177
|
-
print(f"### Done preparing long ORFs ###", file=sys.stderr)
|
|
178
|
-
print(f"##################################", file=sys.stderr)
|
|
179
|
-
print(f"\n\tUse file: {pep_file} for Pfam and/or BlastP searches to enable homology-based coding region identification.\n\n", file=sys.stderr)
|
|
180
|
-
print(f"\tThen, run TransDecoder.Predict\n\n", file=sys.stderr)
|
|
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
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/hexamer.scores.gz
RENAMED
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/preset.json
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/apicomplexan/thresholds.tsv.gz
RENAMED
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/hexamer.scores.gz
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/thresholds.tsv.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/ciliate/training_orfs.cds.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/hexamer.scores.gz
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/thresholds.tsv.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/fungus/training_orfs.cds.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/hexamer.scores.gz
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/thresholds.tsv.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/green_alga/training_orfs.cds.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/hexamer.scores.gz
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/thresholds.tsv.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/insect/training_orfs.cds.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/hexamer.scores.gz
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/thresholds.tsv.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/mammal/training_orfs.cds.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/hexamer.scores.gz
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/thresholds.tsv.gz
RENAMED
|
File without changes
|
{pytransdecoder-0.3.0 → pytransdecoder-0.4.0}/pytransdecoder/presets/plant/training_orfs.cds.gz
RENAMED
|
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
|