pythonQEPest 2.0.0a2__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.
- pythonqepest-2.0.0a2/PKG-INFO +217 -0
- pythonqepest-2.0.0a2/README.md +197 -0
- pythonqepest-2.0.0a2/pyproject.toml +46 -0
- pythonqepest-2.0.0a2/pythonQEPest/.env.example +4 -0
- pythonqepest-2.0.0a2/pythonQEPest/__init__.py +11 -0
- pythonqepest-2.0.0a2/pythonQEPest/cli/__init__.py +7 -0
- pythonqepest-2.0.0a2/pythonQEPest/cli/cli.py +101 -0
- pythonqepest-2.0.0a2/pythonQEPest/config/__init__.py +11 -0
- pythonqepest-2.0.0a2/pythonQEPest/config/config_provider.py +9 -0
- pythonqepest-2.0.0a2/pythonQEPest/config/normalise.py +12 -0
- pythonqepest-2.0.0a2/pythonQEPest/config/qepest_config.py +31 -0
- pythonqepest-2.0.0a2/pythonQEPest/config/qepest_default.py +26 -0
- pythonqepest-2.0.0a2/pythonQEPest/core/__init__.py +7 -0
- pythonqepest-2.0.0a2/pythonQEPest/core/qepest.py +98 -0
- pythonqepest-2.0.0a2/pythonQEPest/core/qepest_meta.py +28 -0
- pythonqepest-2.0.0a2/pythonQEPest/data.txt +2 -0
- pythonqepest-2.0.0a2/pythonQEPest/data.txt.out +2 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/QEPestData.py +21 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/QEPestFile.py +34 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/QEPestInput.py +60 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/QEPestOutput.py +13 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/__init__.py +27 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/coefficients/QEPestCoefficient.py +57 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/coefficients/QEPestCoefficientList.py +29 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/coefficients/QEPestCoefficientNumerics.py +44 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/coefficients/__init__.py +7 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/normalisation/Normaliser.py +16 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/normalisation/__init__.py +3 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/pest_type/PestTypeCoefficient.py +30 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/pest_type/PestTypeConfig.py +9 -0
- pythonqepest-2.0.0a2/pythonQEPest/dto/pest_type/__init__.py +4 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/__init__.py +7 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/actions/__init__.py +9 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/actions/action_clicks.py +42 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/actions/actions_crud.py +131 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/actions/actions_other.py +126 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/elements/ButtonsFrame.py +50 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/elements/DataTree.py +23 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/elements/EditWindow.py +63 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/elements/Menu.py +12 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/elements/ResultTree.py +22 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/elements/SaveButton.py +10 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/elements/__init__.py +17 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/gui.py +87 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/gui_meta.py +17 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/utility/DataManager.py +76 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/utility/DataManagerMeta.py +8 -0
- pythonqepest-2.0.0a2/pythonQEPest/gui/utility/__init__.py +6 -0
- pythonqepest-2.0.0a2/pythonQEPest/helpers/__init__.py +17 -0
- pythonqepest-2.0.0a2/pythonQEPest/helpers/check_nan.py +8 -0
- pythonqepest-2.0.0a2/pythonQEPest/helpers/compute_df.py +5 -0
- pythonqepest-2.0.0a2/pythonQEPest/helpers/get_num_of_cols.py +2 -0
- pythonqepest-2.0.0a2/pythonQEPest/helpers/get_values_from_line.py +5 -0
- pythonqepest-2.0.0a2/pythonQEPest/helpers/norm.py +33 -0
- pythonqepest-2.0.0a2/pythonQEPest/helpers/round_to_4digs.py +2 -0
- pythonqepest-2.0.0a2/pythonQEPest/logger.py +58 -0
- pythonqepest-2.0.0a2/pythonQEPest/main.py +4 -0
- pythonqepest-2.0.0a2/pythonQEPest/providers/__init__.py +6 -0
- pythonqepest-2.0.0a2/pythonQEPest/providers/default_provider.py +23 -0
- pythonqepest-2.0.0a2/pythonQEPest/providers/json_provider.py +30 -0
- pythonqepest-2.0.0a2/pythonQEPest/providers/txt_provider.py +46 -0
- pythonqepest-2.0.0a2/pythonQEPest/services/QEPestFileService.py +125 -0
- pythonqepest-2.0.0a2/pythonQEPest/services/__init__.py +3 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pythonQEPest
|
|
3
|
+
Version: 2.0.0a2
|
|
4
|
+
Summary: Java QEPest but written in Python
|
|
5
|
+
Author: Lina
|
|
6
|
+
Author-email: knocker767@gmail.com
|
|
7
|
+
Requires-Python: >=3.12,<3.15
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Provides-Extra: gui
|
|
13
|
+
Provides-Extra: rdkit
|
|
14
|
+
Requires-Dist: pydantic (==2.12.5)
|
|
15
|
+
Requires-Dist: pyperclip (>=1.11.0,<2.0.0) ; extra == "gui"
|
|
16
|
+
Requires-Dist: python-dotenv (>=1.2.1,<2.0.0)
|
|
17
|
+
Requires-Dist: rdkit (>=2024.3.1,<2026.0.0) ; extra == "rdkit"
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# pythonQEPest
|
|
21
|
+
|
|
22
|
+
[](https://github.com/PonyLianna/pythonQEPest/actions/workflows/python-package.yml)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Python implementation of QEPest (Quantitative Estimation of Pesticide), a program for scoring molecules as herbicides (QEH), insecticides (QEI), and fungicides (QEF).
|
|
26
|
+
|
|
27
|
+
Originally published in: [J Cheminform - QEPest](https://jcheminf.biomedcentral.com/articles/10.1186/s13321-014-0042-6)
|
|
28
|
+
Original Program Link is [here](https://static-content.springer.com/esm/art%3A10.1186%2Fs13321-014-0042-6/MediaObjects/13321_2014_42_MOESM2_ESM.zip)
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- Calculate pesticide scores for herbicidal, insecticidal, and fungicidal activity
|
|
33
|
+
- Command-line interface (CLI)
|
|
34
|
+
- Graphical User Interface (GUI)
|
|
35
|
+
- Support for JSON and TXT output formats
|
|
36
|
+
|
|
37
|
+
### Pre-built binaries
|
|
38
|
+
|
|
39
|
+
Download ready-to-use executables from [Releases](https://github.com/PonyLianna/pythonQEPest/releases):
|
|
40
|
+
|
|
41
|
+
| Platform | Download |
|
|
42
|
+
|----------|----------|
|
|
43
|
+
| Windows CLI | [main.exe](https://github.com/PonyLianna/pythonQEPest/releases/download/v2.0.0-alpha/main.exe) |
|
|
44
|
+
| Windows GUI | [gui.exe](https://github.com/PonyLianna/pythonQEPest/releases/download/v2.0.0-alpha/gui.exe) |
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install pythonQEPest
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or from source:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git clone https://github.com/PonyLianna/pythonQEPest.git
|
|
57
|
+
cd pythonQEPest
|
|
58
|
+
poetry install
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### With GUI support
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install pythonQEPest[gui]
|
|
65
|
+
# or
|
|
66
|
+
poetry install --extras ui
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
### CLI
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pythonqepest -i data.txt -o result.txt
|
|
76
|
+
pythonqepest --input data.txt --format json
|
|
77
|
+
pythonqepest -v # show version
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### GUI
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pythonqepest-gui
|
|
84
|
+
# or
|
|
85
|
+
python -m pythonQEPest.gui.gui
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Python API
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from pythonQEPest import QEPest, QEPestInput
|
|
92
|
+
|
|
93
|
+
# Create input data
|
|
94
|
+
qepest = QEPest()
|
|
95
|
+
qepest.initialize_coefficients()
|
|
96
|
+
qepest.initialize_normalisers()
|
|
97
|
+
|
|
98
|
+
# From individual values
|
|
99
|
+
inp = QEPestInput(
|
|
100
|
+
name="mol1",
|
|
101
|
+
mol_weight=240.2127,
|
|
102
|
+
log_p=3.2392,
|
|
103
|
+
hbond_acceptors=5,
|
|
104
|
+
hbond_donors=1,
|
|
105
|
+
rotatable_bonds=4,
|
|
106
|
+
aromatic_rings=1
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
result = qepest.compute_params(inp)
|
|
110
|
+
|
|
111
|
+
print(result.name) # mol1
|
|
112
|
+
print(result.data.qe_herb) # 0.8511
|
|
113
|
+
print(result.data.qe_insect) # 0.5339
|
|
114
|
+
print(result.data.qe_fung) # 0.6224
|
|
115
|
+
|
|
116
|
+
# Convert to array
|
|
117
|
+
print(result.to_array()) # ["mol1", 0.6224, 0.8511, 0.5339]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Input Format
|
|
121
|
+
|
|
122
|
+
The input file should be a tab-separated text file with the following columns:
|
|
123
|
+
|
|
124
|
+
| Column | Description |
|
|
125
|
+
|--------|-------------|
|
|
126
|
+
| Name | Molecule name |
|
|
127
|
+
| MW | Molecular weight (g/mol) |
|
|
128
|
+
| LogP | Hydrophobicity (octanol-water partition coefficient) |
|
|
129
|
+
| HBA | Number of hydrogen bond acceptors |
|
|
130
|
+
| HBD | Number of hydrogen bond donors |
|
|
131
|
+
| RB | Number of rotatable bonds |
|
|
132
|
+
| arR | Number of aromatic rings |
|
|
133
|
+
|
|
134
|
+
Example `data.txt`:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Name MW LogP HBA HBD RB arR
|
|
138
|
+
mol1 240.2127 3.2392 5 1 4 1
|
|
139
|
+
mol2 249.091 3.0273 3 1 5 1
|
|
140
|
+
mol3 308.354 2.1086 1 0 7 1
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Output Format
|
|
144
|
+
|
|
145
|
+
### TXT (default output for CLI)
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Name QEF QEH QEI
|
|
149
|
+
mol1 0.6224 0.8511 0.5339
|
|
150
|
+
mol2 0.7310 0.9750 0.6913
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### JSON
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
[
|
|
157
|
+
{"name": "mol1", "qe_fung": 0.6224, "qe_herb": 0.8511, "qe_insect": 0.5339},
|
|
158
|
+
{"name": "mol2", "qe_fung": 0.731, "qe_herb": 0.975, "qe_insect": 0.6913}
|
|
159
|
+
]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
### Custom Coefficients
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from pythonQEPest import QEPest
|
|
168
|
+
|
|
169
|
+
custom_coefficients = {
|
|
170
|
+
"herb": [
|
|
171
|
+
(70.77, 283.0, 84.97, -1.185),
|
|
172
|
+
(93.81, 3.077, 1.434, 0.6164),
|
|
173
|
+
# ... 6 tuples total
|
|
174
|
+
],
|
|
175
|
+
"insect": [...],
|
|
176
|
+
"fung": [...]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
qepest = QEPest(coefficients=custom_coefficients)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Custom Normalisers
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from pythonQEPest import QEPest
|
|
186
|
+
from pythonQEPest.dto.normalisation.Normaliser import Normaliser
|
|
187
|
+
|
|
188
|
+
qepest = QEPest(normalisers={"herb": Normaliser(...), ...})
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## CLI Options
|
|
192
|
+
|
|
193
|
+
| Option | Description | Default |
|
|
194
|
+
|--------|-------------|---------|
|
|
195
|
+
| `-i`, `--input` | Input file path | data.txt |
|
|
196
|
+
| `-o`, `--output` | Output file path | data.out.txt |
|
|
197
|
+
| `-f`, `--format` | Output format (json, txt) | txt |
|
|
198
|
+
| `-v`, `--version` | Show version | - |
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
### Run tests
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
poetry run pytest
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Build
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# CLI executable
|
|
212
|
+
poetry run poe build-simple
|
|
213
|
+
|
|
214
|
+
# GUI executable
|
|
215
|
+
poetry run poe build-gui
|
|
216
|
+
```
|
|
217
|
+
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# pythonQEPest
|
|
2
|
+
|
|
3
|
+
[](https://github.com/PonyLianna/pythonQEPest/actions/workflows/python-package.yml)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Python implementation of QEPest (Quantitative Estimation of Pesticide), a program for scoring molecules as herbicides (QEH), insecticides (QEI), and fungicides (QEF).
|
|
7
|
+
|
|
8
|
+
Originally published in: [J Cheminform - QEPest](https://jcheminf.biomedcentral.com/articles/10.1186/s13321-014-0042-6)
|
|
9
|
+
Original Program Link is [here](https://static-content.springer.com/esm/art%3A10.1186%2Fs13321-014-0042-6/MediaObjects/13321_2014_42_MOESM2_ESM.zip)
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Calculate pesticide scores for herbicidal, insecticidal, and fungicidal activity
|
|
14
|
+
- Command-line interface (CLI)
|
|
15
|
+
- Graphical User Interface (GUI)
|
|
16
|
+
- Support for JSON and TXT output formats
|
|
17
|
+
|
|
18
|
+
### Pre-built binaries
|
|
19
|
+
|
|
20
|
+
Download ready-to-use executables from [Releases](https://github.com/PonyLianna/pythonQEPest/releases):
|
|
21
|
+
|
|
22
|
+
| Platform | Download |
|
|
23
|
+
|----------|----------|
|
|
24
|
+
| Windows CLI | [main.exe](https://github.com/PonyLianna/pythonQEPest/releases/download/v2.0.0-alpha/main.exe) |
|
|
25
|
+
| Windows GUI | [gui.exe](https://github.com/PonyLianna/pythonQEPest/releases/download/v2.0.0-alpha/gui.exe) |
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install pythonQEPest
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or from source:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/PonyLianna/pythonQEPest.git
|
|
38
|
+
cd pythonQEPest
|
|
39
|
+
poetry install
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### With GUI support
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install pythonQEPest[gui]
|
|
46
|
+
# or
|
|
47
|
+
poetry install --extras ui
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### CLI
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pythonqepest -i data.txt -o result.txt
|
|
57
|
+
pythonqepest --input data.txt --format json
|
|
58
|
+
pythonqepest -v # show version
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### GUI
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pythonqepest-gui
|
|
65
|
+
# or
|
|
66
|
+
python -m pythonQEPest.gui.gui
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Python API
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from pythonQEPest import QEPest, QEPestInput
|
|
73
|
+
|
|
74
|
+
# Create input data
|
|
75
|
+
qepest = QEPest()
|
|
76
|
+
qepest.initialize_coefficients()
|
|
77
|
+
qepest.initialize_normalisers()
|
|
78
|
+
|
|
79
|
+
# From individual values
|
|
80
|
+
inp = QEPestInput(
|
|
81
|
+
name="mol1",
|
|
82
|
+
mol_weight=240.2127,
|
|
83
|
+
log_p=3.2392,
|
|
84
|
+
hbond_acceptors=5,
|
|
85
|
+
hbond_donors=1,
|
|
86
|
+
rotatable_bonds=4,
|
|
87
|
+
aromatic_rings=1
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
result = qepest.compute_params(inp)
|
|
91
|
+
|
|
92
|
+
print(result.name) # mol1
|
|
93
|
+
print(result.data.qe_herb) # 0.8511
|
|
94
|
+
print(result.data.qe_insect) # 0.5339
|
|
95
|
+
print(result.data.qe_fung) # 0.6224
|
|
96
|
+
|
|
97
|
+
# Convert to array
|
|
98
|
+
print(result.to_array()) # ["mol1", 0.6224, 0.8511, 0.5339]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Input Format
|
|
102
|
+
|
|
103
|
+
The input file should be a tab-separated text file with the following columns:
|
|
104
|
+
|
|
105
|
+
| Column | Description |
|
|
106
|
+
|--------|-------------|
|
|
107
|
+
| Name | Molecule name |
|
|
108
|
+
| MW | Molecular weight (g/mol) |
|
|
109
|
+
| LogP | Hydrophobicity (octanol-water partition coefficient) |
|
|
110
|
+
| HBA | Number of hydrogen bond acceptors |
|
|
111
|
+
| HBD | Number of hydrogen bond donors |
|
|
112
|
+
| RB | Number of rotatable bonds |
|
|
113
|
+
| arR | Number of aromatic rings |
|
|
114
|
+
|
|
115
|
+
Example `data.txt`:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
Name MW LogP HBA HBD RB arR
|
|
119
|
+
mol1 240.2127 3.2392 5 1 4 1
|
|
120
|
+
mol2 249.091 3.0273 3 1 5 1
|
|
121
|
+
mol3 308.354 2.1086 1 0 7 1
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Output Format
|
|
125
|
+
|
|
126
|
+
### TXT (default output for CLI)
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
Name QEF QEH QEI
|
|
130
|
+
mol1 0.6224 0.8511 0.5339
|
|
131
|
+
mol2 0.7310 0.9750 0.6913
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### JSON
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
[
|
|
138
|
+
{"name": "mol1", "qe_fung": 0.6224, "qe_herb": 0.8511, "qe_insect": 0.5339},
|
|
139
|
+
{"name": "mol2", "qe_fung": 0.731, "qe_herb": 0.975, "qe_insect": 0.6913}
|
|
140
|
+
]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Configuration
|
|
144
|
+
|
|
145
|
+
### Custom Coefficients
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from pythonQEPest import QEPest
|
|
149
|
+
|
|
150
|
+
custom_coefficients = {
|
|
151
|
+
"herb": [
|
|
152
|
+
(70.77, 283.0, 84.97, -1.185),
|
|
153
|
+
(93.81, 3.077, 1.434, 0.6164),
|
|
154
|
+
# ... 6 tuples total
|
|
155
|
+
],
|
|
156
|
+
"insect": [...],
|
|
157
|
+
"fung": [...]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
qepest = QEPest(coefficients=custom_coefficients)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Custom Normalisers
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from pythonQEPest import QEPest
|
|
167
|
+
from pythonQEPest.dto.normalisation.Normaliser import Normaliser
|
|
168
|
+
|
|
169
|
+
qepest = QEPest(normalisers={"herb": Normaliser(...), ...})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## CLI Options
|
|
173
|
+
|
|
174
|
+
| Option | Description | Default |
|
|
175
|
+
|--------|-------------|---------|
|
|
176
|
+
| `-i`, `--input` | Input file path | data.txt |
|
|
177
|
+
| `-o`, `--output` | Output file path | data.out.txt |
|
|
178
|
+
| `-f`, `--format` | Output format (json, txt) | txt |
|
|
179
|
+
| `-v`, `--version` | Show version | - |
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
### Run tests
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
poetry run pytest
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Build
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# CLI executable
|
|
193
|
+
poetry run poe build-simple
|
|
194
|
+
|
|
195
|
+
# GUI executable
|
|
196
|
+
poetry run poe build-gui
|
|
197
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pythonQEPest"
|
|
3
|
+
version = "2.0.0a2"
|
|
4
|
+
description = "Java QEPest but written in Python"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12,<3.15"
|
|
7
|
+
authors = [{ name = "Lina", email = "knocker767@gmail.com" }]
|
|
8
|
+
dependencies = ["pydantic==2.12.5", "python-dotenv>=1.2.1,<2.0.0"]
|
|
9
|
+
|
|
10
|
+
[project.optional-dependencies]
|
|
11
|
+
gui = ["pyperclip>=1.11.0,<2.0.0"]
|
|
12
|
+
rdkit = ["rdkit (>=2024.3.1,<2026.0.0)"]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
pythonqepest = "pythonQEPest.cli.cli:main"
|
|
16
|
+
|
|
17
|
+
[project.gui-scripts]
|
|
18
|
+
pythonqepest-gui = "pythonQEPest.gui.gui:main"
|
|
19
|
+
|
|
20
|
+
[tool.poetry]
|
|
21
|
+
packages = [{ include = "pythonQEPest" }]
|
|
22
|
+
|
|
23
|
+
[dependency-groups]
|
|
24
|
+
dev = [
|
|
25
|
+
"pytest (>=9.0.0)",
|
|
26
|
+
"pre-commit (>=4.3.0,<5.0.0)",
|
|
27
|
+
"pyinstaller (>=6.18.0,<7.0.0)",
|
|
28
|
+
"poethepoet[poetry_plugin] (>=0.39.0)",
|
|
29
|
+
"pytest-cov (>=7.0.0,<8.0.0)",
|
|
30
|
+
"twine (>=6.2.0,<7.0.0)",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[build-system]
|
|
34
|
+
requires = ["poetry-core>=1.0.0", "setuptools>=40.8.0"]
|
|
35
|
+
build-backend = "poetry.core.masonry.api"
|
|
36
|
+
|
|
37
|
+
[tool.flake8]
|
|
38
|
+
max-line-length = 88
|
|
39
|
+
extend-ignore = ["E203", "W503"]
|
|
40
|
+
exclude = [".venv", ".git", "__pycache__", "build", "dist"]
|
|
41
|
+
|
|
42
|
+
[tool.poe.tasks]
|
|
43
|
+
test = "pytest"
|
|
44
|
+
build-simple = "pyinstaller --onefile pythonQEPest/main.py"
|
|
45
|
+
build-gui = "pyinstaller --onefile --noconsole pythonQEPest/gui/gui.py"
|
|
46
|
+
publish-pypy = "twine upload --repository pythonQEPest dist/*"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import logging
|
|
5
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Sequence
|
|
8
|
+
|
|
9
|
+
from pythonQEPest.dto import QEPestFile
|
|
10
|
+
from pythonQEPest.services.QEPestFileService import QEPestFileService
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _resolve_package_version() -> str:
|
|
16
|
+
try:
|
|
17
|
+
return version("pythonQEPest")
|
|
18
|
+
except PackageNotFoundError:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
import tomllib # py3.11+
|
|
23
|
+
|
|
24
|
+
pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
25
|
+
data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
|
|
26
|
+
return data["project"]["version"]
|
|
27
|
+
except Exception:
|
|
28
|
+
return "0+unknown"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
32
|
+
parser = argparse.ArgumentParser(
|
|
33
|
+
prog="pythonqepest",
|
|
34
|
+
description="Compute QEPest scores from a tab-separated input file.",
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"-v",
|
|
38
|
+
"--version",
|
|
39
|
+
action="version",
|
|
40
|
+
version=f"%(prog)s {_resolve_package_version()}",
|
|
41
|
+
help="Show program's version number.",
|
|
42
|
+
)
|
|
43
|
+
parser.add_argument(
|
|
44
|
+
"-i",
|
|
45
|
+
"--input",
|
|
46
|
+
default="data.txt",
|
|
47
|
+
help="Path to input tab-separated file with "
|
|
48
|
+
+ "QEPest descriptors (default: data.txt).",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"-o",
|
|
53
|
+
"--output",
|
|
54
|
+
default="data.out.txt",
|
|
55
|
+
help="Path to output tab-separated file with "
|
|
56
|
+
+ "QEPest descriptors (default: data.txt.out).",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"-f",
|
|
61
|
+
"--format",
|
|
62
|
+
default="txt",
|
|
63
|
+
help="Format to output file with QEPest (json, txt).",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
"--smiles",
|
|
68
|
+
action="store_true",
|
|
69
|
+
help="Input file contains SMILES strings "
|
|
70
|
+
"(one per line) instead of descriptors.",
|
|
71
|
+
)
|
|
72
|
+
return parser
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
76
|
+
from dotenv import load_dotenv
|
|
77
|
+
|
|
78
|
+
from pythonQEPest.core.qepest import QEPest
|
|
79
|
+
from pythonQEPest.logger import init_logger
|
|
80
|
+
|
|
81
|
+
args = build_parser().parse_args(argv)
|
|
82
|
+
|
|
83
|
+
load_dotenv()
|
|
84
|
+
init_logger()
|
|
85
|
+
|
|
86
|
+
logger.debug("CLI initiated")
|
|
87
|
+
logger.info(f"CLI args: {argv}")
|
|
88
|
+
|
|
89
|
+
service = QEPestFileService(
|
|
90
|
+
qepest=QEPest(),
|
|
91
|
+
qepest_file=QEPestFile(
|
|
92
|
+
input_file=args.input,
|
|
93
|
+
output_file=args.output,
|
|
94
|
+
format=args.format,
|
|
95
|
+
smiles=args.smiles,
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
service.read_file_and_compute_params()
|
|
100
|
+
|
|
101
|
+
return 0 if not service.error else 1
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from pythonQEPest.config.qepest_default import qepest_default
|
|
2
|
+
from pythonQEPest.config.normalise import normalise_default
|
|
3
|
+
from pythonQEPest.config.qepest_config import QEPestConfig
|
|
4
|
+
from pythonQEPest.config.config_provider import ConfigProvider
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"normalise_default",
|
|
8
|
+
"qepest_default",
|
|
9
|
+
"ConfigProvider",
|
|
10
|
+
"QEPestConfig",
|
|
11
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
normalise_default = {
|
|
2
|
+
"herb": (69.5849922, 94.4228257, 120.4572352, 228.1589796, 89.7012502, 276.9634213),
|
|
3
|
+
"insect": (
|
|
4
|
+
78.2919965,
|
|
5
|
+
71.2829691,
|
|
6
|
+
133.9224801,
|
|
7
|
+
331.170104,
|
|
8
|
+
70.5540709,
|
|
9
|
+
193.0023343,
|
|
10
|
+
),
|
|
11
|
+
"fung": (53.3719946, 52.773116, 73.7976536, 144.9887053, 41.4385926, 102.3024319),
|
|
12
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from pythonQEPest.dto.pest_type.PestTypeConfig import PestTypeConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class QEPestConfig(BaseModel):
|
|
9
|
+
name: Optional[str] = "HerbInsectFung"
|
|
10
|
+
pest_types: list[PestTypeConfig]
|
|
11
|
+
|
|
12
|
+
def get_pest_names(self) -> list[str]:
|
|
13
|
+
return [pest.name for pest in self.pest_types]
|
|
14
|
+
|
|
15
|
+
def get_coefficients(
|
|
16
|
+
self, pest_name: str
|
|
17
|
+
) -> list[tuple[float, float, float, float]]:
|
|
18
|
+
for pest in self.pest_types:
|
|
19
|
+
if pest.name == pest_name:
|
|
20
|
+
return pest.coefficients.as_set()
|
|
21
|
+
|
|
22
|
+
raise ValueError(f"Pest type '{pest_name}' not found")
|
|
23
|
+
|
|
24
|
+
def get_normaliser(
|
|
25
|
+
self, pest_name: str
|
|
26
|
+
) -> tuple[float, float, float, float, float, float]:
|
|
27
|
+
for pest in self.pest_types:
|
|
28
|
+
if pest.name == pest_name:
|
|
29
|
+
return pest.normaliser
|
|
30
|
+
|
|
31
|
+
raise ValueError(f"Pest type '{pest_name}' not found")
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
qepest_default = {
|
|
2
|
+
"herb": [
|
|
3
|
+
(70.77, 283.0, 84.97, -1.185), # mwH
|
|
4
|
+
(93.81, 3.077, 1.434, 0.6164), # logpH
|
|
5
|
+
(117.6, 2.409, 1.567, 7.155), # hbaH
|
|
6
|
+
(233.4, 0.4535, -1.48, 4.47), # hbdH
|
|
7
|
+
(84.7, 4.758, -2.423, 5.437), # rbH
|
|
8
|
+
(301.8, 1.101, 0.8869, -22.81), # arRCH
|
|
9
|
+
],
|
|
10
|
+
"insect": [
|
|
11
|
+
(76.38, 298.3, 83.64, 1.912), # mwI
|
|
12
|
+
(74.27, 4.555, -2.193, -2.987), # logpI
|
|
13
|
+
(139.4, 1.363, 1.283, 0.5341), # hbaI
|
|
14
|
+
(670.6, -1.163, 0.7856, 0.7951), # hbdI
|
|
15
|
+
(65.49, 6.219, -2.448, 5.318), # rbI
|
|
16
|
+
(287.5, 0.305, 1.554, -88.64), # arRCI
|
|
17
|
+
],
|
|
18
|
+
"fung": [
|
|
19
|
+
(51.03, 314.2, -56.31, 2.342), # mwF
|
|
20
|
+
(50.73, 3.674, -1.238, 2.067), # logpF
|
|
21
|
+
(73.79, 1.841, 1.326, 0.5158), # hbaF
|
|
22
|
+
(164.7, -0.9762, -2.027, 1.384), # hbdF
|
|
23
|
+
(40.91, 1.822, 2.582, 0.6235), # rbF
|
|
24
|
+
(134.4, 0.8383, 1.347, -31.17), # arRCF
|
|
25
|
+
],
|
|
26
|
+
}
|