@TemaKam

Почему configparser иногда не может правильно обработать русские символы в названии секции?

Traceback (most recent call last):
  File "", line 1241, in startli_task_f
    cfg[self.task_name].update({'task_startli': str(self.startli_task.isChecked())})
  File "lib\configparser.py", line 960, in __getitem__
    raise KeyError(key)
KeyError: '╧хЁхўхъ'

причем где-то раз в 10-20 использований такое, остальные разы нормально считывает русские символы
как это исправить?

записываю как (в self.task_name эти русские символы):
cfg = ConfigParser()
cfg.read('settings/default/tasks.ini', encoding='utf-8')
cfg[self.task_name].update({'task_startli': str(self.startli_task.isChecked())})
with open('settings/default/tasks.ini', 'w', encoding='utf-8') as setfile:
    cfg.write(setfile)

файл в utf-8
aUyzKZQ.jpg
self.task_name - классовая переменная инициализируется при создании класса в __init__
берется из параметра этой функции, а как параметр попадает из другого класса - из формы приложения на pyqt5, а именно QTextBrowser.toPlainText()
затем не меняется в этом классе вообще

с cfg.set также бывает, и еще выводил в консоль self.task_name, даже в консоли нормально выводит, но конфигпарсеру иногда не нравится
Перечек
Traceback (most recent call last):
  File "", line 1242, in startli_task_f
    cfg.set(self.task_name, 'task_startli', str(self.startli_task.isChecked()))
  File "", line 1201, in set
    super().set(section, option, value)
  File "", line 902, in set
    raise NoSectionError(section) from None
configparser.NoSectionError: No section: '╧хЁхўхъ'
  • Вопрос задан
  • 555 просмотров
Пригласить эксперта
Ответы на вопрос 1
trapwalker
@trapwalker Куратор тега Python
Программист, энтузиаст
Ух каша у вас какая-то тут из гипотез, суеверий, заблуждений и кусков кода, которые, как вам кажется, полностью обрисовывают проблему. А проблема у вас в том, что вы неправильно работаете с кодировками.

Общие правила работы с кодировками в питоне я уже много раз рассказывал на этом ресурсе.
На входе в программу мы всё переводим в юникод, а на выходе всё кодируем в байты.
Для ясности: юникод - это не кодировка, это абстрактный способ однозначной нумерации символов. Кодировка - это способ представить символ (а символ имеет свой однозначный код в таблице Юникода) в виде набора байт.
Итак, текст в юникоде - - это, образно говоря, последовтаельность номеров символов из таблицы юникода.
Текст в любой кодировке - это последовательность байтов.
Важно отметить, что так или инае номера юникода тоже внутри компа хранятся как байты, а питон с ними работает не как с массивом чисел, а как с объектом "строка", значит внутри он всё же хранит юникод в какой-то специальной кодировке, но тут есть важная деталь.

Есть кодировки, способные представить ВСЕ возможные символы Юникода, а есть кодировки, которые могут представить только некоторое подмножество этих символов. К первым относятся UTF-8, UTF-16, UTF-32 - они по-разному представляют номер символа таблицы Юникод в виде байтов, но способны представить любой символ.
Ко вторым, к примеру, однобайтовые кодировки cp1862, cp866, koi8 прочие. Такие кодировки - пережиток прошлого, когда в угоду простоте люди жертвовали универсальностью. Однако со временем, когда требоания к ПО и набору поддерживаемых символов изменилось, появилась необходимость как-то между этими кодировками переключаться, преобразовывать тексты, учитывать, что какойто текст без потери данных вовсе нельзя перевести из одной в другую кодировку, потому что каких то букв просто нет в целевой кодировке. Так простота накопилась техническим долгом и обернулась многократно возросшей сложностью учета всех этих нюансов.

В питоне внутри для хранения юникод-строк (а в 3 питоне это основной вид строк) используется не помню какая и utf-кодировок, но она точно может представить любой символ таблицы Юникода. И нам не нужно даже знать что это за кодировка, нам нужно знать какая кодировка на входе и на выходе программы.
У нас на входе и на выходе всегда байты. А именно:
- стандартные потоки ввода, вывода и ошибок, а также другие пайпы - это обычные байтовые потоки, которые работают ка коткрытые файлы, но являются пайпами на уровне системы и могут быть пернеправлены в реальные файлы в файловой сисеме.
- файлы - в файловой системе данные лежат в виде батов, и, в любом случае, нам нужно их как-то интерпретировать, если это текст.

Питон позволяет сделать обёртки вокруг файлового объекта, которые незаметно и прозрачно преобразовывают кодировки так что пользователь может в программе работать с юникодом не задумываясь о кодировках.
Всего лишь нужно правильно натсроить все эти обёртки и никогда не преобразовывать ничего вручную, а также не работать с байтовыми кодировками напрямую.

У вас, очевидно, self.task_name хранится в закодированном виде или некорректно преоразовывается.

Магии не бывает. Ничего там случайным образом с разу на раз не переключается. Если вы видете разные поведения в рахных ситуациях, то просто упускаете какой-то фактор. К примеру в винде запуск из bat-файла, запуск из консоли и запуск кликом мышкой в проводнике могут повлечь за собой запуск процесса с передачей ему пайпов стандартных потоков ввода вывода в разных кодировках. Если в программе мы этого не учитываем, то можем столкнуться с таким поведением как у вас.

Прологируйте значение вашего repr(self.task_name) перед взятием по ключу когда происходит ошибка и когда не происходит.
Вы увидите что меняется.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы