Пример #1
0
class StoryTests(unittest.TestCase):

    def setUp(self):
        self.s = Story()

    def tearDown(self):
        del self.s

    def test_add_node(self):
        self.s.add_node('a')
        self.assertTrue('a' in self.s)

        self.s.add_node(1)
        self.assertFalse(1 in self.s)
        self.assertTrue('1' in self.s)

        l = ['b', 'c', 'd']
        self.s.add_nodes_from(l)
        for c in l:
            self.assertTrue(c in self.s)
        self.assertTrue('a' in self.s)
        self.assertTrue('1' in self.s)

    def test_add_edge(self):
        self.s.add_node('a')
        self.s.add_node('b')
        self.s.add_edge('a', 'b')
        self.assertTrue('a' in self.s)
        self.assertTrue('b' in self.s)
        self.assertTrue('b' in self.s.neighbors('a'))
        self.assertFalse('a' in self.s.neighbors('b'))

        self.s.add_edge('c', 'd')
        self.assertTrue('c' in self.s)
        self.assertTrue('d' in self.s)
        self.assertTrue('d' in self.s.neighbors('c'))
        self.assertFalse('c' in self.s.neighbors('d'))

        ebunch = [('b', 'c'), ('d', 'e')]
        self.s.add_edges_from(ebunch)
        self.assertTrue('e' in self.s)
        
    def test_add_undir_edge(self):
        self.s.add_node('a')
        self.s.add_node('b')
        self.s.add_undirected_edge('a', 'b')
        self.assertTrue('a' in self.s)
        self.assertTrue('b' in self.s)
        self.assertTrue('b' in self.s.neighbors('a'))
        self.assertTrue('a' in self.s.neighbors('b'))

        self.s.add_undirected_edge('c', 'd')
        self.assertTrue('c' in self.s)
        self.assertTrue('d' in self.s)
        self.assertTrue('d' in self.s.neighbors('c'))
        self.assertTrue('c' in self.s.neighbors('d'))

        ebunch = [('b', 'c'), ('d', 'e')]
        self.s.add_undirected_edges_from(ebunch)
        self.assertTrue('e' in self.s)

    def test_set_current(self):
        with self.assertRaises(StoryError):
            self.s.current = 'a'
        self.s.add_node('a')
        self.s.current = 'a'
        self.assertTrue('a' in self.s.visited)
        self.assertTrue(self.s.current == 'a')

    def test_add_actions(self):
        self.s.add_node('a')
        s1 = 'This is a test message'
        self.s.add_say('a', message=s1)
        s2 = 'Fake message'
        self.s.add_say('a', message=s2)
        actions = self.s.node['a']['actions']
        self.assertTrue(actions == [{'type': 'say', 'kwargs': {'message': s1}},
                                    {'type': 'say', 'kwargs': {'message': s2}}])

    def test_run_conditions1(self):
        l = ['a', 'b', 'c']
        self.s.add_nodes_from(l)
        
        self.s.require_visit('b', 'a')
        self.s.require_visit('c', 'a', 'b')

        self.assertFalse('a' in self.s.visited)
        condition = self.s.run_conditions('b')[0]
        self.assertFalse(condition())
        condition = self.s.run_conditions('c')[0]
        self.assertFalse(condition())

        self.s.current = 'a'
        condition = self.s.run_conditions('b')[0]
        self.assertTrue(condition())
        condition = self.s.run_conditions('c')[0]
        self.assertFalse(condition())

        self.s.current = 'b'
        condition = self.s.run_conditions('c')[0]
        self.assertTrue(condition())

    def test_run_conditions2(self):
        l = ['a', 'b', 'c', 'd']
        self.s.add_nodes_from(l)
        self.s.context = {'apples': 5}

        self.s.check_context_for('b', 'apples')
        self.s.check_context_for('c', apples=6)
        self.s.check_context_for('d', 'oranges')

        condition = self.s.run_conditions('b')[0]
        self.assertTrue(condition())
        condition = self.s.run_conditions('c')[0]
        self.assertFalse(condition())
        condition = self.s.run_conditions('d')[0]
        self.assertFalse(condition())
        
        updated_context = {'apples': 6, 'oranges': 0}
        self.s.update_context(updated_context)

        condition = self.s.run_conditions('b')[0]
        self.assertTrue(condition())
        condition = self.s.run_conditions('c')[0]
        self.assertTrue(condition())
        condition = self.s.run_conditions('d')[0]
        self.assertTrue(condition())

    def test_context(self):
        d = {'a': 1, 'b': 2}
        self.s.context = d
        self.assertTrue(self.s.context == d)
        self.assertFalse(self.s.context is d)

    def test_run(self):
        # test empty
        self.s()

        l = ['a', 'b', 'c', 'd']
        self.s.add_nodes_from(l)
        self.s.add_edge('a', 'b')
        self.s.add_edge('a', 'c')
        self.s.add_edge('c', 'd')
        self.s.current = 'a'
        
        path = ['c', 'd']
        path_iter = iter(path)
        current = iter(path)
        dummy_input = lambda: next(path_iter)
        while not self.s.is_finished:
            self.s.input_fct = dummy_input 
            self.s()
            self.assertTrue(self.s.current == next(current))


    '''
Пример #2
0
class EditScreen(Screen):
    # dropdown_wid = ObjectProperty()
    dropdown_btn_wid = ObjectProperty()
    node_info_wid = ObjectProperty()
    refresh_btn = ObjectProperty()
    storyboard_wid = ObjectProperty()

    def __init__(self, **kwargs):
        super(EditScreen, self).__init__(**kwargs)
        self.d = None
        self.init_node_select_dropdown()
        self.story = Story()
        self.current_node = None
        self.refresh_btn.bind(on_release=self.refresh_graph)
        self.current_file = ''

    def init_node_select_dropdown(self):
        self.d = d = DropDown()
        b = Button(text='Add a node...', size_hint_y=None, height=dp(30))
        b.bind(on_release=self.show_add_popup)
        d.add_widget(b)
        d.bind(on_select=lambda _, text: setattr(self.dropdown_btn_wid, 'text', text))
        self.dropdown_btn_wid.bind(on_release=d.open)

    def show_file_browser(self, action):
        p = FileBrowserPopup()

        def update_current_file(instance, text):
            self.current_file = p.current_path + '/' + text.strip()

        if action == 'save as':
            p.filename_inp.bind(text=update_current_file)
            p.action_btn.text = 'Save'

            def save(button):
                self.save_current()
                p.dismiss()
            p.action_btn.bind(on_release=save)
            p.open()
        elif action == 'load':
            p.action_btn.text = 'Load'
            
            def load(button):
                path = p.selected_file
                self.load_story(path)
                p.dismiss()
            p.action_btn.bind(on_release=load)
            p.open()

    def save_current(self):
        if self.current_file:
            filename = self.current_file.strip()
            
            # check whether user has appended '.story' filename extension
            filename = filename.split('.')
            if len(filename) == 1 or filename[-1] != 'story':
                filename.append('story')
            filename = '.'.join(filename)
            print(filename)
            with open(filename, 'w') as f:
                pickle.dump(self.story, f)
        else:
            self.show_file_browser('save as')

    def load_story(self, path):
        # TODO: check whether current file is saved
        with open(path, 'r') as f:
            try:
                obj = pickle.load(f)
            except IOError as e:
                print(str(e))
                return

            if isinstance(obj, Story):
                self.story = obj
            else:
                # TODO: display helpful message
                return

            for node in self.story:
                b = Button(text=node, size_hint_y=None, height=dp(30)) 
                b.bind(on_release=self.show_info_callback)
                self.d.add_widget(b)

            self.refresh_graph()

    def check_current_file(self):
        board = self.ids['board']
        if board.current_file:
            board.save_story(board.current_file)
        else:
            self.show_file_chooser()

    def refresh_graph(self, *args):
        g = self.story
        plt.clf()
        nx.draw_networkx(g, node_size=2000, font_size=dp(16), node_shape=',')

        curr_axes = plt.gca()
        curr_axes.axes.get_xaxis().set_visible(False)
        curr_axes.axes.get_yaxis().set_visible(False)
        
        buf = io.BytesIO()
        plt.savefig(buf, format='png')
        buf.seek(0)
        image = CoreImage(buf, ext='png')
        
        self.storyboard_wid.texture = image.texture
    
    def show_add_popup(self, button):
        # show the add popup
        p = AddNodePopup(attach_to=self)
        p.open()
        
        def add_callback(button):
            """Add the node to the story and update the dropdown menu
            """
            self.d.dismiss()
            node_name = p.node_name
            self.story.add_node(node_name)
            print(self.story.nodes())
            p.dismiss()

            # update the dropdown menu
            b = Button(text=node_name, size_hint_y=None, height=dp(30)) 
            b.bind(on_release=self.show_info_callback)
            self.d.add_widget(b)
        p.submit_btn_wid.bind(on_release=add_callback)

    def show_info_callback(self, button):
        """Shows the node information in the sidebar
        """
        self.current_node = button.text
        self.d.select(button.text)
        # p.dismiss()
        node_info = self.node_info_wid
        node_info.clear_widgets()
        
        node_info.add_widget(Label(text='name:'))
        # TODO: allow node renaming?
        node_info.add_widget(TextInput(text=button.text, multiline=False))

        node_info.add_widget(Label(text='actions:'))
        actions_b = Button(text='edit...')
        actions_b.bind(on_release=self.show_add_action_popup)
        node_info.add_widget(actions_b)

        node_info.add_widget(Label(text='destinations:'))
        dest_b = Button(text='edit...')
        dest_b.bind(on_release=self.show_add_dest_popup)
        node_info.add_widget(dest_b)

        node_info.add_widget(Label(text='origins:'))
        orig_b = Button(text='edit...')
        orig_b.bind(on_release=self.show_add_origin_popup)
        node_info.add_widget(orig_b)

    def show_add_action_popup(self, button):
        p = AddActionPopup(existing_actions=self.story.get_actions(self.current_node),
                attach_to=self)
        p.open()
        def add_action_callback(button):
            a = Action()
            p.add_action(a)
            # p.actions_list_wid.add_widget(a)
            # p.actions_temp.append(a)

        def update_story(action):
            if action.action_type == 'say':
                self.story.add_say(self.current_node, **action.parameters)
            elif action.action_type == 'listen':
                self.story.add_listen(self.current_node, **action.parameters)
            elif action.action_type == 'play':
                self.story.add_play(self.current_node, **action.parameters)

        def save_callback(button):
            actions = p.actions_temp
            for action in actions:
                update_story(action)
            p.dismiss()

        p.add_action_btn_wid.bind(on_release=add_action_callback)
        p.save_btn.bind(on_release=save_callback)

    def show_add_dest_popup(self, button):
        p = AddEdgePopup(title='Add destinations')
        valid_dest = self.story.nodes()
        valid_dest.remove(self.current_node)
        for dest in valid_dest:
            b = ToggleButton(text=dest, size_hint_y=None, height=dp(30))
            if dest in self.story.neighbors(self.current_node):
                b.state = 'down'
            p.node_list.add_widget(b)
        p.node_list.add_widget(Widget())

        def save_callback(button):
            to_add = []
            to_remove = []
            for child in p.node_list.children:
                if isinstance(child, ToggleButton):
                    node_name = child.text
                    if child.state == 'down':
                        to_add.append(node_name)
                    else:
                        to_remove.append(node_name)
            for node in to_add:
                if node not in self.story.neighbors(self.current_node):
                    self.story.add_edge(self.current_node, node)
            for node in to_remove:
                if node in self.story.neighbors(self.current_node):
                    self.story.remove_edge(self.current_node, node)
            p.dismiss()
        p.save_btn.bind(on_release=save_callback)
        
        p.open()

    def show_add_origin_popup(self, button):
        p = AddEdgePopup(title='Add origins')
        valid_orig = self.story.nodes()
        valid_orig.remove(self.current_node)
        for orig in valid_orig:
            b = ToggleButton(text=orig, size_hint_y=None, height=dp(30))
            if orig in self.story.predecessors(self.current_node):
                b.state = 'down'
            p.node_list.add_widget(b)
        p.node_list.add_widget(Widget())

        def save_callback(button):
            to_add = []
            to_remove = []
            for child in p.node_list.children:
                if isinstance(child, ToggleButton):
                    node_name = child.text
                    if child.state == 'down':
                        to_add.append(node_name)
                    else:
                        to_remove.append(node_name)
            for node in to_add:
                if node not in self.story.predecessors(self.current_node):
                    self.story.add_edge(node, self.current_node)
            for node in to_remove:
                if node in self.story.predecessors(self.current_node):
                    self.story.remove_edge(node, self.current_node)
            p.dismiss()
        p.save_btn.bind(on_release=save_callback)
        
        p.open()