Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • cubicweb/cubes/subprocess
1 result
Show changes
Commits on Source (2)
Showing
with 352 additions and 284 deletions
# pylint: disable=W0622
"""cubicweb-subprocess application packaging information"""
modname = 'subprocess'
distname = 'cubicweb-subprocess'
modname = "subprocess"
distname = "cubicweb-subprocess"
numversion = (1, 3, 0)
......@@ -6,4 +6,4 @@
numversion = (1, 3, 0)
version = '.'.join(str(num) for num in numversion)
version = ".".join(str(num) for num in numversion)
......@@ -9,7 +9,7 @@
license = 'LGPL'
author = 'LOGILAB S.A. (Paris, FRANCE)'
author_email = 'contact@logilab.fr'
description = 'This cube helps to manage and monitor subprocesses.'
web = 'https://forge.extranet.logilab.fr/cubicweb/cubes/%s' % distname
license = "LGPL"
author = "LOGILAB S.A. (Paris, FRANCE)"
author_email = "contact@logilab.fr"
description = "This cube helps to manage and monitor subprocesses."
web = "https://forge.extranet.logilab.fr/cubicweb/cubes/%s" % distname
......@@ -15,6 +15,5 @@
__depends__ = {'cubicweb': ">= 3.38.0, < 3.39.0",
'cubicweb-file': '>= 1.16.0'}
__depends__ = {"cubicweb": ">= 3.38.0, < 3.39.0", "cubicweb-file": ">= 1.16.0"}
__recommends__ = {}
classifiers = [
......@@ -18,10 +17,10 @@
__recommends__ = {}
classifiers = [
'Environment :: Web Environment',
'Framework :: CubicWeb',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: JavaScript',
]
"Environment :: Web Environment",
"Framework :: CubicWeb",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: JavaScript",
]
......@@ -30,7 +30,7 @@
def kill(pid):
if os.name == 'posix':
if os.name == "posix":
# no windows support for this before python 2.7 ...
os.kill(pid, signal.SIGTERM)
else:
......@@ -34,8 +34,8 @@
# no windows support for this before python 2.7 ...
os.kill(pid, signal.SIGTERM)
else:
proc = Popen(['taskkill', '/f', '/t', '/pid', '%s' % pid])
proc = Popen(["taskkill", "/f", "/t", "/pid", "%s" % pid])
proc.wait()
class Subprocess(AnyEntity):
......@@ -38,9 +38,9 @@
proc.wait()
class Subprocess(AnyEntity):
__regid__ = 'Subprocess'
envencoding = 'utf-8'
__regid__ = "Subprocess"
envencoding = "utf-8"
def dc_title(self):
try:
......@@ -44,9 +44,9 @@
def dc_title(self):
try:
return u' '.join(json.loads(self.cmdline))
return " ".join(json.loads(self.cmdline))
except (ValueError, TypeError):
return self.cmdline
@property
def finished(self):
......@@ -48,12 +48,10 @@
except (ValueError, TypeError):
return self.cmdline
@property
def finished(self):
'''Return True is the process has been run and finished.'''
return not list(
self.cw_adapt_to('IWorkflowable').possible_transitions()
)
"""Return True is the process has been run and finished."""
return not list(self.cw_adapt_to("IWorkflowable").possible_transitions())
def _create_output_file(self, name):
return self._cw.create_entity(
......@@ -57,5 +55,5 @@
def _create_output_file(self, name):
return self._cw.create_entity(
'File',
"File",
data=Binary(),
......@@ -61,5 +59,5 @@
data=Binary(),
data_format=u'text/plain',
data_format="text/plain",
data_name=name,
output_of=self,
)
......@@ -68,8 +66,10 @@
env = os.environ.copy()
env.update(json.loads(self.env) if self.env else {})
return dict(
(k.encode(self.envencoding) if isinstance(k, str) else k,
v.encode(self.envencoding) if isinstance(v, str) else v)
(
k.encode(self.envencoding) if isinstance(k, str) else k,
v.encode(self.envencoding) if isinstance(v, str) else v,
)
for k, v in env.items()
)
......@@ -83,9 +83,11 @@
return code of the subprocess.
"""
cmd_args = json.loads(self.cmdline)
proc = Popen(cmd_args, cwd=self.cwd,
env=self._environ(),
stdout=PIPE, stderr=PIPE)
outputs = {'stdout': self._create_output_file(u'stdout'),
'stderr': self._create_output_file(u'stderr')}
proc = Popen(
cmd_args, cwd=self.cwd, env=self._environ(), stdout=PIPE, stderr=PIPE
)
outputs = {
"stdout": self._create_output_file("stdout"),
"stderr": self._create_output_file("stderr"),
}
self.cw_set(pid=proc.pid)
......@@ -91,6 +93,9 @@
self.cw_set(pid=proc.pid)
self.info('started subprocess with pid %d (cmdline: %s)',
proc.pid, list2cmdline(cmd_args))
self.info(
"started subprocess with pid %d (cmdline: %s)",
proc.pid,
list2cmdline(cmd_args),
)
self._cw.commit()
for outname, content in communicate(proc):
......@@ -94,8 +99,12 @@
self._cw.commit()
for outname, content in communicate(proc):
self.debug('Appending %s bytes to %s (stream %s)',
len(content), outputs[outname].eid, outname)
self.debug(
"Appending %s bytes to %s (stream %s)",
len(content),
outputs[outname].eid,
outname,
)
outputs[outname].data.write(content)
outputs[outname].cw_set(data=outputs[outname].data)
outputs[outname].data.seek(0, 2) # go to the end of stream
......@@ -105,8 +114,8 @@
def _finalize(self, return_code, trname):
"""Save subprocess metadata into the database"""
adapted = self.cw_adapt_to('IWorkflowable')
if adapted.state == 'in progress': # can be in other state if it
adapted = self.cw_adapt_to("IWorkflowable")
if adapted.state == "in progress": # can be in other state if it
adapted.fire_transition(trname) # was killed.
self.cw_set(return_code=return_code)
self._cw.commit()
......@@ -114,8 +123,8 @@
def _start(self):
"""Process the subprocess"""
return_code = self._launch()
trname = 'complete' if return_code == 0 else 'abort'
trname = "complete" if return_code == 0 else "abort"
self._finalize(return_code, trname)
@property
def stderr(self):
......@@ -118,8 +127,8 @@
self._finalize(return_code, trname)
@property
def stderr(self):
return self.get_output(u'stderr')
return self.get_output("stderr")
@property
def stdout(self):
......@@ -123,6 +132,6 @@
@property
def stdout(self):
return self.get_output(u'stdout')
return self.get_output("stdout")
def get_output(self, name):
......@@ -127,8 +136,8 @@
def get_output(self, name):
data = self._cw.find('File', output_of=self, data_name=name).one().data
data = self._cw.find("File", output_of=self, data_name=name).one().data
if data is not None:
return data.getvalue()
def start(self):
"""start the subprocess."""
......@@ -130,10 +139,10 @@
if data is not None:
return data.getvalue()
def start(self):
"""start the subprocess."""
assert self.cw_adapt_to('IWorkflowable').state == 'in progress'
assert self.cw_adapt_to("IWorkflowable").state == "in progress"
def _launch():
with self._cw.repo.internal_cnx() as cnx: # dedicated cnx in thread
cnx.entity_from_eid(self.eid)._start()
......@@ -136,10 +145,11 @@
def _launch():
with self._cw.repo.internal_cnx() as cnx: # dedicated cnx in thread
cnx.entity_from_eid(self.eid)._start()
self.info('launching subprocess #%d', self.eid)
self.info("launching subprocess #%d", self.eid)
self._cw.repo.threaded_task(_launch)
def synchronousstart(self):
"""start the subprocess."""
cnx = self._cw
......@@ -141,9 +151,9 @@
self._cw.repo.threaded_task(_launch)
def synchronousstart(self):
"""start the subprocess."""
cnx = self._cw
wfadapter = self.cw_adapt_to('IWorkflowable')
assert wfadapter.state == 'initialized'
with cnx.allow_all_hooks_but('subprocess.workflow'):
wfadapter = self.cw_adapt_to("IWorkflowable")
assert wfadapter.state == "initialized"
with cnx.allow_all_hooks_but("subprocess.workflow"):
# this ^^ must be inhibited if we want control
......@@ -149,8 +159,8 @@
# this ^^ must be inhibited if we want control
wfadapter.fire_transition('start', u'started synchronous subprocess')
wfadapter.fire_transition("start", "started synchronous subprocess")
cnx.commit()
self.cw_clear_all_caches()
self._start()
return self.return_code
def _kill(self):
......@@ -151,10 +161,9 @@
cnx.commit()
self.cw_clear_all_caches()
self._start()
return self.return_code
def _kill(self):
"""kill the subprocess if it's running.
"""
"""kill the subprocess if it's running."""
pid = self.pid
if pid is None:
......@@ -159,7 +168,7 @@
pid = self.pid
if pid is None:
raise ProcessNotRunning('The process is not started')
raise ProcessNotRunning("The process is not started")
kill(pid)
def kill(self):
"""kill the subprocess if it is running."""
......@@ -162,8 +171,9 @@
kill(pid)
def kill(self):
"""kill the subprocess if it is running."""
if not self.cw_adapt_to('IWorkflowable').state == 'in progress':
raise ValidationError(self.eid, {
None: _('You must use the workflow to start the subprocess')})
if not self.cw_adapt_to("IWorkflowable").state == "in progress":
raise ValidationError(
self.eid, {None: _("You must use the workflow to start the subprocess")}
)
self._kill()
......@@ -18,7 +18,7 @@
"""cubicweb-subprocess entity's classes"""
from cubicweb import ExecutionError
__all__ = ('ProcessNotRunning',)
__all__ = ("ProcessNotRunning",)
class ProcessNotRunning(ExecutionError):
......@@ -22,5 +22,5 @@
class ProcessNotRunning(ExecutionError):
'''Exception raised when a process with a certain PID doesn't or no
longer exists.'''
"""Exception raised when a process with a certain PID doesn't or no
longer exists."""
......@@ -22,13 +22,13 @@
class StartHook(hook.Hook):
__regid__ = 'subprocess.start'
__select__ = hook.Hook.__select__ & on_fire_transition('Subprocess', 'start')
events = ('after_add_entity',)
category = 'subprocess.workflow'
__regid__ = "subprocess.start"
__select__ = hook.Hook.__select__ & on_fire_transition("Subprocess", "start")
events = ("after_add_entity",)
category = "subprocess.workflow"
def __call__(self):
StartOp.get_instance(self._cw).add_data(self.entity.for_entity)
class StartOp(hook.DataOperationMixIn, hook.Operation):
......@@ -29,13 +29,12 @@
def __call__(self):
StartOp.get_instance(self._cw).add_data(self.entity.for_entity)
class StartOp(hook.DataOperationMixIn, hook.Operation):
def postcommit_event(self):
for sub in self.get_data():
sub.start()
class KillHook(hook.Hook):
......@@ -36,16 +35,16 @@
def postcommit_event(self):
for sub in self.get_data():
sub.start()
class KillHook(hook.Hook):
__regid__ = 'subprocess.kill'
__select__ = hook.Hook.__select__ & on_fire_transition('Subprocess', 'kill')
events = ('after_add_entity',)
category = 'subprocess.workflow'
__regid__ = "subprocess.kill"
__select__ = hook.Hook.__select__ & on_fire_transition("Subprocess", "kill")
events = ("after_add_entity",)
category = "subprocess.workflow"
def __call__(self):
KillOp.get_instance(self._cw).add_data(self.entity.for_entity)
class KillOp(hook.DataOperationMixIn, hook.Operation):
......@@ -46,10 +45,9 @@
def __call__(self):
KillOp.get_instance(self._cw).add_data(self.entity.for_entity)
class KillOp(hook.DataOperationMixIn, hook.Operation):
def postcommit_event(self):
for sub in self.get_data():
sub.kill()
sync_schema_props_perms('output_of')
sync_schema_props_perms("output_of")
......@@ -24,7 +24,13 @@
class Subprocess(WorkflowableEntityType):
cmdline = String(description=_('subprocess command line as a json list'), required=True)
cwd = String(description=_('subprocess working directory [defaults to a temporary directory]'))
cmdline = String(
description=_("subprocess command line as a json list"), required=True
)
cwd = String(
description=_(
"subprocess working directory [defaults to a temporary directory]"
)
)
env = String(
description=_(
......@@ -29,6 +35,6 @@
env = String(
description=_(
'subprocess environment variables as a json dict '
'[defaults to application environment]'
"subprocess environment variables as a json dict "
"[defaults to application environment]"
)
)
......@@ -33,9 +39,11 @@
)
)
pid = Int(description=_('subprocess system identifier'))
advance_ratio = Float(description=_('Between 0 and 1'),
constraints=[IntervalBoundConstraint(minvalue=0, maxvalue=1)])
return_code = Int(description=_('subprocess return code'))
pid = Int(description=_("subprocess system identifier"))
advance_ratio = Float(
description=_("Between 0 and 1"),
constraints=[IntervalBoundConstraint(minvalue=0, maxvalue=1)],
)
return_code = Int(description=_("subprocess return code"))
class output_of(RelationDefinition):
......@@ -39,7 +47,7 @@
class output_of(RelationDefinition):
subject = 'File'
object = 'Subprocess'
cardinality = '?*'
subject = "File"
object = "Subprocess"
cardinality = "?*"
inlined = True
......@@ -45,2 +53,2 @@
inlined = True
composite = 'object'
composite = "object"
......@@ -31,7 +31,7 @@
__docformat__ = "restructuredtext en"
try:
if os.environ.get('NO_SETUPTOOLS'):
if os.environ.get("NO_SETUPTOOLS"):
raise ImportError() # do as there is no setuptools
from setuptools import setup
from setuptools.command import install_lib
......@@ -35,7 +35,8 @@
raise ImportError() # do as there is no setuptools
from setuptools import setup
from setuptools.command import install_lib
USE_SETUPTOOLS = True
except ImportError:
from distutils.core import setup
from distutils.command import install_lib
......@@ -38,7 +39,8 @@
USE_SETUPTOOLS = True
except ImportError:
from distutils.core import setup
from distutils.command import install_lib
USE_SETUPTOOLS = False
......@@ -52,12 +54,12 @@
# get required metadatas
modname = pkginfo['modname']
version = pkginfo['version']
license = pkginfo['license']
description = pkginfo['description']
web = pkginfo['web']
author = pkginfo['author']
author_email = pkginfo['author_email']
classifiers = pkginfo['classifiers']
modname = pkginfo["modname"]
version = pkginfo["version"]
license = pkginfo["license"]
description = pkginfo["description"]
web = pkginfo["web"]
author = pkginfo["author"]
author_email = pkginfo["author_email"]
classifiers = pkginfo["classifiers"]
......@@ -63,5 +65,5 @@
with open(join(base_dir, 'README')) as f:
with open(join(base_dir, "README")) as f:
long_description = f.read()
# get optional metadatas
......@@ -65,14 +67,14 @@
long_description = f.read()
# get optional metadatas
distname = pkginfo.get('distname', modname)
scripts = pkginfo.get('scripts', ())
include_dirs = pkginfo.get('include_dirs', ())
data_files = pkginfo.get('data_files', None)
ext_modules = pkginfo.get('ext_modules', None)
dependency_links = pkginfo.get('dependency_links', ())
distname = pkginfo.get("distname", modname)
scripts = pkginfo.get("scripts", ())
include_dirs = pkginfo.get("include_dirs", ())
data_files = pkginfo.get("data_files", None)
ext_modules = pkginfo.get("ext_modules", None)
dependency_links = pkginfo.get("dependency_links", ())
if USE_SETUPTOOLS:
requires = {}
for entry in ("__depends__",): # "__recommends__"):
requires.update(pkginfo.get(entry, {}))
......@@ -74,10 +76,11 @@
if USE_SETUPTOOLS:
requires = {}
for entry in ("__depends__",): # "__recommends__"):
requires.update(pkginfo.get(entry, {}))
install_requires = [("%s %s" % (d, v and v or "")).strip()
for d, v in requires.items()]
install_requires = [
("%s %s" % (d, v and v or "")).strip() for d, v in requires.items()
]
else:
install_requires = []
......@@ -81,8 +84,8 @@
else:
install_requires = []
BASE_BLACKLIST = ('CVS', '.svn', '.hg', '.git', 'debian', 'dist', 'build')
IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~')
BASE_BLACKLIST = ("CVS", ".svn", ".hg", ".git", "debian", "dist", "build")
IGNORED_EXTENSIONS = (".pyc", ".pyo", ".elc", "~")
def ensure_scripts(linux_scripts):
......@@ -91,10 +94,11 @@
(taken from 4Suite)
"""
from distutils import util
if util.get_platform()[:3] == 'win':
scripts_ = [script + '.bat' for script in linux_scripts]
if util.get_platform()[:3] == "win":
scripts_ = [script + ".bat" for script in linux_scripts]
else:
scripts_ = linux_scripts
return scripts_
......@@ -96,12 +100,15 @@
else:
scripts_ = linux_scripts
return scripts_
def export(from_dir, to_dir,
blacklist=BASE_BLACKLIST,
ignore_ext=IGNORED_EXTENSIONS,
verbose=True):
def export(
from_dir,
to_dir,
blacklist=BASE_BLACKLIST,
ignore_ext=IGNORED_EXTENSIONS,
verbose=True,
):
"""make a mirror of from_dir in to_dir, omitting directories and files
listed in the black list
"""
......@@ -105,6 +112,7 @@
"""make a mirror of from_dir in to_dir, omitting directories and files
listed in the black list
"""
def make_mirror(arg, directory, fnames):
"""walk handler"""
for norecurs in blacklist:
......@@ -116,6 +124,6 @@
# don't include binary files
if filename[-4:] in ignore_ext:
continue
if filename[-1] == '~':
if filename[-1] == "~":
continue
src = join(directory, filename)
......@@ -120,4 +128,4 @@
continue
src = join(directory, filename)
dest = to_dir + src[len(from_dir):]
dest = to_dir + src[len(from_dir) :]
if verbose:
......@@ -123,5 +131,5 @@
if verbose:
sys.stderr.write('%s -> %s\n' % (src, dest))
sys.stderr.write("%s -> %s\n" % (src, dest))
if os.path.isdir(src):
if not exists(dest):
os.mkdir(dest)
......@@ -129,8 +137,9 @@
if exists(dest):
os.remove(dest)
shutil.copy2(src, dest)
try:
os.mkdir(to_dir)
except OSError as ex:
# file exists ?
import errno
......@@ -132,8 +141,9 @@
try:
os.mkdir(to_dir)
except OSError as ex:
# file exists ?
import errno
if ex.errno != errno.EEXIST:
raise
os.walk(from_dir, make_mirror, None)
......@@ -143,6 +153,7 @@
"""extend install_lib command to handle package __init__.py and
include_dirs variable if necessary
"""
def run(self):
"""overridden from install_lib class"""
install_lib.install_lib.run(self)
......@@ -160,5 +171,6 @@
# overwrite InstallData to use sys.prefix instead of the egg directory
class MyInstallData(old_install_data):
"""A class that manages data files installation"""
def run(self):
_old_install_dir = self.install_dir
......@@ -163,6 +175,6 @@
def run(self):
_old_install_dir = self.install_dir
if self.install_dir.endswith('egg'):
if self.install_dir.endswith("egg"):
self.install_dir = sys.prefix
old_install_data.run(self)
self.install_dir = _old_install_dir
......@@ -166,6 +178,7 @@
self.install_dir = sys.prefix
old_install_data.run(self)
self.install_dir = _old_install_dir
try:
# only if easy_install available
import setuptools.command.easy_install # noqa
......@@ -169,5 +182,6 @@
try:
# only if easy_install available
import setuptools.command.easy_install # noqa
# monkey patch: Crack SandboxViolation verification
from setuptools.sandbox import DirectorySandbox as DS
......@@ -172,5 +186,6 @@
# monkey patch: Crack SandboxViolation verification
from setuptools.sandbox import DirectorySandbox as DS
old_ok = DS._ok
def _ok(self, path):
......@@ -181,6 +196,7 @@
if realpath.startswith(allowed_path):
out = True
return out
DS._ok = _ok
except ImportError:
pass
......@@ -189,6 +205,6 @@
def install(**kwargs):
"""setup entry point"""
if USE_SETUPTOOLS:
if '--force-manifest' in sys.argv:
sys.argv.remove('--force-manifest')
if "--force-manifest" in sys.argv:
sys.argv.remove("--force-manifest")
# install-layout option was introduced in 2.5.3-1~exp1
......@@ -194,5 +210,5 @@
# install-layout option was introduced in 2.5.3-1~exp1
elif sys.version_info < (2, 5, 4) and '--install-layout=deb' in sys.argv:
sys.argv.remove('--install-layout=deb')
cmdclass = {'install_lib': MyInstallLib}
elif sys.version_info < (2, 5, 4) and "--install-layout=deb" in sys.argv:
sys.argv.remove("--install-layout=deb")
cmdclass = {"install_lib": MyInstallLib}
if USE_SETUPTOOLS:
......@@ -198,6 +214,6 @@
if USE_SETUPTOOLS:
kwargs['install_requires'] = install_requires
kwargs['dependency_links'] = dependency_links
kwargs['zip_safe'] = False
cmdclass['install_data'] = MyInstallData
kwargs["install_requires"] = install_requires
kwargs["dependency_links"] = dependency_links
kwargs["zip_safe"] = False
cmdclass["install_data"] = MyInstallData
......@@ -203,18 +219,19 @@
return setup(name=distname,
version=version,
license=license,
description=description,
long_description=long_description,
author=author,
author_email=author_email,
url=web,
scripts=ensure_scripts(scripts),
data_files=data_files,
ext_modules=ext_modules,
cmdclass=cmdclass,
classifiers=classifiers,
**kwargs
)
return setup(
name=distname,
version=version,
license=license,
description=description,
long_description=long_description,
author=author,
author_email=author_email,
url=web,
scripts=ensure_scripts(scripts),
data_files=data_files,
ext_modules=ext_modules,
cmdclass=cmdclass,
classifiers=classifiers,
**kwargs,
)
......@@ -219,4 +236,4 @@
if __name__ == '__main__':
if __name__ == "__main__":
install()
......@@ -16,5 +16,5 @@
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
STYLESHEETS.append(data('cubes.subprocess.css'))
JAVASCRIPTS.append(data('cubes.subprocess.js'))
STYLESHEETS.append(data("cubes.subprocess.css"))
JAVASCRIPTS.append(data("cubes.subprocess.js"))
......@@ -42,7 +42,7 @@
def _pipe_reader(name, pipe):
try:
for content in iter(lambda: pipe.readline(chunk_size), b''):
for content in iter(lambda: pipe.readline(chunk_size), b""):
queue.put((name, content))
finally:
queue.put((name, None))
......@@ -46,8 +46,9 @@
queue.put((name, content))
finally:
queue.put((name, None))
thread_stdout = Thread(target=_pipe_reader, args=('stdout', process.stdout))
thread_stderr = Thread(target=_pipe_reader, args=('stderr', process.stderr))
thread_stdout = Thread(target=_pipe_reader, args=("stdout", process.stdout))
thread_stderr = Thread(target=_pipe_reader, args=("stderr", process.stderr))
thread_stdout.start()
thread_stderr.start()
nb_threads = 2
......
......@@ -21,6 +21,6 @@
class SubprocessOutOfContextView(OutOfContextView):
__select__ = OutOfContextView.__select__ & is_instance('Subprocess')
__select__ = OutOfContextView.__select__ & is_instance("Subprocess")
def _progress_html(self, entity):
......@@ -25,7 +25,7 @@
def _progress_html(self, entity):
return tags.tag('progress')(
u'%.0f %%' % (100 * (entity.advance_ratio or 0)),
value=entity.advance_ratio)
return tags.tag("progress")(
"%.0f %%" % (100 * (entity.advance_ratio or 0)), value=entity.advance_ratio
)
def _link_html(self, entity):
......@@ -30,5 +30,5 @@
def _link_html(self, entity):
return self._cw.view('oneline', rset=entity.as_rset(), w=None)
return self._cw.view("oneline", rset=entity.as_rset(), w=None)
def _wrapper_html(self, entity, progress_html, link_html):
......@@ -33,5 +33,5 @@
def _wrapper_html(self, entity, progress_html, link_html):
div_classes = ['cw-subprocess-progress']
adapted = entity.cw_adapt_to('IWorkflowable')
div_classes = ["cw-subprocess-progress"]
adapted = entity.cw_adapt_to("IWorkflowable")
state = adapted.state
......@@ -37,3 +37,3 @@
state = adapted.state
div_classes.append(state.replace(' ', '-'))
div_classes.append(state.replace(" ", "-"))
if entity.finished:
......@@ -39,10 +39,13 @@
if entity.finished:
div_classes.append('ended')
return tags.div(progress_html + link_html, Class=' '.join(div_classes),
title=state,
id=u'js-cw-subprocess-%s' % entity.eid)
div_classes.append("ended")
return tags.div(
progress_html + link_html,
Class=" ".join(div_classes),
title=state,
id="js-cw-subprocess-%s" % entity.eid,
)
def cell_call(self, row, col):
entity = self.cw_rset.get_entity(row, col)
if not entity.finished:
self._cw.add_onload('cw.subprocess.autoRefreshImporter("%s");' % entity.eid)
......@@ -44,8 +47,10 @@
def cell_call(self, row, col):
entity = self.cw_rset.get_entity(row, col)
if not entity.finished:
self._cw.add_onload('cw.subprocess.autoRefreshImporter("%s");' % entity.eid)
self.w(self._wrapper_html(entity,
self._progress_html(entity),
self._link_html(entity)))
self.w(
self._wrapper_html(
entity, self._progress_html(entity), self._link_html(entity)
)
)
......@@ -38,6 +38,6 @@
"""return field's *typed* value."""
val = super(CmdlineInput, self).typed_value(form, field)
try:
val = u' '.join(json.loads(val))
val = " ".join(json.loads(val))
except (ValueError, TypeError):
pass
......@@ -42,3 +42,3 @@
except (ValueError, TypeError):
pass
return str(val or u'')
return str(val or "")
......@@ -24,8 +24,8 @@
_afs = uicfg.autoform_section
_affk = uicfg.autoform_field_kwargs
_afs.tag_attribute(('Subprocess', 'pid'), 'main', 'hidden')
_afs.tag_attribute(('Subprocess', 'advance_ratio'), 'main', 'hidden')
_afs.tag_attribute(('Subprocess', 'return_code'), 'main', 'hidden')
_afs.tag_attribute(("Subprocess", "pid"), "main", "hidden")
_afs.tag_attribute(("Subprocess", "advance_ratio"), "main", "hidden")
_afs.tag_attribute(("Subprocess", "return_code"), "main", "hidden")
......@@ -30,3 +30,3 @@
_affk.tag_attribute(('Subprocess', 'cmdline'), {'widget': CmdlineInput})
_affk.tag_attribute(("Subprocess", "cmdline"), {"widget": CmdlineInput})
......@@ -18,10 +18,10 @@
def define_subprocess_workflow(add_workflow):
wf = add_workflow(u'Subprocess workflow', 'Subprocess')
initialized = wf.add_state(_('initialized'), initial=True)
in_progress = wf.add_state(_('in progress'))
succeeded = wf.add_state(_('succeeded'))
failed = wf.add_state(_('failed'))
killed = wf.add_state(_('killed'))
wf = add_workflow("Subprocess workflow", "Subprocess")
initialized = wf.add_state(_("initialized"), initial=True)
in_progress = wf.add_state(_("in progress"))
succeeded = wf.add_state(_("succeeded"))
failed = wf.add_state(_("failed"))
killed = wf.add_state(_("killed"))
......@@ -27,5 +27,5 @@
wf.add_transition(_('start'), (initialized, ), in_progress, ('managers', 'owners'))
wf.add_transition(_('complete'), (in_progress, ), succeeded, ())
wf.add_transition(_('abort'), (in_progress, ), failed, ())
wf.add_transition(_('kill'), (in_progress, ), killed, ('managers', 'owners'))
wf.add_transition(_("start"), (initialized,), in_progress, ("managers", "owners"))
wf.add_transition(_("complete"), (in_progress,), succeeded, ())
wf.add_transition(_("abort"), (in_progress,), failed, ())
wf.add_transition(_("kill"), (in_progress,), killed, ("managers", "owners"))
......@@ -30,9 +30,9 @@
# load metadata from the __pkginfo__.py file so there is no risk of conflict
# see https://packaging.python.org/en/latest/single_source_version.html
pkginfo = join(here, 'cubicweb_subprocess', '__pkginfo__.py')
pkginfo = join(here, "cubicweb_subprocess", "__pkginfo__.py")
__pkginfo__ = {}
with open(pkginfo) as f:
exec(f.read(), __pkginfo__)
# get required metadatas
......@@ -34,14 +34,14 @@
__pkginfo__ = {}
with open(pkginfo) as f:
exec(f.read(), __pkginfo__)
# get required metadatas
distname = __pkginfo__['distname']
version = __pkginfo__['version']
license = __pkginfo__['license']
description = __pkginfo__['description']
web = __pkginfo__['web']
author = __pkginfo__['author']
author_email = __pkginfo__['author_email']
classifiers = __pkginfo__['classifiers']
distname = __pkginfo__["distname"]
version = __pkginfo__["version"]
license = __pkginfo__["license"]
description = __pkginfo__["description"]
web = __pkginfo__["web"]
author = __pkginfo__["author"]
author_email = __pkginfo__["author_email"]
classifiers = __pkginfo__["classifiers"]
......@@ -47,5 +47,5 @@
with open(join(here, 'README.rst')) as f:
with open(join(here, "README.rst")) as f:
long_description = f.read()
# get optional metadatas
......@@ -49,10 +49,10 @@
long_description = f.read()
# get optional metadatas
data_files = __pkginfo__.get('data_files', None)
dependency_links = __pkginfo__.get('dependency_links', ())
data_files = __pkginfo__.get("data_files", None)
dependency_links = __pkginfo__.get("dependency_links", ())
requires = {}
for entry in ("__depends__",): # "__recommends__"):
requires.update(__pkginfo__.get(entry, {}))
......@@ -54,10 +54,11 @@
requires = {}
for entry in ("__depends__",): # "__recommends__"):
requires.update(__pkginfo__.get(entry, {}))
install_requires = ["{0} {1}".format(d, v and v or "").strip()
for d, v in requires.items()]
install_requires = [
"{0} {1}".format(d, v and v or "").strip() for d, v in requires.items()
]
setup(
......@@ -70,7 +71,7 @@
author_email=author_email,
url=web,
classifiers=classifiers,
packages=find_packages(exclude=['test']),
packages=find_packages(exclude=["test"]),
install_requires=install_requires,
include_package_data=True,
entry_points={
......@@ -74,7 +75,7 @@
install_requires=install_requires,
include_package_data=True,
entry_points={
'cubicweb.cubes': [
'subprocess=cubicweb_subprocess',
"cubicweb.cubes": [
"subprocess=cubicweb_subprocess",
],
},
......@@ -79,5 +80,4 @@
],
},
zip_safe=False,
)
......@@ -29,6 +29,6 @@
(man 3 getlogin)
Another solution would be to use $LOGNAME, $USER or $USERNAME
"""
if sys.platform == 'win32':
return os.environ.get('USERNAME') or 'cubicweb'
if sys.platform == "win32":
return os.environ.get("USERNAME") or "cubicweb"
import pwd
......@@ -34,6 +34,7 @@
import pwd
return pwd.getpwuid(os.getuid())[0]
def update_parser(parser):
login = getlogin()
......@@ -35,21 +36,50 @@
return pwd.getpwuid(os.getuid())[0]
def update_parser(parser):
login = getlogin()
parser.add_option('-r', '--rebuild-database', dest='rebuild_db',
default=False, action="store_true",
help="remove tmpdb and rebuilds the test database")
parser.add_option('-u', '--dbuser', dest='dbuser', action='store',
default=login, help="database user")
parser.add_option('-w', '--dbpassword', dest='dbpassword', action='store',
default=login, help="database user's password")
parser.add_option('-n', '--dbname', dest='dbname', action='store',
default=None, help="database name")
parser.add_option('--euser', dest='euser', action='store',
default=login, help="euser name")
parser.add_option('--epassword', dest='epassword', action='store',
default=login, help="euser's password' name")
parser.add_option(
"-r",
"--rebuild-database",
dest="rebuild_db",
default=False,
action="store_true",
help="remove tmpdb and rebuilds the test database",
)
parser.add_option(
"-u",
"--dbuser",
dest="dbuser",
action="store",
default=login,
help="database user",
)
parser.add_option(
"-w",
"--dbpassword",
dest="dbpassword",
action="store",
default=login,
help="database user's password",
)
parser.add_option(
"-n",
"--dbname",
dest="dbname",
action="store",
default=None,
help="database name",
)
parser.add_option(
"--euser", dest="euser", action="store", default=login, help="euser name"
)
parser.add_option(
"--epassword",
dest="epassword",
action="store",
default=login,
help="euser's password' name",
)
return parser
......@@ -57,5 +87,5 @@
def __init__(self, cvg, options):
super(CustomPyTester, self).__init__(cvg, options)
if options.rebuild_db:
os.unlink('tmpdb')
os.unlink('tmpdb-template')
os.unlink("tmpdb")
os.unlink("tmpdb-template")
......@@ -23,5 +23,5 @@
pass
if __name__ == '__main__':
if __name__ == "__main__":
from logilab.common.testlib import unittest_main
......@@ -27,2 +27,3 @@
from logilab.common.testlib import unittest_main
unittest_main()
......@@ -29,5 +29,5 @@
def pid_exists(pid):
# http://stackoverflow.com/a/17645146
if os.name == 'posix':
if os.name == "posix":
import errno
......@@ -33,4 +33,5 @@
import errno
if pid < 0:
return False
try:
......@@ -41,6 +42,7 @@
return True
else:
import ctypes
kernel32 = ctypes.windll.kernel32
SYNCHRONIZE = 0x100000
......@@ -53,5 +55,4 @@
class SubprocessEntityTC(SubprocessTC):
def check_subprocess_status(self, retcode, expected_state):
......@@ -57,6 +58,6 @@
def check_subprocess_status(self, retcode, expected_state):
'''Start a subprocess that returns with ``retcode``.
Check the db for recorded return code and workflow state.'''
cmd = 'import sys; sys.exit(%d)' % retcode
"""Start a subprocess that returns with ``retcode``.
Check the db for recorded return code and workflow state."""
cmd = "import sys; sys.exit(%d)" % retcode
with self.admin_access.client_cnx() as cnx:
subprocess = self.pyprocess(cnx, cmd)
......@@ -61,6 +62,6 @@
with self.admin_access.client_cnx() as cnx:
subprocess = self.pyprocess(cnx, cmd)
self.fire_transition(subprocess, 'start')
self.fire_transition(subprocess, "start")
self.wait_finished(subprocess)
subprocess.cw_clear_all_caches()
self.assertEqual(retcode, subprocess.return_code)
......@@ -64,8 +65,8 @@
self.wait_finished(subprocess)
subprocess.cw_clear_all_caches()
self.assertEqual(retcode, subprocess.return_code)
effective_state = subprocess.cw_adapt_to('IWorkflowable').state
effective_state = subprocess.cw_adapt_to("IWorkflowable").state
self.assertEqual(expected_state, effective_state)
def test_start(self):
with self.admin_access.repo_cnx() as cnx:
......@@ -68,11 +69,11 @@
self.assertEqual(expected_state, effective_state)
def test_start(self):
with self.admin_access.repo_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'pass')
self.fire_transition(subprocess, 'start')
subprocess = self.pyprocess(cnx, "pass")
self.fire_transition(subprocess, "start")
self.wait_finished(subprocess)
self.assertEqual(0, subprocess.return_code)
def test_unicode_key_in_env_and_synchronousstart(self):
with self.admin_access.repo_cnx() as cnx:
......@@ -74,13 +75,13 @@
self.wait_finished(subprocess)
self.assertEqual(0, subprocess.return_code)
def test_unicode_key_in_env_and_synchronousstart(self):
with self.admin_access.repo_cnx() as cnx:
cmdline = json.dumps([sys.executable, '-c', 'pass'])
os.environ[u'FOO'] = u'BABAR'
subprocess = cnx.create_entity('Subprocess', cmdline=cmdline)
cmdline = json.dumps([sys.executable, "-c", "pass"])
os.environ["FOO"] = "BABAR"
subprocess = cnx.create_entity("Subprocess", cmdline=cmdline)
cnx.commit()
subprocess.synchronousstart()
self.assertEqual(0, subprocess.return_code)
def test_start_and_succeeds(self):
......@@ -82,8 +83,8 @@
cnx.commit()
subprocess.synchronousstart()
self.assertEqual(0, subprocess.return_code)
def test_start_and_succeeds(self):
self.check_subprocess_status(retcode=0, expected_state=u'succeeded')
self.check_subprocess_status(retcode=0, expected_state="succeeded")
def test_start_and_fails(self):
......@@ -88,7 +89,7 @@
def test_start_and_fails(self):
'''what ?!? The answer of the universe is expected as a failure :/'''
self.check_subprocess_status(retcode=42, expected_state=u'failed')
"""what ?!? The answer of the universe is expected as a failure :/"""
self.check_subprocess_status(retcode=42, expected_state="failed")
def test_start_fails_outside_workflow(self):
with self.admin_access.repo_cnx() as cnx:
......@@ -92,8 +93,8 @@
def test_start_fails_outside_workflow(self):
with self.admin_access.repo_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'pass')
subprocess = self.pyprocess(cnx, "pass")
self.assertRaises(AssertionError, subprocess.start)
def test_kill_running(self):
with self.admin_access.repo_cnx() as cnx:
......@@ -96,6 +97,6 @@
self.assertRaises(AssertionError, subprocess.start)
def test_kill_running(self):
with self.admin_access.repo_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'import time; time.sleep(3600);')
subprocess = self.pyprocess(cnx, "import time; time.sleep(3600);")
starttime = time.time()
......@@ -101,5 +102,5 @@
starttime = time.time()
self.fire_transition(subprocess, 'start')
self.fire_transition(subprocess, "start")
self.wait_started(subprocess)
with self.admin_access.repo_cnx() as cnx:
......@@ -111,6 +112,6 @@
def test_kill_finished(self):
with self.admin_access.repo_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'pass')
self.fire_transition(subprocess, 'start')
subprocess = self.pyprocess(cnx, "pass")
self.fire_transition(subprocess, "start")
self.wait_finished(subprocess)
......@@ -116,5 +117,5 @@
self.wait_finished(subprocess)
self.assertRaises(ValidationError, self.fire_transition, subprocess, 'kill')
self.assertRaises(ValidationError, self.fire_transition, subprocess, "kill")
def test_kill_not_running(self):
with self.admin_access.repo_cnx() as cnx:
......@@ -118,9 +119,9 @@
def test_kill_not_running(self):
with self.admin_access.repo_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'import time; time.sleep(3600);')
self.fire_transition(subprocess, 'start', deny_hooks='subprocess.workflow')
subprocess = self.pyprocess(cnx, "import time; time.sleep(3600);")
self.fire_transition(subprocess, "start", deny_hooks="subprocess.workflow")
self.assertRaises(ProcessNotRunning, subprocess.kill)
def test_kill_fails_outside_workflow(self):
with self.admin_access.repo_cnx() as cnx:
......@@ -123,11 +124,11 @@
self.assertRaises(ProcessNotRunning, subprocess.kill)
def test_kill_fails_outside_workflow(self):
with self.admin_access.repo_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'import time; time.sleep(3600);')
subprocess = self.pyprocess(cnx, "import time; time.sleep(3600);")
self.assertRaises(ValidationError, subprocess.kill)
def test_stdout_stderr(self):
with self.admin_access.repo_cnx() as cnx:
pycode = 'print("toto" * 1000); raise ValueError("tutu")'
subprocess = self.pyprocess(cnx, pycode)
......@@ -128,9 +129,9 @@
self.assertRaises(ValidationError, subprocess.kill)
def test_stdout_stderr(self):
with self.admin_access.repo_cnx() as cnx:
pycode = 'print("toto" * 1000); raise ValueError("tutu")'
subprocess = self.pyprocess(cnx, pycode)
self.fire_transition(subprocess, 'start')
self.fire_transition(subprocess, "start")
self.wait_finished(subprocess)
subprocess.cw_clear_all_caches()
......@@ -135,5 +136,5 @@
self.wait_finished(subprocess)
subprocess.cw_clear_all_caches()
efiles = cnx.find('File', output_of=subprocess.eid)
efiles = cnx.find("File", output_of=subprocess.eid)
self.assertEqual(2, len(efiles))
expecteds = {
......@@ -138,5 +139,5 @@
self.assertEqual(2, len(efiles))
expecteds = {
'stdout': ('toto' * 1000 + os.linesep).encode('utf-8'),
'stderr': os.linesep.join(
"stdout": ("toto" * 1000 + os.linesep).encode("utf-8"),
"stderr": os.linesep.join(
(
......@@ -142,3 +143,3 @@
(
'Traceback (most recent call last):',
"Traceback (most recent call last):",
' File "<string>", line 1, in <module>',
......@@ -144,4 +145,4 @@
' File "<string>", line 1, in <module>',
'ValueError: tutu',
''
"ValueError: tutu",
"",
)
......@@ -147,5 +148,5 @@
)
).encode('utf-8')
).encode("utf-8"),
}
for efile in efiles.entities():
self.assertEqual(expecteds[efile.data_name], efile.data.getvalue())
......@@ -149,5 +150,5 @@
}
for efile in efiles.entities():
self.assertEqual(expecteds[efile.data_name], efile.data.getvalue())
self.assertEqual(2, cnx.find('File').rowcount)
self.assertEqual(2, cnx.find("File").rowcount)
subprocess.cw_delete()
......@@ -153,4 +154,4 @@
subprocess.cw_delete()
self.assertEqual(0, cnx.find('File').rowcount)
self.assertEqual(0, cnx.find("File").rowcount)
......@@ -155,4 +156,4 @@
if __name__ == '__main__':
if __name__ == "__main__":
import unittest
......@@ -158,2 +159,3 @@
import unittest
unittest.main()
......@@ -26,9 +26,10 @@
class WorkflowHooksTC(SubprocessTC):
def test_start(self):
with saved_vars(Subprocess):
@monkeypatch(Subprocess)
def start(self):
self.cw_set(pid=1)
with self.admin_access.client_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'print "toto"')
......@@ -29,10 +30,10 @@
@monkeypatch(Subprocess)
def start(self):
self.cw_set(pid=1)
with self.admin_access.client_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'print "toto"')
self.fire_transition(subprocess, 'start')
self.fire_transition(subprocess, "start")
cnx.commit()
with self.admin_access.client_cnx() as cnx:
subprocess = cnx.entity_from_eid(subprocess.eid)
......@@ -40,6 +41,7 @@
def test_kill(self):
with saved_vars(Subprocess):
@monkeypatch(Subprocess)
def start(self):
self.cw_set(pid=1)
......@@ -50,11 +52,11 @@
with self.admin_access.client_cnx() as cnx:
subprocess = self.pyprocess(cnx, 'print "toto"')
self.fire_transition(subprocess, 'start')
self.fire_transition(subprocess, 'kill')
self.fire_transition(subprocess, "start")
self.fire_transition(subprocess, "kill")
cnx.commit()
with self.admin_access.client_cnx() as cnx:
subprocess = cnx.entity_from_eid(subprocess.eid)
self.assertEqual(0, subprocess.pid)
......@@ -55,8 +57,8 @@
cnx.commit()
with self.admin_access.client_cnx() as cnx:
subprocess = cnx.entity_from_eid(subprocess.eid)
self.assertEqual(0, subprocess.pid)
if __name__ == '__main__':
if __name__ == "__main__":
import unittest
......@@ -62,2 +64,3 @@
import unittest
unittest.main()
......@@ -27,8 +27,8 @@
class TestCommunicate(TestCase):
def test_stdout_stderr(self):
pycode = r'''import sys
pycode = r"""import sys
sys.stdout.write('\N{RIGHTWARDS ARROW}' * 666)
sys.stdout.flush()
sys.stderr.write('\N{LEFTWARDS ARROW}' * 200)
sys.stderr.flush()
......@@ -31,12 +31,11 @@
sys.stdout.write('\N{RIGHTWARDS ARROW}' * 666)
sys.stdout.flush()
sys.stderr.write('\N{LEFTWARDS ARROW}' * 200)
sys.stderr.flush()
'''
outputs = {'stdout': BytesIO(),
'stderr': BytesIO()}
cmdline = [sys.executable, '-c', pycode]
"""
outputs = {"stdout": BytesIO(), "stderr": BytesIO()}
cmdline = [sys.executable, "-c", pycode]
proc = Popen(cmdline, stdout=PIPE, stderr=PIPE)
for name, content in communicate(proc, chunk_size=500):
outputs[name].write(content)
......@@ -39,8 +38,8 @@
proc = Popen(cmdline, stdout=PIPE, stderr=PIPE)
for name, content in communicate(proc, chunk_size=500):
outputs[name].write(content)
self.assertEqual('' * 666, outputs['stdout'].getvalue().decode('utf-8'))
self.assertEqual('' * 200, outputs['stderr'].getvalue().decode('utf-8'))
self.assertEqual("" * 666, outputs["stdout"].getvalue().decode("utf-8"))
self.assertEqual("" * 200, outputs["stderr"].getvalue().decode("utf-8"))
def test_tiny_lines(self):
......@@ -45,7 +44,7 @@
def test_tiny_lines(self):
pycode = r'''import sys
pycode = r"""import sys
print('toto')
sys.stdout.flush()
print('tata')
sys.stdout.flush()
......@@ -48,12 +47,11 @@
print('toto')
sys.stdout.flush()
print('tata')
sys.stdout.flush()
'''
outputs = {'stdout': [],
'stderr': []}
cmdline = [sys.executable, '-c', pycode]
"""
outputs = {"stdout": [], "stderr": []}
cmdline = [sys.executable, "-c", pycode]
proc = Popen(cmdline, stdout=PIPE, stderr=PIPE)
for name, content in communicate(proc, chunk_size=500):
outputs[name].append(content)
......@@ -56,8 +54,8 @@
proc = Popen(cmdline, stdout=PIPE, stderr=PIPE)
for name, content in communicate(proc, chunk_size=500):
outputs[name].append(content)
self.assertEqual(2, len(outputs['stdout']))
self.assertEqual(0, len(outputs['stderr']))
self.assertEqual(2, len(outputs["stdout"]))
self.assertEqual(0, len(outputs["stderr"]))
self.assertEqual(
[
......@@ -62,5 +60,5 @@
self.assertEqual(
[
('toto' + os.linesep).encode('utf-8'),
('tata' + os.linesep).encode('utf-8')
("toto" + os.linesep).encode("utf-8"),
("tata" + os.linesep).encode("utf-8"),
],
......@@ -66,5 +64,5 @@
],
outputs['stdout']
outputs["stdout"],
)
......@@ -68,5 +66,5 @@
)
if __name__ == '__main__':
if __name__ == "__main__":
main()
......@@ -25,7 +25,7 @@
@contextmanager
def saved_vars(obj):
'''Save vars(obj) and restore it on exit.'''
"""Save vars(obj) and restore it on exit."""
old_vars = vars(obj).copy()
yield
for key, value in old_vars.items():
......@@ -29,9 +29,9 @@
old_vars = vars(obj).copy()
yield
for key, value in old_vars.items():
if not key.startswith('__'): # at least __doc__ is not writable
if not key.startswith("__"): # at least __doc__ is not writable
setattr(obj, key, value)
class SubprocessTC(CubicWebTC):
def pyprocess(self, cnx, pycode):
......@@ -33,7 +33,7 @@
setattr(obj, key, value)
class SubprocessTC(CubicWebTC):
def pyprocess(self, cnx, pycode):
'''Return a new subprocess executing the given python code.
"""Return a new subprocess executing the given python code.
The 'start' transition is silently fired (without hooks).
......@@ -39,7 +39,7 @@
The 'start' transition is silently fired (without hooks).
'''
cmdline = json.dumps([sys.executable, '-c', pycode])
subprocess = cnx.create_entity('Subprocess', cmdline=cmdline)
"""
cmdline = json.dumps([sys.executable, "-c", pycode])
subprocess = cnx.create_entity("Subprocess", cmdline=cmdline)
cnx.commit()
return subprocess
......@@ -49,7 +49,6 @@
while subprocess.pid is None:
subprocess.cw_clear_all_caches()
if (time.time() - starttime) > max_duration:
self.fail('the process took more than %ss to start' %
max_duration)
self.fail("the process took more than %ss to start" % max_duration)
def wait_finished(self, subprocess, max_duration=1):
......@@ -54,4 +53,4 @@
def wait_finished(self, subprocess, max_duration=1):
'''Wait the ``subprocess`` to complete until ``max_duration`` (in
"""Wait the ``subprocess`` to complete until ``max_duration`` (in
seconds) is reached.
......@@ -57,6 +56,6 @@
seconds) is reached.
'''
"""
starttime = time.time()
while subprocess.return_code is None:
subprocess.cw_clear_all_caches()
if (time.time() - starttime) > max_duration:
......@@ -59,8 +58,7 @@
starttime = time.time()
while subprocess.return_code is None:
subprocess.cw_clear_all_caches()
if (time.time() - starttime) > max_duration:
self.fail('the process took more than %ss to complete' %
max_duration)
self.fail("the process took more than %ss to complete" % max_duration)
def _fire_transition(self, subprocess, trname):
......@@ -65,8 +63,7 @@
def _fire_transition(self, subprocess, trname):
'''fire the transition ``trname`` on the ``subprocess``.
'''
subprocess.cw_adapt_to('IWorkflowable').fire_transition(trname)
"""fire the transition ``trname`` on the ``subprocess``."""
subprocess.cw_adapt_to("IWorkflowable").fire_transition(trname)
subprocess._cw.commit()
def fire_transition(self, subprocess, trname, deny_hooks=None):
......@@ -70,8 +67,7 @@
subprocess._cw.commit()
def fire_transition(self, subprocess, trname, deny_hooks=None):
'''fire the transition ``trname`` on the ``subprocess``.
'''
"""fire the transition ``trname`` on the ``subprocess``."""
if deny_hooks:
with subprocess._cw.allow_all_hooks_but(deny_hooks):
self._fire_transition(subprocess, trname)
......