from pythran.tests import TestEnv
from pythran.syntax import PythranSyntaxError

class TestNamedParameters(TestEnv):

    def test_call_with_named_argument(self):
        self.run_test("""
def foo(a):
    return a
def call_with_named_argument(n):
    return foo(a=n)""", 1, call_with_named_argument=[int])

    def test_call_with_named_arguments(self):
        self.run_test("""
def foo(a,b):
    return a / b
def call_with_named_arguments(n):
    return foo(b=n, a=2*n)""", 1, call_with_named_arguments=[int])

    def test_call_with_args_and_named_argument(self):
        self.run_test("""
def foo(a, b):
    return a - b
def call_with_args_and_named_argument(m,n):
    return foo(m, b=n)""", 1, 2, call_with_args_and_named_argument=[int, int])

    def test_call_with_args_and_named_arguments(self):
        self.run_test("""
def foo(a,b,c):
    return c + a / b
def call_with_args_and_named_arguments(n, m):
    return foo(m, c=2*n, b=n)""", 1, 2, call_with_args_and_named_arguments=[int, int])

    def test_call_with_default_and_named_argument(self):
        self.run_test("""
def foo(a, b=1):
    return a - b
def call_with_default_and_named_argument(m,n):
    return foo(a=m)""", 1, 2, call_with_default_and_named_argument=[int, int])

    def test_call_with_default_and_named_arguments(self):
        self.run_test("""
def foo(a,b,c=1):
    return c + a / b
def call_with_default_and_named_arguments(n, m):
    return foo(m, b=n)""", 1, 2, call_with_default_and_named_arguments=[int, int])

    def test_intrinsic_named_argument(self):
        """ Check named arguments with attributes as value. """
        self.run_test("""
            def intrinsic_named_argument(n):
                import numpy
                return numpy.ones(n, dtype=numpy.uint8).nbytes""",
                      4, intrinsic_named_argument=[int])

    def test_intrinsic_named_argument_without_default(self):
        self.run_test("""
            def intrinsic_named_argument_without_default(n):
                import numpy as np
                return np.expand_dims(np.ones(n), axis=0)""",
                      4, intrinsic_named_argument_without_default=[int])

    def test_nested_function_with_named_arguments(self):
        self.run_test('''
def nested_function_with_named_arguments(a):
    b = a * 2
    def foo(c):
        return b + c
    return foo(c=a)''',
        4, nested_function_with_named_arguments=[int])

    def test_nested_function_with_several_named_arguments(self):
        self.run_test('''
def nested_function_with_several_named_arguments(a):
    b = a * 2
    def foo(c, e):
        return b + c + e
    return foo(e = 4, c=a)''',
        4, nested_function_with_several_named_arguments=[int])

    def test_aliasing_functions_with_named_arguments(self):
        self.run_test('''
            def aliasing_functions_with_named_arguments(n):
                import numpy
                if n > 10:
                    my = numpy.ones
                else:
                    my = numpy.zeros
                return my(n, dtype=numpy.uint8).nbytes''',
                      4, aliasing_functions_with_named_arguments=[int])

    def test_aliasing_functions_with_different_structural_types(self):
        with self.assertRaises(PythranSyntaxError):
            self.run_test('''
def aliasing_functions_with_different_structural_types(n):
    import numpy
    if n > 10:
        my = sum
    else:
        my = numpy.zeros
    return my(n, dtype=numpy.uint8).nbytes''',
            4, aliasing_functions_with_different_structural_types=[int])

    def test_default_argument_all_filled(self):
        code = '''
            def default_argument_all_filled(x):
                return test2(x,2)

            def test2(a, b=3):
                return a, b'''
        self.run_test(code, 10, default_argument_all_filled=[int])


from pythran.tests import TestEnv
from pythran.syntax import PythranSyntaxError

class TestNamedParameters(TestEnv):

    def test_call_with_named_argument(self):
        self.run_test("""
def foo(a):
    return a
def call_with_named_argument(n):
    return foo(a=n)""", 1, call_with_named_argument=[int])

    def test_call_with_named_arguments(self):
        self.run_test("""
def foo(a,b):
    return a / b
def call_with_named_arguments(n):
    return foo(b=n, a=2*n)""", 1, call_with_named_arguments=[int])

    def test_call_with_args_and_named_argument(self):
        self.run_test("""
def foo(a, b):
    return a - b
def call_with_args_and_named_argument(m,n):
    return foo(m, b=n)""", 1, 2, call_with_args_and_named_argument=[int, int])

    def test_call_with_args_and_named_arguments(self):
        self.run_test("""
def foo(a,b,c):
    return c + a / b
def call_with_args_and_named_arguments(n, m):
    return foo(m, c=2*n, b=n)""", 1, 2, call_with_args_and_named_arguments=[int, int])

    def test_call_with_default_and_named_argument(self):
        self.run_test("""
def foo(a, b=1):
    return a - b
def call_with_default_and_named_argument(m,n):
    return foo(a=m)""", 1, 2, call_with_default_and_named_argument=[int, int])

    def test_call_with_default_and_named_arguments(self):
        self.run_test("""
def foo(a,b,c=1):
    return c + a / b
def call_with_default_and_named_arguments(n, m):
    return foo(m, b=n)""", 1, 2, call_with_default_and_named_arguments=[int, int])

    def test_intrinsic_named_argument(self):
        """ Check named arguments with attributes as value. """
        self.run_test("""
            def intrinsic_named_argument(n):
                import numpy
                return numpy.ones(n, dtype=numpy.uint8).nbytes""",
                      4, intrinsic_named_argument=[int])

    def test_intrinsic_named_argument_without_default(self):
        self.run_test("""
            def intrinsic_named_argument_without_default(n):
                import numpy as np
                return np.expand_dims(np.ones(n), axis=0)""",
                      4, intrinsic_named_argument_without_default=[int])

    def test_nested_function_with_named_arguments(self):
        self.run_test('''
def nested_function_with_named_arguments(a):
    b = a * 2
    def foo(c):
        return b + c
    return foo(c=a)''',
        4, nested_function_with_named_arguments=[int])

    def test_nested_function_with_several_named_arguments(self):
        self.run_test('''
def nested_function_with_several_named_arguments(a):
    b = a * 2
    def foo(c, e):
        return b + c + e
    return foo(e = 4, c=a)''',
        4, nested_function_with_several_named_arguments=[int])

    def test_aliasing_functions_with_named_arguments(self):
        self.run_test('''
            def aliasing_functions_with_named_arguments(n):
                import numpy
                if n > 10:
                    my = numpy.ones
                else:
                    my = numpy.zeros
                return my(n, dtype=numpy.uint8).nbytes''',
                      4, aliasing_functions_with_named_arguments=[int])

    def test_aliasing_functions_with_different_structural_types(self):
        with self.assertRaises(PythranSyntaxError):
            self.run_test('''
def aliasing_functions_with_different_structural_types(n):
    import numpy
    if n > 10:
        my = sum
    else:
        my = numpy.zeros
    return my(n, dtype=numpy.uint8).nbytes''',
            4, aliasing_functions_with_different_structural_types=[int])

    def test_default_argument_all_filled(self):
        code = '''
            def default_argument_all_filled(x):
                return test2(x,2)

            def test2(a, b=3):
                return a, b'''
        self.run_test(code, 10, default_argument_all_filled=[int])


def foo(a):     return a def call_with_named_argument(n):     return foo(a=n) def foo(a,b):     return a / b def call_with_named_arguments(n):     return foo(b=n, a=2*n) def foo(a, b):     return a - b def call_with_args_and_named_argument(m,n):     return foo(m, b=n) def foo(a,b,c):     return c + a / b def call_with_args_and_named_arguments(n, m):     return foo(m, c=2*n, b=n) def foo(a, b=1):     return a - b def call_with_default_and_named_argument(m,n):     return foo(a=m) def foo(a,b,c=1):     return c + a / b def call_with_default_and_named_arguments(n, m):     return foo(m, b=n) Check named arguments with attributes as value. def intrinsic_named_argument(n):                 import numpy                 return numpy.ones(n, dtype=numpy.uint8).nbytes def intrinsic_named_argument_without_default(n):                 import numpy as np                 return np.expand_dims(np.ones(n), axis=0) def nested_function_with_named_arguments(a):     b = a * 2     def foo(c):         return b + c     return foo(c=a) def nested_function_with_several_named_arguments(a):     b = a * 2     def foo(c, e):         return b + c + e     return foo(e = 4, c=a) def aliasing_functions_with_named_arguments(n):                 import numpy                 if n > 10:                     my = numpy.ones                 else:                     my = numpy.zeros                 return my(n, dtype=numpy.uint8).nbytes def aliasing_functions_with_different_structural_types(n):     import numpy     if n > 10:         my = sum     else:         my = numpy.zeros     return my(n, dtype=numpy.uint8).nbytes def default_argument_all_filled(x):                 return test2(x,2)              def test2(a, b=3):                 return a, b