14.08.2022

В 3.6% протестированных Python-репозиториев выявлены ошибки, связанные с пропущенными запятыми

Опубликованы результаты исследования подверженности кода на языке Python ошибкам, связанным с некорректным использованием запятых в коде. Проблемы вызваны тем, что при перечислениях Python автоматически объединяет строки в списке, если они не разделены запятой, а также обрабатывает значение, как кортеж, если после значения следует запятая. Проведя автоматизированный анализ 666 GitHub-репозиториев с кодом на языке Python исследователи выявили возможные проблемы с запятыми в 5% изученных проектов.

Дальнейшая ручная проверка показала, что реальные ошибки присутствуют только в 24 репозиториях (3.6%), а остальные 1.4% являются ложными срабатываниями (например, запятая могла быть специально пропущена между строками для объединения разбитых на несколько строк файловых путей, длинных хэшей, HTML-блоков или SQL-выражений). Примечательно, что в числе 24 репозиториев с реальными ошибками оказались такие крупные проекты, как Tensorflow, Google V8, Sentry, Pydata xarray, rapidpro, django-colorfield и django-helpdesk. При этом проблемы с запятыми не специфичны для Python и часто всплывают в проектах на C/C++ (примерны недавних исправлений — LLVM, Mono, Tensorflow).

Основные виды изученных ошибок:

  • Случайно пропущенная запятая в списках, кортежах и множествах, приводящая к объединению строк вместо их интерпретации как отдельных значений. Например, в Sentry в одном из тестов была пропущена запятая между строками «releases» и «discover» в списке, что привело к проверке несуществующего обработчика «/releasesdiscover», вместо раздельной проверки «/releases» и «/discover».

    Другой пример — пропущенная запятая в rapidpro приводила к объединению дух разных правил в строке 572:

  • Пропущенная запятая в конце определения кортежа из одного элемента, приводящая к тому, что в ходе присвоения будет присвоен не кортеж, а обычный тип. Например, выражение «values = (1,)» приведёт к присвоению переменной кортежа из одного элемента, но «values = (1)» приведёт к присвоению целого типа. Скобки в указанных присвоениях не влияют на определение типа и являются необязательными, а наличие кортежа определяется парсером только на основе наличия запятых.
     REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated' # вместо кортежа будет присвоена строка. ) }
    
  • Обратная ситуация — лишние запятые при присвоении. Если в конце присвоения случайно оставлена запятая, то в качестве значения вместо обычного типа будет присвоен кортеж (например, если вместо «value = 1» указано «value = 1,»).

Источник.