# Copyright Stanislav Mironov import time import traceback import xlrd from coord import Coord from translations import ExcelSheetReader import hashlib import requests from urllib.parse import urlsplit, urlunsplit, quote def get_preferer_facultet(facultets_data: dict, excel_url: str, skip_for=None, ): if skip_for is None: skip_for = [] for _key, _value in facultets_data.items(): if _key.startswith("_"): continue if _key in skip_for: continue short_names = _value.get("short_names", None) if short_names is None: continue for name in short_names: if name.lower() in excel_url.lower(): return _key def get_abbrev_for_facultet(facultets_data: dict, facultet_id: str, fallback_not_found="?", fallback_error="?", fallback_no_short_name="?"): if (facultet_id == 'mag'): return "МАГ" if (facultet_id == 'asp'): return "АСП" for _key, _value in facultets_data.items(): if _key != facultet_id: continue short_names = _value.get("short_names", None) if short_names is None: return fallback_no_short_name try: return short_names[0] except Exception as e: traceback.print_exception(e) return fallback_error return fallback_not_found def download_file_from_url(url, output_filename): """ Скачивает файл по URL со спецсимволами и пробелами, сохраняя его под указанным именем. Args: url (str): Исходный URL, который может содержать пробелы и кириллицу. output_filename (str): Имя файла для сохранения (например, 'calc.xls'). """ try: # --- Шаг 1: Правильное кодирование URL --- # Разбираем URL на части: ('https', 'www.vstu.ru', '/path/to file.xls', '', '') parts = urlsplit(url) # Кодируем только путь, оставляя слэши '/' безопасными # Это превратит ' ' в '%20', 'В' в '%D0%92' и т.д. encoded_path = quote(parts.path, safe='/-_') # Собираем URL обратно из частей с уже закодированным путем encoded_url = urlunsplit((parts.scheme, parts.netloc, encoded_path, parts.query, parts.fragment)) # --- Шаг 2: Скачивание файла --- response = requests.get(encoded_url, stream=True) # Проверяем, успешен ли запрос (код 200 OK) # Если сервер вернет ошибку (404, 500 и т.д.), здесь возникнет исключение response.raise_for_status() # --- Шаг 3: Сохранение файла --- # Открываем файл для записи в бинарном режиме ('wb') # Использование 'with' гарантирует, что файл будет закрыт автоматически with open(output_filename, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) print(f"✅ Файл успешно скачан и сохранен как '{output_filename}'") except requests.exceptions.RequestException as e: print(f"❌ Ошибка скачивания: {e}") except Exception as e: print(f"❌ Произошла непредвиденная ошибка: {e}") def calculate_sha1(filepath): """ Calculates the SHA1 hash of a given file. Args: filepath (str): The path to the file. Returns: str: The hexadecimal representation of the SHA1 hash, or None if the file is not found. """ sha1_hash = hashlib.sha1() try: with open(filepath, "rb") as f: # Read the file in chunks to handle large files efficiently for chunk in iter(lambda: f.read(4096), b""): sha1_hash.update(chunk) return sha1_hash.hexdigest() except FileNotFoundError: print(f"Error: File not found at {filepath}") return None except Exception as e: print(f"An error occurred: {e}") return None class StepTimeCounter: def __init__(self): self.time: float = -1.0 self.createtime = time.time() self.setnow() def setnow(self): self.time = time.time() def step(self, no_set_now=False): left = time.time() - self.time if not no_set_now: self.setnow() return left def from_create(self): left = time.time() - self.createtime return left EMPTY_CTYPES = [xlrd.XL_CELL_EMPTY, xlrd.XL_CELL_BLANK] def discards_list(trg, nones=True, emptystrings=True): if nones: remove_from_list(trg, [None]) if emptystrings: remove_from_list(trg, [""]) def has_no_bottom_border(reader: "ExcelSheetReader", coord): return reader.get_border_style(coord, 'bottom') == 0 and reader.get_border_style(coord.shift(down=1), 'top') == 0 def find_element_index(my_list, element): if element in my_list: return my_list.index(element) else: return -1 def next_element(arr, el): index = find_element_index(arr, el) return arr[index + 1] def remove_from_list(l: list, todel: list): for x in todel: if x in l: l.remove(x) return l def parse_all_dirt(reader: "ExcelSheetReader", min_pos: Coord, right, down, with_cells=False): RET = set() row = min_pos.row while row < min_pos.row + down: col = min_pos.col while col < min_pos.col + right: #print(excel_coordinate(row, col)) cv = reader.cell(row, col) if cv is not None and not cv.is_empty(): RET.add(cv if with_cells else str(cv.value)) col += 1 row += 1 return RET def excel_coordinate(row, col): """ Преобразует координаты строки и столбца (начиная с 0) в эквивалент Excel (например, A7, CB34). Args: row: Индекс строки (начиная с 0). col: Индекс столбца (начиная с 0). Returns: Строка, представляющая координату ячейки в стиле Excel. ~ Google Gemini, tested """ col_str = '' while col >= 0: col_str = chr(ord('A') + col % 26) + col_str # Преобразуем в буквы, начиная с A col = col // 26 - 1 # Уменьшаем номер столбца и учитываем переход к следующему разряду (как в 26-ричной системе) return col_str + str(row + 1) # Добавляем номер строки (Excel начинается с 1) def merged_humanize(crange): """Получить из 4 цифр границ AA:BB координаты как в Excel""" row_low, col_low, row_high, col_high = crange # see order! return excel_coordinate(row_low, col_low) + ":" + excel_coordinate(row_high, col_high) def unspace(s: str): """Убрать пробелы из текста""" if s is None: return "!!!Python None!!!" return s.strip().replace(" ", "").replace("\t", "") def find(sh, query = None): for rx in range(sh.nrows): i = 0 for x in sh.row(rx): if x.value == query: return rx, i i += 1 return None def weekday_to_num(st: str): if st.upper().strip().startswith("ПОНЕД"): return 1 if st.upper().strip() == "ВТОРНИК": return 2 if st.upper().strip() == "СРЕДА": return 3 if st.upper().strip() == "ЧЕТВЕРГ": return 4 if st.upper().strip() == "ПЯТНИЦА": return 5 if st.upper().strip() == "СУББОТА": return 6 if st.upper().strip().startswith("ВОСКР"): return 7 print(f"Unknown weekday num for str: {st}; returnted -1") return -1