<commit_before>"""Model an algorithm as a list of functions.


Installation
------------

:py:mod:`algorithm` is available on `GitHub`_ and on `PyPI`_::

    $ pip install algorithm

We `test <https://travis-ci.org/gittip/algorithm.py>`_ against
Python 2.6, 2.7, 3.2, and 3.3.

:py:mod:`algorithm` is in the `public domain`_.


.. _GitHub: https://github.com/gittip/algorithm.py
.. _PyPI: https://pypi.python.org/pypi/algorithm
.. _public domain: http://creativecommons.org/publicdomain/zero/1.0/


Introduction
------------

This module provides an abstraction for implementing arbitrary algorithms as a
list of functions that operate on a shared namespace, which makes it easy to
arbitrarily modify the algorithm at run time and to provide cascading exception
handling.

First, define an algorithm by defining a series of functions in a Python file::

    def foo():
        return {'baz': 1}

    def bar():
        return {'buz': 2}

    def bloo(baz, buz):
        return {'sum': baz + buz)


Save this file on your ``PYTHONPATH`` as ``blah_algorithm.py``. Now here's how to use it:

    >>> from algorithm import Algorithm
    >>> blah = Algorithm('blah_algorithm')


When you instantiate :py:class:`Algorithm` you give it the dotted path to a
Python module. All of the functions defined in the module are loaded into a
list, in the order they're defined in the file:

    >>> blah.functions #doctest: +ELLIPSIS
    [<function foo at ...>, <function bar at ...>, <function bloo at ...>]


Each function returns a mapping, which is used to update the state of the
current run of the algorithm. Names from the state dictionary are made
available to downstream functions via :py:mod:`dependency_injection`.

Now you can use :py:func:`~Algorithm.run` to run the algorithm. You'll get back
a dictionary representing the algorithm's final state:

    >>> state = blah.run()
    >>> state['sum']
    3


API Reference
-------------

"""
from __future__ import absolute_import, division, print_function, unicode_literals

import re
import sys
import types
import traceback

from dependency_injection import resolve_dependencies


if sys.version_info >= (3, 0, 0):

    _get_func_code = lambda f: f.__code__
    _get_func_name = lambda f: f.__name__

    def _transfer_func_name(to, from_):
        to.__name__ = from_.__name__

    def exec_(some_python, namespace):
        exec(some_python, namespace)
else:
    _get_func_code = lambda f: f.func_code
    _get_func_name = lambda f: f.func_name

    def _transfer_func_name(to, from_):
        to.func_name = from_.func_name

    def exec_(some_python, namespace):
        # Have to double-exec because the Python 2 form is SyntaxError in 3.
        exec("exec some_python in namespace")


class FunctionNotFound(Exception):
    def __str__(self):
        return "The function '{0}' isn't in this algorithm.".format(*self.args)


class Algorithm(object):
    """Model an algorithm as a list of functions.

    :param dotted_name: The dotted name of a Python module containing the
        algorithm definition.


    Each function in your algorithm must return a mapping or :py:class:`None`.
    If it returns a mapping, that will be used to update the state of the
    current run of the algorithm. Functions in the algorithm can use any name
    from the current state as a parameter, and the values will then be supplied
    via :py:mod:`depedency_injection`.<commit_msg>Fix typo in module reference<commit_after>"""Model an algorithm as a list of functions.


Installation
------------

:py:mod:`algorithm` is available on `GitHub`_ and on `PyPI`_::

    $ pip install algorithm

We `test <https://travis-ci.org/gittip/algorithm.py>`_ against
Python 2.6, 2.7, 3.2, and 3.3.

:py:mod:`algorithm` is in the `public domain`_.


.. _GitHub: https://github.com/gittip/algorithm.py
.. _PyPI: https://pypi.python.org/pypi/algorithm
.. _public domain: http://creativecommons.org/publicdomain/zero/1.0/


Introduction
------------

This module provides an abstraction for implementing arbitrary algorithms as a
list of functions that operate on a shared namespace, which makes it easy to
arbitrarily modify the algorithm at run time and to provide cascading exception
handling.

First, define an algorithm by defining a series of functions in a Python file::

    def foo():
        return {'baz': 1}

    def bar():
        return {'buz': 2}

    def bloo(baz, buz):
        return {'sum': baz + buz)


Save this file on your ``PYTHONPATH`` as ``blah_algorithm.py``. Now here's how to use it:

    >>> from algorithm import Algorithm
    >>> blah = Algorithm('blah_algorithm')


When you instantiate :py:class:`Algorithm` you give it the dotted path to a
Python module. All of the functions defined in the module are loaded into a
list, in the order they're defined in the file:

    >>> blah.functions #doctest: +ELLIPSIS
    [<function foo at ...>, <function bar at ...>, <function bloo at ...>]


Each function returns a mapping, which is used to update the state of the
current run of the algorithm. Names from the state dictionary are made
available to downstream functions via :py:mod:`dependency_injection`.

Now you can use :py:func:`~Algorithm.run` to run the algorithm. You'll get back
a dictionary representing the algorithm's final state:

    >>> state = blah.run()
    >>> state['sum']
    3


API Reference
-------------

"""
from __future__ import absolute_import, division, print_function, unicode_literals

import re
import sys
import types
import traceback

from dependency_injection import resolve_dependencies


if sys.version_info >= (3, 0, 0):

    _get_func_code = lambda f: f.__code__
    _get_func_name = lambda f: f.__name__

    def _transfer_func_name(to, from_):
        to.__name__ = from_.__name__

    def exec_(some_python, namespace):
        exec(some_python, namespace)
else:
    _get_func_code = lambda f: f.func_code
    _get_func_name = lambda f: f.func_name

    def _transfer_func_name(to, from_):
        to.func_name = from_.func_name

    def exec_(some_python, namespace):
        # Have to double-exec because the Python 2 form is SyntaxError in 3.
        exec("exec some_python in namespace")


class FunctionNotFound(Exception):
    def __str__(self):
        return "The function '{0}' isn't in this algorithm.".format(*self.args)


class Algorithm(object):
    """Model an algorithm as a list of functions.

    :param dotted_name: The dotted name of a Python module containing the
        algorithm definition.


    Each function in your algorithm must return a mapping or :py:class:`None`.
    If it returns a mapping, that will be used to update the state of the
    current run of the algorithm. Functions in the algorithm can use any name
    from the current state as a parameter, and the values will then be supplied
    via :py:mod:`dependency_injection`.
{'fraction_non_alphanumeric': 0.09941690962099126, 'fraction_numerical': 0.0055393586005830905, 'mean_word_length': 3.4122186495176847, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 43, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3770001', 'n_tokens_mistral': 2059, 'n_tokens_neox': 1917, 'n_words': 807}