Ошибка при установке пакета Python: AttributeError: module 'pkgutil' has no attribute 'ImpImporter'

Почему так, Обэмэ?

При попытке установить Python-пакет (обычно через pip install) сборка падает с трассировкой типа:

AttributeError: module 'pkgutil' has no attribute 'ImpImporter'. Did you mean: 'zipimporter'?

Ошибка возникает не в самом устанавливаемом пакете, а в setuptools - библиотеке, которая отвечает за сборку (build backend) большинства Python-пакетов, использующих setup.py. Старые версии setuptools внутри себя обращаются к классу pkgutil.ImpImporter, который был вспомогательным инструментом для старого механизма импорта модулей в Python

  1. imp и связанные с ним API удалены в Python 3.12.
    Модуль imp был объявлен устаревшим ещё в Python 3.4, а в Python 3.12 его окончательно удалили в пользу современного importlib. Вместе с ним из pkgutil пропал и класс ImpImporter, который был обёрткой над старым импортёром.

  2. Старый setuptools ещё использует удалённый API.
    Версии setuptools ниже примерно 60.x содержат код (в setuptools/_distutils или в pkg_resources), который на этапе обнаружения путей к пакетам (pkgutil.ImpImporter использовался для поддержки namespace-пакетов старого стиля) вызывает pkgutil.ImpImporter. Как только Python обновляется до 3.12+, этот вызов падает, потому что атрибута больше не существует.

  3. Изолированная среда сборки (build isolation).
    Начиная с PEP 517/518, pip по умолчанию создаёт временное изолированное окружение для сборки пакета и устанавливает туда ту версию setuptools, которая указана в pyproject.toml/setup_requires пакета, либо версию по умолчанию, зашитую в pip. Если эта версия старая, можно столкнуться с ошибкой, даже если в основном окружении setuptools уже свежий.

  4. Устаревший/недообновлённый интерпретатор Python.
    Часто это всплывает после обновления системы или установки нового Python (3.12+) «поверх» - при этом связка pip/setuptools, поставляемая вместе с интерпретатором, могла остаться старой, так как ensurepip не переустанавливается автоматически при каждом запуске.

Итого: причина проблемы - несовместимость версии setuptools с версией Python, а не проблема конкретного пакета, который ты пытаешься установить.

Что делать?

python -m ensurepip --upgrade
python -m pip install --upgrade pip setuptools wheel

1. python -m ensurepip --upgrade

ensurepip - это стандартный модуль, встроенный в Python, который гарантирует наличие pip в окружении и умеет переустановить/обновить его до версии, «зашитой» в дистрибутив текущего интерпретатора.

  • Флаг --upgrade заставляет ensurepip обновить уже установленный pip до актуальной для данного Python версии, даже если он уже есть.
  • Это полезно, если по каким-то причинам pip в окружении битый, отсутствует или сильно устарел - команда чинит его «с нуля», используя ресурсы, встроенные в сам интерпретатор Python, без обращения к сети.

По сути, это восстановление базового инструмента установки пакетов, прежде чем им пользоваться дальше.

2. python -m pip install --upgrade pip setuptools wheel

Эта команда обновляет три ключевых инструмента экосистемы упаковки Python:

  • pip - сам менеджер пакетов. Новые версии pip умеют правильно резолвить зависимости для сборки и подтягивать современные версии setuptools в build isolation.
  • setuptools - именно здесь и была причина ошибки. Обновление до актуальной версии (60+ и выше) убирает использование удалённого pkgutil.ImpImporter, так как в новых версиях setuptools эта логика переписана под importlib.
  • wheel - инструмент для сборки .whl-пакетов (бинарных дистрибутивов). Его тоже стоит держать актуальным, так как многие пакеты при отсутствии wheel собираются менее надёжно (через sdist), что увеличивает шанс столкнуться с подобными проблемами совместимости.

Флаг --upgrade обновляет пакеты, даже если какая-то версия уже установлена, до последней доступной в PyPI (или в вашем внутреннем индексе).

После этих двух команд pip и setuptools в вашем текущем интерпретаторе становятся совместимы с Python 3.12+, и последующие pip install <package> больше не должны падать с этой ошибкой.

Нюансы

Если ошибка возникает внутри виртуального окружения

Виртуальные окружения (venv, virtualenv) наследуют pip/setuptools на момент создания. Если venv был создан давно на другой версии Python, стоит:

python -m venv .venv --upgrade-deps

Флаг --upgrade-deps (доступен с Python 3.9+) сразу создаёт venv с актуальными pip и setuptools, что избавляет от необходимости обновлять их вручную после создания.

Если ошибка возникает именно в изолированной среде сборки

Иногда обновление setuptools в основном окружении не помогает, потому что pip всё равно подтягивает старую версию в изолированную build-среду конкретного пакета (управляется build-system.requires в его pyproject.toml). В этом случае можно:

  • Отключить изоляцию сборки и заставить pip использовать setuptools из текущего окружения:
    shell pip install --no-build-isolation <package>
    (Работает только если в текущем окружении уже стоит достаточно новый setuptools.)

  • Либо, если пакет откровенно устарел и не обновляется мейнтейнером, временно откатиться на более старую версию Python (например, 3.11), где pkgutil.ImpImporter ещё существует - это скорее «костыль» на время, пока апстрим не поправит зависимости.

ensurepip --upgrade не требует интернета - он использует копию pip, встроенную в сам дистрибутив Python. А вот второй шаг (pip install --upgrade ...) требует доступа к индексу пакетов (PyPI или внутреннему зеркалу), это стоит учитывать при диагностике, если вторая команда «зависает» или падает с сетевой ошибкой.

Итог

Ошибка носит системный характер - она не связана с багом в конкретном устанавливаемом пакете, а является следствием удаления устаревшего API в новых версиях Python. Поэтому универсальное и правильное решение - держать pip, setuptools и wheel актуальными в каждом используемом окружении (глобальном или виртуальном).

#pip#python#ошибка#траблшутинг

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

Комментарий появится после проверки модератором.