EasyProcess-0.2.3/0000775000175000017500000000000012774147713013737 5ustar titititi00000000000000EasyProcess-0.2.3/setup.cfg0000664000175000017500000000007312774147713015560 0ustar titititi00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 EasyProcess-0.2.3/README.rst0000664000175000017500000001462512657600261015426 0ustar titititi00000000000000EasyProcess is an easy to use python subprocess interface. Links: * home: https://github.com/ponty/EasyProcess * documentation: http://EasyProcess.readthedocs.org * PYPI: https://pypi.python.org/pypi/EasyProcess |Travis| |Coveralls| |Latest Version| |Supported Python versions| |License| |Downloads| |Code Health| |Documentation| Features: - layer on top of subprocess_ module - easy to start, stop programs - easy to get standard output/error, return code of programs - command can be list or string - logging - timeout - unit-tests - cross-platform, development on linux - global config file with program aliases - shell is not supported - pipes are not supported - stdout/stderr is set only after the subprocess has finished - stop() does not kill whole subprocess tree - unicode support - supported python versions: 2.6, 2.7, 3.3, 3.4, 3.5 - Method chaining_ Similar projects: * execute (http://pypi.python.org/pypi/execute) * commandwrapper (http://pypi.python.org/pypi/commandwrapper) * extcmd (http://pypi.python.org/pypi/extcmd) * sh (https://github.com/amoffat/sh) * envoy (https://github.com/kennethreitz/envoy) * plumbum (https://github.com/tomerfiliba/plumbum) Basic usage =========== >>> from easyprocess import EasyProcess >>> EasyProcess('python --version').call().stderr u'Python 2.6.6' Installation ============ General ------- * install pip_ * install the program:: # as root pip install EasyProcess Ubuntu 14.04 ------------ :: sudo apt-get install python-pip sudo pip install EasyProcess Uninstall --------- :: # as root pip uninstall EasyProcess Usage ===== Simple example -------------- Example program:: #-- include('examples/hello.py')--# from easyprocess import EasyProcess import sys s = EasyProcess([sys.executable, '-c', 'print "hello"']).call().stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.hello')--# hello #-# General ------- The command can be a string list or a concatenated string:: #-- include('examples/cmd.py')--# from easyprocess import EasyProcess print('-- Run program, wait for it to complete, get stdout (command is string):') s=EasyProcess('python -c "print 3"').call().stdout print(s) print('-- Run program, wait for it to complete, get stdout (command is list):') s=EasyProcess(['python','-c','print 3']).call().stdout print(s) print('-- Run program, wait for it to complete, get stderr:') s=EasyProcess('python --version').call().stderr print(s) print('-- Run program, wait for it to complete, get return code:') s=EasyProcess('python --version').call().return_code print(s) print('-- Run program, wait 1 second, stop it, get stdout:') s=EasyProcess('ping localhost').start().sleep(1).stop().stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.cmd')--# -- Run program, wait for it to complete, get stdout (command is string): 3 -- Run program, wait for it to complete, get stdout (command is list): 3 -- Run program, wait for it to complete, get stderr: Python 2.7.6 -- Run program, wait for it to complete, get return code: 0 -- Run program, wait 1 second, stop it, get stdout: PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.017 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.034 ms #-# Shell commands -------------- Shell commands are not supported. .. warning:: ``echo`` is a shell command on Windows (there is no echo.exe), but it is a program on Linux return_code ----------- :attr:`EasyProcess.return_code` is None until :func:`EasyProcess.stop` or :func:`EasyProcess.wait` is called. With ---- By using :keyword:`with` statement the process is started and stopped automatically:: from easyprocess import EasyProcess with EasyProcess('ping 127.0.0.1') as proc: # start() # communicate with proc pass # stopped Equivalent with:: from easyprocess import EasyProcess proc = EasyProcess('ping 127.0.0.1').start() try: # communicate with proc pass finally: proc.stop() Timeout ------- This was implemented with "daemon thread". "The entire Python program exits when only daemon threads are left." http://docs.python.org/library/threading.html:: #-- include('examples/timeout.py')--# from easyprocess import EasyProcess s = EasyProcess('ping localhost').call(timeout=2).stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.timeout')--# PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.018 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.037 ms 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.025 ms #-# Replacing existing functions ---------------------------- Replacing os.system:: retcode = os.system("ls -l") ==> p = EasyProcess("ls -l").call() retcode = p.return_code print p.stdout Replacing subprocess.call:: retcode = subprocess.call(["ls", "-l"]) ==> p = EasyProcess(["ls", "-l"]).call() retcode = p.return_code print p.stdout .. _pip: http://pip.openplans.org/ .. _subprocess: http://docs.python.org/library/subprocess.html .. _chaining: https://en.wikipedia.org/wiki/Method_chaining#Python .. |Travis| image:: http://img.shields.io/travis/ponty/EasyProcess.svg :target: https://travis-ci.org/ponty/EasyProcess/ .. |Coveralls| image:: http://img.shields.io/coveralls/ponty/EasyProcess/master.svg :target: https://coveralls.io/r/ponty/EasyProcess/ .. |Latest Version| image:: https://img.shields.io/pypi/v/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Supported Python versions| image:: https://img.shields.io/pypi/pyversions/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |License| image:: https://img.shields.io/pypi/l/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Downloads| image:: https://img.shields.io/pypi/dm/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Code Health| image:: https://landscape.io/github/ponty/EasyProcess/master/landscape.svg?style=flat :target: https://landscape.io/github/ponty/EasyProcess/master .. |Documentation| image:: https://readthedocs.org/projects/pyscreenshot/badge/?version=latest :target: http://easyprocess.readthedocs.org EasyProcess-0.2.3/docs/0000775000175000017500000000000012774147713014667 5ustar titititi00000000000000EasyProcess-0.2.3/docs/conf.py0000664000175000017500000000235012703743014016152 0ustar titititi00000000000000import os import sys project = 'EasyProcess' author = 'ponty' copyright = '2011, ponty' __version__ = None exec(open(os.path.join('..', project.lower(), 'about.py')).read()) release = __version__ # logging.basicConfig(level=logging.DEBUG) sys.path.insert(0, os.path.abspath('..')) # Extension extensions = [ # -*-Extensions: -*- 'sphinx.ext.autodoc', # 'sphinxcontrib.programoutput', # 'sphinxcontrib.programscreenshot', # 'sphinx.ext.graphviz', # 'sphinxcontrib.autorun', #'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', ] intersphinx_mapping = {'python': ('http://docs.python.org/', None)} # Source master_doc = 'index' templates_path = ['_templates'] source_suffix = '.rst' exclude_trees = [] pygments_style = 'sphinx' # html build settings html_theme = 'default' html_static_path = ['_static'] # htmlhelp settings htmlhelp_basename = '%sdoc' % project # latex build settings latex_documents = [ ('index', '%s.tex' % project, u'%s Documentation' % project, author, 'manual'), ] # remove blank pages from pdf # http://groups.google.com/group/sphinx- # dev/browse_thread/thread/92e19267d095412d/d60dcba483c6b13d latex_font_size = '10pt,oneside' latex_elements = dict( papersize='a4paper', ) EasyProcess-0.2.3/docs/index.rst0000664000175000017500000000015012614056033016507 0ustar titititi00000000000000=========== EasyProcess =========== About ===== .. include:: ../README.rst .. include:: api.rst EasyProcess-0.2.3/docs/api.rst0000644000175000017500000000006711664677574016205 0ustar titititi00000000000000API === .. automodule:: easyprocess :members: EasyProcess-0.2.3/docs/api/0000775000175000017500000000000012774147713015440 5ustar titititi00000000000000EasyProcess-0.2.3/docs/api/easyprocess.examples.rst0000664000175000017500000000203012614056033022325 0ustar titititi00000000000000easyprocess.examples package ============================ Submodules ---------- easyprocess.examples.cmd module ------------------------------- .. automodule:: easyprocess.examples.cmd :members: :undoc-members: :show-inheritance: easyprocess.examples.hello module --------------------------------- .. automodule:: easyprocess.examples.hello :members: :undoc-members: :show-inheritance: easyprocess.examples.log module ------------------------------- .. automodule:: easyprocess.examples.log :members: :undoc-members: :show-inheritance: easyprocess.examples.timeout module ----------------------------------- .. automodule:: easyprocess.examples.timeout :members: :undoc-members: :show-inheritance: easyprocess.examples.ver module ------------------------------- .. automodule:: easyprocess.examples.ver :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: easyprocess.examples :members: :undoc-members: :show-inheritance: EasyProcess-0.2.3/docs/api/easyprocess.rst0000664000175000017500000000105012614056033020511 0ustar titititi00000000000000easyprocess package =================== Subpackages ----------- .. toctree:: easyprocess.examples Submodules ---------- easyprocess.about module ------------------------ .. automodule:: easyprocess.about :members: :undoc-members: :show-inheritance: easyprocess.unicodeutil module ------------------------------ .. automodule:: easyprocess.unicodeutil :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: easyprocess :members: :undoc-members: :show-inheritance: EasyProcess-0.2.3/docs/api/modules.rst0000664000175000017500000000010612614056033017622 0ustar titititi00000000000000easyprocess =========== .. toctree:: :maxdepth: 4 easyprocess EasyProcess-0.2.3/PKG-INFO0000664000175000017500000002220512774147713015035 0ustar titititi00000000000000Metadata-Version: 1.1 Name: EasyProcess Version: 0.2.3 Summary: Easy to use python subprocess interface. Home-page: https://github.com/ponty/easyprocess Author: ponty Author-email: UNKNOWN License: BSD Description: EasyProcess is an easy to use python subprocess interface. Links: * home: https://github.com/ponty/EasyProcess * documentation: http://EasyProcess.readthedocs.org * PYPI: https://pypi.python.org/pypi/EasyProcess |Travis| |Coveralls| |Latest Version| |Supported Python versions| |License| |Downloads| |Code Health| |Documentation| Features: - layer on top of subprocess_ module - easy to start, stop programs - easy to get standard output/error, return code of programs - command can be list or string - logging - timeout - unit-tests - cross-platform, development on linux - global config file with program aliases - shell is not supported - pipes are not supported - stdout/stderr is set only after the subprocess has finished - stop() does not kill whole subprocess tree - unicode support - supported python versions: 2.6, 2.7, 3.3, 3.4, 3.5 - Method chaining_ Similar projects: * execute (http://pypi.python.org/pypi/execute) * commandwrapper (http://pypi.python.org/pypi/commandwrapper) * extcmd (http://pypi.python.org/pypi/extcmd) * sh (https://github.com/amoffat/sh) * envoy (https://github.com/kennethreitz/envoy) * plumbum (https://github.com/tomerfiliba/plumbum) Basic usage =========== >>> from easyprocess import EasyProcess >>> EasyProcess('python --version').call().stderr u'Python 2.6.6' Installation ============ General ------- * install pip_ * install the program:: # as root pip install EasyProcess Ubuntu 14.04 ------------ :: sudo apt-get install python-pip sudo pip install EasyProcess Uninstall --------- :: # as root pip uninstall EasyProcess Usage ===== Simple example -------------- Example program:: #-- include('examples/hello.py')--# from easyprocess import EasyProcess import sys s = EasyProcess([sys.executable, '-c', 'print "hello"']).call().stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.hello')--# hello #-# General ------- The command can be a string list or a concatenated string:: #-- include('examples/cmd.py')--# from easyprocess import EasyProcess print('-- Run program, wait for it to complete, get stdout (command is string):') s=EasyProcess('python -c "print 3"').call().stdout print(s) print('-- Run program, wait for it to complete, get stdout (command is list):') s=EasyProcess(['python','-c','print 3']).call().stdout print(s) print('-- Run program, wait for it to complete, get stderr:') s=EasyProcess('python --version').call().stderr print(s) print('-- Run program, wait for it to complete, get return code:') s=EasyProcess('python --version').call().return_code print(s) print('-- Run program, wait 1 second, stop it, get stdout:') s=EasyProcess('ping localhost').start().sleep(1).stop().stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.cmd')--# -- Run program, wait for it to complete, get stdout (command is string): 3 -- Run program, wait for it to complete, get stdout (command is list): 3 -- Run program, wait for it to complete, get stderr: Python 2.7.6 -- Run program, wait for it to complete, get return code: 0 -- Run program, wait 1 second, stop it, get stdout: PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.017 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.034 ms #-# Shell commands -------------- Shell commands are not supported. .. warning:: ``echo`` is a shell command on Windows (there is no echo.exe), but it is a program on Linux return_code ----------- :attr:`EasyProcess.return_code` is None until :func:`EasyProcess.stop` or :func:`EasyProcess.wait` is called. With ---- By using :keyword:`with` statement the process is started and stopped automatically:: from easyprocess import EasyProcess with EasyProcess('ping 127.0.0.1') as proc: # start() # communicate with proc pass # stopped Equivalent with:: from easyprocess import EasyProcess proc = EasyProcess('ping 127.0.0.1').start() try: # communicate with proc pass finally: proc.stop() Timeout ------- This was implemented with "daemon thread". "The entire Python program exits when only daemon threads are left." http://docs.python.org/library/threading.html:: #-- include('examples/timeout.py')--# from easyprocess import EasyProcess s = EasyProcess('ping localhost').call(timeout=2).stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.timeout')--# PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.018 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.037 ms 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.025 ms #-# Replacing existing functions ---------------------------- Replacing os.system:: retcode = os.system("ls -l") ==> p = EasyProcess("ls -l").call() retcode = p.return_code print p.stdout Replacing subprocess.call:: retcode = subprocess.call(["ls", "-l"]) ==> p = EasyProcess(["ls", "-l"]).call() retcode = p.return_code print p.stdout .. _pip: http://pip.openplans.org/ .. _subprocess: http://docs.python.org/library/subprocess.html .. _chaining: https://en.wikipedia.org/wiki/Method_chaining#Python .. |Travis| image:: http://img.shields.io/travis/ponty/EasyProcess.svg :target: https://travis-ci.org/ponty/EasyProcess/ .. |Coveralls| image:: http://img.shields.io/coveralls/ponty/EasyProcess/master.svg :target: https://coveralls.io/r/ponty/EasyProcess/ .. |Latest Version| image:: https://img.shields.io/pypi/v/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Supported Python versions| image:: https://img.shields.io/pypi/pyversions/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |License| image:: https://img.shields.io/pypi/l/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Downloads| image:: https://img.shields.io/pypi/dm/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Code Health| image:: https://landscape.io/github/ponty/EasyProcess/master/landscape.svg?style=flat :target: https://landscape.io/github/ponty/EasyProcess/master .. |Documentation| image:: https://readthedocs.org/projects/pyscreenshot/badge/?version=latest :target: http://easyprocess.readthedocs.org Keywords: subprocess interface Platform: UNKNOWN Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 EasyProcess-0.2.3/EasyProcess.egg-info/0000775000175000017500000000000012774147713017671 5ustar titititi00000000000000EasyProcess-0.2.3/EasyProcess.egg-info/top_level.txt0000664000175000017500000000001412774147712022415 0ustar titititi00000000000000easyprocess EasyProcess-0.2.3/EasyProcess.egg-info/dependency_links.txt0000664000175000017500000000000112774147712023736 0ustar titititi00000000000000 EasyProcess-0.2.3/EasyProcess.egg-info/PKG-INFO0000664000175000017500000002220512774147712020766 0ustar titititi00000000000000Metadata-Version: 1.1 Name: EasyProcess Version: 0.2.3 Summary: Easy to use python subprocess interface. Home-page: https://github.com/ponty/easyprocess Author: ponty Author-email: UNKNOWN License: BSD Description: EasyProcess is an easy to use python subprocess interface. Links: * home: https://github.com/ponty/EasyProcess * documentation: http://EasyProcess.readthedocs.org * PYPI: https://pypi.python.org/pypi/EasyProcess |Travis| |Coveralls| |Latest Version| |Supported Python versions| |License| |Downloads| |Code Health| |Documentation| Features: - layer on top of subprocess_ module - easy to start, stop programs - easy to get standard output/error, return code of programs - command can be list or string - logging - timeout - unit-tests - cross-platform, development on linux - global config file with program aliases - shell is not supported - pipes are not supported - stdout/stderr is set only after the subprocess has finished - stop() does not kill whole subprocess tree - unicode support - supported python versions: 2.6, 2.7, 3.3, 3.4, 3.5 - Method chaining_ Similar projects: * execute (http://pypi.python.org/pypi/execute) * commandwrapper (http://pypi.python.org/pypi/commandwrapper) * extcmd (http://pypi.python.org/pypi/extcmd) * sh (https://github.com/amoffat/sh) * envoy (https://github.com/kennethreitz/envoy) * plumbum (https://github.com/tomerfiliba/plumbum) Basic usage =========== >>> from easyprocess import EasyProcess >>> EasyProcess('python --version').call().stderr u'Python 2.6.6' Installation ============ General ------- * install pip_ * install the program:: # as root pip install EasyProcess Ubuntu 14.04 ------------ :: sudo apt-get install python-pip sudo pip install EasyProcess Uninstall --------- :: # as root pip uninstall EasyProcess Usage ===== Simple example -------------- Example program:: #-- include('examples/hello.py')--# from easyprocess import EasyProcess import sys s = EasyProcess([sys.executable, '-c', 'print "hello"']).call().stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.hello')--# hello #-# General ------- The command can be a string list or a concatenated string:: #-- include('examples/cmd.py')--# from easyprocess import EasyProcess print('-- Run program, wait for it to complete, get stdout (command is string):') s=EasyProcess('python -c "print 3"').call().stdout print(s) print('-- Run program, wait for it to complete, get stdout (command is list):') s=EasyProcess(['python','-c','print 3']).call().stdout print(s) print('-- Run program, wait for it to complete, get stderr:') s=EasyProcess('python --version').call().stderr print(s) print('-- Run program, wait for it to complete, get return code:') s=EasyProcess('python --version').call().return_code print(s) print('-- Run program, wait 1 second, stop it, get stdout:') s=EasyProcess('ping localhost').start().sleep(1).stop().stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.cmd')--# -- Run program, wait for it to complete, get stdout (command is string): 3 -- Run program, wait for it to complete, get stdout (command is list): 3 -- Run program, wait for it to complete, get stderr: Python 2.7.6 -- Run program, wait for it to complete, get return code: 0 -- Run program, wait 1 second, stop it, get stdout: PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.017 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.034 ms #-# Shell commands -------------- Shell commands are not supported. .. warning:: ``echo`` is a shell command on Windows (there is no echo.exe), but it is a program on Linux return_code ----------- :attr:`EasyProcess.return_code` is None until :func:`EasyProcess.stop` or :func:`EasyProcess.wait` is called. With ---- By using :keyword:`with` statement the process is started and stopped automatically:: from easyprocess import EasyProcess with EasyProcess('ping 127.0.0.1') as proc: # start() # communicate with proc pass # stopped Equivalent with:: from easyprocess import EasyProcess proc = EasyProcess('ping 127.0.0.1').start() try: # communicate with proc pass finally: proc.stop() Timeout ------- This was implemented with "daemon thread". "The entire Python program exits when only daemon threads are left." http://docs.python.org/library/threading.html:: #-- include('examples/timeout.py')--# from easyprocess import EasyProcess s = EasyProcess('ping localhost').call(timeout=2).stdout print(s) #-# Output:: #-- sh('python -m easyprocess.examples.timeout')--# PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.018 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.037 ms 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.025 ms #-# Replacing existing functions ---------------------------- Replacing os.system:: retcode = os.system("ls -l") ==> p = EasyProcess("ls -l").call() retcode = p.return_code print p.stdout Replacing subprocess.call:: retcode = subprocess.call(["ls", "-l"]) ==> p = EasyProcess(["ls", "-l"]).call() retcode = p.return_code print p.stdout .. _pip: http://pip.openplans.org/ .. _subprocess: http://docs.python.org/library/subprocess.html .. _chaining: https://en.wikipedia.org/wiki/Method_chaining#Python .. |Travis| image:: http://img.shields.io/travis/ponty/EasyProcess.svg :target: https://travis-ci.org/ponty/EasyProcess/ .. |Coveralls| image:: http://img.shields.io/coveralls/ponty/EasyProcess/master.svg :target: https://coveralls.io/r/ponty/EasyProcess/ .. |Latest Version| image:: https://img.shields.io/pypi/v/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Supported Python versions| image:: https://img.shields.io/pypi/pyversions/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |License| image:: https://img.shields.io/pypi/l/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Downloads| image:: https://img.shields.io/pypi/dm/EasyProcess.svg :target: https://pypi.python.org/pypi/EasyProcess/ .. |Code Health| image:: https://landscape.io/github/ponty/EasyProcess/master/landscape.svg?style=flat :target: https://landscape.io/github/ponty/EasyProcess/master .. |Documentation| image:: https://readthedocs.org/projects/pyscreenshot/badge/?version=latest :target: http://easyprocess.readthedocs.org Keywords: subprocess interface Platform: UNKNOWN Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 EasyProcess-0.2.3/EasyProcess.egg-info/SOURCES.txt0000664000175000017500000000105312774147713021554 0ustar titititi00000000000000LICENSE.txt MANIFEST.in README.rst setup.py EasyProcess.egg-info/PKG-INFO EasyProcess.egg-info/SOURCES.txt EasyProcess.egg-info/dependency_links.txt EasyProcess.egg-info/top_level.txt docs/api.rst docs/conf.py docs/index.rst docs/api/easyprocess.examples.rst docs/api/easyprocess.rst docs/api/modules.rst easyprocess/__init__.py easyprocess/about.py easyprocess/unicodeutil.py easyprocess/examples/__init__.py easyprocess/examples/cmd.py easyprocess/examples/hello.py easyprocess/examples/log.py easyprocess/examples/timeout.py easyprocess/examples/ver.pyEasyProcess-0.2.3/easyprocess/0000775000175000017500000000000012774147713016277 5ustar titititi00000000000000EasyProcess-0.2.3/easyprocess/__init__.py0000664000175000017500000003111012774142346020401 0ustar titititi00000000000000"""Easy to use python subprocess interface.""" from easyprocess.unicodeutil import split_command, unidecode, uniencode import logging import os.path import platform import signal import subprocess import tempfile import threading import time from easyprocess.about import __version__ log = logging.getLogger(__name__) log.debug('version=%s', __version__) SECTION_LINK = 'link' POLL_TIME = 0.1 USE_POLL = 0 class EasyProcessError(Exception): def __init__(self, easy_process, msg=''): self.easy_process = easy_process self.msg = msg def __str__(self): return self.msg + ' ' + repr(self.easy_process) template = '''cmd=%s OSError=%s Program install error! ''' class EasyProcessCheckInstalledError(Exception): """This exception is raised when a process run by check() returns a non-zero exit status or OSError is raised. """ def __init__(self, easy_process): self.easy_process = easy_process def __str__(self): msg = template % (self.easy_process.cmd, self.easy_process.oserror, ) if self.easy_process.url: msg += '\nhome page: ' + self.easy_process.url if platform.dist()[0].lower() == 'ubuntu': if self.easy_process.ubuntu_package: msg += '\nYou can install it in terminal:\n' msg += 'sudo apt-get install %s' % self.easy_process.ubuntu_package return msg class EasyProcess(object): ''' .. module:: easyprocess simple interface for :mod:`subprocess` shell is not supported (shell=False) .. warning:: unicode is supported only for string list command (Python2.x) (check :mod:`shlex` for more information) :param cmd: string ('ls -l') or list of strings (['ls','-l']) :param cwd: working directory :param use_temp_files: use temp files instead of pipes for stdout and stderr, pipes can cause deadlock in some cases (see unit tests) :param env: If *env* is not ``None``, it must be a mapping that defines the environment variables for the new process; these are used instead of inheriting the current process' environment, which is the default behavior. (check :mod:`subprocess` for more information) ''' def __init__(self, cmd, ubuntu_package=None, url=None, cwd=None, use_temp_files=True, env=None): self.use_temp_files = use_temp_files self._outputs_processed = False self.env = env self.popen = None self.stdout = None self.stderr = None self._stdout_file = None self._stderr_file = None self.url = url self.ubuntu_package = ubuntu_package self.is_started = False self.oserror = None self.cmd_param = cmd self._thread = None # self.max_bytes_to_log = max_bytes_to_log self._stop_thread = False self.timeout_happened = False self.cwd = cwd cmd = split_command(cmd) self.cmd = cmd self.cmd_as_string = ' '.join(self.cmd) # TODO: not perfect log.debug('param: "%s" ', self.cmd_param) log.debug('command: %s', self.cmd) log.debug('joined command: %s', self.cmd_as_string) if not len(cmd): raise EasyProcessError(self, 'empty command!') def __repr__(self): msg = '<%s cmd_param=%s cmd=%s oserror=%s return_code=%s stdout="%s" stderr="%s" timeout_happened=%s>' % ( self.__class__.__name__, self.cmd_param, self.cmd, self.oserror, self.return_code, self.stdout, self.stderr, self.timeout_happened, ) return msg @property def pid(self): ''' PID (:attr:`subprocess.Popen.pid`) :rtype: int ''' if self.popen: return self.popen.pid @property def return_code(self): ''' returncode (:attr:`subprocess.Popen.returncode`) :rtype: int ''' if self.popen: return self.popen.returncode def check(self, return_code=0): """Run command with arguments. Wait for command to complete. If the exit code was as expected and there is no exception then return, otherwise raise EasyProcessError. :param return_code: int, expected return code :rtype: self """ ret = self.call().return_code ok = ret == return_code if not ok: raise EasyProcessError( self, 'check error, return code is not zero!') return self def check_installed(self): """Used for testing if program is installed. Run command with arguments. Wait for command to complete. If OSError raised, then raise :class:`EasyProcessCheckInstalledError` with information about program installation :param return_code: int, expected return code :rtype: self """ try: self.call() except Exception: raise EasyProcessCheckInstalledError(self) return self def call(self, timeout=None): """Run command with arguments. Wait for command to complete. same as: 1. :meth:`start` 2. :meth:`wait` 3. :meth:`stop` :rtype: self """ self.start().wait(timeout=timeout) if self.is_alive(): self.stop() return self def start(self): """start command in background and does not wait for it. :rtype: self """ if self.is_started: raise EasyProcessError(self, 'process was started twice!') if self.use_temp_files: self._stdout_file = tempfile.TemporaryFile(prefix='stdout_') self._stderr_file = tempfile.TemporaryFile(prefix='stderr_') stdout = self._stdout_file stderr = self._stderr_file else: stdout = subprocess.PIPE stderr = subprocess.PIPE cmd = list(map(uniencode, self.cmd)) try: self.popen = subprocess.Popen(cmd, stdout=stdout, stderr=stderr, cwd=self.cwd, env=self.env, ) except OSError, oserror: log.debug('OSError exception: %s', oserror) self.oserror = oserror raise EasyProcessError(self, 'start error') self.is_started = True log.debug('process was started (pid=%s)', self.pid) return self def is_alive(self): ''' poll process using :meth:`subprocess.Popen.poll` :rtype: bool ''' if self.popen: return self.popen.poll() is None else: return False def wait(self, timeout=None): """Wait for command to complete. Timeout: - discussion: http://stackoverflow.com/questions/1191374/subprocess-with-timeout - implementation: threading :rtype: self """ if timeout is not None: if not self._thread: self._thread = threading.Thread(target=self._wait4process) self._thread.daemon = 1 self._thread.start() if self._thread: self._thread.join(timeout=timeout) self.timeout_happened = self.timeout_happened or self._thread.isAlive() else: # no timeout and no existing thread self._wait4process() return self def _wait4process(self): if self._outputs_processed: return def remove_ending_lf(s): if s.endswith('\n'): return s[:-1] else: return s if self.popen: if self.use_temp_files: if USE_POLL: while 1: if self.popen.poll() is not None: break if self._stop_thread: return time.sleep(POLL_TIME) else: # wait() blocks process, timeout not possible self.popen.wait() self._outputs_processed = True self._stdout_file.seek(0) self._stderr_file.seek(0) self.stdout = self._stdout_file.read() self.stderr = self._stderr_file.read() self._stdout_file.close() self._stderr_file.close() else: # This will deadlock when using stdout=PIPE and/or stderr=PIPE # and the child process generates enough output to a pipe such # that it blocks waiting for the OS pipe buffer to accept more data. # Use communicate() to avoid that. # self.popen.wait() # self.stdout = self.popen.stdout.read() # self.stderr = self.popen.stderr.read() # communicate() blocks process, timeout not possible self._outputs_processed = True (self.stdout, self.stderr) = self.popen.communicate() log.debug('process has ended') self.stdout = remove_ending_lf(unidecode(self.stdout)) self.stderr = remove_ending_lf(unidecode(self.stderr)) log.debug('return code=%s', self.return_code) # def limit_str(s): # if len(s) > self.max_bytes_to_log: # warn = '[middle of output was removed, max_bytes_to_log=%s]'%(self.max_bytes_to_log) # s = s[:self.max_bytes_to_log / 2] + warn + s[-self.max_bytes_to_log / 2:] # return s log.debug('stdout=%s', self.stdout) log.debug('stderr=%s', self.stderr) def stop(self): """Kill process and wait for command to complete. same as: 1. :meth:`sendstop` 2. :meth:`wait` :rtype: self """ return self.sendstop().wait() def sendstop(self): ''' Kill process (:meth:`subprocess.Popen.terminate`). Do not wait for command to complete. :rtype: self ''' if not self.is_started: raise EasyProcessError(self, 'process was not started!') log.debug('stopping process (pid=%s cmd="%s")', self.pid, self.cmd) if self.popen: if self.is_alive(): log.debug('process is active -> sending SIGTERM') try: try: self.popen.terminate() except AttributeError: os.kill(self.popen.pid, signal.SIGKILL) except OSError, oserror: log.debug('exception in terminate:%s', oserror) else: log.debug('process was already stopped') else: log.debug('process was not started') return self def sleep(self, sec): ''' sleeping (same as :func:`time.sleep`) :rtype: self ''' time.sleep(sec) return self def wrap(self, func, delay=0): ''' returns a function which: 1. start process 2. call func, save result 3. stop process 4. returns result similar to :keyword:`with` statement :rtype: ''' def wrapped(): self.start() if delay: self.sleep(delay) x = None try: x = func() except OSError, oserror: log.debug('OSError exception:%s', oserror) self.oserror = oserror raise EasyProcessError(self, 'wrap error!') finally: self.stop() return x return wrapped def __enter__(self): '''used by the :keyword:`with` statement''' self.start() return self def __exit__(self, *exc_info): '''used by the :keyword:`with` statement''' self.stop() def extract_version(txt): """This function tries to extract the version from the help text of any program.""" words = txt.replace(',', ' ').split() version = None for x in reversed(words): if len(x) > 2: if x[0].lower() == 'v': x = x[1:] if '.' in x and x[0].isdigit(): version = x break return version Proc = EasyProcess EasyProcess-0.2.3/easyprocess/about.py0000664000175000017500000000002612774147376017766 0ustar titititi00000000000000__version__ = '0.2.3' EasyProcess-0.2.3/easyprocess/examples/0000775000175000017500000000000012774147713020115 5ustar titititi00000000000000EasyProcess-0.2.3/easyprocess/examples/hello.py0000664000175000017500000000020012614056033021545 0ustar titititi00000000000000from easyprocess import EasyProcess import sys s = EasyProcess([sys.executable, '-c', 'print "hello"']).call().stdout print(s) EasyProcess-0.2.3/easyprocess/examples/cmd.py0000664000175000017500000000132512657600261021223 0ustar titititi00000000000000from easyprocess import EasyProcess print( '-- Run program, wait for it to complete, get stdout (command is string):') s = EasyProcess('python -c "print 3"').call().stdout print(s) print('-- Run program, wait for it to complete, get stdout (command is list):') s = EasyProcess(['python', '-c', 'print 3']).call().stdout print(s) print('-- Run program, wait for it to complete, get stderr:') s = EasyProcess('python --version').call().stderr print(s) print('-- Run program, wait for it to complete, get return code:') s = EasyProcess('python --version').call().return_code print(s) print('-- Run program, wait 1 second, stop it, get stdout:') s = EasyProcess('ping localhost').start().sleep(1).stop().stdout print(s) EasyProcess-0.2.3/easyprocess/examples/timeout.py0000664000175000017500000000014712614056033022142 0ustar titititi00000000000000from easyprocess import EasyProcess s = EasyProcess('ping localhost').call(timeout=2).stdout print(s) EasyProcess-0.2.3/easyprocess/examples/__init__.py0000644000175000017500000000000012057113340022171 0ustar titititi00000000000000EasyProcess-0.2.3/easyprocess/examples/ver.py0000644000175000017500000000022112057113340021233 0ustar titititi00000000000000from easyprocess import EasyProcess import sys v = EasyProcess([sys.executable, '--version']).call().stderr print('your python version:%s' % v) EasyProcess-0.2.3/easyprocess/examples/log.py0000664000175000017500000000065212657600261021243 0ustar titititi00000000000000from easyprocess import EasyProcess import logging # turn on logging logging.basicConfig(level=logging.DEBUG) EasyProcess('python --version').call() EasyProcess('ping localhost').start().sleep(1).stop() EasyProcess('python --version').check() try: EasyProcess('bad_command').check() except Exception, detail: print detail try: EasyProcess('sh -c bad_command').check() except Exception, detail: print detail EasyProcess-0.2.3/easyprocess/unicodeutil.py0000664000175000017500000000276312774142346021202 0ustar titititi00000000000000import logging import shlex import sys import unicodedata log = logging.getLogger(__name__) PY3 = sys.version_info[0] >= 3 if PY3: string_types = str, else: string_types = basestring, class EasyProcessUnicodeError(Exception): pass def split_command(cmd): ''' - cmd is string list -> nothing to do - cmd is string -> split it using shlex :param cmd: string ('ls -l') or list of strings (['ls','-l']) :rtype: string list ''' if not isinstance(cmd, string_types): # cmd is string list pass else: if not PY3: # cmd is string # The shlex module currently does not support Unicode input (in # 2.x)! if isinstance(cmd, unicode): try: cmd = unicodedata.normalize( 'NFKD', cmd).encode('ascii', 'strict') except UnicodeEncodeError: raise EasyProcessUnicodeError('unicode command "%s" can not be processed.' % cmd + 'Use string list instead of string') log.debug('unicode is normalized') cmd = shlex.split(cmd) return cmd def uniencode(s): if PY3: pass # s=s.encode() else: if isinstance(s, unicode): s = s.encode('utf-8') return s def unidecode(s): if PY3: s = s.decode() else: if isinstance(s, str): s = s.decode('utf-8', 'ignore') return s EasyProcess-0.2.3/LICENSE.txt0000644000175000017500000000243511524175751015557 0ustar titititi00000000000000Copyright (c) 2011, ponty All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. EasyProcess-0.2.3/MANIFEST.in0000664000175000017500000000015612502630726015465 0ustar titititi00000000000000graft docs include LICENSE* include TODO* include CHANGES* include README* include setup.py prune docs/_build EasyProcess-0.2.3/setup.py0000664000175000017500000000371412614056033015441 0ustar titititi00000000000000from setuptools import setup import sys import os if os.environ.get('distutils_issue8876_workaround_enabled', False): # sdist_hack: Remove reference to os.link to disable using hardlinks when # building setup.py's sdist target. This is done because # VirtualBox VMs shared filesystems don't support hardlinks. del os.link NAME = 'easyprocess' PYPI_NAME = 'EasyProcess' URL = 'https://github.com/ponty/easyprocess' DESCRIPTION = 'Easy to use python subprocess interface.' PACKAGES = [NAME, NAME + '.examples', ] # get __version__ __version__ = None exec(open(os.path.join(NAME, 'about.py')).read()) VERSION = __version__ extra = {} if sys.version_info >= (3,): extra['use_2to3'] = True classifiers = [ # Get more strings from # http://pypi.python.org/pypi?%3Aaction=list_classifiers "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", # "Programming Language :: Python :: 2.3", # "Programming Language :: Python :: 2.4", #"Programming Language :: Python :: 2.5", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", # "Programming Language :: Python :: 2 :: Only", "Programming Language :: Python :: 3", # "Programming Language :: Python :: 3.0", # "Programming Language :: Python :: 3.1", # "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", ] setup( name=PYPI_NAME, version=VERSION, description=DESCRIPTION, long_description=open('README.rst', 'r').read(), classifiers=classifiers, keywords='subprocess interface', author='ponty', # author_email='', url=URL, license='BSD', packages=PACKAGES, **extra )