Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9bb0748
style[.env.example]: redundant spacing
PonyLianna Feb 8, 2026
e531d66
feat[python-package]: Workflow update
PonyLianna Feb 8, 2026
e401086
fix[python-package]: Pytest-coverage
PonyLianna Feb 8, 2026
9bbed3c
fix[pyproject, python-package]: forgot to commit pyproject ><
PonyLianna Feb 8, 2026
29f12a4
feat: Attemption of making a normal package
PonyLianna Feb 8, 2026
2c26cc6
feat[tests]: for previous commit
PonyLianna Feb 8, 2026
83cd1e7
fix[poetry.lock]: no comments here
PonyLianna Feb 8, 2026
c1bf0f2
fix: Mmm... Test coverage for only 40% instead of 60%
PonyLianna Feb 8, 2026
4ce7d19
fix: smoke test
PonyLianna Feb 8, 2026
c2b0c1d
feat[requirements]: update
PonyLianna Feb 8, 2026
abdaa39
fix[__init__]: absolete imports
PonyLianna Feb 9, 2026
1269bd0
fix[test_import_contract]: More robust smoke test
PonyLianna Feb 9, 2026
5aa34d2
fix: No more output files in QEPest Main logic
PonyLianna Feb 9, 2026
46cc00d
fix[test_cli_contract]: accidentially committed wrong test structure :/
PonyLianna Feb 9, 2026
7fbd772
feat[imports]: QEPestOutput
PonyLianna Feb 9, 2026
b4b994f
feat[test_qepest_file]: QEPestFile test
PonyLianna Feb 9, 2026
dffc2c7
feat[cli]: tests unification + version command
PonyLianna Feb 11, 2026
cc4f2bf
feat[test_import_contract]: Standartisation + helpers import test
PonyLianna Feb 11, 2026
399ceb9
style[test_logging]: Standartisation
PonyLianna Feb 11, 2026
cd2d127
style: rearrange
PonyLianna Feb 11, 2026
a9351fb
feat[CLI]: More stable approach of getting version of app
PonyLianna Feb 11, 2026
cec94ec
fix[tests]: Disable helpers imports
PonyLianna Feb 11, 2026
6bf3862
update[pre-commit]: flake8, black, check-merge-conflict, debug-statem…
PonyLianna Feb 11, 2026
81d96fc
fix[version]: 1.1.4
PonyLianna Feb 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 37 additions & 26 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ on:
push:
branches: [ "development" ]
pull_request:
branches: [ "development" , "release" ]
branches: [ "development", "release" ]
workflow_dispatch:

jobs:
build:
Expand All @@ -16,30 +17,40 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
python-version: [ "3.10", "3.11", "3.12" ]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}

- name: Install poetry
run: |
python -m pip install --upgrade pip
python -m pip install poetry

- name: Install dependencies
run: |
poetry install
# - name: Lint with flake8
# run: |
# # stop the build if there are Python syntax errors or undefined names
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
poetry run poe test
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install poetry
run: |
python -m pip install --upgrade pip
python -m pip install poetry

- name: Install dependencies
run: |
poetry install --with dev

# - name: Lint with flake8
# run: |
# # stop the build if there are Python syntax errors or undefined names
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest (coverage)
run: |
poetry run pytest -q --cov=pythonQEPest --cov-report=term-missing --cov-fail-under=40

- name: Build dist
run: |
poetry build

- name: Install built wheel and smoke import
run: |
python -m pip install dist/*.whl
python -c "from pythonQEPest import QEPest, QEPestInput; QEPest().compute_params(QEPestInput(name='smoke', mol_weight=240.2127, log_p=3.2392, hbond_acceptors=5, hbond_donors=1, rotatable_bonds=4, aromatic_rings=1))"
25 changes: 25 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ repos:
pass_filenames: false
files: \.py$
exclude: ^tests/data/

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
Expand All @@ -17,3 +18,27 @@ repos:
files: \.py$
- id: check-yaml
files: \.ya?ml$
- id: check-merge-conflict
- id: debug-statements
- id: check-added-large-files

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 26.1.0
hooks:
- id: black
# It is recommended to specify the latest version of Python
# supported by your project here, or alternatively use
# pre-commit's default_language_version, see
# https://pre-commit.com/#top_level-default_language_version
language_version: python3.13

- repo: https://github.com/pycqa/flake8
rev: 7.3.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-comprehensions
args:
- --max-line-length=88
- --extend-ignore=E203,W503
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The rewritten version of Java QEPest. Made by PonyLianna (https://github.com/Pon
You can use a .exe version (which you can find at https://github.com/PonyLianna/pythonQEPest/releases)
or run it by yourself.

To be able to do it you'll need `Python >3.12 + pip3` (https://www.python.org/downloads/)
To be able to do it you'll need `Python >3.10 + pip3` (https://www.python.org/downloads/)

Further installation (I skip venv here):

Expand Down
132 changes: 130 additions & 2 deletions poetry.lock

Large diffs are not rendered by default.

29 changes: 17 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
[project]
name = "pythonQEPest"
version = "1.1.2"
version = "1.1.4"
description = "The rewritten version of Java QEPest"
readme = "README.md"
requires-python = ">=3.10,<3.13"
authors = [
{ name = "Lina", email = "knocker767@gmail.com" }
]
dependencies = [
"pydantic==2.12.5",
"python-dotenv>=1.2.1,<2.0.0"
]
authors = [{ name = "Lina", email = "knocker767@gmail.com" }]
dependencies = ["pydantic==2.12.5", "python-dotenv>=1.2.1,<2.0.0"]

[project.optional-dependencies]
gui = ["pyperclip>=1.11.0,<2.0.0"]

[project.scripts]
pythonqepest = "pythonQEPest.cli.cli:main"

[project.gui-scripts]
pythonqepest-gui = "pythonQEPest.gui.gui:main"

[tool.poetry]
packages = [
{ include = "pythonQEPest" }
]
packages = [{ include = "pythonQEPest" }]

[dependency-groups]
dev = [
"pytest (>=9.0.0)",
"pre-commit (>=4.3.0,<5.0.0)",
"pyinstaller (>=6.18.0,<7.0.0)",
"poethepoet[poetry_plugin] (>=0.39.0)"
"poethepoet[poetry_plugin] (>=0.39.0)",
"pytest-cov (>=7.0.0,<8.0.0)",
]

[build-system]
requires = ["poetry-core>=1.0.0", "setuptools>=40.8.0"]
build-backend = "poetry.core.masonry.api"

[tool.flake8]
max-line-length = 88
extend-ignore = ["E203", "W503"]
exclude = [".venv", ".git", "__pycache__", "build", "dist"]

[tool.poe.tasks]
test = "pytest"
build-simple = "pyinstaller --onefile pythonQEPest/main.py"
Expand Down
6 changes: 3 additions & 3 deletions pythonQEPest/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
LOG_LEVEL = "INFO"
LOG_FILE_LOCATION = "logs/app.log"
LOG_LEVEL="INFO"
LOG_FILE_LOCATION="logs/app.log"

APP_DEBUG_ENABLE = "false"
APP_DEBUG_ENABLE="false"
11 changes: 11 additions & 0 deletions pythonQEPest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pythonQEPest.core import QEPest
from pythonQEPest.dto import QEPestData
from pythonQEPest.dto import QEPestInput
from pythonQEPest.dto import QEPestOutput

__all__ = [
"QEPest",
"QEPestData",
"QEPestInput",
"QEPestOutput",
]
7 changes: 7 additions & 0 deletions pythonQEPest/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
def main():
from pythonQEPest.cli.cli import main as _main

return _main()


__all__ = ["main"]
94 changes: 85 additions & 9 deletions pythonQEPest/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
from pythonQEPest.core.qepest_meta import QEPestMeta
from pythonQEPest.helpers.get_num_of_cols import get_num_of_cols
from pythonQEPest.helpers.get_values_from_line import get_values_from_line
from __future__ import annotations

import argparse
import logging
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path
from typing import Sequence

from pythonQEPest.core import QEPestMeta
from pythonQEPest.dto import QEPestFile
from pythonQEPest.helpers import get_num_of_cols
from pythonQEPest.helpers.get_values_from_line import get_values_from_line

logger = logging.getLogger(__name__)


class CLI:
qepest: QEPestMeta | None = None

def __init__(self, qepest: QEPestMeta):
def __init__(self, qepest: QEPestMeta, qepest_file: QEPestFile):
self.qepest = qepest
self.qepest_file = qepest_file

def read_file_and_compute_params(self):
try:
with open(self.qepest.input_file, "r") as file:
with open(self.qepest_file.input_file, "r") as file:
lines = file.readlines()

with open(f"{self.qepest.input_file}.out", "w") as wr:
with open(self.qepest_file.output_file, "w") as wr:
for index, line in enumerate(lines):
if index == 0:
if get_num_of_cols(line) != self.qepest.col_number:
Expand All @@ -31,9 +39,11 @@ def read_file_and_compute_params(self):
if get_num_of_cols(line) == self.qepest.col_number:
d_values = get_values_from_line(line.split("\t"))
self.qepest.get_qex_values(d_values)
splitted_line = line.split('\t')[0]
splitted_line = line.split("\t")[0]
wr.write(
f"{splitted_line} {self.qepest.qex.qe_h} {self.qepest.qex.qe_i} {self.qepest.qex.qe_f}{chr(10)}"
f"{splitted_line} {self.qepest.qex.qe_h} "
+ f"{self.qepest.qex.qe_i} {self.qepest.qex.qe_f}"
+ f"{chr(10)}"
)
else:
er = f"Error: Line {index} does not have seven elements."
Expand All @@ -46,5 +56,71 @@ def read_file_and_compute_params(self):

except FileNotFoundError as e:
self.qepest.noError = False
logger.error("Error: can't find : %s", input)
logger.error("Error: can't find : %s", self.qepest_file.input_file)
logger.exception(e)


def _resolve_package_version() -> str:
try:
return version("pythonQEPest")
except PackageNotFoundError:
pass

try:
import tomllib # py3.11+

pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
return data["project"]["version"]
except Exception:
return "0+unknown"


def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="pythonqepest",
description="Compute QEPest scores from a tab-separated input file.",
)
parser.add_argument(
"-v",
"--version",
action="version",
version=f"%(prog)s {_resolve_package_version()}",
help="Show program's version number.",
)
parser.add_argument(
"-i",
"--input",
default="data.txt",
help="Path to input tab-separated file with "
+ "QEPest descriptors (default: data.txt).",
)

parser.add_argument(
"-o",
"--output",
default="data.txt.out",
help="Path to output tab-separated file with "
+ "QEPest descriptors (default: data.txt.out).",
)
return parser


def main(argv: Sequence[str] | None = None) -> int:
from dotenv import load_dotenv

from pythonQEPest.core.qepest import QEPest
from pythonQEPest.logger import init_logger

args = build_parser().parse_args(argv)

load_dotenv()
init_logger()

cli = CLI(
qepest=QEPest(),
qepest_file=QEPestFile(input_file=args.input, output_file=args.output),
)
cli.read_file_and_compute_params()

return 0 if cli.qepest and cli.qepest.noError else 1
2 changes: 1 addition & 1 deletion pythonQEPest/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .qepest_meta import QEPestMeta
from .qepest import QEPest
from .qepest_meta import QEPestMeta

__all__ = [
"QEPestMeta",
Expand Down
18 changes: 10 additions & 8 deletions pythonQEPest/core/qepest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

class QEPest(QEPestMeta):
def compute_params(self, data_input: QEPestInput) -> QEPestOutput:
self.get_qex_values(get_values_from_line(list(data_input.model_dump().values())))
self.get_qex_values(
get_values_from_line(list(data_input.model_dump().values()))
)
return QEPestOutput(data=self.qex, name=data_input.name)

def get_qex_values(self, d) -> None:
Expand Down Expand Up @@ -42,30 +44,30 @@ def log_compute_df(func, index, lst, data_lst) -> float:

def initialize_coefficients(self) -> None:
coefficients = {
'herb': [
"herb": [
(70.77, 283.0, 84.97, -1.185), # mwH
(93.81, 3.077, 1.434, 0.6164), # logpH
(117.6, 2.409, 1.567, 7.155), # hbaH
(233.4, 0.4535, -1.48, 4.47), # hbdH
(84.7, 4.758, -2.423, 5.437), # rbH
(301.8, 1.101, 0.8869, -22.81) # arRCH
(301.8, 1.101, 0.8869, -22.81), # arRCH
],
'insect': [
"insect": [
(76.38, 298.3, 83.64, 1.912), # mwI
(74.27, 4.555, -2.193, -2.987), # logpI
(139.4, 1.363, 1.283, 0.5341), # hbaI
(670.6, -1.163, 0.7856, 0.7951), # hbdI
(65.49, 6.219, -2.448, 5.318), # rbI
(287.5, 0.305, 1.554, -88.64) # arRCI
(287.5, 0.305, 1.554, -88.64), # arRCI
],
'fung': [
"fung": [
(51.03, 314.2, -56.31, 2.342), # mwF
(50.73, 3.674, -1.238, 2.067), # logpF
(73.79, 1.841, 1.326, 0.5158), # hbaF
(164.7, -0.9762, -2.027, 1.384), # hbdF
(40.91, 1.822, 2.582, 0.6235), # rbF
(134.4, 0.8383, 1.347, -31.17) # arRCF
]
(134.4, 0.8383, 1.347, -31.17), # arRCF
],
}

for category, data in coefficients.items():
Expand Down
Loading