Переносимый офлайн-менеджер Python-пакетов
- О проекте
- Целевая аудитория
- Что умеет
- Важно
- Быстрый старт
- Команды
- Где хранить архив
- История развития проекта
- Лицензия
- Примечания
pyoffline — автономный менеджер Python-окружений, которому не нужен постоянный доступ к интернету.
Кратко:
PyOffline2 — ваш переносимый «чемоданчик судного дня» для Python-разработки. Один раз, пока есть интернет, скачайте нужные версии Python (портативные, без глобальной установки) и все необходимые пакеты из PyPI в локальный архив. Никаких серверов, баз данных и сложного развёртывания — всё работает из коробки, запускается за пару минут и не требует специальных знаний. Дальше создавайте проекты где угодно, полностью офлайн, вообще без интернета. Нестабильная связь, долгая загрузка или внезапная недоступность репозиториев перестают быть проблемой — всё уже у вас под рукой. При этом PyOffline2 не заменяет uv или pip, а дополняет их, работая параллельно и не вмешиваясь в привычный вам процесс.
Термины использующиеся далее:
-
архив- подразумевается папка resources в которую скачиваются портативные версии python (resources/python_strage), и пакеты (resourcs/packages_storage), то есть те ресурсы которые сохраняются и могут использоваться в том числе оффлайн. -
проект- папка с кодом python и своим виртуальным окружением которое может быть создано черезpyoff initна базе python из архива (из папки python_storage), в него устанавливаются проекты из архива (packages_storage).
┌─────────────────────────────────────────────────────────────────┐
│ АРХИВ (resources/) │
│ ┌───────────────────┐ ┌───────────────────────────────────┐ │
│ │ python_storage/ │ │ packages_storage/ │ │
│ │ 3.10/ │ │ 3.10/ │ │
│ │ 3.12/ │ │ fastapi/ requests/ │ │
│ │ 3.14/ │ │ 3.12/ │ │
│ └───────────────────┘ │ fastapi/ requests/ │ │
│ └───────────────────────────────────┘ │
│ │
│ Заранее запасенные python-portable дистрибутивы, и пакеты с │
│ pypi.org │
│ │
└─────────────────────────────────────────────────────────────────┘
│
│ pyoff init -pv 3.12
│ pyoff add fastapi
▼
┌─────────────────────────────────────────────────────────────────┐
│ ПРОЕКТ (my-project/) │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ .venv/ (виртуальное окружение на базе Python 3.12) │ │
│ │ pyproject.toml (зависимости: fastapi==0.138.0) │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ Пользовательский проект, пересоздаваемая единица, использующая, │
│ ресурсы из resources. │
│ │
└─────────────────────────────────────────────────────────────────┘
Подробно:
В современном мире мы привыкли полагаться на облака, CDN и глобальные репозитории. Это удобно, пока связь стабильна. Но что происходит, когда:
- интернет медленный, нестабильный или отсутствует?
- нужно развернуть десяток проектов, а каждый
pip installзаново качает гигабайты? - критически важные пакеты вдруг становятся недоступны по независящим от вас причинам? (потеря связи с PyPi.org, Python.org, блокировки, политика... Другие обстоятельства.)
pyoffline даёт простой ответ: один раз скачал — пользуешься везде.
Вы формируете собственный архив интерпретаторов Python и пакетов, после чего создание проектов и установка зависимостей происходят полностью офлайн. Никакой магии, никакой привязки к внешним серверам. Только вы, ваш код и всё, что нужно для работы.
Версии python скачиваются под конкретную версию вашей ОС (проверено на windows 10, linux ubuntu/mint):
Например результат выполнения команды get-python 3.10 :
...
├─ 📁 resources
│ ├── 📁 python_storage
│ │ └── 📁 windows-x86_64 <- действие было выполнено на windows
│ │ ├── 📁 3.10 <- добавлен python 3.10 (результат `get-python 3.10`)
│ │ │ └── 📃 ...
│ │ ├── 📁 3.12
│ │ │ └── 📃 ...
│ │ ├── 📁 3.14
│ │ │ └── 📃 ...
...
Например результат выполнения команды get python-dotenv, requests :
...
├─ 📁 resources
│ ├─ 📁 packages_storage
│ │ └─ 📁 windows-x86_64 <- действие было выполнено на windows
│ │ ├─ 📁 3.10
│ │ │ ├─ 📁 python_dotenv==1.2.2
│ │ │ │ └─ 📦 python_dotenv-1.2.2-py3-none-any.whl
│ │ │ └─ 📁 requests==2.34.2
│ │ │ ├─ 📦 certifi-2026.6.17-py3-none-any.whl
│ │ │ ├─ 📦 charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl
│ │ │ ├─ 📦 idna-3.18-py3-none-any.whl
│ │ │ ├─ 📦 requests-2.34.2-py3-none-any.whl
│ │ │ └─ 📦 urllib3-2.7.0-py3-none-any.whl
│ │ ├─ 📁 3.12
│ │ │ ├─ 📁 python_dotenv==1.2.2
│ │ │ │ └─ 📦 python_dotenv-1.2.2-py3-none-any.whl
│ │ │ └─ 📁 requests==2.34.2
│ │ │ ├─ 📦 certifi-2026.6.17-py3-none-any.whl
│ │ │ ├─ 📦 charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl
│ │ │ ├─ 📦 idna-3.18-py3-none-any.whl
│ │ │ ├─ 📦 requests-2.34.2-py3-none-any.whl
│ │ │ └─ 📦 urllib3-2.7.0-py3-none-any.whl
│ │ └─ 📁 3.14
│ │ ├─ 📁 python_dotenv==1.2.2
│ │ │ └─ 📦 python_dotenv-1.2.2-py3-none-any.whl
│ │ └─ 📁 requests==2.34.2
│ │ ├─ 📦 certifi-2026.6.17-py3-none-any.whl
│ │ ├─ 📦 charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl
│ │ ├─ 📦 idna-3.18-py3-none-any.whl
│ │ ├─ 📦 requests-2.34.2-py3-none-any.whl
│ │ └─ 📦 urllib3-2.7.0-py3-none-any.whl
...
Пакеты скачались на все версии Python и распределились в каталоге resources. Транзитивные зависимости также подхватываются.
Я искренне надеюсь, что использование этого проекта ограничится потребностью развернуть проект там, где временно плохой интернет — например, у бабушки в деревне. Но всякое бывает, и лучше иметь и не нуждаться, чем нуждаться и не иметь.
- Хобби- и соло-разработчики
- Небольшие команды
- Все, кто не хочет поднимать промышленные серверные решения ради сохранения набора любимых библиотек
- 🐍 Скачивать Python — портативные сборки
с python-build-standalone через
getpybs - 🐍 Создавать виртуальные окружения на целевой машине:
init -pv 3.12 - 📦 Скачивать пакеты с PyPI и распределять их по версиям Python:
get fastapi uvicornилиget-from requirements.txt - 📦 Устанавливать пакеты в целевой проект
add fastapi uvicornилиadd passlib[argon2](работает сpyproject.toml) - 📦 Обновлять уже скачанные пакеты
updateа если добавить флагkeep, то старые версии будут удаляться, останется только указанное число последних версий не раздувая архив. - 🧹 Удалять пакеты из целевого проекта с очисткой зависимостей-сирот — аналог
uv remove, только полностью офлайн. Удаляет то, что больше не используется ни одним другим пакетом - 📖 Вести структурированный (машиночитаемый) лог о выполненных операциях корневая папка logs команда
folder, чтобы открыть корневую папку приложения. - 📂 Выводить дерево проекта и копировать контент в буфер обмена. Удобно для обзора проекта, и для чата с ИИ. Смотреть анимацию
PyOffline2 не обходит блокировки и не восстанавливает доступ к PyPI или python.org. Он лишь позволяет сохранить пакеты заранее, пока связь ещё есть — то есть «подстелить соломку» на случай возможных ограничений. Пока есть соединение с PyPi.org вы делаете свой чемоданчик судного дня.
PyOffline2 не конкурирует с uv, pip и другими инструментами. Он опирается на их сильные стороны и дополняет их,
адаптируя под конкретную задачу: работа без связи с pypi.org и python.org.
Для windows/linux качаются разные whl и python.
Переходим сразу к делу:
git clone https://github.com/Mike2024New/pyoffline2.git # Скачать репозиторий
cd Pyoffline2 # Перейти в папку с архивом
python -m venv .venv # Создать venv (! Папка должна называться .venv, минимальная версия 3.12)
.venv/Scripts/activate # Активировать виртуальное окружение:
python start.py # Запустить стартовый скрипт который скачает зависимости проекта.
python cli.py --help # Войти в интерфейс приложения.
# 7. Опционально: для получения исполняемого файла (bin/exe):
python cli.py build # сборка .exe
# * - откроется папка с собранным дистрибутивом, который можно прописать в системных переменныхПосле команды `python cli.py build`, откроется папка с проектом, и там будет файл `pyoff.exe`, прописать путь этой
к этой папке в переменных средах, например C:\Users\<ваше_имя>\Pyoffline2\releases\win\dist ** Перезагрузить терминал **.
# базовый кейс (после того как приложение было прописано в системных переменны):
pyoff get-python 3.10 # скачать портативный python в архив (один раз)
pyoff get fastapi, pydantic # скачать пакеты в архив (для всех python доступных в архиве)
mkdir my-project # создать папку проекта если её ещё нет
cd my-project # перейти в папку целевого проекта (здесь для примера такой путь, у вас своя папка)
pyoff init -pv 3.12 # инициализировать проект создав виртуальное окружение
.venv\Scripts\activate # войти в виртуальное окружение проекта (не обязательно)
pyoff project # посмотреть информацию о проекте
pyoff add fastapi, pydantic # установить пакеты в проект (были скачаны занее через pyoff get)
pyoff project # посмотреть информацию о проекте
pip list # проверка что пакеты реально установились
pyoff remove fastapi # Удаление fastapi с очисткой "сирот"
pyoff project # посмотреть информацию о проекте
pip list # проверка что fastapi удалился корректно, но pydantic не пострадал
pyoff remove-all # удаление всех пакетов проекта
pyoff tree -st # вывести дерево проекта в терминал (для копирования в буфер укажите флаг -cb)git clone https://github.com/Mike2024New/pyoffline2.git # Скачать репозиторий
cd Pyoffline2 # Перейти в папку с архивом
python3 -m venv .venv # Создать venv (! Папка должна называться .venv, минимальная версия 3.12)
source .venv/bin/activate # Активировать виртуальное окружение
python start.py # Запустить стартовый скрипт который скачает зависимости проекта.
python cli.py # Войти в интерфейс приложения.
python cli.py build # Опционально: для получения исполняемого файла (bin/exe)
# * - откроется папка с собранным дистрибутивом, который можно прописать в системных переменных- После команды
python cli.py build, откроется папка с проектом, и там будет файлpyoff.exe. - Узнать оболочку
echo $SHELL - Прописать папку с приложением в системных переменных PATH:
# Если оболочка `/bin/bash/`:
echo 'export PATH="$PATH:/home/mike/pyoff"' >> ~/.bashrc
source ~/.bashrc
# проверка что всё корректно
pyoff --help # Если оболочка `/bin/zsh/`:
echo 'export PATH="$PATH:/home/mike/pyoff"' >> ~/.zshrc
source ~/.zshrc
# проверка что всё корректно
pyoff --help # базовый кейс (после того как приложение было прописано в системных переменны):
pyoff get-python 3.10 # скачать портативный python в архив (один раз)
pyoff get fastapi, pydantic # скачать пакеты в архив (для всех python доступных в архиве)
mkdir my-project # создать папку проекта если её ещё нет
cd my-project # перейти в папку целевого проекта (здесь для примера такой путь, у вас своя папка)
pyoff init -pv 3.12 # инициализировать проект создав виртуальное окружение
source .venv/bin/activate # войти в виртуальное окружение проекта (не обязательно)
pyoff project # посмотреть информацию о проекте
pyoff add fastapi, pydantic # установить пакеты в проект (были скачаны занее через pyoff get)
pyoff project # посмотреть информацию о проекте
pip list # проверка что пакеты реально установились
pyoff remove fastapi # Удаление fastapi с очисткой "сирот"
pyoff project # посмотреть информацию о проекте
pip list # проверка что fastapi удалился корректно, но pydantic не пострадал
pyoff remove-all # удаление всех пакетов проекта
pyoff tree -st # вывести дерево проекта в терминал (для копирования в буфер укажите флаг -cb)
pyoff tree-cfg # открыть папку с файлами конфигурации где в `hidden.json` можно указать пропускаемые папки и файлы с учётом частичного включения '*'Команды приложения (в режиме разработки python cli.py <command>, например python cli.py show:
show— просмотр доступных версий Python и пакетов.get python-dotenv— скачать пакет для всех версий Python в архиве.get-from requirements.txt— скачать список пакетов из файла.get-python 3.12— скачать портативный Python-standalone в архив.update -k 3— получить latest версии всех пакетов,-kудалить все неактуальные кроме 3 последних версий.init -pv 3.12— создать проект с виртуальным окружением.init -pv 3.12 -rp— пересоздать проект.add python-dotenv— установить пакет в целевой проектremove python-dotenv— удалить пакет с очисткой сиротremove-all— удалить все пакеты из проектаproject- показать информацию о проекте (версия python, зависимости)sync- установить все пакеты изpyproject.tomlцелевого проектаfolder— открыть папку приложенияrun-tests— запустить тесты (только из кода, до сборки)build— собрать исполняемый файл (только из кода, до сборки)tree— вывести дерево проекта в терминал, (добавить флаги -sc - показать контент, или -cb копировать в буфер обмена)tree-cfg— открыть папку с файлами конфигурации где вhidden.jsonможно указать пропускаемые папки и файлы с учётом частичного включения '*'
Единственное, что вам нужно решить — где будет лежать папка resources. Это может быть:
- Внешний SSD или флешка (берите с собой в поездки)
- Общая сетевая папка в офисе (для всей команды)
- Облачный диск (всё равно не понадобится интернет для установки, только для пополнения)
Никаких настроек серверов, баз данных и Docker-контейнеров.
02.07.2026 - v0.2.1
- Добавлена обработка ошибки копирования в буфер (команда tree) для linux.
02.07.2026 - v0.2.0
- Добавлена команда вывода дерева проекта и контента в консоль и копирования в буфер обмена Смотреть анимацию. Пример дерева (этого проекта):
Details
```text 📁 PyOffline2 ├─ 📁 .git [содержимое скрыто] ├─ 📁 .idea [содержимое скрыто] ├─ 📁 .pytest_cache [содержимое скрыто] ├─ 📁 .venv [содержимое скрыто] ├─ 📁 __pycache__ [содержимое скрыто] ├─ 📁 config │ ├─ 📁 __pycache__ [содержимое скрыто] │ ├─ 🐍 __init__.py │ └─ 🐍 schemas.py ├─ 📁 docs │ ├─ 📁 assets │ │ ├─ 🖼️ installing.gif │ │ ├─ 🖼️ linux_installing.gif │ │ ├─ 🖼️ linux_use_case.gif │ │ ├─ 🖼️ linux_variable_path.gif │ │ ├─ 🖼️ path_variables.gif │ │ └─ 🖼️ use_case.gif │ ├─ 📝 habr_public.md │ ├─ 📝 linux_install.md │ ├─ 📝 linux_use_case.md │ ├─ 📝 linux_variable_path.md │ ├─ 📝 win_install.md │ ├─ 📝 win_use_case.md │ └─ 📝 win_variable_path.md ├─ 📁 functions │ ├─ 📁 __pycache__ [содержимое скрыто] │ ├─ 🐍 __init__.py │ ├─ 🐍 get_orphan_deps.py │ ├─ 🐍 packages_fn.py │ ├─ 🐍 python_fn.py │ └─ 🐍 toml_manager.py ├─ 📁 layers │ ├─ 📁 __pycache__ [содержимое скрыто] │ ├─ 📁 archive_manager │ │ ├─ 📁 __pycache__ [содержимое скрыто] │ │ ├─ 🐍 __init__.py │ │ ├─ 🐍 helper.py │ │ └─ 🐍 main.py │ ├─ 📁 directory_walker │ │ ├─ 📁 __pycache__ [содержимое скрыто] │ │ ├─ 🐍 __init__.py │ │ └─ 🐍 main.py │ ├─ 📁 pack_installer │ │ ├─ 📁 __pycache__ [содержимое скрыто] │ │ ├─ 🐍 __init__.py │ │ └─ 🐍 main.py │ ├─ 📁 python_manager │ │ ├─ 📁 __pycache__ [содержимое скрыто] │ │ ├─ 🐍 __init__.py │ │ ├─ 🐍 main.py │ │ └─ 🐍 start.py │ └─ 🐍 __init__.py ├─ 📁 logs [содержимое скрыто] ├─ 📁 python_embed [содержимое скрыто] ├─ 📁 releases [содержимое скрыто] ├─ 📁 resources │ ├─ 📁 packages_storage │ │ └─ 📁 windows-x86_64 │ │ ├─ 📁 3.10 │ │ │ ├─ 📁 fastapi==0.139.0 │ │ │ │ ├─ 📄 annotated_doc-0.0.4-py3-none-any.whl │ │ │ │ ├─ 📄 annotated_types-0.7.0-py3-none-any.whl │ │ │ │ ├─ 📄 anyio-4.14.1-py3-none-any.whl │ │ │ │ ├─ 📄 exceptiongroup-1.3.1-py3-none-any.whl │ │ │ │ ├─ 📄 fastapi-0.139.0-py3-none-any.whl │ │ │ │ ├─ 📄 idna-3.18-py3-none-any.whl │ │ │ │ ├─ 📄 pydantic-2.13.4-py3-none-any.whl │ │ │ │ ├─ 📄 pydantic_core-2.46.4-cp310-cp310-win_amd64.whl │ │ │ │ ├─ 📄 starlette-1.3.1-py3-none-any.whl │ │ │ │ ├─ 📄 typing_extensions-4.16.0-py3-none-any.whl │ │ │ │ └─ 📄 typing_inspection-0.4.2-py3-none-any.whl │ │ │ ├─ 📁 python_dotenv==1.2.2 │ │ │ │ └─ 📄 python_dotenv-1.2.2-py3-none-any.whl │ │ │ ├─ 📁 requests==2.34.2 │ │ │ │ ├─ 📄 certifi-2026.6.17-py3-none-any.whl │ │ │ │ ├─ 📄 charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl │ │ │ │ ├─ 📄 idna-3.18-py3-none-any.whl │ │ │ │ ├─ 📄 requests-2.34.2-py3-none-any.whl │ │ │ │ └─ 📄 urllib3-2.7.0-py3-none-any.whl │ │ │ └─ 📁 uvicorn==0.49.0 │ │ │ ├─ 📄 click-8.4.2-py3-none-any.whl │ │ │ ├─ 📄 colorama-0.4.6-py2.py3-none-any.whl │ │ │ ├─ 📄 h11-0.16.0-py3-none-any.whl │ │ │ ├─ 📄 typing_extensions-4.16.0-py3-none-any.whl │ │ │ └─ 📄 uvicorn-0.49.0-py3-none-any.whl │ │ ├─ 📁 3.12 │ │ │ ├─ 📁 fastapi==0.139.0 │ │ │ │ ├─ 📄 annotated_doc-0.0.4-py3-none-any.whl │ │ │ │ ├─ 📄 annotated_types-0.7.0-py3-none-any.whl │ │ │ │ ├─ 📄 anyio-4.14.1-py3-none-any.whl │ │ │ │ ├─ 📄 fastapi-0.139.0-py3-none-any.whl │ │ │ │ ├─ 📄 idna-3.18-py3-none-any.whl │ │ │ │ ├─ 📄 pydantic-2.13.4-py3-none-any.whl │ │ │ │ ├─ 📄 pydantic_core-2.46.4-cp312-cp312-win_amd64.whl │ │ │ │ ├─ 📄 starlette-1.3.1-py3-none-any.whl │ │ │ │ ├─ 📄 typing_extensions-4.16.0-py3-none-any.whl │ │ │ │ └─ 📄 typing_inspection-0.4.2-py3-none-any.whl │ │ │ ├─ 📁 python_dotenv==1.2.2 │ │ │ │ └─ 📄 python_dotenv-1.2.2-py3-none-any.whl │ │ │ ├─ 📁 requests==2.34.2 │ │ │ │ ├─ 📄 certifi-2026.6.17-py3-none-any.whl │ │ │ │ ├─ 📄 charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl │ │ │ │ ├─ 📄 idna-3.18-py3-none-any.whl │ │ │ │ ├─ 📄 requests-2.34.2-py3-none-any.whl │ │ │ │ └─ 📄 urllib3-2.7.0-py3-none-any.whl │ │ │ └─ 📁 uvicorn==0.49.0 │ │ │ ├─ 📄 click-8.4.2-py3-none-any.whl │ │ │ ├─ 📄 colorama-0.4.6-py2.py3-none-any.whl │ │ │ ├─ 📄 h11-0.16.0-py3-none-any.whl │ │ │ └─ 📄 uvicorn-0.49.0-py3-none-any.whl │ │ └─ 📁 3.14 │ │ ├─ 📁 fastapi==0.139.0 │ │ │ ├─ 📄 annotated_doc-0.0.4-py3-none-any.whl │ │ │ ├─ 📄 annotated_types-0.7.0-py3-none-any.whl │ │ │ ├─ 📄 anyio-4.14.1-py3-none-any.whl │ │ │ ├─ 📄 fastapi-0.139.0-py3-none-any.whl │ │ │ ├─ 📄 idna-3.18-py3-none-any.whl │ │ │ ├─ 📄 pydantic-2.13.4-py3-none-any.whl │ │ │ ├─ 📄 pydantic_core-2.46.4-cp314-cp314-win_amd64.whl │ │ │ ├─ 📄 starlette-1.3.1-py3-none-any.whl │ │ │ ├─ 📄 typing_extensions-4.16.0-py3-none-any.whl │ │ │ └─ 📄 typing_inspection-0.4.2-py3-none-any.whl │ │ ├─ 📁 python_dotenv==1.2.2 │ │ │ └─ 📄 python_dotenv-1.2.2-py3-none-any.whl │ │ ├─ 📁 requests==2.34.2 │ │ │ ├─ 📄 certifi-2026.6.17-py3-none-any.whl │ │ │ ├─ 📄 charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl │ │ │ ├─ 📄 idna-3.18-py3-none-any.whl │ │ │ ├─ 📄 requests-2.34.2-py3-none-any.whl │ │ │ └─ 📄 urllib3-2.7.0-py3-none-any.whl │ │ └─ 📁 uvicorn==0.49.0 │ │ ├─ 📄 click-8.4.2-py3-none-any.whl │ │ ├─ 📄 colorama-0.4.6-py2.py3-none-any.whl │ │ ├─ 📄 h11-0.16.0-py3-none-any.whl │ │ └─ 📄 uvicorn-0.49.0-py3-none-any.whl │ └─ 📁 python_storage │ └─ 📁 windows-x86_64 │ ├─ 📁 3.10 │ │ └─ 📁 python [содержимое скрыто] │ ├─ 📁 3.12 │ │ └─ 📁 python [содержимое скрыто] │ └─ 📁 3.14 │ └─ 📁 python [содержимое скрыто] ├─ 📁 tests │ ├─ 📁 __pycache__ [содержимое скрыто] │ ├─ 🐍 test_archive_packages.py │ ├─ 🐍 test_init_project.py │ └─ 🐍 test_python.py ├─ 📁 tree_cfg │ ├─ 📄 hidden.json │ └─ 📄 icons.json ├─ 🔒 .gitignore ├─ 📄 .python-version ├─ 🐍 build.py ├─ 🐍 cli.py ├─ 🐍 helper.py ├─ 📄 LICENSE ├─ 📄 pyproject.toml ├─ 📝 README.md ├─ 🐍 start.py └─ 📄 todo.txt ```MIT. Подробнее в файле LICENSE.
- Проект использует утилиты из репозитория infrastructure.
- Протестировано на windows10, linux ubuntu/mint.
- Любая обратная связь приветствуется.
"Если пользователь не понял — я объяснил плохо. Значит, мне нужно переписать документацию, добавить примеры, улучшить сообщения об ошибках."