From c23fc500fe32a97b0d5970cb92e3d5e8a607e9bd Mon Sep 17 00:00:00 2001 From: tjkessler Date: Fri, 28 Jun 2019 14:57:40 -0400 Subject: [PATCH 1/2] from_smiles/from_mdl timeouts now affect subprocess timeout, not padel's --- padelpy/functions.py | 11 +++++++---- padelpy/wrapper.py | 30 +++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/padelpy/functions.py b/padelpy/functions.py index 743122b..8cbf3df 100644 --- a/padelpy/functions.py +++ b/padelpy/functions.py @@ -14,13 +14,14 @@ from datetime import datetime from os import remove from re import compile, IGNORECASE +from time import sleep # PaDELPy imports from padelpy import padeldescriptor def from_smiles(smiles: str, output_csv: str=None, descriptors: bool=True, - fingerprints: bool=False, timeout: int=4) -> OrderedDict: + fingerprints: bool=False, timeout: int=12) -> OrderedDict: ''' from_smiles: converts SMILES string to QSPR descriptors/fingerprints Args: @@ -55,13 +56,14 @@ def from_smiles(smiles: str, output_csv: str=None, descriptors: bool=True, d_2d=descriptors, d_3d=descriptors, fingerprints=fingerprints, - maxruntime=1000*timeout + sp_timeout=timeout ) break except RuntimeError as exception: if attempt == 2: remove('{}.smi'.format(timestamp)) if not save_csv: + sleep(0.5) remove(output_csv) raise RuntimeError(exception) else: @@ -81,7 +83,7 @@ def from_smiles(smiles: str, output_csv: str=None, descriptors: bool=True, def from_mdl(mdl_file: str, output_csv: str=None, descriptors: bool=True, - fingerprints: bool=False, timeout: int=4) -> list: + fingerprints: bool=False, timeout: int=12) -> list: ''' from_mdl: converts MDL file into QSPR descriptors/fingerprints; multiple molecules may be represented in the MDL file @@ -121,12 +123,13 @@ def from_mdl(mdl_file: str, output_csv: str=None, descriptors: bool=True, d_2d=descriptors, d_3d=descriptors, fingerprints=fingerprints, - maxruntime=1000*timeout + sp_timeout=timeout ) break except RuntimeError as exception: if attempt == 2: if not save_csv: + sleep(0.5) remove(output_csv) raise RuntimeError(exception) else: diff --git a/padelpy/wrapper.py b/padelpy/wrapper.py index 606b517..d707af4 100644 --- a/padelpy/wrapper.py +++ b/padelpy/wrapper.py @@ -12,6 +12,7 @@ from os.path import abspath, dirname, join from shutil import which from subprocess import PIPE, Popen +from time import sleep # PaDEL-Descriptor is packaged with PaDELPy _PADEL_PATH = join( @@ -21,6 +22,29 @@ ) +def _popen_timeout(command: str, timeout: int) -> tuple: + ''' Calls PaDEL-Descriptor, with optional subprocess timeout + + Args: + command (str): command to execute via subprocess.Popen + timeout (int): if not None, times out after this many seconds + + Returns: + tuple: (stdout of process, stderr of process) + ''' + + p = Popen(command.split(), stdout=PIPE, stderr=PIPE) + if timeout is not None: + for t in range(timeout): + sleep(1) + if p.poll() is not None: + return p.communicate() + p.kill() + return (-1, b'PaDEL-Descriptor timed out during subprocess call') + else: + return p.communicate() + + def padeldescriptor(maxruntime: int=-1, waitingjobs: int=-1, threads: int=-1, d_2d: bool=False, d_3d: bool=False, config: str=None, convert3d: bool=False, descriptortypes: str=None, @@ -30,7 +54,8 @@ def padeldescriptor(maxruntime: int=-1, waitingjobs: int=-1, threads: int=-1, removesalt: bool=False, retain3d: bool=False, retainorder: bool=False, standardizenitro: bool=False, standardizetautomers: bool=False, tautomerlist: str=None, - usefilenameasmolname: bool=False) -> None: + usefilenameasmolname: bool=False, + sp_timeout: int=None) -> None: ''' padeldescriptor: complete wrapper for PaDEL-Descriptor descriptor/ fingerprint generation software @@ -117,8 +142,7 @@ def padeldescriptor(maxruntime: int=-1, waitingjobs: int=-1, threads: int=-1, if usefilenameasmolname is True: command += ' -usefilenameasmolname' - p = Popen(command.split(), stdout=PIPE, stderr=PIPE) - _, err = p.communicate() + _, err = _popen_timeout(command, sp_timeout) if err != b'': raise RuntimeError('PaDEL-Descriptor encountered an error: {}'.format( err.decode('utf-8') From e74c9a299b5e37f387b0263cd50aba2e51c3ac0d Mon Sep 17 00:00:00 2001 From: tjkessler Date: Fri, 28 Jun 2019 16:50:26 -0400 Subject: [PATCH 2/2] Version bump: 0.1.5 -> 0.1.6 --- padelpy/__init__.py | 2 +- padelpy/functions.py | 2 +- padelpy/wrapper.py | 2 +- setup.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/padelpy/__init__.py b/padelpy/__init__.py index 84c0e68..4b3a7e7 100644 --- a/padelpy/__init__.py +++ b/padelpy/__init__.py @@ -1,3 +1,3 @@ from padelpy.wrapper import padeldescriptor from padelpy.functions import from_mdl, from_smiles -__version__ = '0.1.5' +__version__ = '0.1.6' diff --git a/padelpy/functions.py b/padelpy/functions.py index 8cbf3df..e4dafd8 100644 --- a/padelpy/functions.py +++ b/padelpy/functions.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # padelpy/functions.py -# v.0.1.5 +# v.0.1.6 # Developed in 2019 by Travis Kessler # # Contains various functions commonly used with PaDEL-Descriptor diff --git a/padelpy/wrapper.py b/padelpy/wrapper.py index d707af4..4bb5515 100644 --- a/padelpy/wrapper.py +++ b/padelpy/wrapper.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # padelpy/wrapper.py -# v.0.1.5 +# v.0.1.6 # Developed in 2019 by Travis Kessler # # Contains the `padeldescriptor` function, a wrapper for PaDEL-Descriptor diff --git a/setup.py b/setup.py index 3546564..fc06b57 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='padelpy', - version='0.1.5', + version='0.1.6', description='A Python wrapper for PaDEL-Descriptor', url='https://github.com/ecrl/padelpy', author='Travis Kessler',