import sys
from dataclasses import dataclass
from itertools import groupby
from typing import Iterable, Callable
from PyQt6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
@dataclass
class Song:
artist: str
album: str
title: str
@classmethod
def from_db(cls) -> Iterable['Song']:
from mysql.connector import connect
with connect(
user='Estranger',
password='********',
host='127.0.0.1',
port=3306,
database='Music',
) as conn, conn.cursor() as cursor:
cursor.execute(
'select artist, album, title from songs '
'order by artist, album'
)
for row in cursor.fetchall():
yield cls(*row)
@classmethod
def fake_rows(cls) -> Iterable['Song']:
return (
cls('Weird Al Yankovic', 'Running with Scissors', 'Pretty Fly for a Rabbi'),
cls('Weird Al Yankovic', 'Running with Scissors', 'Albuquerque'),
cls('Weird Al Yankovic', 'Off the Deep End', "I Can't Watch This"),
cls('Weird Al Yankovic', 'Off the Deep End', 'Smells like Nirvana'),
cls('The Arrogant Worms', "C'est Cheese", 'Mounted Animal Nature Trail'),
)
@staticmethod
def by_artist(self): return self.artist
@staticmethod
def by_album(self): return self.album
class GUI:
HEADERS = ('Name', 'Artist', 'Album', 'Title')
def __init__(self, songs):
app = QApplication(sys.argv)
tree = QTreeWidget()
# a reference needs to be held or this will be garbage-collected
self.tree = tree
tree.resize(1280, 720)
tree.setWindowTitle('tree')
frame = tree.frameGeometry()
center = tree.screen().availableGeometry().center()
frame.moveCenter(center)
tree.move(frame.topLeft())
tree.setColumnCount(len(self.HEADERS))
tree.setHeaderLabels(self.HEADERS)
for artist, after_artist in groupby(songs, Song.by_artist):
artist_node = QTreeWidgetItem((artist,))
for album, after_album in groupby(after_artist, Song.by_album):
album_node = QTreeWidgetItem((album, artist, album))
for song in after_album:
song_node = QTreeWidgetItem((song.title, artist, album, song.title))
album_node.addChild(song_node)
artist_node.addChild(album_node)
tree.addTopLevelItem(artist_node)
tree.show()
self.run: Callable[[], int] = app.exec
def main() -> None:
songs = Song.fake_rows()
gui = GUI(songs)
exit(gui.run())
if __name__ == '__main__':
main()
import sys
from dataclasses import dataclass
from itertools import groupby
from typing import Iterable, Callable
from PyQt6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
@dataclass
class Song:
artist: str
album: str
title: str
@classmethod
def from_db(cls) -> Iterable['Song']:
from mysql.connector import connect
with connect(
user='Estranger',
password='********',
host='127.0.0.1',
port=3306,
database='Music',
) as conn, conn.cursor() as cursor:
cursor.execute(
'select artist, album, title from songs '
'order by artist, album'
)
for row in cursor.fetchall():
yield cls(*row)
@classmethod
def fake_rows(cls) -> Iterable['Song']:
return (
cls('Weird Al Yankovic', 'Running with Scissors', 'Pretty Fly for a Rabbi'),
cls('Weird Al Yankovic', 'Running with Scissors', 'Albuquerque'),
cls('Weird Al Yankovic', 'Off the Deep End', "I Can't Watch This"),
cls('Weird Al Yankovic', 'Off the Deep End', 'Smells like Nirvana'),
cls('The Arrogant Worms', "C'est Cheese", 'Mounted Animal Nature Trail'),
)
@staticmethod
def by_artist(self): return self.artist
@staticmethod
def by_album(self): return self.album
class GUI:
HEADERS = ('Name', 'Artist', 'Album', 'Title')
def __init__(self, songs):
app = QApplication(sys.argv)
tree = QTreeWidget()
# a reference needs to be held or this will be garbage-collected
self.tree = tree
tree.resize(1280, 720)
tree.setWindowTitle('tree')
frame = tree.frameGeometry()
center = tree.screen().availableGeometry().center()
frame.moveCenter(center)
tree.move(frame.topLeft())
tree.setColumnCount(len(self.HEADERS))
tree.setHeaderLabels(self.HEADERS)
for artist, after_artist in groupby(songs, Song.by_artist):
artist_node = QTreeWidgetItem((artist,))
for album, after_album in groupby(after_artist, Song.by_album):
album_node = QTreeWidgetItem((album, artist, album))
for song in after_album:
song_node = QTreeWidgetItem((song.title, artist, album, song.title))
album_node.addChild(song_node)
artist_node.addChild(album_node)
tree.addTopLevelItem(artist_node)
tree.show()
self.run: Callable[[], int] = app.exec
def main() -> None:
songs = Song.fake_rows()
gui = GUI(songs)
exit(gui.run())
if __name__ == '__main__':
main()
import sys
from dataclasses import dataclass
from itertools import groupby
from typing import Iterable, Callable
from PyQt6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
@dataclass
class Song:
artist: str
album: str
title: str
@classmethod
def from_db(cls) -> Iterable['Song']:
from mysql.connector import connect
with connect(
user='Estranger',
password='********',
host='127.0.0.1',
port=3306,
database='Music',
) as conn, conn.cursor() as cursor:
cursor.execute(
'select artist, album, title from songs '
'order by artist, album'
)
for row in cursor.fetchall():
yield cls(*row)
@classmethod
def fake_rows(cls) -> Iterable['Song']:
return (
cls('Weird Al Yankovic', 'Running with Scissors', 'Pretty Fly for a Rabbi'),
cls('Weird Al Yankovic', 'Running with Scissors', 'Albuquerque'),
cls('Weird Al Yankovic', 'Off the Deep End', "I Can't Watch This"),
cls('Weird Al Yankovic', 'Off the Deep End', 'Smells like Nirvana'),
cls('The Arrogant Worms', "C'est Cheese", 'Mounted Animal Nature Trail'),
)
def by_artist(self): return self.artist
def by_album(self): return self.album
class GUI:
HEADERS = ('Name', 'Artist', 'Album', 'Title')
def __init__(self, songs):
app = QApplication(sys.argv)
tree = QTreeWidget()
# a reference needs to be held or this will be garbage-collected
self.tree = tree
tree.resize(1280, 720)
tree.setWindowTitle('tree')
frame = tree.frameGeometry()
center = tree.screen().availableGeometry().center()
frame.moveCenter(center)
tree.move(frame.topLeft())
tree.setColumnCount(len(self.HEADERS))
tree.setHeaderLabels(self.HEADERS)
for artist, after_artist in groupby(songs, Song.by_artist):
artist_node = QTreeWidgetItem((artist,))
for album, after_album in groupby(after_artist, Song.by_album):
album_node = QTreeWidgetItem((album, artist, album))
for song in after_album:
song_node = QTreeWidgetItem((song.title, artist, album, song.title))
album_node.addChild(song_node)
artist_node.addChild(album_node)
tree.addTopLevelItem(artist_node)
tree.show()
self.run: Callable[[], int] = app.exec
def main() -> None:
songs = Song.fake_rows()
gui = GUI(songs)
exit(gui.run())
if __name__ == '__main__':
main()
import sys
from dataclasses import dataclass
from itertools import groupby
from typing import Iterable, Callable
from PyQt6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
@dataclass
class Song:
artist: str
album: str
title: str
@classmethod
def from_db(cls) -> Iterable['Song']:
from mysql.connector import connect
with connect(
user='Estranger',
password='********',
host='127.0.0.1',
port=3306,
database='Music',
) as conn, conn.cursor() as cursor:
cursor.execute(
'select artist, album, title from songs '
'order by artist, album'
)
for row in cursor.fetchall():
yield cls(*row)
@classmethod
def fake_rows(cls) -> Iterable['Song']:
return (
cls('Weird Al Yankovic', 'Running with Scissors', 'Pretty Fly for a Rabbi'),
cls('Weird Al Yankovic', 'Running with Scissors', 'Albuquerque'),
cls('Weird Al Yankovic', 'Off the Deep End', "I Can't Watch This"),
cls('Weird Al Yankovic', 'Off the Deep End', 'Smells like Nirvana'),
cls('The Arrogant Worms', "C'est Cheese", 'Mounted Animal Nature Trail'),
)
@staticmethod
def by_artist(self): return self.artist
@staticmethod
def by_album(self): return self.album
class GUI:
HEADERS = ('Name', 'Artist', 'Album', 'Title')
def __init__(self, songs):
app = QApplication(sys.argv)
tree = QTreeWidget()
# a reference needs to be held or this will be garbage-collected
self.tree = tree
tree.resize(1280, 720)
tree.setWindowTitle('tree')
frame = tree.frameGeometry()
center = tree.screen().availableGeometry().center()
frame.moveCenter(center)
tree.move(frame.topLeft())
tree.setColumnCount(len(self.HEADERS))
tree.setHeaderLabels(self.HEADERS)
for artist, after_artist in groupby(songs, Song.by_artist):
artist_node = QTreeWidgetItem((artist,))
for album, after_album in groupby(after_artist, Song.by_album):
album_node = QTreeWidgetItem((album, artist, album))
for song in after_album:
song_node = QTreeWidgetItem((song.title, artist, album, song.title))
album_node.addChild(song_node)
artist_node.addChild(album_node)
tree.addTopLevelItem(artist_node)
tree.show()
self.run: Callable[[], int] = app.exec
def main() -> None:
songs = tuple(Song.fake_rows())
gui = GUI(songs)
exit(gui.run())
if __name__ == '__main__':
main()
import sys
from dataclasses import dataclass
from itertools import groupby
from typing import Iterable, Callable
from PyQt6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
@dataclass
class Song:
artist: str
album: str
title: str
@classmethod
def from_db(cls) -> Iterable['Song']:
from mysql.connector import connect
with connect(
user='Estranger',
password='********',
host='127.0.0.1',
port=3306,
database='Music',
) as conn, conn.cursor() as cursor:
cursor.execute(
'select artist, album, title from songs '
'order by artist, album'
)
for row in cursor.fetchall():
yield cls(*row)
@classmethod
def fake_rows(cls) -> Iterable['Song']:
return (
cls('Weird Al Yankovic', 'Running with Scissors', 'Pretty Fly for a Rabbi'),
cls('Weird Al Yankovic', 'Running with Scissors', 'Albuquerque'),
cls('Weird Al Yankovic', 'Off the Deep End', "I Can't Watch This"),
cls('Weird Al Yankovic', 'Off the Deep End', 'Smells like Nirvana'),
cls('The Arrogant Worms', "C'est Cheese", 'Mounted Animal Nature Trail'),
)
@staticmethod
def by_artist(self): return self.artist
@staticmethod
def by_album(self): return self.album
class GUI:
HEADERS = ('Name', 'Artist', 'Album', 'Title')
def __init__(self, songs):
app = QApplication(sys.argv)
tree = QTreeWidget()
# a reference needs to be held or this will be garbage-collected
self.tree = tree
tree.resize(1280, 720)
tree.setWindowTitle('tree')
frame = tree.frameGeometry()
center = tree.screen().availableGeometry().center()
frame.moveCenter(center)
tree.move(frame.topLeft())
tree.setColumnCount(len(self.HEADERS))
tree.setHeaderLabels(self.HEADERS)
for artist, after_artist in groupby(songs, Song.by_artist):
artist_node = QTreeWidgetItem((artist,))
for album, after_album in groupby(after_artist, Song.by_album):
album_node = QTreeWidgetItem((album, artist, album))
for song in after_album:
song_node = QTreeWidgetItem((song.title, artist, album, song.title))
album_node.addChild(song_node)
artist_node.addChild(album_node)
tree.addTopLevelItem(artist_node)
tree.show()
self.run: Callable[[], int] = app.exec
def main() -> None:
songs = tuple(Song.fake_rows())
gui = GUI(songs)
exit(gui.run())
if __name__ == '__main__':
main()
import sys
from dataclasses import dataclass
from itertools import groupby
from typing import Iterable, Callable
from PyQt6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
@dataclass
class Song:
artist: str
album: str
title: str
@classmethod
def from_db(cls) -> Iterable['Song']:
from mysql.connector import connect
with connect(
user='Estranger',
password='********',
host='127.0.0.1',
port=3306,
database='Music',
) as conn, conn.cursor() as cursor:
cursor.execute(
'select artist, album, title from songs '
'order by artist, album'
)
for row in cursor.fetchall():
yield cls(*row)
@classmethod
def fake_rows(cls) -> Iterable['Song']:
return (
cls('Weird Al Yankovic', 'Running with Scissors', 'Pretty Fly for a Rabbi'),
cls('Weird Al Yankovic', 'Running with Scissors', 'Albuquerque'),
cls('Weird Al Yankovic', 'Off the Deep End', "I Can't Watch This"),
cls('Weird Al Yankovic', 'Off the Deep End', 'Smells like Nirvana'),
cls('The Arrogant Worms', "C'est Cheese", 'Mounted Animal Nature Trail'),
)
@staticmethod
def by_artist(self): return self.artist
@staticmethod
def by_album(self): return self.album
class GUI:
HEADERS = ('Name', 'Artist', 'Album', 'Title')
def __init__(self, songs):
app = QApplication(sys.argv)
tree = QTreeWidget()
# a reference needs to be held or this will be garbage-collected
self.tree = tree
tree.resize(1280, 720)
tree.setWindowTitle('tree')
frame = tree.frameGeometry()
center = tree.screen().availableGeometry().center()
frame.moveCenter(center)
tree.move(frame.topLeft())
tree.setColumnCount(len(self.HEADERS))
tree.setHeaderLabels(self.HEADERS)
for artist, after_artist in groupby(songs, Song.by_artist):
artist_node = QTreeWidgetItem((artist,))
for album, after_album in groupby(after_artist, Song.by_album):
album_node = QTreeWidgetItem((album, artist, album))
for song in after_album:
song_node = QTreeWidgetItem((song.title, artist, album, song.title))
album_node.addChild(song_node)
artist_node.addChild(album_node)
tree.addTopLevelItem(artist_node)
tree.show()
self.run: Callable[[], int] = app.exec
def main() -> None:
songs = Song.fake_rows()
gui = GUI(songs)
exit(gui.run())
if __name__ == '__main__':
main()
- You have a pile of unstructured, global code; this needs to be organized into functions and maybe classes
- Close your cursor once you're done with it, ideally via context management
- Order your query using the database itself, to make grouping less painful; also query in order of hierarchy (artist, album, song)
- You don't need
entries; just add items one at a time - 4 should not be hard-coded
- Your repeated set comprehensions can be greatly simplified (i.e. abolished) via
itertools.groupby
This example code localises the MySQL import because I don't have it; I've generated fake data instead.
import sys
from dataclasses import dataclass
from itertools import groupby
from typing import Iterable, Callable
from PyQt6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
@dataclass
class Song:
artist: str
album: str
title: str
@classmethod
def from_db(cls) -> Iterable['Song']:
from mysql.connector import connect
with connect(
user='Estranger',
password='********',
host='127.0.0.1',
port=3306,
database='Music',
) as conn, conn.cursor() as cursor:
cursor.execute(
'select artist, album, title from songs '
'order by artist, album'
)
for row in cursor.fetchall():
yield cls(*row)
@classmethod
def fake_rows(cls) -> Iterable['Song']:
return (
cls('Weird Al Yankovic', 'Running with Scissors', 'Pretty Fly for a Rabbi'),
cls('Weird Al Yankovic', 'Running with Scissors', 'Albuquerque'),
cls('Weird Al Yankovic', 'Off the Deep End', "I Can't Watch This"),
cls('Weird Al Yankovic', 'Off the Deep End', 'Smells like Nirvana'),
cls('The Arrogant Worms', "C'est Cheese", 'Mounted Animal Nature Trail'),
)
@staticmethod
def by_artist(self): return self.artist
@staticmethod
def by_album(self): return self.album
class GUI:
HEADERS = ('Name', 'Artist', 'Album', 'Title')
def __init__(self, songs):
app = QApplication(sys.argv)
tree = QTreeWidget()
# a reference needs to be held or this will be garbage-collected
self.tree = tree
tree.resize(1280, 720)
tree.setWindowTitle('tree')
frame = tree.frameGeometry()
center = tree.screen().availableGeometry().center()
frame.moveCenter(center)
tree.move(frame.topLeft())
tree.setColumnCount(len(self.HEADERS))
tree.setHeaderLabels(self.HEADERS)
for artist, after_artist in groupby(songs, Song.by_artist):
artist_node = QTreeWidgetItem((artist,))
for album, after_album in groupby(after_artist, Song.by_album):
album_node = QTreeWidgetItem((album, artist, album))
for song in after_album:
song_node = QTreeWidgetItem((song.title, artist, album, song.title))
album_node.addChild(song_node)
artist_node.addChild(album_node)
tree.addTopLevelItem(artist_node)
tree.show()
self.run: Callable[[], int] = app.exec
def main() -> None:
songs = tuple(Song.fake_rows())
gui = GUI(songs)
exit(gui.run())
if __name__ == '__main__':
main()
lang-py
