add: логгер
This commit is contained in:
parent
b593c0148b
commit
70ddf17c9f
@ -1,6 +1,6 @@
|
|||||||
| in progress // в процессе разработки |
|
| in progress // в процессе разработки |
|
||||||
|--------------------------------------|
|
|--------------------------------------|
|
||||||
| ------5 |
|
| -------6 |
|
||||||
|
|
||||||
# Типограф для Web
|
# Типограф для Web
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ Typography - библиотека для экранной типографики
|
|||||||
"""
|
"""
|
||||||
__version__ = "0.1.0"
|
__version__ = "0.1.0"
|
||||||
|
|
||||||
|
import etpgrf.defaults
|
||||||
from etpgrf.typograph import Typographer
|
from etpgrf.typograph import Typographer
|
||||||
from etpgrf.hyphenation import Hyphenator
|
from etpgrf.hyphenation import Hyphenator
|
||||||
import etpgrf.defaults
|
import etpgrf.logger
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
# etpgrf/defaults.py -- Настройки по умолчанию для типографа etpgrf
|
# etpgrf/defaults.py -- Настройки по умолчанию для типографа etpgrf
|
||||||
|
import logging
|
||||||
from etpgrf.config import LANG_RU, MODE_MIXED
|
from etpgrf.config import LANG_RU, MODE_MIXED
|
||||||
|
|
||||||
|
class LoggingDefaults:
|
||||||
|
LEVEL = logging.DEBUG
|
||||||
|
FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
# Можно добавить ещё настройки, если понадобятся:
|
||||||
|
# FORMAT: str = '%(asctime)s - %(name)s - %(levelname)s - %(module)s.%(funcName)s:%(lineno)d - %(message)s'
|
||||||
|
# FILE_PATH: str | None = None # Путь к файлу лога, если None - не пишем в файл
|
||||||
|
|
||||||
|
|
||||||
class HyphenationDefaults:
|
class HyphenationDefaults:
|
||||||
"""
|
"""
|
||||||
Настройки по умолчанию для Hyphenator etpgrf.
|
Настройки по умолчанию для Hyphenator etpgrf.
|
||||||
@ -16,6 +25,7 @@ class EtpgrfDefaultSettings:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.LANGS: list[str] | str = LANG_RU
|
self.LANGS: list[str] | str = LANG_RU
|
||||||
self.MODE: str = MODE_MIXED
|
self.MODE: str = MODE_MIXED
|
||||||
|
self.logging_settings = LoggingDefaults()
|
||||||
self.hyphenation = HyphenationDefaults()
|
self.hyphenation = HyphenationDefaults()
|
||||||
# self.quotes = EtpgrfQuoteDefaults()
|
# self.quotes = EtpgrfQuoteDefaults()
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import regex
|
import regex
|
||||||
|
import logging
|
||||||
from etpgrf.config import LANG_RU, LANG_RU_OLD, LANG_EN, SHY_ENTITIES, MODE_UNICODE
|
from etpgrf.config import LANG_RU, LANG_RU_OLD, LANG_EN, SHY_ENTITIES, MODE_UNICODE
|
||||||
from etpgrf.defaults import etpgrf_settings
|
from etpgrf.defaults import etpgrf_settings
|
||||||
from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs
|
from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs
|
||||||
@ -16,7 +17,11 @@ _RU_OLD_CONSONANTS_UPPER = frozenset(['Ѳ', # Фита (согласная)
|
|||||||
_EN_VOWELS_UPPER = frozenset(['A', 'E', 'I', 'O', 'U', 'Æ', 'Œ'])
|
_EN_VOWELS_UPPER = frozenset(['A', 'E', 'I', 'O', 'U', 'Æ', 'Œ'])
|
||||||
_EN_CONSONANTS_UPPER = frozenset(['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'])
|
_EN_CONSONANTS_UPPER = frozenset(['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'])
|
||||||
|
|
||||||
|
# --- Настройки логирования ---
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Класс Hyphenator (расстановка переносов) ---
|
||||||
class Hyphenator:
|
class Hyphenator:
|
||||||
"""Правила расстановки переносов для разных языков.
|
"""Правила расстановки переносов для разных языков.
|
||||||
"""
|
"""
|
||||||
@ -41,8 +46,10 @@ class Hyphenator:
|
|||||||
self._load_language_resources_for_hyphenation()
|
self._load_language_resources_for_hyphenation()
|
||||||
# Определяем символ переноса в зависимости от режима
|
# Определяем символ переноса в зависимости от режима
|
||||||
self._split_code: str = SHY_ENTITIES['SHY'][0] if self.mode == MODE_UNICODE else SHY_ENTITIES['SHY'][1]
|
self._split_code: str = SHY_ENTITIES['SHY'][0] if self.mode == MODE_UNICODE else SHY_ENTITIES['SHY'][1]
|
||||||
print(f"========={self.max_unhyphenated_len}===========")
|
# ...
|
||||||
|
logger.debug(f"Hyphenator `__init__`. Langs: {self.langs}, Mode: {self.mode},"
|
||||||
|
f" Max unhyphenated_len: {self.max_unhyphenated_len},"
|
||||||
|
f" Min chars_per_part: {self.min_chars_per_part}")
|
||||||
|
|
||||||
def _load_language_resources_for_hyphenation(self):
|
def _load_language_resources_for_hyphenation(self):
|
||||||
# Определяем наборы гласных, согласных и т.д. в зависимости языков.
|
# Определяем наборы гласных, согласных и т.д. в зависимости языков.
|
||||||
@ -100,13 +107,13 @@ class Hyphenator:
|
|||||||
if len(word) <= self.max_unhyphenated_len or not any(self._is_vow(c) for c in word):
|
if len(word) <= self.max_unhyphenated_len or not any(self._is_vow(c) for c in word):
|
||||||
# Если слово короткое или не содержит гласных, перенос не нужен
|
# Если слово короткое или не содержит гласных, перенос не нужен
|
||||||
return word
|
return word
|
||||||
print("слово:", word, " // mode:", self.mode, " // langs:", self.langs)
|
logger.debug(f"Hyphenator: word: `{word}` // langs: {self.langs} // mode: {self.mode} // max_unhyphenated_len: {self.max_unhyphenated_len} // min_tail_len: {self.min_chars_per_part}")
|
||||||
# 2. ОБНАРУЖЕНИЕ ЯЗЫКА И ПОДКЛЮЧЕНИЕ ЯЗЫКОВОЙ ЛОГИКИ
|
# 2. ОБНАРУЖЕНИЕ ЯЗЫКА И ПОДКЛЮЧЕНИЕ ЯЗЫКОВОЙ ЛОГИКИ
|
||||||
# Поиск вхождения букв строки (слова) через `frozenset` -- O(1). Это быстрее регулярного выражения -- O(n)
|
# Поиск вхождения букв строки (слова) через `frozenset` -- O(1). Это быстрее регулярного выражения -- O(n)
|
||||||
# 2.1. Проверяем RU и RU_OLD (правила одинаковые, но разные наборы букв)
|
# 2.1. Проверяем RU и RU_OLD (правила одинаковые, но разные наборы букв)
|
||||||
if (LANG_RU in self.langs or LANG_RU_OLD in self.langs) and frozenset(word.upper()) <= self._ru_alphabet_upper:
|
if (LANG_RU in self.langs or LANG_RU_OLD in self.langs) and frozenset(word.upper()) <= self._ru_alphabet_upper:
|
||||||
# Пользователь подключил русскую логику, и слово содержит только русские буквы
|
# Пользователь подключил русскую логику, и слово содержит только русские буквы
|
||||||
print(f"#### Applying Russian rules to: {word}")
|
logger.debug(f"`{word}` -- use `{LANG_RU}` or `{LANG_RU_OLD}` rules")
|
||||||
# Поиск допустимой позиции для переноса около заданного индекса
|
# Поиск допустимой позиции для переноса около заданного индекса
|
||||||
def find_hyphen_point_ru(word_segment: str, start_idx: int) -> int:
|
def find_hyphen_point_ru(word_segment: str, start_idx: int) -> int:
|
||||||
vow_indices = [i for i, char_w in enumerate(word_segment) if self._is_vow(char_w)]
|
vow_indices = [i for i, char_w in enumerate(word_segment) if self._is_vow(char_w)]
|
||||||
@ -153,7 +160,7 @@ class Hyphenator:
|
|||||||
# 2.2. Проверяем EN
|
# 2.2. Проверяем EN
|
||||||
elif LANG_EN in self.langs and frozenset(word.upper()) <= self._en_alphabet_upper:
|
elif LANG_EN in self.langs and frozenset(word.upper()) <= self._en_alphabet_upper:
|
||||||
# Пользователь подключил английскую логику, и слово содержит только английские буквы
|
# Пользователь подключил английскую логику, и слово содержит только английские буквы
|
||||||
print(f"#### Applying English rules to: {word}") # Для отладки
|
logger.debug(f"`{word}` -- use `{LANG_EN}` rules")
|
||||||
# --- Начало логики для английского языка (заглушка) ---
|
# --- Начало логики для английского языка (заглушка) ---
|
||||||
# ПРИМЕЧАНИЕ: Это очень упрощенная заглушка.
|
# ПРИМЕЧАНИЕ: Это очень упрощенная заглушка.
|
||||||
def find_hyphen_point_en(word_segment: str) -> int:
|
def find_hyphen_point_en(word_segment: str) -> int:
|
||||||
@ -175,7 +182,7 @@ class Hyphenator:
|
|||||||
return split_word_en(word)
|
return split_word_en(word)
|
||||||
else:
|
else:
|
||||||
# кстати "слова" в которых есть пробелы или другие разделители, тоже попадают сюда
|
# кстати "слова" в которых есть пробелы или другие разделители, тоже попадают сюда
|
||||||
print("!!!!ФИГНЯ")
|
logger.debug(f"`{word}` -- use `UNDEFINE` rules")
|
||||||
return word
|
return word
|
||||||
|
|
||||||
|
|
||||||
@ -195,11 +202,8 @@ class Hyphenator:
|
|||||||
hyphenated_word = self.hyp_in_word(word_to_process)
|
hyphenated_word = self.hyp_in_word(word_to_process)
|
||||||
|
|
||||||
# ============= Для отладки (слова в которых появились переносы) ==================
|
# ============= Для отладки (слова в которых появились переносы) ==================
|
||||||
print(f"hyp_in_text: '{word_to_process}'", end="")
|
|
||||||
if word_to_process != hyphenated_word:
|
if word_to_process != hyphenated_word:
|
||||||
print(f" -> '{hyphenated_word}'")
|
logger.debug(f"hyp_in_text: '{word_to_process}' -> '{hyphenated_word}'")
|
||||||
else:
|
|
||||||
print(" (no change)")
|
|
||||||
|
|
||||||
return hyphenated_word
|
return hyphenated_word
|
||||||
|
|
||||||
|
121
etpgrf/logger.py
Normal file
121
etpgrf/logger.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
# etpgrf/logging_settings.py
|
||||||
|
import logging
|
||||||
|
from etpgrf.defaults import etpgrf_settings # Импортируем наш объект настроек по умолчанию
|
||||||
|
|
||||||
|
# --- Корневой логгер для всей библиотеки etpgrf ---
|
||||||
|
# Имя логгера "etpgrf" позволит пользователям настраивать
|
||||||
|
# логирование для всех частей библиотеки.
|
||||||
|
# Например, logging.getLogger("etpgrf").setLevel(logging.DEBUG)
|
||||||
|
# или logging.getLogger("etpgrf.hyphenation").setLevel(logging.INFO)
|
||||||
|
_etpgrf_init_logger = logging.getLogger("etpgrf")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Настройка корневого логгера ---
|
||||||
|
def setup_library_logging():
|
||||||
|
"""
|
||||||
|
Настраивает корневой логгер для библиотеки etpgrf.
|
||||||
|
Эту функцию следует вызывать один раз (например, при импорте
|
||||||
|
основного модуля библиотеки или при первом обращении к логгеру).
|
||||||
|
"""
|
||||||
|
# Проверяем инициализацию хандлеров логера, чтобы случайно не добавлять хендлеры многократно
|
||||||
|
if not _etpgrf_init_logger.hasHandlers():
|
||||||
|
log_level_to_set = logging.WARNING # Значение по умолчанию
|
||||||
|
log_format_to_set = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' # Формат по умолчанию
|
||||||
|
|
||||||
|
fin_message: str | None = None
|
||||||
|
if hasattr(etpgrf_settings, 'logging_settings'):
|
||||||
|
if hasattr(etpgrf_settings.logging_settings, 'LEVEL'):
|
||||||
|
log_level_to_set = etpgrf_settings.logging_settings.LEVEL
|
||||||
|
if hasattr(etpgrf_settings.logging_settings, 'FORMAT') and etpgrf_settings.logging_settings.FORMAT:
|
||||||
|
log_format_to_set = etpgrf_settings.logging_settings.FORMAT
|
||||||
|
else:
|
||||||
|
# Этого не должно происходить, если defaults.py настроен правильно
|
||||||
|
fin_message= "ПРЕДУПРЕЖДЕНИЕ: etpgrf_settings.logging_settings не найдены при начальной настройке логгера."
|
||||||
|
|
||||||
|
_etpgrf_init_logger.setLevel(log_level_to_set) # Устанавливаем уровень логирования
|
||||||
|
console_handler = logging.StreamHandler() # Создаем хендлер вывода в консоль
|
||||||
|
console_handler.setLevel(log_level_to_set) # Уровень для хендлера тоже
|
||||||
|
formatter = logging.Formatter(log_format_to_set) # Создаем форматтер для вывода
|
||||||
|
console_handler.setFormatter(formatter) # Устанавливаем форматтер для хендлера
|
||||||
|
_etpgrf_init_logger.addHandler(console_handler) # Добавляем хендлер в логгер
|
||||||
|
if fin_message is not None:
|
||||||
|
# Если есть сообщение об отсутствии настроек в `etpgrf_settings`, выводим его
|
||||||
|
_etpgrf_init_logger.warning(fin_message)
|
||||||
|
_etpgrf_init_logger.debug(f"Корневой логгер 'etpgrf' инициализирован."
|
||||||
|
f" Уровень: {logging.getLevelName(_etpgrf_init_logger.getEffectiveLevel())}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Динамическое изменение уровня логирования ---
|
||||||
|
def update_etpgrf_log_level_from_settings():
|
||||||
|
"""
|
||||||
|
Обновляет уровень логирования для корневого логгера `etpgrf` и его
|
||||||
|
обработчиков, читая значение из `etpgrf_settings.logging_settings.LEVEL`.
|
||||||
|
"""
|
||||||
|
# Проверяем, что настройки логирования и уровень существуют в `defaults.etpgrf_settings`
|
||||||
|
if not hasattr(etpgrf_settings, 'logging_settings') or \
|
||||||
|
not hasattr(etpgrf_settings.logging_settings, 'LEVEL'):
|
||||||
|
_etpgrf_init_logger.warning("Невозможно обновить уровень логгера: `etpgrf_settings.logging_settings.LEVEL`"
|
||||||
|
" не найден.")
|
||||||
|
return
|
||||||
|
|
||||||
|
new_level = etpgrf_settings.logging_settings.LEVEL
|
||||||
|
_etpgrf_init_logger.setLevel(new_level)
|
||||||
|
for handler in _etpgrf_init_logger.handlers:
|
||||||
|
handler.setLevel(new_level) # Устанавливаем уровень для каждого хендлера
|
||||||
|
|
||||||
|
_etpgrf_init_logger.info(f"Уровень логирования `etpgrf` динамически обновлен на:"
|
||||||
|
f" {logging.getLevelName(_etpgrf_init_logger.getEffectiveLevel())}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Динамическое изменение формата логирования ---
|
||||||
|
def update_etpgrf_log_format_from_settings():
|
||||||
|
"""
|
||||||
|
Обновляет формат логирования для обработчиков корневого логгера etpgrf,
|
||||||
|
читая значение из etpgrf_settings.logging_settings.FORMAT.
|
||||||
|
"""
|
||||||
|
if not hasattr(etpgrf_settings, 'logging_settings') or \
|
||||||
|
not hasattr(etpgrf_settings.logging_settings, 'FORMAT') or \
|
||||||
|
not etpgrf_settings.logging_settings.FORMAT:
|
||||||
|
_etpgrf_init_logger.warning("Невозможно обновить формат логгера: `etpgrf_settings.logging_settings.FORMAT`"
|
||||||
|
" не найден или пуст.")
|
||||||
|
return
|
||||||
|
|
||||||
|
new_format_string = etpgrf_settings.logging_settings.FORMAT
|
||||||
|
new_formatter = logging.Formatter(new_format_string)
|
||||||
|
|
||||||
|
for handler in _etpgrf_init_logger.handlers:
|
||||||
|
handler.setFormatter(new_formatter) # Применяем новый форматтер к каждому хендлеру
|
||||||
|
|
||||||
|
_etpgrf_init_logger.info(f"Формат логирования для 'etpgrf' динамически обновлен на: '{new_format_string}'")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Инициализация логгера при первом импорте ---
|
||||||
|
setup_library_logging()
|
||||||
|
|
||||||
|
|
||||||
|
# --- Предоставление логгеров для модулей ---
|
||||||
|
def get_logger(name: str) -> logging.Logger:
|
||||||
|
"""
|
||||||
|
Возвращает логгер для указанного имени.
|
||||||
|
Обычно используется как logging.getLogger(__name__) в модулях.
|
||||||
|
Имя будет дочерним по отношению к "etpgrf", например, "etpgrf.hyphenation".
|
||||||
|
"""
|
||||||
|
# Убедимся, что имя логгера начинается с "etpgrf." для правильной иерархии,
|
||||||
|
# если только это не сам корневой логгер.
|
||||||
|
if not name.startswith("etpgrf") and name != "etpgrf":
|
||||||
|
# Это может быть __name__ из модуля верхнего уровня, использующего библиотеку. В этом случае мы не хотим
|
||||||
|
# делать его дочерним от "etpgrf" насильно. Просто вернем логгер с именем...
|
||||||
|
# Либо можно настроить, что все логгеры, получаемые через эту функцию, должны быть частью иерархии "etpgrf"...
|
||||||
|
# Для простоты оставим так:
|
||||||
|
pass # logging_settings = logging.getLogger(name)
|
||||||
|
# Более правильный подход для модулей ВНУТРИ библиотеки etpgrf: они должны вызывать `logging.getLogger(__name__)`
|
||||||
|
# напрямую. Тогда эта функция `get_logger()` может быть и не нужна, если модули ничего не делают кроме:
|
||||||
|
# import logging
|
||||||
|
# logging_settings = logging.getLogger(__name__)
|
||||||
|
#
|
||||||
|
# Однако, если нужно централизованно получать логгеры, можно сделать, чтобы `get_logger()` всегда возвращал
|
||||||
|
# дочерний логгер:
|
||||||
|
# if not name.startswith("etpgrf."):
|
||||||
|
# name = f"etpgrf.{name}"
|
||||||
|
return logging.getLogger(name)
|
||||||
|
|
@ -1,6 +1,9 @@
|
|||||||
from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs
|
from etpgrf.comutil import parse_and_validate_mode, parse_and_validate_langs
|
||||||
|
|
||||||
from etpgrf.hyphenation import Hyphenator
|
from etpgrf.hyphenation import Hyphenator
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# --- Настройки логирования ---
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# --- Основной класс Typographer ---
|
# --- Основной класс Typographer ---
|
||||||
@ -17,7 +20,6 @@ class Typographer:
|
|||||||
self.langs: frozenset[str] = parse_and_validate_langs(langs)
|
self.langs: frozenset[str] = parse_and_validate_langs(langs)
|
||||||
# B. --- Обработка и валидация параметра mode ---
|
# B. --- Обработка и валидация параметра mode ---
|
||||||
self.mode: str = parse_and_validate_mode(mode)
|
self.mode: str = parse_and_validate_mode(mode)
|
||||||
print("Typographer: langs:", self.langs, "// mode:", self.mode) # Для отладки
|
|
||||||
# C. --- Инициализация правила переноса ---
|
# C. --- Инициализация правила переноса ---
|
||||||
# Предпосылка: если вызвали типограф, значит, мы хотим обрабатывать текст и переносы тоже нужно расставлять.
|
# Предпосылка: если вызвали типограф, значит, мы хотим обрабатывать текст и переносы тоже нужно расставлять.
|
||||||
# А для специальных случаев, когда переносы не нужны, пусть не ленятся и делают `hyphenation=False`.
|
# А для специальных случаев, когда переносы не нужны, пусть не ленятся и делают `hyphenation=False`.
|
||||||
@ -35,6 +37,7 @@ class Typographer:
|
|||||||
# 4. Если hyphenation что-то неведомое, то игнорируем его и правило переноса выключено
|
# 4. Если hyphenation что-то неведомое, то игнорируем его и правило переноса выключено
|
||||||
self.hyphenation = None
|
self.hyphenation = None
|
||||||
# D. --- Конфигурация других правил---
|
# D. --- Конфигурация других правил---
|
||||||
|
logger.debug(f"Typographer `__init__`: langs: {self.langs}, mode: {self.mode}, hyphenation: {self.hyphenation}")
|
||||||
|
|
||||||
|
|
||||||
# Конвейер для обработки текста
|
# Конвейер для обработки текста
|
||||||
|
7
main.py
7
main.py
@ -1,11 +1,14 @@
|
|||||||
import etpgrf
|
import etpgrf
|
||||||
|
import logging
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# --- Пример использования ---
|
# --- Пример использования ---
|
||||||
print("\n--- Пример использования класса---\n")
|
print("\n--- Пример использования класса---\n")
|
||||||
|
|
||||||
etpgrf.defaults.etpgrf_settings.hyphenation.MAX_UNHYPHENATED_LEN = 8
|
etpgrf.defaults.etpgrf_settings.hyphenation.MAX_UNHYPHENATED_LEN = 8
|
||||||
|
etpgrf.defaults.etpgrf_settings.logging_settings.LEVEL = logging.DEBUG
|
||||||
|
etpgrf.logger.update_etpgrf_log_level_from_settings() # Обновляем уровень логирования из настроек
|
||||||
|
etpgrf.defaults.etpgrf_settings.logging_settings.FORMAT = '%(asctime)s - %(name)s = %(levelname)s - %(message)s'
|
||||||
|
etpgrf.logger.update_etpgrf_log_format_from_settings() # Обновляем формат логирования из настроек
|
||||||
|
|
||||||
# Определяем пользовательские правила переносов
|
# Определяем пользовательские правила переносов
|
||||||
hyphen_settings = etpgrf.Hyphenator(langs='ru', max_unhyphenated_len=8)
|
hyphen_settings = etpgrf.Hyphenator(langs='ru', max_unhyphenated_len=8)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user