def test_init(self): aTree1 = Tree(3) self.assertEqual(3, aTree1.getNode()) self.assertEqual([], aTree1.getChildren()) aTree2 = Tree(4, [Tree(3), Tree(5)]) self.assertEqual(4, aTree2.getNode()) self.assertEqual(2, len(aTree2.getChildren()))
class Foo(QtGui.QMainWindow): def __init__(self): super(Foo, self).__init__() self.initUI() def initUI(self): config = Foo.readConfig('options') self.timeOut = -1 self.radio = False self.statusBar().showMessage('Ready') self.createMenu() self.setWindowTitle("Foo.cd") self.player = Player(Foo.readConfig('audio')) self.player.bus.connect('message::eos', self.stop) self.player.bus.connect('message::duration-changed', self.onDurationChanged) self.tree = Tree(self, config['tree_order']) self.tree.addSongs.connect(self.addSongsFromTree) self.tree.customContextMenuRequested.connect(self.tmpTag) if not self.radio: self.table = Table(self, config) self.handlerATF = self.player.playbin.connect( "about-to-finish", self.onAboutToFinish) self.table.runAction.connect(self.tableAction) else: configRadio = Foo.readConfigRadios() self.table = TableRadio(self, configRadio) self.table.runAction.connect(self.tableAction) self.handlerT = self.player.bus.connect('message::tag', self.table.onTag) self.playbackButtons = PlaybackButtons(None) self.playbackButtons.buttonPlay.clicked.connect(self.toggleSong) self.playbackButtons.buttonStop.clicked.connect(self.stop) self.playbackButtons.buttonPrev.clicked.connect(self.previous) self.playbackButtons.buttonNext.clicked.connect(self.next) self.volumeSlider = VolumeSlider(self) self.volumeSlider.sliderMoved.connect(self.player.setVolume) self.scrollSlider = ScrollSlider(self) self.scrollSlider.sliderPressed.connect(self.player.toggle) self.scrollSlider.sliderReleased.connect(self.player.toggle) self.scrollSlider.sliderMoved.connect(self.player.seek) self.pixmap = Image(self, config['cover_names'], config['extensions']) # Album cover connections self.tree.selectionModel().selectionChanged.connect( lambda: self.pixmap.onSelectionChanged(self.tree.getChildren()[0]. get('file', None))) self.table.selectionModel().selectionChanged.connect( lambda: self.pixmap.onSelectionChanged(self.table.getSelection(). get('file', None))) self.searchArea = SearchArea(self) self.searchArea.searchLine.returnPressed.connect(self.startSearch) self.playbackButtons.addWidget(self.volumeSlider) self.playbackButtons.addWidget(self.scrollSlider) splitterLeftRight = QtGui.QSplitter() self.splitterTopBottom = QtGui.QSplitter(Qt.Vertical, self) self.infoFrame = QtGui.QFrame() infoLayout = QtGui.QVBoxLayout() infoLayout.setContentsMargins(0, 0, 0, 0) infoLayout.addLayout(self.playbackButtons) infoLayout.addWidget(self.pixmap) self.infoFrame.setLayout(infoLayout) libLayout = QtGui.QVBoxLayout() libLayout.setContentsMargins(0, 0, 0, 0) libLayout.addWidget(self.tree) libLayout.addLayout(self.searchArea) libFrame = QtGui.QFrame() libFrame.setLayout(libLayout) self.splitterTopBottom.addWidget(self.table) self.splitterTopBottom.addWidget(self.infoFrame) self.splitterTopBottom.setStretchFactor(0, 1) #self.splitterTopBottom.setStretchFactor(1,0) splitterLeftRight.addWidget(libFrame) splitterLeftRight.addWidget(self.splitterTopBottom) splitterLeftRight.setStretchFactor(0, 2) splitterLeftRight.setStretchFactor(1, 3) mainLayout = QtGui.QGridLayout() mainLayout.setContentsMargins(4, 4, 4, 4) mainLayout.addWidget(splitterLeftRight) dummyWidget = QtGui.QWidget() dummyWidget.setLayout(mainLayout) self.setCentralWidget(dummyWidget) self.setTabOrder(self.tree, self.table) dictShortcuts = self.readConfig('shortcuts') modifier = dictShortcuts['modifier'] + '+' self.shortQuit = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['quit']), self, self.close) self.shortStop = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['stop']), self, self.stop) self.shortPlayPause = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['play_pause']), self, self.toggleSong) self.shortSongPrevious = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['previous']), self, self.previous) self.shortSongNext = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['next']), self, self.next) self.shortVolDown = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['volume_down']), self, self.volumeSlider.decr) self.shortVolUp = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['volume_up']), self, self.volumeSlider.incr) self.shortRadioMode = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['radio_mode']), self, self.toggleRadio) self.shortEqualizer = QtGui.QShortcut( QtGui.QKeySequence(modifier + dictShortcuts['equalizer']), self, self.openEqualizer) thread = QtCore.QThread(self) thread.worker = WorkThreadPipe() thread.worker.moveToThread(thread) thread.started.connect(thread.worker.process) thread.worker.hotKey.connect(self.onHotKey) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.start() self.show() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Alt: self.menuBar().setVisible(not self.menuBar().isVisible()) else: QWidget.keyPressEvent(self, event) # Triggered by player end of stream event # or called by hand to stop the stream def stop(self, bus=None, msg=None): self.player.stop() self.scrollSlider.setValue(0) self.table.displayPlayToStop() self.stopStatusEmission('Ready') def previous(self): if self.table.playingId > 0: self.player.stop() self.table.playingId -= 1 self.player.add(self.table.model().item(self.table.playingId, 0).data()['file']) self.player.play() def next(self): if self.table.model().rowCount() - 1 > self.table.playingId: self.player.stop() self.table.playingId += 1 self.player.add(self.table.model().item(self.table.playingId, 0).data()['file']) self.player.play() def toggleSong(self): state = self.player.playbin.get_state(Gst.State.NULL) if state[1] == Gst.State.PLAYING: self.table.displayPlayToPause() self.player.toggle() status = self.statusBar().currentMessage().replace( 'Playing', 'Paused') self.stopStatusEmission(status) else: self.table.displayPauseToPlay(self.table.playingId) self.player.toggle() #self.onDurationChanged(0,0) status = self.table.getStatus() self.setStatusEmission(status) # Triggered by player when a song starts def onDurationChanged(self, bus, msg): self.table.displayNext() print('Duration changed signal !') filename = self.table.model().item(self.table.playingId, 0).data()['file'][7:] data = wave.getDBData(filename) wave.createImg(data) self.scrollSlider.setStyleSheet("border-image: url(./wave.png)") # Triggered by player at the end of a song def onAboutToFinish(self, bus): if self.table.model().rowCount() - 1 > self.table.playingId: print('About to finish !') self.table.playingId += 1 self.player.add(self.table.model().item(self.table.playingId, 0).data()['file']) def addSongsFromTree(self, list, play): if not self.radio: i = self.table.model().rowCount() for l in list: self.table.addRow(l) self.table.resizeRowsToContents() if play: self.stop() self.player.add(list[0]['file']) self.player.play() self.table.displayStopToPlay(i) status = self.table.getStatus() self.setStatusEmission(status) def setStatusEmission(self, status): if self.timeOut > 0: GObject.source_remove(self.timeOut) self.timeOut = GObject.timeout_add(1000, self.update, status) def stopStatusEmission(self, status): if self.timeOut > 0: GObject.source_remove(self.timeOut) self.timeOut = GObject.timeout_add(0, self.update, status) self.timeOut = -1 def update(self, status): print('.') try: duration_nanosecs = self.player.getDuration() duration = float(duration_nanosecs) / 1000000000 self.scrollSlider.setRange(0, duration) nanosecs = self.player.getPosition() position = float(nanosecs) // 1000000000 self.scrollSlider.setValue(position) m, s = divmod(position, 60) self.statusBar().showMessage( status.replace('%', "%02d:%02d" % (m, s))) except Exception as e: print(e) pass if 'Playing' in status: return True else: return False def tableAction(self, str): if str == 'stop': self.stop() elif str == 'play': if self.table.selectedIndexes(): index = self.table.selectedIndexes()[0] else: index = self.table.model().index( self.table.selectionModel().currentIndex().row(), 0) songURI = index.model().itemFromIndex(index).data()['file'] self.player.stop() self.player.add(songURI) self.player.play() self.table.displayStopToPlay(index.row()) status = self.table.getStatus() self.setStatusEmission(status) @staticmethod def readConfig(section): parser = RawConfigParser() if getattr(sys, 'frozen', False): # frozen parser.read( os.path.dirname(os.path.realpath(sys.executable)) + '/config') else: # unfrozen parser.read( os.path.dirname(os.path.realpath(__file__)) + '/config') return dict(parser.items(section)) #Create menu bar def createMenu(self): self.menuBar() self.menuBar().setVisible(False) actionMenu = self.menuBar().addMenu('&Action') scanMusicFolderAction = QtGui.QAction('Scan Music Folder', self) showShortcutAction = QtGui.QAction('Show Shortcut', self) addFolderToLibraryAction = QtGui.QAction('Add Folder to Library', self) scanWaveformsAction = QtGui.QAction('Scan wave froms', self) #self.toggleRadioAction= QtGui.QAction('Switch to Radio mode',self) if not self.radio: self.toggleRadioAction = QtGui.QAction('Switch to Radio mode', self) else: self.toggleRadioAction = QtGui.QAction('Switch to Library mode', self) scanMusicFolderAction.triggered.connect(self.scanMusicFolder) actionMenu.addAction(scanMusicFolderAction) showShortcutAction.triggered.connect(self.showShortcut) actionMenu.addAction(showShortcutAction) addFolderToLibraryAction.triggered.connect(self.addFolderToLibrary) actionMenu.addAction(addFolderToLibraryAction) scanWaveformsAction.triggered.connect(self.scanWaveforms) actionMenu.addAction(scanWaveformsAction) self.toggleRadioAction.triggered.connect(self.toggleRadio) actionMenu.addAction(self.toggleRadioAction) # Menu Action 1 def scanMusicFolder(self): thread = QtCore.QThread(self) thread.worker = WorkThread( Foo.readConfig('options')['music_folder'], False) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.process) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start() # Menu Action 2 def showShortcut(self): dictSC = Foo.readConfig('shortcuts') message = '''<b>''' + dictSC['modifier'] + '''+''' + dictSC[ 'stop'] + '''</b> : Stop<br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC['quit'] + '''</b> : Quit<br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC[ 'play_pause'] + '''</b> : Play/Pause <br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC[ 'previous'] + '''</b> : Previous<br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC['next'] + '''</b> : Next<br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC[ 'volume_down'] + '''</b> : Volume down<br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC[ 'volume_up'] + '''</b> : Volume up<br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC[ 'radio_mode'] + '''</b> : Toggle radio mode<br/>''' + ''' <b>''' + dictSC['modifier'] + '''+''' + dictSC[ 'equalizer'] + '''</b> : Equalizer<br/>''' print(len(self.findChildren(QtCore.QObject))) box = QMessageBox.about(self, 'About Shortcuts', message) print(len(self.findChildren(QtCore.QObject))) print('must delete') # Menu Action3 # Must be subdirectory of music folder otherwise wont be rescanned def addFolderToLibrary(self): dir = QFileDialog.getExistingDirectory( None, "Open Directory", Foo.readConfig('options')['music_folder'], QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) thread = QtCore.QThread(self) thread.worker = WorkThread(dir, True) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.process) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start() # Menu action 4 def scanWaveforms(self): from wave import Wave thread = QtCore.QThread(self) thread.worker = Wave(Foo.readConfig('options')['music_folder']) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.processScan) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start() # Menu Action5 def toggleRadio(self): self.table.deleteLater() self.table.close() if not self.radio: configRadio = Foo.readConfig('radios') self.table = TableRadio(self.tree, configRadio) self.toggleRadioAction.setText('Switch to Library mode') self.radio = True self.player.playbin.disconnect(self.handlerATF) self.handlerT = self.player.bus.connect('message::tag', self.table.onTag) else: config = Foo.readConfig('options') self.table = Table(self.tree, config) self.toggleRadioAction.setText('Switch to Radio mode') self.radio = False self.handlerATF = self.player.playbin.connect( "about-to-finish", self.onAboutToFinish) self.player.bus.disconnect(self.handlerT) self.splitterTopBottom.addWidget(self.table) # Since the frame is already attached to the splitter, # it only moves it to the new position self.splitterTopBottom.addWidget(self.infoFrame) self.table.runAction.connect(self.tableAction) self.setTabOrder(self.tree, self.table) self.splitterTopBottom.setStretchFactor(0, 10) #self.splitterTopBottom.setStretchFactor(3,1) @QtCore.pyqtSlot() def startSearch(self): input = self.searchArea.searchLine.text() db = thread.load() songList = [] songGenerator = (Song(self.tree.comm, **dict) for dict in db) self.tree.model().removeRows(0, self.tree.model().rowCount()) if self.searchArea.searchExact.isChecked(): songList = [e for e in songGenerator if e.exactMatch(input)] elif self.searchArea.searchPrecise.isChecked(): songList = [e for e in songGenerator if e.preciseMatch(input)] else: songList = [e for e in songGenerator if e.fuzzyMatch(input)] del db[:] songList.sort(key=self.tree.sortFunc) self.tree.populateTree(songList) @QtCore.pyqtSlot(str) def onHotKey(self, key): print('Hotkey was pressed', key) if key == 'quit': self.shortQuit.activated.emit() if key == 'stop': self.shortStop.activated.emit() if key == 'play_pause': self.shortPlayPause.activated.emit() if key == 'volume_up': self.shortVolUp.activated.emit() if key == 'volume_down': self.shortVolDown.activated.emit() if key == 'song_next': self.shortSongNext.activated.emit() if key == 'song_prev': self.shortSongPrev.activated.emit() if key == 'tree_up': if self.radio: self.table.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Up, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Up, Qt.KeyboardModifier(), '')) if key == 'tree_down': if self.radio: self.table.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Down, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Down, Qt.KeyboardModifier(), '')) if key == 'tree_left': if not self.radio: self.tree.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Left, Qt.KeyboardModifier(), '')) if key == 'tree_right': if not self.radio: self.tree.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Right, Qt.KeyboardModifier(), '')) if key == 'tree_validate': if self.radio: self.table.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent( QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(), '')) if key == 'tree_append': if not self.radio: self.tree.keyPressEvent( QtGui.QKeyEvent( QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(QtCore.Qt.ShiftModifier), '')) if key == 'radio_mode': self.shortRadioMode.activated.emit() def tmpTag(self, position): menu = QtGui.QMenu() tagging = QtGui.QAction('Tagging', self) replayGain = QtGui.QAction('ReplayGain', self) tagging.triggered.connect(self.openTagging) replayGain.triggered.connect(self.startReplayGain) menu.addAction(tagging) menu.addAction(replayGain) menu.exec_(self.tree.viewport().mapToGlobal(position)) def startReplayGain(self): children = self.tree.getChildren() self.RG = ReplayGain([x['file'] for x in children]) self.RG.exec_() def openTagging(self): children = self.tree.getChildren() #[7:] to drop the 'file://' appended for gstreamer retag = Retagging([x['file'][7:] for x in children]) res = retag.exec_() if res: self.tree.initUI() print(res) def openEqualizer(self): from configparser import RawConfigParser equa = Equalizer(self, Foo.readConfig('audio')) equa.equalize.connect(self.applyEqua) if equa.exec_(): parser = RawConfigParser() parser.read( os.path.dirname(os.path.realpath(__file__)) + '/config') parser['audio']['settings'] = str(equa.config) with open( os.path.dirname(os.path.realpath(__file__)) + '/config', 'w') as configfile: parser.write(configfile) def applyEqua(self, band, value): print('receiving equa', str(band), value) if str(band) == 'band0' and value == 0: self.player.equalizer.set_property('band0', 0.01) else: self.player.equalizer.set_property(str(band), value)
class Foo(QtGui.QMainWindow): def __init__(self): super(Foo, self).__init__() self.initUI() def initUI(self): config = Foo.readConfig('options') self.timeOut = -1 self.radio = False self.statusBar().showMessage('Ready') self.createMenu() self.setWindowTitle("Foo.cd") self.player = Player(Foo.readConfig('audio')) self.player.bus.connect('message::eos', self.stop) self.player.bus.connect('message::duration-changed', self.onDurationChanged) self.tree = Tree(self, config['tree_order']) self.tree.addSongs.connect(self.addSongsFromTree) self.tree.customContextMenuRequested.connect(self.tmpTag) if not self.radio: self.table=Table( self, config) self.handlerATF = self.player.playbin.connect("about-to-finish", self.onAboutToFinish) self.table.runAction.connect(self.tableAction) else: configRadio = Foo.readConfigRadios() self.table=TableRadio( self, configRadio) self.table.runAction.connect(self.tableAction) self.handlerT = self.player.bus.connect('message::tag', self.table.onTag) self.playbackButtons = PlaybackButtons(None) self.playbackButtons.buttonPlay.clicked.connect(self.toggleSong) self.playbackButtons.buttonStop.clicked.connect(self.stop) self.playbackButtons.buttonPrev.clicked.connect(self.previous) self.playbackButtons.buttonNext.clicked.connect(self.next) self.volumeSlider = VolumeSlider(self) self.volumeSlider.sliderMoved.connect(self.player.setVolume) self.scrollSlider = ScrollSlider(self) self.scrollSlider.sliderPressed.connect(self.player.toggle) self.scrollSlider.sliderReleased.connect(self.player.toggle) self.scrollSlider.sliderMoved.connect(self.player.seek) self.pixmap = Image(self, config['cover_names'], config['extensions']) # Album cover connections self.tree.selectionModel().selectionChanged.connect(lambda: self.pixmap.onSelectionChanged(self.tree.getChildren()[0].get('file', None))) self.table.selectionModel().selectionChanged.connect(lambda: self.pixmap.onSelectionChanged(self.table.getSelection().get('file', None))) self.searchArea = SearchArea(self) self.searchArea.searchLine.returnPressed.connect(self.startSearch) self.playbackButtons.addWidget(self.volumeSlider) self.playbackButtons.addWidget(self.scrollSlider) splitterLeftRight = QtGui.QSplitter() self.splitterTopBottom = QtGui.QSplitter(Qt.Vertical, self) self.infoFrame = QtGui.QFrame() infoLayout = QtGui.QVBoxLayout() infoLayout.setContentsMargins(0,0,0,0) infoLayout.addLayout(self.playbackButtons) infoLayout.addWidget(self.pixmap) self.infoFrame.setLayout(infoLayout) libLayout = QtGui.QVBoxLayout() libLayout.setContentsMargins(0,0,0,0) libLayout.addWidget(self.tree) libLayout.addLayout(self.searchArea) libFrame = QtGui.QFrame() libFrame.setLayout(libLayout) self.splitterTopBottom.addWidget(self.table) self.splitterTopBottom.addWidget(self.infoFrame) self.splitterTopBottom.setStretchFactor(0,1) #self.splitterTopBottom.setStretchFactor(1,0) splitterLeftRight.addWidget(libFrame) splitterLeftRight.addWidget(self.splitterTopBottom) splitterLeftRight.setStretchFactor(0,2) splitterLeftRight.setStretchFactor(1,3) mainLayout = QtGui.QGridLayout() mainLayout.setContentsMargins(4, 4, 4, 4) mainLayout.addWidget(splitterLeftRight) dummyWidget = QtGui.QWidget() dummyWidget.setLayout(mainLayout) self.setCentralWidget(dummyWidget) self.setTabOrder(self.tree, self.table) dictShortcuts = self.readConfig('shortcuts') modifier = dictShortcuts['modifier']+'+' self.shortQuit = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['quit']), self, self.close) self.shortStop = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['stop']), self, self.stop) self.shortPlayPause = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['play_pause']), self, self.toggleSong) self.shortSongPrevious = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['previous']), self, self.previous) self.shortSongNext = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['next']), self, self.next) self.shortVolDown = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['volume_down']), self, self.volumeSlider.decr) self.shortVolUp = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['volume_up']), self, self.volumeSlider.incr) self.shortRadioMode = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['radio_mode']), self, self.toggleRadio) self.shortEqualizer = QtGui.QShortcut(QtGui.QKeySequence(modifier+dictShortcuts['equalizer']), self, self.openEqualizer) thread = QtCore.QThread(self) thread.worker = WorkThreadPipe() thread.worker.moveToThread(thread); thread.started.connect(thread.worker.process) thread.worker.hotKey.connect(self.onHotKey) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.start() self.show() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Alt: self.menuBar().setVisible(not self.menuBar().isVisible()) else: QWidget.keyPressEvent(self, event) # Triggered by player end of stream event # or called by hand to stop the stream def stop(self, bus=None, msg=None): self.player.stop() self.scrollSlider.setValue(0) self.table.displayPlayToStop() self.stopStatusEmission('Ready') def previous(self): if self.table.playingId > 0: self.player.stop() self.table.playingId-=1 self.player.add(self.table.model().item(self.table.playingId,0).data()['file']) self.player.play() def next(self): if self.table.model().rowCount()-1 > self.table.playingId: self.player.stop() self.table.playingId+=1 self.player.add(self.table.model().item(self.table.playingId,0).data()['file']) self.player.play() def toggleSong(self): state = self.player.playbin.get_state(Gst.State.NULL) if state[1] == Gst.State.PLAYING: self.table.displayPlayToPause() self.player.toggle() status = self.statusBar().currentMessage().replace('Playing', 'Paused') self.stopStatusEmission(status) else: self.table.displayPauseToPlay(self.table.playingId) self.player.toggle() #self.onDurationChanged(0,0) status = self.table.getStatus() self.setStatusEmission(status) # Triggered by player when a song starts def onDurationChanged(self, bus, msg): self.table.displayNext() print('Duration changed signal !') filename = self.table.model().item(self.table.playingId,0).data()['file'][7:] data = wave.getDBData(filename) wave.createImg(data) self.scrollSlider.setStyleSheet("border-image: url(./wave.png)") # Triggered by player at the end of a song def onAboutToFinish(self, bus): if self.table.model().rowCount()-1 > self.table.playingId: print('About to finish !') self.table.playingId+=1 self.player.add(self.table.model().item(self.table.playingId,0).data()['file']) def addSongsFromTree(self, list, play): if not self.radio: i = self.table.model().rowCount() for l in list: self.table.addRow(l) self.table.resizeRowsToContents() if play: self.stop() self.player.add(list[0]['file']) self.player.play() self.table.displayStopToPlay(i) status = self.table.getStatus() self.setStatusEmission(status) def setStatusEmission(self, status): if self.timeOut > 0: GObject.source_remove(self.timeOut) self.timeOut = GObject.timeout_add(1000, self.update, status) def stopStatusEmission(self, status): if self.timeOut > 0: GObject.source_remove(self.timeOut) self.timeOut = GObject.timeout_add(0, self.update, status) self.timeOut=-1 def update(self, status): print('.') try: duration_nanosecs = self.player.getDuration() duration = float(duration_nanosecs) / 1000000000 self.scrollSlider.setRange(0, duration) nanosecs = self.player.getPosition() position = float(nanosecs) // 1000000000 self.scrollSlider.setValue(position) m, s = divmod(position, 60) self.statusBar().showMessage(status.replace('%',"%02d:%02d" % (m, s))) except Exception as e: print(e) pass if 'Playing' in status: return True else: return False def tableAction(self, str): if str == 'stop': self.stop() elif str == 'play': if self.table.selectedIndexes(): index = self.table.selectedIndexes()[0] else: index= self.table.model().index(self.table.selectionModel().currentIndex().row(),0) songURI = index.model().itemFromIndex(index).data()['file'] self.player.stop() self.player.add(songURI) self.player.play() self.table.displayStopToPlay(index.row()) status = self.table.getStatus() self.setStatusEmission(status) @staticmethod def readConfig(section): parser = RawConfigParser() if getattr(sys, 'frozen', False): # frozen parser.read(os.path.dirname(os.path.realpath(sys.executable))+'/config') else: # unfrozen parser.read(os.path.dirname(os.path.realpath(__file__))+'/config') return dict(parser.items(section)) #Create menu bar def createMenu(self): self.menuBar() self.menuBar().setVisible(False) actionMenu = self.menuBar().addMenu('&Action') scanMusicFolderAction = QtGui.QAction('Scan Music Folder', self) showShortcutAction = QtGui.QAction('Show Shortcut',self) addFolderToLibraryAction = QtGui.QAction('Add Folder to Library',self) scanWaveformsAction = QtGui.QAction('Scan wave froms',self) #self.toggleRadioAction= QtGui.QAction('Switch to Radio mode',self) if not self.radio: self.toggleRadioAction= QtGui.QAction('Switch to Radio mode',self) else: self.toggleRadioAction= QtGui.QAction('Switch to Library mode',self) scanMusicFolderAction.triggered.connect(self.scanMusicFolder) actionMenu.addAction(scanMusicFolderAction) showShortcutAction.triggered.connect(self.showShortcut) actionMenu.addAction(showShortcutAction) addFolderToLibraryAction.triggered.connect(self.addFolderToLibrary) actionMenu.addAction(addFolderToLibraryAction) scanWaveformsAction.triggered.connect(self.scanWaveforms) actionMenu.addAction(scanWaveformsAction) self.toggleRadioAction.triggered.connect(self.toggleRadio) actionMenu.addAction(self.toggleRadioAction) # Menu Action 1 def scanMusicFolder(self): thread = QtCore.QThread(self) thread.worker = WorkThread(Foo.readConfig('options')['music_folder'], False) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.process) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start() # Menu Action 2 def showShortcut(self): dictSC = Foo.readConfig('shortcuts') message = '''<b>'''+dictSC['modifier']+'''+'''+dictSC['stop']+'''</b> : Stop<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['quit']+'''</b> : Quit<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['play_pause']+'''</b> : Play/Pause <br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['previous']+'''</b> : Previous<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['next']+'''</b> : Next<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['volume_down']+'''</b> : Volume down<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['volume_up']+'''</b> : Volume up<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['radio_mode']+'''</b> : Toggle radio mode<br/>''' + ''' <b>'''+dictSC['modifier']+'''+'''+dictSC['equalizer']+'''</b> : Equalizer<br/>''' print(len(self.findChildren(QtCore.QObject))) box = QMessageBox.about(self, 'About Shortcuts', message) print(len(self.findChildren(QtCore.QObject))) print('must delete') # Menu Action3 # Must be subdirectory of music folder otherwise wont be rescanned def addFolderToLibrary(self): dir = QFileDialog.getExistingDirectory(None, "Open Directory", Foo.readConfig('options')['music_folder'], QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) thread = QtCore.QThread(self) thread.worker = WorkThread(dir, True) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.process) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start() # Menu action 4 def scanWaveforms(self): from wave import Wave thread = QtCore.QThread(self) thread.worker = Wave(Foo.readConfig('options')['music_folder']) thread.worker.moveToThread(thread) thread.started.connect(thread.worker.processScan) thread.worker.finished.connect(thread.quit) thread.worker.finished.connect(thread.worker.deleteLater) thread.finished.connect(thread.deleteLater) thread.finished.connect(self.tree.initUI) thread.start() # Menu Action5 def toggleRadio(self): self.table.deleteLater() self.table.close() if not self.radio: configRadio = Foo.readConfig('radios') self.table=TableRadio(self.tree, configRadio) self.toggleRadioAction.setText('Switch to Library mode') self.radio=True self.player.playbin.disconnect(self.handlerATF) self.handlerT=self.player.bus.connect('message::tag', self.table.onTag) else: config = Foo.readConfig('options') self.table=Table( self.tree, config) self.toggleRadioAction.setText('Switch to Radio mode') self.radio=False self.handlerATF = self.player.playbin.connect("about-to-finish",self.onAboutToFinish) self.player.bus.disconnect(self.handlerT) self.splitterTopBottom.addWidget(self.table) # Since the frame is already attached to the splitter, # it only moves it to the new position self.splitterTopBottom.addWidget(self.infoFrame) self.table.runAction.connect(self.tableAction) self.setTabOrder(self.tree, self.table) self.splitterTopBottom.setStretchFactor(0,10) #self.splitterTopBottom.setStretchFactor(3,1) @QtCore.pyqtSlot() def startSearch(self): input = self.searchArea.searchLine.text() db = thread.load() songList = [] songGenerator = (Song(self.tree.comm, **dict) for dict in db) self.tree.model().removeRows(0, self.tree.model().rowCount()) if self.searchArea.searchExact.isChecked(): songList = [ e for e in songGenerator if e.exactMatch(input) ] elif self.searchArea.searchPrecise.isChecked(): songList = [ e for e in songGenerator if e.preciseMatch(input) ] else: songList = [ e for e in songGenerator if e.fuzzyMatch(input) ] del db[:] songList.sort(key=self.tree.sortFunc) self.tree.populateTree(songList) @QtCore.pyqtSlot(str) def onHotKey(self, key): print('Hotkey was pressed', key) if key == 'quit': self.shortQuit.activated.emit() if key == 'stop': self.shortStop.activated.emit() if key == 'play_pause': self.shortPlayPause.activated.emit() if key == 'volume_up': self.shortVolUp.activated.emit() if key == 'volume_down': self.shortVolDown.activated.emit() if key == 'song_next': self.shortSongNext.activated.emit() if key == 'song_prev': self.shortSongPrev.activated.emit() if key == 'tree_up': if self.radio: self.table.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Up, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Up, Qt.KeyboardModifier(), '')) if key == 'tree_down': if self.radio: self.table.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Down, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Down, Qt.KeyboardModifier(), '')) if key == 'tree_left': if not self.radio: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Left, Qt.KeyboardModifier(), '')) if key == 'tree_right': if not self.radio: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Right, Qt.KeyboardModifier(), '')) if key == 'tree_validate': if self.radio: self.table.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(), '')) else: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(), '')) if key == 'tree_append': if not self.radio: self.tree.keyPressEvent(QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Key_Return, Qt.KeyboardModifier(QtCore.Qt.ShiftModifier), '')) if key == 'radio_mode': self.shortRadioMode.activated.emit() def tmpTag(self, position): menu = QtGui.QMenu() tagging = QtGui.QAction('Tagging',self) replayGain = QtGui.QAction('ReplayGain',self) tagging.triggered.connect(self.openTagging) replayGain.triggered.connect(self.startReplayGain) menu.addAction(tagging) menu.addAction(replayGain) menu.exec_(self.tree.viewport().mapToGlobal(position)) def startReplayGain(self): children = self.tree.getChildren() self.RG = ReplayGain([x['file'] for x in children]) self.RG.exec_() def openTagging(self): children = self.tree.getChildren() #[7:] to drop the 'file://' appended for gstreamer retag = Retagging([x['file'][7:] for x in children]) res = retag.exec_() if res: self.tree.initUI() print(res) def openEqualizer(self): from configparser import RawConfigParser equa = Equalizer(self, Foo.readConfig('audio')) equa.equalize.connect(self.applyEqua) if equa.exec_(): parser = RawConfigParser() parser.read(os.path.dirname(os.path.realpath(__file__))+'/config') parser['audio']['settings']= str(equa.config) with open(os.path.dirname(os.path.realpath(__file__))+'/config', 'w') as configfile: parser.write(configfile) def applyEqua(self,band, value): print('receiving equa', str(band), value) if str(band) == 'band0' and value == 0: self.player.equalizer.set_property('band0', 0.01) else: self.player.equalizer.set_property(str(band), value)
class TestTree(unittest.TestCase): def setUp(self): self.root = Tree(NAME) self.tree2 = None self.tree3 = None self.tree4 = None def _AddChild(self, name): new_tree = Tree(name) self.root.addChild(new_tree) return new_tree def _createComplexTree(self, root_name=NAME): """ Creates the following tree NAME1 NAME2 NAME4 NAME3 :param str root_name: name of the root node """ self.tree2 = self._AddChild(NAME2) self.tree3 = self._AddChild(NAME3) self.tree4 = Tree(NAME4) self.tree2.addChild(self.tree4) self.root.setName(root_name) def testConstructor(self): if IGNORE_TEST: return self.assertEqual(self.root._name, NAME) self.assertEqual(len(self.root._children), 0) def testAddChild(self): if IGNORE_TEST: return new_tree = self._AddChild(NAME2) self.assertEqual(len(self.root._children), 1) self.assertEqual(self.root._children[0], new_tree) newer_tree = self._AddChild(NAME3) self.assertEqual(len(self.root._children), 2) self.assertEqual(self.root._children[1], newer_tree) def testAddChildComplex(self): if IGNORE_TEST: return self._createComplexTree() self.assertTrue(self.tree4 in self.tree2.getChildren()) def testGetAllNodes(self): """ NAME1->NAME2->NAME4 NAME1->NAME3 """ if IGNORE_TEST: return root = Tree(NEW_NAME) nodes = root.getAllNodes() self.assertEqual(len(nodes), 1) self.assertEqual(nodes[0]._name, NEW_NAME) self._createComplexTree() names = [n._name for n in self.root.getAllNodes()] _verifyComplexTreeDepthFirstList(names, root_name=NAME) def testRemoveChildSimple(self): if IGNORE_TEST: return new_tree = self._AddChild(NAME2) new_tree.removeTree() self.assertIsNone(new_tree._parent) self.assertEqual(len(self.root._children), 0) def testRemoveChildComplex(self): if IGNORE_TEST: return self._createComplexTree() self.tree4.removeTree() self.assertIsNone(self.tree4._parent) self.assertEqual(len(self.tree2._children), 0) self.assertEqual(len(self.root._children), 2) def testGetRoot(self): if IGNORE_TEST: return self._createComplexTree() self.assertEqual(self.tree2._children[0], self.tree4) root = self.tree4.getRoot() self.assertEqual(root, self.root) root = self.root.getRoot() self.assertEqual(root, self.root) root = self.tree3.getRoot() self.assertEqual(root, self.root) def testGetChildrenFromRoot(self): if IGNORE_TEST: return self._createComplexTree() children = self.tree2.getChildren(is_from_root=False) self.assertEqual(children, [self.tree4]) children = self.tree4.getChildren(is_from_root=True, is_recursive=True) self.assertEqual(len(children), 3) self.assertFalse(self.root in children) self.assertTrue(self.tree2 in children) self.assertTrue(self.tree4 in children) def testGetChildrenFromSelf(self): """ NAME1: NAME2 NAME4 NAME4.1 NAME4.2 NAME3 """ if IGNORE_TEST: return self._createComplexTree() self.tree4.addChild(Tree(NAME4 + ".1")) self.tree4.addChild(Tree(NAME4 + ".2")) children = self.tree2.getChildren(is_from_root=False, is_recursive=True) grandchildren = self.tree4.getChildren(is_from_root=False) self.assertEqual(len(children), 3) self.assertEqual(len(grandchildren), 2) self.assertTrue(self.tree4 in children) def testFindPathFromRoot(self): if IGNORE_TEST: return self._createComplexTree() path = self.tree2.findPathFromRoot() self.assertEqual(path, [NAME, NAME2]) path = self.tree4.findPathFromRoot() self.assertEqual(path, [NAME, NAME2, NAME4]) def testFindName(self): if IGNORE_TEST: return self._createComplexTree() trees = self.tree2.findChildrenWithName(NAME3, is_from_root=True) self.assertEqual(trees, [self.tree3]) trees = self.tree2.findChildrenWithName(NAME3, is_from_root=False) self.assertEqual(trees, []) def _checkNodeLists(self, list1, list2): names1 = [l.getName() for l in list1] names2 = [l.getName() for l in list2] return set(names1) == set(names2) def testGetLeaves(self): if IGNORE_TEST: return self._createComplexTree() leaves = self.tree2.getLeaves(is_from_root=True) self.assertTrue(self._checkNodeLists(leaves, [self.tree3, self.tree4])) leaves = self.tree2.getLeaves(is_from_root=False) self.assertTrue(self._checkNodeLists(leaves, [self.tree4])) def testToString(self): if IGNORE_TEST: return self._createComplexTree() self.root.setName(NEW_NAME) print_string = self.root.toString() _verifyComplexTreeDepthFirstList(print_string) def testIsAlwaysLeaf(self): if IGNORE_TEST: return self._createComplexTree() self.assertFalse(self.tree2.isAlwaysLeaf()) def testCopy(self): if IGNORE_TEST: return self._createComplexTree() new_tree = self.root.copy() self.assertTrue(self.root.isEquivalent(new_tree)) def testComplexCopy(self): if IGNORE_TEST: return tree = Tree.createRandomTree(100, 0.8) new_tree = tree.copy() self.assertTrue(tree.isEquivalent(new_tree)) def testGetReverseOrderListOfNodes(self): if IGNORE_TEST: return self._createComplexTree() reverse_nodes = self.root.getReverseOrderListOfNodes() forward_nodes = [n for n in self.root] forward_nodes.reverse() self.assertEqual(forward_nodes, reverse_nodes) def _testRandomTrees(self, leaf_cls=None, nonleaf_cls=None, tree_test=lambda x: True): num_nodes = [3, 100, 20, 1] branching_probabilities = [0.5, 0.2, 0.8] for nn in num_nodes: for pp in branching_probabilities: tree = Tree.createRandomTree(nn, pp, seed=0.3, leaf_cls=leaf_cls, nonleaf_cls=nonleaf_cls) nodes = [n for n in tree] diff = abs(len(nodes) - nn) if diff > 1: import pdb pdb.set_trace() self.assertTrue(diff < 2) if not tree_test(tree): import pdb pdb.set_trace() self.assertTrue(tree_test(tree)) def testRandomTrees(self): if IGNORE_TEST: return self._testRandomTrees() def testGetUniqueName(self): if IGNORE_TEST: return self._createComplexTree() unique_name = self.tree4.getUniqueName() self.assertEqual(unique_name, 'NAME1.NAME2.NAME4') def testGetChldrenAsDict(self): if IGNORE_TEST: return self._createComplexTree() children_dict = self.root.getChildrenBreadthFirst() self.assertEqual(children_dict["node"], self.root) self.assertEqual(len(children_dict["children"]), 2) # children_dict = self.root.getChildrenBreadthFirst( excludes=[self.tree2]) self.assertEqual(children_dict["node"], self.root) self.assertEqual(len(children_dict["children"]), 1) # children_dict = self.root.getChildrenBreadthFirst( includes=[self.root, self.tree2]) self.assertEqual(children_dict["node"], self.root) self.assertEqual(len(children_dict["children"]), 1) # children_dict = self.root.getChildrenBreadthFirst( includes=[self.tree2]) self.assertEqual(len(children_dict.keys()), 0) def testGetAttachedNodes(self): """ NAME1 NAME2 NAME4 NAME3 """ if IGNORE_TEST: return # All leaves self._createComplexTree() all_leaves = self.root.getLeaves() leaves = self.root.getAttachedNodes(all_leaves) self.assertEqual(set(leaves), set([self.tree4, self.tree3])) # Eliminate NAME4 self.tree2.setIsAttached(False) leaves = self.root.getAttachedNodes(all_leaves) self.assertEqual(leaves, [self.tree3]) # Detaching the root shouldn't matter self.root.setIsAttached(False) leaves = self.root.getAttachedNodes(all_leaves) self.assertEqual(leaves, [self.tree3])
class TestTree(unittest.TestCase): def setUp(self): self.root = Tree(NAME) self.tree2 = None self.tree3 = None self.tree4 = None def _AddChild(self, name): new_tree = Tree(name) self.root.addChild(new_tree) return new_tree def _createComplexTree(self): """ Creates the following tree NAME1->NAME2->NAME4 NAME1->NAME3 """ self.tree2 = self._AddChild(NAME2) self.tree3 = self._AddChild(NAME3) self.tree4 = Tree(NAME4) self.tree2.addChild(self.tree4) def testConstructor(self): if IGNORE_TEST: return self.assertEqual(self.root._name, NAME) self.assertEqual(len(self.root._children), 0) def testAddChild(self): if IGNORE_TEST: return new_tree = self._AddChild(NAME2) self.assertEqual(len(self.root._children), 1) self.assertEqual(self.root._children[0], new_tree) newer_tree = self._AddChild(NAME3) self.assertEqual(len(self.root._children), 2) self.assertEqual(self.root._children[1], newer_tree) def testAddChildComplex(self): if IGNORE_TEST: return self._createComplexTree() self.assertTrue(self.tree4 in self.tree2.getChildren()) def testRemoveChildSimple(self): if IGNORE_TEST: return new_tree = self._AddChild(NAME2) new_tree.removeTree() self.assertIsNone(new_tree._parent) self.assertEqual(len(self.root._children), 0) def testRemoveChildComplex(self): if IGNORE_TEST: return self._createComplexTree() self.tree4.removeTree() self.assertIsNone(self.tree4._parent) self.assertEqual(len(self.tree2._children), 0) self.assertEqual(len(self.root._children), 2) def testGetRoot(self): if IGNORE_TEST: return self._createComplexTree() self.assertEqual(self.tree2._children[0], self.tree4) root = self.tree4.getRoot() self.assertEqual(root, self.root) root = self.root.getRoot() self.assertEqual(root, self.root) root = self.tree3.getRoot() self.assertEqual(root, self.root) def testGetChildrenFromRoot(self): if IGNORE_TEST: return self._createComplexTree() children = self.tree2.getChildren(is_from_root=False) self.assertEqual(children, [self.tree4]) children = self.tree4.getChildren(is_from_root=True, is_recursive=True) self.assertEqual(len(children), 3) self.assertFalse(self.root in children) self.assertTrue(self.tree2 in children) self.assertTrue(self.tree4 in children) def testGetChildrenFromSelf(self): if IGNORE_TEST: return self._createComplexTree() children = self.tree2.getChildren(is_from_root=False) grandchildren = self.tree4.getChildren(is_from_root=False) self.assertEqual(len(children), 1) self.assertEqual(len(grandchildren), 0) self.assertTrue(self.tree4 in children) def testFindPathFromRoot(self): if IGNORE_TEST: return self._createComplexTree() path = self.tree2.findPathFromRoot() self.assertEqual(path, [NAME, NAME2]) path = self.tree4.findPathFromRoot() self.assertEqual(path, [NAME, NAME2, NAME4]) def testFindName(self): if IGNORE_TEST: return self._createComplexTree() trees = self.tree2.findChildrenWithName(NAME3, is_from_root=True) self.assertEqual(trees, [self.tree3]) trees = self.tree2.findChildrenWithName(NAME3, is_from_root=False) self.assertEqual(trees, []) def _checkNodeLists(self, list1, list2): names1 = [l.getName() for l in list1] names2 = [l.getName() for l in list2] return set(names1) == set(names2) def testGetLeaves(self): if IGNORE_TEST: return self._createComplexTree() leaves = self.tree2.getLeaves(is_from_root=True) self.assertTrue(self._checkNodeLists(leaves, [self.tree3, self.tree4])) leaves = self.tree2.getLeaves(is_from_root=False) self.assertTrue(self._checkNodeLists(leaves, [self.tree4])) def testToString(self): if IGNORE_TEST: return self._createComplexTree() print_string = self.root.toString() self.assertTrue("%s->%s" % (NAME, NAME3) in print_string) self.assertTrue("%s->%s" % (NAME, NAME2) in print_string) self.assertTrue("%s->%s" % (NAME2, NAME4) in print_string) def testIsAlwaysLeaf(self): if IGNORE_TEST: return self._createComplexTree() self.assertFalse(self.tree2.isAlwaysLeaf()) def testCopy(self): if IGNORE_TEST: return new_tree = self.root.copy() self.assertTrue(self.root.isEquivalent(new_tree))
if menu_input == str(1): # Fresh output output = [] name_to_search = input("Enter name to find\n") output.extend(tree.searchName(name_to_search)) tree.displayInfo(output) elif menu_input == str(2): name_to_search = input("Enter name to find father\n") output.append(tree.findRelativeOf(name_to_search, "father")) tree.displayInfo(output) elif menu_input == str(3): name_to_search = input("Enter name to find mother\n") output.append(tree.findRelativeOf(name_to_search, "mother")) tree.displayInfo(output) elif menu_input == str(4): name_to_search = input("Enter name to find children\n") output.extend(tree.getChildren(name_to_search)) tree.displayInfo(output) elif menu_input == str(5): break else: print("Choose a valid option") os.system("clear")