예제 #1
0
 def test_settings_2(self, mock_ip):
     # - if index is None, field and value are valid, it'll set for all IPs
     test_wm = WorkflowManager([u'a', u'b', u'c'])
     self.assertEqual(3, mock_ip.call_count)  # to make sure we're using the mock, not real IP
     test_wm.settings(None, u'filter repeats', True)
     for i in xrange(3):
         self.assertEqual(True, test_wm._settings[i][u'filter repeats'])
    def test_intervs_3(self, mock_guc, mock_rfa, mock_rep):
        """Ensure _intervs() calls everything in the right order, with the right args & settings.
           This uses the default *except* requires removing rests, so it's more complex."""
        test_settings = {'simple or compound': 'compound', 'quality': False}
        test_pieces = [MagicMock(spec_set=IndexedPiece) for _ in range(3)]
        returns = [
            pandas.DataFrame([pandas.Series(['3', 'Rest', '5'])],
                             index=[['interval.IntervalIndexer'], ['0,1']]).T
            for i in range(len(test_pieces))
        ]
        for piece in test_pieces:
            piece.get_data.side_effect = lambda *x: returns.pop(0)
        exp_series_ind = ('interval.IntervalIndexer', '0,1')
        expected_df = pandas.DataFrame(
            {exp_series_ind: pandas.Series(['3', '5'], index=[0, 2])})
        exp_analyzers = [noterest.NoteRestIndexer, interval.IntervalIndexer]

        test_wc = WorkflowManager(test_pieces)
        test_wc.settings(None, 'count frequency', False)
        actual = test_wc._intervs()  # pylint: disable=protected-access

        self.assertEqual(0, mock_guc.call_count)
        self.assertEqual(len(test_pieces), len(actual))
        self.assertEqual(0, mock_rfa.call_count)
        self.assertEqual(0, mock_rep.call_count)
        for piece in test_pieces:
            piece.get_data.assert_called_once_with(exp_analyzers,
                                                   test_settings)
        for i in range(len(actual)):
            self.assertSequenceEqual(list(expected_df.columns),
                                     list(actual[i].columns))
            self.assertSequenceEqual(list(expected_df[exp_series_ind].index),
                                     list(actual[i][exp_series_ind].index))
            self.assertSequenceEqual(list(expected_df[exp_series_ind].values),
                                     list(actual[i][exp_series_ind].values))
 def test_intervs_3(self, mock_int, mock_nri, mock_rep, mock_rfa, mock_ror):
     # --> test whether _intervs() when we specify an impossible voice pair ('[[0, 1, 2]]')
     # 1.) prepare the test and mocks
     test_settings = {u'simple or compound': u'compound', u'quality': False}
     test_pieces = [MagicMock(IndexedPiece, name=x) for x in [u'test1', u'test2', u'test3']]
     the_dicts = [MagicMock(dict, name=u'get_data() piece' + str(i), return_value=[4]) \
                  for i in xrange(3)]
     returns = the_dicts
     def side_effect(*args):
         # NB: we need to accept "args" as a mock framework formality
         # pylint: disable=W0613
         return returns.pop(0)
     for piece in test_pieces:
         piece.get_data.side_effect = side_effect
     mock_ror.return_value = [pandas.Series(['Rest', 'P5', 'm3']) for _ in xrange(len(test_pieces))]
     expected = [pandas.Series(['Rest', 'P5', 'm3']) for _ in xrange(len(test_pieces))]
     expected_pairs = [[0, 1, 2]]
     expected_error_message = WorkflowManager._REQUIRE_PAIRS_ERROR % len(expected_pairs[0])
     # 2.) run the test
     test_wc = WorkflowManager(test_pieces)
     # (have to set the voice-pair settings)
     for i in xrange(len(test_pieces)):
         test_wc._settings[i][u'voice combinations'] = unicode(expected_pairs)
     # 3.) verify
     self.assertRaises(RuntimeError, test_wc._intervs)
     try:
         test_wc._intervs()
     except RuntimeError as runerr:
         self.assertEqual(expected_error_message, runerr.message)
    def test_intervs_1(self, mock_guc, mock_rfa, mock_rep):
        """Ensure _intervs() calls everything in the right order, with the right args & settings.
           This test uses all the default settings."""
        test_settings = {'simple or compound': 'compound', 'quality': False}
        test_pieces = [MagicMock(spec_set=IndexedPiece) for _ in range(3)]
        returns = ['get_data() {}'.format(i) for i in range(len(test_pieces))]
        for piece in test_pieces:
            piece.get_data.side_effect = lambda *x: returns.pop(0)
        expected = ['get_data() {}'.format(i) for i in range(len(test_pieces))]
        exp_analyzers = [noterest.NoteRestIndexer, interval.IntervalIndexer]

        test_wc = WorkflowManager(test_pieces)
        test_wc.settings(None, 'include rests', True)
        actual = test_wc._intervs()  # pylint: disable=protected-access

        self.assertEqual(0, mock_guc.call_count)
        self.assertEqual(len(test_pieces), len(expected), len(actual))
        self.assertEqual(0, mock_rep.call_count)
        mock_rfa.assert_called_once_with('interval.IntervalIndexer')
        for piece in test_pieces:
            piece.get_data.assert_called_once_with(exp_analyzers,
                                                   test_settings)
        for i in range(len(actual)):
            # NB: in real use, _run_freq_agg() would aggregate a piece's voice pairs and save it in
            #     self._result... but since that method's mocked out, we have to check here the
            #     return of each piece's get_data() call
            self.assertSequenceEqual(expected[i], actual[i])
 def test_intervs_1(self, mock_int, mock_nri, mock_rfa, mock_ror):
     # --> test whether _intervs() calls all those things in the right order, with the right
     #     args, using all the default settings
     # 1.) prepare the test and mocks
     test_settings = {u'simple or compound': u'compound', u'quality': False}
     test_pieces = [MagicMock(IndexedPiece, name=x) for x in [u'test1', u'test2', u'test3']]
     returns = [MagicMock(dict, name=u'get_data() piece' + str(i), return_value=[4]) \
                for i in xrange(3)]
     def side_effect(*args):
         # NB: we need to accept "args" as a mock framework formality
         # pylint: disable=W0613
         return returns.pop(0)
     for piece in test_pieces:
         piece.get_data.side_effect = side_effect
     mock_ror.return_value = [pandas.Series(['Rest', 'P5', 'm3']) for _ in xrange(len(test_pieces))]
     expected = [pandas.Series(['P5', 'm3'], index=[1, 2]) for _ in xrange(len(test_pieces))]
     # 2.) run the test
     test_wc = WorkflowManager(test_pieces)
     actual = test_wc._intervs()
     # 3.) confirm everything was called in the right order
     for piece in test_pieces:
         self.assertEqual(1, piece.get_data.call_count)
         piece.get_data.assert_called_once_with([mock_nri, mock_int], test_settings)
     self.assertEqual(len(test_pieces), mock_ror.call_count)
     mock_rfa.assert_called_once_with()
     self.assertEqual(len(test_pieces), len(expected), len(actual))
     for i in xrange(len(actual)):
         # NB: in real use, _run_freq_agg() would aggregate a piece's voice pairs, so we
         #     wouldn't need to ask for the [0] index here... but also, this experiment shouldn't
         #     call _run_freq_agg() anyway
         self.assertSequenceEqual(list(expected[i]), list(actual[i][0]))
         self.assertSequenceEqual(list(expected[i].index), list(actual[i][0].index))
 def test_interval_ngrams_2(self, mock_two, mock_all, mock_var, mock_rfa):
     # --> same as test_interval_ngrams_1(), but with "count frequency" set to False
     # 1.) prepare mocks
     ind_pieces = [MagicMock(spec=IndexedPiece) for _ in xrange(3)]
     mock_rfa.return_value = u'mock_rfa() return value'
     mock_two.return_value = [u'mock_two() return value']
     mock_all.return_value = [u'mock_all() return value']
     mock_var.return_value = [u'mock_var() return value']
     expected = [mock_all.return_value, mock_two.return_value, mock_var.return_value]
     # 2.) run the test
     test_wm = WorkflowManager(ind_pieces)
     test_wm.settings(0, u'voice combinations', u'all')
     test_wm.settings(1, u'voice combinations', u'all pairs')
     test_wm.settings(2, u'voice combinations', u'[[0, 1]]')
     test_wm.settings(None, 'count frequency', False)
     actual = test_wm._interval_ngrams()
     # 3.) verify the mocks
     # NB: in actual use, _run_freq_agg() would have the final say on the value of
     #     test_wm._result... but it's mocked out, which means we can test whether
     #     _interval_ngrams() puts the right stuff there
     self.assertEqual(3, len(test_wm._result))
     for ret_val in expected:
         self.assertTrue(ret_val in test_wm._result)
     mock_two.assert_called_once_with(1)
     mock_all.assert_called_once_with(0)
     mock_var.assert_called_once_with(2)
     self.assertEqual(0, mock_rfa.call_count)
     self.assertEqual(expected, actual)
     self.assertSequenceEqual(expected, test_wm._result)
    def test_intervs_3(self, mock_guc, mock_rfa, mock_rep):
        """Ensure _intervs() calls everything in the right order, with the right args & settings.
           This uses the default *except* requires removing rests, so it's more complex."""
        test_settings = {'simple or compound': 'compound', 'quality': False}
        test_pieces = [MagicMock(spec_set=IndexedPiece) for _ in range(3)]
        returns = [pandas.DataFrame([pandas.Series(['3', 'Rest', '5'])],
                                    index=[['interval.IntervalIndexer'], ['0,1']]).T
                   for i in range(len(test_pieces))]
        for piece in test_pieces:
            piece.get_data.side_effect = lambda *x: returns.pop(0)
        exp_series_ind = ('interval.IntervalIndexer', '0,1')
        expected_df = pandas.DataFrame({exp_series_ind: pandas.Series(['3', '5'], index=[0, 2])})
        exp_analyzers = [noterest.NoteRestIndexer, interval.IntervalIndexer]

        test_wc = WorkflowManager(test_pieces)
        test_wc.settings(None, 'count frequency', False)
        actual = test_wc._intervs()  # pylint: disable=protected-access

        self.assertEqual(0, mock_guc.call_count)
        self.assertEqual(len(test_pieces), len(actual))
        self.assertEqual(0, mock_rfa.call_count)
        self.assertEqual(0, mock_rep.call_count)
        for piece in test_pieces:
            piece.get_data.assert_called_once_with(exp_analyzers, test_settings)
        for i in range(len(actual)):
            self.assertSequenceEqual(list(expected_df.columns), list(actual[i].columns))
            self.assertSequenceEqual(list(expected_df[exp_series_ind].index),
                                     list(actual[i][exp_series_ind].index))
            self.assertSequenceEqual(list(expected_df[exp_series_ind].values),
                                     list(actual[i][exp_series_ind].values))
    def test_intervs_1(self, mock_guc, mock_rfa, mock_rep):
        """Ensure _intervs() calls everything in the right order, with the right args & settings.
           This test uses all the default settings."""
        test_settings = {'simple or compound': 'compound', 'quality': False}
        test_pieces = [MagicMock(spec_set=IndexedPiece) for _ in range(3)]
        returns = ['get_data() {}'.format(i) for i in range(len(test_pieces))]
        for piece in test_pieces:
            piece.get_data.side_effect = lambda *x: returns.pop(0)
        expected = ['get_data() {}'.format(i) for i in range(len(test_pieces))]
        exp_analyzers = [noterest.NoteRestIndexer, interval.IntervalIndexer]

        test_wc = WorkflowManager(test_pieces)
        test_wc.settings(None, 'include rests', True)
        actual = test_wc._intervs()  # pylint: disable=protected-access

        self.assertEqual(0, mock_guc.call_count)
        self.assertEqual(len(test_pieces), len(expected), len(actual))
        self.assertEqual(0, mock_rep.call_count)
        mock_rfa.assert_called_once_with('interval.IntervalIndexer')
        for piece in test_pieces:
            piece.get_data.assert_called_once_with(exp_analyzers, test_settings)
        for i in range(len(actual)):
            # NB: in real use, _run_freq_agg() would aggregate a piece's voice pairs and save it in
            #     self._result... but since that method's mocked out, we have to check here the
            #     return of each piece's get_data() call
            self.assertSequenceEqual(expected[i], actual[i])
예제 #9
0
 def test_load_1(self):
     # that "get_data" is called correctly on each thing
     test_wc = WorkflowManager([])
     test_wc._data = [mock.MagicMock(spec=IndexedPiece) for _ in xrange(5)]
     test_wc.load(u'pieces')
     for mock_piece in test_wc._data:
         mock_piece.get_data.assert_called_once_with([noterest.NoteRestIndexer])
     self.assertTrue(test_wc._loaded)
예제 #10
0
 def test_output_4(self):
     """ensure RuntimeError if self._result is None"""
     test_wc = WorkflowManager([])
     test_wc._result = None  # just in case
     self.assertRaises(RuntimeError, test_wc.output, 'R histogram')
     try:
         test_wc.output('R histogram')
     except RuntimeError as run_err:
         self.assertEqual(WorkflowManager._NO_RESULTS_ERROR, run_err.args[0])
예제 #11
0
 def test_filter_dataframe_3(self):
     """test with top_x=3, threshold=5 (so the top_x still removes after threshold), name=auto"""
     test_wc = WorkflowManager([])
     test_wc._result = pandas.DataFrame({'data': pandas.Series([i for i in range(10, 0, -1)])})
     expected = pandas.DataFrame({'data': pandas.Series([10, 9, 8])})
     actual = test_wc._filter_dataframe(top_x=3, threshold=5)
     self.assertEqual(len(expected.columns), len(actual.columns))
     for i in expected.columns:
         self.assertSequenceEqual(list(expected[i].index), list(actual[i].index))
         self.assertSequenceEqual(list(expected[i].values), list(actual[i].values))
예제 #12
0
 def test_lilypond_1a(self):
     """error conditions: if 'count frequency' is True (but the lengths are okay)"""
     test_wm = WorkflowManager(['fake piece'])
     test_wm._data = ['fake IndexedPiece']
     test_wm._result = ['fake results']
     # test twice like this to make sure (1) the try/except will definitely catch something, and
     # (2) we're not getting hit by another RuntimeError, of which there could be many
     with self.assertRaises(RuntimeError) as run_err:
         test_wm._make_lilypond(['paths'])
     self.assertEqual(WorkflowManager._COUNT_FREQUENCY_MESSAGE, run_err.exception.args[0])
예제 #13
0
 def test_settings_9(self, mock_ip):
     # - if trying to set 'offset interval' to 0, it should actually be set to None
     test_wm = WorkflowManager([u'a', u'b', u'c'])
     self.assertEqual(3, mock_ip.call_count)  # to make sure we're using the mock, not real IP
     # "None" is default value, so first set to non-zero
     test_wm.settings(1, u'offset interval', 4.0)
     self.assertEqual(4.0, test_wm._settings[1][u'offset interval'])
     # now run our test
     test_wm.settings(1, u'offset interval', 0)
     self.assertEqual(None, test_wm._settings[1][u'offset interval'])
예제 #14
0
 def test_get_dataframe_2(self):
     # test with name='asdf', top_x=3, threshold=auto
     test_wc = WorkflowManager([])
     test_wc._result = pandas.Series([i for i in xrange(10, 0, -1)])
     expected = pandas.DataFrame({'asdf': pandas.Series([10, 9, 8])})
     actual = test_wc._get_dataframe('asdf', 3)
     self.assertEqual(len(expected.columns), len(actual.columns))
     for i in expected.columns:
         self.assertSequenceEqual(list(expected.loc[:,i].index), list(actual.loc[:,i].index))
         self.assertSequenceEqual(list(expected.loc[:,i].values), list(actual.loc[:,i].values))
예제 #15
0
 def test_get_dataframe_4(self):
     # test with name=auto, top_x=5, threshold=7 (so threshold leaves fewer than 3 results)
     test_wc = WorkflowManager([])
     test_wc._result = pandas.Series([i for i in xrange(10, 0, -1)])
     expected = pandas.DataFrame({'data': pandas.Series([10, 9, 8])})
     actual = test_wc._get_dataframe(top_x=5, threshold=7)
     self.assertEqual(len(expected.columns), len(actual.columns))
     for i in expected.columns:
         self.assertSequenceEqual(list(expected.loc[:,i].index), list(actual.loc[:,i].index))
         self.assertSequenceEqual(list(expected.loc[:,i].values), list(actual.loc[:,i].values))
예제 #16
0
 def test_output_3(self):
     """ensure RuntimeError if there's an invalid instruction"""
     test_wc = WorkflowManager([])
     test_wc._result = [5]  # make sure that's not what causes it
     bad_instruction = 'eat dirt'
     self.assertRaises(RuntimeError, test_wc.output, bad_instruction)
     try:
         test_wc.output(bad_instruction)
     except RuntimeError as run_err:
         self.assertEqual(WorkflowManager._UNRECOGNIZED_INSTRUCTION.format(bad_instruction),
                          run_err.args[0])
예제 #17
0
 def test_filter_dataframe_5(self):
     """test with top_x=3, threshold=auto, name='asdf'; many input columns"""
     test_wc = WorkflowManager([])
     test_wc._result = pandas.DataFrame({('1', 'b'): pandas.Series([i for i in range(10, 0, -1)]),
                                         ('1', 'z'): pandas.Series([i for i in range(10, 20)]),
                                         ('2', 'e'): pandas.Series([i for i in range(40, 900)])})
     expected = pandas.DataFrame({'asdf': pandas.Series([10, 9, 8])})
     actual = test_wc._filter_dataframe(top_x=3, name='asdf')
     self.assertEqual(len(expected.columns), len(actual.columns))
     for i in expected.columns:
         self.assertSequenceEqual(list(expected[i].index), list(actual[i].index))
         self.assertSequenceEqual(list(expected[i].values), list(actual[i].values))
 def test_ngrams_6(self):
     # test madrigal51 with all-voice 2-grams and rests
     test_wm = WorkflowManager(['vis/tests/corpus/madrigal51.mxl'])
     test_wm.settings(0, 'voice combinations', 'all')
     test_wm.settings(None, 'include rests', True)
     test_wm.load('pieces')
     test_wm.settings(0, 'continuer', '_')
     actual = test_wm.run('interval n-grams')
     exp_ind = list(NGramsTests.EXPECTED_6.index)
     act_ind = list(actual.index)
     for ind_item in exp_ind:
         self.assertTrue(ind_item in act_ind)
     for ind_item in exp_ind:
         self.assertEqual(NGramsTests.EXPECTED_6[ind_item], actual[ind_item])
 def test_ngrams_2(self):
     # test all two-part combinations of bwv77; 5-grams
     test_wm = WorkflowManager(['vis/tests/corpus/bwv77.mxl'])
     test_wm.load('pieces')
     test_wm.settings(0, 'voice combinations', 'all pairs')
     test_wm.settings(0, 'n', 5)
     test_wm.settings(0, 'continuer', '_')
     actual = test_wm.run('interval n-grams')[:10]
     exp_ind = list(NGramsTests.EXPECTED_2.index)
     act_ind = list(actual.index)
     for ind_item in exp_ind:
         self.assertTrue(ind_item in act_ind)
     for ind_item in exp_ind:
         self.assertEqual(NGramsTests.EXPECTED_2[ind_item], actual[ind_item])
 def test_interval_ngrams_1(self, mock_two, mock_all, mock_var, mock_rfa):
     # --> test with three pieces, each of which requires a different helper
     # 1.) prepare mocks
     ind_pieces = [MagicMock(spec=IndexedPiece) for _ in xrange(3)]
     mock_rfa.return_value = u'mock_rfa() return value'
     mock_two.return_value = [u'mock_two() return value']
     mock_all.return_value = [u'mock_all() return value']
     mock_var.return_value = [u'mock_var() return value']
     expected = [mock_all.return_value, mock_two.return_value, mock_var.return_value]
     # 2.) run the test
     test_wm = WorkflowManager(ind_pieces)
     test_wm.settings(0, u'voice combinations', u'all')
     test_wm.settings(1, u'voice combinations', u'all pairs')
     test_wm.settings(2, u'voice combinations', u'[[0, 1]]')
     actual = test_wm._interval_ngrams()
     # 3.) verify the mocks
     # NB: in actual use, _run_freq_agg() would have the final say on the value of
     #     test_wm._result... but it's mocked out, which means we can test whether
     #     _interval_ngrams() puts the right stuff there
     mock_two.assert_called_once_with(1)
     mock_all.assert_called_once_with(0)
     mock_var.assert_called_once_with(2)
     mock_rfa.assert_called_once_with()
     self.assertSequenceEqual(expected, actual)
     self.assertSequenceEqual(expected, test_wm._result)
예제 #21
0
 def test_ngrams_4(self):
     # test all voices of bwv2; 3-grams; simple intervals
     test_wm = WorkflowManager(['vis/tests/corpus/bwv2.xml'])
     test_wm.load('pieces')
     test_wm.settings(0, 'voice combinations', 'all')
     test_wm.settings(0, 'n', 2)
     test_wm.settings(None, 'simple intervals', True)
     actual = test_wm.run('interval n-grams')[:10]
     exp_ind = list(NGramsTests.EXPECTED_4.index)
     act_ind = list(actual.index)
     for ind_item in exp_ind:
         self.assertTrue(ind_item in act_ind)
     for ind_item in exp_ind:
         self.assertEqual(NGramsTests.EXPECTED_4[ind_item], actual[ind_item])
 def test_ngrams_1(self):
     # test the two highest voices of bwv77; 2-grams
     test_wm = WorkflowManager(['vis/tests/corpus/bwv77.mxl'])
     test_wm.load('pieces')
     test_wm.settings(0, 'voice combinations', '[[0, 1]]')
     test_wm.settings(0, 'n', 2)
     test_wm.settings(0, 'continuer', '_')
     actual = test_wm.run('interval n-grams')
     exp_ind = list(NGramsTests.EXPECTED_1.index)
     act_ind = list(actual.index)
     for ind_item in exp_ind:
         self.assertTrue(ind_item in act_ind)
     for ind_item in exp_ind:
         self.assertEqual(NGramsTests.EXPECTED_1[ind_item], actual[ind_item])
예제 #23
0
 def test_histogram_1(self, mock_call, mock_gdf, mock_join):
     # with specified pathname; last experiment was intervals with 20 pieces; self._result is DF
     test_wc = WorkflowManager([])
     test_wc._previous_exp = u'intervals'
     test_wc._data = [1 for _ in xrange(20)]
     test_wc._result = MagicMock(spec=pandas.DataFrame)
     path = u'pathname!'
     actual = test_wc._make_histogram(path)
     self.assertEqual(0, mock_gdf.call_count)
     expected_args = [u'Rscript', u'--vanilla', mock_join.return_value,
                      path + u'.dta', path + u'.png', u'int', u'20']
     mock_call.assert_called_once_with(expected_args)
     self.assertEqual(path + u'.png', actual)
     self.assertEqual(1, mock_join.call_count)
 def test_ngrams_9c(self):
     # same as 9b but 'interval quality' is set to False (by default).
     test_wm = WorkflowManager(['vis/tests/corpus/Kyrie_short.krn'])
     test_wm.load()
     test_wm.settings(0, 'voice combinations', '[[1,3]]')
     test_wm.settings(0, 'n', 2)
     test_wm.settings(0, 'offset interval', 2.0)
     actual = test_wm.run('interval n-grams')
     exp_ind = list(NGramsTests.EXPECTED_9c.index)
     act_ind = list(actual.index)
     self.assertEqual(len(exp_ind), len(act_ind))
     for ind_item in exp_ind:
         self.assertTrue(ind_item in act_ind)
         self.assertEqual(NGramsTests.EXPECTED_9c[ind_item], actual[ind_item])
예제 #25
0
 def test_load_3(self):
     # NB: this is more of an integration test
     test_wc = WorkflowManager([u'vis/tests/corpus/try_opus.krn'])
     test_wc.load('pieces')
     self.assertEqual(3, len(test_wc))
     # NOTE: we have to do this by digging until music21 imports metadata from **kern files, at
     #       which point we'll be able to use our very own metadata() method
     exp_names = [u'Alex', u'Sarah', u'Emerald']
     for i in xrange(3):
         # first Score gets some extra metadata
         which_el = 5 if i == 0 else 3
         piece = test_wc._data[i]._import_score()
         self.assertTrue(isinstance(piece[which_el], GlobalReference))
         self.assertEqual(u'COM', piece[which_el].code)
         self.assertEqual(exp_names[i], piece[which_el].value)
예제 #26
0
 def test_run_off_rep_4(self, mock_off, mock_rep):
     # run offset and repeat indexer
     # setup
     workm = WorkflowManager(['', '', ''])
     workm._data = [None, MagicMock(spec=IndexedPiece), None]
     workm._data[1].get_data.return_value = 24
     workm.settings(1, 'offset interval', 0.5)
     workm.settings(1, 'filter repeats', True)
     in_val = 42
     # run
     actual = workm._run_off_rep(1, in_val)
     # test
     self.assertEqual(workm._data[1].get_data.return_value, actual)
     self.assertEqual(2, workm._data[1].get_data.call_count)
     workm._data[1].get_data.assert_any_call([mock_off], {'quarterLength': 0.5}, in_val)
     workm._data[1].get_data.assert_any_call([mock_rep], {}, workm._data[1].get_data.return_value)
예제 #27
0
 def test_extra_pairs_5(self):
     # --> when there are lots of pairs, only some of which are desired, and there are invalid
     vert_ints = {'4,20': 0, '0,1': 1, '11,12': 4, '0,2': 2, '1,2': 3, '256,128': 12}
     combos = [[0, 1], [1, 2, 3, 4, 5], [0, 2], [1, 2], [9, 11, 43], [4]]
     expected = {'0,1': 1, '0,2': 2, '1,2': 3}
     actual = WorkflowManager._remove_extra_pairs(vert_ints, combos)
     self.assertSequenceEqual(expected, actual)
예제 #28
0
 def test_output_2(self, mock_lily):
     # ensure output() calls _make_lilypond() as required
     # 1: prepare
     lily_path = u'the_path'
     mock_lily.return_value = lily_path
     test_wc = WorkflowManager([])
     test_wc._previous_exp = u'intervals'
     test_wc._data = [1 for _ in xrange(20)]
     test_wc._result = MagicMock(spec=pandas.DataFrame)
     path = u'pathname!'
     expected_args = [path]
     # 2: run
     actual = test_wc.output('LilyPond', path)
     # 3: check
     self.assertEqual(lily_path, actual)
     mock_lily.assert_called_once_with(*expected_args)
    def test_intervals_7(self):  # TODO: add a frequency-counted test
        """same as test_6 *but* no quality"""
        # NB: the "expected" was hand-counted
        expected = pandas.read_csv(os.path.join(VIS_PATH, 'tests', 'expecteds', 'bwv77', 'SA_intervals_nq.csv'),
                                   comment='#', index_col=0, header=[0, 1], quotechar="'", dtype='object')

        test_wm = WorkflowManager([os.path.join(VIS_PATH, 'tests', 'corpus', 'bwv77.mxl')])
        test_wm.load('pieces')
        test_wm.settings(0, 'voice combinations', '[[0, 1]]')
        test_wm.settings(None, 'count frequency', False)
        test_wm.settings(None, 'interval quality', False)
        actual = test_wm.run('intervals')

        self.assertEqual(1, len(actual))
        actual = actual[0].dropna()
        self.assertDataFramesEqual(expected, actual)
예제 #30
0
 def test_output_5(self, mock_table):
     """ensure output() calls export() as required"""
     # 1: prepare
     export_path = 'the_path'
     mock_table.return_value = export_path
     test_wc = WorkflowManager([])
     test_wc._previous_exp = 'intervals'
     test_wc._data = [1 for _ in range(20)]
     test_wc._result = MagicMock(spec=pandas.DataFrame)
     path = 'pathname!'
     expected_args = ['Excel', path, None, None]
     # 2: run
     actual = test_wc.output('Excel', path)
     # 3: check
     self.assertEqual(export_path, actual)
     mock_table.assert_called_once_with(*expected_args)
예제 #31
0
 def test_extra_pairs_2(self):
     # testing WorkflowManager._remove_extra_pairs()
     # --> when no pairs are desired
     vert_ints = {'0,1': 1, '0,2': 2, '1,2': 3}
     combos = []
     expected = {}
     actual = WorkflowManager._remove_extra_pairs(vert_ints, combos)
     self.assertSequenceEqual(expected, actual)
예제 #32
0
 def test_extra_pairs_3(self):
     # testing WorkflowManager._remove_extra_pairs()
     # --> when there are desired pairs, but they are not present
     vert_ints = {'0,1': 1, '0,2': 2, '1,2': 3}
     combos = [[4, 20], [11, 12]]
     expected = {}
     actual = WorkflowManager._remove_extra_pairs(vert_ints, combos)
     self.assertSequenceEqual(expected, actual)
예제 #33
0
 def test_intervals_4(self):
     """test all combinations of madrigal51 with rests"""
     test_wm = WorkflowManager(
         [os.path.join(VIS_PATH, 'tests', 'corpus', 'madrigal51.mxl')])
     test_wm.load('pieces')
     test_wm.settings(0, 'voice combinations', 'all pairs')
     test_wm.settings(None, 'include rests', True)
     actual = test_wm.run('intervals')
     self.assertEqual(1, len(actual.columns))
     actual = actual['aggregator.ColumnAggregator']
     exp_ind = list(IntervalsTests.EXPECTED_4.index)
     act_ind = list(actual.index)
     for ind_item in exp_ind:
         self.assertTrue(ind_item in act_ind)
     for ind_item in exp_ind:
         self.assertEqual(IntervalsTests.EXPECTED_4[ind_item],
                          actual[ind_item])
    def test_intervs_2(self, mock_guc, mock_rfa, mock_rep):
        """Ensure _intervs() calls everything in the right order, with the right args & settings.
           Same as test_intervs_1() but:
              - calls _remove_extra_pairs(), and
              - doesn't call _run_freq_agg()."""
        mock_guc.return_value = [[0, 1]]
        voice_combos = str(mock_guc.return_value)
        exp_voice_combos = ['0,1']
        test_settings = {'simple or compound': 'compound', 'quality': False}
        test_pieces = [MagicMock(spec_set=IndexedPiece) for _ in range(3)]
        returns = ['get_data() {}'.format(i) for i in range(len(test_pieces))]
        for piece in test_pieces:
            piece.get_data.side_effect = lambda *x: returns.pop(0)
        exp_into_mock_rep = [
            'get_data() {}'.format(i) for i in range(len(test_pieces))
        ]
        mock_rep_returns = [
            'IndP-{} no pairs'.format(i) for i in range(len(test_pieces))
        ]
        mock_rep.side_effect = lambda *x: mock_rep_returns.pop(0)
        expected = [
            'IndP-{} no pairs'.format(i) for i in range(len(test_pieces))
        ]
        exp_analyzers = [noterest.NoteRestIndexer, interval.IntervalIndexer]
        exp_mock_guc = [mock.call(i) for i in range(len(test_pieces))]

        test_wc = WorkflowManager(test_pieces)
        test_wc.settings(None, 'include rests', True)
        test_wc.settings(None, 'count frequency', False)
        test_wc.settings(None, 'voice combinations', voice_combos)
        actual = test_wc._intervs()  # pylint: disable=protected-access

        self.assertSequenceEqual(exp_mock_guc, mock_guc.call_args_list)
        self.assertEqual(len(test_pieces), len(expected), len(actual))
        self.assertEqual(0, mock_rfa.call_count)
        self.assertEqual(len(test_pieces), mock_rep.call_count)
        for i in range(len(test_pieces)):
            mock_rep.assert_any_call(exp_into_mock_rep[i], exp_voice_combos)
        for piece in test_pieces:
            piece.get_data.assert_called_once_with(exp_analyzers,
                                                   test_settings)
        for i in range(len(actual)):
            self.assertSequenceEqual(expected[i], actual[i])
예제 #35
0
 def test_intervals_5(self):
     """test all combinations of vis_Test_Piece"""
     test_wm = WorkflowManager(
         [os.path.join(VIS_PATH, 'tests', 'corpus', 'vis_Test_Piece.xml')])
     test_wm.load('pieces')
     test_wm.settings(0, 'voice combinations', 'all pairs')
     test_wm.settings(None, 'include rests', True)
     expected = pandas.read_csv(os.path.join(VIS_PATH, 'tests', 'corpus',
                                             'test_intervals_5.csv'),
                                index_col=0)
     actual = test_wm.run('intervals')
     self.assertEqual(1, len(actual.columns))
     self.assertSequenceEqual(list(expected.columns), list(actual.columns))
     for col_name in expected.columns:
         self.assertEqual(len(expected[col_name]), len(actual[col_name]))
         for each_interval in expected[col_name].index:
             # NOTE: for whatever reason, the "expected" file always imports with an Int64Index,
             #       so .loc() won't find things properly unless we give the int64 index to the
             #       expected and the str index to the actual
             self.assertEqual(expected[col_name].loc[each_interval],
                              actual[col_name].loc[str(each_interval)])
예제 #36
0
    def test_intervals_6(self):  # TODO: add a frequency-counted test
        """test Soprano and Alto of bwv77; with quality; not counting frequency"""
        # NB: the "expected" was hand-counted
        expected = pandas.read_csv(os.path.join(VIS_PATH, 'tests', 'expecteds',
                                                'bwv77', 'SA_intervals.csv'),
                                   comment='#',
                                   index_col=0,
                                   header=[0, 1],
                                   quotechar="'")

        test_wm = WorkflowManager(
            [os.path.join(VIS_PATH, 'tests', 'corpus', 'bwv77.mxl')])
        test_wm.load('pieces')
        test_wm.settings(0, 'voice combinations', '[[0, 1]]')
        test_wm.settings(None, 'count frequency', False)
        test_wm.settings(None, 'interval quality', True)
        actual = test_wm.run('intervals')

        self.assertEqual(1, len(actual))
        actual = actual[0].dropna()
        self.assertDataFramesEqual(expected, actual)
    def test_intervs_4(self):
        """Ensure _intervs() fails when given an impossible 'voice pair'."""
        test_pieces = [MagicMock(spec_set=IndexedPiece) for _ in range(3)]
        returns = ['get_data() {}'.format(i) for i in range(len(test_pieces))]
        for piece in test_pieces:
            piece.get_data.side_effect = lambda *x: returns.pop(0)
        exp_err_msg = WorkflowManager._REQUIRE_PAIRS_ERROR.format(3)  # pylint: disable=protected-access

        test_wc = WorkflowManager(test_pieces)
        test_wc.settings(None, 'include rests', True)
        test_wc.settings(None, 'voice combinations',
                         '[[0, 1, 2]]')  # that's not a pair!

        self.assertRaises(RuntimeError, test_wc._intervs)  # pylint: disable=protected-access
        try:
            test_wc._intervs()  # pylint: disable=protected-access
        except RuntimeError as run_err:
            self.assertEqual(exp_err_msg, run_err.args[0])
예제 #38
0
 def test_intervals_1(self):
     """test the two highest voices of bwv77"""
     test_wm = WorkflowManager(
         [os.path.join(VIS_PATH, 'tests', 'corpus', 'bwv77.mxl')])
     test_wm.load('pieces')
     test_wm.settings(0, 'voice combinations', '[[0, 1]]')
     actual = test_wm.run('intervals')
     self.assertEqual(1, len(actual.columns))
     actual = actual['aggregator.ColumnAggregator']
     exp_ind = list(IntervalsTests.EXPECTED_1.index)
     act_ind = list(actual.index)
     for ind_item in exp_ind:
         self.assertTrue(ind_item in act_ind)
     for ind_item in exp_ind:
         self.assertEqual(IntervalsTests.EXPECTED_1[ind_item],
                          actual[ind_item])
예제 #39
0
def import_files(request):
    """
    Called with the /api/import URL to load files into the WorkflowManager and return the metadata
    it discovers.
    """
    filepaths = [
        piece.file.path
        for piece in Piece.objects.filter(user_id=request.session.session_key)
    ]
    workm = WorkflowManager(filepaths)
    workm.load('pieces')
    request.session['workm'] = workm
    return [{
        "Filename": os.path.basename(workm.metadata(i, 'pathname')),
        "Title": workm.metadata(i, 'title'),
        "Part Names": workm.metadata(i, 'parts'),
        "Offset": None,
        "Part Combinations": None,
        "Repeat Identical": False
    } for i in xrange(len(workm))], 200
예제 #40
0
class WorkflowWrapper(QAbstractTableModel):
    """
    This is a wrapper class for the :class:`vis.workflow.WorkflowManager` that allows its use as a
    :class:`QAbstractTableModel` for PyQt4. This class only wraps :meth:`metadata` and
    :meth:`setting`, which are those methods needed by PyQt. For all other :class:`Workflowmanager`
    methods, access the internally-stored instance with :meth:`get_workflow_manager`.

    ** How to Use the WorkflowWrapper: **

    The :class:`WorkflowWrapper` always returns valid values, and will not raise exceptions of its
    own. However, "valid" values are not always "correct" or "expected." We recommend you use the
    :class:`WorkflowWrapper` like this:

    #. Instantiate the object.
    #. Set the object as the model for its view.
    #. Call :meth:`insertRows` with the total number of pieces to be added.
    #. Call :meth:`setData` once per piece to set the pathname.
    #. Once each row has a pathname, the object will instantiate its internal
        :class:`WorkflowManager` instance and call its :meth:`load` method to import the score,
        run the :class:`NoteRestIndexer`, and save its metadata.
    #. Subsequent calls to :meth:`data` will return the most correct information available.

    ** How not to Use the WorkflowWrapper: **

    We recommend you do not use the :class:`WorkflowWrapper` like this:

    * Do not add pieces by calling :meth:`insertRows` then :meth:`setData` with the pathname, then
        :meth:`insertRows` then :meth:`setData` with the pathname, and so on. In this case, the
        :class:`WorkflowWrapper` would create a new :class:`WorkflowManager` after each call to
        :meth:`setData`, which would import each piece many times.
    * Do not add pieces after you modify a metadata or setting field. When you add a piece, a new
        :class:`WorkflowManager` instance is created. The new instance replaces any customized
        settings and metadata with the default values.
    * Do not call :meth:`data` before you add the pathnames of all pieces. Real metadata is only
        available after the :class:`WorkflowManager` is created, which happens after all the pieces
        have a pathname. If you call :meth:`data` when there is no :class:`WorkflowManager`, the
        return value will always be ``None``.

    ** Columns in the Data Model: **

    The :class:`WorkflowWrapper` creates a two-dimensional data model, where each row represents an
    :class:`IndexedPiece` stored in the :class:`WorkflowManager` and each column represents either
    a setting or a metadatum field. The following six fields are different for each piece, and
    should be displayed in the :class:`QTableView` widget:

    * filename
    * title
    * parts_list
    * offset_interval
    * parts_combinations
    * repeat_identical

    The :class:`WorkflowManager` additionally wraps these data fields, which are shared by all
    pieces, and will therefore not apear in the :class:`QTableView` widget:

    * quality
    * simple_ints

    Use class properties with those names to specify columns to :meth:`data` and :meth:`getData`.
    For example:

    >>> workm.data((0, WorkflowWrapper.title), Qt.DisplayRole)
    u'02_eleva'
    >>> workm.setData((0, WorkflowWrapper.title), u'Elevator Love Letter', Qt.EditRole)
    >>> workm.data((0, WorkflowWrapper.parts_list), Qt.DisplayRole)
    [u'Amy Milan', u'Torquil Campbell', u'Evan Cranley', u'Chris Seligman', u'Pat McGee']
    """

    # Public class variables to track which column has which data
    # NOTE: Update _num_cols whenever you change the number of columns,
    #       since this variable is used by columnCount().
    # NOTE: Update _header_names whenever you change the number or definition of
    #       columns, since this variale is used by headerData().
    _num_cols = 6
    _header_names = [
        'Path', 'Title', 'List of Part Names', 'Offset Interval',
        'Part Combinations', 'Repeat Identical'
    ]
    # displayed fields
    filename = 0
    title = 1
    parts_list = 2
    offset_interval = 3
    parts_combinations = 4
    repeat_identical = 5

    # non-displayed fields
    quality = 100
    simple_ints = 101

    # instead of DisplayRole; used to tell data() to return the list of part names as a list
    ListRole = 4000

    # when a value hasn't been set, return a QVariant with this in it
    default_value = u'(unset)'

    def __init__(self, parent=QModelIndex()):
        """
        Create a new :class:`WorkflowWrapper` instance.
        """
        super(WorkflowWrapper, self).__init__()
        self._pathnames = [
        ]  # hold a list of pathnames for before the WorkflowManager
        self._workm = None  # hold the WorkflowManager
        self._settings_changed = False  # whether setData() was called (for settings_changed())
        self._when_done_import = None  # method to call when we're finished importing

    def rowCount(self, parent=QModelIndex()):
        """
        Return the number of pieces in this list. If the internal :class:`WorkflowManager` exists,
        this is the number of piece stored there; otherwise it is the number of places for
        pathnames.

        :returns: The number of pieces in this list.
        :rtype: ``int``
        """
        if self._workm is None:
            return len(self._pathnames)
        else:
            return len(self._workm)

    def columnCount(self, parent=QModelIndex()):
        "Return the number of columns in this WorkflowWrapper."
        return WorkflowWrapper._num_cols

    def data(self, index, role):
        """
        Get the data for the piece and metadatum or setting specified. Only the "parts_list" column
        responds to the WorkflowWrapper.ListRole, in which case a list of strings is returned
        instead of a comma-separated list of part names.

        :param index: The row-and-column index you wish to access. Either you can use a
            :class:`QModelIndex` or a 2-tuple where the first element is an ``int`` representing the
            index of the piece in the models, and the second element is one of the class properties
            described above in "Columns in the Data Model."
        :type index: :class:`QModelIndex` or 2-tuple of ``int``

        :param role: Either Qt.DisplayRole or WorkflowWrapper.ListRole
        :type role: ``int``

        :returns: The requested data or, if ``index`` or ``role`` is invalid, ``None``.
        :rtype: :class:`QVariant`

        .. note:: The method always returns a :class:`QVariant`. Access the Python object with the
            :meth:`toPyObject` method.

        .. note:: If the internal :class:`WorkflowManager` has not been instantiated, the return
            value is always ``None``.

        .. note:: This method never actually returns ``None``, but rather an empty :class:`QVariant`
            that will be ``None`` when you call :meth:`toPyObject` on it.
        """
        if self._workm is None or (Qt.DisplayRole != role
                                   and WorkflowWrapper.ListRole != role):
            return QVariant()

        # Set the row and column
        row = None
        column = None
        if isinstance(index, QModelIndex):
            # if the QModelIndex is invalid, we won't bother with it
            if not index.isValid():
                return QVariant()
            # otherwise, get the row and column from the QModelIndex
            row = index.row()
            column = index.column()
        else:
            row = index[0]
            column = index[1]

        # Verify the row and column
        if row >= self.rowCount() or column >= self._num_cols and \
        (column != WorkflowWrapper.quality and column != WorkflowWrapper.simple_ints):
            return QVariant()

        post = None
        if Qt.DisplayRole == role:
            # displayed fields
            if WorkflowWrapper.filename == column:
                post = self._workm.metadata(row, u'pathname')
            elif WorkflowWrapper.title == column:
                post = self._workm.metadata(row, u'title')
            elif WorkflowWrapper.parts_list == column:
                post = u', '.join(self._workm.metadata(row, u'parts'))
            elif WorkflowWrapper.offset_interval == column:
                post = self._workm.settings(row, u'offset interval')
            elif WorkflowWrapper.parts_combinations == column:
                post = self._workm.settings(row, u'voice combinations')
            elif WorkflowWrapper.repeat_identical == column:
                # the wording in the GUI and WorkflowManager has opposite meanings
                post = not self._workm.settings(row, u'filter repeats')
            # non-displayed fields
            elif WorkflowWrapper.quality == column:
                post = self._workm.settings(None, u'interval quality')
            elif WorkflowWrapper.simple_ints == column:
                post = self._workm.settings(None, u'simple intervals')
            else:
                post = QVariant()
        elif WorkflowWrapper.ListRole == role:
            if WorkflowWrapper.parts_list == column:
                post = self._workm.metadata(row, u'parts')
            else:
                post = QVariant()
        else:
            post = QVariant()

        if not isinstance(post, QVariant):
            if post is None:
                post = WorkflowWrapper.default_value
            post = QVariant(post)
        return post

    def headerData(self, section, orientation, role):
        """
        Return the column names for a WorkflowWrapper instance.

        Arguments:
        - section: the index of the column you want the name of
        - orientation: should be Qt.Horizontal; Qt.Vertical is ignored
        - role: should be Qt.DisplayRole; others are ignored

        If the section index is out of range, or the orientation or role is
        different than expected, an empty QVariant is returned.
        """
        # All of the column titles are stored as class variables. I decided to
        # use the class name here, rather than "self," just in case they were
        # accidentally changed in this instance. We do not want to allow that.
        if Qt.Horizontal == orientation and Qt.DisplayRole == role and \
        0 <= section < WorkflowWrapper._num_cols:
            return WorkflowWrapper._header_names[section]
        else:
            return QVariant()

    def setData(self, index, value, role):
        """
        Set the data for the piece and metadatum or setting specified. If the internal
            :class:`WorkflowManager` has not yet been created and this is the last pathname added,
            instantiate the :class:`WorkflowManager` and call :meth:`load`.

        :param index: The row-and-column index you wish to access. Either you can use a
            :class:`QModelIndex` or a 2-tuple where the first element is an ``int`` representing the
            index of the piece in the models, and the second element is one of the class properties
            described above in "Columns in the Data Model."
        :type index: :class:`QModelIndex` or 2-tuple of ``int``

        :param value: The desired value of the setting or metadatum. If you submit a
            :class:`QVariant`, we will call :meth:`toPyObject` before sending to the
            :class:`WorkflowManager`.
        :type value: :class:`QVariant` or any

        :param role: This should be Qt.EditRole.
        :type role: :class:`EditRole`

        :returns: Whether the data was successfully set.
        :rtype: ``True`` or ``False``

        .. note:: If the internal :class:`WorkflowManager` has not been instantiated, you can only
            set the ``pathname`` field. All other calls to :meth:`setData` will fail.
        """

        if Qt.EditRole != role:
            return False

        # Set the row and column
        row = None
        column = None
        if isinstance(index, QModelIndex):
            # if the QModelIndex is invalid, we won't bother with it
            if not index.isValid():
                return False
            # otherwise, get the row and column from the QModelIndex
            row = index.row()
            column = index.column()
        else:
            row = index[0]
            column = index[1]
            index = self.createIndex(row, column)

        # Verify the row and column
        if row >= self.rowCount() or column >= self._num_cols and \
        (column != WorkflowWrapper.quality and column != WorkflowWrapper.simple_ints):
            return False

        set_val = value.toPyObject() if isinstance(value, QVariant) else value

        # ensure we're trying to set a valid thing
        if self._workm is None:
            if WorkflowWrapper.filename != column:
                return False
            else:
                self._pathnames[row] = set_val
                ch_ind_1, ch_ind_2 = None, None
                if all(self._pathnames):
                    self._workm = WorkflowManager(self._pathnames)
                    self._workm.load(u'pieces')
                    # now that we imported, all the data's changed
                    ch_ind_1 = self.createIndex(0, 0)
                    ch_ind_2 = self.createIndex(len(self), self._num_cols - 1)
                    # let the GUI know
                    self._when_done_import()
                else:
                    # only one cell has changed
                    ch_ind_1 = ch_ind_2 = self.createIndex(row, column)
                self.dataChanged.emit(ch_ind_1, ch_ind_2)
                return True

        # displayed fields
        if WorkflowWrapper.filename == column:
            self._workm.metadata(row, u'pathname', set_val)
        elif WorkflowWrapper.title == column:
            self._workm.metadata(row, u'title', set_val)
        elif WorkflowWrapper.parts_list == column:
            self._workm.metadata(row, u'parts', set_val)
        elif WorkflowWrapper.offset_interval == column:
            self._workm.settings(row, u'offset interval', set_val)
        elif WorkflowWrapper.parts_combinations == column:
            self._workm.settings(row, u'voice combinations', set_val)
        elif WorkflowWrapper.repeat_identical == column:
            # the wording in the GUI and WorkflowManager has opposite meanings
            self._workm.settings(row, u'filter repeats', not set_val)
        # non-displayed fields
        elif WorkflowWrapper.quality == column:
            self._workm.settings(None, u'interval quality', set_val)
        elif WorkflowWrapper.simple_ints == column:
            self._workm.settings(None, u'simple intervals', set_val)
        else:
            return False
        self._settings_changed = True
        self.dataChanged.emit(index, index)
        return True

    def insertRows(self, row, count, parent=QModelIndex()):
        """
        Append new rows to the data model. Yes---append, not insert.

        :param row: An argument that will be ignored.
        :type row: any
        :param count: The number of rows you want to append.
        :type count: ``int``

        .. note:: If the internal :class:`WorkflowManager` already exists, it is destroyed and all
            metadata and settings are lost.

        .. note:: We recommend you add all the rows you will need before you call :meth:`setData`
            to set the pathnames of the newly-added rows.
        """
        if self._workm is not None:
            self._workm = None
        self.beginInsertRows(parent, len(self._pathnames),
                             len(self._pathnames) + count - 1)
        self._pathnames.extend([None for _ in xrange(count)])
        self.endInsertRows()

    def removeRows(self, row, count, parent=QModelIndex()):
        """
        This is the opposite of insertRows(), and the arguments work in the same
        way.
        """
        pass

    def __len__(self):
        "Alias for rowCount()."
        return self.rowCount()

    def __getitem__(self, index):
        "It's __getitem__(), what do you want?!"
        return self._workm[index]

    def connect_workflow_signals(self, finished_import):
        """
        Connect the WorkflowManager's PyQt signals to the methods or functions given here.

        "finished_import" is for the WorkM's "finished_import" signal.
        """
        print('--> type: ' + str(finished_import))  # DEBUG
        self._when_done_import = finished_import
        #self._workm.finished_import.connect(finished_import)
        #pass

    def get_workflow_manager(self):
        """
        Get the internal :class:`WorkflowManager` instance.
        """
        return self._workm

    def settings_changed(self):
        """
        Know whether there has been a call to :meth:`setData` since the last time this method was
        called.
        """
        ret = self._settings_changed
        self._settings_changed = False
        return ret
예제 #41
0
    def setData(self, index, value, role):
        """
        Set the data for the piece and metadatum or setting specified. If the internal
            :class:`WorkflowManager` has not yet been created and this is the last pathname added,
            instantiate the :class:`WorkflowManager` and call :meth:`load`.

        :param index: The row-and-column index you wish to access. Either you can use a
            :class:`QModelIndex` or a 2-tuple where the first element is an ``int`` representing the
            index of the piece in the models, and the second element is one of the class properties
            described above in "Columns in the Data Model."
        :type index: :class:`QModelIndex` or 2-tuple of ``int``

        :param value: The desired value of the setting or metadatum. If you submit a
            :class:`QVariant`, we will call :meth:`toPyObject` before sending to the
            :class:`WorkflowManager`.
        :type value: :class:`QVariant` or any

        :param role: This should be Qt.EditRole.
        :type role: :class:`EditRole`

        :returns: Whether the data was successfully set.
        :rtype: ``True`` or ``False``

        .. note:: If the internal :class:`WorkflowManager` has not been instantiated, you can only
            set the ``pathname`` field. All other calls to :meth:`setData` will fail.
        """

        if Qt.EditRole != role:
            return False

        # Set the row and column
        row = None
        column = None
        if isinstance(index, QModelIndex):
            # if the QModelIndex is invalid, we won't bother with it
            if not index.isValid():
                return False
            # otherwise, get the row and column from the QModelIndex
            row = index.row()
            column = index.column()
        else:
            row = index[0]
            column = index[1]
            index = self.createIndex(row, column)

        # Verify the row and column
        if row >= self.rowCount() or column >= self._num_cols and \
        (column != WorkflowWrapper.quality and column != WorkflowWrapper.simple_ints):
            return False

        set_val = value.toPyObject() if isinstance(value, QVariant) else value

        # ensure we're trying to set a valid thing
        if self._workm is None:
            if WorkflowWrapper.filename != column:
                return False
            else:
                self._pathnames[row] = set_val
                ch_ind_1, ch_ind_2 = None, None
                if all(self._pathnames):
                    self._workm = WorkflowManager(self._pathnames)
                    self._workm.load(u'pieces')
                    # now that we imported, all the data's changed
                    ch_ind_1 = self.createIndex(0, 0)
                    ch_ind_2 = self.createIndex(len(self), self._num_cols - 1)
                    # let the GUI know
                    self._when_done_import()
                else:
                    # only one cell has changed
                    ch_ind_1 = ch_ind_2 = self.createIndex(row, column)
                self.dataChanged.emit(ch_ind_1, ch_ind_2)
                return True

        # displayed fields
        if WorkflowWrapper.filename == column:
            self._workm.metadata(row, u'pathname', set_val)
        elif WorkflowWrapper.title == column:
            self._workm.metadata(row, u'title', set_val)
        elif WorkflowWrapper.parts_list == column:
            self._workm.metadata(row, u'parts', set_val)
        elif WorkflowWrapper.offset_interval == column:
            self._workm.settings(row, u'offset interval', set_val)
        elif WorkflowWrapper.parts_combinations == column:
            self._workm.settings(row, u'voice combinations', set_val)
        elif WorkflowWrapper.repeat_identical == column:
            # the wording in the GUI and WorkflowManager has opposite meanings
            self._workm.settings(row, u'filter repeats', not set_val)
        # non-displayed fields
        elif WorkflowWrapper.quality == column:
            self._workm.settings(None, u'interval quality', set_val)
        elif WorkflowWrapper.simple_ints == column:
            self._workm.settings(None, u'simple intervals', set_val)
        else:
            return False
        self._settings_changed = True
        self.dataChanged.emit(index, index)
        return True