Skip to content

Commit

Permalink
Merge pull request #8 from ECRL/dev
Browse files Browse the repository at this point in the history
Better subprocess handling
  • Loading branch information
tjkessler authored Jun 28, 2019
2 parents 93c25aa + e74c9a2 commit 99eabb5
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 11 deletions.
2 changes: 1 addition & 1 deletion padelpy/__init__.py
Original file line number Diff line number Diff line change
@@ -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'
13 changes: 8 additions & 5 deletions padelpy/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# padelpy/functions.py
# v.0.1.5
# v.0.1.6
# Developed in 2019 by Travis Kessler <[email protected]>
#
# Contains various functions commonly used with PaDEL-Descriptor
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down
32 changes: 28 additions & 4 deletions padelpy/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# padelpy/wrapper.py
# v.0.1.5
# v.0.1.6
# Developed in 2019 by Travis Kessler <[email protected]>
#
# Contains the `padeldescriptor` function, a wrapper for PaDEL-Descriptor
Expand All @@ -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(
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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')
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 99eabb5

Please sign in to comment.