У меня была мысль написать экспериментальную реализацию import-а (вроде такое можно сделать в питоне). Что бы она смотрела кто вызывает импорт, например это foo-1.0. После чего смотрела на его зависимости, например там будет bar-1.0. И соответственно импортировало bar-1.0. А если импорт bar-а делает пакет image, у которого в зависимостях написано bar-2.0, то для этого пакета выдавать именно bar-2.0.
Это всё по аналогии с тем как это работает для Rust и других языков, где имя и версия пакета не является, чем-то глобальным и определяется только в рамках другого пакета, для которого он нужен.
Тут конечно могут быть проблемы, если foo возвращает объекты из bar, и мы потом эти объекты захотим прокинуть в image, которая использует внутри себя новую версию bar с несовместимыми типами bar-объектов. Питон без статической типизации не сможет нас от этого защитить на этапе "компиляции". Но может это будет не так страшно, и не так часто встречаться, и вообще "утка спасёт мир".
Из плюсов такого решения - можно будет ставить одновременно разные версии одного и того же пакета и не разруливать с матами несовместимые зависимости зависимостей.