def test_add_new_unbound_positional():
    """ Tests that the mechanism provided to support additional functions works, by testing that log can be
    converted. This test checks the behaviour with positional arguments only """

    from mini_lambda import x, _
    from math import log, e

    with pytest.raises(FunctionDefinitionError):
        log(x)

    Log = make_lambda_friendly_method(log)
    complex_identity = _(Log(e ** x))

    # first check that with one argument it works
    assert abs(complex_identity(3.5) - 3.5) < 10e-5
    print(complex_identity)
    # this is the remaining issue: the value of math.e is displayed instead of 'e'. We have to define 'constants'
    assert str(complex_identity) == "log(" + str(e) + " ** x)"

    # then for several arguments
    complex_identity = _(Log(10 ** x, 10))
    assert complex_identity(3.5) == 3.5
    assert str(complex_identity) == 'log(10 ** x, 10)'

    complex_constant = _(Log(x ** 10, x))
    assert complex_constant(3.5) == 10
    assert str(complex_constant) == 'log(x ** 10, x)'
def test_add_class():
    """ This test demonstrates how you can convert any class to a lambda-friendly class """

    from mini_lambda import x, _

    class Temp:
        def __init__(self, den):
            self.den = den

        def divide1(self, dummy, times, dummy2=None, num=None):
            """ this could be an existing function that you want to convert """
            return times * num / self.den

        @staticmethod
        def divide2(dummy, times, num, den=None):
            """ this could be an existing function that you want to convert """
            return times * num / den

        @classmethod
        def divide3(cls, dummy, times, num, den=None):
            """ this could be an existing function that you want to convert """
            return times * num / den

    TTemp = make_lambda_friendly_class(Temp)
    complex_constant = _(TTemp(x).divide1(None, x, num=1))
    assert complex_constant(10) == 1
    assert complex_constant(-5) == 1

    complex_constant = _(TTemp.divide2(None, x, den=x, num=1))
    assert complex_constant(10) == 1
    assert complex_constant(-5) == 1

    complex_constant = _(TTemp.divide3(None, x, den=x, num=1))
    assert complex_constant(10) == 1
    assert complex_constant(-5) == 1
def test_doc_usage_expressions_2():
    """ Tests that the second set of examples in doc/usage in the expressions section works """

    from mini_lambda import x, _, L, F

    # An expression is built using python syntax with a variable
    my_first_expr = (1 + 1) * x + 1 > 0

    assert my_first_expr.evaluate(-1 / 2) is False
    assert my_first_expr.to_string() == "2 * x + 1 > 0"
    assert my_first_expr(-1 / 2).to_string() == "(2 * x + 1 > 0)(-0.5)"

    one = my_first_expr.as_function()  # explicit conversion
    two = _(my_first_expr)  # _() does the same thing
    three = L(my_first_expr)  # L() is an alias for _()
    four = F(my_first_expr)  #F too
    five, six = _(my_first_expr, x)  # both accept multiple arguments

    # you can now use the functions directly
    assert one(-1 / 2) is False
    assert two(-1 / 2) is False
    assert three(-1 / 2) is False
    assert four(-1 / 2) is False
    assert five(-1 / 2) is False
    assert six(-1 / 2) == -0.5

    # string representation
    assert str(one) == "2 * x + 1 > 0"
    assert str(six) == "x"
def test_add_new_unbound_no_name():
    """ Tests that the mechanism provided to support additional functions works with partial and lambda functions, for
    which the user is asked to provide a name """

    from mini_lambda import x, _
    from math import log

    # partial function (to fix leftmost positional arguments and/or keyword arguments)
    from functools import partial

    with pytest.raises(ValueError):
        make_lambda_friendly_method(partial(log, 15))  # we forgot the name

    Log15BaseX = make_lambda_friendly_method(partial(log, 15), name='log15baseX')
    complex_identity = _(1 / Log15BaseX(15 ** x))
    assert complex_identity(3.5) == 3.5
    assert str(complex_identity) == '1 / log15baseX(15 ** x)'

    # another partial function example
    is_superclass_of_bool = make_lambda_friendly_method(partial(issubclass, bool), name='is_superclass_of_bool')
    expr = _(is_superclass_of_bool(x))
    assert expr(int) is True
    assert expr(str) is False
    assert str(expr) == 'is_superclass_of_bool(x)'

    # lambda function
    with pytest.raises(ValueError):
        make_lambda_friendly_method(lambda x: log(x, 10))  # we forgot the name

    Log10 = make_lambda_friendly_method(lambda x: log(x, 10), name='log10')
    complex_identity = _(Log10(10 ** x))
    assert complex_identity(3.5) == 3.5
    assert str(complex_identity) == 'log10(10 ** x)'
def test_doc_index_2():
    """ Tests that the second example in the documentation main page works """

    from mini_lambda import s, x, _, Log  # this is a dynamic creation hence pycharm does not see it

    # various lambda functions
    is_lowercase = _(s.islower())
    get_prefix_upper_shebang = _(s[0:4].upper() + ' !')
    numeric_test_1 = _(-x > x**2)
    numeric_test_2 = _(((1 - 2 * x) <= -x) | (-x > x**2))
    complex_identity = _(Log(10**x, 10))

    # use the functions
    assert is_lowercase('Hello') is False
    assert get_prefix_upper_shebang('hello') == 'HELL !'
    assert numeric_test_1(0.5) is False
    assert numeric_test_2(1) is True
    assert complex_identity(10) == 10

    # string representation
    print(is_lowercase)  # s.islower()
    print(get_prefix_upper_shebang)  # s[0:4].upper() + ' !'
    print(numeric_test_1)  # -x > x ** 2
    print(numeric_test_2)  # (1 - 2 * x <= -x) | (-x > x ** 2)
    print(complex_identity)  # log(10 ** x, 10)

    assert str(is_lowercase) == 's.islower()'
    assert str(get_prefix_upper_shebang) == "s[0:4].upper() + ' !'"
    assert str(numeric_test_1) == '-x > x ** 2'
    assert str(numeric_test_2) == '(1 - 2 * x <= -x) | (-x > x ** 2)'
    assert str(complex_identity) == 'log(10 ** x, 10)'
def test_constants_named():
    """ This test demonstrates the possibility to create constants """

    from mini_lambda import x, _, C
    from math import e

    E = C(e, 'e')
    assert str(_(x + e)) == 'x + 2.718281828459045'
    assert str(_(x + E)) == 'x + e'
    assert str(_(E + E)) == 'e + e'
def test_doc_usage_other_constants():
    """ Tests that the example in doc/usage in the others/constants section works  """
    from mini_lambda import x, _, E, C
    from math import e

    assert str(_(x + e)) == 'x + 2.718281828459045'
    assert str(_(x + E)) == 'x + e'
    assert str(_(E + E)) == 'e + e'

    # define the constant
    E = C(e, 'e')

    # use it in expressions. The name appears when printed
    assert str(_(x + E)) == 'x + e'
def test_doc_usage_all_at_once():
    """ Tests that the example in doc/usage in the others/anything section works """
    from mini_lambda import _, C
    from mini_lambda.numpy import X
    import numpy as np
    import pandas as pd

    all_at_once = _(C(print)(C(pd.DataFrame)(X).transpose()))

    all_at_once(np.array([1, 2]))
    assert str(all_at_once) == 'print(DataFrame(X).transpose())'
def test_add_new_bound_keywords_static_class():
    """ Tests that the mechanism provided to support additional bound functions works, by testing that a custom class
    with a function including positional and keyword arguments can be converted."""

    from mini_lambda import x, _

    class Temp:
        def __init__(self, num):
            self.num = num

        def divide1(self, dummy, times, dummy2=None, den=None):
            """ this could be an existing function that you want to convert """
            return times * self.num / den

        @staticmethod
        def divide2(dummy, times, num, den=None):
            """ this could be an existing function that you want to convert """
            return times * num / den

        @classmethod
        def divide3(cls, dummy, times, num, den=None):
            """ this could be an existing function that you want to convert """
            return times * num / den

    # standard bound method
    Divide = make_lambda_friendly_method(Temp.divide1)
    complex_constant = _(Divide(Temp(1), None, x, den=x))
    assert complex_constant(10) == 1
    assert complex_constant(-5) == 1

    # static method
    Divide2 = make_lambda_friendly_method(Temp.divide2)
    complex_constant = _(Divide2(None, 1, x, den=x))
    assert complex_constant(10) == 1
    assert complex_constant(-5) == 1

    # class method
    Divide3 = make_lambda_friendly_method(Temp.divide3.__func__)
    complex_constant = _(Divide3(Temp, None, 1, x, den=x))
    assert complex_constant(10) == 1
    assert complex_constant(-5) == 1
def test_evaluator_iterable_all():
    """ Iterable + all operator: Checks that the all operator  raises an exception but that the All replacement function
    works """

    li = InputVar('li', list)

    with pytest.raises(FunctionDefinitionError):
        all(li)

    all_is_true = _(All(li))
    assert all_is_true([True, True, True])
    assert not all_is_true([False, True, False])
def test_generated_methods():
    """ Tests that equivalent methods generated by the package from various packages (currently, only math) work"""

    from mini_lambda import x, _, Sin
    from math import sin

    sine = _(Sin(x))

    assert sine(3.5) == sin(3.5)
    print(sine)

    assert str(sine) == "sin(x)"
Esempio n. 12
0
def test_doc_usage_other_classes():
    """ Tests that the example in doc/usage in the others/classes section works """
    from mini_lambda import _, make_lambda_friendly_class
    from mini_lambda.numpy import X
    import numpy as np
    import pandas as pd

    DDataframe = make_lambda_friendly_class(pd.DataFrame)
    expr = _(DDataframe(X).max().values[0])

    assert expr(np.array([1, 2])) == 2
    assert str(expr) == "DataFrame(X).max().values[0]"
Esempio n. 13
0
def test_doc_usage_other_functions_1():
    """ Tests that the example in doc/usage in the others/functions section (1) works """
    from mini_lambda import x, _

    # ** standard class function
    StartsWith = make_lambda_friendly_method(str.startswith)

    # now you can use `StartsWith` in your lambda expressions
    str_tester = _(StartsWith('hello', 'el', x))

    # first check that with one argument it works
    str_tester(0)  # False
    str_tester(1)  # True
    print(str_tester)  # "startswith('hello', 'el', x)"

    # ** static and class functions
    class Foo:
        @staticmethod
        def bar1(times, num, den):
            return times * num / den

        @classmethod
        def bar2(cls, times, num, den):
            return times * num / den

    FooBar1 = make_lambda_friendly_method(Foo.bar1)
    fun1 = _(FooBar1(x, den=x, num=1))
    assert fun1(5.5) == 1

    FooBar2a = make_lambda_friendly_method(
        Foo.bar2)  # the `cls` argument is `Foo` and cant be changed
    fun2a = _(FooBar2a(x, den=x, num=1))
    assert fun2a(5.5) == 1

    FooBar2b = make_lambda_friendly_method(
        Foo.bar2.__func__)  # the `cls` argument can be changed
    fun2b = _(FooBar2b(Foo, x, den=x, num=1))
    assert fun2b(5.5) == 1
Esempio n. 14
0
def test_doc_usage_other_functions_2():
    """ Tests that the example in doc/usage in the others/functions section (2) works """
    from mini_lambda import x, _

    class Foo:
        @staticmethod
        def bar1(times, num, den):
            return times * num / den

        @classmethod
        def bar2(cls, times, num, den):
            return times * num / den

    FooBar1 = make_lambda_friendly_method(Foo.bar1)
    fun1 = _(FooBar1(x, den=x, num=1))

    FooBar2a = make_lambda_friendly_method(
        Foo.bar2)  # the `cls` argument is `Foo` and cant be changed
    fun2a = _(FooBar2a(x, den=x, num=1))

    FooBar2b = make_lambda_friendly_method(
        Foo.bar2.__func__)  # the `cls` argument can be changed
    fun2b = _(FooBar2b(Foo, x, den=x, num=1))

    assert fun1(5.5) == 1
    # apparently the order may vary: in travis it is reversed
    assert (str(fun1)) in {'bar1(x, den=x, num=1)', 'bar1(x, num=1, den=x)'}

    assert fun2a(5.5) == 1
    # apparently the order may vary: in travis it is reversed
    assert (str(fun2a)) in {'bar2(x, den=x, num=1)', 'bar2(x, num=1, den=x)'}

    assert fun2b(5.5) == 1
    # apparently the order may vary: in travis it is reversed
    assert (str(fun2b)) in {
        'bar2(Foo, x, den=x, num=1)', 'bar2(Foo, x, num=1, den=x)'
    }
def test_donot_add_new_bound_with_constants():
    """ This test demonstrates that you may not need to add a bound method if you transform the object into a
    constant """

    from mini_lambda import x, _, C
    from math import e

    with pytest.raises(FunctionDefinitionError):
        'hello'.startswith('el', x)

    str_tester = _(C('hello').startswith('el', x))

    # first check that with one argument it works
    assert str_tester(0) is False
    assert str_tester(1) is True
Esempio n. 16
0
def test_doc_index_1():
    """ Tests that the first example in the documentation main page works """

    # import magic variable 's'
    from mini_lambda import s

    # write an expression and wrap it with _() to make a function
    from mini_lambda import _
    say_hello_function = _('Hello, ' + s + ' !')

    # use the function
    print(say_hello_function('world'))  # 'Hello, world !'
    assert say_hello_function('world') == 'Hello, world !'
    print(say_hello_function)
    assert str(say_hello_function) == "'Hello, ' + s + ' !'"
def test_add_new_bound_positional():
    """ Tests that the mechanism provided to support additional bound functions works, by testing that str.startswith()
    can be converted. This test checks the behaviour with positional arguments only """

    from mini_lambda import x, _

    with pytest.raises(FunctionDefinitionError):
        'hello'.startswith('el', x)

    StartsWith = make_lambda_friendly_method(str.startswith)
    str_tester = _(StartsWith('hello', 'el', x))

    # first check that with one argument it works
    assert str_tester(0) is False
    assert str_tester(1) is True
    assert str(str_tester) == "startswith('hello', 'el', x)"
def test_add_new_unbound_keywords():
    """ Tests that the mechanism provided to support additional functions works, by testing that a custom function with
    positional and keyword arguments can be converted."""

    from mini_lambda import x, _

    def divide(dummy, times, num, den=None):
        """ an existing function that you want to convert """
        return times * num / den

    Divide = make_lambda_friendly_method(divide)
    complex_constant = _(1 + Divide(None, x, den=x, num=1))

    assert complex_constant(10) == 2
    assert complex_constant(-5) == 2
    # apparently the order may vary: in travis it is reversed
    assert str(complex_constant) in {'1 + divide(None, x, den=x, num=1)', '1 + divide(None, x, num=1, den=x)'}
def test_evaluator_comparable():
    """ Comparable Object : tests that lt, le, eq, ne, gt, and ge are correctly supported """

    x = InputVar('x', float)

    is_big = _(x > 4.5)
    # is_big = is_big.as_function()

    assert is_big(5.2)
    assert not is_big(-1.1)

    is_very_special = ((3.2 <= x) & (x < 4.5) & (x != 4)) | (x == 2)
    is_very_special = is_very_special.as_function()

    assert is_very_special(2)
    assert is_very_special(3.4)
    assert not is_very_special(-1.1)
    assert not is_very_special(4)
Esempio n. 20
0
def create_base_functions():

    # Existing - already ok
    is_finite = isfinite

    # Existing + Functools Partial
    is_superclass_of_bool = partial(issubclass, bool)
    """ Checks that c is a superclass of the bool type """

    # User-defined, standard
    def is_multiple_of_3(x):
        """ Checks that x is a multiple of 3 """
        return x % 3 == 0

    # User-defined, Lambda
    is_lowercase = lambda s: s.islower()
    is_lowercase.__doc__ = "Checks that s is lowercase"

    # User-defined, mini-lambda
    from mini_lambda import _, s
    starts_with_a = _(s.lower().startswith('a'))

    # The factory of validator functions
    def is_multiple_of(ref):
        """
        Returns a validation function to validate that x is a multiple of <ref>

        :param ref: the reference to compare x to
        :return: a validation function
        """
        def is_multiple_of_ref(x):
            return x % ref == 0

        is_multiple_of_ref.__doc__ = "Checks that x is a multiple of %s" % ref
        is_multiple_of_ref.__name__ = "is_multiple_of_" + str(ref)
        return is_multiple_of_ref

    # Here we use the factory to create two validator functions
    is_multiple_of_5 = is_multiple_of(5)
    is_multiple_of_9 = is_multiple_of(9)

    return is_multiple_of, is_multiple_of_3
Esempio n. 21
0
def test_is_subset_is_superset():
    """ Checks that is_subset and is_superset work """

    a = is_subset({'+', '-'})
    a({'+'})
    with pytest.raises(ValidationFailure):
        a({'+', '-', '*'})

    b = is_superset({'+', '-'})
    b({'+', '-', '*'})
    with pytest.raises(ValidationFailure):
        b({'+'})

    Is_subset = make_lambda_friendly_method(is_subset)
    Is_superset = make_lambda_friendly_method(is_superset)
    c = _(Is_subset({'+', '-'})(x) & Is_superset({'+', '-'})(x))
    c({'+', '-'})
    with pytest.raises(ValidationFailure):
        c({'+', '-', '*'})
    with pytest.raises(ValidationFailure):
        c({'+'})
def test_evaluator_numeric():
    """ Numeric-like Object : tests that +,-,*,/,%,divmod(),pow(),**,@,//,<<,>>,-,+,abs,~ work """

    x = InputVar('x', int)

    add_one = _(x + 1)
    assert add_one(1) == 2

    remove_one = _(x - 1)
    assert remove_one(1) == 0

    times_two = _(x * 2)
    assert times_two(1) == 2

    div_two = _(x / 2)
    assert div_two(1) == 0.5

    neg = _(x % 2)
    assert neg(3) == 1

    pos = _(divmod(x, 3))
    assert pos(16) == (5, 1)

    pow_two = _(x**2)
    assert pow_two(2) == 4

    pow_two = _(pow(x, 2))
    assert pow_two(2) == 4

    # TODO matmul : @...

    floor_div_two = _(x // 2)
    assert floor_div_two(1) == 0

    lshift_ = _(256 << x)
    assert lshift_(1) == 512

    rshift_ = _(256 >> x)
    assert rshift_(1) == 128

    neg = _(-x)
    assert neg(3) == -3

    pos = _(+x)
    assert pos(-16) == -16

    abs_ = _(abs(x))
    assert abs_(-22) == 22

    inv = _(~x)
    assert inv(2) == -3
Esempio n. 23
0
def test_doc_usage_expressions_3_all_at_once():
    """ Tests that the last example in doc/usage in the expressions section works """
    from mini_lambda import s, _, Print
    say_hello = _(Print('Hello, ' + s + ' !'))
    say_hello('world')
def test_constants_methods_can_be_combined():
    a = C(isfinite)  # define a constant function (a lambda-friendly function)

    f = _(a(0) & a(0))
    assert f(None)