pythonQEPest 2.0.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. pythonQEPest/.env.example +4 -0
  2. pythonQEPest/__init__.py +11 -0
  3. pythonQEPest/cli/__init__.py +7 -0
  4. pythonQEPest/cli/cli.py +101 -0
  5. pythonQEPest/config/__init__.py +11 -0
  6. pythonQEPest/config/config_provider.py +9 -0
  7. pythonQEPest/config/normalise.py +12 -0
  8. pythonQEPest/config/qepest_config.py +31 -0
  9. pythonQEPest/config/qepest_default.py +26 -0
  10. pythonQEPest/core/__init__.py +7 -0
  11. pythonQEPest/core/qepest.py +98 -0
  12. pythonQEPest/core/qepest_meta.py +28 -0
  13. pythonQEPest/data.txt +2 -0
  14. pythonQEPest/data.txt.out +2 -0
  15. pythonQEPest/dto/QEPestData.py +21 -0
  16. pythonQEPest/dto/QEPestFile.py +34 -0
  17. pythonQEPest/dto/QEPestInput.py +60 -0
  18. pythonQEPest/dto/QEPestOutput.py +13 -0
  19. pythonQEPest/dto/__init__.py +27 -0
  20. pythonQEPest/dto/coefficients/QEPestCoefficient.py +57 -0
  21. pythonQEPest/dto/coefficients/QEPestCoefficientList.py +29 -0
  22. pythonQEPest/dto/coefficients/QEPestCoefficientNumerics.py +44 -0
  23. pythonQEPest/dto/coefficients/__init__.py +7 -0
  24. pythonQEPest/dto/normalisation/Normaliser.py +16 -0
  25. pythonQEPest/dto/normalisation/__init__.py +3 -0
  26. pythonQEPest/dto/pest_type/PestTypeCoefficient.py +30 -0
  27. pythonQEPest/dto/pest_type/PestTypeConfig.py +9 -0
  28. pythonQEPest/dto/pest_type/__init__.py +4 -0
  29. pythonQEPest/gui/__init__.py +7 -0
  30. pythonQEPest/gui/actions/__init__.py +9 -0
  31. pythonQEPest/gui/actions/action_clicks.py +42 -0
  32. pythonQEPest/gui/actions/actions_crud.py +131 -0
  33. pythonQEPest/gui/actions/actions_other.py +126 -0
  34. pythonQEPest/gui/elements/ButtonsFrame.py +50 -0
  35. pythonQEPest/gui/elements/DataTree.py +23 -0
  36. pythonQEPest/gui/elements/EditWindow.py +63 -0
  37. pythonQEPest/gui/elements/Menu.py +12 -0
  38. pythonQEPest/gui/elements/ResultTree.py +22 -0
  39. pythonQEPest/gui/elements/SaveButton.py +10 -0
  40. pythonQEPest/gui/elements/__init__.py +17 -0
  41. pythonQEPest/gui/gui.py +87 -0
  42. pythonQEPest/gui/gui_meta.py +17 -0
  43. pythonQEPest/gui/utility/DataManager.py +76 -0
  44. pythonQEPest/gui/utility/DataManagerMeta.py +8 -0
  45. pythonQEPest/gui/utility/__init__.py +6 -0
  46. pythonQEPest/helpers/__init__.py +17 -0
  47. pythonQEPest/helpers/check_nan.py +8 -0
  48. pythonQEPest/helpers/compute_df.py +5 -0
  49. pythonQEPest/helpers/get_num_of_cols.py +2 -0
  50. pythonQEPest/helpers/get_values_from_line.py +5 -0
  51. pythonQEPest/helpers/norm.py +33 -0
  52. pythonQEPest/helpers/round_to_4digs.py +2 -0
  53. pythonQEPest/logger.py +58 -0
  54. pythonQEPest/main.py +4 -0
  55. pythonQEPest/providers/__init__.py +6 -0
  56. pythonQEPest/providers/default_provider.py +23 -0
  57. pythonQEPest/providers/json_provider.py +30 -0
  58. pythonQEPest/providers/txt_provider.py +46 -0
  59. pythonQEPest/services/QEPestFileService.py +125 -0
  60. pythonQEPest/services/__init__.py +3 -0
  61. pythonqepest-2.0.0a2.dist-info/METADATA +217 -0
  62. pythonqepest-2.0.0a2.dist-info/RECORD +64 -0
  63. pythonqepest-2.0.0a2.dist-info/WHEEL +4 -0
  64. pythonqepest-2.0.0a2.dist-info/entry_points.txt +6 -0
@@ -0,0 +1,4 @@
1
+ LOG_LEVEL="INFO"
2
+ LOG_FILE_LOCATION="logs/app.log"
3
+
4
+ APP_DEBUG_ENABLE="false"
@@ -0,0 +1,11 @@
1
+ from pythonQEPest.core import QEPest
2
+ from pythonQEPest.dto import QEPestData
3
+ from pythonQEPest.dto import QEPestInput
4
+ from pythonQEPest.dto import QEPestOutput
5
+
6
+ __all__ = [
7
+ "QEPest",
8
+ "QEPestData",
9
+ "QEPestInput",
10
+ "QEPestOutput",
11
+ ]
@@ -0,0 +1,7 @@
1
+ def main():
2
+ from pythonQEPest.cli.cli import main as _main
3
+
4
+ return _main()
5
+
6
+
7
+ __all__ = ["main"]
@@ -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,9 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from pythonQEPest.config.qepest_config import QEPestConfig
4
+
5
+
6
+ class ConfigProvider(ABC):
7
+ @abstractmethod
8
+ def load(self) -> QEPestConfig:
9
+ pass
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ from .qepest import QEPest
2
+ from .qepest_meta import QEPestMeta
3
+
4
+ __all__ = [
5
+ "QEPestMeta",
6
+ "QEPest",
7
+ ]
@@ -0,0 +1,98 @@
1
+ import logging
2
+ import math
3
+ from typing import Optional
4
+
5
+ from pythonQEPest.config import ConfigProvider
6
+ from pythonQEPest.core.qepest_meta import QEPestMeta
7
+ from pythonQEPest.config.qepest_config import QEPestConfig
8
+ from pythonQEPest.dto import QEPestData
9
+
10
+ from pythonQEPest.dto.QEPestInput import QEPestInput
11
+ from pythonQEPest.dto.QEPestOutput import QEPestOutput
12
+ from pythonQEPest.dto.normalisation.Normaliser import Normaliser
13
+ from pythonQEPest.helpers.check_nan import check_nan
14
+ from pythonQEPest.helpers.compute_df import compute_df
15
+ from pythonQEPest.helpers.get_values_from_line import get_values_from_line
16
+ from pythonQEPest.helpers.round_to_4digs import round_to_4digs
17
+ from pythonQEPest.providers import DefaultConfigProvider
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class QEPest(QEPestMeta):
23
+ def __init__(self, provider: Optional[ConfigProvider] = None, *args, **kwargs):
24
+ super().__init__(*args, **kwargs)
25
+
26
+ self.config: QEPestConfig
27
+ self.normalisers: dict[str, Normaliser] = {}
28
+ self.qex: QEPestData = QEPestData({})
29
+
30
+ logger.debug("QEPest initialization")
31
+
32
+ self.initialise_config(provider)
33
+
34
+ logger.debug("QEPest initialization successful")
35
+
36
+ def initialise_config(self, provider: Optional[ConfigProvider] = None):
37
+ logger.debug("Config initialisation")
38
+ if provider is None:
39
+ logger.debug("Config is empty. Loading default one.")
40
+ provider = DefaultConfigProvider()
41
+
42
+ self.config = provider.load()
43
+ logger.debug(f"Config {self.config} loaded")
44
+
45
+ for pest in self.config.pest_types:
46
+ self.normalisers[pest.name] = Normaliser(pest.normaliser)
47
+
48
+ def _log_compute_df(
49
+ self, func, index: int, lst: list[float], data_lst: list
50
+ ) -> float:
51
+ df_result = compute_df(lst[index], *data_lst[index])
52
+ return math.log(func(df_result, index))
53
+
54
+ def get_names(self) -> list[str]:
55
+ return self.config.get_pest_names()
56
+
57
+ def compute_params(self, data_input: QEPestInput) -> QEPestOutput:
58
+ self.get_qex_values(
59
+ get_values_from_line(list(data_input.model_dump().values()))
60
+ )
61
+ return QEPestOutput(data=self.qex, name=data_input.name)
62
+
63
+ def get_qex_values(self, d: list[float]) -> QEPestData:
64
+ names = self.get_names()
65
+
66
+ if len(names) == 0:
67
+ raise ValueError(
68
+ "No pest types configured. " "Please provide a valid configuration."
69
+ )
70
+
71
+ qe_values = dict.fromkeys(names, 0.0)
72
+
73
+ d_num = len(d)
74
+ for i in range(d_num):
75
+ for name in names:
76
+ coeffs = self.config.get_coefficients(name)
77
+ normaliser = self.normalisers[name]
78
+ qe_values[name] += self._log_compute_df(
79
+ func=normaliser.norm,
80
+ index=i,
81
+ lst=d,
82
+ data_lst=coeffs,
83
+ )
84
+
85
+ result = [round_to_4digs(math.exp(qe_values[name] / d_num)) for name in names]
86
+
87
+ result = check_nan(result)
88
+
89
+ self.qex = QEPestData(
90
+ {f"qe_{name}": result[idx] for idx, name in enumerate(names)}
91
+ )
92
+
93
+ return self.qex
94
+
95
+
96
+ if __name__ == "__main__":
97
+ qepest = QEPest()
98
+ qepest.get_qex_values([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0])
@@ -0,0 +1,28 @@
1
+ import os
2
+ from abc import abstractmethod, ABC
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from pythonQEPest.dto import QEPestInput, QEPestOutput
7
+
8
+
9
+ class QEPestMeta(ABC):
10
+ def __init__(self, *args, **kwargs):
11
+ self.qex: BaseModel | None = None
12
+
13
+ self.col_number: int = 7
14
+ self.dir: str = os.getcwd()
15
+
16
+ @abstractmethod
17
+ def compute_params(self, data_input: QEPestInput) -> QEPestOutput:
18
+ pass
19
+
20
+ @abstractmethod
21
+ def get_qex_values(self, d: list[float]) -> None:
22
+ pass
23
+
24
+ @abstractmethod
25
+ def _log_compute_df(
26
+ self, func, index: int, lst: list[float], data_lst: list
27
+ ) -> float:
28
+ pass
pythonQEPest/data.txt ADDED
@@ -0,0 +1,2 @@
1
+ Name MW LogP HBA HBD RB arR
2
+ Nc1nc2CCCC3O[C@H](CCC)C(=O)c(n1)c23 247.29799999999994 1.8178 5 1 2 1
@@ -0,0 +1,2 @@
1
+ Name QEH QEI QEF
2
+ Nc1nc2CCCC3O[C@H](CCC)C(=O)c(n1)c23 0.7387 0.4635 0.5941
@@ -0,0 +1,21 @@
1
+ from pydantic import RootModel, model_validator
2
+
3
+
4
+ class QEPestData(RootModel[dict[str, float]]):
5
+ @model_validator(mode="before")
6
+ @classmethod
7
+ def handle_input(cls, data):
8
+ if data is None:
9
+ return {}
10
+ if isinstance(data, dict):
11
+ return data
12
+ return data
13
+
14
+ def __getattr__(self, name: str) -> float:
15
+ return self.root.get(name, 0.0)
16
+
17
+ def __setattr__(self, name: str, value: float) -> None:
18
+ if name == "root":
19
+ super().__setattr__(name, value)
20
+ else:
21
+ self.root[name] = value
@@ -0,0 +1,34 @@
1
+ from enum import Enum
2
+ from typing import Optional
3
+
4
+ from pydantic import BaseModel, model_validator
5
+
6
+
7
+ class QEPestFormat(Enum):
8
+ TXT = "txt"
9
+ JSON = "json"
10
+
11
+
12
+ class QEPestFile(BaseModel):
13
+ input_file: Optional[str] = None
14
+ output_file: Optional[str] = None
15
+ format: Optional[QEPestFormat] = QEPestFormat.TXT
16
+ smiles: Optional[bool] = False
17
+
18
+ model_config = {"arbitrary_types_allowed": True}
19
+
20
+ @model_validator(mode="after")
21
+ def set_defaults(self):
22
+ if self.input_file is None:
23
+ self.input_file = "data.txt"
24
+
25
+ if self.format is None:
26
+ self.format = QEPestFormat.TXT
27
+
28
+ formatted_output = self.input_file.replace(".txt", "").replace(".json", "")
29
+ if self.format == QEPestFormat.JSON:
30
+ self.output_file = f"{formatted_output}.out.json"
31
+ else:
32
+ self.output_file = f"{formatted_output}.out.txt"
33
+
34
+ return self
@@ -0,0 +1,60 @@
1
+ import logging
2
+ from typing import Union
3
+
4
+ from pydantic import BaseModel
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ class QEPestInput(BaseModel):
10
+ name: str = ""
11
+
12
+ mol_weight: float = 0.0
13
+ log_p: float = 0.0
14
+
15
+ hbond_acceptors: int = 0
16
+ hbond_donors: int = 0
17
+
18
+ rotatable_bonds: int = 0
19
+ aromatic_rings: int = 0
20
+
21
+ @classmethod
22
+ def from_array(cls, data: Union[list, tuple, set]):
23
+ if len(data) != 7:
24
+ raise ValueError(f"Expected 7 elements, got {len(data)}")
25
+ return cls(
26
+ name=data[0],
27
+ mol_weight=float(data[1]),
28
+ log_p=float(data[2]),
29
+ hbond_acceptors=int(data[3]),
30
+ hbond_donors=int(data[4]),
31
+ rotatable_bonds=int(data[5]),
32
+ aromatic_rings=int(data[6]),
33
+ )
34
+
35
+ @classmethod
36
+ def from_smiles(cls, smiles: str, name: str = ""):
37
+ try:
38
+ from rdkit import Chem
39
+ from rdkit.Chem import Descriptors
40
+ except ImportError:
41
+ logger.warning(
42
+ "RDKit is not installed. Install it with: poetry install --with rdkit. "
43
+ "Returning QEPestInput with default values."
44
+ )
45
+ return cls(name=name)
46
+
47
+ mol = Chem.MolFromSmiles(smiles)
48
+
49
+ if mol is None:
50
+ raise ValueError(f"Invalid SMILES: {smiles}")
51
+
52
+ return cls(
53
+ name=name,
54
+ mol_weight=Descriptors.ExactMolWt(mol),
55
+ log_p=Descriptors.MolLogP(mol),
56
+ hbond_acceptors=Descriptors.NumHAcceptors(mol),
57
+ hbond_donors=Descriptors.NumHDonors(mol),
58
+ rotatable_bonds=Descriptors.NumRotatableBonds(mol),
59
+ aromatic_rings=Descriptors.NumAromaticRings(mol),
60
+ )
@@ -0,0 +1,13 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import BaseModel
4
+ from pythonQEPest.dto.QEPestData import QEPestData
5
+
6
+
7
+ class QEPestOutput(BaseModel):
8
+ data: QEPestData
9
+ name: Optional[str] = ""
10
+
11
+ def to_array(self) -> list:
12
+ values = list(self.data.root.values())
13
+ return [self.name] + values
@@ -0,0 +1,27 @@
1
+ from pythonQEPest.dto.QEPestData import QEPestData
2
+ from pythonQEPest.dto.QEPestInput import QEPestInput
3
+ from pythonQEPest.dto.QEPestFile import QEPestFile, QEPestFormat
4
+ from pythonQEPest.dto.QEPestOutput import QEPestOutput
5
+
6
+ from pythonQEPest.dto.coefficients import QEPestCoefficient
7
+ from pythonQEPest.dto.coefficients import QEPestCoefficientList
8
+ from pythonQEPest.dto.coefficients import QEPestCoefficientNumerics
9
+
10
+ from pythonQEPest.dto.normalisation import Normaliser
11
+
12
+ from pythonQEPest.dto.pest_type.PestTypeCoefficient import PestTypeCoefficient
13
+ from pythonQEPest.dto.pest_type.PestTypeConfig import PestTypeConfig
14
+
15
+ __all__ = [
16
+ "QEPestOutput",
17
+ "QEPestData",
18
+ "QEPestInput",
19
+ "QEPestFile",
20
+ "QEPestFormat",
21
+ "PestTypeConfig",
22
+ "PestTypeCoefficient",
23
+ "Normaliser",
24
+ "QEPestCoefficientNumerics",
25
+ "QEPestCoefficientList",
26
+ "QEPestCoefficient",
27
+ ]
@@ -0,0 +1,57 @@
1
+ from pydantic import BaseModel
2
+
3
+ from pythonQEPest.dto.coefficients import QEPestCoefficientNumerics
4
+
5
+
6
+ class QEPestCoefficient(BaseModel):
7
+ name: str
8
+ coefficients: QEPestCoefficientNumerics
9
+
10
+ def __init__(self, *args, **kwargs):
11
+ if args:
12
+ if len(args) != 1:
13
+ raise ValueError(f"Expected len(args) == 1, got {len(args)}")
14
+
15
+ # In case of {"test": [[1,2,3,4],[1,2,3,4],[1,2,3,4]}
16
+ if len(args[0]) == 1:
17
+ must_be_dict = args[0]
18
+ if isinstance(must_be_dict, dict):
19
+ key = list(must_be_dict.keys())[0]
20
+ coefficients = QEPestCoefficientNumerics(must_be_dict[key])
21
+ super().__init__(name=key, coefficients=coefficients)
22
+
23
+ # In case of ["test", [[1,2,3,4],[1,2,3,4],[1,2,3,4]]
24
+ elif len(args[0]) == 2:
25
+ arr = args[0]
26
+ if (
27
+ isinstance(arr, tuple)
28
+ or isinstance(arr, set)
29
+ or isinstance(arr, list)
30
+ ):
31
+ name = arr[0]
32
+ coefficients = QEPestCoefficientNumerics(arr[1])
33
+ super().__init__(name=name, coefficients=coefficients)
34
+
35
+ elif kwargs:
36
+ super().__init__(**kwargs)
37
+ else:
38
+ raise ValueError(
39
+ "No name and coefficients provided. Please provide either a "
40
+ + "name and coefficients tuple or keyword arguments."
41
+ )
42
+
43
+
44
+ if __name__ == "__main__":
45
+ # Example usage
46
+ coefficients = QEPestCoefficient(
47
+ mw=[0.1, 0.2, 0.3, 0.4],
48
+ logp=[0.1, 0.2, 0.3, 0.4],
49
+ hba=[0.1, 0.2, 0.3, 0.4],
50
+ hbd=[0.1, 0.2, 0.3, 0.4],
51
+ rb=[0.1, 0.2, 0.3, 0.4],
52
+ ar=[0.1, 0.2, 0.3, 0.4],
53
+ )
54
+ print(coefficients)
55
+
56
+ coefficients_alternative = QEPestCoefficient([[0.1, 0.2, 0.3, 0.4] * 6])
57
+ print(coefficients_alternative)
@@ -0,0 +1,29 @@
1
+ from typing import Optional, List
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from pythonQEPest.dto.coefficients import QEPestCoefficient
6
+
7
+
8
+ class QEPestCoefficientList(BaseModel):
9
+ name: Optional[str]
10
+ named_coefficients: List[QEPestCoefficient]
11
+
12
+ # TODO: Done all the cases and make some sort of docs here, pls
13
+ def __init__(self, *args, **kwargs):
14
+ if args:
15
+ named_coeff = args[0]
16
+ if len(named_coeff) == 1:
17
+ pass
18
+ elif len(named_coeff) > 1:
19
+ if isinstance(named_coeff, dict):
20
+ lst = [QEPestCoefficient({i: z}) for i, z in named_coeff.items()]
21
+ super().__init__(name="generic", named_coefficients=lst)
22
+
23
+ elif kwargs:
24
+ super().__init__(**kwargs)
25
+ else:
26
+ raise ValueError(
27
+ "No name and coefficients provided. Please provide either a "
28
+ + "name and coefficients tuple or keyword arguments."
29
+ )
@@ -0,0 +1,44 @@
1
+ from pydantic import BaseModel
2
+
3
+ CoefficientTuple = tuple[float, float, float, float]
4
+
5
+
6
+ class QEPestCoefficientNumerics(BaseModel):
7
+ mw: CoefficientTuple
8
+ logp: CoefficientTuple
9
+ hba: CoefficientTuple
10
+ hbd: CoefficientTuple
11
+ rb: CoefficientTuple
12
+ ar: CoefficientTuple
13
+
14
+ def __init__(self, *args, **kwargs):
15
+ if args:
16
+ # In case of [[1,2,3,4],[1,2,3,4],[1,2,3,4]]
17
+ # I don't want it to be a pain to init D:
18
+ if len(args) != 1:
19
+ raise ValueError(
20
+ f"Expected a single list of coefficients, got {len(args)}"
21
+ )
22
+
23
+ coefficients = args[0]
24
+ if len(coefficients) != 6:
25
+ raise ValueError(
26
+ "Expected list with structure [[1,2,3,4,5,6], ",
27
+ "[1,2,3,4,5,6], [1,...] ...] got ",
28
+ f"{len(coefficients)} and {coefficients}",
29
+ )
30
+
31
+ coefficients_mapped = {
32
+ field: coefficients[i]
33
+ for i, field in enumerate(["mw", "logp", "hba", "hbd", "rb", "ar"])
34
+ }
35
+ super().__init__(**coefficients_mapped)
36
+
37
+ elif kwargs:
38
+ super().__init__(**kwargs)
39
+
40
+ else:
41
+ raise ValueError(
42
+ "No coefficients provided. Please provide either a ",
43
+ "list of coefficient tuples or keyword arguments.",
44
+ )
@@ -0,0 +1,7 @@
1
+ from pythonQEPest.dto.coefficients.QEPestCoefficientNumerics import (
2
+ QEPestCoefficientNumerics,
3
+ )
4
+ from pythonQEPest.dto.coefficients.QEPestCoefficient import QEPestCoefficient
5
+ from pythonQEPest.dto.coefficients.QEPestCoefficientList import QEPestCoefficientList
6
+
7
+ __all__ = ["QEPestCoefficientNumerics", "QEPestCoefficient", "QEPestCoefficientList"]