-
Notifications
You must be signed in to change notification settings - Fork 533
[ENH] Revising use of subprocess.Popen #2289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
b0828e0
89371e8
1913dca
309c6ea
7f0ef16
cadcdbe
07a62fb
ff63da8
73ff136
1676c84
3f0991c
4a7474a
19aca5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,11 +9,10 @@ | |
Requires Packages to be installed | ||
""" | ||
from __future__ import print_function, division, unicode_literals, absolute_import | ||
from future import standard_library | ||
standard_library.install_aliases() | ||
import gc | ||
|
||
from builtins import range, object, open, str, bytes | ||
|
||
from configparser import NoOptionError | ||
from copy import deepcopy | ||
import datetime | ||
from datetime import datetime as dt | ||
|
@@ -26,7 +25,6 @@ | |
import select | ||
import subprocess as sp | ||
import sys | ||
import time | ||
from textwrap import wrap | ||
from warnings import warn | ||
import simplejson as json | ||
|
@@ -43,6 +41,8 @@ | |
traits, Undefined, TraitDictObject, TraitListObject, TraitError, isdefined, | ||
File, Directory, DictStrStr, has_metadata, ImageFile) | ||
from ..external.due import due | ||
from future import standard_library | ||
standard_library.install_aliases() | ||
|
||
nipype_version = Version(__version__) | ||
iflogger = logging.getLogger('interface') | ||
|
@@ -58,6 +58,7 @@ | |
class Str(traits.Unicode): | ||
"""Replacement for the default traits.Str based in bytes""" | ||
|
||
|
||
traits.Str = Str | ||
|
||
|
||
|
@@ -634,16 +635,16 @@ def __deepcopy__(self, memo): | |
return memo[id_self] | ||
dup_dict = deepcopy(self.get(), memo) | ||
# access all keys | ||
for key in self.copyable_trait_names(): | ||
if key in self.__dict__.keys(): | ||
_ = getattr(self, key) | ||
# for key in self.copyable_trait_names(): | ||
# if key in self.__dict__.keys(): | ||
# _ = getattr(self, key) | ||
# clone once | ||
dup = self.clone_traits(memo=memo) | ||
for key in self.copyable_trait_names(): | ||
try: | ||
_ = getattr(dup, key) | ||
except: | ||
pass | ||
# for key in self.copyable_trait_names(): | ||
# try: | ||
# _ = getattr(dup, key) | ||
# except: | ||
# pass | ||
# clone twice | ||
dup = self.clone_traits(memo=memo) | ||
dup.trait_set(**dup_dict) | ||
|
@@ -1260,6 +1261,7 @@ class SimpleInterface(BaseInterface): | |
>>> os.chdir(old.strpath) | ||
|
||
""" | ||
|
||
def __init__(self, from_file=None, resource_monitor=None, **inputs): | ||
super(SimpleInterface, self).__init__( | ||
from_file=from_file, resource_monitor=resource_monitor, **inputs) | ||
|
@@ -1387,8 +1389,7 @@ def run_command(runtime, output=None, timeout=0.01): | |
shell=True, | ||
cwd=runtime.cwd, | ||
env=env, | ||
close_fds=True, | ||
) | ||
close_fds=True) | ||
result = { | ||
'stdout': [], | ||
'stderr': [], | ||
|
@@ -1427,12 +1428,7 @@ def _process(drain=0): | |
temp.sort() | ||
result['merged'] = [r[1] for r in temp] | ||
|
||
if output == 'allatonce': | ||
stdout, stderr = proc.communicate() | ||
result['stdout'] = read_stream(stdout, logger=iflogger) | ||
result['stderr'] = read_stream(stderr, logger=iflogger) | ||
|
||
elif output.startswith('file'): | ||
if output.startswith('file'): | ||
proc.wait() | ||
if outfile is not None: | ||
stdout.flush() | ||
|
@@ -1452,12 +1448,30 @@ def _process(drain=0): | |
result['merged'] = result['stdout'] | ||
result['stdout'] = [] | ||
else: | ||
proc.communicate() # Discard stdout and stderr | ||
stdoutstr, stderrstr = proc.communicate() | ||
if output == 'allatonce': # Discard stdout and stderr otherwise | ||
result['stdout'] = read_stream(stdoutstr, logger=iflogger) | ||
result['stderr'] = read_stream(stderrstr, logger=iflogger) | ||
del stdoutstr | ||
del stderrstr | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, meant for these to replace the I guess, though, that those only exist under certain sub-branches. Not sure how you want to go about this. |
||
|
||
runtime.returncode = proc.returncode | ||
try: | ||
proc.terminate() # Ensure we are done | ||
except OSError as error: | ||
# Python 2 raises when the process is already gone | ||
if error.errno != errno.ESRCH: | ||
raise | ||
|
||
# Dereference & force GC for a cleanup | ||
del proc | ||
del stdout | ||
del stderr | ||
gc.collect() | ||
|
||
runtime.stderr = '\n'.join(result['stderr']) | ||
runtime.stdout = '\n'.join(result['stdout']) | ||
runtime.merged = '\n'.join(result['merged']) | ||
runtime.returncode = proc.returncode | ||
return runtime | ||
|
||
|
||
|
@@ -1467,21 +1481,26 @@ def get_dependencies(name, environ): | |
Uses otool on darwin, ldd on linux. Currently doesn't support windows. | ||
|
||
""" | ||
cmd = None | ||
if sys.platform == 'darwin': | ||
proc = sp.Popen('otool -L `which %s`' % name, | ||
stdout=sp.PIPE, | ||
stderr=sp.PIPE, | ||
shell=True, | ||
env=environ) | ||
cmd = 'otool -L `which {}`'.format | ||
elif 'linux' in sys.platform: | ||
proc = sp.Popen('ldd `which %s`' % name, | ||
stdout=sp.PIPE, | ||
stderr=sp.PIPE, | ||
shell=True, | ||
env=environ) | ||
else: | ||
cmd = 'ldd -L `which {}`'.format | ||
|
||
if cmd is None: | ||
return 'Platform %s not supported' % sys.platform | ||
o, e = proc.communicate() | ||
|
||
try: | ||
proc = sp.Popen( | ||
cmd(name), stdout=sp.PIPE, stderr=sp.PIPE, shell=True, | ||
env=environ, close_fds=True) | ||
o, _ = proc.communicate() | ||
proc.terminate() | ||
gc.collect() | ||
except: | ||
iflogger.warning( | ||
'Could not get linked libraries for "%s".', name) | ||
return 'Failed collecting dependencies' | ||
return o.rstrip() | ||
|
||
|
||
|
@@ -1572,6 +1591,9 @@ def __init__(self, command=None, terminal_output=None, **inputs): | |
# Set command. Input argument takes precedence | ||
self._cmd = command or getattr(self, '_cmd', None) | ||
|
||
# Store dependencies in runtime object | ||
self._ldd = str2bool(config.get('execution', 'get_linked_libs', 'true')) | ||
|
||
if self._cmd is None: | ||
raise Exception("Missing command") | ||
|
||
|
@@ -1620,6 +1642,8 @@ def _get_environ(self): | |
return getattr(self.inputs, 'environ', {}) | ||
|
||
def version_from_command(self, flag='-v'): | ||
iflogger.warning('version_from_command member of CommandLine was ' | ||
'Deprecated in nipype-1.0.0 and deleted in 2.0.0') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should perhaps keep this in the 1.0 branch so deleted in 1.1 |
||
cmdname = self.cmd.split()[0] | ||
env = dict(os.environ) | ||
if _exists_in_path(cmdname, env): | ||
|
@@ -1664,7 +1688,8 @@ def _run_interface(self, runtime, correct_return_codes=(0,)): | |
(self.cmd.split()[0], runtime.hostname)) | ||
|
||
runtime.command_path = cmd_path | ||
runtime.dependencies = get_dependencies(executable_name, runtime.environ) | ||
runtime.dependencies = (get_dependencies(executable_name, runtime.environ) | ||
if self._ldd else '<skipped>') | ||
runtime = run_command(runtime, output=self.terminal_output) | ||
if runtime.returncode is None or \ | ||
runtime.returncode not in correct_return_codes: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dynamic traits won't work without these. i'm not sure we have a test for it but this is the relevant issue and PR.
enthought/traits#373