minor: улучшена читаемость кода

This commit is contained in:
2026-06-26 18:21:55 +03:00
parent d53330554b
commit 01710200b2
+216 -226
View File
@@ -609,260 +609,250 @@ def validate_entity_for_admin_form(form_instance, cleaned_data,
metadata_field_name=metadata_field_name, metadata_field_name=metadata_field_name,
) )
if VALIDATE_KEY__MATCH_TYPE not in result:
return # Нет совпадений, продолжаем обработку формы
# Обрабатываем результаты проверки в зависимости от типа найденного совпадения # Обрабатываем результаты проверки в зависимости от типа найденного совпадения
if VALIDATE_KEY__MATCH_TYPE in result: match_type = result[VALIDATE_KEY__MATCH_TYPE]
match_type = result[VALIDATE_KEY__MATCH_TYPE] duplicates_queryset = result[VALIDATE_KEY__VALUE]
duplicates_queryset = result[VALIDATE_KEY__VALUE]
# В dup_links формируем ссылки на найденные дубликаты для быстрого перехода в админке # В dup_links формируем ссылки на найденные дубликаты для быстрого перехода в админке
dup_links = [] dup_links = []
# Используем match-case для удобной обработки разных типов совпадений # Используем match-case для удобной обработки разных типов совпадений
# С Enum вместо магических чисел код становится самодокументируемым # С Enum вместо магических чисел код становится самодокументируемым
# В будущем легко добавить новые типы: ValidateMatchType.PARTIAL_MATCH = 2 и т.д. # В будущем легко добавить новые типы: ValidateMatchType.PARTIAL_MATCH = 2 и т.д.
match match_type: match match_type:
case ValidateMatchType.IS_DUPLICATE: case ValidateMatchType.IS_DUPLICATE:
# ОБРАБОТКА ТОЧНЫХ ДУБЛИКАТОВ # ОБРАБОТКА ТОЧНЫХ ДУБЛИКАТОВ
for dup in duplicates_queryset:
# Относительная ссылка зависит от режима админки:
# При создании: /admin/app/model/add/ → ../456/change/
# При редактировании: /admin/app/model/123/change/ → ../..456/change/
rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/"
# Получаем значение основного поля из дубликата для вывода в ссылке
dup_value = getattr(dup, main_field_name, '?')
dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>")
# Объединяем все найденные дубликаты в один список
dup_list = ", ".join(dup_links)
# Для случая IS_DUPLICATE всегда выбрасываем ошибку, т.к. это критическая ситуация
# и поле часто имеет unique=True на уровне модели.
raise ValidationError(
mark_safe(
f"ОШИБКА: Найдено ПОЛНОЕ совпадение! "
f"Измените название или отредактируйте {dup_list}."
)
)
case ValidateMatchType.FIND_IN_SYNONYM:
# ОБРАБОТКА СОВПАДЕНИЙ В СИНОНИМАХ (основное поле совпадает с синонимами других)
# Проверяем: это запрос с подтверждением (ignore_validate=1) или первоначальная проверка?
if request and request.GET.get('ignore_validate') == '1':
# РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь нажал красную кнопку и подтвердил "Я проверил и уверен!")
# Тихо удаляем найденные совпадения из синонимов других записей
remove_conflicting_synonyms_from_duplicates(
duplicates_queryset,
metadata_field_name,
[normalized_main_value], # Удаляем основное поле текущей записи
)
# Выходим без ошибки в админку, т.к. пользователь "проверил и уверен!"
# Конфликтующие синонимы удалены, запись сохранится нормально
return
else:
# РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА
# Показываем пользователю красную кнопку подтверждения с информацией о совпадениях
for dup in duplicates_queryset: for dup in duplicates_queryset:
# Относительная ссылка зависит от режима админки:
# При создании: /admin/app/model/add/ → ../456/change/
# При редактировании: /admin/app/model/123/change/ → ../..456/change/
rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/" rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/"
# Получаем значение основного поля из дубликата для вывода в ссылке
dup_value = getattr(dup, main_field_name, '?') dup_value = getattr(dup, main_field_name, '?')
dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>") dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>")
# Объединяем все найденные дубликаты в один список
dup_list = ", ".join(dup_links) dup_list = ", ".join(dup_links)
# Для случая IS_DUPLICATE всегда выбрасываем ошибку, т.к. это критическая ситуация # Кнопка подтверждения создания несмотря на синонимы
# и поле часто имеет unique=True на уровне модели. # При клике вызывает функцию markSubmitButtonsToIgnoreValidation()
# которая добавляет класс force-ignore-validation ко всем submit-кнопкам.
# Вотчер видит этот класс и добавляет onclick обработчик к кнопкам
# для добавления GET параметра ignore_validate=1 перед отправкой формы.
# Весь JS код находится в form-field-watcher.js для чистоты и переиспользования.
raise ValidationError( raise ValidationError(
mark_safe( mark_safe(
f"ОШИБКА: Найдено ПОЛНОЕ совпадение! " f"ВНИМАНИЕ: Найдено совпадение в синонимах! "
f"Измените название или отредактируйте {dup_list}." f"Проверьте {dup_list} "
f"или используйте синонимы из найденной записи."
f"<div class=\"confirmation-button-container\">"
f" <button type=\"button\" onclick=\"markSubmitButtonsToIgnoreValidation();\">"
f" <big>Я проверил и уверен!</big><br/>"
f" Сохранить, несмотря на синонимы.<br/>"
f" <i>Точные совпадения в синонимах других записей будут удалены.</i>"
f" </button>"
f" <em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>"
f"</div>"
) )
) )
case ValidateMatchType.FIND_IN_SYNONYM: case ValidateMatchType.EXACT_SYNONYM_MATCH:
# ОБРАБОТКА СОВПАДЕНИЙ В СИНОНИМАХ (основное поле совпадает с синонимами других) # ОБРАБОТКА СОВПАДЕНИЙ СИНОНИМОВ (синонимы текущей записи совпадают с синонимами других)
# Проверяем: это запрос с подтверждением (ignore_validate=1) или первоначальная проверка? # Проверяем: это запрос с подтверждением (ignore_validate=1) или первоначальная проверка?
if request and request.GET.get('ignore_validate') == '1': if request and request.GET.get('ignore_validate') == '1':
# РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь нажал красную кнопку и подтвердил "Я проверил и уверен!") # РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь нажал красную кнопку и подтвердил "Я проверил и уверен!")
# Тихо удаляем найденные совпадения из синонимов других записей # Тихо удаляем из других записей те синонимы, которые совпадают с синонимами текущей.
remove_conflicting_synonyms_from_duplicates( remove_conflicting_synonyms_from_duplicates(
duplicates_queryset, duplicates_queryset,
metadata_field_name, metadata_field_name,
[normalized_main_value], # Удаляем основное поле текущей записи metadata_dict.get(KEY_SYNONYM) or [], # Удаляем все синонимы текущей записи
) )
# Выходим без ошибки в админку, т.к. пользователь "проверил и уверен!" # Выходим без ошибки в админку, т.к. пользователь "проверил и уверен!"
# Конфликтующие синонимы удалены, запись сохранится нормально # Конфликтующие синонимы удалены, запись сохранится нормально
return return
else: else:
# РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА # РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА
# Показываем пользователю красную кнопку подтверждения с информацией о совпадениях # Обрабатываем на Python (без доп запросов к БД) - duplicates_queryset уже в памяти
# Для каждого синонима текущей записи ищем, в каких записях он есть
# Собираем текущие синонимы с нормализацией
current_synonyms_list = metadata_dict.get(KEY_SYNONYM) or []
# Строим словарь: {нормализованный синоним: {оригинальный синоним, запись1, запись2, ...}}
synonym_to_records = {}
for current_syn in current_synonyms_list:
normalized_syn = normalize_string(current_syn)
if normalized_syn not in synonym_to_records:
synonym_to_records[normalized_syn] = {
'original': current_syn,
'records': []
}
# Ищем этот синоним в метаданных других записей
for dup in duplicates_queryset: for dup in duplicates_queryset:
rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/" dup_metadata = getattr(dup, metadata_field_name) or {}
dup_value = getattr(dup, main_field_name, '?') dup_synonyms = dup_metadata.get(KEY_SYNONYM) or []
dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>")
dup_list = ", ".join(dup_links)
# Кнопка подтверждения создания несмотря на синонимы # Проверяем: есть ли текущий синоним в синонимах этой записи
# При клике вызывает функцию markSubmitButtonsToIgnoreValidation() for dup_syn in dup_synonyms:
# которая добавляет класс force-ignore-validation ко всем submit-кнопкам. if normalize_string(dup_syn) == normalized_syn:
# Вотчер видит этот класс и добавляет onclick обработчик к кнопкам # Добавляем запись если ее еще нет в списке
# для добавления GET параметра ignore_validate=1 перед отправкой формы. rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/"
# Весь JS код находится в form-field-watcher.js для чистоты и переиспользования. dup_value = getattr(dup, main_field_name, '?')
confirmation_button = ''' dup_link = f"<a href='{rel_url}'>#{dup.pk} '{dup_value}'</a>"
<div class="confirmation-button-container">
<button type="button" onclick="markSubmitButtonsToIgnoreValidation();">
<big>Я проверил и уверен!</big><br/>
Сохранить, несмотря на синонимы.<br/>
<i>Точные совпадения в синонимах других записей будут удалены.</i>
</button>
<em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>
</div>
'''
raise ValidationError( # Проверяем что эту запись еще не добавили для этого синонима
mark_safe( if dup_link not in synonym_to_records[normalized_syn]['records']:
f"ВНИМАНИЕ: Найдено совпадение в синонимах! " synonym_to_records[normalized_syn]['records'].append(dup_link)
f"Проверьте {dup_list} " break
f"или используйте синонимы из найденной записи."
f"{confirmation_button}" # Строим текст с детализацией по каждому синониму
) synonym_details = []
for normalized_syn, info in synonym_to_records.items():
original_syn = info['original']
records = info['records']
if records: # Только если этот синоним найден в других записях
records_html = ", ".join(records)
synonym_details.append(f"<b>'{original_syn}'</b> найден в: {records_html}")
# Объединяем все детали в один список
synonym_details_text = "<br/>".join(synonym_details) if synonym_details else "Синонимы не найдены"
# Кнопка подтверждения создания несмотря на совпадение синонимов
raise ValidationError(
mark_safe(
f"ВНИМАНИЕ: Найдено совпадение синонимов!<br/>"
f"Синонимы совпадают:<br/>{synonym_details_text}<br/>"
f"Проверьте и уточните синонимы если нужно."
f"<div class=\"confirmation-button-container\">"
f" <button type=\"button\" onclick=\"markSubmitButtonsToIgnoreValidation();\">"
f" <big>Я проверил и уверен!</big><br/>"
f" Сохранить, несмотря на совпадение синонимов.<br/>"
f" <i>Совпадающие синонимы в других записях будут удалены.</i>"
f" </button>"
f" <em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>"
f"</div>"
) )
)
case ValidateMatchType.EXACT_SYNONYM_MATCH: case ValidateMatchType.PARTIAL_MATCH:
# ОБРАБОТКА СОВПАДЕНИЙ СИНОНИМОВ (синонимы текущей записи совпадают с синонимами других) # ОБРАБОТКА ЧАСТИЧНЫХ СОВПАДЕНИЙ (слова совпадают)
# Проверяем: это запрос с подтверждением (ignore_validate=1) или первоначальная проверка? # Это просто схожесть, не критично. Показываем предупреждение, но не блокируем сохранение.
if request and request.GET.get('ignore_validate') == '1': # При подтверждении просто сохраняем без каких-либо изменений в других записях.
# РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь нажал красную кнопку и подтвердил "Я проверил и уверен!")
# Тихо удаляем из других записей те синонимы, которые совпадают с синонимами текущей. if request and request.GET.get('ignore_validate') == '1':
remove_conflicting_synonyms_from_duplicates( # РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь подтвердил что ознакомлен)
duplicates_queryset, # Тихо сохраняем запись, ничего не меняя в других записях
metadata_field_name, return
metadata_dict.get(KEY_SYNONYM) or [], # Удаляем все синонимы текущей записи
else:
# РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА
# Показываем пользователю информативное предупреждение о схожести
for dup in duplicates_queryset:
rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/"
dup_value = getattr(dup, main_field_name, '?')
dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>")
dup_list = ", ".join(dup_links)
# Кнопка для игнорирования предупреждения (без критичности)
raise ValidationError(
mark_safe(
f"ИНФОРМАЦИЯ: Найдены похожие записи со схожими словами! "
f"Проверьте: {dup_list} "
f"Это просто информация, не ошибка. Но неточности на сайте могут рассмешить"
f" (или огорчить) пользователей."
f"<div class=\"confirmation-button-container\">"
f" <button type=\"button\" onclick=\"markSubmitButtonsToIgnoreValidation();\">"
f" <big>OK, Я ПРОВЕРИЛ. ПРОБЛЕМ НЕ БУДЕТ</big><br/>"
f" Сохранить запись<br/>"
f" <i>Я уверен в своих действиях.</i>"
f" </button>"
f" <em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>"
f"</div>"
) )
# Выходим без ошибки в админку, т.к. пользователь "проверил и уверен!" )
# Конфликтующие синонимы удалены, запись сохранится нормально
return
else: case ValidateMatchType.PARTIAL_MATCH__RISK_SHORT_WORDS:
# РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА # ОБРАБОТКА ЧАСТИЧНЫХ СОВПАДЕНИЙ С ВЫСОКИМ РИСКОМ (очень короткие слова/синонимы)
# Обрабатываем на Python (без доп запросов к БД) - duplicates_queryset уже в памяти # Найдены совпадения, но среди слов есть очень короткие (< MIN_SYNONYM_WORD_LENGTH)
# Для каждого синонима текущей записи ищем, в каких записях он есть # Это может быть как вероятное совпадение (B'Z, XL) так и ложное срабатывание (А, И)
# Показываем ещё более серьезное предупреждение о необходимости проверки
# Собираем текущие синонимы с нормализацией if request and request.GET.get('ignore_validate') == '1':
current_synonyms_list = metadata_dict.get(KEY_SYNONYM) or [] # РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь подтвердил что ознакомлен с рисками)
# Тихо сохраняем запись, ничего не меняя в других записях
return
# Строим словарь: {нормализованный синоним: {оригинальный синоним, запись1, запись2, ...}} else:
synonym_to_records = {} # РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА
for current_syn in current_synonyms_list: # Показываем пользователю СЕРЬЕЗНОЕ предупреждение о высоком риске ошибки
normalized_syn = normalize_string(current_syn) for dup in duplicates_queryset:
if normalized_syn not in synonym_to_records: rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/"
synonym_to_records[normalized_syn] = { dup_value = getattr(dup, main_field_name, '?')
'original': current_syn, dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>")
'records': [] dup_list = ", ".join(dup_links)
}
# Ищем этот синоним в метаданных других записей # Кнопка для подтверждения с указанием на риск
for dup in duplicates_queryset: raise ValidationError(
dup_metadata = getattr(dup, metadata_field_name) or {} mark_safe(
dup_synonyms = dup_metadata.get(KEY_SYNONYM) or [] f"ВНИМАНИЕ: ВЫСОКИЙ РИСК ОШИБКИ! Найдены похожие записи с ОЧЕНЬ КОРОТКИМИ словами! "
f"Проверьте ОЧЕНЬ ВНИМАТЕЛЬНО: {dup_list} "
# Проверяем: есть ли текущий синоним в синонимах этой записи f"Совпадения могут быть двухбуквенными и даже однобуквенными словами (например:"
for dup_syn in dup_synonyms: f" \"B'Z\"\"B Z\" или \"R&B\"\"R B\" ). ОЧЕНЬ ВЕЛИК РИСК ложных срабатываний!"
if normalize_string(dup_syn) == normalized_syn: f"<div class=\"confirmation-button-container\">"
# Добавляем запись если ее еще нет в списке f" <button type=\"button\" onclick=\"markSubmitButtonsToIgnoreValidation();\">"
rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/" f" <big>ВНИМАНИЕ: ВЫСОКИЙ РИСК!</big><br/>"
dup_value = getattr(dup, main_field_name, '?') f" Я всё проверил и уверен в своих действиях.<br/>"
dup_link = f"<a href='{rel_url}'>#{dup.pk} '{dup_value}'</a>" f" <i>Очень короткие слова (символов менее {MIN_SYNONYM_WORD_LENGTH}), подтверждаю!</i>"
f" </button>"
# Проверяем что эту запись еще не добавили для этого синонима f" <em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>"
if dup_link not in synonym_to_records[normalized_syn]['records']: f"</div>"
synonym_to_records[normalized_syn]['records'].append(dup_link)
break
# Строим текст с детализацией по каждому синониму
synonym_details = []
for normalized_syn, info in synonym_to_records.items():
original_syn = info['original']
records = info['records']
if records: # Только если этот синоним найден в других записях
records_html = ", ".join(records)
synonym_details.append(f"<b>'{original_syn}'</b> найден в: {records_html}")
# Объединяем все детали в один список
synonym_details_text = "<br/>".join(synonym_details) if synonym_details else "Синонимы не найдены"
# Кнопка подтверждения создания несмотря на совпадение синонимов
confirmation_button = '''
<div class="confirmation-button-container">
<button type="button" onclick="markSubmitButtonsToIgnoreValidation();">
<big>Я проверил и уверен!</big><br/>
Сохранить, несмотря на совпадение синонимов.<br/>
<i>Совпадающие синонимы в других записях будут удалены.</i>
</button>
<em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>
</div>
'''
raise ValidationError(
mark_safe(
f"ВНИМАНИЕ: Найдено совпадение синонимов!<br/>"
f"Синонимы совпадают:<br/>{synonym_details_text}<br/>"
f"Проверьте и уточните синонимы если нужно."
f"{confirmation_button}"
)
) )
)
case ValidateMatchType.PARTIAL_MATCH: case _:
# ОБРАБОТКА ЧАСТИЧНЫХ СОВПАДЕНИЙ (слова совпадают) # Неизвестный или не обработанный тип совпадения
# Это просто схожесть, не критично. Показываем предупреждение, но не блокируем сохранение. # В будущем сюда можно добавить логирование неожиданных типов
# При подтверждении просто сохраняем без каких-либо изменений в других записях. pass
if request and request.GET.get('ignore_validate') == '1': return
# РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь подтвердил что ознакомлен)
# Тихо сохраняем запись, ничего не меняя в других записях
return
else:
# РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА
# Показываем пользователю информативное предупреждение о схожести
for dup in duplicates_queryset:
rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/"
dup_value = getattr(dup, main_field_name, '?')
dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>")
dup_list = ", ".join(dup_links)
# Кнопка для игнорирования предупреждения (без критичности)
confirmation_button = '''
<div class="confirmation-button-container">
<button type="button" onclick="markSubmitButtonsToIgnoreValidation();">
<big>OK, Я ПРОВЕРИЛ. ПРОБЛЕМ НЕ БУДЕТ</big><br/>
Сохранить запись<br/>
<i>Я уверен в своих действиях.</i>
</button>
<em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>
</div>
'''
raise ValidationError(
mark_safe(
f"ИНФОРМАЦИЯ: Найдены похожие записи со схожими словами! "
f"Проверьте: {dup_list} "
f"Это просто информация, не ошибка. Но неточности на сайте могут рассмешить"
f" (или огорчить) пользователей. {confirmation_button}"
)
)
case ValidateMatchType.PARTIAL_MATCH__RISK_SHORT_WORDS:
# ОБРАБОТКА ЧАСТИЧНЫХ СОВПАДЕНИЙ С ВЫСОКИМ РИСКОМ (очень короткие слова/синонимы)
# Найдены совпадения, но среди слов есть очень короткие (< MIN_SYNONYM_WORD_LENGTH)
# Это может быть как вероятное совпадение (B'Z, XL) так и ложное срабатывание (А, И)
# Показываем ещё более серьезное предупреждение о необходимости проверки
if request and request.GET.get('ignore_validate') == '1':
# РЕЖИМ: ОБХОД ВАЛИДАЦИИ (пользователь подтвердил что ознакомлен с рисками)
# Тихо сохраняем запись, ничего не меняя в других записях
return
else:
# РЕЖИМ: ПЕРВОНАЧАЛЬНАЯ ПРОВЕРКА
# Показываем пользователю СЕРЬЕЗНОЕ предупреждение о высоком риске ошибки
for dup in duplicates_queryset:
rel_url = f"../{dup.pk}/change/" if form_instance.instance.pk is None else f"../../{dup.pk}/change/"
dup_value = getattr(dup, main_field_name, '?')
dup_links.append(f"<big><a href='{rel_url}'>#{dup.pk} '{dup_value}'</a></big>")
dup_list = ", ".join(dup_links)
# Кнопка для подтверждения с указанием на риск
confirmation_button = '''
<div class="confirmation-button-container">
<button type="button" onclick="markSubmitButtonsToIgnoreValidation();">
<big>ВНИМАНИЕ: ВЫСОКИЙ РИСК!</big><br/>
Я уверен в своих действиях<br/>
<i>Найдены очень короткие слова (< 4 символов), высокий риск ошибки!</i>
</button>
<em>Теперь нажмите стандартные кнопки сохранения снизу, чтобы сохранить.</em>
</div>
'''
raise ValidationError(
mark_safe(
f"ВНИМАНИЕ: ВЫСОКИЙ РИСК ОШИБКИ! Найдены похожие записи с ОЧЕНЬ КОРОТКИМИ словами! "
f"Проверьте ОЧЕНЬ ВНИМАТЕЛЬНО: {dup_list} "
f"Совпадения могут быть с однобуквенными или двухбуквенными словами (например: 'B'Z''B Z'). "
f"Велик риск ложных срабатываний! {confirmation_button}"
)
)
case _:
# Неизвестный или не обработанный тип совпадения
# В будущем сюда можно добавить логирование неожиданных типов
pass
def validate_and_raise_for_duplicates( def validate_and_raise_for_duplicates(