Почему так, Обэмэ?
При попытке установить Python-пакет (обычно через pip install) сборка падает с трассировкой типа:
AttributeError: module 'pkgutil' has no attribute 'ImpImporter'. Did you mean: 'zipimporter'?
Ошибка возникает не в самом устанавливаемом пакете, а в setuptools - библиотеке, которая отвечает за сборку (build backend) большинства Python-пакетов, использующих setup.py. Старые версии setuptools внутри себя обращаются к классу pkgutil.ImpImporter, который был вспомогательным инструментом для старого механизма импорта модулей в Python
-
impи связанные с ним API удалены в Python 3.12.
Модульimpбыл объявлен устаревшим ещё в Python 3.4, а в Python 3.12 его окончательно удалили в пользу современногоimportlib. Вместе с ним изpkgutilпропал и классImpImporter, который был обёрткой над старым импортёром. -
Старый setuptools ещё использует удалённый API.
Версии setuptools ниже примерно 60.x содержат код (вsetuptools/_distutilsили вpkg_resources), который на этапе обнаружения путей к пакетам (pkgutil.ImpImporterиспользовался для поддержки namespace-пакетов старого стиля) вызываетpkgutil.ImpImporter. Как только Python обновляется до 3.12+, этот вызов падает, потому что атрибута больше не существует. -
Изолированная среда сборки (
build isolation).
Начиная с PEP 517/518,pipпо умолчанию создаёт временное изолированное окружение для сборки пакета и устанавливает туда ту версию setuptools, которая указана вpyproject.toml/setup_requiresпакета, либо версию по умолчанию, зашитую в pip. Если эта версия старая, можно столкнуться с ошибкой, даже если в основном окружении setuptools уже свежий. -
Устаревший/недообновлённый интерпретатор 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 актуальными в каждом используемом окружении (глобальном или виртуальном).
Комментарии
Пока нет комментариев. Будьте первым!
Оставить комментарий