p2smi 0.1.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.
- p2smi-0.1.0/LICENSE +18 -0
- p2smi-0.1.0/PKG-INFO +109 -0
- p2smi-0.1.0/README.md +88 -0
- p2smi-0.1.0/p2smi/__init__.py +0 -0
- p2smi-0.1.0/p2smi/chemMods.py +136 -0
- p2smi-0.1.0/p2smi/chemProps.py +120 -0
- p2smi-0.1.0/p2smi/fasta2smi.py +101 -0
- p2smi-0.1.0/p2smi/genPeps.py +135 -0
- p2smi-0.1.0/p2smi/synthRules.py +144 -0
- p2smi-0.1.0/p2smi/utilities/__init__.py +0 -0
- p2smi-0.1.0/p2smi/utilities/aminoacids.py +4957 -0
- p2smi-0.1.0/p2smi/utilities/smilesgen.py +617 -0
- p2smi-0.1.0/p2smi.egg-info/PKG-INFO +109 -0
- p2smi-0.1.0/p2smi.egg-info/SOURCES.txt +24 -0
- p2smi-0.1.0/p2smi.egg-info/dependency_links.txt +1 -0
- p2smi-0.1.0/p2smi.egg-info/entry_points.txt +6 -0
- p2smi-0.1.0/p2smi.egg-info/requires.txt +9 -0
- p2smi-0.1.0/p2smi.egg-info/top_level.txt +1 -0
- p2smi-0.1.0/pyproject.toml +27 -0
- p2smi-0.1.0/setup.cfg +22 -0
- p2smi-0.1.0/tests/test_chemMods.py +62 -0
- p2smi-0.1.0/tests/test_chemProps.py +78 -0
- p2smi-0.1.0/tests/test_fasta2smi.py +64 -0
- p2smi-0.1.0/tests/test_genPeps.py +42 -0
- p2smi-0.1.0/tests/test_synthRules.py +69 -0
p2smi-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aaron Feller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
13
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
14
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
15
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
16
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
17
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
18
|
+
SOFTWARE.
|
p2smi-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: p2smi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A package for converting peptide FASTA to SMILES strings and calculating molecular properties.
|
|
5
|
+
Home-page: https://github.com/AaronFeller/p2smi
|
|
6
|
+
Author: Aaron L. Feller
|
|
7
|
+
Author-email: Aaron Feller <aaronleefeller@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: rdkit
|
|
13
|
+
Requires-Dist: numpy
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest; extra == "dev"
|
|
16
|
+
Requires-Dist: black; extra == "dev"
|
|
17
|
+
Requires-Dist: flake8; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
19
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# p2smi: Peptide FASTA-to-SMILES Conversion and Molecular Property Tools
|
|
23
|
+
|
|
24
|
+
**p2smi** is a Python package for generating and modifying peptide SMILES strings from FASTA input and computing molecular properties. It supports cyclic and linear peptides, noncanonical amino acids, and common chemical modifications (e.g., N-methylation, PEGylation).
|
|
25
|
+
|
|
26
|
+
This package was released in its current form to support work on the **PeptideCLM** model, described in our [Publication](https://pubs.acs.org/doi/10.1021/acs.jcim.4c01441).
|
|
27
|
+
|
|
28
|
+
> **If you use this tool, please cite the PeptideCLM paper.** A JOSS publication is forthcoming.
|
|
29
|
+
|
|
30
|
+
## Manuscript
|
|
31
|
+
- [View PDF](manuscript/paper.pdf)
|
|
32
|
+
- [View markdown source](manuscript/paper.md)
|
|
33
|
+
|
|
34
|
+
## Directory
|
|
35
|
+
|
|
36
|
+
- [Features](#features)
|
|
37
|
+
- [Installation](#installation)
|
|
38
|
+
- [Command-Line Tools](#command-line-tools)
|
|
39
|
+
- [Example Usage](#example-usage)
|
|
40
|
+
- [Future Work](#future-work)
|
|
41
|
+
- [License](#license)
|
|
42
|
+
- [Citation](#citation)
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
- Convert peptide FASTA files into valid SMILES strings
|
|
46
|
+
- Automatically handle peptide cyclizations (disulfide, head-to-tail, side-chain to N-term, side-chain to C-term, side-chain to side-chain)
|
|
47
|
+
- Modify peptide SMILES with customizable N-methylation and PEGylation
|
|
48
|
+
- Evaluate synthesis feasibility with defined synthesis rules
|
|
49
|
+
- Compute molecular properties: logP, TPSA, molecular formula, and Lipinski rule evaluation
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
```bash
|
|
53
|
+
pip install p2smi
|
|
54
|
+
```
|
|
55
|
+
For development:
|
|
56
|
+
```bash
|
|
57
|
+
git clone <your-repo-url>
|
|
58
|
+
cd p2smi
|
|
59
|
+
pip install -e .[dev]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Command-Line Tools
|
|
63
|
+
|
|
64
|
+
| Command | Description |
|
|
65
|
+
|-----------------------|-----------------------------------------------------------------|
|
|
66
|
+
| `generate-peptides` | Generate random peptide sequences based on user-defined constraints and modifications |
|
|
67
|
+
| `fasta2smi` | Convert a FASTA file of peptide sequences into SMILES format |
|
|
68
|
+
| `modify-smiles` | Apply modifications (N-methylation, PEGylation) to existing SMILES strings |
|
|
69
|
+
| `smiles-props` | Compute molecular properties (logP, TPSA, formula, Lipinski rules) from SMILES |
|
|
70
|
+
| `synthesis-check` | Check synthesis constraints for peptides (*currently only functional for natural amino acids*) |
|
|
71
|
+
|
|
72
|
+
> Run each command with `--help` to view usage and options:
|
|
73
|
+
```bash
|
|
74
|
+
generate-peptides --help
|
|
75
|
+
fasta2smi --help
|
|
76
|
+
modify-smiles --help
|
|
77
|
+
smiles-props --help
|
|
78
|
+
synthesis-check --help
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Example Usage
|
|
82
|
+
|
|
83
|
+
**Convert a FASTA file to SMILES:**
|
|
84
|
+
```bash
|
|
85
|
+
fasta2smi -i peptides.fasta -o output.smi
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Modify existing SMILES strings (N-methylation/PEGylation):**
|
|
89
|
+
```bash
|
|
90
|
+
modify-smiles -i input.smi -o modified.smi --peg_rate 0.3 --nmeth_rate 0.2 --nmeth_residues 0.25
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Compute properties of a SMILES string:**
|
|
94
|
+
```bash
|
|
95
|
+
smiles-props "C1CC(NC(=O)C2CC2)C1"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Future Work
|
|
99
|
+
- Expand support for additional post-translational modifications
|
|
100
|
+
- Enhance synthesis-check with rules for noncanonical amino acid and modified peptides
|
|
101
|
+
-
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
MIT License
|
|
105
|
+
|
|
106
|
+
## Citation
|
|
107
|
+
> If you use this tool, please cite:
|
|
108
|
+
- [Peptide-Aware Chemical Language Model Successfully Predicts Membrane Diffusion of Cyclic Peptides (JCIM)](https://pubs.acs.org/doi/10.1021/acs.jcim.4c01441)
|
|
109
|
+
A JOSS paper will follow.
|
p2smi-0.1.0/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# p2smi: Peptide FASTA-to-SMILES Conversion and Molecular Property Tools
|
|
2
|
+
|
|
3
|
+
**p2smi** is a Python package for generating and modifying peptide SMILES strings from FASTA input and computing molecular properties. It supports cyclic and linear peptides, noncanonical amino acids, and common chemical modifications (e.g., N-methylation, PEGylation).
|
|
4
|
+
|
|
5
|
+
This package was released in its current form to support work on the **PeptideCLM** model, described in our [Publication](https://pubs.acs.org/doi/10.1021/acs.jcim.4c01441).
|
|
6
|
+
|
|
7
|
+
> **If you use this tool, please cite the PeptideCLM paper.** A JOSS publication is forthcoming.
|
|
8
|
+
|
|
9
|
+
## Manuscript
|
|
10
|
+
- [View PDF](manuscript/paper.pdf)
|
|
11
|
+
- [View markdown source](manuscript/paper.md)
|
|
12
|
+
|
|
13
|
+
## Directory
|
|
14
|
+
|
|
15
|
+
- [Features](#features)
|
|
16
|
+
- [Installation](#installation)
|
|
17
|
+
- [Command-Line Tools](#command-line-tools)
|
|
18
|
+
- [Example Usage](#example-usage)
|
|
19
|
+
- [Future Work](#future-work)
|
|
20
|
+
- [License](#license)
|
|
21
|
+
- [Citation](#citation)
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
- Convert peptide FASTA files into valid SMILES strings
|
|
25
|
+
- Automatically handle peptide cyclizations (disulfide, head-to-tail, side-chain to N-term, side-chain to C-term, side-chain to side-chain)
|
|
26
|
+
- Modify peptide SMILES with customizable N-methylation and PEGylation
|
|
27
|
+
- Evaluate synthesis feasibility with defined synthesis rules
|
|
28
|
+
- Compute molecular properties: logP, TPSA, molecular formula, and Lipinski rule evaluation
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
```bash
|
|
32
|
+
pip install p2smi
|
|
33
|
+
```
|
|
34
|
+
For development:
|
|
35
|
+
```bash
|
|
36
|
+
git clone <your-repo-url>
|
|
37
|
+
cd p2smi
|
|
38
|
+
pip install -e .[dev]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Command-Line Tools
|
|
42
|
+
|
|
43
|
+
| Command | Description |
|
|
44
|
+
|-----------------------|-----------------------------------------------------------------|
|
|
45
|
+
| `generate-peptides` | Generate random peptide sequences based on user-defined constraints and modifications |
|
|
46
|
+
| `fasta2smi` | Convert a FASTA file of peptide sequences into SMILES format |
|
|
47
|
+
| `modify-smiles` | Apply modifications (N-methylation, PEGylation) to existing SMILES strings |
|
|
48
|
+
| `smiles-props` | Compute molecular properties (logP, TPSA, formula, Lipinski rules) from SMILES |
|
|
49
|
+
| `synthesis-check` | Check synthesis constraints for peptides (*currently only functional for natural amino acids*) |
|
|
50
|
+
|
|
51
|
+
> Run each command with `--help` to view usage and options:
|
|
52
|
+
```bash
|
|
53
|
+
generate-peptides --help
|
|
54
|
+
fasta2smi --help
|
|
55
|
+
modify-smiles --help
|
|
56
|
+
smiles-props --help
|
|
57
|
+
synthesis-check --help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Example Usage
|
|
61
|
+
|
|
62
|
+
**Convert a FASTA file to SMILES:**
|
|
63
|
+
```bash
|
|
64
|
+
fasta2smi -i peptides.fasta -o output.smi
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Modify existing SMILES strings (N-methylation/PEGylation):**
|
|
68
|
+
```bash
|
|
69
|
+
modify-smiles -i input.smi -o modified.smi --peg_rate 0.3 --nmeth_rate 0.2 --nmeth_residues 0.25
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Compute properties of a SMILES string:**
|
|
73
|
+
```bash
|
|
74
|
+
smiles-props "C1CC(NC(=O)C2CC2)C1"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Future Work
|
|
78
|
+
- Expand support for additional post-translational modifications
|
|
79
|
+
- Enhance synthesis-check with rules for noncanonical amino acid and modified peptides
|
|
80
|
+
-
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
MIT License
|
|
84
|
+
|
|
85
|
+
## Citation
|
|
86
|
+
> If you use this tool, please cite:
|
|
87
|
+
- [Peptide-Aware Chemical Language Model Successfully Predicts Membrane Diffusion of Cyclic Peptides (JCIM)](https://pubs.acs.org/doi/10.1021/acs.jcim.4c01441)
|
|
88
|
+
A JOSS paper will follow.
|
|
File without changes
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import math
|
|
3
|
+
import random
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
from rdkit import Chem
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def is_valid_smiles(sequence):
|
|
10
|
+
return Chem.MolFromSmiles(sequence) is not None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def add_n_methylation(sequence, methylation_residue_fraction):
|
|
14
|
+
pattern = r"C\(=O\)N\[C@"
|
|
15
|
+
positions = [m.start() for m in re.finditer(pattern, sequence)]
|
|
16
|
+
num_to_methylate = math.ceil(len(positions) * methylation_residue_fraction)
|
|
17
|
+
|
|
18
|
+
for pos in sorted(
|
|
19
|
+
random.sample(positions, min(num_to_methylate, len(positions))),
|
|
20
|
+
reverse=True,
|
|
21
|
+
):
|
|
22
|
+
sequence = sequence[: pos + 6] + "(C)" + sequence[pos + 6 :]
|
|
23
|
+
return sequence, num_to_methylate
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def add_pegylation(sequence):
|
|
27
|
+
peg = "O" + "".join(["CCO" for _ in range(random.randint(1, 4))]) + "C"
|
|
28
|
+
positions = [m.start() for m in re.finditer(r"CN\)", sequence)]
|
|
29
|
+
if not positions:
|
|
30
|
+
return sequence, None
|
|
31
|
+
pos = random.choice(positions)
|
|
32
|
+
return sequence[: pos + 2] + peg + sequence[pos + 2 :], peg
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def parse_input_lines(input_lines):
|
|
36
|
+
for line in input_lines:
|
|
37
|
+
parts = line.strip().split(": ", 1)
|
|
38
|
+
if len(parts) == 2:
|
|
39
|
+
yield tuple(parts)
|
|
40
|
+
else:
|
|
41
|
+
yield ("[Malformed line]", None)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def modify_sequence(sequence, methylate, pegylate, nmeth_residues):
|
|
45
|
+
modifications = []
|
|
46
|
+
if methylate:
|
|
47
|
+
sequence, methyl_count = add_n_methylation(sequence, nmeth_residues)
|
|
48
|
+
modifications.append(f"N-methylation({methyl_count})")
|
|
49
|
+
if pegylate:
|
|
50
|
+
sequence, peg = add_pegylation(sequence)
|
|
51
|
+
# find number of PEG units added
|
|
52
|
+
if peg:
|
|
53
|
+
number_of_peg_units = peg.count("CCO")
|
|
54
|
+
modifications.append(f"PEGylation({number_of_peg_units})")
|
|
55
|
+
else:
|
|
56
|
+
modifications.append("PEGylation('N/A')")
|
|
57
|
+
return sequence, modifications
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def process_sequences(input_lines, nmeth_rate, peg_rate, nmeth_residues):
|
|
61
|
+
total = len(input_lines)
|
|
62
|
+
methylate_indices = (
|
|
63
|
+
set(random.sample(range(total), math.ceil(total * nmeth_rate)))
|
|
64
|
+
if nmeth_rate > 0
|
|
65
|
+
else set()
|
|
66
|
+
)
|
|
67
|
+
pegylate_indices = (
|
|
68
|
+
set(random.sample(range(total), math.ceil(total * peg_rate)))
|
|
69
|
+
if peg_rate > 0
|
|
70
|
+
else set()
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
for i, (header, seq) in enumerate(parse_input_lines(input_lines)):
|
|
74
|
+
if seq is None:
|
|
75
|
+
yield f"{header} [Skipped malformed line]"
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
sequence, mods = modify_sequence(
|
|
79
|
+
seq, i in methylate_indices, i in pegylate_indices, nmeth_residues
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if not is_valid_smiles(sequence):
|
|
83
|
+
yield f"{header} [Invalid SMILES skipped]"
|
|
84
|
+
continue
|
|
85
|
+
|
|
86
|
+
mod_str = f" [{' - '.join(mods)}]" if mods else ""
|
|
87
|
+
yield f"{header}{mod_str}: {sequence}"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def process_file(input_file, output_file, peg_rate, nmeth_rate, nmeth_residues):
|
|
91
|
+
with open(input_file, "r") as infile:
|
|
92
|
+
lines = [line.strip() for line in infile if line.strip()]
|
|
93
|
+
|
|
94
|
+
modified_lines = process_sequences(lines, nmeth_rate, peg_rate, nmeth_residues)
|
|
95
|
+
|
|
96
|
+
with open(output_file, "w") as outfile:
|
|
97
|
+
outfile.write("\n".join(modified_lines) + "\n")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def main():
|
|
101
|
+
parser = argparse.ArgumentParser(
|
|
102
|
+
description=("Modify peptide sequences with" "PEGylation and N-methylation.")
|
|
103
|
+
)
|
|
104
|
+
parser.add_argument("-i", "--input_file", required=True, help="Input file path.")
|
|
105
|
+
parser.add_argument("-o", "--output_file", required=True, help="Output file path.")
|
|
106
|
+
parser.add_argument(
|
|
107
|
+
"--peg_rate",
|
|
108
|
+
type=float,
|
|
109
|
+
default=0.2,
|
|
110
|
+
help="Fraction of sequences to PEGylate (0-1).",
|
|
111
|
+
)
|
|
112
|
+
parser.add_argument(
|
|
113
|
+
"--nmeth_rate",
|
|
114
|
+
type=float,
|
|
115
|
+
default=0.2,
|
|
116
|
+
help="Fraction of sequences to N-methylate (0-1).",
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"--nmeth_residues",
|
|
120
|
+
type=float,
|
|
121
|
+
default=0.2,
|
|
122
|
+
help="Fraction of bonds in each sequence to N-methylate (0-1).",
|
|
123
|
+
)
|
|
124
|
+
args = parser.parse_args()
|
|
125
|
+
|
|
126
|
+
process_file(
|
|
127
|
+
args.input_file,
|
|
128
|
+
args.output_file,
|
|
129
|
+
args.peg_rate,
|
|
130
|
+
args.nmeth_rate,
|
|
131
|
+
args.nmeth_residues,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == "__main__":
|
|
136
|
+
main()
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Chemical data about a molecule.
|
|
4
|
+
|
|
5
|
+
Molecules are defined by SMILES strings.
|
|
6
|
+
Computes logP, Lipinski's rules, molecular formula,
|
|
7
|
+
TPSA, rotatable bonds, ring count, fraction Csp3,
|
|
8
|
+
heavy atom count, and formal charge.
|
|
9
|
+
|
|
10
|
+
Uses RDKit.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from rdkit import Chem
|
|
14
|
+
from rdkit.Chem import (
|
|
15
|
+
Crippen,
|
|
16
|
+
Descriptors,
|
|
17
|
+
Lipinski,
|
|
18
|
+
rdMolDescriptors,
|
|
19
|
+
rdmolops,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SmilesError(Exception):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def log_partition_coefficient(smiles):
|
|
28
|
+
mol = Chem.MolFromSmiles(smiles)
|
|
29
|
+
if mol is None:
|
|
30
|
+
raise SmilesError(f"{smiles} is not a valid SMILES string")
|
|
31
|
+
return Crippen.MolLogP(mol)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def lipinski_trial(smiles):
|
|
35
|
+
mol = Chem.MolFromSmiles(smiles)
|
|
36
|
+
if mol is None:
|
|
37
|
+
raise SmilesError(f"{smiles} is not a valid SMILES string")
|
|
38
|
+
|
|
39
|
+
passed, failed = [], []
|
|
40
|
+
num_hdonors = Lipinski.NumHDonors(mol)
|
|
41
|
+
num_hacceptors = Lipinski.NumHAcceptors(mol)
|
|
42
|
+
mol_weight = Descriptors.MolWt(mol)
|
|
43
|
+
mol_logp = Crippen.MolLogP(mol)
|
|
44
|
+
|
|
45
|
+
if num_hdonors > 5:
|
|
46
|
+
failed.append(f"Over 5 H-bond donors (found {num_hdonors})")
|
|
47
|
+
else:
|
|
48
|
+
passed.append(f"{num_hdonors} H-bond donors")
|
|
49
|
+
|
|
50
|
+
if num_hacceptors > 10:
|
|
51
|
+
failed.append(f"Over 10 H-bond acceptors (found {num_hacceptors})")
|
|
52
|
+
else:
|
|
53
|
+
passed.append(f"{num_hacceptors} H-bond acceptors")
|
|
54
|
+
|
|
55
|
+
if mol_weight >= 500:
|
|
56
|
+
failed.append(f"Molecular weight over 500 (calculated {mol_weight:.2f})")
|
|
57
|
+
else:
|
|
58
|
+
passed.append(f"Molecular weight: {mol_weight:.2f}")
|
|
59
|
+
|
|
60
|
+
if mol_logp >= 5:
|
|
61
|
+
failed.append(f"logP over 5 (calculated {mol_logp:.2f})")
|
|
62
|
+
else:
|
|
63
|
+
passed.append(f"logP: {mol_logp:.2f}")
|
|
64
|
+
|
|
65
|
+
return passed, failed
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def lipinski_pass(smiles):
|
|
69
|
+
_, failed = lipinski_trial(smiles)
|
|
70
|
+
return not failed
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def molecular_formula(smiles):
|
|
74
|
+
mol = Chem.MolFromSmiles(smiles)
|
|
75
|
+
if mol is None:
|
|
76
|
+
raise SmilesError(f"{smiles} is not a valid SMILES string")
|
|
77
|
+
return rdMolDescriptors.CalcMolFormula(mol)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def tpsa(smiles):
|
|
81
|
+
mol = Chem.MolFromSmiles(smiles)
|
|
82
|
+
if mol is None:
|
|
83
|
+
raise SmilesError(f"{smiles} is not a valid SMILES string")
|
|
84
|
+
return Descriptors.TPSA(mol)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def molecule_summary(smiles):
|
|
88
|
+
mol = Chem.MolFromSmiles(smiles)
|
|
89
|
+
if mol is None:
|
|
90
|
+
raise SmilesError(f"{smiles} is not a valid SMILES string")
|
|
91
|
+
|
|
92
|
+
summary = {
|
|
93
|
+
"Formula": molecular_formula(smiles),
|
|
94
|
+
"Molecular Weight": round(Descriptors.MolWt(mol), 2),
|
|
95
|
+
"logP": round(Crippen.MolLogP(mol), 2),
|
|
96
|
+
"TPSA": round(Descriptors.TPSA(mol), 2),
|
|
97
|
+
"H-bond donors": Lipinski.NumHDonors(mol),
|
|
98
|
+
"H-bond acceptors": Lipinski.NumHAcceptors(mol),
|
|
99
|
+
"Rotatable Bonds": Lipinski.NumRotatableBonds(mol),
|
|
100
|
+
"Rings": mol.GetRingInfo().NumRings(),
|
|
101
|
+
"Fraction Csp3": round(rdMolDescriptors.CalcFractionCSP3(mol), 3),
|
|
102
|
+
"Heavy Atoms": mol.GetNumHeavyAtoms(),
|
|
103
|
+
"Formal Charge": rdmolops.GetFormalCharge(mol),
|
|
104
|
+
"Lipinski pass": lipinski_pass(smiles),
|
|
105
|
+
}
|
|
106
|
+
return summary
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
if __name__ == "__main__":
|
|
110
|
+
import argparse
|
|
111
|
+
import json
|
|
112
|
+
|
|
113
|
+
parser = argparse.ArgumentParser(
|
|
114
|
+
description="Analyze SMILES strings for molecular properties."
|
|
115
|
+
)
|
|
116
|
+
parser.add_argument("smiles", type=str, help="SMILES string of the molecule")
|
|
117
|
+
args = parser.parse_args()
|
|
118
|
+
|
|
119
|
+
result = molecule_summary(args.smiles)
|
|
120
|
+
print(json.dumps(result, indent=2))
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module to input FASTA peptide files and generate 3D structures.
|
|
3
|
+
Original by Fergal; modified by Aaron Feller (2025)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
|
|
8
|
+
import p2smi.utilities.smilesgen as smilesgen
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class InvalidConstraintError(Exception):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_fasta(fasta_file):
|
|
16
|
+
"""
|
|
17
|
+
Generator that yields (sequence, constraint) tuples from a FASTA file.
|
|
18
|
+
"""
|
|
19
|
+
with open(fasta_file, "r") as fasta:
|
|
20
|
+
sequence, constraint = "", ""
|
|
21
|
+
for line in fasta:
|
|
22
|
+
line = line.strip()
|
|
23
|
+
if line.startswith(">"):
|
|
24
|
+
if sequence:
|
|
25
|
+
yield sequence, constraint
|
|
26
|
+
sequence = ""
|
|
27
|
+
constraint = line.split("|")[-1] if "|" in line else ""
|
|
28
|
+
else:
|
|
29
|
+
sequence += line
|
|
30
|
+
if sequence:
|
|
31
|
+
yield sequence, constraint
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def constraint_resolver(sequence, constraint):
|
|
35
|
+
"""
|
|
36
|
+
Resolves constraints for a sequence using available functions
|
|
37
|
+
or generates fallback structures.
|
|
38
|
+
"""
|
|
39
|
+
constraint_functions = {
|
|
40
|
+
"SS": smilesgen.can_ssbond,
|
|
41
|
+
"HT": smilesgen.can_htbond,
|
|
42
|
+
"SCNT": smilesgen.can_scntbond,
|
|
43
|
+
"SCCT": smilesgen.can_scctbond,
|
|
44
|
+
"SCSC": smilesgen.can_scscbond,
|
|
45
|
+
}
|
|
46
|
+
valid_constraints = smilesgen.what_constraints(sequence)
|
|
47
|
+
|
|
48
|
+
if constraint.upper() in valid_constraints:
|
|
49
|
+
return (sequence, constraint)
|
|
50
|
+
elif constraint.upper() in constraint_functions:
|
|
51
|
+
result = constraint_functions[constraint.upper()](sequence)
|
|
52
|
+
return result or (sequence, "")
|
|
53
|
+
elif constraint.upper() == "SC":
|
|
54
|
+
for func in [
|
|
55
|
+
constraint_functions[k] for k in constraint_functions if "SC" in k
|
|
56
|
+
]:
|
|
57
|
+
result = func(sequence)
|
|
58
|
+
if result:
|
|
59
|
+
return result
|
|
60
|
+
raise InvalidConstraintError(f"{sequence} has invalid constraint {constraint}")
|
|
61
|
+
elif constraint in (None, ""):
|
|
62
|
+
return (sequence, "")
|
|
63
|
+
else:
|
|
64
|
+
raise InvalidConstraintError(f"{sequence} has invalid constraint {constraint}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def process_constraints(fasta_file):
|
|
68
|
+
"""
|
|
69
|
+
Processes constraints for all sequences in the FASTA file.
|
|
70
|
+
"""
|
|
71
|
+
return (constraint_resolver(seq, constr) for seq, constr in parse_fasta(fasta_file))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def generate_3d_structures(input_fasta, out_file):
|
|
75
|
+
"""
|
|
76
|
+
Generates 3D structures from FASTA input and writes to output.
|
|
77
|
+
"""
|
|
78
|
+
resolved_sequences = process_constraints(input_fasta)
|
|
79
|
+
smilesgen.write_library(
|
|
80
|
+
(
|
|
81
|
+
smilesgen.constrained_peptide_smiles(seq, constr)
|
|
82
|
+
for seq, constr in resolved_sequences
|
|
83
|
+
),
|
|
84
|
+
out_file,
|
|
85
|
+
write="text",
|
|
86
|
+
write_to_file=True,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def main():
|
|
91
|
+
parser = argparse.ArgumentParser(description="Generate peptides from a FASTA file.")
|
|
92
|
+
parser.add_argument(
|
|
93
|
+
"-i", "--input_fasta", required=True, help="FASTA file of peptides."
|
|
94
|
+
)
|
|
95
|
+
parser.add_argument("-o", "--out_file", required=True, help="Output file.")
|
|
96
|
+
args = parser.parse_args()
|
|
97
|
+
generate_3d_structures(args.input_fasta, args.out_file)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
main()
|