From 1b2971e76f5c5691d54b740400f57154740d400e Mon Sep 17 00:00:00 2001 From: Mac Date: Fri, 21 Nov 2025 14:02:50 +0300 Subject: [PATCH 1/2] 544_table_percentage --- app/main/check_packs/pack_config.py | 1 + app/main/checks/report_checks/__init__.py | 1 + .../checks/report_checks/table_percentage.py | 127 ++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 app/main/checks/report_checks/table_percentage.py diff --git a/app/main/check_packs/pack_config.py b/app/main/check_packs/pack_config.py index 91e08134..63946d7b 100644 --- a/app/main/check_packs/pack_config.py +++ b/app/main/check_packs/pack_config.py @@ -38,6 +38,7 @@ ["literature_references"], ["image_references"], ["table_references"], + ["table_percentage"], ["first_pages_check"], ["main_character_check"], ["needed_headers_check"], diff --git a/app/main/checks/report_checks/__init__.py b/app/main/checks/report_checks/__init__.py index 0ed2a8dc..511311b1 100644 --- a/app/main/checks/report_checks/__init__.py +++ b/app/main/checks/report_checks/__init__.py @@ -8,6 +8,7 @@ from .literature_references import ReferencesToLiteratureCheck from .image_references import ImageReferences from .table_references import TableReferences +from .table_percentage import TablePercentage from .main_text_check import ReportMainTextCheck from .needed_headers_check import ReportNeededHeadersCheck from .page_counter import ReportPageCounter diff --git a/app/main/checks/report_checks/table_percentage.py b/app/main/checks/report_checks/table_percentage.py new file mode 100644 index 00000000..b326fe04 --- /dev/null +++ b/app/main/checks/report_checks/table_percentage.py @@ -0,0 +1,127 @@ + +import fitz +from docx import Document +from ..base_check import BaseReportCriterion, answer + +default_font_size: int = 12 # Значение размера шрифта по умолчанию +default_line_spacing: float = 1.0 # Значение межстрочного интервала по умолчанию +chars_per_line: int = 20 # Примерное кол-во символов в строке ячейки +cell_padding = 5 # Примерный размер отступов от границ ячейки +row_padding = 2 # Примерное расстояние между строками таблиц + +#С данными значениями погрешность 4-5 процентов + + +class TablePercentage(BaseReportCriterion): + label = "Проверка процентного соотношения таблиц в документе" + description = "Проверяет, что таблицы занимают не более установленного процента площади документа" + id = 'table_percentage' + + + def __init__(self, file_info, max_percentage = 30): + super().__init__(file_info) + self._max_percentage = max_percentage + + def get_font_size(self, run, paragraph) -> float: + """Функция получения размера шрифта""" + if run.font.size: + return run.font.size.pt + elif run.style and run.style.font.size: + return run.style.font.size.pt + elif paragraph.style and paragraph.style.font.size: + return paragraph.style.font.size.pt + else: + return default_font_size + + def heightCell(self, cell) -> float: + """Функция получения высоты ячейки""" + total_height = 0 + + for paragraph in cell.paragraphs: + line_count = 1 + + text_length = len(paragraph.text) + if text_length > 0: + line_count = max(1, (text_length + chars_per_line - 1) // chars_per_line) + + max_font_size = default_font_size + for run in paragraph.runs: + font_size = self.get_font_size(run, paragraph) + max_font_size = max(max_font_size, font_size) + + line_spacing = default_line_spacing + + paragraph_height = line_count * max_font_size * line_spacing + total_height += paragraph_height + + if paragraph.paragraph_format.space_after: + total_height += paragraph.paragraph_format.space_after.pt + if paragraph.paragraph_format.space_before: + total_height += paragraph.paragraph_format.space_before.pt + + total_height += 2 * cell_padding + + return total_height + + def heightTable(self, table) -> float: + """Функция получения высоты таблицы""" + total_height = 0 + for row in table.rows: + if row.height: + total_height += row.height.pt + else: + heights = [] + for cell in row.cells: + heights.append(self.heightCell(cell)) + total_height += max(heights) if heights else 0 + + total_height += row_padding + + return total_height + + def getPercentOfTables(self) -> float: + """Функция получение процента таблиц в документе""" + doc_docx = self.file.file + + page_count = self.file.page_counter() + if page_count == 0: + return 0 + + section = doc_docx.sections[0] + page_height = section.page_height.pt + total_height = page_height * page_count + + if total_height == 0: + return 0 + + tables_height = 0 + + for table in doc_docx.tables: + table_height = self.heightTable(table) + tables_height += table_height + + percentage = (tables_height / total_height) * 100 + return percentage + + def check(self): + try: + if self.file.page_counter() < 4: + return answer(False, "В отчете недостаточно страниц. Нечего проверять.") + + percent_tables = self.getPercentOfTables() + + if percent_tables <= self._max_percentage: + return answer( + True, + "Пройдена!" + ) + else: + return answer( + False, + f"Таблицы занимают {percent_tables:.1f}% документа, " + f"что превышает допустимые {self._max_percentage}%. " + f"Рекомендуется сократить количество или размер таблиц." + ) + except Exception as e: + return answer(False, f"Ошибка при проверке процентного соотношения таблиц: {str(e)}") + From d3d35edf6a7371e69e1d436a327adaa09a1ea343 Mon Sep 17 00:00:00 2001 From: Mac Date: Tue, 25 Nov 2025 11:51:37 +0300 Subject: [PATCH 2/2] exclusion of applications tables --- .../checks/report_checks/table_percentage.py | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/app/main/checks/report_checks/table_percentage.py b/app/main/checks/report_checks/table_percentage.py index b326fe04..6c6fc664 100644 --- a/app/main/checks/report_checks/table_percentage.py +++ b/app/main/checks/report_checks/table_percentage.py @@ -1,4 +1,3 @@ - import fitz from docx import Document from ..base_check import BaseReportCriterion, answer @@ -11,16 +10,16 @@ #С данными значениями погрешность 4-5 процентов - class TablePercentage(BaseReportCriterion): label = "Проверка процентного соотношения таблиц в документе" description = "Проверяет, что таблицы занимают не более установленного процента площади документа" id = 'table_percentage' - def __init__(self, file_info, max_percentage = 30): + def __init__(self, file_info, hasApplication = True,max_percentage = 30): super().__init__(file_info) self._max_percentage = max_percentage + self._hasApplication = hasApplication def get_font_size(self, run, paragraph) -> float: """Функция получения размера шрифта""" @@ -96,13 +95,45 @@ def getPercentOfTables(self) -> float: tables_height = 0 - for table in doc_docx.tables: - table_height = self.heightTable(table) - tables_height += table_height + end_index = len(doc_docx.tables) + + if self._hasApplication: + end_index = self.find_table_index_after_text('ПРИЛОЖЕНИЕ') + end_index = end_index if end_index is not None else len(doc_docx.tables) + + for table_index, table in enumerate(doc_docx.tables): + if table_index < end_index: + table_height = self.heightTable(table) + tables_height += table_height percentage = (tables_height / total_height) * 100 return percentage + + def find_table_index_after_text(self, target_text: str) -> int | None: + """Функция находит первый индекс таблицы после target_text, если не найден, то вернет None""" + doc_docx = self.file.file + for i, paragraph in enumerate(doc_docx.paragraphs): + if target_text in paragraph.text: + + para_elem = paragraph._element + following_tables = para_elem.xpath('./following-sibling::w:tbl') + + for table_elem in following_tables: + + for index, table in enumerate(doc_docx.tables): + if table._element == table_elem: + return index + + return None + + def find_tables_indexs_between_text(self,start_text: str, end_text: str | None = None): + """Функция нахождения индексов начала и конца таблиц между двумя текстами""" + start_index = self.find_table_index_after_text(start_text) + end_index = self.find_table_index_after_text(end_text) + + return (start_index, end_index) + def check(self): try: if self.file.page_counter() < 4: @@ -118,9 +149,15 @@ def check(self): else: return answer( False, - f"Таблицы занимают {percent_tables:.1f}% документа, " - f"что превышает допустимые {self._max_percentage}%. " - f"Рекомендуется сократить количество или размер таблиц." + f''' + Таблицы занимают {percent_tables:.1f}% документа, что превышает допустимые {self._max_percentage}%. + Рекомендации: + + ''' ) except Exception as e: return answer(False, f"Ошибка при проверке процентного соотношения таблиц: {str(e)}")