示例#1
0
    def test_registering_helper_works(self):
        from types import GeneratorType

        class CustomResponse(CometResponse): pass

        def process_request(inst):
            self.assertTrue(inst.is_sijax_request)
            response = inst.process_request()
            self.assertTrue(isinstance(response, GeneratorType))
            # something needs to "move the generator forward" if we want
            # to proceed in the call chain
            for string in response:
                pass

        call_history = []

        def invalid_call(obj_response, callback):
            self.fail("Invalid call handler triggered!")

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '[]'})

        def my_callback(obj_response):
            self.assertTrue(isinstance(obj_response, CometResponse))
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("my_callback")
            call_history.append(type(obj_response).__name__)

        register_comet_callback(inst, "my_func", my_callback)
        process_request(inst)

        # let's see if we can override the default args and the response
        # class during callback registration
        params_custom = {cls.PARAM_RESPONSE_CLASS: CustomResponse}
        register_comet_callback(inst, "my_func", my_callback, **params_custom)
        process_request(inst)

        # Try mass registering now
        class SijaxHandler(object):
            @staticmethod
            def callback_one(obj_response, arg1):
                self.assertTrue(isinstance(obj_response, CustomResponse))
                call_history.append("callback_one")
                call_history.append(type(obj_response).__name__)
                call_history.append(arg1)

        register_comet_object(inst, SijaxHandler, **params_custom)
        inst.set_data({cls.PARAM_REQUEST: "callback_one", cls.PARAM_ARGS: '[45]'})
        process_request(inst)

        call_history_expected = [
            "my_callback", "CometResponse",
            "my_callback", "CustomResponse",
            "callback_one", "CustomResponse", 45
        ]
        self.assertEqual(call_history_expected, call_history)
    def test_executing_regular_callbacks_works(self):
        from types import StringType

        calls_history = []
        call_args_history = []

        def event_before(obj_response):
            self.assertTrue(isinstance(obj_response, BaseResponse))
            calls_history.append("before")

            obj_response.script("javascript here..")

        def event_after(obj_response):
            self.assertTrue(isinstance(obj_response, BaseResponse))
            calls_history.append("after")

            obj_response.css("#element", "backgroundColor", "red")

        def callback_main(obj_response, arg1, arg2):
            self.assertTrue(isinstance(obj_response, BaseResponse))

            calls_history.append("main")
            call_args_history.append(arg1)
            call_args_history.append(arg2)

            obj_response.alert("alert from main")

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_BEFORE_PROCESSING, event_before)
        inst.register_event(cls.EVENT_AFTER_PROCESSING, event_after)

        call_args = ["arg1", 15]
        response = inst.execute_callback(call_args, callback=callback_main)

        self.assertEqual(["before", "main", "after"], calls_history)
        self.assertEqual(call_args, call_args_history)

        # the response should be a string for regular functions
        # streaming functions return generators instead..
        self.assertTrue(isinstance(response, StringType))

        from sijax.helper import json
        try:
            commands = json.loads(response)
        except:
            self.fail("Invalid JSON response!")
        else:
            self.assertTrue(isinstance(commands, list))

            commands_history = []
            for cmd_params in commands:
                self.assertTrue(isinstance(cmd_params, dict))
                self.assertTrue("type" in cmd_params, "Unknown command type!")
                commands_history.append(cmd_params["type"])

        self.assertEqual(["script", "alert", "css"], commands_history)
示例#3
0
    def test_executing_regular_callbacks_works(self):

        calls_history = []
        call_args_history = []

        def event_before(obj_response):
            self.assertTrue(isinstance(obj_response, BaseResponse))
            calls_history.append("before")

            obj_response.script("javascript here..")

        def event_after(obj_response):
            self.assertTrue(isinstance(obj_response, BaseResponse))
            calls_history.append("after")

            obj_response.css("#element", "backgroundColor", "red")

        def callback_main(obj_response, arg1, arg2):
            self.assertTrue(isinstance(obj_response, BaseResponse))

            calls_history.append("main")
            call_args_history.append(arg1)
            call_args_history.append(arg2)

            obj_response.alert("alert from main")

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_BEFORE_PROCESSING, event_before)
        inst.register_event(cls.EVENT_AFTER_PROCESSING, event_after)

        call_args = ["arg1", 15]
        response = inst.execute_callback(call_args, callback=callback_main)

        self.assertEqual(["before", "main", "after"], calls_history)
        self.assertEqual(call_args, call_args_history)

        # the response should be a string for regular functions
        # streaming functions return generators instead..
        self.assertTrue(isinstance(response, string_types))

        from sijax.helper import json
        try:
            commands = json.loads(response)
        except:
            self.fail("Invalid JSON response!")
        else:
            self.assertTrue(isinstance(commands, list))

            commands_history = []
            for cmd_params in commands:
                self.assertTrue(isinstance(cmd_params, dict))
                self.assertTrue("type" in cmd_params, "Unknown command type!")
                commands_history.append(cmd_params["type"])

        self.assertEqual(["script", "alert", "css"], commands_history)
示例#4
0
    def test_registering_custom_events_works(self):
        inst = Sijax()

        event_name = "my_event"
        event_callback = lambda obj_response: obj_response.alert("Event")

        self.assertFalse(inst.has_event(event_name), "Custom event registered")

        inst.register_event(event_name, event_callback)

        self.assertTrue(inst.has_event(event_name), "Failed to register event")
示例#5
0
    def test_registering_custom_events_works(self):
        inst = Sijax()

        event_name = "my_event"
        event_callback = lambda obj_response: obj_response.alert("Event")

        self.assertFalse(inst.has_event(event_name), "Custom event registered")

        inst.register_event(event_name, event_callback)

        self.assertTrue(inst.has_event(event_name), "Failed to register event")
示例#6
0
    def test_registering_helper_works(self):
        from types import GeneratorType

        from sijax.plugin.upload import func_name_by_form_id

        class CustomResponse(UploadResponse):
            pass

        def process_request(inst):
            self.assertTrue(inst.is_sijax_request)
            response = inst.process_request()
            self.assertTrue(isinstance(response, GeneratorType))
            # something needs to "move the generator forward" if we want
            # to proceed in the call chain
            for string in response:
                pass

        call_history = []

        def invalid_call(obj_response, callback):
            self.fail("Invalid call handler triggered!")

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)

        def my_callback(obj_response, files, form_values):
            self.assertTrue(isinstance(obj_response, UploadResponse))
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("my_callback")
            call_history.append(obj_response.form_id)
            call_history.append(type(obj_response).__name__)
            call_history.append(files["file"])  # reaching into the file object

            # ensure that from all the post data, only the valid (non-system)
            # stuff made it through
            self.assertEqual({
                "form_key": "value",
                "form_key2": 15
            }, form_values)

        def my_callback2(obj_response, custom_arg1, custom_arg2, form_values):
            self.assertTrue(isinstance(obj_response, UploadResponse))
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("custom_callback")
            call_history.append(obj_response.form_id)
            call_history.append(type(obj_response).__name__)
            call_history.append(custom_arg1)
            call_history.append(custom_arg2)

            # ensure that from all the post data, only the valid (non-system)
            # stuff made it through
            self.assertEqual({
                "form_key": "value",
                "form_key2": 15
            }, form_values)

        form_id = "my_form"
        # the developer usually doesn't need to know the public system assigned
        # name of the callback function.. we'll need it though to fake the request
        public_callback_name = func_name_by_form_id(form_id)
        request_args_json = '["%s"]' % form_id
        post = {}
        post[cls.PARAM_REQUEST] = public_callback_name
        post[cls.PARAM_ARGS] = request_args_json
        post["form_key"] = "value"
        post["form_key2"] = 15
        inst.set_data(post)

        files = {"file": "object", "passed": "here"}
        register_upload_callback(inst,
                                 form_id,
                                 my_callback,
                                 args_extra=(files, ))
        process_request(inst)

        # let's see if we can override the default args and the response
        # class during callback registration
        params_custom = {cls.PARAM_RESPONSE_CLASS: CustomResponse}
        register_upload_callback(inst,
                                 form_id,
                                 my_callback2,
                                 args_extra=("custom1", "custom2"),
                                 **params_custom)
        process_request(inst)

        call_history_expected = [
            "my_callback", form_id, "UploadResponse", "object",
            "custom_callback", form_id, "CustomResponse", "custom1", "custom2"
        ]
        self.assertEqual(call_history_expected, call_history)
示例#7
0
    def test_registering_helper_works(self):
        from types import GeneratorType

        class CustomResponse(CometResponse):
            pass

        def process_request(inst):
            self.assertTrue(inst.is_sijax_request)
            response = inst.process_request()
            self.assertTrue(isinstance(response, GeneratorType))
            # something needs to "move the generator forward" if we want
            # to proceed in the call chain
            for string in response:
                pass

        call_history = []

        def invalid_call(obj_response, callback):
            self.fail("Invalid call handler triggered!")

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '[]'})

        def my_callback(obj_response):
            self.assertTrue(isinstance(obj_response, CometResponse))
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("my_callback")
            call_history.append(type(obj_response).__name__)

        register_comet_callback(inst, "my_func", my_callback)
        process_request(inst)

        # let's see if we can override the default args and the response
        # class during callback registration
        params_custom = {cls.PARAM_RESPONSE_CLASS: CustomResponse}
        register_comet_callback(inst, "my_func", my_callback, **params_custom)
        process_request(inst)

        # Try mass registering now
        class SijaxHandler(object):
            @staticmethod
            def callback_one(obj_response, arg1):
                self.assertTrue(isinstance(obj_response, CustomResponse))
                call_history.append("callback_one")
                call_history.append(type(obj_response).__name__)
                call_history.append(arg1)

        register_comet_object(inst, SijaxHandler, **params_custom)
        inst.set_data({
            cls.PARAM_REQUEST: "callback_one",
            cls.PARAM_ARGS: '[45]'
        })
        process_request(inst)

        call_history_expected = [
            "my_callback", "CometResponse", "my_callback", "CustomResponse",
            "callback_one", "CustomResponse", 45
        ]
        self.assertEqual(call_history_expected, call_history)
示例#8
0
    def test_invalid_call_event_works(self):
        from types import GeneratorType, FunctionType
        call_history = []

        def my_callback(obj_response, arg1, arg2):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("call ok")

        def my_callback_raising_TypeError(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            raise TypeError('this should be re-raised by Sijax')

        def my_callback_raising_TypeError2(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))

            def inner():
                raise TypeError('this should be re-raised by Sijax')

            inner()

        def invalid_call(obj_response, failed_callback):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            self.assertTrue(isinstance(failed_callback, FunctionType))
            call_history.append("invalid %s" % failed_callback.__name__)

        def exhaust_generator(gen):
            self.assertTrue(isinstance(gen, GeneratorType))
            try:
                while True:
                    next(gen)
            except StopIteration:
                pass

        inst = Sijax()
        cls = inst.__class__
        options = {cls.PARAM_RESPONSE_CLASS: StreamingIframeResponse}

        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)
        inst.register_callback("my_func", my_callback, **options)

        inst.set_data({
            cls.PARAM_REQUEST: "my_func",
            cls.PARAM_ARGS: '["arg1", 12]'
        })
        self.assertTrue(inst.is_sijax_request)
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual(["arg1", 12], inst.request_args)
        response = inst.process_request()
        exhaust_generator(response)

        # we should have succeeded until now..
        # let's try to make the call invalid and observe the failure
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '[]'})
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual([], inst.request_args)
        response = inst.process_request()
        exhaust_generator(response)

        # let's ensure that raising a TypeError from within a handler,
        # is not mistaken for an invalid call (EVENT_INVALID_CALL),
        # and re-raises the exception
        inst.register_callback("my_func", my_callback_raising_TypeError,
                               **options)
        try:
            response = inst.process_request()
            exhaust_generator(response)
        except TypeError:
            call_history.append('TypeError')

        inst.register_callback("my_func", my_callback_raising_TypeError2,
                               **options)
        try:
            response = inst.process_request()
            exhaust_generator(response)
        except TypeError:
            call_history.append('TypeError2')

        expected = [
            'call ok', 'invalid my_callback', 'TypeError', 'TypeError2'
        ]
        self.assertEqual(expected, call_history)
示例#9
0
    def test_streaming_functions_return_generators(self):
        # Every function registered as streaming should return a generator
        # when it's executed, even if the actual function decides to act
        # as a normal function, and not generate anything
        # This is very important, because it allows mixing streaming with
        # regular functions when the StreamingIframeResponse is used

        from types import GeneratorType

        call_history = []

        def callback_before(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("before")
            obj_response.html("#div", "before html")

        def callback_after(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("after")
            # intentionally not pushing new commands
            # which means it should not be yielding at implicitly

        def callback_yielding(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("yielding")
            obj_response.alert("test")
            yield obj_response
            obj_response.css("#div", "color", "red")

        def callback_normal(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("normal")
            obj_response.script(".. javascript here..")

        def assert_generator_entries_length(generator, length):
            items = []
            try:
                while True:
                    items.append(next(generator))
            except StopIteration:
                pass

            self.assertEqual(length, len(items))

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_BEFORE_PROCESSING, callback_before)
        inst.register_event(cls.EVENT_AFTER_PROCESSING, callback_after)
        options = {cls.PARAM_RESPONSE_CLASS: StreamingIframeResponse}

        response = inst.execute_callback([],
                                         callback=callback_yielding,
                                         **options)
        self.assertTrue(isinstance(response, GeneratorType))
        # We should have the following yields:
        # 1. Implicit yield after callback_before
        # 2. Explicit yield from callback_yielding
        # 3. Implicit yield when calback_yielding ends
        # Note that callback_after should not yield implicitly,
        # because it has not pushed new commands, so it makes no sense!
        assert_generator_entries_length(response, 3)

        def callback_before_new(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("before_new")

            # this doesn't really push data, as we haven't added commands yet
            # flushing would be wasteful
            for i in range(10):
                yield obj_response

            for i in range(2):
                obj_response.alert("hey")
                yield obj_response

        inst.register_event(cls.EVENT_BEFORE_PROCESSING, callback_before_new)
        inst.register_event(cls.EVENT_AFTER_PROCESSING,
                            lambda r: r.alert("this yields"))
        response = inst.execute_callback([],
                                         callback=callback_normal,
                                         **options)
        self.assertTrue(isinstance(response, GeneratorType))
        # We're expecting the following yields:
        # 1. Explicit yield from callback_before_new
        # 2. Explicit yield from callback_before_new
        # 3. Implicit yield after callback_normal
        # 4. Implicit yield after EVENT_AFTER_PROCESSING callback
        assert_generator_entries_length(response, 4)

        call_history_expected = [
            "before", "yielding", "after", "before_new", "normal"
        ]
        self.assertEqual(call_history_expected, call_history)
示例#10
0
    def test_process_request_calls_invalid_call_event_for_invalid_calls(self):
        from types import FunctionType
        from sijax.helper import json

        # An invalid call is a call to a function that appears valid.
        # The function is registered (known), but calling fails, because
        # the function expects another number of arguments

        call_history = []

        def my_callback(obj_response, arg1, arg2):
            call_history.append("call ok")

        def my_callback_with_defaults(obj_response, arg1=138, arg2=15):
            call_history.append("defaults ok")

        def my_callback_raising_TypeError(obj_response):
            raise TypeError('this should be re-raised by Sijax')

        def my_callback_raising_TypeError2(obj_response):
            def inner():
                raise TypeError('this should be re-raised by Sijax')

            inner()

        def invalid_call(obj_response, failed_callback):
            self.assertTrue(isinstance(failed_callback, FunctionType))
            call_history.append("invalid %s" % failed_callback.__name__)

        inst = Sijax()
        cls = inst.__class__
        inst.register_callback("my_func", my_callback)

        # Make a valid call that would succeed
        inst.set_data({
            cls.PARAM_REQUEST: "my_func",
            cls.PARAM_ARGS: '["arg1", 12]'
        })
        self.assertTrue(inst.is_sijax_request)
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual(["arg1", 12], inst.request_args)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))

        # Make a call with a wrong number of arguments, and a default
        # event handler for invalid calls
        inst.set_data({
            cls.PARAM_REQUEST: "my_func",
            cls.PARAM_ARGS: '["arg1"]'
        })
        self.assertTrue(inst.is_sijax_request)
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual(["arg1"], inst.request_args)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))
        try:
            commands = json.loads(response)
        except:
            self.fail("Invalid JSON generated!")
        else:
            self.assertTrue(isinstance(commands, list))
            # we expect the default "Action performed in a wrong way" alert
            self.assertEqual(1, len(commands))
            command_data = commands.pop(0)
            self.assertTrue("type" in command_data)
            self.assertEqual("alert", command_data["type"])

        # Make an invalid call with a custom event handler function
        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '[]'})
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual([], inst.request_args)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))

        # let's see if calling works with default arguments
        inst.register_callback("my_func", my_callback_with_defaults)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))

        # let's ensure that raising a TypeError from within a handler,
        # is not mistaken for an invalid call (EVENT_INVALID_CALL),
        # and re-raises the exception
        inst.register_callback("my_func", my_callback_raising_TypeError)
        try:
            inst.process_request()
        except TypeError:
            call_history.append('TypeError')

        inst.register_callback("my_func", my_callback_raising_TypeError2)
        try:
            inst.process_request()
        except TypeError:
            call_history.append('TypeError2')

        expected = [
            'call ok', 'invalid my_callback', 'defaults ok', 'TypeError',
            'TypeError2'
        ]
        self.assertEqual(expected, call_history)
示例#11
0
    def test_registering_helper_works(self):
        from types import GeneratorType

        from sijax.plugin.upload import func_name_by_form_id

        class CustomResponse(UploadResponse): pass

        def process_request(inst):
            self.assertTrue(inst.is_sijax_request)
            response = inst.process_request()
            self.assertTrue(isinstance(response, GeneratorType))
            # something needs to "move the generator forward" if we want
            # to proceed in the call chain
            for string in response:
                pass

        call_history = []

        def invalid_call(obj_response, callback):
            self.fail("Invalid call handler triggered!")

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)

        def my_callback(obj_response, files, form_values):
            self.assertTrue(isinstance(obj_response, UploadResponse))
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("my_callback")
            call_history.append(obj_response.form_id)
            call_history.append(type(obj_response).__name__)
            call_history.append(files["file"]) # reaching into the file object

            # ensure that from all the post data, only the valid (non-system)
            # stuff made it through
            self.assertEqual({"form_key": "value", "form_key2": 15}, form_values)

        def my_callback2(obj_response, custom_arg1, custom_arg2, form_values):
            self.assertTrue(isinstance(obj_response, UploadResponse))
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("custom_callback")
            call_history.append(obj_response.form_id)
            call_history.append(type(obj_response).__name__)
            call_history.append(custom_arg1)
            call_history.append(custom_arg2)

            # ensure that from all the post data, only the valid (non-system)
            # stuff made it through
            self.assertEqual({"form_key": "value", "form_key2": 15}, form_values)

        form_id = "my_form"
        # the developer usually doesn't need to know the public system assigned
        # name of the callback function.. we'll need it though to fake the request
        public_callback_name = func_name_by_form_id(form_id)
        request_args_json = '["%s"]' % form_id
        post = {}
        post[cls.PARAM_REQUEST] = public_callback_name
        post[cls.PARAM_ARGS] = request_args_json
        post["form_key"] = "value"
        post["form_key2"] = 15
        inst.set_data(post)

        files = {"file": "object", "passed": "here"}
        register_upload_callback(inst, form_id, my_callback, args_extra=(files,))
        process_request(inst)


        # let's see if we can override the default args and the response
        # class during callback registration
        params_custom = {cls.PARAM_RESPONSE_CLASS: CustomResponse}
        register_upload_callback(inst, form_id, my_callback2, args_extra=("custom1", "custom2"), **params_custom)
        process_request(inst)

        call_history_expected = [
            "my_callback", form_id, "UploadResponse", "object",
            "custom_callback", form_id, "CustomResponse", "custom1", "custom2"
        ]
        self.assertEqual(call_history_expected, call_history)
示例#12
0
    def test_invalid_call_event_works(self):
        from types import GeneratorType, FunctionType
        call_history = []

        def my_callback(obj_response, arg1, arg2):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("call ok")

        def my_callback_raising_TypeError(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            raise TypeError('this should be re-raised by Sijax')

        def my_callback_raising_TypeError2(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            def inner():
                raise TypeError('this should be re-raised by Sijax')
            inner()

        def invalid_call(obj_response, failed_callback):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            self.assertTrue(isinstance(failed_callback, FunctionType))
            call_history.append("invalid %s" % failed_callback.__name__)

        def exhaust_generator(gen):
            self.assertTrue(isinstance(gen, GeneratorType))
            try:
                while True:
                    next(gen)
            except StopIteration:
                pass

        inst = Sijax()
        cls = inst.__class__
        options = {cls.PARAM_RESPONSE_CLASS: StreamingIframeResponse}

        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)
        inst.register_callback("my_func", my_callback, **options)

        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '["arg1", 12]'})
        self.assertTrue(inst.is_sijax_request)
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual(["arg1", 12], inst.request_args)
        response = inst.process_request()
        exhaust_generator(response)

        # we should have succeeded until now..
        # let's try to make the call invalid and observe the failure
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '[]'})
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual([], inst.request_args)
        response = inst.process_request()
        exhaust_generator(response)

        # let's ensure that raising a TypeError from within a handler,
        # is not mistaken for an invalid call (EVENT_INVALID_CALL),
        # and re-raises the exception
        inst.register_callback("my_func", my_callback_raising_TypeError, **options)
        try:
            response = inst.process_request()
            exhaust_generator(response)
        except TypeError:
            call_history.append('TypeError')

        inst.register_callback("my_func", my_callback_raising_TypeError2, **options)
        try:
            response = inst.process_request()
            exhaust_generator(response)
        except TypeError:
            call_history.append('TypeError2')

        expected = ['call ok', 'invalid my_callback',
                    'TypeError', 'TypeError2']
        self.assertEqual(expected, call_history)
示例#13
0
    def test_streaming_functions_return_generators(self):
        # Every function registered as streaming should return a generator
        # when it's executed, even if the actual function decides to act
        # as a normal function, and not generate anything
        # This is very important, because it allows mixing streaming with
        # regular functions when the StreamingIframeResponse is used

        from types import GeneratorType

        call_history = []

        def callback_before(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("before")
            obj_response.html("#div", "before html")

        def callback_after(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("after")
            # intentionally not pushing new commands
            # which means it should not be yielding at implicitly

        def callback_yielding(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("yielding")
            obj_response.alert("test")
            yield obj_response
            obj_response.css("#div", "color", "red")

        def callback_normal(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("normal")
            obj_response.script(".. javascript here..")

        def assert_generator_entries_length(generator, length):
            items = []
            try:
                while True:
                    items.append(next(generator))
            except StopIteration:
                pass

            self.assertEqual(length, len(items))

        inst = Sijax()
        cls = inst.__class__
        inst.register_event(cls.EVENT_BEFORE_PROCESSING, callback_before)
        inst.register_event(cls.EVENT_AFTER_PROCESSING, callback_after)
        options = {cls.PARAM_RESPONSE_CLASS: StreamingIframeResponse}

        response = inst.execute_callback([], callback=callback_yielding, **options)
        self.assertTrue(isinstance(response, GeneratorType))
        # We should have the following yields:
        # 1. Implicit yield after callback_before
        # 2. Explicit yield from callback_yielding
        # 3. Implicit yield when calback_yielding ends
        # Note that callback_after should not yield implicitly,
        # because it has not pushed new commands, so it makes no sense!
        assert_generator_entries_length(response, 3)

        def callback_before_new(obj_response):
            self.assertTrue(isinstance(obj_response, StreamingIframeResponse))
            call_history.append("before_new")

            # this doesn't really push data, as we haven't added commands yet
            # flushing would be wasteful
            for i in range(10):
                yield obj_response

            for i in range(2):
                obj_response.alert("hey")
                yield obj_response

        inst.register_event(cls.EVENT_BEFORE_PROCESSING, callback_before_new)
        inst.register_event(cls.EVENT_AFTER_PROCESSING, lambda r: r.alert("this yields"))
        response = inst.execute_callback([], callback=callback_normal, **options)
        self.assertTrue(isinstance(response, GeneratorType))
        # We're expecting the following yields:
        # 1. Explicit yield from callback_before_new
        # 2. Explicit yield from callback_before_new
        # 3. Implicit yield after callback_normal
        # 4. Implicit yield after EVENT_AFTER_PROCESSING callback
        assert_generator_entries_length(response, 4)

        call_history_expected = [
            "before", "yielding", "after",
            "before_new", "normal"
        ]
        self.assertEqual(call_history_expected, call_history)
示例#14
0
    def test_process_request_calls_invalid_call_event_for_invalid_calls(self):
        from types import FunctionType
        from sijax.helper import json

        # An invalid call is a call to a function that appears valid.
        # The function is registered (known), but calling fails, because
        # the function expects another number of arguments

        call_history = []

        def my_callback(obj_response, arg1, arg2):
            call_history.append("call ok")

        def my_callback_with_defaults(obj_response, arg1=138, arg2=15):
            call_history.append("defaults ok")

        def my_callback_raising_TypeError(obj_response):
            raise TypeError('this should be re-raised by Sijax')

        def my_callback_raising_TypeError2(obj_response):
            def inner():
                raise TypeError('this should be re-raised by Sijax')
            inner()

        def invalid_call(obj_response, failed_callback):
            self.assertTrue(isinstance(failed_callback, FunctionType))
            call_history.append("invalid %s" % failed_callback.__name__)

        inst = Sijax()
        cls = inst.__class__
        inst.register_callback("my_func", my_callback)

        # Make a valid call that would succeed
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '["arg1", 12]'})
        self.assertTrue(inst.is_sijax_request)
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual(["arg1", 12], inst.request_args)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))


        # Make a call with a wrong number of arguments, and a default
        # event handler for invalid calls
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '["arg1"]'})
        self.assertTrue(inst.is_sijax_request)
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual(["arg1"], inst.request_args)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))
        try:
            commands = json.loads(response)
        except:
            self.fail("Invalid JSON generated!")
        else:
            self.assertTrue(isinstance(commands, list))
            # we expect the default "Action performed in a wrong way" alert
            self.assertEqual(1, len(commands))
            command_data = commands.pop(0)
            self.assertTrue("type" in command_data)
            self.assertEqual("alert", command_data["type"])

        # Make an invalid call with a custom event handler function
        inst.register_event(cls.EVENT_INVALID_CALL, invalid_call)
        inst.set_data({cls.PARAM_REQUEST: "my_func", cls.PARAM_ARGS: '[]'})
        self.assertEqual("my_func", inst.requested_function)
        self.assertEqual([], inst.request_args)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))

        # let's see if calling works with default arguments
        inst.register_callback("my_func", my_callback_with_defaults)
        response = inst.process_request()
        self.assertTrue(isinstance(response, string_types))

        # let's ensure that raising a TypeError from within a handler,
        # is not mistaken for an invalid call (EVENT_INVALID_CALL),
        # and re-raises the exception
        inst.register_callback("my_func", my_callback_raising_TypeError)
        try:
            inst.process_request()
        except TypeError:
            call_history.append('TypeError')

        inst.register_callback("my_func", my_callback_raising_TypeError2)
        try:
            inst.process_request()
        except TypeError:
            call_history.append('TypeError2')

        expected = ['call ok', 'invalid my_callback', 'defaults ok',
                    'TypeError', 'TypeError2']
        self.assertEqual(expected, call_history)