Форум сайта python.su
Заранее прошу сильно не пинать )
Пишу для себя, но хочется иметь сабж
Читать по оформлению лень, просто ткните носом что и где не так. На живом примере быстрее запомнится.
Код начал оптимизировать, поэтому он еще кривой. Вот собственно и нужны советы. Может что-то объединить в функции, строки документации как правильно оформить и т.д. Спасибо заранее.
#!/usr/bin/env python3 """ Просмотр базы данных библиотеки Flibusta Список элементов формы. Представления: genreView - QTreeView - список жанров; genreBook - QTableView - список книг определенного жанра; seriesTableView - QTableView - список серий; booksInSeriesView - QTableView - список книг определенной серии; annotation - QTextBrowser - аннотации к книгам. Кнопки: alphabetBtns - QGroupBox - группа кнопок с русским и латинским алфавитами; auth_btn - кнопка поиска автора; title_btn - кнопка поиска книги по названию; series_btn - кнопка поиска книг по серии. Поля ввода: auth_le - QLineEdit - автор; title_le - QLineEdit - название книги; series_le - QLineEdit - название серии. Различные label для вывода информации из базы (количество книг, авторов, серий, жанров). Изменение размера заголовков в таблице: Interactive - 0 Fixed - 2 Stretch - 1 ResizeToContents - 3 """ from PyQt5 import QtWidgets, QtGui, QtCore, uic import sys from querydb import * import string def alphabet_dicts(): rus_list = [chr(c) for c in range(ord('А'), ord('Я') + 1)] eng_list = [chr(c) for c in range(ord('A'), ord('Z') + 1)] eng_list.extend(['*', '#']) eng_list.extend(string.digits) return eng_list, rus_list class MainForm(QtWidgets.QWidget): def __init__(self, db, parent=None): # noinspection PyArgumentList QtWidgets.QWidget.__init__(self, parent) uic.loadUi('ui/mainform.ui', self) # noinspection PyArgumentList self.setFont(QtGui.QFont('Play', pointSize=10)) self.db = db self.initUI() # def item_changed(self): def initUI(self): self.init_genre_ui() self.init_series_ui() self.init_books_of_auth_ui() self.alphabetic_dict(self.alphabetBtns) # серии по алфавиту self.connect_btns(self.alphabetBtns, self.series_char_checked) self.alphabetic_dict(self.authAlphabetBtns) # авторы по алфавиту self.connect_btns(self.authAlphabetBtns, self.auth_char_checked) self.about_library() # о содержимом базы данных self.booksInSeriesView. \ doubleClicked.connect(self.get_book_annotation) # получить аннотацию self.seriesTableView. \ doubleClicked.connect(self.books_in_series) # книги в серии self.genreBook. \ doubleClicked.connect(self.on_genreBook_click) # выбор книги определенного жанра # self.authListView.doubleClicked.connect(self.books_of_auth) self.booksOfAuth.doubleClicked.connect(self.on_BooksOfAuth_click) self.auth_btn.clicked.connect(self.auth_btn_clicked) self.title_btn.clicked.connect(self.title_btn_clicked) self.titleTableView.doubleClicked.connect(self.on_titleTableView_click) self.series_btn.clicked.connect(self.series_btn_clicked) # self.alphabetBtns.clicked.connect(self.series_char_checked) # # self.authAlphabetBtns.toggled.connect(self.auth_char_checked) def init_series_ui(self): self.seriesModel = QtGui.QStandardItemModel() self.seriesTableView.setModel(self.seriesModel) self.seriesModel.setHorizontalHeaderLabels(['Серия', 'ID']) self.seriesTableView.setColumnHidden(1, True) self.seriesTableView.sortByColumn(0, 0) self.seriesTableView.resizeColumnToContents(0) # растягивание # колонки по содержимому и появление горизонтального скролла self.seriesTableView.horizontalHeader(). \ setDefaultAlignment(QtCore.Qt.AlignLeft) # выравнивание заголовка колонки def init_genre_ui(self): self.genreModel = self.create_genre_model() # отображение жанров self.genreView.setModel(self.genreModel) # отображает жанры self.genreView.header().setSectionResizeMode(0) self.genreView.sortByColumn(0, 0) self.genreView.setColumnHidden(1, True) self.genreView.doubleClicked.connect(self.get_books_of_genre) def init_books_of_auth_ui(self): self.books_of_auth = QtGui.QStandardItemModel() self.booksOfAuth.setModel(self.books_of_auth) self.booksOfAuth.setColumnHidden(5, True) self.booksOfAuth.sortByColumn(0, 0) self.booksOfAuth.setColumnWidth(4, 45) self.booksOfAuth.setColumnWidth(3, 110) self.booksOfAuth.setColumnWidth(2, 110) self.booksOfAuth.setColumnWidth(1, 200) self.booksOfAuth.setColumnWidth(0, 200) self.books_of_auth.setHorizontalHeaderLabels(['Название', 'Альтернативное название', 'Серия', 'Номер в серии', 'Год', 'ID']) @QtCore.pyqtSlot() def series_btn_clicked(self): if not self.series_le.text(): return lst = get_series_by_name(self.db, self.series_le.text()) if not lst: return for i in lst: self.seriesModel.appendRow([QtGui.QStandardItem(str(item if item else '')) for item in i]) self.tabWidget.setCurrentWidget(self.tab_2) @QtCore.pyqtSlot() def on_titleTableView_click(self): idx = self.titleTableView.currentIndex() column = idx.column() if column == 2: self.auth_le.setText(idx.data()) elif column == 0: self.title_le.setText(idx.data()) elif column == 3: self.series_le.setText(idx.data()) book_id = idx.model().item(idx.row(), 6).text() self.get_book_annotation(book_id) @QtCore.pyqtSlot() def title_btn_clicked(self): title = self.title_le.text() lst = get_title(self.db, title) model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(['Название', 'Альтернативное название', 'Автор', 'Серия', 'Номер в серии', 'Год', 'ID']) for i in lst: model.appendRow([QtGui.QStandardItem(str(item if item else '')) for item in i]) if self.titleTableView.model(): self.titleTableView.model().clear() self.titleTableView.setModel(model) self.titleTableView.setColumnHidden(6, True) self.titleTableView.setColumnWidth(5, 45) self.titleTableView.setColumnWidth(4, 110) self.titleTableView.setColumnWidth(3, 110) self.titleTableView.setColumnWidth(2, 200) self.titleTableView.setColumnWidth(1, 200) self.titleTableView.setColumnWidth(0, 200) self.titleTableView.sortByColumn(0, 0) self.tabWidget.setCurrentWidget(self.tab_4) @QtCore.pyqtSlot() def auth_btn_clicked(self): if self.auth_le.text(): lst = get_auth_by_name(self.db, self.auth_le.text()) else: return # if not lst: # return model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(['Имя автора', 'ID']) if self.booksOfAuth.model(): self.booksOfAuth.model().clear() for i in lst: model.appendRow([QtGui.QStandardItem(i[0]), QtGui.QStandardItem(str(i[-1]))]) self.authListView.setModel(model) self.authListView.setColumnHidden(1, True) self.authListView.sortByColumn(0, 0) self.authListView.resizeColumnToContents(0) self.authListView.horizontalHeader(). \ setDefaultAlignment(QtCore.Qt.AlignLeft) self.tabWidget.setCurrentWidget(self.tab_3) # noinspection PyPep8Naming @QtCore.pyqtSlot() def on_BooksOfAuth_click(self): idx = self.booksOfAuth.currentIndex() col = idx.column() row = idx.row() if col == 0: self.title_le.setText(idx.data().strip()) elif col == 2: self.series_le.setText(idx.data().strip()) book_id = idx.model().item(row, 5).text() self.get_book_annotation(book_id) @QtCore.pyqtSlot() def books_of_auth(self): """ Поиск книг автора по его ID """ idx = self.authListView.currentIndex() model = idx.model() auth_id = model.item(idx.row(), 1).text() self.auth_le.setText(idx.data().strip()) lst = get_books_by_auth_id(self.db, auth_id) # books_of_auth = QtGui.QStandardItemModel() # books_of_auth.setHorizontalHeaderLabels(['Название', # 'Альтернативное название', # 'Серия', # 'Номер в серии', # 'Год', # 'ID']) for i in lst: self.books_of_auth.appendRow([QtGui.QStandardItem(str(elem) if elem is not None else '') for elem in i]) # self.booksOfAuth.setModel(books_of_auth) # self.booksOfAuth.setColumnHidden(5, True) # self.booksOfAuth.sortByColumn(0, 0) # self.booksOfAuth.setColumnWidth(4, 45) # self.booksOfAuth.setColumnWidth(3, 110) # self.booksOfAuth.setColumnWidth(2, 110) # self.booksOfAuth.setColumnWidth(1, 200) # self.booksOfAuth.setColumnWidth(0, 200) def connect_btns(self, groupBox, func): """ Подключаем сигналы кнопок к слотам :param groupBox: QGroupBox :param func: :return: """ children = groupBox.children() # получаем дочерние элементы for elem in children: if isinstance(elem, QtWidgets.QPushButton): elem.toggled.connect(func) def alphabetic_dict(self, groupBox): """ В QGroupBox вставляем кнопки с буквами алфавита """ hbox_eng = QtWidgets.QHBoxLayout() hbox_rus = QtWidgets.QHBoxLayout() vbox = QtWidgets.QVBoxLayout() groupBox.setLayout(vbox) rus_dict, eng_dict = alphabet_dicts() def alphabet(box, dct): for i in dct: btn = QtWidgets.QPushButton(i) btn.setMaximumSize(19, 19) btn.setCheckable(True) btn.setAutoExclusive(True) btn.setFlat(True) box.addWidget(btn) box.addStretch(0) alphabet(hbox_eng, eng_dict) alphabet(hbox_rus, rus_dict) vbox.addLayout(hbox_eng) vbox.addLayout(hbox_rus) @QtCore.pyqtSlot() def on_genreBook_click(self): """ Заносим название книги из genreBook в title_le """ idx = self.genreBook.currentIndex() self.title_le.clear() self.auth_le.clear() if idx.column() == 0: self.title_le.setText(idx.data().strip()) else: self.auth_le.setText(idx.data().strip()) book_id = idx.model().item(idx.row(), 2).text() if not book_id: return self.get_book_annotation(book_id) @QtCore.pyqtSlot() def auth_char_checked(self): """ Находим авторов по букве алфавита """ btn = self.sender() if btn.isChecked(): letter = btn.text() lst = get_auth_by_letter(self.db, letter) if lst is None: return model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(['Имя автора', 'ID']) for i in lst: model.appendRow([QtGui.QStandardItem(str(i[0])), QtGui.QStandardItem(str(i[1]))]) self.authListView.setModel(model) self.authListView.setColumnHidden(1, True) self.authListView.sortByColumn(0, 0) self.authListView.resizeColumnToContents(0) self.authListView.horizontalHeader(). \ setDefaultAlignment(QtCore.Qt.AlignLeft) @QtCore.pyqtSlot() def series_char_checked(self): """ Получаем выбранную букву алфавита и находим серии """ btn = self.sender() # получаем кнопку, которая послала сигнал if btn.isChecked(): char = btn.text() lst = get_all_series(self.db, '%' if char == '*' else char) for i in lst: self.seriesModel.appendRow([QtGui.QStandardItem(str(i[0])), QtGui.QStandardItem(str(i[1]))]) @QtCore.pyqtSlot() def books_in_series(self): """ Книги в серии """ idx = self.seriesTableView.currentIndex() model = idx.model() series_id = model.item(idx.row(), 1).text() book_lst = get_books_by_series_id(self.db, series_id) books_in_series_model = QtGui.QStandardItemModel() books_in_series_model.setHorizontalHeaderLabels(['Автор', 'Название', 'Номер в серии', 'ID']) for i in book_lst: books_in_series_model.appendRow([QtGui.QStandardItem(str(item) if item is not None else '') for item in i]) self.booksInSeriesView.setModel(books_in_series_model) self.booksInSeriesView.setColumnHidden(3, True) self.booksInSeriesView.sortByColumn(0, 0) self.booksInSeriesView.horizontalHeader().setSectionResizeMode(0) self.booksInSeriesView.resizeColumnToContents(0) self.booksInSeriesView.resizeColumnToContents(1) # self.booksInSeriesView.horizontalHeader(). \ # setSectionResizeMode(0, QtWidgets.QHeaderView.Interactive) @QtCore.pyqtSlot() def get_book_annotation(self, book_id=None): """ Поиск аннотации по book_id и заполнение полей ввода автором и названием книги """ if not book_id: idx = self.booksInSeriesView.currentIndex() column = idx.column() model = idx.model() if column == 0: self.auth_le.clear() self.auth_le.setText(idx.data().strip()) # автор elif column == 1: self.title_le.clear() self.title_le.setText(idx.data().strip()) # название книги book_id = model.item(idx.row(), 3).text() annot = get_annotaion(self.db, book_id) self.annotation.clear() if not annot: self.annotation.setText('Аннотация отсутствует') else: self.annotation.setText(annot) @QtCore.pyqtSlot() def get_books_of_genre(self): """ Получить ниги определенного жанра """ idx = self.genreView.currentIndex() func = idx.sibling # получить индекс элемента того же уровня вложенности # parent = idx.parent() # индекс родительского элемента if idx.parent().isValid(): # родительский ли элемент. если родительский то False data = [func(idx.row(), i).data() for i in range(self.genreModel.columnCount())] lst = get_books_of_genre(self.db, data[-1]) model = QtGui.QStandardItemModel() # отображение книг определенного жанра self.genreBook.setModel(model) model.clear() model.setHorizontalHeaderLabels(['Название', 'Автор', 'ID']) for i in lst: model.appendRow([QtGui.QStandardItem(str(item) if item else '') for item in i]) self.genreBook.setColumnHidden(2, True) self.genreBook.horizontalHeader().setDefaultAlignment(QtCore.Qt.AlignLeft) # выравнивание текста self.genreBook.sortByColumn(0, 0) # сортировка по колонке 0 и порядок сортировки # self.genreBook.resizeColumnToContents(0) # self.genreBook.horizontalHeader(). \ # setSectionResizeMode(0) # растягивание заголовка в зависимости от содержания ячейки # noinspection PyMethodMayBeStatic def create_genre_model(self): """ Модель с жанрами """ lst = get_genre_lst(self.db) model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(['Жанр', 'Genre ID']) for k, v in lst.items(): root = QtGui.QStandardItem(k) for item in v: root.appendRow([QtGui.QStandardItem(item[0]), QtGui.QStandardItem(str(item[1]))]) model.appendRow(root) return model def about_library(self): """ Количество книг, серий, жанров и авторов в базе данных """ count_in_dbase = count(self.db) auth, genre, series, books = count_in_dbase self.auth_label.setText(str(auth)) self.genre_label.setText(str(genre)) self.books_label.setText(str(books)) self.series_label.setText(str(series)) if __name__ == '__main__': db = connect() app = QtWidgets.QApplication(sys.argv) win = MainForm(db) win.show() app.exec_() db.close()
Отредактировано asgrom (Авг. 10, 2018 01:58:53)
Офлайн
Поставь себе линтер (программа, проверяющая код на банальные ошибки).
Для твоего кода прогнал линтером
[guest@localhost py]$ pylint3 tqt.py
No config file found, using default configuration
************* Module tqt
C:208, 0: Line too long (116/100) (line-too-long)
C:313, 0: Line too long (119/100) (line-too-long)
C:365, 0: Line too long (109/100) (line-too-long)
C:369, 0: Line too long (102/100) (line-too-long)
C:401, 0: Final newline missing (missing-final-newline)
E: 29, 0: Unable to import 'querydb' (import-error)
W: 29, 0: Wildcard import querydb (wildcard-import)
C: 31, 0: Missing function docstring (missing-docstring)
C: 44, 8: Invalid attribute name "db" (invalid-name)
C: 74, 8: Invalid attribute name "seriesModel" (invalid-name)
C: 84, 8: Invalid attribute name "genreModel" (invalid-name)
C: 37, 0: Missing class docstring (missing-docstring)
W: 38,23: Redefining name 'db' from outer scope (line 396) (redefined-outer-name)
C: 47, 4: Invalid method name "initUI" (invalid-name)
C: 47, 4: Missing method docstring (missing-docstring)
C: 73, 4: Missing method docstring (missing-docstring)
C: 83, 4: Missing method docstring (missing-docstring)
C: 90, 4: Missing method docstring (missing-docstring)
C:107, 4: Missing method docstring (missing-docstring)
E:110,14: Undefined variable 'get_series_by_name' (undefined-variable)
C:118, 4: Invalid method name "on_titleTableView_click" (invalid-name)
C:118, 4: Missing method docstring (missing-docstring)
C:130, 4: Missing method docstring (missing-docstring)
E:132,14: Undefined variable 'get_title' (undefined-variable)
C:157, 4: Missing method docstring (missing-docstring)
E:159,18: Undefined variable 'get_auth_by_name' (undefined-variable)
C:180, 4: Invalid method name "on_BooksOfAuth_click" (invalid-name)
C:180, 4: Missing method docstring (missing-docstring)
E:191, 4: An attribute defined in tqt line 91 hides this method (method-hidden)
E:199,14: Undefined variable 'get_books_by_auth_id' (undefined-variable)
C:217, 4: Invalid argument name "groupBox" (invalid-name)
R:217, 4: Method could be a function (no-self-use)
C:228, 4: Invalid argument name "groupBox" (invalid-name)
C:237, 8: Missing function docstring (missing-docstring)
R:228, 4: Method could be a function (no-self-use)
C:251, 4: Invalid method name "on_genreBook_click" (invalid-name)
E:274,18: Undefined variable 'get_auth_by_letter' (undefined-variable)
E:296,18: Undefined variable 'get_all_series' (undefined-variable)
E:308,19: Undefined variable 'get_books_by_series_id' (undefined-variable)
E:338,16: Undefined variable 'get_annotaion' (undefined-variable)
E:354,18: Undefined variable 'get_books_of_genre' (undefined-variable)
E:375,14: Undefined variable 'get_genre_lst' (undefined-variable)
C:378,15: Invalid variable name "v" (invalid-name)
E:389,25: Undefined variable 'count' (undefined-variable)
W: 74, 8: Attribute 'seriesModel' defined outside __init__ (attribute-defined-outside-init)
W: 84, 8: Attribute 'genreModel' defined outside __init__ (attribute-defined-outside-init)
C:396, 4: Invalid constant name "db" (invalid-name)
E:396, 9: Undefined variable 'connect' (undefined-variable)
C:397, 4: Invalid constant name "app" (invalid-name)
C:398, 4: Invalid constant name "win" (invalid-name)
C: 28, 0: standard import "import sys" should be placed before "from PyQt5 import QtWidgets, QtGui, QtCore, uic" (wrong-import-order)
C: 30, 0: standard import "import string" should be placed before "from PyQt5 import QtWidgets, QtGui, QtCore, uic" (wrong-import-order)
-----------------------------------
Your code has been rated at 5.88/10
[guest@localhost py]$
[guest@localhost py]$
[guest@localhost py]$
[guest@localhost py]$
[guest@localhost py]$
[guest@localhost py]$ pypep8 tqt.py
tqt.py:20:80: E501 line too long (92 > 79 characters)
tqt.py:31:1: E302 expected 2 blank lines, found 0
tqt.py:37:1: E302 expected 2 blank lines, found 0
tqt.py:47:5: E301 expected 1 blank line, found 0
tqt.py:59:80: E501 line too long (81 > 79 characters)
tqt.py:63:80: E501 line too long (93 > 79 characters)
tqt.py:73:5: E301 expected 1 blank line, found 0
tqt.py:82:80: E501 line too long (86 > 79 characters)
tqt.py:83:5: E301 expected 1 blank line, found 0
tqt.py:90:5: E301 expected 1 blank line, found 0
tqt.py:101:80: E501 line too long (80 > 79 characters)
tqt.py:106:5: E301 expected 1 blank line, found 0
tqt.py:114:80: E501 line too long (86 > 79 characters)
tqt.py:117:5: E301 expected 1 blank line, found 0
tqt.py:129:5: E301 expected 1 blank line, found 0
tqt.py:156:5: E301 expected 1 blank line, found 0
tqt.py:179:5: E301 expected 1 blank line, found 0
tqt.py:190:5: E301 expected 1 blank line, found 0
tqt.py:208:80: E501 line too long (116 > 79 characters)
tqt.py:217:5: E301 expected 1 blank line, found 0
tqt.py:228:5: E301 expected 1 blank line, found 0
tqt.py:237:9: E301 expected 1 blank line, found 0
tqt.py:250:5: E301 expected 1 blank line, found 0
tqt.py:266:5: E301 expected 1 blank line, found 0
tqt.py:288:5: E301 expected 1 blank line, found 0
tqt.py:300:5: E301 expected 1 blank line, found 0
tqt.py:311:80: E501 line too long (80 > 79 characters)
tqt.py:313:80: E501 line too long (119 > 79 characters)
tqt.py:322:5: E301 expected 1 blank line, found 0
tqt.py:325:80: E501 line too long (85 > 79 characters)
tqt.py:344:5: E301 expected 1 blank line, found 0
tqt.py:350:80: E501 line too long (81 > 79 characters)
tqt.py:352:80: E501 line too long (89 > 79 characters)
tqt.py:353:80: E501 line too long (92 > 79 characters)
tqt.py:355:80: E501 line too long (86 > 79 characters)
tqt.py:365:80: E501 line too long (109 > 79 characters)
tqt.py:366:80: E501 line too long (93 > 79 characters)
tqt.py:369:80: E501 line too long (102 > 79 characters)
tqt.py:371:5: E301 expected 1 blank line, found 0
tqt.py:385:5: E301 expected 1 blank line, found 0
tqt.py:401:15: W292 no newline at end of file
[guest@localhost py]$
import tqt help(tqt)
asgromТак не стоит выравнивать. Если аргументы не влазят, переноси их все с отступом.self.books_of_auth.setHorizontalHeaderLabels(['Название', 'Альтернативное название', 'Серия', 'Номер в серии', 'Год', 'ID'])
self.books_of_auth.setHorizontalHeaderLabels( ['Название', 'Альтернативное название', 'Серия', 'Номер в серии', 'Год', 'ID'])
Отредактировано py.user.next (Авг. 10, 2018 05:44:40)
Офлайн
py.user.nextСпс большое.
Поставь себе линтер (программа, проверяющая код на банальные ошибки).Для твоего кода прогнал линтером
Офлайн
Еще кое-что, в прошлых версиях PEP 8 (и в нынешней тоже кое-что есть) говорилось, что при заранее известном наборе используемых фуекций модуля лучше использовать конструкцию
from module import func1, func2, func3
import module
# Life loop while alive: if (fun > boredom) and money: pass_day(fun, boredom, money) continue else: break
Офлайн
Я уже много раз писал что PEP 8 это плохой стандарт и нет никаких объективных причин что бы его придерживаться.
Офлайн
RodegastХм, я думал что это 1ое правило по поддержке формата кода.
Я уже много раз писал что PEP 8 это плохой стандарт и нет никаких объективных причин что бы его придерживаться.
# Life loop while alive: if (fun > boredom) and money: pass_day(fun, boredom, money) continue else: break
Офлайн
> Хм, я думал что это 1ое правило по поддержке формата кода.
Первое правило это наличие формализованного стиля кодирования. Действительно в качестве его обычно используют PEP 8 (хотя он и является анахронизмом), но ты это делать не обязан.
Офлайн