Metadata-Version: 1.0
Name: nicecall
Version: 1.0.2
Summary: A library which provides a slightly more convinient way to launch processes, compared to Python's subprocess module.
Home-page: http://go.pelicandd.com/n/python-niceprocess
Author: Arseni Mourzenko
Author-email: arseni.mourzenko@pelicandd.com
License: MIT
Description: While |python-subprocess|_ is great, it may not be the easiest library to use. This is the reason I created ``nicecall``: it allows to do simple tasks with processes very easily.
        
        .. |python-subprocess| replace:: Python's ``subprocess`` library
        .. _python-subprocess: https://docs.python.org/3/library/subprocess.html
        
        Note that ``nicecall`` is not a substitute to ``subprocess``, because much of ``subprocess`` functionality doesn't exist. For instance, one can't use ``stdin`` or pipes with ``nicecall``. The goal is not to replace ``subprocess``, but only to provide an easy way to do the most common tasks.
        
        How to use the library
        ----------------------
        
        Note: make sure you also check `the tests <http://source.pelicandd.com/codebase/nicecall/tests/>`_ which
        give a few examples of how to use the library. Most pieces of code below are in ``tests/smoke/test_docs.py``.
        
        Fluent interface
        ~~~~~~~~~~~~~~~~
        
        The library uses method chaining, which allows to add logic on the fly before actually launching the process. Methods such as ``on_stdout``, ``ignore``, etc. create a copy of the object, modify this copy, and return it to the caller. This makes it possible to reuse base objects in multiple locations in your code, reducing code duplication.
        
        Exit code
        ~~~~~~~~~
        
        Let's start by executing a task:
        ::
        
            result = nicecall.Process(["touch", "/tmp/hello"]).execute()
        
        The ``result`` contains the exit code, which makes it possible to determine whether the process terminated successfully. Below, the value of ``result`` is expected to be zero. You may also make it fail:
        ::
        
            result = nicecall.Process(["touch", "/tmp/a/b/c/d"]).execute()
        
        The ``result`` should now be ``1``, assuming you don't have ``/tmp/a/b/c`` directory.
        
        ``stdout`` and ``stderr``
        ~~~~~~~~~~~~~~~~~~~~~~~~~
        
        One can also perform a bunch of actions on `stdout` and `stderr`. Let's display `stdout` in terminal:
        ::
        
            nicecall.Process(["echo", "a\nb\nc"]).on_stdout(print).execute()
        
        The output should be:
        ::
        
            a
            b
            c
        
        If you're *absolutely sure* that the process will be fast and produce a small amount of ``stdout`` or ``stderr``, you can ask the library to buffer the contents in order to process them later:
        ::
        
            stdout_buffer = nicecall.Buffer()
            nicecall \
                .Process(["echo", "a\nb"]) \
                .on_stdout(stdout_buffer.store) \
                .execute()
        
        Now you can access the content either as a list:
        ::
        
            >>> print(stdout_buffer.lines)
            ['a', 'b']
        
        or as a string with newlines:
        ::
        
            >>> stdout_buffer.contents
            a
            b
        
        Logging
        ~~~~~~~
        
        A common thing, at least in my case, is to log ``stdout`` or ``stderr`` to syslog. With ``nicecall``, it's easy:
        ::
        
            # Initialize logging.
            log_handler = logging.handlers.SysLogHandler(address="/dev/log")
            formatter = logging.Formatter("demo: [%(levelname)s] %(message)s")
            log_handler.setFormatter(formatter)
            log_handler.setLevel(logging.DEBUG)
        
            demo_logger = logging.getLogger("demo")
            demo_logger.setLevel(logging.DEBUG)
            demo_logger.addHandler(log_handler)
        
            ...
        
            # Log stdout.
            logger = nicecall.StdoutLogger("test")
            nicecall.Process(["echo", "a\nb"]).on_stdout(logger.log).execute()
        
        Note that ``nicecall.StdoutLogger`` can be initialized with either the name of the logger, or the instance of the logger itself.
        
        The library itself logs calls (``INFO`` level) and call failures (``WARNING`` level) through the logger named `nicecall.process`. For instance, executing ``touch /tmp/a/b/c/d`` will produce two log messages:
        ::
        
            INFO:nicecall.process:Called “touch /tmp/a/b/c/d”.
            WARNING:nicecall.process:“touch /tmp/a/b/c/d” failed with exit code 1.
        
        Filtering
        ~~~~~~~~~
        
        Sometimes, you don't want to process specific content such as empty lines or whitespace. This is what filters are about:
        ::
        
            nicecall \
                .Process(["echo", "a\n\nb"]) \
                .ignore(nicecall.filters.whitespace) \
                .on_stdout(print) \
                .execute()
        
        Here, ``a`` and ``b`` will be displayed in terminal; however, the empty line will be ignored. The reverse is called ``keep``. Both ``keep`` and ``ignore`` accept any function which takes a string as a parameter and returns a boolean. For instance, this will print only ``stdout`` content longer than fifteen characters:
        ::
        
            nicecall \
                .Process(["echo", "Hello World!\nWhat a lovely day!"]) \
                .keep(lambda line: len(line) > 15) \
                .on_stdout(print) \
                .execute()
        
        Multiple ``keep`` and ``ignore`` methods can be combined. The output will keep the lines which match *all* predicates from ``keep`` methods and *none* from ``ignore`` ones.
        
        Filters apply to both ``stdout`` and ``stderr``; there is no way to apply them to only one of the streams.
        
        Classes
        -------
        
        ``process.py``
        ~~~~~~~~~~~~~~
        
        The class is the entry point of the library. It makes it possible to specify different options before actually starting the process.
        
         * ``__init__``: creates a new instance of the class.
        
           *Parameters:*
        
           ``args`` is an array which indicates the process to start, and its parameters. Example: ``["touch", "/tmp/hello"]``.
        
         * ``args`` property: the getter which returns the value initially passed to the constructor.
        
         * ``execute``: actually executes the process and blocks until the process finishes.
        
           *Returns:*
        
           Returns the exit code.
        
         * ``keep``: specifies a filter to apply to determine if the line of ``stdout`` or ``stderr`` should be processed by the actions specified through ``on_stdout`` and ``on_stderr``.
        
           The method can be called multiple times and mixed with ``ignore`` to aggregate multiple filters.
        
           *Parameters:*
        
           ``predicate`` is a function which takes a string as a parameter and returns a boolean value: ``true`` if the line should be processed, or ``false`` otherwise.
        
           *Returns:*
        
           Returns a new instance of the ``Process`` class with the new filter.
        
         * ``ignore``: see ``keep``. Here, the predicate is reverted.
        
         * ``on_stdout``: adds an action to perform when a line from ``stdout`` is received.
        
           The method can be called multiple times if multiple actions should be performed for every line of ``stdout``.
        
           *Parameters:*
        
           ``action``: a function which takes a string as a parameter and doesn't return anything.
        
           *Returns:*
        
           Returns a new instance of the ``Process`` class with the new action.
        
         * ``on_stderr``: see ``on_stdout``. Here, it deals with ``stderr`` instead.
        
        ``filters.py``
        ~~~~~~~~~~~~~~
        
        The file contains a bunch of filters which can be used in ``Process.keep`` and ``Process.ignore``.
        
        ``buffer.py``
        ~~~~~~~~~~~~~
        
        This class makes it possible to store in memory the output from ``stdout`` or ``stderr``. It is expected to be used exclusively for short processes which output only a small amount of lines. In other cases, consider processing the output on the fly.
        
        ``logger.py``
        ~~~~~~~~~~~~~
        
        This class is used to log output from ``stdout`` or ``stderr``.
        
        Compatibility
        -------------
        
        The library was written for Python 3 under Linux. I haven't tested it neither with Python 2, nor under Windows.
        
        Reliability
        -----------
        
        While I used Test Driven Development when creating this library and naturally have a 100% branch coverage, I don't know neither Python, nor ``subprocess`` well enough to be sure that the library can be used reliably in production. Use at own risk.
        
        Contributing
        ------------
        
        If you want to contribute, contact me at `arseni.mourzenko@pelicandd.com <mailto:arseni.mourzenko@pelicandd.com>`_. You'll be able to contribute to the project using the `official SVN repository <http://source.pelicandd.com/codebase/nicecall/>`_. If you find it more convinient to clone the source to GitHub, you can do that too.
        
        The source code of the library and the corresponding documentation are covered by the `MIT License <https://opensource.org/licenses/MIT>`_.
        
Keywords: system subprocess process
Platform: UNKNOWN
