Beispiel #1
0
def test_injection():
    """ Tests that the function can be injected as first argument when inject_as_first_arg=True """
    def generic_handler(f, *args, **kwargs):
        print("This is generic handler called by %s" % f.__name__)
        # here you could use f.__name__ in a if statement to determine what to do
        if f.__name__ == "func1":
            print("called from func1 !")
        return args, kwargs

    # generate 2 functions
    func1 = create_function("func1(a, b)", generic_handler, inject_as_first_arg=True)
    func2 = create_function("func2(a, d)", generic_handler, inject_as_first_arg=True)

    func1(1, 2)
    func2(1, 2)
Beispiel #2
0
def test_ex_nihilo(type, decorator):
    """ First example from the documentation: tests that we can generate a function from a string """

    # (1) define the signature.
    if type == 'str':
        func_sig = "foo(b, a=0)"
        func_name = None
    else:
        parameters = [Parameter('b', kind=Parameter.POSITIONAL_OR_KEYWORD),
                      Parameter('a', kind=Parameter.POSITIONAL_OR_KEYWORD, default=0), ]
        func_sig = Signature(parameters)
        func_name = 'foo'

    # (2) define the function implementation
    def func_impl(*args, **kwargs):
        """This docstring will be used in the generated function by default"""
        print("func_impl called !")
        return args, kwargs

    # (3) create the dynamic function
    if decorator:
        gen_func = with_signature(func_sig, func_name=func_name)(func_impl)
    else:
        gen_func = create_function(func_sig, func_impl, func_name=func_name)

    # first check the source code
    ref_src = "def foo(b, a=0):\n    return _func_impl_(b=b, a=a)\n"
    print("Generated Source :\n" + gen_func.__source__)
    assert gen_func.__source__ == ref_src

    # then the behaviour
    args, kwargs = gen_func(2)
    assert args == ()
    assert kwargs == {'a': 0, 'b': 2}
Beispiel #3
0
def test_create_facades(capsys):
    """
    Simple test to create multiple functions with the same body
    This corresponds to the answer at
    https://stackoverflow.com/questions/13184281/python-dynamic-function-creation-with-custom-names/55105893#55105893
    :return:
    """

    # generic core implementation
    def generic_impl(f, *args, **kwargs):
        print("This is generic impl called by %s" % f.__name__)
        # here you could use f.__name__ in a if statement to determine what to do
        if f.__name__ == "func1":
            print("called from func1 !")
        return args, kwargs

    my_module = getmodule(generic_impl)

    # generate 3 facade functions with various signatures
    for f_name, f_params in [("func1", "b, *, a"),
                             ("func2", "*args, **kwargs"),
                             ("func3", "c, *, a, d=None")]:
        if f_name in {"func1", "func3"} and sys.version_info < (3, 0):
            # Python 2 does not support function annotations; Python 3.0-3.4 do not support variable annotations.
            pass
        else:
            # the signature to generate
            f_sig = "%s(%s)" % (f_name, f_params)

            # create the function dynamically
            f = create_function(f_sig, generic_impl, inject_as_first_arg=True)

            # assign the symbol somewhere (local context, module...)
            setattr(my_module, f_name, f)

    # grab each function and use it
    if sys.version_info >= (3, 0):
        func1 = getattr(my_module, 'func1')
        assert func1(25, a=12) == ((), dict(b=25, a=12))

    func2 = getattr(my_module, 'func2')
    assert func2(25, a=12) == ((25, ), dict(a=12))

    if sys.version_info >= (3, 0):
        func3 = getattr(my_module, 'func3')
        assert func3(25, a=12) == ((), dict(c=25, a=12, d=None))

    captured = capsys.readouterr()
    with capsys.disabled():
        print(captured.out)

    if sys.version_info >= (3, 0):
        assert captured.out == """This is generic impl called by func1
called from func1 !
This is generic impl called by func2
This is generic impl called by func3
"""
    else:
        assert captured.out == """This is generic impl called by func2
Beispiel #4
0
    def generate_function(func_sig, dummy_call):
        def func_impl(*args, **kwargs):
            """This docstring will be used in the generated function by default"""
            print("func_impl called !")
            dummy_call(*args, **kwargs)
            return args, kwargs

        return create_function(func_sig, func_impl)
Beispiel #5
0
def test_arguments(case_data):
    """ Tests that the `PARAM_DEF` regexp works correctly """
    def generic_handler(*args, **kwargs):
        return args, kwargs

    params_str, inputs, (eargs, ekwargs) = case_data.get()

    f = create_function("foo(%s)" % params_str, generic_handler)

    args, kwargs = eval("f(%s)" % inputs, globals(), locals())

    assert args == eargs
    assert kwargs == ekwargs
def test_positional_only():
    """Tests that as of today one cannot create positional-only functions"""

    params = [Parameter('a', kind=Parameter.POSITIONAL_ONLY),
              Parameter('args', kind=Parameter.VAR_POSITIONAL),
              Parameter('kwargs', kind=Parameter.VAR_KEYWORD)]

    func_signature = Signature(parameters=params)

    with pytest.raises(SyntaxError):
        dynamic_fun = create_function(func_signature, my_handler, func_name="foo")
        print(dynamic_fun.__source__)
        assert dynamic_fun(0, 1) == ((1,), {'a': 0})
Beispiel #7
0
def test_generator():
    """ Tests that we can use a generator as function_handler in `create_function`"""

    # define the handler that should be called
    def my_generator_handler(b, a=0):
        for i in range(a, b):
            yield i * i

    # create the dynamic function
    dynamic_fun = create_function("foo(a, b)", my_generator_handler)

    assert isgeneratorfunction(dynamic_fun)

    assert list(dynamic_fun(1, 4)) == [1, 4, 9]
Beispiel #8
0
def test_ex_nihilo_kw_only():
    """Same than ex nihilo but keyword only"""

    def func_impl(*args, **kwargs):
        """This docstring will be used in the generated function by default"""
        print("func_impl called !")
        return args, kwargs

    func_sig = "foo(b, *, a=0, **kwargs)"
    gen_func = create_function(func_sig, func_impl)

    ref_src = "def foo(b, *, a=0, **kwargs):\n    return _func_impl_(b=b, a=a, **kwargs)\n"
    print(gen_func.__source__)
    assert gen_func.__source__ == ref_src
Beispiel #9
0
def test_type_comments():
    """Tests that """

    func_signature = """
foo(b,      # type: int
    a = 0,  # type: float
    ):
    # type: (...) -> str
"""

    def dummy_handler(*args, **kwargs):
        return "hello"

    dynamic_fun = create_function(func_signature, dummy_handler)

    assert dynamic_fun.__annotations__ == {'a': float, 'b': int, 'return': str}
Beispiel #10
0
    def create_initiation_function(cls, gen_init):
        # (1) check which signature we want to create
        params = [Parameter('self', kind=Parameter.POSITIONAL_OR_KEYWORD)]
        for mandatory_arg_name in cls.__init_args__:
            params.append(
                Parameter(mandatory_arg_name,
                          kind=Parameter.POSITIONAL_OR_KEYWORD))
        for default_arg_name, default_arg_val in cls.__opt_init_args__.items():
            params.append(
                Parameter(default_arg_name,
                          kind=Parameter.POSITIONAL_OR_KEYWORD,
                          default=default_arg_val))
        sig = Signature(params)

        # (2) create the init function dynamically
        return create_function(sig, generic_init)
Beispiel #11
0
def test_native_coroutine():
    """ Tests that we can use a native async coroutine as function_handler in `create_function`"""

    # define the handler that should be called
    from makefun.tests._test_py35 import make_native_coroutine_handler
    my_native_coroutine_handler = make_native_coroutine_handler()

    # create the dynamic function
    dynamic_fun = create_function("foo(sleep_time=2)",
                                  my_native_coroutine_handler)

    # check that this is a coroutine for inspect and for asyncio
    assert iscoroutinefunction(dynamic_fun)
    from asyncio import iscoroutinefunction as is_native_co
    assert is_native_co(dynamic_fun)

    # verify that the new function is a native coroutine and behaves correctly
    from asyncio import get_event_loop
    out = get_event_loop().run_until_complete(dynamic_fun(0.1))
    assert out == 0.1
Beispiel #12
0
    def mark(self) -> Callable[..., Any]:
        """generate mark method"""
        assert self.fixture_function
        fixture_sig: Signature = signature(self.fixture_function)

        def _mark(**kwargs) -> TestFuncT:
            _validate_input(mark_sig, **kwargs)
            return getattr(pytest.mark, self.name)(**kwargs)

        mark_sig = signature(_mark)
        mark_parameters = tuple(p for p in fixture_sig.parameters.values()
                                if p.default is not _empty)
        mark_sig = mark_sig.replace(parameters=mark_parameters)
        mark = create_function(
            mark_sig,
            _mark,
            func_name=f"{self.name}_mark",
            module_name=self.fixture_function.__module__,
        )
        return mark
Beispiel #13
0
    def fixture(cls, *args: Any,
                **kwargs: Any) -> Union[_FixtureFunctionT, _FixtureFunctionB]:
        # todo, generics?
        if len(args) == 1 and not kwargs and callable(args[0]):
            # if the function is called as a decorator
            return cls(args[0]).pytest_fixture()
        elif kwargs.pop("autoparam", False):
            # if the function is called as a autoparam

            calling_frame = inspect.stack()[1]
            assert calling_frame, "no frames?"
            calling_module = inspect.getmodule(calling_frame[0])
            assert calling_module, "no module?"

            try:
                # this is the most hack i have ever hacked, this is terrible but should work for what we need
                # example:
                #   calling_frame.code_context ==  ['c = fixture(test_1=1, test_2=2, autoparam=True)\n']
                calling_context = calling_frame.code_context
                if calling_context:
                    fixture_name = calling_frame.code_context[0].split("=")
                else:
                    fixture_name = "gen-fixture"
            except Exception:
                fixture_name = "gen-fixture"

            @_make_class_agnostic
            def _func(request: SubRequest) -> Any:
                return request.param

            # todo we need to skip the current class
            func = create_function(
                signature(_func),
                _func,
                func_name=fixture_name,
                module_name=calling_module.__name__,
            )

            return cls(func).pytest_fixture(*args, **kwargs)
        else:
            return cls(*args, **kwargs).wrapper
Beispiel #14
0
    def build_handler(self, route_parameters):
        """
        This special method is used when using the Flask style routes, it using meta-programming to
        create a controller for the method then links the action, them makes them callable ,the send control
        back to the normal execution path
        :param route_parameters:
        :return:
        """
        Controller = route_parameters["controller"]
        action = route_parameters["action"]
        if Controller == "SegoBaseController":
            handler_id = self.configuration_manager.get("dynamic_routes", action)
            handler = ctypes.cast(handler_id, ctypes.py_object).value
        else:
            _class = self.dynamic_import(Controller)
            handler = getattr(_class(), action)
        middleware_manager = self.middleware_manager

        def handler_implementation(*args, **kwargs):
            """
            Handler wrapper
            """
            if route_parameters is not None:
                middleware_manager.process_middleware(stage=Middleware.PREPROCESS, \
                                                      route=route_parameters, \
                                                      request=request, \
                                                      response=None)
            response = handler(**kwargs)
            if route_parameters is not None:
                middleware_manager.process_middleware(stage=Middleware.POSTPROCESS, \
                                                      route=route_parameters, \
                                                      request=request, \
                                                      response=response)

            return response

        method_signature = str(handler.__name__) + str(signature(handler))
        wrapped_handler = create_function(method_signature, handler_implementation, func_name=str(handler.__name__))

        return wrapped_handler
Beispiel #15
0
def test_generator_based_coroutine():
    """ Tests that we can use a generator coroutine as function_handler in `create_function`"""

    # define the handler that should be called
    def my_gencoroutine_handler(first_msg):
        second_msg = (yield first_msg)
        yield second_msg

    # create the dynamic function
    dynamic_fun = create_function("foo(first_msg='hello')",
                                  my_gencoroutine_handler)

    # a legacy (generator-based) coroutine is not an asyncio coroutine..
    assert not iscoroutinefunction(dynamic_fun)
    assert isgeneratorfunction(dynamic_fun)

    cor = dynamic_fun('hi')
    first_result = next(cor)
    assert first_result == 'hi'
    second_result = cor.send('chaps')
    assert second_result == 'chaps'
    with pytest.raises(StopIteration):
        cor.send('ola')
Beispiel #16
0
def test_basic(params_type_hints, with_self_ref):
    """
    Tests that we can create a simple dynamic function from a signature string, redirected to a generic handler.
    """

    if params_type_hints == 1:
        from typing import Any
        func_signature = "foo(b,      # type: int\n" \
                         "    a = 0,  # type: float\n" \
                         "    ):\n    # type: (...) -> Any"
    elif params_type_hints == 2:
        from typing import Any
        func_signature = "foo(b: int, a: float=0) -> Any"
    else:
        func_signature = "foo(b, a=0)"

    # this handler will grab the inputs and return them
    if with_self_ref:

        def identity_handler(facade, *args, **kwargs):
            """test doc"""
            return facade, args, kwargs
    else:

        def identity_handler(*args, **kwargs):
            """test doc"""
            return args, kwargs

    # create the dynamic function
    dynamic_fun = create_function(func_signature,
                                  identity_handler,
                                  inject_as_first_arg=with_self_ref)

    # a few asserts on the signature
    assert dynamic_fun.__name__ == 'foo'
    assert dynamic_fun.__doc__ == 'test doc'
    assert dynamic_fun.__module__ == test_basic.__module__
    if params_type_hints == 1:
        # unfortunately
        assert dynamic_fun.__annotations__ == {}
    elif params_type_hints == 2:
        assert dynamic_fun.__annotations__ == {
            'a': float,
            'b': int,
            'return': Any
        }
    else:
        assert dynamic_fun.__annotations__ == {}
    assert dynamic_fun.__defaults__ == (0, )
    assert dynamic_fun.__kwdefaults__ is None

    if params_type_hints != 1:
        func_signature = func_signature + ":"
    if with_self_ref:
        src = "def " + func_signature + '\n    return _func_impl_(foo, b=b, a=a)\n'
    else:
        src = "def " + func_signature + '\n    return _func_impl_(b=b, a=a)\n'

    dct = {'__source__': src, '__func_impl__': identity_handler}
    if not params_type_hints_allowed:
        dct['__annotations__'] = dict()
        dct['__kwdefaults__'] = None
    assert vars(dynamic_fun) == dct

    # try to call it !
    if with_self_ref:
        f, args, kwargs = dynamic_fun(2)
        assert f is dynamic_fun
    else:
        args, kwargs = dynamic_fun(2)

    assert args == ()
    assert kwargs == {'a': 0, 'b': 2}
Beispiel #17
0
 def patch(self):
     ex = create_function(self.ex_function, execute, doc=self.doc)
     self.execute = types.MethodType(ex, self)
     print('%s.%s' % (os.path.splitext(os.path.basename(
         self.input_path))[0], self.ex_function))
     print(self.execute.__doc__)
Beispiel #18
0
    def call(self) -> Callable[..., Any]:
        """generate fixture callable"""
        assert self.fixture_function

        fixture_sig: Signature = signature(self.fixture_function)
        fixture_self_index = _param_index(fixture_sig, "self")
        fixture_request_index = _param_index(fixture_sig, "request")

        call_sig: Signature
        call_self_index: Optional[int]
        call_request_index: Optional[int]

        fixture_function = self.fixture_function

        def _the_thing(*args: Any, **kwargs: Any) -> Any:
            # raise error if we have a signature mismatch
            _validate_input(call_sig, *args, **kwargs)

            # coalese args and kwargs for parameter indexing
            args_n_kwargs = [*args, *kwargs.values()]

            # pluck the request out
            assert call_request_index is not None
            request = args_n_kwargs[call_request_index]
            mark_kwargs = getattr(request.node.get_closest_marker(self.name),
                                  "kwargs", {})

            if call_self_index is not None:
                kwargs = {
                    "self": args[call_self_index],
                    **kwargs,
                    **mark_kwargs
                }
            else:
                kwargs = {**kwargs, **mark_kwargs}

            # print(signature(fixture_function), args, kwargs, mark_kwargs)
            return fixture_function(**kwargs)

        # setup call func
        if fixture_self_index is None:
            if fixture_request_index is None:
                # no self, needs request
                def _call(request: SubRequest, *args: Any,
                          **kwargs: Any) -> Any:
                    # print("no self, needs request", args, kwargs)
                    return _the_thing(request, *args, **kwargs)

            else:
                # no self, has request
                def _call(*args: Any, **kwargs: Any) -> Any:
                    # print("no self, has request", args, kwargs)
                    return _the_thing(*args, **kwargs)

        else:
            # has self
            if fixture_request_index is None:
                # has self, needs request
                def _call(self, request: SubRequest, *args: Any,
                          **kwargs: Any) -> Any:
                    # print("has self, needs request", args, kwargs)
                    return _the_thing(self, request, *args, **kwargs)

            else:
                # has self, has request
                def _call(self, *args: Any, **kwargs: Any) -> Any:
                    # print("has self, has request", args, kwargs)
                    return _the_thing(self, *args, **kwargs)

        # extract as variable for _validate_input closures above
        call = wraps(self.fixture_function)(_call)

        call_sig = _insert_request_param(signature(call))
        call_self_index = _param_index(call_sig, "self")
        call_request_index = _param_index(call_sig, "request")

        call = create_function(call_sig, _call, func_name=self.name)
        call.mark = self.mark()

        return call