From d40e8977f024fd0efbb81c9e80ce5158c60fb14c Mon Sep 17 00:00:00 2001 From: LeaonArchie Date: Sun, 23 Feb 2025 09:55:12 +0300 Subject: [PATCH] releace v.4.0.0 --- CODE_OF_CONDUCT.md | 1 + LICENSE | 1 - README.md | 59 ++++++--- README_user.md | 200 +++++++++++++++++++++++++++++ SECURITY.md | 5 +- Scripts/Final_check.py | 81 ++++++++++++ Scripts/FindError.py | 7 +- Scripts/Lider.py | 70 ++++++++--- Scripts/add_groups.py | 156 +++++++++++++++++++++++ Scripts/add_key.py | 80 ++++++++++++ Scripts/all_null_lesson.py | 120 ++++++++++++++++++ Scripts/check_group.py | 24 ++-- Scripts/csv_to_json.py | 8 +- Scripts/delete.py | 31 +++-- Scripts/exel_to_csv.py | 6 +- Scripts/json_to_GIS_SO.py | 2 +- Scripts/lesson_sort.py | 57 +++++++++ Scripts/normalization.py | 235 ----------------------------------- Scripts/sinh_time.py | 59 +++++++++ Scripts/update_cab.py | 56 +++++++++ Scripts/update_lesson_gis.py | 78 ++++++++++++ 21 files changed, 1037 insertions(+), 299 deletions(-) create mode 100644 README_user.md create mode 100644 Scripts/Final_check.py create mode 100644 Scripts/add_groups.py create mode 100644 Scripts/add_key.py create mode 100644 Scripts/all_null_lesson.py create mode 100644 Scripts/lesson_sort.py delete mode 100644 Scripts/normalization.py create mode 100644 Scripts/sinh_time.py create mode 100644 Scripts/update_cab.py create mode 100644 Scripts/update_lesson_gis.py diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index bc01d5f..f3b5e8f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -117,3 +117,4 @@ enforcement ladder](https://github.com/mozilla/diversity). Ответы на общие вопросы о данном кодексе поведения ищите на странице FAQ: https://www.contributor-covenant.org/faq. Переводы доступны по адресу https://www.contributor-covenant.org/translations. + diff --git a/LICENSE b/LICENSE index 5f98dd1..af1d96d 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,6 @@ See the License for the specific language governing permissions and limitations under the License. - Лицензия Apache Версия 2.0, январь 2004 года http://www.apache.org/licenses/ diff --git a/README.md b/README.md index 5fd78d2..4fd7bc0 100644 --- a/README.md +++ b/README.md @@ -13,29 +13,45 @@ Leader.py Основной скрипт, координирующий выполнение всех остальных скриптов. Управляет порядком выполнения, обрабатывает ошибки. delete.py - Скрипт для удаления временных файлов + Удаление временных файлов если они существуют exel_to_csv.py - Преобразует Excel-файлы (.xlsx или .xls) в CSV-файлы с разделителем ; и кодировкой Windows-1251. + Преобразовывает файлы в csv формат в кодировке windows-1251 + csv_to_json.py - Преобразует CSV-файлы с расписанием в JSON-формат. (кодировка UTF-8) + Преобразовывает csv файл расписания в json файл для работы программы + FindError.py - Проверяет данные в JSON-файле на соответствие спискам классов и уроков из CSV-файлов. Записывает найденные ошибки в файл error.log. + Выполняет проверку на ошибка файла raspisanie.json - ! ВНИМАНИЕ ! - Если обнаружены ошибки, то исполнение будет остановлено - - normalization.py - Нормализует структуру JSON-файла, добавляя недостающие ключи и исправляя форматирование. (создает файл raspisanie_modified.json в кодировке UTF-8) - - check_group.py - Проверяет предметы из справочника групп и если такой предмет встречается в расписании без группы записывает предупреждение в err_groups.log + add_key.py + Технический скрипт, проверяет ключи в файле raspisanie.json - ! ВНИМАНИЕ ! - Эти ошибки НЕ блокируют работу скрипта + sinh_time.py + Технический скрипт, добавляет время в уроки по подгруппам - json_to_GIS_SO.py - Преобразует нормализованный JSON-файл в CSV-формат, подходящий для импорта в ГИС СО ЕЦП. + add_groups.py + Скрипт выполняет привязку групп к урокам которые где они должны быть + + all_null_lesson.py + Технический скрипт, нормализует raspisanie_groups_added.json добавляя пустые массивы + lesson_sort.py + Технический скрипт, сортирует массивы в нутри дня недели + + update_cab.py + Технический скрипт, добавляет значение Нет кабинет там где они не указаны + + check_group.py + Скрипт проверяет назначение групп + + update_lesson_gis.py + Скрипт выполняет замену названий уроков с соответсвии с справочником zamena.csv + + Final_check.py + Скрипт выполняет проверки названий уроков в соответсвии с справочником уроков lesson.csv + + json_to_GIS_SO.py + Скрипт готовит расписание для загрузки в ГИС СО ЕЦП Зависимости Для работы скриптов требуются следующие библиотеки Python: @@ -55,6 +71,8 @@ lesson.xlsx: Список уроков. (Выгружается из справочников ГИС СО ЕЦП) groups.xlsx: Список групп в связке с классом и предметом Класс Предмет Учитель Группа + zamens.xlsx^ Список уроков для замены + Ключ Значение !ВНИМАНИЕ! @@ -90,6 +108,8 @@ log.log: Журнал событий. error.log: Файл с ошибками (если они были обнаружены). err_groups.log: Файл с ошибками групп (если они были обнаружены). + chech_groups.log: Файл с ошибками назначения групп. + final_error.log: Файл с ошибками финальной проверки перед загрузкой Важные замечания: Все файлы должны быть в кодировке cp1251 (Windows-1251), за исключением JSON-файлов, которые используют кодировку utf-8. @@ -128,4 +148,9 @@ Дата: 03.02.2025 Версия: 3.0 - Если у вас возникли вопросы или предложения по улучшению проекта, пожалуйста, свяжитесь с автором. \ No newline at end of file + Если у вас возникли вопросы или предложения по улучшению проекта, пожалуйста, свяжитесь с автором. + + Если у Вас возникла какая либо ошибка которую Вы не можете разобрать самостоятельно + После исполнения скрипта не изменяйте никаких файлов, заархивируте всю папку со скриптом + Отправьте архив по адресу levmikhailovish@yandex.ru и/или service@ippetunin.ru + В теле письма опишите Вашу проблему и мы постараемся помочь в ближайшее время \ No newline at end of file diff --git a/README_user.md b/README_user.md new file mode 100644 index 0000000..a5ba9cc --- /dev/null +++ b/README_user.md @@ -0,0 +1,200 @@ +Изменения в релизе v.4.0.0 + + Скрипт normalizations.py удален + Функционал скрипта распределен по другим скриптам + Добавлен функционал замены уроков по списку замен + + Порядок работы + Выгрузите расписание из ПО АВЕРС + Прведите нормализацию файла расписания + - Не трогайте строки до первого класса (они будут проверяться при запуске программы) + - Уберите незначащие строки (строки к которых нет уроков а указано только время) + - Приведите расписание к формату (РАСПИСАНИЕ КЛАССА - ПУСТАЯ СТРОКА - КЛАСС - ПУСТАЯ СТРОКА) + - Первый столбец выделите и установить тип ячеек текст + - Проверьте что номера уроков состоят только из цифр от 1 до 10 (номера уроков второй смены нужно изменить на 1-10) + - Переименуйте файл в raspisanie.xlsx + - Положите файл в папку со скриптами + + Подготовьте справочник кабинетов klass.xlsx + - Выгрузите справочник из ГИС СО ЕЦП + Ручных правок как правило не требуется + - Формат справочника + Кабинеты + Наименование школы + Заголовки + Далее в первом столбце перечислите наименования кабинетов, в одной ячейке один кабинет + + - Переименуйте файл в klass.xlsx + - Положите файл в папку со скриптами + + Подготовьте справичник уроков lesson.xlsx + - Выгрузите справочник из ГИС СО ЕЦП + Ручных правок не требуется + + - Переименуйте файл в lesson.xlsx + - Положите файл в папку со скриптами + + Подготовьте справочник групп groups.xlsx + - Можно составить самостоятельно или частично выгрузить из справчника групп ГИС СО ЕЦП + - Формат файла + Заголовки + Первый столбец Второй столбец Третий столбец Четвертый столбец + Класс Предмет Учитель Группа + Пример 11А Информатика Иванов И. И. Группа 1 + + - Переименуйте файл в groups.xlsx + - Положите файл в папку со скриптами + + + ! ВАЖНО ! + + ГИС СО ЕЦП Не умеет работать со скобками проследите что в названиях предметов и в группах нет скобок + Если у Вас в названиях уроков при выгрузке есть скобки то скрипт замен специально для Вас + Группы нужно отредактировать и привести к формату без скобок + + ! ВАЖНО ! + + Подготовьте справочник замены zamena.xlsx + - Формат файла + Заголовки + Первый столбец Второй столбец + (Что меняем) (На что меняем) + Пример Алгебра (е) Алгебра и начало математического анализа + + - Переименуйте файл в zamena.xlsx + - Положите файл в папку со скриптами + + Запустите файл Lider.py + Будут по очереди запускаться скрипты весь ход исполнения записывается в файл log.log + В случае обнаружения ошибок в этом файле скрипт запросит разрешение на продолжение работы + Так же если будут обнаружены файлы ошибок "error.log", "err_groups.log", "chech_groups.log", "final_error.log" + скрипт так же будет ждать раррешения на продолжение + + Оприсание исполнения скриптов + delete.py + Удаление временных файлов если они существуют + Список файлов + "log.log", + "error.log", + "err_groups.log", + "final_error.log", + "chech_groups.log", + "GIS_schedule.csv", + "klass.csv", + "lesson.csv", + "raspisanie.csv", + "groups.csv", + "zamena.csv", + "raspisanie.json", + "raspisanie_key_added.json", + "raspisanie_sinh_time.json", + "raspisanie_groups_added.json", + "raspisanie_null_lesson_added.json", + "raspisanie_sorted_schedule.json", + "raspisanie_replace_lessons.json", + "raspisanie_cab_updated.json" + exel_to_csv.py + Преобразовывает файлы 'raspisanie.xlsx', 'klass.xlsx', 'lesson.xlsx', 'groups.xlsx', 'zamena.xlsx' + В csv формат в кодировке windows-1251 + На выходе получаем 'raspisanie.csv', 'klass.csv', 'lesson.csv', 'groups.csv', 'zamena.csv' + + csv_to_json.py + Преобразовывает csv файл расписания в json файл для работы программы + Принимает на вход файл raspisanie.csv + На выходе отдает файл raspisanie.json + + + ! ВАЖНО ! + + Все json файлы в кодировке utf-8 + + ! ВАЖНО ! + + + FindError.py + Выполняет проверку на ошибка файла raspisanie.json + Скрипт проверяет, что наименования уроков и кабинета существуют в ГИС СО ЕЦП + Скрипт проверяет какие кабинеты и уроки есть в справочниках lesson.csv, klass.csv + Затем сверяет, что в расписание внесены именно эти уроки и кабинеты + Если скрипт выявляет отклонения то записывает ошибки в файл error.log + + Ошибки не всегда являются стоп факторм для остановки работы + Если в будущем эти уроки будут заменены скриптом замены, то ошибки можно игнорировать + В будущем релизе будет дополнительная проверка которая уберет эти ошибки + + В противном случае нужно внести исправления + + + add_key.py + Технический скрипт, проверяет ключи в файле raspisanie.json + Исправляет ошибки ключей если их обнаруживает + На выходе имеем файл raspisanie_key_added.json + + sinh_time.py + Технический скрипт + Добавляет время в уроки по подгруппам + Входящий файл raspisanie_key_added.json + На выходе имеем raspisanie_sinh_time.json + + add_groups.py + Скрипт выполняет привязку групп к урокам которые где они должны быть + Входящий файл raspisanie_sinh_time.json + Справочник для работы groups.csv + На выходе имеем raspisanie_groups_added.json + Проверка ведется по связке + Класс + Предмет + Учитель + Если для связки найдено более отдного совпадения, то + На одного учителя будут назначены обе группы + Если связка только одна, то она привяжется по соответсвующим ключам + Ошибки дополнительно отбрасываются в err_groups.log + + all_null_lesson.py + Технический скрипт + Нормализует raspisanie_groups_added.json добавляя пустые массивы + Там где они необходимы, уравнивая количество массивов в каждом дне недели для класса + На вызоде имеем raspisanie_null_lesson_added.json + + lesson_sort.py + Технический скрипт + Сортирует массивы в нутри дня недели + На вход raspisanie_null_lesson_added.json + На выходе raspisanie_sorted_schedule.json + + update_cab.py + Технический скрипт + Проверяет файл raspisanie_sorted_schedule.json + Добавляет значение Нет кабинет там где они не указаны + Пустые массивы игнорирует + На выходе raspisanie_cab_updated.json + + check_group.py + Скрипт проверяет назначение групп + если предмет указан в справочнике groups.csv + но группы не привязаны записывает ошибка в файл chech_groups.log + Возомжны ложные срабатывания, например в начально школе урок технология ведет классный руководитель + для всего класса, соответсвенно группа не указана. + Такие ошибки можно игнорировать + + update_lesson_gis.py + Скрипт выполняет замену названий уроков с соответсвии с справочником zamena.csv + На вход принимает файл raspisanie_cab_updated.json + На выходе имеем файл raspisanie_replace_lessons.json + + Final_check.py + Скрипт выполняет проверки названий уроков в соответсвии с справочником уроков lesson.csv + Ошибки отбрасывает в файл final_error.log + Не рекомендую игнорировать ошибки в данном файле (гарантировано будут ошибки при загрузке) + + json_to_GIS_SO.py + Скрипт готовит расписание для загрузки в ГИС СО ЕЦП + Берет файл raspisanie_replace_lessons.json + На выходе иммем файл GIS_schedule.csv + + Осталось только открыть полученный файл сокопировать все в шаблон от ГИС СО ЕЦП + Загрузить на сервер + Вы бесподобны + + Если у Вас возникла какая либо ошибка которую Вы не можете разобрать самостоятельно + После исполнения скрипта не изменяйте никаких файлов, заархивируте всю папку со скриптом + Отправьте архив по адресу levmikhailovish@yandex.ru и/или service@ippetunin.ru + В теле письма опишите Вашу проблему и мы постараемся помочь в ближайшее время diff --git a/SECURITY.md b/SECURITY.md index 8558357..8c26e72 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,10 +5,11 @@ | Версия | Поддержка | | ------- | ------------------ | -| 3.0 | :white_check_mark: | +| 4.0 | :white_check_mark: | +| 3.0 | :x: | | 2.1 | :x: | | 2.0 | :x: | -| < 1.0 | :x: | +| 1.0 | :x: | ## Сообщение об уязвимости diff --git a/Scripts/Final_check.py b/Scripts/Final_check.py new file mode 100644 index 0000000..2e70bb6 --- /dev/null +++ b/Scripts/Final_check.py @@ -0,0 +1,81 @@ +import csv +import json +import logging +import time + +# Настройка логирования +logging.basicConfig( + filename='log.log', + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s' +) + +time.sleep(2) + +# Открываем файл klass.csv и считываем первые значения из каждой строки (пропуская первые 3 строки) +klass = [] +try: + with open('klass.csv', 'r', encoding='windows-1251') as file: + reader = csv.reader(file, delimiter=';') + for i in range(3): # Пропускаем первые 3 строки + next(reader, None) + for row in reader: + if row: # Проверяем, что строка не пустая + klass.append(row[0].strip()) + logging.info("Файл klass.csv успешно обработан.") +except Exception as e: + logging.error(f"Ошибка при чтении файла klass.csv: {e}") + +# Открываем файл lesson.csv и считываем все строки (пропуская первые 2 строки) +lesson = [] +try: + with open('lesson.csv', 'r', encoding='windows-1251') as file: + reader = csv.reader(file, delimiter=';') + for i in range(2): # Пропускаем первые 2 строки + next(reader, None) + for row in reader: + if row: # Проверяем, что строка не пустая + lesson.append(row[0].strip()) + logging.info("Файл lesson.csv успешно обработан.") +except Exception as e: + logging.error(f"Ошибка при чтении файла lesson.csv: {e}") + +# Считываем файл raspisanie_replace_lessons.json +try: + with open('raspisanie_replace_lessons.json', 'r', encoding='utf-8') as file: + data = json.load(file) + logging.info("Файл raspisanie_replace_lessons.json успешно загружен.") +except Exception as e: + logging.error(f"Ошибка при чтении файла raspisanie_replace_lessons.json: {e}") + exit() + +# Проверяем значения в JSON файле +errors = [] +for class_name, days in data.items(): + for day, lessons in days.items(): + for lesson_num, lesson_info in lessons.items(): + # Проверяем ключ "lesson" + lesson_value = lesson_info.get("lesson", "").strip() + if lesson_value and lesson_value not in lesson: # Проверяем только если значение не пустое + errors.append(f"Класс: {class_name}, День: {day}, Урок: {lesson_num}, " + f"Несоответствие в lesson: {lesson_value}") + # Проверяем ключ "number" + number_value = lesson_info.get("number", "").strip() + if number_value and number_value != "Нет кабинета" and number_value not in klass: # Игнорируем "Нет кабинета" + errors.append(f"Класс: {class_name}, День: {day}, Урок: {lesson_num}, " + f"Несоответствие в number: {number_value}") + +# Записываем ошибки в файл final_error.log +if errors: + try: + with open('final_error.log', 'w', encoding='utf-8') as file: + for error in errors: + file.write(error + '\n') + logging.error(error) + logging.info("Несоответствия записаны в файл final_error.log.") + except Exception as e: + logging.error(f"Ошибка при записи в файл final_error.log: {e}") +else: + logging.info("Несоответствий не найдено.") + +time.sleep(2) \ No newline at end of file diff --git a/Scripts/FindError.py b/Scripts/FindError.py index 582f9de..9fcdc38 100644 --- a/Scripts/FindError.py +++ b/Scripts/FindError.py @@ -1,6 +1,7 @@ import csv import json import logging +import time # Настройка логирования logging.basicConfig( @@ -9,6 +10,8 @@ format='%(asctime)s - %(levelname)s - %(message)s' ) +time.sleep(2) + # Открываем файл klass.csv и считываем первые значения из каждой строки (пропуская первые 3 строки) klass = [] try: @@ -75,4 +78,6 @@ except Exception as e: logging.error(f"Ошибка при записи в файл error.log: {e}") else: - logging.info("Несоответствий не найдено.") \ No newline at end of file + logging.info("Несоответствий не найдено.") + +time.sleep(2) \ No newline at end of file diff --git a/Scripts/Lider.py b/Scripts/Lider.py index 205a621..ccc4fd6 100644 --- a/Scripts/Lider.py +++ b/Scripts/Lider.py @@ -8,8 +8,15 @@ ".\\exel_to_csv.py", ".\\csv_to_json.py", ".\\FindError.py", - ".\\normalization.py", + ".\\add_key.py", + ".\\sinh_time.py", + ".\\add_groups.py", + ".\\all_null_lesson.py", + ".\\lesson_sort.py", + ".\\update_cab.py", ".\\check_group.py", + ".\\update_lesson_gis.py", + ".\\Final_check.py", ".\\json_to_GIS_SO.py" ] @@ -28,39 +35,66 @@ def run_script(script_path): def read_file(file_name, encoding="cp1251"): if os.path.exists(file_name): with open(file_name, "r", encoding=encoding) as file: - return file.read() + content = file.read() + return content return None # Функция для обработки ошибок -def handle_error(error_message, log_file="log.log"): +def handle_error(error_message): print(error_message) - log_content = read_file(log_file) - if log_content: - print("\nСодержимое файла log.log:") - print(log_content) + +# Функция для запроса согласия пользователя +def ask_user_confirmation(prompt): + while True: + user_input = input(prompt).strip().lower() + if user_input in ['да', 'yes']: + return True + elif user_input in ['нет', 'no']: + return False + else: + print("Пожалуйста, введите 'да' или 'нет'.") # Основной код if __name__ == "__main__": + # Пауза перед стартом + print(f"Начинаю работу") + time.sleep(2) + for i, script in enumerate(scripts_to_run): # Запуск скрипта + print(f"Скрипт {script} запущен.") success = run_script(script) if not success: handle_error("Остановлено из-за ошибки. Проверьте файл log.log.") break - # Проверка наличия error.log после FindError.py - if script == ".\\FindError.py": - if os.path.exists("error.log"): - error_content = read_file("error.log") - print("Найден файл error.log. Выполнение прекращено.") - if error_content: - print("\nСодержимое файла error.log:") - print(error_content) - break + # Пауза после выполнения скрипта + print(f"Скрипт {script} выполнен. Ожидание 5 секунд перед следующими проверками...") + time.sleep(5) - # Вывод сообщения о завершении скрипта и таймаут - print(f"Скрипт {script} выполнен. Ожидание 3 секунды перед запуском следующего скрипта...") + # Пауза перед проверкой специальных файлов + print("Проверка специальных файлов через 3 секунды...") time.sleep(3) + # Проверка файла log.log на наличие слова ERROR + log_content = read_file("log.log") + if log_content and "ERROR" in log_content: + print("\nВ файле log.log найдены ошибки") + if not ask_user_confirmation("Продолжить выполнение? (да/нет): "): + print("Выполнение скрипта завершено по запросу пользователя.") + break + + # Проверка наличия error.log или err_groups.log + error_files = ["error.log", "err_groups.log", "chech_groups.log", "final_error.log"] + files_found = [file for file in error_files if os.path.exists(file)] + if files_found: + print(f"Найдены следующие файлы ошибок: {', '.join(files_found)}.") + if not ask_user_confirmation("Продолжить выполнение? (да/нет): "): + print("Выполнение скрипта завершено по запросу пользователя.") + break + + # Закрытие всех файлов перед уведомлением пользователя + print("Закрытие всех открытых файлов...") + time.sleep(3) print("Выполнение скрипта завершено.") \ No newline at end of file diff --git a/Scripts/add_groups.py b/Scripts/add_groups.py new file mode 100644 index 0000000..18838ed --- /dev/null +++ b/Scripts/add_groups.py @@ -0,0 +1,156 @@ +import json +import csv +import logging +import os +import time + +# Настройка основного логгера +logger = logging.getLogger('main_logger') +logger.setLevel(logging.DEBUG) + +# Обработчик для log.log (все уровни логирования) +log_handler = logging.FileHandler('log.log', mode='w', encoding='cp1251') # Кодировка windows-1251 +log_handler.setLevel(logging.DEBUG) +log_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) +logger.addHandler(log_handler) + +# Обработчик для err_groups.log (только ERROR и выше) +error_handler = logging.FileHandler('err_groups.log', mode='w', encoding='cp1251', delay=True) # Отложенное создание + кодировка windows-1251 +error_handler.setLevel(logging.ERROR) +error_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) +logger.addHandler(error_handler) + +# Функция для загрузки данных из groups.csv +def load_groups_csv(file_path): + """Загружает данные из groups.csv.""" + groups_data = {} + try: + with open(file_path, 'r', encoding='cp1251') as file: + reader = csv.reader(file, delimiter=';') + next(reader) # Пропускаем заголовки + for row in reader: + class_name, subject, teacher, group = row + class_name = class_name.lower() # Только класс переводим в нижний регистр + key = (class_name, subject.strip(), teacher.strip()) + if key not in groups_data: + groups_data[key] = [] + groups_data[key].append(group.strip()) # Удаляем лишние пробелы + logger.debug(f"Добавлена группа: {group} для ключа {key}") + logger.info("Файл groups.csv успешно загружен") + return groups_data + except FileNotFoundError: + logger.error("Файл groups.csv не найден") + raise SystemExit("Файл groups.csv не найден") + except UnicodeDecodeError: + logger.error("Ошибка декодирования файла groups.csv. Проверьте кодировку файла.") + raise SystemExit("Ошибка декодирования файла groups.csv. Проверьте кодировку файла.") + +# Функция для загрузки данных из raspisanie_sinh_time.json +def load_raspisanie(file_path): + """Загружает данные из raspisanie_sinh_time.json.""" + try: + with open(file_path, 'r', encoding='utf-8') as file: + data = json.load(file) + return data + except FileNotFoundError: + logger.error("Файл raspisanie_sinh_time.json не найден") + raise SystemExit("Файл raspisanie_sinh_time.json не найден") + except Exception as e: + logger.error(f"Ошибка при чтении файла raspisanie_sinh_time.json: {e}") + raise SystemExit(f"Ошибка при чтении файла raspisanie_sinh_time.json: {e}") + +# Функция для добавления групп +def add_groups(data, groups_data): + """Добавляет группы для основных уроков и .1.""" + for class_name, days in data.items(): + class_name_lower = class_name.lower() + logger.info(f"Начинаем обработку класса: {class_name}") + + for day_name, lessons in days.items(): + logger.info(f"Начинаем обработку дня: {day_name}") + + for key, lesson in lessons.items(): + if key.endswith(".1"): + # Ищем родительский ключ + parent_key = key.split(".1")[0] + + if parent_key not in lessons: + logger.warning(f"Для ключа {key} не найден родительский ключ {parent_key}. Пропускаем.") + continue + + # Получаем данные из родительского урока + parent_lesson = lessons[parent_key] + parent_subject = parent_lesson.get("lesson", "") + parent_teacher = parent_lesson.get("teach", "") + + # Проверяем, совпадают ли параметры основного и дочернего урока + if ( + lesson.get("lesson") == parent_subject and + lesson.get("teach") == parent_teacher + ): + # Формируем ключ для поиска групп + key_for_groups = (class_name_lower, parent_subject.strip(), parent_teacher.strip()) + logger.debug(f"Сформирован ключ для поиска групп (совпадающие параметры): {key_for_groups}") + + # Находим соответствующие группы + groups = groups_data.get(key_for_groups, []) + + if len(groups) >= 2: + # Распределяем группы между основным и дочерним уроками + parent_lesson["groups"] = groups[0] + lesson["groups"] = groups[1] + logger.info(f"Обновлены группы для ключей {parent_key} и {key}: {groups[0]}, {groups[1]}") + elif len(groups) == 1: + # Если только одна группа, присваиваем её основному уроку + parent_lesson["groups"] = groups[0] + logger.info(f"Найдена одна группа для ключа {parent_key}: {groups[0]}") + else: + # Если группы не найдены, записываем предупреждение + logger.error(f"Не найдено подходящих групп для ключа {key_for_groups}") + + else: + # Если параметры не совпадают, формируем уникальные ключи + parent_key_for_groups = (class_name_lower, parent_subject.strip(), parent_teacher.strip()) + child_key_for_groups = (class_name_lower, lesson.get("lesson", "").strip(), lesson.get("teach", "").strip()) + + logger.debug(f"Сформирован уникальный ключ для родительского урока: {parent_key_for_groups}") + logger.debug(f"Сформирован уникальный ключ для дочернего урока: {child_key_for_groups}") + + # Находим группы для каждого ключа + parent_groups = groups_data.get(parent_key_for_groups, []) + child_groups = groups_data.get(child_key_for_groups, []) + + if parent_groups: + parent_lesson["groups"] = parent_groups[0] + logger.info(f"Найдена группа для родительского урока {parent_key}: {parent_groups[0]}") + else: + logger.error(f"Не найдено подходящих групп для родительского ключа {parent_key_for_groups}") + + if child_groups: + lesson["groups"] = child_groups[0] + logger.info(f"Найдена группа для дочернего урока {key}: {child_groups[0]}") + else: + logger.error(f"Не найдено подходящих групп для дочернего ключа {child_key_for_groups}") + + return data + +if __name__ == "__main__": + time.sleep(2) + script_dir = os.path.dirname(os.path.abspath(__file__)) + groups_file_path = os.path.join(script_dir, 'groups.csv') + input_file_path = os.path.join(script_dir, 'raspisanie_sinh_time.json') + + # Загрузка данных + groups_data = load_groups_csv(groups_file_path) + schedule_data = load_raspisanie(input_file_path) + + # Обработка данных + updated_data = add_groups(schedule_data, groups_data) + + # Сохранение результатов + output_file_path = os.path.join(script_dir, 'raspisanie_groups_added.json') + with open(output_file_path, 'w', encoding='utf-8') as file: + json.dump(updated_data, file, ensure_ascii=False, indent=4) + + logger.info(f"Файл успешно обработан и сохранен как {output_file_path}") + time.sleep(2) \ No newline at end of file diff --git a/Scripts/add_key.py b/Scripts/add_key.py new file mode 100644 index 0000000..d80aeae --- /dev/null +++ b/Scripts/add_key.py @@ -0,0 +1,80 @@ +import json +import logging +from collections import OrderedDict +import os +import time + +# Настройка логирования +logging.basicConfig( + filename='log.log', + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s' +) + +def load_raspisanie(file_path): + """Загружает данные из raspisanie.json.""" + try: + with open(file_path, 'r', encoding='utf-8') as file: + data = json.load(file, object_pairs_hook=OrderedDict) + return data + except FileNotFoundError: + logging.error("Файл raspisanie.json не найден") + raise SystemExit("Файл raspisanie.json не найден") + except Exception as e: + logging.error(f"Ошибка при чтении файла raspisanie.json: {e}") + raise SystemExit(f"Ошибка при чтении файла raspisanie.json: {e}") + +def add_keys(data): + """Обрабатывает ключи, заканчивающиеся на .1, чтобы они соответствовали формату previous_key.1.""" + for class_name, days in data.items(): + logging.info(f"Начинаем обработку класса: {class_name}") + + for day_name, lessons in days.items(): + logging.info(f"Начинаем обработку дня: {day_name}") + + new_lessons = OrderedDict() + previous_key = None + + for key, lesson in lessons.items(): + logging.debug(f"Обработка урока с ключом: {key}") + + if key.isdigit(): + # Если ключ числовой, обновляем previous_key + previous_key = key + logging.debug(f"Обновление previous_key на '{key}'") + + if key.endswith(".1"): + # Если ключ заканчивается на .1 + if previous_key is not None: + expected_key = f"{previous_key}.1" + if key != expected_key: + # Если ключ не соответствует формату previous_key.1, изменяем его + logging.warning(f"Ключ {key} не соответствует формату '{expected_key}'. Исправляем.") + key = expected_key # Изменяем ключ + + # Добавляем ключ и его значение в новый словарь + new_lessons[key] = lesson + logging.debug(f"Добавлен ключ {key} со значением {lesson}") + + # Заменяем старый словарь новым + days[day_name] = new_lessons + logging.info(f"Обновленные данные для дня {day_name}: {new_lessons}") + + return data + +if __name__ == "__main__": + script_dir = os.path.dirname(os.path.abspath(__file__)) + input_file_path = os.path.join(script_dir, 'raspisanie.json') + + # Загрузка данных + schedule_data = load_raspisanie(input_file_path) + + # Обработка данных + updated_data = add_keys(schedule_data) + + # Сохранение результатов + output_file_path = os.path.join(script_dir, 'raspisanie_key_added.json') + with open(output_file_path, 'w', encoding='utf-8') as file: + json.dump(updated_data, file, ensure_ascii=False, indent=4) + logging.info(f"Файл успешно обработан и сохранен как {output_file_path}") + time.sleep(2) \ No newline at end of file diff --git a/Scripts/all_null_lesson.py b/Scripts/all_null_lesson.py new file mode 100644 index 0000000..26c736f --- /dev/null +++ b/Scripts/all_null_lesson.py @@ -0,0 +1,120 @@ +import json +import logging +import os +from collections import OrderedDict +import time + +# Настройка логирования +logging.basicConfig( + filename='log.log', + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s' +) + +def load_raspisanie(file_path): + """Загружает данные из JSON-файла.""" + try: + with open(file_path, 'r', encoding='utf-8') as file: + data = json.load(file) + logging.info(f"Файл успешно загружен: {file_path}") + return data + except FileNotFoundError: + logging.error(f"Файл не найден: {file_path}") + raise SystemExit(f"Файл не найден: {file_path}") + except Exception as e: + logging.error(f"Ошибка при чтении файла {file_path}: {e}") + raise SystemExit(f"Ошибка при чтении файла {file_path}: {e}") + +def add_missing_keys(data): + """Добавляет отсутствующие основные и дополнительные ключи с подробным логированием.""" + empty_template = { + "time": "", + "lesson": "", + "teach": "", + "number": "", + "groups": "" + } + + for class_name, days in data.items(): + logging.info(f"=== Начинается обработка класса: {class_name} ===") + + # Собираем все уникальные основные и дополнительные ключи + all_main_keys = set() + all_dot_one_keys = {} # Словарь для хранения дополнительных ключей по основным + + for day_name, lessons in days.items(): + logging.debug(f"Сбор ключей из дня: {day_name}") + for key in lessons: + if key.isdigit(): # Основные ключи + all_main_keys.add(key) + elif key.endswith(".1"): # Дополнительные ключи + base_key = key.split(".")[0] + if base_key not in all_dot_one_keys: + all_dot_one_keys[base_key] = set() + all_dot_one_keys[base_key].add(key) + + # Логируем собранные ключи + logging.info(f"Все основные ключи для класса {class_name}: {sorted(all_main_keys, key=int)}") + logging.info(f"Все дополнительные ключи для класса {class_name}: {all_dot_one_keys}") + + # Проверяем каждый день на наличие основных и дополнительных ключей + for day_name, lessons in days.items(): + existing_keys = set(lessons.keys()) + ordered_lessons = OrderedDict(sorted(lessons.items(), key=lambda x: int(x[0].split('.')[0]))) + logging.info(f"Обработка дня: {day_name}. Существующие ключи: {sorted(existing_keys)}") + + # Шаг 1: Добавляем отсутствующие основные ключи + added_main_keys = [] + for main_key in sorted(all_main_keys, key=int): + if main_key not in existing_keys: + ordered_lessons[main_key] = empty_template.copy() + added_main_keys.append(main_key) + logging.info(f"Добавлен основной ключ {main_key} в день {day_name}") + + if added_main_keys: + logging.info(f"В день {day_name} добавлены основные ключи: {added_main_keys}") + else: + logging.info(f"В день {day_name} все основные ключи уже существуют.") + + # Шаг 2: Добавляем отсутствующие дополнительные ключи + added_dot_one_keys = [] + for base_key, dot_one_keys in all_dot_one_keys.items(): + if base_key in existing_keys or base_key in added_main_keys: # Проверяем, существует ли основной ключ + for dot_one_key in sorted(dot_one_keys): + if dot_one_key not in existing_keys: + ordered_lessons[dot_one_key] = empty_template.copy() + added_dot_one_keys.append(dot_one_key) + logging.info(f"Добавлен дополнительный ключ {dot_one_key} в день {day_name}") + + if added_dot_one_keys: + logging.info(f"В день {day_name} добавлены дополнительные ключи: {added_dot_one_keys}") + else: + logging.info(f"В день {day_name} все дополнительные ключи уже существуют.") + + # Обновляем данные для текущего дня + days[day_name] = ordered_lessons + logging.info(f"День {day_name} успешно обработан. Итоговые ключи: {list(ordered_lessons.keys())}") + + logging.info(f"=== Обработка класса {class_name} завершена ===") + + return data + + +if __name__ == "__main__": + time.sleep(2) # Задержка перед началом работы + script_dir = os.path.dirname(os.path.abspath(__file__)) + input_file_path = os.path.join(script_dir, 'raspisanie_groups_added.json') + + # Загрузка данных + schedule_data = load_raspisanie(input_file_path) + + # Обработка данных + updated_data = add_missing_keys(schedule_data) + + # Сохранение результатов + output_file_path = os.path.join(script_dir, 'raspisanie_null_lesson_added.json') + with open(output_file_path, 'w', encoding='utf-8') as file: + json.dump(updated_data, file, ensure_ascii=False, indent=4) + + logging.info(f"Файл успешно обработан и сохранен как {output_file_path}") + time.sleep(2) # Финальная задержка перед завершением \ No newline at end of file diff --git a/Scripts/check_group.py b/Scripts/check_group.py index 876f03b..515a2ad 100644 --- a/Scripts/check_group.py +++ b/Scripts/check_group.py @@ -2,6 +2,7 @@ import json import os from datetime import datetime +import time # Функция для записи логов def log_message(log_file, level, message): @@ -10,6 +11,8 @@ def log_message(log_file, level, message): with open(log_file, 'a', encoding='cp1251') as f: f.write(log_entry) +time.sleep(2) + # Чтение файла groups.csv и формирование массива lessons lessons = set() try: @@ -26,19 +29,21 @@ def log_message(log_file, level, message): # Преобразуем множество в список lessons = list(lessons) -# Чтение файла raspisanie_modified.json (всегда в UTF-8) -if not os.path.exists('raspisanie_modified.json'): - print("Файл raspisanie_modified.json не найден.") +# Чтение файла raspisanie_cab_updated.json (всегда в UTF-8) +if not os.path.exists('raspisanie_cab_updated.json'): + print("Файл raspisanie_cab_updated.json не найден.") exit() try: - with open('raspisanie_modified.json', 'r', encoding='utf-8') as jsonfile: + with open('raspisanie_cab_updated.json', 'r', encoding='utf-8') as jsonfile: schedule = json.load(jsonfile) except json.JSONDecodeError: - print("Ошибка декодирования JSON. Проверьте формат файла raspisanie_modified.json.") + print("Ошибка декодирования JSON. Проверьте формат файла raspisanie_cab_updated.json.") exit() -# Проверка данных в raspisanie_modified.json +time.sleep(2) + +# Проверка данных в raspisanie_cab_updated.json for class_name, days in schedule.items(): for day, lessons_schedule in days.items(): for lesson_number, lesson_data in lessons_schedule.items(): @@ -56,7 +61,8 @@ def log_message(log_file, level, message): # Записываем в log.log log_message('log.log', 'ERROR', error_message) - # Записываем в err_groups.log - log_message('err_groups.log', 'ERROR', error_message) + # Записываем в chech_groups.log + log_message('chech_groups.log', 'ERROR', error_message) -print("Обработка завершена. Логи записаны в файлы log.log и err_groups.log.") \ No newline at end of file +time.sleep(2) +print("Обработка завершена. Логи записаны в файлы log.log и chech_groups.log.") \ No newline at end of file diff --git a/Scripts/csv_to_json.py b/Scripts/csv_to_json.py index 23f181d..060e864 100644 --- a/Scripts/csv_to_json.py +++ b/Scripts/csv_to_json.py @@ -2,6 +2,7 @@ import json import logging import os +import time # Настройка логирования logging.basicConfig( @@ -154,6 +155,11 @@ def process_lesson(par_lesson, teach_lesson, class_data, days, is_additional=Fal # Вызов функции if __name__ == "__main__": + # Пауза перед стартом + time.sleep(2) + input_filename = 'raspisanie.csv' output_filename = 'raspisanie.json' - convert_csv_to_json(input_filename, output_filename) \ No newline at end of file + convert_csv_to_json(input_filename, output_filename) + + time.sleep(2) \ No newline at end of file diff --git a/Scripts/delete.py b/Scripts/delete.py index 6fa2a1c..b88d3be 100644 --- a/Scripts/delete.py +++ b/Scripts/delete.py @@ -1,28 +1,35 @@ import os +import time # Список файлов для удаления перед стартом files_to_delete = [ + "log.log", + "error.log", + "err_groups.log", + "final_error.log", + "chech_groups.log", "GIS_schedule.csv", "klass.csv", - "lesson.csv", - "log.log", + "lesson.csv", "raspisanie.csv", + "groups.csv", + "zamena.csv", "raspisanie.json", - "raspisanie_modified.json", - "error.log", - "group.csv", - "err_groups.log", - "groups.csv" + "raspisanie_key_added.json", + "raspisanie_sinh_time.json", + "raspisanie_groups_added.json", + "raspisanie_null_lesson_added.json", + "raspisanie_sorted_schedule.json", + "raspisanie_replace_lessons.json", + "raspisanie_cab_updated.json" ] def delete_files(file_list): for file_name in file_list: if os.path.exists(file_name): os.remove(file_name) - print(f"Файл {file_name} удален.") - else: - print(f"Файл {file_name} не найден.") - print("Все файлы удалены.") if __name__ == "__main__": - delete_files(files_to_delete) \ No newline at end of file + time.sleep(2) + delete_files(files_to_delete) + time.sleep(5) \ No newline at end of file diff --git a/Scripts/exel_to_csv.py b/Scripts/exel_to_csv.py index 7ebd951..6a4c6ad 100644 --- a/Scripts/exel_to_csv.py +++ b/Scripts/exel_to_csv.py @@ -1,6 +1,7 @@ import os import logging import pandas as pd +import time # Настройка логирования logging.basicConfig( @@ -32,10 +33,11 @@ def convert_excel_to_csv(file_name): # Основной скрипт if __name__ == "__main__": + time.sleep(2) logging.info("Скрипт начал выполнение.") # Список файлов для проверки - files = ['raspisanie.xlsx', 'klass.xlsx', 'lesson.xlsx', 'groups.xlsx'] + files = ['raspisanie.xlsx', 'klass.xlsx', 'lesson.xlsx', 'groups.xlsx', 'zamena.xlsx'] # Проверяем наличие файлов if not check_files(files): @@ -45,5 +47,5 @@ def convert_excel_to_csv(file_name): # Преобразуем каждый файл Excel в CSV for file in files: convert_excel_to_csv(file) - + time.sleep(2) logging.info("Скрипт успешно завершил выполнение.") \ No newline at end of file diff --git a/Scripts/json_to_GIS_SO.py b/Scripts/json_to_GIS_SO.py index a11b838..f050b40 100644 --- a/Scripts/json_to_GIS_SO.py +++ b/Scripts/json_to_GIS_SO.py @@ -114,7 +114,7 @@ def create_csv_schedule(json_file_path, output_csv_path): # Путь к JSON-файлу -json_file_path = 'raspisanie_modified.json' +json_file_path = 'raspisanie_replace_lessons.json' # Путь для сохранения CSV-файла output_csv_path = 'GIS_schedule.csv' diff --git a/Scripts/lesson_sort.py b/Scripts/lesson_sort.py new file mode 100644 index 0000000..8f780fe --- /dev/null +++ b/Scripts/lesson_sort.py @@ -0,0 +1,57 @@ +import json +import logging +from collections import OrderedDict +import os +import time + +# Настройка логирования +logging.basicConfig( + filename='log.log', + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s' +) + +def load_raspisanie(file_path): + """Загружает данные из raspisanie_null_lesson_added.json.""" + try: + with open(file_path, 'r', encoding='utf-8') as file: + data = json.load(file) + return data + except FileNotFoundError: + logging.error("Файл raspisanie_null_lesson_added.json не найден") + raise SystemExit("Файл raspisanie_null_lesson_added.json не найден") + except Exception as e: + logging.error(f"Ошибка при чтении файла raspisanie_null_lesson_added.json: {e}") + raise SystemExit(f"Ошибка при чтении файла raspisanie_null_lesson_added.json: {e}") + +def sort_lessons(data): + """Переставляет уроки в правильном порядке.""" + for class_name, days in data.items(): + logging.info(f"Сортировка уроков для класса: {class_name}") + + for day_name, lessons in days.items(): + new_lessons = OrderedDict() + for key in sorted(lessons, key=lambda x: int(x.split('.')[0]) if x.split('.')[0].isdigit() else x): + new_lessons[key] = lessons[key] + days[day_name] = new_lessons + logging.info(f"Обновленные данные для дня {day_name}: {new_lessons}") + + return data + +if __name__ == "__main__": + time.sleep(2) + script_dir = os.path.dirname(os.path.abspath(__file__)) + input_file_path = os.path.join(script_dir, 'raspisanie_null_lesson_added.json') + + # Загрузка данных + schedule_data = load_raspisanie(input_file_path) + + # Обработка данных + updated_data = sort_lessons(schedule_data) + + # Сохранение результатов + output_file_path = os.path.join(script_dir, 'raspisanie_sorted_schedule.json') + with open(output_file_path, 'w', encoding='utf-8') as file: + json.dump(updated_data, file, ensure_ascii=False, indent=4) + logging.info(f"Файл успешно обработан и сохранен как {output_file_path}") + time.sleep(2) \ No newline at end of file diff --git a/Scripts/normalization.py b/Scripts/normalization.py deleted file mode 100644 index 460203d..0000000 --- a/Scripts/normalization.py +++ /dev/null @@ -1,235 +0,0 @@ -import json -import os -import csv -import logging -from collections import OrderedDict - -# Настройка логирования -logging.basicConfig( - filename='log.log', - level=logging.DEBUG, - format='%(asctime)s - %(levelname)s - %(message)s' -) - -def load_groups_csv(file_path): - """Загружает данные из groups.csv и создает словарь для быстрого поиска.""" - groups_data = {} - try: - with open(file_path, 'r', encoding='cp1251') as file: - reader = csv.reader(file, delimiter=';') - next(reader) # Пропускаем заголовок - for row in reader: - class_name, subject, teacher, group = row - class_name = class_name.lower() # Только класс переводим в нижний регистр - key = (class_name, subject.strip(), teacher.strip()) - if key not in groups_data: - groups_data[key] = [] - groups_data[key].append(group.strip()) # Удаляем лишние пробелы - logging.debug(f"Добавлена группа: {group} для ключа {key}") - logging.info("Файл groups.csv успешно загружен") - return groups_data - except FileNotFoundError: - logging.error("Файл groups.csv не найден") - raise SystemExit("Файл groups.csv не найден") - except UnicodeDecodeError: - logging.error("Ошибка декодирования файла groups.csv. Проверьте кодировку файла.") - raise SystemExit("Ошибка декодирования файла groups.csv. Проверьте кодировку файла.") - -def process_raspisanie(data, groups_data): - """Обрабатывает данные из raspisanie.json согласно новой логике.""" - for class_name, days in data.items(): - class_name_lower = class_name.lower() - logging.info(f"Начинаем обработку класса: {class_name}") - - for day_name, lessons in days.items(): - logging.info(f"Начинаем обработку дня: {day_name}") - - new_lessons = OrderedDict() - previous_key = None - - for key, lesson in lessons.items(): - logging.debug(f"Обработка урока с ключом: {key}") - - if key.endswith(".1") and previous_key is not None: - # Обработка *.1 - parent_key = previous_key - parent_lesson = lessons.get(parent_key, {}) - - if "time" in parent_lesson: - lesson["time"] = parent_lesson["time"] - logging.debug(f"Подтянуто время для ключа '{key}' из родительского урока '{parent_key}': {parent_lesson['time']}") - - # Проверяем наличие lesson и teach в основном уроке - if "lesson" in parent_lesson and "teach" in parent_lesson: - subject = parent_lesson["lesson"] # Без изменения регистра - teacher = parent_lesson["teach"] # Сохраняем пробелы - - # Делаем выборку из groups.csv - key_for_groups = (class_name_lower, subject, teacher) - groups = groups_data.get(key_for_groups, []) - logging.debug(f"Поиск групп для ключа {key_for_groups}. Найдено групп: {len(groups)}") - - if len(groups) == 2: - # Проверяем, совпадают ли параметры в *.1 - if all(k in lesson for k in ["lesson", "teach"]) and \ - lesson["lesson"] == parent_lesson["lesson"] and \ - lesson["teach"] == parent_lesson["teach"]: - # Записываем группы - parent_lesson["groups"] = groups[0] - lesson["groups"] = groups[1] - logging.info(f"Обновлены группы для ключей {parent_key} и {key}: {groups[0]}, {groups[1]}") - else: - # Оставляем только первую группу - parent_lesson["groups"] = groups[0] - logging.warning(f"Параметры в {key} не совпадают, оставлено первое значение группы: {groups[0]}") - elif len(groups) == 1: - # Оставляем только первую группу - parent_lesson["groups"] = groups[0] - logging.info(f"Найдена одна группа для ключа {parent_key}: {groups[0]}") - else: - logging.warning(f"Не найдено подходящих групп для ключа {parent_key}") - - # Добавляем *.1 в новый словарь - new_lessons[key] = lesson - - else: - # Добавляем остальные ключи без изменений - new_lessons[key] = lesson - if key.isdigit(): - previous_key = key - logging.debug(f"Обновление previous_key на '{key}'") - else: - previous_key = None - logging.debug(f"Сброс previous_key для нечислового ключа '{key}'") - - # Заменяем старый словарь новым - days[day_name] = new_lessons - logging.info(f"Обновленные данные для дня {day_name}: {new_lessons}") - - return data - -def add_dot_one_to_all_days(data): - """Добавляет .1 в остальные дни недели для каждого класса.""" - for class_name, days in data.items(): - logging.info(f"Добавление .1 в все дни для класса: {class_name}") - - dot_one_keys = set() - for day_name, lessons in days.items(): - for key in lessons: - if key.endswith(".1"): - dot_one_keys.add(key) - logging.debug(f"Найден ключ .1 в день {day_name}: {key}") - - if dot_one_keys: - empty_dot_one_template = { - "time": "", - "lesson": "", - "teach": "", - "number": "", - "groups": "" - } - for day_name, lessons in days.items(): - existing_keys = set(lessons.keys()) - ordered_lessons = OrderedDict(lessons.items()) - i = 0 - - while i < len(ordered_lessons): - key, value = list(ordered_lessons.items())[i] - - # Добавляем текущий ключ в упорядоченный словарь - ordered_lessons[key] = value - - # Проверяем, нужно ли добавить соответствующий .1 после текущего ключа - if key.isdigit() and f"{key}.1" in dot_one_keys and f"{key}.1" not in existing_keys: - dot_one_key = f"{key}.1" - ordered_lessons[dot_one_key] = empty_dot_one_template.copy() - logging.info(f"Добавлен пустой массив {dot_one_key} в день {day_name} после ключа {key}") - - i += 1 - - # Заменяем старый словарь упорядоченным - days[day_name] = ordered_lessons - - return data - -def update_dot_one_fields(data): - """Обновляет поля в массивах *.1 и переставляет их в правильный порядок.""" - for class_name, days in data.items(): - logging.info(f"Обновление полей в *.1 для класса: {class_name}") - - for day_name, lessons in days.items(): - logging.info(f"Обработка дня: {day_name}") - - # Создаем временный упорядоченный словарь для нового порядка - new_lessons = OrderedDict() - - for key in sorted(lessons, key=lambda x: int(x.split('.')[0]) if x.split('.')[0].isdigit() else x): - lesson = lessons[key] - - if key.endswith(".1"): - # Проверяем условия для обновления поля number - if all(lesson.get(field) for field in ["time", "lesson", "teach"]) and not lesson.get("number"): - lesson["number"] = "Нет кабинета" - logging.info(f"Установлено значение 'Нет кабинета' для ключа {key}") - - # Добавляем урок в новый словарь - new_lessons[key] = lesson - - # Заменяем старый словарь новым - days[day_name] = new_lessons - logging.info(f"Обновленные данные для дня {day_name}: {new_lessons}") - - return data - -# Определение путей к файлам -script_dir = os.path.dirname(os.path.abspath(__file__)) -groups_file_path = os.path.join(script_dir, 'groups.csv') -input_file_path = os.path.join(script_dir, 'raspisanie.json') -output_file_path = os.path.join(script_dir, 'raspisanie_modified.json') - -# Чтение файла groups.csv -try: - groups_data = load_groups_csv(groups_file_path) -except Exception as e: - logging.error(f"Ошибка при чтении файла groups.csv: {e}") - raise SystemExit(f"Ошибка при чтении файла groups.csv: {e}") - -# Чтение файла raspisanie.json -try: - with open(input_file_path, 'r', encoding='utf-8') as file: - schedule_data = json.load(file, object_pairs_hook=OrderedDict) - - # Преобразуем названия классов в нижний регистр - normalized_schedule_data = OrderedDict() - for class_name, days in schedule_data.items(): - normalized_class_name = class_name.lower() - normalized_schedule_data[normalized_class_name] = days - logging.debug(f"Преобразование класса '{class_name}' в нижний регистр: '{normalized_class_name}'") - - schedule_data = normalized_schedule_data # Используем нормализованные данные - logging.info("Файл raspisanie.json успешно загружен и нормализован") -except FileNotFoundError: - logging.error("Файл raspisanie.json не найден") - raise SystemExit("Файл raspisanie.json не найден") -except Exception as e: - logging.error(f"Ошибка при чтении файла raspisanie.json: {e}") - raise SystemExit(f"Ошибка при чтении файла raspisanie.json: {e}") - -# Обработка данных -try: - schedule_data = process_raspisanie(schedule_data, groups_data) - schedule_data = add_dot_one_to_all_days(schedule_data) - schedule_data = update_dot_one_fields(schedule_data) # Вызываем новую функцию - logging.info("Данные успешно обработаны") -except Exception as e: - logging.error(f"Ошибка при обработке данных: {e}") - raise SystemExit(f"Ошибка при обработке данных: {e}") - -# Запись измененного JSON обратно в файл -try: - with open(output_file_path, 'w', encoding='utf-8') as file: - json.dump(schedule_data, file, ensure_ascii=False, indent=4) - logging.info(f"Файл успешно обработан и сохранен как {output_file_path}") -except Exception as e: - logging.error(f"Ошибка при записи файла: {e}") - raise SystemExit(f"Ошибка при записи файла: {e}") \ No newline at end of file diff --git a/Scripts/sinh_time.py b/Scripts/sinh_time.py new file mode 100644 index 0000000..c022e06 --- /dev/null +++ b/Scripts/sinh_time.py @@ -0,0 +1,59 @@ +import json +import logging +import os +import time + +# Настройка логирования +logging.basicConfig( + filename='log.log', + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s' +) + +def load_raspisanie(file_path): + """Загружает данные из raspisanie_key_added.json.""" + try: + with open(file_path, 'r', encoding='utf-8') as file: + data = json.load(file) + return data + except FileNotFoundError: + logging.error("Файл raspisanie_key_added.json не найден") + raise SystemExit("Файл raspisanie_key_added.json не найден") + except Exception as e: + logging.error(f"Ошибка при чтении файла raspisanie_key_added.json: {e}") + raise SystemExit(f"Ошибка при чтении файла raspisanie_key_added.json: {e}") + +def set_sinh_time(data): + """Устанавливает время для ключей .1 из основного урока.""" + for class_name, days in data.items(): + logging.info(f"Начинаем обработку класса: {class_name}") + + for day_name, lessons in days.items(): + logging.info(f"Начинаем обработку дня: {day_name}") + + for key, lesson in lessons.items(): + if key.endswith(".1"): + parent_key = key.split(".1")[0] + if parent_key in lessons and "time" in lessons[parent_key]: + lesson["time"] = lessons[parent_key]["time"] + logging.debug(f"Подтянуто время для ключа '{key}' из родительского урока '{parent_key}': {lesson['time']}") + + return data + +if __name__ == "__main__": + time.sleep(2) + script_dir = os.path.dirname(os.path.abspath(__file__)) + input_file_path = os.path.join(script_dir, 'raspisanie_key_added.json') + + # Загрузка данных + schedule_data = load_raspisanie(input_file_path) + + # Обработка данных + updated_data = set_sinh_time(schedule_data) + + # Сохранение результатов + output_file_path = os.path.join(script_dir, 'raspisanie_sinh_time.json') + with open(output_file_path, 'w', encoding='utf-8') as file: + json.dump(updated_data, file, ensure_ascii=False, indent=4) + logging.info(f"Файл успешно обработан и сохранен как {output_file_path}") + time.sleep(2) \ No newline at end of file diff --git a/Scripts/update_cab.py b/Scripts/update_cab.py new file mode 100644 index 0000000..40a32db --- /dev/null +++ b/Scripts/update_cab.py @@ -0,0 +1,56 @@ +import json +import logging +import os +import time + +# Настройка логирования +logging.basicConfig( + filename='log.log', + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s' +) + +def load_raspisanie(file_path): + """Загружает данные из raspisanie_sorted_schedule.json.""" + try: + with open(file_path, 'r', encoding='utf-8') as file: + data = json.load(file) + return data + except FileNotFoundError: + logging.error("Файл raspisanie_sorted_schedule.json не найден") + raise SystemExit("Файл raspisanie_sorted_schedule.json не найден") + except Exception as e: + logging.error(f"Ошибка при чтении файла raspisanie_sorted_schedule.json: {e}") + raise SystemExit(f"Ошибка при чтении файла raspisanie_sorted_schedule.json: {e}") + +def update_dot_one_fields(data): + """Обновляет поля в массивах .1.""" + for class_name, days in data.items(): + logging.info(f"Обновление полей в .1 для класса: {class_name}") + + for day_name, lessons in days.items(): + for key, lesson in lessons.items(): + if key.endswith(".1"): + if all(lesson.get(field) for field in ["time", "lesson", "teach"]) and not lesson.get("number"): + lesson["number"] = "Нет кабинета" + logging.info(f"Установлено значение 'Нет кабинета' для ключа {key}") + + return data + +if __name__ == "__main__": + time.sleep(2) + script_dir = os.path.dirname(os.path.abspath(__file__)) + input_file_path = os.path.join(script_dir, 'raspisanie_sorted_schedule.json') + + # Загрузка данных + schedule_data = load_raspisanie(input_file_path) + + # Обработка данных + updated_data = update_dot_one_fields(schedule_data) + + # Сохранение результатов + output_file_path = os.path.join(script_dir, 'raspisanie_cab_updated.json') + with open(output_file_path, 'w', encoding='utf-8') as file: + json.dump(updated_data, file, ensure_ascii=False, indent=4) + logging.info(f"Файл успешно обработан и сохранен как {output_file_path}") + time.sleep(2) \ No newline at end of file diff --git a/Scripts/update_lesson_gis.py b/Scripts/update_lesson_gis.py new file mode 100644 index 0000000..b72ee80 --- /dev/null +++ b/Scripts/update_lesson_gis.py @@ -0,0 +1,78 @@ +import csv +import json +import logging +import time + +# Настройка логирования +logging.basicConfig( + filename='log.log', # Файл для записи логов + level=logging.INFO, # Уровень логирования + format='%(asctime)s - %(levelname)s - %(message)s' # Формат записи логов +) + +# Функция для загрузки данных из CSV файла (в кодировке Windows-1251) +def load_replacements(csv_file): + replacements = {} + try: + with open(csv_file, mode='r', encoding='windows-1251') as file: # Указываем кодировку Windows-1251 + reader = csv.reader(file, delimiter=';') # Используем точку с запятой как разделитель + next(reader) # Пропускаем первую строку + for row in reader: + if len(row) == 2: # Проверяем, что есть два значения + old_value, new_value = row + replacements[old_value] = new_value + logging.info(f"Добавлена замена: '{old_value}' -> '{new_value}'") + else: + logging.warning(f"Неправильный формат строки в файле {csv_file}: {row}") + logging.info("Замены успешно загружены из файла.") + except Exception as e: + logging.error(f"Ошибка при чтении файла {csv_file}: {e}") + raise + return replacements + +# Функция для обновления JSON файла +def update_json(input_json_file, output_json_file, replacements): + try: + with open(input_json_file, 'r', encoding='utf-8') as file: + data = json.load(file) + logging.info(f"Файл {input_json_file} успешно загружен.") + + # Проходим по всем классам и дням недели + changes_made = False + for class_name, days in data.items(): + for day, lessons in days.items(): + for lesson_number, lesson_info in lessons.items(): + if 'lesson' in lesson_info: + original_lesson = lesson_info['lesson'] + for old_value, new_value in replacements.items(): + if old_value in lesson_info['lesson']: + lesson_info['lesson'] = lesson_info['lesson'].replace(old_value, new_value) + logging.info(f"Замена выполнена: класс={class_name}, день={day}, урок={lesson_number}, " + f"'{original_lesson}' -> '{lesson_info['lesson']}'") + changes_made = True + + if not changes_made: + logging.info("Нет изменений для применения.") + + # Сохраняем обновленные данные в новый файл + with open(output_json_file, 'w', encoding='utf-8') as file: + json.dump(data, file, ensure_ascii=False, indent=4) + logging.info(f"Обновленные данные успешно сохранены в файл {output_json_file}.") + except Exception as e: + logging.error(f"Ошибка при обработке файла {input_json_file}: {e}") + raise + +# Основная часть скрипта +if __name__ == "__main__": + logging.info("Скрипт начал работу.") + time.sleep(2) + try: + # Загружаем замены из CSV файла (в кодировке Windows-1251) + replacements = load_replacements('zamena.csv') + + # Обновляем JSON файл на основе замен и сохраняем в новый файл + update_json('raspisanie_cab_updated.json', 'raspisanie_replace_lessons.json', replacements) + logging.info("Скрипт успешно завершил работу.") + except Exception as e: + logging.error(f"Критическая ошибка: {e}") + time.sleep(2) \ No newline at end of file