Package: conditions
Implementation of the Common Lisp’s conditions system in Python.Free software: BSD license.RationaleCommon Lisp (CL) has a very rich condition system. Conditions in CL is a some sort
of signals, and used not only for exception handling but also in some other patterns.
There is a very good explanation of how they works – a chapter from the book
Practical Common Lisp by Peter Seibel:Beyond Exception Handling: Conditions and Restarts.Python’s exceptions cover only one scenerio from this book, but Common Lisp’s conditions
allows more interesting usage, particlarly “restarts”. Restart is a way to continue
code execution after the exception was signaled, without unwinding a call stack.
I’ll repeat: without unwinding a call stack.Moreover, conditions allows to the author of the library to define varios cases to be
choosen to take over the exception.ExampleHere is example from the book, but implemented in python usingconditionslibrary:def parse_log_entry(text):
    """This function does all real job on log line parsing.
    it setup two cases for restart parsing if a line
    with wrong format was found.

    Restarts:
    - use_value: just retuns an object it was passed. This can
      be any value.
    - reparse: calls `parse_log_entry` again with other text value.
      Beware, this call can lead to infinite recursion.
    """
    text = text.strip()

    if well_formed_log_entry_p(text):
        return LogEntry(text)
    else:
        def use_value(obj):
            return obj
        def reparse(text):
            return parse_log_entry(text)

        with restarts(use_value,
                      reparse) as call:
            return call(signal, MalformedLogEntryError(text))


def log_analyzer(path):
    """This procedure replaces every line which can't be parsed
    with special object MalformedLogEntry.
    """
    with handle(MalformedLogEntryError,
                  lambda (c):
                      invoke_restart('use_value',
                                     MalformedLogEntry(c.text))):
        for filename in find_all_logs(path):
            analyze_log(filename)


def log_analyzer2(path):
    """This procedure considers every line which can't be parsed
    as a line with ERROR level.
    """
    with handle(MalformedLogEntryError,
                  lambda (c):
                      invoke_restart('reparse',
                                     'ERROR: ' + c.text)):
        for filename in find_all_logs(path):
            analyze_log(filename)What we have here is a functionparse_log_entrywhich defines two
ways of handling an exceptional situation:use_valueandreparse.
But decision how bad lines should be handled is made by high level functionlog_analyser. Original book’s chapter have only one version of thelog_analyser, but I’ve added an alternativelog_analyser2to
illustrate a why restarts is a useful pattern. The value of this
pattern is in the ability to move dicision making code from low level
library functions into the higher level business logic.Full version of this example can be found inexample/example.pyfile.Installationpip install conditionsDocumentationhttps://python-cl-conditions.readthedocs.org/DevelopmentTo run the all tests run:toxNote, to combine the coverage data from all the tox environments run:Windowsset PYTEST_ADDOPTS=--cov-append
toxOtherPYTEST_ADDOPTS=--cov-append toxRelated projectsThere is alsowithrestartpython library, created with
the same intent asconditions. But it have clunky API and
weird name seems abandoned since 2010.Changelog0.2.0 (2016-04-05)Added context managerrestartsand managerrestartnow gets
only a function and returns a function like  to call code
to be restarted.0.1.0 (2016-03-29)First release on PyPI.