From ebcca913568ec0eb0bc4a7d68354a0e339f48538 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl>
Date: Wed, 28 Jul 2021 23:31:48 +0200
Subject: [PATCH] axed callHierarchy

---
 CHANGELOG.md                             |   1 +
 docs/coding/call_hierarchy.rst           |  70 -----
 docs/index.rst                           |   1 -
 satella/__init__.py                      |   2 +-
 satella/coding/call_hierarchy.py         | 325 -----------------------
 tests/test_coding/test_call_hierarchy.py |  73 -----
 6 files changed, 2 insertions(+), 470 deletions(-)
 delete mode 100644 docs/coding/call_hierarchy.rst
 delete mode 100644 satella/coding/call_hierarchy.py
 delete mode 100644 tests/test_coding/test_call_hierarchy.py

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f535d16..abc8f4e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,3 +3,4 @@
 * deprecated `call_and_return_stdout`
 * deprecated `retry(call_on_failure=)`
 * added default parameter to `ThreadCollection`
+* axed entire CallHierarchy
diff --git a/docs/coding/call_hierarchy.rst b/docs/coding/call_hierarchy.rst
deleted file mode 100644
index 11c8dcfb..00000000
--- a/docs/coding/call_hierarchy.rst
+++ /dev/null
@@ -1,70 +0,0 @@
-==============
-Call hierarchy
-==============
-
-..note:: This package is purely experimental!
-
-Satella enables you to define function call and their trees programmatically, so you can
-for example express such a condition "call a function C with given args when either call of function A with given args or function B with given args returned True".
-
-You can specify different argument sets for execution of such a tree, ie. you can provide different argument sets
-and just tell your function to use the _i_-th one.
-
-It additionally supports optional parallelization of function calls, if given an Executor.
-
-.. autoclass:: satella.coding.call_hierarchy.Call
-    :members:
-
-.. autoclass:: satella.coding.call_hierarchy.CallWithArgumentSet
-    :members:
-
-.. autoclass:: satella.coding.call_hierarchy.CallIf
-    :members:
-
-.. autoclass:: satella.coding.call_hierarchy.Reduce
-    :members:
-
-.. autoclass:: satella.coding.call_hierarchy.ExecutionEnvironment
-    :members:
-
-You should run the callables in such a way
-
-    ::
-
-        def add(a, b):
-            print(a+b)
-
-        call_1 = CallWithArgumentSet(add, 0)
-        ee = ExecutionEnvironment([((1, 2), {})])
-        ee(call_1)
-
-but in a pinch you can just type
-
-    ::
-
-        def add(a, b):
-            print(a+b)
-
-        call_1 = CallWithArgumentSet(add, 0)
-        call_1(1, 2)
-
-Note that you need to go through ExecutionEnvironment if you want to make use of parallelism.
-
-.. autofunction:: satella.coding.call_hierarchy.call_with_ee
-
-.. autofunction:: satella.coding.call_hierarchy.call
-
-.. autofunction:: satella.coding.call_hierarchy.package_for_execution
-
-While inside such calls, you can use the following functions:
-
-.. autofunction:: satella.coding.call_hierarchy.current_ee
-
-.. autofunction:: satella.coding.call_hierarchy.current_call
-
-.. autofunction:: satella.coding.call_hierarchy.current_args
-
-.. autofunction:: satella.coding.call_hierarchy.current_kwargs
-
-.. autofunction:: satella.coding.call_hierarchy.current_history
-
diff --git a/docs/index.rst b/docs/index.rst
index 7a13933c..fe5dbf0c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -16,7 +16,6 @@ Visit the project's page at GitHub_!
            coding/futures
            coding/structures
            coding/decorators
-           coding/call_hierarchy
            coding/predicates
            coding/concurrent
            coding/sequences
diff --git a/satella/__init__.py b/satella/__init__.py
index 88c43039..0551dbf7 100644
--- a/satella/__init__.py
+++ b/satella/__init__.py
@@ -1 +1 @@
-__version__ = '2.17.16a5'
+__version__ = '2.17.16a6'
diff --git a/satella/coding/call_hierarchy.py b/satella/coding/call_hierarchy.py
deleted file mode 100644
index 6d9d91e8..00000000
--- a/satella/coding/call_hierarchy.py
+++ /dev/null
@@ -1,325 +0,0 @@
-import threading
-import typing as tp
-import warnings
-from concurrent.futures import Executor
-
-from satella.coding.decorators.decorators import wraps
-from satella.warnings import ExperimentalWarning
-
-local_ee = threading.local()
-
-__all__ = ['Call', 'CallIf', 'CallWithArgumentSet', 'ExecutionEnvironment', 'call_with_ee',
-           'package_for_execution', 'current_call', 'current_args', 'current_history',
-           'current_kwargs', 'current_ee']
-
-
-def push_call_stack(cs: tp.Callable, args: tuple = (), kwargs: tp.Optional[dict] = None) -> None:
-    kwargs = kwargs or {}
-    arg_tuple = ((cs, args, kwargs),)
-    if not hasattr(local_ee, 'cs'):
-        local_ee.cs = arg_tuple
-    else:
-        local_ee.cs = local_ee.cs + arg_tuple
-
-
-def pop_call_stack() -> tp.Optional[tp.Tuple[tp.Callable, tuple, dict]]:
-    if not hasattr(local_ee, 'cs'):
-        return None
-    cs = local_ee.cs
-    if not cs:
-        return None
-    v = cs[-1]
-    local_ee.cs = local_ee.cs[:-1]
-    return v
-
-
-def before_call(fun):
-    @wraps(fun)
-    def inner(self, *args, **kwargs):
-        if not hasattr(local_ee, 'ee'):
-            v = call_with_ee(fun, ExecutionEnvironment([(args, kwargs)]))
-            return v(self, *args, **kwargs)
-        else:
-            return fun(self, *args, **kwargs)
-
-    return inner
-
-
-class Call:
-    """
-    A call to given function with a given set of arguments
-    """
-    __slots__ = 'fn', 'args', 'kwargs'
-
-    def __init__(self, fn, *args, **kwargs):
-        warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-        self.fn = fn
-        self.args = args
-        self.kwargs = kwargs
-
-    @before_call
-    def __call__(self, *args, **kwargs):
-        """
-        Call this callable.
-
-        If an execution environment is already defined, it will be used. If not,
-        a new execution environment will be defined with the 0-th set of arguments
-        as args, kwargs.
-
-        :param args: args to use as the 0-th set of arguments
-        :param kwargs: kwargs to use as the 0-th set of arguments
-        :return: return value
-        """
-        push_call_stack(self, self.args, self.kwargs)
-        try:
-            return self.fn(*self.args, **self.kwargs)
-        finally:
-            pop_call_stack()
-
-
-class CallWithArgumentSet(Call):
-    """
-    Call a function with a set of arguments provided by the environment
-    """
-    __slots__ = 'fn', 'arg_set_no'
-
-    def __init__(self, fn, arg_set_no: int = 0):
-        warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-        self.fn = fn
-        self.arg_set_no = arg_set_no
-
-    @before_call
-    def __call__(self, *args, **kwargs):
-        try:
-            ee = local_ee.ee
-        except AttributeError:
-            raise RuntimeError('Execution environment is required!')
-        args, kwargs = ee[self.arg_set_no]
-        push_call_stack(self, args, kwargs)
-        try:
-            return self.fn(*args, **kwargs)
-        finally:
-            pop_call_stack()
-
-
-class CallIf(Call):
-    """
-    Call a function only if fn_if_call returned True
-    """
-    __slots__ = 'fn_to_call', 'fn_call_if'
-
-    def __init__(self, fn_if_call: Call, fn_to_call: Call):
-        warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-        self.fn_to_call = fn_to_call
-        self.fn_call_if = fn_if_call
-
-    @before_call
-    def __call__(self, *args, **kwargs):
-        if self.fn_call_if():
-            return self.fn_to_call()
-
-
-class Reduce(Call):
-    """
-    A call consisting of calling other calls (possibly in parallel).
-
-    It's result will be the combination of some other function calls by a given operator,
-    starting with a starting value.
-
-    By default the starting operator just discards the results.
-
-    :param callables: callables to call in parallel
-    :param reducing_op: a callable/2 that takes previous result (or the starting value) and current
-        callable result, returning a new starting value
-    :param starting_value: starting value
-    :param do_parallel: whether try to execute these calls in parallel, if possible.
-        Parallel execution will be done only if an executor is given in the execution environment.
-    """
-    __slots__ = 'reducing_op', 'starting_value', 'do_parallel', 'callables'
-
-    def __init__(self, *callables: Call,
-                 reducing_op: tp.Callable[[tp.Any, tp.Any], tp.Any] = lambda a, b: None,
-                 starting_value: tp.Any = 0,
-                 do_parallel: bool = True):
-        warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-        self.reducing_op = reducing_op
-        self.starting_value = starting_value
-        self.do_parallel = do_parallel
-        self.callables = callables
-
-    @before_call
-    def __call__(self, *args, **kwargs):
-        push_call_stack(self)
-        if self.do_parallel:
-            if local_ee.ee.executor is not None:
-                executor = local_ee.ee.executor
-                sv = self.starting_value
-                futures = [executor.submit(call_with_ee(callable_, local_ee.ee, local_ee.cs))
-                           for callable_ in self.callables]
-                for future in futures:
-                    sv = self.reducing_op(sv, future.result())
-                return sv
-        sv = self.starting_value
-        for callable_ in self.callables:
-            b = callable_()
-            sv = self.reducing_op(sv, b)
-        pop_call_stack()
-        return sv
-
-
-class ExecutionEnvironment:
-    """
-    This has no __slots__ so you can add anything here really
-    """
-
-    def __init__(self, argument_sets: tp.Iterable[tp.Tuple[tp.Tuple[tp.Any], tp.Dict]],
-                 executor: tp.Optional[Executor] = None,
-                 cs=()):
-        self.arg_sets = []
-        for args, kwargs in argument_sets:
-            self.arg_sets.append((args, kwargs))
-        self.executor = executor
-        self.cs = cs
-
-    def _set_call_stack_to(self, cs: tp.Optional[tp.List[tp.Callable]] = None):
-        return ExecutionEnvironment(self.arg_sets, self.executor, cs)
-
-    def __call__(self, callable_: Call, *args, **kwargs):
-        """
-        Run a given callable within the current EE.
-
-        :param callable_: callable to run
-        :return: value returned by that callable
-        """
-        had_cs = hasattr(local_ee, 'cs')
-        if had_cs:
-            prev_cs = local_ee.cs
-
-        local_ee.cs = self.cs
-
-        had_ee = hasattr(local_ee, 'ee')
-        if had_ee:
-            prev_ee = local_ee.ee
-        local_ee.ee = self
-        try:
-            return callable_(*args, **kwargs)
-        finally:
-            if had_ee:
-                local_ee.ee = prev_ee
-            else:
-                del local_ee.ee
-            if had_cs:
-                local_ee.cs = prev_cs
-            else:
-                del local_ee.cs
-
-    def __getitem__(self, item: int) -> tp.Tuple[tp.Tuple, tp.Dict]:
-        """Return the n-th argument set"""
-        try:
-            v = self.arg_sets[item]
-        except IndexError:
-            v = (), {}
-        return v
-
-
-def call_with_ee(callable_: tp.Callable, ee: ExecutionEnvironment,
-                 _copy_call_stack_from: tp.Optional[tp.List[tp.Callable]] = None) -> tp.Callable:
-    """
-    Return a callable that will invoke the target callable with specified execution environment,
-    but only if an EE is not defined right now.
-
-    To explicitly provide an execution environment use this:
-
-    >>> call_1 = Call(...)
-    >>> ee = ExecutionEnvironment()
-    >>> ee(call_1)
-
-    :param callable_: callable to invoke
-    :param ee: execution environment to use
-    :param _copy_call_stack_from: used internally, don't use
-    :return: a new callable
-    """
-    warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-
-    def inner(*args, **kwargs):
-        if not hasattr(local_ee, 'ee'):
-            if _copy_call_stack_from is not None:
-                ef = ee._set_call_stack_to(_copy_call_stack_from)
-            else:
-                ef = ee
-            return ef(callable_, *args, **kwargs)
-        else:
-            return callable_(*args, **kwargs)
-
-    return inner
-
-
-def package_for_execution(clbl: tp.Callable, ee: ExecutionEnvironment) -> tp.Callable:
-    """
-    Return a callable that, when called, will call specified callable in target
-    execution environment.
-
-    :param clbl: callable to run
-    :param ee: EE to use
-    :return: a callable
-    """
-    warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-
-    def inner():
-        return ee(clbl)
-
-    return inner
-
-
-def call(fun):
-    """
-    Make the decorated function a callable, with it's args and kwargs to be set as a 0-th argument
-    set.
-    """
-    a = CallWithArgumentSet(fun, 0)
-    return wraps(fun)(a)
-
-
-def current_ee() -> ExecutionEnvironment:
-    warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-    return local_ee.ee
-
-
-def current_call() -> Call:
-    """
-    Return currently processed Call, or None if not available
-    """
-    warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-    return local_ee.cs[-1][0]
-
-
-def current_args() -> tp.Optional[tuple]:
-    """
-    Return currently used positional arguments, or None if not available
-    """
-    warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-    if not local_ee.cs:
-        return None
-    return local_ee.cs[-1][1]
-
-
-def current_kwargs() -> tp.Optional[dict]:
-    """
-    Return currently used kwargs, or None if not available
-    """
-    warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-    if not local_ee.cs:
-        return None
-    return local_ee.cs[-1][2]
-
-
-def current_history() -> tp.Tuple[tp.Tuple[Call, tuple, dict]]:
-    """
-    Return a tuple of subsequent calls that led to this call.
-
-    Position 0 will have the absolutely first call in the hierarchy, where -1 will have the current
-    one.
-    :return: a tuple of tuples (Call instance, args tuple, kwargs dict)
-    """
-    warnings.warn('This module is experimental, use at your own peril', ExperimentalWarning)
-    return local_ee.cs
diff --git a/tests/test_coding/test_call_hierarchy.py b/tests/test_coding/test_call_hierarchy.py
deleted file mode 100644
index d1ee8a01..00000000
--- a/tests/test_coding/test_call_hierarchy.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import unittest
-from concurrent.futures.thread import ThreadPoolExecutor
-
-from satella.coding.call_hierarchy import Call, CallWithArgumentSet, Reduce, CallIf, \
-    ExecutionEnvironment, package_for_execution, call, current_args, current_kwargs, current_history
-
-
-class TestCallHierarchy(unittest.TestCase):
-    def test_call(self):
-        call_ = Call(lambda: 5)
-        self.assertEqual(call_(), 5)
-
-    def test_exec_parallel(self):
-        arg_sets = []
-
-        def mult(y):
-            return y*2
-
-        for value in [1, 2, 3, 4, 5, 6, 7]:
-            arg_sets.append(((value, ), {}))
-
-        calls = []
-        for i, _ in enumerate(arg_sets):
-            calls.append(CallWithArgumentSet(mult, i))
-        call_v = Reduce(*calls, reducing_op=lambda a, b: a+b, starting_value=0)
-        tpe = ThreadPoolExecutor(max_workers=4)
-
-        ee = ExecutionEnvironment(arg_sets, tpe)
-        pp = package_for_execution(call_v, ee)
-        self.assertEqual(pp(), 56)
-
-    def test_current(self):
-        @call
-        def nested(a: int):
-            self.assertEqual(len(current_history()), 2)
-
-        @call
-        def call_me(a: int):
-            self.assertEqual(a, 5)
-            self.assertEqual(current_args(), (5, ))
-            self.assertEqual(current_kwargs(), {})
-            nested()
-
-        call_me(5)
-
-    def test_arg_sets(self):
-        def add(a, b):
-            return a+b
-
-        call1 = CallWithArgumentSet(add, 0)
-        call2 = CallWithArgumentSet(add, 1)
-        call_v = Reduce(call1, call2, reducing_op=lambda a, b: a+b, starting_value=0)
-        ee = ExecutionEnvironment([((1, 2), {}), ((3, 4), {})])
-        self.assertEqual(ee(call_v), 10)
-
-    def test_call_if(self):
-        a = {'test': True, 'b': 0}
-
-        def a_is_true():
-            nonlocal a
-            return a['test']
-
-        def incr_b():
-            nonlocal a
-            a['b'] += 1
-
-        call_if_true = CallIf(a_is_true, incr_b)
-
-        call_if_true()
-        self.assertEqual(a['b'], 1)
-        a['test'] = False
-        call_if_true()
-        self.assertEqual(a['b'], 1)
-- 
GitLab