2025, Nov 21 21:01

Почему в ISPF/3270 ломаются скобки и падает Python на z/OS

Почему в ISPF/3270 на z/OS скобки меняются, а Python падает с Unicode/SyntaxError. Проверяем EBCDIC-байты [=AD,BD] и настраиваем кодовую страницу эмулятора.

Редактирование Python на z/OS может неожиданно оказаться непростым, если в процессе задействованы эмулятор 3270 и ISPF Edit. Типичный признак — квадратные скобки внезапно превращаются в треугольные глифы в редакторе. Затем файл падает во время выполнения с ошибками кодировки или синтаксиса, хотя сам код валиден для Python. Причина кроется не в Python, а в кодовых страницах терминала и сопоставлении клавиш.

Минимальный пример, который вызывает проблему

Ниже фрагмент читает член набора данных в USS и выводит первые четыре символа каждой строки. Логика проста; проблемы начинаются в тот момент, когда скобки вводятся в ISPF‑редакторе через неверно настроенный эмулятор.

from zoautil_py import datasets as ds_api
data_ref = "'CICS.H39808.PROCLIB(S55CTL)'"
text_blob = ds_api.read(data_ref)
row_list = text_blob.split('\n')
for rec in row_list:
    print(rec[0:4])

Вывод всей строки вместо среза часто срабатывает в этой ситуации. Стоит вернуть срез [0:4], как скобки, которые выглядели нормально, при сохранении превращаются в другие символы, и Python сообщает об ошибках вроде UnicodeDecodeError для UTF‑8 или SyntaxError с жалобой на “Non-UTF-8 code … but no encoding declared.” Попытки сменить кодировку через iconv или добавить объявление исходной кодировки, например cp1047, затем приводят к новым ошибкам или сообщениям “illegal character sequence”.

Что на самом деле происходит

Ключевой фактор — среда, в которой создаётся и редактируется файл: эмулятор 3270, через который запускается TSO/ISPF (Опция 3.17) для редактирования содержимого USS. Кодовая страница эмулятора и сопоставление клавиш определяют, какие байты EBCDIC записываются при нажатии [ и ]. Если сопоставление неверно, редактор сохранит вовсе другие символы. Затем Python читает эти байты и либо не может декодировать их как UTF‑8, либо воспринимает как недопустимый синтаксис.

Проверить сопоставление просто: включите Hex‑отображение в ISPF Edit при просмотре файла и посмотрите байты для символов скобок. При правильной настройке для [ должен быть x’ad’, а для ] — x’bd’. Если видите другие значения, эмулятор отправляет не те коды.

Этим же объясняется, почему перекодирование постфактум не помогает. Если неправильные байты попали в файл на этапе ввода, смена кодировки лишь перекладывает ошибочные байты между наборами символов. Точно так же добавление «cookie» кодировки, например cp1047, не исправит символы, которые изначально не были скобками, и может породить новые ошибки декодирования. Напротив, создание файла вне ISPF — например, локальное редактирование в Notepad++ с последующей отправкой в USS или работа напрямую по SSH — обходят путь через 3270 и связанные с ним ловушки раскладки и кодовых страниц.

Как это исправить

Начните с корректировки настроек эмулятора 3270. Проверьте кодовую страницу и убедитесь, что для клавиш [ и ] используется ожидаемое сопоставление. После правок откройте файл в ISPF Edit, включите Hex и подтвердите, что скобки сохранены как x’ad’ и x’bd’. Когда байты правильные, исходник будет сохраняться корректно, и Python перестанет спотыкаться о ошибки декодирования и синтаксиса, связанные со скобками.

Если вы создаёте и редактируете файлы специально для USS, подумайте о работе напрямую в shell‑сессии, а не через ISPF Edit. Так вы полностью избегаете особенностей кодовых страниц 3270. В обсуждении, которое привело к решению, файлы, созданные вне ISPF (например, в Notepad++ с последующей передачей в USS), вели себя как нужно, тогда как отредактированные в ISPF при неверной настройке эмулятора — нет.

Рабочий код после исправления окружения

Когда эмулятор и сопоставление клавиш настроены верно, менять логику Python не требуется. Тот же самый скрипт работает как задумано, если скобки записываются правильными байтами.

from zoautil_py import datasets as ds_api
mbr_ref = "'CICS.H39808.PROCLIB(S55CTL)'"
content = ds_api.read(mbr_ref)
records = content.split('\n')
for row in records:
    print(row[0:4])

Почему это важно

На z/OS корректность — это не только про код, но и про путь, который проходят символы от клавиатуры до файла. Неправильно настроенный 3270 способен незаметно переписать символы в другие коды EBCDIC, из‑за чего в целом корректный Python перестаёт запускаться. Умение распознавать симптомы — превращение скобок в другие глифы в ISPF, постоянные UnicodeDecodeError или SyntaxError из‑за не‑UTF‑8 байтов — и знание, что нужно проверить кодовую страницу эмулятора и сопоставление клавиш, экономят часы бессмысленных попыток с iconv или «cookies» кодировки.

Выводы

Если квадратные скобки и другая пунктуация загадочно меняются в ISPF Edit, а Python начинает выдавать ошибки кодировки или синтаксиса, сначала проверьте эмулятор. Убедитесь в правильности кодовой страницы 3270 и сопоставления клавиш, а в редакторе включите Hex‑режим и проверьте, что для [ и ] записаны x’ad’ и x’bd’. Когда возможно, редактируйте файлы USS по SSH или готовьте их вне платформы с последующей передачей — так вы полностью обходите проблемы кодовых страниц и сопоставления клавиш 3270. При корректно настроенном окружении исходники Python будут хранить нужные символы, и изначальная логика заработает без изменений.