Exemple #1
0
    def test_delays_unsubscribe_until_the_end_of_current_dispatch(self):
        store = create_store(reducers['todos'])

        unsubscribe_handles = []
        def do_unsubscribe_all():
            for unsubscribe in unsubscribe_handles:
                unsubscribe()

        listener_1 = mock.MagicMock()
        listener_2 = mock.MagicMock()
        listener_3 = mock.MagicMock()

        unsubscribe_handles.append(store['subscribe'](lambda: listener_1()))
        unsubscribe_handles.append(store['subscribe'](lambda: [listener_2(), do_unsubscribe_all()]))
        unsubscribe_handles.append(store['subscribe'](lambda: listener_3()))

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_1.call_args_list), 1)
        self.assertEqual(len(listener_2.call_args_list), 1)
        self.assertEqual(len(listener_3.call_args_list), 1)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_1.call_args_list), 1)
        self.assertEqual(len(listener_2.call_args_list), 1)
        self.assertEqual(len(listener_3.call_args_list), 1)
Exemple #2
0
    def test_delays_subscribe_until_the_end_of_current_dispatch(self):
        store = create_store(reducers['todos'])

        listener_1 = mock.MagicMock()
        listener_2 = mock.MagicMock()
        listener_3 = mock.MagicMock()

        listener_3_added = [False]
        def maybe_add_third_listener():
            if not listener_3_added[0]:
                listener_3_added[0] = True
                store['subscribe'](lambda: listener_3())

        store['subscribe'](lambda: listener_1())
        store['subscribe'](lambda: [listener_2(), maybe_add_third_listener()])

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_1.call_args_list), 1)
        self.assertEqual(len(listener_2.call_args_list), 1)
        self.assertEqual(len(listener_3.call_args_list), 0)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_1.call_args_list), 2)
        self.assertEqual(len(listener_2.call_args_list), 2)
        self.assertEqual(len(listener_3.call_args_list), 1)
Exemple #3
0
    def __init__(self, loglevel, client_id, client_secret):
        setup_logging(loglevel)
        print('PythonDashWunderlist {}'.format(__version__))
        store = create_store(
            reducer,
            initial_state={
                'client_id': client_id,
                'client_secret': client_secret,
                'access_token':
                'a4a548b2974997cfc7302ee8e6065c363a3c53bd5057a1a2e11ae56d237b',
                'dash_actions': {
                    '00:bb:3a:a0:e5:ac': {
                        'type': ADD_WUNDERLIST_ENTRY,
                        'list': 'WG Einkaufsliste',
                        'entry': 'Milch'
                    }
                }
            },
            enhancer=apply_middleware(
                sniffer_middleware,
                dash_button_middleware,
                wunderlist_middleware,
                log_middleware,
            ))

        store.subscribe(diff_state_print_function(store))
        reactor.run()
Exemple #4
0
    def test_handles_nested_dispatches_gracefully(self):
        def foo(state, action={}):
            if state is None:
                state = 0
            if action.get('type') == 'foo':
                return 1
            return state

        def bar(state, action={}):
            if state is None:
                state = 0
            if action.get('type') == 'bar':
                return 2
            else:
                return state

        store = create_store(combine_reducers({ 'foo': foo, 'bar': bar }))
        def kinda_component_did_update():
            state = store['get_state']()
            if state.get('bar') == 0:
                store['dispatch']({ 'type': 'bar' })
        store['subscribe'](kinda_component_did_update)
        store['dispatch']({ 'type': 'foo' })

        self.assertEqual(store['get_state'](), {
            'foo': 1,
            'bar': 2
        })
Exemple #5
0
    def test_applied_reducer_to_initial_state(self):
        store = create_store(reducers['todos'], [
            {
                'id': 1,
                'text': 'Hello'
            }
        ])
        self.assertEqual(store['get_state'](), [
            {
                'id': 1,
                'text': 'Hello'
            }
        ])

        store['dispatch'](unknown_action())
        self.assertEqual(store['get_state'](), [
            {
                'id': 1,
                'text': 'Hello'
            }
        ])

        store['dispatch'](add_todo('World'))
        self.assertEqual(store['get_state'](), [
            {
                'id': 1,
                'text': 'Hello'
            },
            {
                'id': 2,
                'text': 'World'
            }
        ])
Exemple #6
0
 def test_does_not_throw_if_action_type_is_falsy(self):
     store = create_store(reducers['todos'])
     try:
         store['dispatch']({ 'type': False })
         store['dispatch']({ 'type': 0 })
         store['dispatch']({ 'type': '' })
     except Exception:
         self.fail('These should not have raised an exception')
Exemple #7
0
 def test_passes_initial_action_and_initial_state(self):
     store = create_store(reducers['todos'], [
         {
             'id': 1,
             'text': 'Hello'
         }
     ])
     self.assertEqual(store['get_state'](), [{ 'id': 1, 'text': 'Hello' }])
Exemple #8
0
    def test_throws_if_listener_is_not_a_function(self):
        store = create_store(reducers['todos'])

        with self.assertRaises(Exception):
            store['subscribe']()
        with self.assertRaises(Exception):
            store['subscribe']('')
        with self.assertRaises(Exception):
            store['subscribe'](None)
Exemple #9
0
    def test_exposes_public_API(self):
        store = create_store(combine_reducers(reducers))
        methods = store.keys()

        self.assertEqual(len(methods), 4)
        self.assertTrue('subscribe' in methods)
        self.assertTrue('dispatch' in methods)
        self.assertTrue('get_state' in methods)
        self.assertTrue('replace_reducer' in methods)
Exemple #10
0
    def __store(self):
        """
        Store constructor, default reducer does nothing
        :return:
        """
        def default(state, action):
            return state

        return pydux.create_store(default, {})
Exemple #11
0
 def test_throws_if_reducer_is_not_a_function(self):
     with self.assertRaises(Exception):
         create_store(combine_reducers)
     with self.assertRaises(Exception):
         create_store('test')
     with self.assertRaises(Exception):
         create_store({})
     try:
         create_store(lambda *x: {})
     except Exception as e:
         self.fail('create_store(lambda: {}) should not have failed')
 def test_validation_subject_reducer(self):
     """
     The validationReport should contain an ID of the root node that was validated in the graph.
     For example, if the input was the URL of an Assertion, that URL (the assertion['id'] would appear.
     """
     node_id = 'http://example.com/assertion'
     store = create_store(main_reducer, INITIAL_STATE)
     store.dispatch(set_validation_subject(node_id))
     state = store.get_state()
     self.assertEqual(state['report']['validationSubject'], node_id)
Exemple #13
0
    def test_throws_if_next_reducer_is_not_a_function(self):
        store = create_store(reducers['todos'])
        with self.assertRaises(Exception) as e:
            store['replace_reducer']('not a function')
        self.assertTrue('Expected next_reducer to be a function' in str(e.exception))

        try:
            store['replace_reducer'](lambda *x: x)
        except Exception:
            self.fail('Should not have raised an exception')
Exemple #14
0
    def test_original_json_option(self):
        store = create_store(main_reducer, INITIAL_STATE)
        store.dispatch(
            store_original_resource('http://example.org/1',
                                    '{"data": "test data"}'))

        report = generate_report(store)
        self.assertNotIn('original_json', list(report['input'].keys()))

        report = generate_report(store, {'include_original_json': True})
        self.assertIn('original_json', list(report['input'].keys()))
Exemple #15
0
 def test_provides_up_to_date_state_when_subscriber_is_notified(self):
     store = create_store(reducers['todos'])
     def callback():
         state = store['get_state']()
         self.assertEqual(state, [
             {
                 'id': 1,
                 'text': 'Hello'
             }
         ])
     store['dispatch'](add_todo('Hello'))
Exemple #16
0
    def test_message_reporting(self):
        store = create_store(main_reducer, INITIAL_STATE)
        store.dispatch(report_message('TEST MESSAGE'))

        state = store.get_state()
        self.assertEqual(len(state['tasks']), 1)

        result = generate_report(store)
        self.assertEqual(len(result['report']['messages']), 1)
        self.assertEqual(result['report']['messages'][0]['result'],
                         'TEST MESSAGE')
Exemple #17
0
    def test_only_removes_relevant_listener_when_unsubscribe_is_called(self):
        store = create_store(reducers['todos'])
        listener = mock.MagicMock()

        store['subscribe'](listener)
        unsubscribe_second = store['subscribe'](listener)

        unsubscribe_second()
        unsubscribe_second()

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener.call_args_list), 1)
Exemple #18
0
def verification_store(badge_input,
                       recipient_profile=None,
                       store=None,
                       options=DEFAULT_OPTIONS):
    if store is None:
        store = create_store(main_reducer, INITIAL_STATE)
    try:
        if hasattr(badge_input, 'read') and hasattr(badge_input, 'seek'):
            badge_input.seek(0)
            badge_data = unbake(badge_input)
            if not badge_data:
                raise ValueError(
                    "Could not find Open Badges metadata in file.")
        else:
            badge_data = badge_input
    except ValueError as e:
        # Could not obtain badge data from input. Set the result as a failed DETECT_INPUT_TYPE task.
        store.dispatch(store_input(badge_input.name))
        store.dispatch(add_task(tasks.DETECT_INPUT_TYPE))
        store.dispatch(set_input_type('file'))
        task = store.get_state()['tasks'][0]
        store.dispatch(
            resolve_task(task.get('task_id'), success=False, result=e.message))
    else:
        store.dispatch(store_input(badge_data))
        store.dispatch(
            add_task(tasks.DETECT_INPUT_TYPE,
                     expected_class=OBClasses.Assertion))

    if recipient_profile:
        profile_id = recipient_profile.get('id')
        recipient_profile['@context'] = recipient_profile.get(
            '@context', OPENBADGES_CONTEXT_V2_URI)
        task = add_task(JSONLD_COMPACT_DATA,
                        data=json.dumps(recipient_profile),
                        expected_class=OBClasses.ExpectedRecipientProfile)
        if profile_id:
            task['node_id'] = profile_id
        store.dispatch(task)

    last_task_id = 0
    while len(filter_active_tasks(store.get_state())):
        active_tasks = filter_active_tasks(store.get_state())
        task_meta = active_tasks[0]
        task_func = tasks.task_named(task_meta['name'])

        if task_meta['task_id'] == last_task_id:
            break

        last_task_id = task_meta['task_id']
        call_task(task_func, task_meta, store, options)

    return store
Exemple #19
0
def play():
    store = pydux.create_store(reducer)
    game_engine = GameEngine(store)

    game_engine.request({'type': 'create_state'})
    response = game_engine.request({
        'type': 'play_creature',
        'card_index': 0,
        'player': 'p1',
        'lane': 'field_lane'
    })

    print(pprint(response))
Exemple #20
0
    def test_only_removes_listener_once_when_unsubscribe_is_called(self):
        store = create_store(reducers['todos'])
        listener_a = mock.MagicMock()
        listener_b = mock.MagicMock()

        unsubscribe_a = store['subscribe'](listener_a)
        store['subscribe'](listener_b)

        unsubscribe_a()
        unsubscribe_a()

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_a.call_args_list), 0)
        self.assertEqual(len(listener_b.call_args_list), 1)
Exemple #21
0
    def test_only_accepts_plain_objects(self):
        store = create_store(reducers['todos'])

        try:
            store['dispatch'](unknown_action())
        except Exception:
            self.fail('Should not have thrown exception')

        class AwesomeMap:
            def __init__(self):
                self.x = 1

        for non_object in [None, 42, 'hey', AwesomeMap()]:
            with self.assertRaises(Exception):
                store['dispatch'](non_object)
Exemple #22
0
    def test_supports_removing_a_subscription_within_a_subscription(self):
        store = create_store(reducers['todos'])
        listener_a = mock.MagicMock()
        listener_b = mock.MagicMock()
        listener_c = mock.MagicMock()

        store['subscribe'](listener_a)
        unsub_b = store['subscribe'](lambda: [listener_b(), unsub_b()])
        store['subscribe'](listener_c)

        store['dispatch'](unknown_action())
        store['dispatch'](unknown_action())

        self.assertEqual(len(listener_a.call_args_list), 2)
        self.assertEqual(len(listener_b.call_args_list), 1)
        self.assertEqual(len(listener_c.call_args_list), 2)
Exemple #23
0
    def test_supports_multiple_subscriptions(self):
        store = create_store(reducers['todos'])
        listener_a = mock.MagicMock()
        listener_b = mock.MagicMock()

        unsubscribe_a = store['subscribe'](listener_a)
        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_a.call_args_list), 1)
        self.assertEqual(len(listener_b.call_args_list), 0)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_a.call_args_list), 2)
        self.assertEqual(len(listener_b.call_args_list), 0)

        unsubscribe_b = store['subscribe'](listener_b)
        self.assertEqual(len(listener_a.call_args_list), 2)
        self.assertEqual(len(listener_b.call_args_list), 0)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_a.call_args_list), 3)
        self.assertEqual(len(listener_b.call_args_list), 1)

        unsubscribe_a()
        self.assertEqual(len(listener_a.call_args_list), 3)
        self.assertEqual(len(listener_b.call_args_list), 1)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_a.call_args_list), 3)
        self.assertEqual(len(listener_b.call_args_list), 2)

        unsubscribe_b()
        self.assertEqual(len(listener_a.call_args_list), 3)
        self.assertEqual(len(listener_b.call_args_list), 2)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_a.call_args_list), 3)
        self.assertEqual(len(listener_b.call_args_list), 2)

        unsubscribe_a = store['subscribe'](listener_a)
        self.assertEqual(len(listener_a.call_args_list), 3)
        self.assertEqual(len(listener_b.call_args_list), 2)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_a.call_args_list), 4)
        self.assertEqual(len(listener_b.call_args_list), 2)
Exemple #24
0
def extension_validation_store(extension_input,
                               store=None,
                               options=DEFAULT_OPTIONS):
    if store is None:
        store = create_store(main_reducer, INITIAL_STATE)

    if not isinstance(extension_input, dict):
        raise ValueError

    store.dispatch(store_input(extension_input.copy()))

    extension_input['@context'] = extension_input.get(
        '@context', OPENBADGES_CONTEXT_V2_URI)
    extension_input['id'] = extension_input.get(
        'id', '_:extension_validation_input')
    compact_task = add_task(JSONLD_COMPACT_DATA,
                            detectAndValidateClass=False,
                            data=json.dumps(extension_input))
    store.dispatch(compact_task)

    tasks_remaining = True
    while tasks_remaining:
        active_tasks = filter_active_tasks(store.get_state())
        if len(active_tasks) < 1:
            tasks_remaining = False
            break
        task_meta = active_tasks[0]
        task_func = tasks.task_named(task_meta['name'])
        call_task(task_func, task_meta, store, options)

    all_tasks = store.get_state()['tasks']
    try:
        first_extension_node_validation_task = [
            t for t in all_tasks if t['name'] == VALIDATE_EXTENSION_NODE
        ][0]
    except IndexError:
        store.dispatch(
            report_message(
                "No extensions were found to test. Check for proper use of context and type to declare an extension.",
                message_level=MESSAGE_LEVEL_ERROR,
                success=False))

    return store
Exemple #25
0
    def test_uses_last_snapshot_of_subscribers_during_nested_dispatch(self):
        store = create_store(reducers['todos'])

        listener_1 = mock.MagicMock()
        listener_2 = mock.MagicMock()
        listener_3 = mock.MagicMock()
        listener_4 = mock.MagicMock()

        unsubscribe_4 = [None]
        unsubscribe_1 = [None]
        def callback_for_listener_1():
            listener_1()
            self.assertEqual(len(listener_1.call_args_list), 1)
            self.assertEqual(len(listener_2.call_args_list), 0)
            self.assertEqual(len(listener_3.call_args_list), 0)
            self.assertEqual(len(listener_4.call_args_list), 0)

            unsubscribe_1[0]()
            unsubscribe_4[0] = store['subscribe'](listener_4)
            store['dispatch'](unknown_action())

            self.assertEqual(len(listener_1.call_args_list), 1)
            self.assertEqual(len(listener_2.call_args_list), 1)
            self.assertEqual(len(listener_3.call_args_list), 1)
            self.assertEqual(len(listener_4.call_args_list), 1)

        unsubscribe_1[0] = store['subscribe'](callback_for_listener_1)
        store['subscribe'](listener_2)
        store['subscribe'](listener_3)

        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_1.call_args_list), 1)
        self.assertEqual(len(listener_2.call_args_list), 2)
        self.assertEqual(len(listener_3.call_args_list), 2)
        self.assertEqual(len(listener_4.call_args_list), 1)

        unsubscribe_4[0]()
        store['dispatch'](unknown_action())
        self.assertEqual(len(listener_1.call_args_list), 1)
        self.assertEqual(len(listener_2.call_args_list), 3)
        self.assertEqual(len(listener_3.call_args_list), 3)
        self.assertEqual(len(listener_4.call_args_list), 1)
Exemple #26
0
    def test_can_print_exception(self):
        state = INITIAL_STATE.copy()
        # Create a state that will trigger an exception
        state['graph'] = [AttributeError("Haha this isn't a dict!")]
        task = add_task(VALIDATE_PROPERTY,
                        node_id='http://example.org/1',
                        prop_name='turnips',
                        prop_type=ValueTypes.TEXT)
        store = create_store(main_reducer, state)
        store.dispatch(task)

        call_task(task_named(VALIDATE_PROPERTY),
                  store.get_state()['tasks'][0], store)

        state = store.get_state()
        self.assertEqual(len(state['tasks']), 1, 'There is one task in state.')
        task = state['tasks'][0]
        self.assertFalse(task['success'])
        self.assertIn('AttributeError:', task['result'],
                      "assert an AttributeError is formatted as the message.")
Exemple #27
0
    def test_accepts_enhancer_as_third_argument(self):
        empty_array = []
        def spy_enhancer(vanilla_create_store):
            def enhancer(*args):
                self.assertEqual(args[0], reducers['todos'])
                self.assertEqual(args[1], empty_array)
                self.assertEqual(len(args), 2)
                vanilla_store = vanilla_create_store(*args)
                vanilla_store['dispatch'] = mock.MagicMock(side_effect=vanilla_store['dispatch'])
                return vanilla_store
            return enhancer

        store = create_store(reducers['todos'], empty_array, spy_enhancer)
        action = add_todo('Hello')
        store['dispatch'](action)
        self.assertEqual(store['dispatch'].call_args_list, [mock.call(action)])
        self.assertEqual(store['get_state'](), [{
            'id': 1,
            'text': 'Hello'
        }])
Exemple #28
0
    def __init__(self, vosekast):
        """ All the values which interest us are stored in this store . The
        checkboxes are created according to this store. It can only be changed
        by means of the dispatch-function.
        """
        self.vosekast = vosekast

        def reducer(state, action):
            if action is None or action.get("type") is None:
                return state
            else:
                newState = deepcopy(state)

                if action.get("body") is None:
                    return newState
                else:
                    if action["type"] == "Update Pump Measuring Tank":
                        newState["Pump Measuring Tank"] = deepcopy(action.get("body"))
                        return newState
                    elif action["type"] == "Update Pump Base Tank":
                        newState["Pump Base Tank"] = deepcopy(action.get("body"))
                        return newState
                    elif action["type"] == "UPDATE_SCALE":
                        newState["Scale"] = deepcopy(action.get("body"))
                        return newState
                    elif action["type"] == "Update Measuring Drain Valve":
                        newState["Measuring Drain Valve"] = deepcopy(action.get("body"))
                        return newState
                    elif action["type"] == "Update Measuring Tank Switch":
                        newState["Measuring Tank Switch"] = deepcopy(action.get("body"))
                        return newState

        default_state = {
            "Pump Measuring Tank": {"State": 0},
            "Pump Base Tank": {"State": 0},
            "Scale": {"State": 0, "Value": 0},
            "Measuring Drain Valve": {"State": 5},
            "Measuring Switch Valve": {"State": 5},
        }

        self._store = pydux.create_store(reducer, default_state)
 def test_does_not_allow_dispatch_from_within_reducer(self):
     store = create_store(reducers['dispatch_in_middle_of_reducer'])
     with self.assertRaises(Exception) as e:
         store['dispatch'](dispatch_in_middle(lambda: store['dispatch'](unknown_action())))
     self.assertTrue('may not dispatch' in str(e.exception))
    def test_preserves_state_when_replacing_reducer(self):
        store = create_store(reducers['todos'])
        store['dispatch'](add_todo('Hello'))
        store['dispatch'](add_todo('World'))
        self.assertEqual(store['get_state'](), [
            {
                'id': 1,
                'text': 'Hello'
            },
            {
                'id': 2,
                'text': 'World'
            }
        ])

        store['replace_reducer'](reducers['todos_reverse'])
        self.assertEqual(store['get_state'](), [
            {
                'id': 1,
                'text': 'Hello'
            },
            {
                'id': 2,
                'text': 'World'
            }
        ])

        store['dispatch'](add_todo('Perhaps'))
        self.assertEqual(store['get_state'](), [
            {
                'id': 3,
                'text': 'Perhaps'
            },
            {
                'id': 1,
                'text': 'Hello'
            },
            {
                'id': 2,
                'text': 'World'
            }
        ])

        store['replace_reducer'](reducers['todos'])
        self.assertEqual(store['get_state'](), [
            {
                'id': 3,
                'text': 'Perhaps'
            },
            {
                'id': 1,
                'text': 'Hello'
            },
            {
                'id': 2,
                'text': 'World'
            }
        ])

        store['dispatch'](add_todo('Surely'))
        self.assertEqual(store['get_state'](), [
            {
                'id': 3,
                'text': 'Perhaps'
            },
            {
                'id': 1,
                'text': 'Hello'
            },
            {
                'id': 2,
                'text': 'World'
            },
            {
                'id': 4,
                'text': 'Surely'
            }
        ])
Exemple #31
0
#
# In this example, we use a `if` statement and strings, but you can use a
# helper that follows a different convention if it makes sense for your
# project.
def counter(state, action):
    if state is None:
        state = 0
    if action is None:
        return state
    elif action['type'] == 'INCREMENT':
        return state + 1
    elif action['type'] == 'DECREMENT':
        return state - 1
    return state

# Create a Redux store holding the state of your app.
# Its API is { subscribe, dispatch, get_state }.
store = pydux.create_store(counter)

# You can use subscribe() to update the UI in response to state changes.
store.subscribe(lambda: print(store.get_state()))

# The only way to mutate the internal state is to dispatch an action.
# The actions can be serialized, logged or stored and later replayed.
store.dispatch({ 'type': 'INCREMENT' })
# 1
store.dispatch({ 'type': 'INCREMENT' })
# 2
store.dispatch({ 'type': 'DECREMENT' })
# 1
 def test_throws_if_enhancer_is_neither_undefined_or_a_function(self):
     with self.assertRaises(Exception):
         create_store(reducers['todos'], None, {})
     with self.assertRaises(Exception):
         create_store(reducers['todos'], None, [])
     with self.assertRaises(Exception):
         create_store(reducers['todos'], None, False)
     try:
         create_store(reducers['todos'], None, None)
         create_store(reducers['todos'], None, lambda x: x)
         create_store(reducers['todos'], lambda x: x)
         create_store(reducers['todos'], [])
         create_store(reducers['todos'], {})
     except Exception:
         self.fail('Should not have thrown an exception')
Exemple #33
0
 def setUp(self):
     self.store = create_store(main_reducer, INITIAL_STATE)
Exemple #34
0
import warnings

import pydux

from frozendict import frozendict

from . import reducers

reducers_map = {
    "CHANGE_BOX": reducers.change_box,
    "ADD_COMMIT": reducers.add_commit,
    "REMOVE_COMMIT": reducers.remove_commit,
    "CLEAR_COMMITS": reducers.clear_commits,
    "LOAD_COMMITS": reducers.load_commits,
    "REBASE": reducers.rebase,
}


initial = {"commits": [], "selected": [], "box": None}


def reducer(state, action):
    if action["type"] not in reducers_map:
        warnings.warn(f"Unhandled action \"{action['type']}\".", UserWarning)
        return state.copy()
    return reducers_map[action["type"]](state, action)


store = pydux.create_store(reducer, initial_state=frozendict(initial))
    def test_throws_if_action_type_is_none(self):
        store = create_store(reducers['todos'])

        with self.assertRaises(Exception) as e:
            store['dispatch']({ 'type': None })
        self.assertTrue('Actions must have a non-None "type" property.' in str(e.exception))