oligraph 0.2.0__tar.gz → 0.2.2__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.
- {oligraph-0.2.0 → oligraph-0.2.2}/Cargo.lock +1 -1
- {oligraph-0.2.0 → oligraph-0.2.2}/PKG-INFO +22 -1
- {oligraph-0.2.0 → oligraph-0.2.2}/README.md +21 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/pyproject.toml +5 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/python/Cargo.toml +1 -1
- oligraph-0.2.2/python/oligraph/__main__.py +146 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/Cargo.toml +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/LICENSE +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/oligraph-rs/Cargo.toml +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/oligraph-rs/src/lib.rs +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/oligraph-rs/src/main.rs +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/python/oligraph/__init__.py +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/python/oligraph/_oligraph.pyi +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/python/oligraph/py.typed +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/python/src/lib.rs +0 -0
- {oligraph-0.2.0 → oligraph-0.2.2}/python/src/writers.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oligraph
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Science/Research
|
|
6
6
|
Classifier: Operating System :: OS Independent
|
|
@@ -36,6 +36,8 @@ Available as a CLI tool, a Python package, and a browser-based web app (all comp
|
|
|
36
36
|
oligraph-rs -i <input.fasta> -o <output_prefix> [-l <min_overlap>] [-m <all|pca>]
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
(There is also an `oligraph` command in the [Python package](#command-line), if you would rather not build the Rust binary.)
|
|
40
|
+
|
|
39
41
|
| Flag | Description |
|
|
40
42
|
|---|---|
|
|
41
43
|
| `-i, --input` | Input FASTA file of oligonucleotide sequences |
|
|
@@ -100,6 +102,25 @@ To build from source instead (needs Rust 1.85 or later):
|
|
|
100
102
|
pip install git+https://github.com/AgentK9/oligraph-rs
|
|
101
103
|
```
|
|
102
104
|
|
|
105
|
+
### Command line
|
|
106
|
+
|
|
107
|
+
Installing the package also provides an `oligraph` command (and `python -m oligraph`), so the tool is usable without a Rust toolchain:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
oligraph -i pool.fasta.gz -o results -l 20 -m pca
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Flags match the Rust CLI above, with these additions:
|
|
114
|
+
|
|
115
|
+
| Flag | Description |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `-o, --output` | Optional here — omit it to write the GFA to stdout |
|
|
118
|
+
| `--on-invalid` | `skip` (default) drops unusable records and names them on stderr; `raise` fails |
|
|
119
|
+
| `--positional-ids` | Label output with indices, reproducing the Rust CLI's output exactly |
|
|
120
|
+
| `-q, --quiet` | Suppress progress on stderr |
|
|
121
|
+
|
|
122
|
+
The one behavioural difference from `oligraph-rs`: output is labelled with FASTA record names by default rather than positional indices.
|
|
123
|
+
|
|
103
124
|
### Quick start
|
|
104
125
|
|
|
105
126
|
Pass a dict of sequences, and get back a graph whose edges and contigs are labelled with your own names:
|
|
@@ -10,6 +10,8 @@ Available as a CLI tool, a Python package, and a browser-based web app (all comp
|
|
|
10
10
|
oligraph-rs -i <input.fasta> -o <output_prefix> [-l <min_overlap>] [-m <all|pca>]
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
(There is also an `oligraph` command in the [Python package](#command-line), if you would rather not build the Rust binary.)
|
|
14
|
+
|
|
13
15
|
| Flag | Description |
|
|
14
16
|
|---|---|
|
|
15
17
|
| `-i, --input` | Input FASTA file of oligonucleotide sequences |
|
|
@@ -74,6 +76,25 @@ To build from source instead (needs Rust 1.85 or later):
|
|
|
74
76
|
pip install git+https://github.com/AgentK9/oligraph-rs
|
|
75
77
|
```
|
|
76
78
|
|
|
79
|
+
### Command line
|
|
80
|
+
|
|
81
|
+
Installing the package also provides an `oligraph` command (and `python -m oligraph`), so the tool is usable without a Rust toolchain:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
oligraph -i pool.fasta.gz -o results -l 20 -m pca
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Flags match the Rust CLI above, with these additions:
|
|
88
|
+
|
|
89
|
+
| Flag | Description |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `-o, --output` | Optional here — omit it to write the GFA to stdout |
|
|
92
|
+
| `--on-invalid` | `skip` (default) drops unusable records and names them on stderr; `raise` fails |
|
|
93
|
+
| `--positional-ids` | Label output with indices, reproducing the Rust CLI's output exactly |
|
|
94
|
+
| `-q, --quiet` | Suppress progress on stderr |
|
|
95
|
+
|
|
96
|
+
The one behavioural difference from `oligraph-rs`: output is labelled with FASTA record names by default rather than positional indices.
|
|
97
|
+
|
|
77
98
|
### Quick start
|
|
78
99
|
|
|
79
100
|
Pass a dict of sequences, and get back a graph whose edges and contigs are labelled with your own names:
|
|
@@ -28,6 +28,11 @@ classifiers = [
|
|
|
28
28
|
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
29
29
|
]
|
|
30
30
|
|
|
31
|
+
# Console entry point. The Rust CLI binary cannot ship inside a pyo3 extension
|
|
32
|
+
# wheel, so this is a Python front-end over the same bindings.
|
|
33
|
+
[project.scripts]
|
|
34
|
+
oligraph = "oligraph.__main__:main"
|
|
35
|
+
|
|
31
36
|
[project.urls]
|
|
32
37
|
Homepage = "https://github.com/AgentK9/oligraph-rs"
|
|
33
38
|
Repository = "https://github.com/AgentK9/oligraph-rs"
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""Command-line interface for OliGraph.
|
|
2
|
+
|
|
3
|
+
Installed as the ``oligraph`` command, and runnable as ``python -m oligraph``.
|
|
4
|
+
|
|
5
|
+
Flags mirror the Rust CLI (``oligraph-rs``) so the two are interchangeable, with
|
|
6
|
+
one deliberate difference: this one labels its output with the FASTA record names
|
|
7
|
+
rather than positional indices. Pass ``--positional-ids`` for byte-identical
|
|
8
|
+
output to the Rust CLI.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import List, Optional
|
|
17
|
+
|
|
18
|
+
from . import __version__, build_from_fasta
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
22
|
+
p = argparse.ArgumentParser(
|
|
23
|
+
prog="oligraph",
|
|
24
|
+
description=(
|
|
25
|
+
"Overlap graph builder and contig assembler for oligonucleotide pools."
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
p.add_argument(
|
|
29
|
+
"-i",
|
|
30
|
+
"--input",
|
|
31
|
+
required=True,
|
|
32
|
+
type=Path,
|
|
33
|
+
metavar="FASTA",
|
|
34
|
+
help="input FASTA/FASTQ file; plain or gzipped",
|
|
35
|
+
)
|
|
36
|
+
p.add_argument(
|
|
37
|
+
"-o",
|
|
38
|
+
"--output",
|
|
39
|
+
type=Path,
|
|
40
|
+
metavar="PREFIX",
|
|
41
|
+
help=(
|
|
42
|
+
"output prefix; writes PREFIX.gfa, PREFIX.fasta and "
|
|
43
|
+
"PREFIX.contigs.fasta. Omit to write the GFA to stdout"
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
# No 1-64 bound is declared here on purpose: the range lives in the Rust core
|
|
47
|
+
# (validate_min_overlap) and is reported through the ValueError below, so it
|
|
48
|
+
# is never restated in two places.
|
|
49
|
+
p.add_argument(
|
|
50
|
+
"-l",
|
|
51
|
+
"--min-overlap",
|
|
52
|
+
type=int,
|
|
53
|
+
default=20,
|
|
54
|
+
metavar="BP",
|
|
55
|
+
help="minimum overlap length in bases (default: 20, range: 1-64)",
|
|
56
|
+
)
|
|
57
|
+
p.add_argument(
|
|
58
|
+
"-m",
|
|
59
|
+
"--method",
|
|
60
|
+
choices=("all", "pca"),
|
|
61
|
+
default="all",
|
|
62
|
+
help="'all' keeps every edge type; 'pca' keeps only 3'-end annealing",
|
|
63
|
+
)
|
|
64
|
+
p.add_argument(
|
|
65
|
+
"--on-invalid",
|
|
66
|
+
choices=("skip", "raise"),
|
|
67
|
+
default="skip",
|
|
68
|
+
help=(
|
|
69
|
+
"what to do with an empty or non-ACGT record (default: skip, which "
|
|
70
|
+
"drops it and reports the name on stderr)"
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
p.add_argument(
|
|
74
|
+
"--positional-ids",
|
|
75
|
+
action="store_true",
|
|
76
|
+
help="label output with positional indices instead of record names",
|
|
77
|
+
)
|
|
78
|
+
p.add_argument(
|
|
79
|
+
"-q", "--quiet", action="store_true", help="suppress progress on stderr"
|
|
80
|
+
)
|
|
81
|
+
p.add_argument("--version", action="version", version=f"oligraph {__version__}")
|
|
82
|
+
return p
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
86
|
+
args = _build_parser().parse_args(argv)
|
|
87
|
+
|
|
88
|
+
def log(msg: str) -> None:
|
|
89
|
+
if not args.quiet:
|
|
90
|
+
print(msg, file=sys.stderr)
|
|
91
|
+
|
|
92
|
+
# The core reports bad input as typed errors; surface them as a one-line
|
|
93
|
+
# message rather than a traceback.
|
|
94
|
+
try:
|
|
95
|
+
g = build_from_fasta(
|
|
96
|
+
args.input,
|
|
97
|
+
min_overlap=args.min_overlap,
|
|
98
|
+
method=args.method,
|
|
99
|
+
on_invalid=args.on_invalid,
|
|
100
|
+
)
|
|
101
|
+
except (OSError, ValueError) as e:
|
|
102
|
+
print(f"error: {e}", file=sys.stderr)
|
|
103
|
+
return 1
|
|
104
|
+
|
|
105
|
+
names = not args.positional_ids
|
|
106
|
+
stats = g.stats
|
|
107
|
+
log(
|
|
108
|
+
f"loaded {stats.n_sequences} sequences "
|
|
109
|
+
f"(lengths {stats.len_min}-{stats.len_max}) with min_overlap={g.min_overlap}"
|
|
110
|
+
)
|
|
111
|
+
if g.skipped:
|
|
112
|
+
log(f"skipped {len(g.skipped)} unusable records: {', '.join(g.skipped)}")
|
|
113
|
+
log(f"found {stats.n_edges} edges, {stats.n_isolated} isolated sequences")
|
|
114
|
+
|
|
115
|
+
if args.output is None:
|
|
116
|
+
sys.stdout.write(g.to_gfa(names=names))
|
|
117
|
+
return 0
|
|
118
|
+
|
|
119
|
+
prefix = args.output
|
|
120
|
+
if prefix.parent != Path(""):
|
|
121
|
+
prefix.parent.mkdir(parents=True, exist_ok=True)
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
gfa = prefix.with_suffix(".gfa")
|
|
125
|
+
g.write_gfa(gfa, names=names)
|
|
126
|
+
log(f"wrote {gfa}")
|
|
127
|
+
|
|
128
|
+
fasta = prefix.with_suffix(".fasta")
|
|
129
|
+
g.write_fasta(fasta, names=names)
|
|
130
|
+
log(f"wrote {fasta}")
|
|
131
|
+
|
|
132
|
+
if g.contigs:
|
|
133
|
+
contigs = prefix.with_suffix(".contigs.fasta")
|
|
134
|
+
g.write_contigs_fasta(contigs, names=names)
|
|
135
|
+
log(f"wrote {contigs} ({stats.n_contigs} contigs)")
|
|
136
|
+
else:
|
|
137
|
+
log("no contigs assembled (no connected components with edges)")
|
|
138
|
+
except OSError as e:
|
|
139
|
+
print(f"error: {e}", file=sys.stderr)
|
|
140
|
+
return 1
|
|
141
|
+
|
|
142
|
+
return 0
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
raise SystemExit(main())
|
|
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
|