MicroPython:Основы/Язык MicroPython и его реализация/Дистрибутивы, управление пакетами и развертка приложений: различия между версиями
Myagkij (обсуждение | вклад) (Новая страница: «{{MicroPython/Панель перехода}} {{Перевод от Сubewriter}} {{Myagkij-редактор}} <syntaxhighlight lang="python" enclose="div"> =...») |
Нет описания правки |
||
(не показаны 4 промежуточные версии 1 участника) | |||
Строка 3: | Строка 3: | ||
{{Myagkij-редактор}} | {{Myagkij-редактор}} | ||
=Дистрибутивы, управление пакетами и развертка приложений<ref>[http://docs.micropython.org/en/latest/reference/packages.html docs.micropython.org - Distribution packages, package management, and deploying applications]</ref>= | |||
Как и в ''«старшем»'' [[Python]], в [[MicroPython]] можно создавать ''«сторонние»'' пакеты, распространять их и легко устанавливать на платформу каждого пользователя. Здесь рассказывается, как все это делать, но подразумевается, что у вас уже есть некоторые знания о работе с пакетами в [[Python]]. | |||
<syntaxhighlight lang="python" | Процесс создания и использования пакетов включает в себя следующие этапы: | ||
# Модули и пакеты [[Python]] преобразовываются в дистрибутивные пакеты-архивы и публикуются в каталоге [[Python Package Index]] (''«каталог пакетов Python»'') или [[PyPI]]. | |||
# Для установки дистрибутивного пакета (дистрибутива) в [[MicroPython-порт]], у которого есть средства для выхода в сеть (например, [[Unix]]), можно воспользоваться менеджером пакетов [[upip]]. | |||
# Для установки дистрибутива в [[MicroPython-порт]], у которого нет средства для выхода в сеть, можно сначала подготовить ''«установочный образ»'' на [[Unix-порт]]е, а затем с помощью подходящих коммуникационных средств передать его на устройство. | |||
# Если речь об устройства с ограниченной памятью, установочный образ можно заморозить как [[байт-код]] в прошивку [[MicroPython]], что позволит минимизировать требования к памяти. | |||
Ниже все эти шаги описаны более подробно. | |||
== Распространение пакетов == | |||
Модули и пакеты [[Python]] можно упаковать в архивы, которые затем можно передавать из одной системы в другую, сохранять в общеизвестном хранилище ([[PyPl]]) и при необходимости оттуда их скачивать (чтобы потом установить). Эти архивы также называются ''«дистрибутивами»'' (что отличает их от Python-пакетов, предназначенных для организации исходного кода [[Python]]). | |||
Форматом для дистрибутива [[MicroPython]] является широко известный ''«tar.gz»'', но с некоторыми адаптациями. В компрессоре [[GZIP]] для работы с [[TAR-архив]]ами используется внешняя утилита, которая по умолчанию использует размер словаря в ''32 Кб'', и это значит, что при распаковке сжатого потокового объекта понадобятся смежные участки памяти общим размером в ''32 Кб''. На устройствах с ограниченной памятью такой вариант может быть неприемлем, потому что вся их память может быть меньше, чем эти ''32 Кб'', но даже если больше, из-за фрагментации такой большой блок смежных участков памяти, возможно, найти будет трудно. Для решения этой проблемы в дистрибутивах [[MicroPython]] используется [[GZIP-сжатие]] с размером словаря в ''4 Кб'', что создает приемлемый компромисс между возможностью более-менее сжать данные и возможностью распаковать их даже на самых маленьких устройствах. | |||
Помимо маленького размера словаря при сжатии, в дистрибутивах [[MicroPython]] есть и другие оптимизационные функции – вроде удаления из архива всех файлов, не используемых в процессе установки. В частности, во время установки менеджер пакетов [[upip]] не выполняет файл ''«setup.py»'' (см. выше), и поэтому этот файл в архив добавлен не будет. | |||
В то же время эти оптимизационные меры делают дистрибутивы [[MicroPython]] не совместимыми с пакетным менеджером [[CPython]] – [[pip]]. Но это не такая уж большая проблема, потому что пакеты можно установить с помощью [[upip]], а потом использовать с помощью [[CPython]] (если они совместимы). С другой стороны, большинство пакетов [[CPython]] по разным причинам не совместимы с [[MicroPython]], в первую очередь – потому что полагаются на функции, которые не реализованы в [[MicroPython]]. | |||
Итак, если вкратце, дистрибутивы-архивы [[MicroPython]] хорошо оптимизированы под целевые платформы [[MicroPython]], коими являются устройства с ограниченными ресурсами. | |||
== Менеджер пакетов upip == | |||
Дистрибутивы [[MicroPython]] необходимо устанавливать с помощью менеджера пакетов [[upip]]. Это [[Python]]-приложение, которое обычно распространяется (в виде замороженного [[байт-код]]а) вместе с портами [[MicroPython]], имеющими средства для работы с сетью. Менеджер пакетов [[upip]] доступен как минимум на порте [[MicroPython]] [[Unix]]. | |||
На любом [[MicroPython-порт]]е, где есть [[upip]], доступ к нему можно получить следующим образом: | |||
<syntaxhighlight lang="python"> | |||
import upip | |||
upip.help() | |||
upip.install(package_or_package_list, [path]) | |||
</syntaxhighlight> | |||
Здесь ''package_or_package_list'' – это название дистрибутива или список с названиями дистрибутивов, которые нужно установить. В опциональном параметре ''path'' указывается место в файловой системе, куда его/их надо установить. По умолчанию установка выполняется в стандартную директорию с библиотеками (см. ниже). | |||
Ниже – пример установки пакета и его последующего использования: | |||
<syntaxhighlight lang="python"> | |||
>>> import upip | |||
>>> upip.install("micropython-pystone_lowmem") | |||
[...] | |||
>>> import pystone_lowmem | |||
>>> pystone_lowmem.main() | |||
</syntaxhighlight> | |||
Обратите внимание, что названия [[Python-пакет]]а и дистрибутива, как правило, совпадать не должны, и зачастую действительно не совпадают. Дело в том, что [[PyPI]] – это центральный репозиторий пакетов для всего разнообразия реализаций и версий Python, и поэтому ваш дистрибутив, возможно, надо будет поместить в пространство имен конкретной реализации. К примеру, названия всех пакетов в ''«micropython-lib»'' следуют следующему правилу: если модуль или пакет [[Python]] назван foo, то его дистрибутив будет называться ''micropython-foo''. | |||
В портах, где прошивка [[MicroPython]] запускается из командной оболочки [[ОС]] (вроде [[Unix-порт]]а), [[upip]] можно запустить (и обычно именно так он и запускается) именно оттуда, а не из [[MicroPython]]’овского терминала [[REPL]]. Вот команды, соответствующие фрагменту выше: | |||
<syntaxhighlight lang="python"> | |||
micropython -m upip -h | |||
micropython -m upip install [-p <path>] <packages>... | |||
micropython -m upip install micropython-pystone_lowmem | |||
</syntaxhighlight> | |||
== Кросс-установка пакетов == | |||
Для [[MicroPython-порт]]ов, не имеющих средства для работы с сетью, рекомендуется ''«кросс-установить»'' их в ''«установочный образ»'' при помощи порта [[MicroPython]] [[Unix]], а затем передать этот образ на устройство с помощью подходящих коммуникационных средств. | |||
Для установки в установочный образ в [[upip]] нужно воспользоваться переключателем ''-p'': | |||
<syntaxhighlight lang="python"> | |||
micropython -m upip install -p install_dir micropython-pystone_lowmem | |||
</syntaxhighlight> | |||
После того, как эта команда будет выполнена, содержимое пакета (и всех зависимых пакетов) можно будет найти в поддиректории ''install_dir/''. Вам нужно будет отправить содержимое этой директории (без префикса ''install_dir/'') на необходимое место в устройстве – туда, где его сможет найти [[Python-оператор]] [[import]] (см. раздел «[http://wikihandbk.com/wiki/MicroPython:%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B/%D0%AF%D0%B7%D1%8B%D0%BA_MicroPython_%D0%B8_%D0%B5%D0%B3%D0%BE_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F/%D0%94%D0%B8%D1%81%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%B8%D0%B2%D1%8B,_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%B0%D0%BA%D0%B5%D1%82%D0%B0%D0%BC%D0%B8_%D0%B8_%D1%80%D0%B0%D0%B7%D0%B2%D0%B5%D1%80%D1%82%D0%BA%D0%B0_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9#.D0.9C.D0.B5.D0.BD.D0.B5.D0.B4.D0.B6.D0.B5.D1.80_.D0.BF.D0.B0.D0.BA.D0.B5.D1.82.D0.BE.D0.B2_upip Менеджер пакетов upip]» выше). | |||
== Кросс-установка пакетов с заморозкой == | |||
Для устройств с ограниченной памятью вариант установки в предыдущем разделе не слишком эффективен с точки зрения использования памяти, потому что в нем пакеты устанавливаются в виде исходного кода, поэтому при каждом импорте их надо будет компилировать в [[байт-код]]. Эта компиляция требует [[RAM-памяти]], и получившийся [[байт-код]] тоже будет храниться в RAM-памяти, что уменьшит количество памяти для хранения данных приложения. Более того, процесс установки выше требует наличия файловой системы на устройстве, а у большинства устройств с ограниченной памятью ее может даже не быть. | |||
Заморозка байт-кода – это процесс, позволяющий решить все описанные выше проблемы, потому что: | |||
* Исходный код предкомпилируется в байт-код и будет сохранен в таком виде | |||
* Байт-код хранится в ROM-, а не в RAM-памяти | |||
* Замороженным пакетам файловая система не нужна | |||
Использование замороженного байт-кода требует создания прошивки MicroPython-порта из исходного кода на [[Си]]. Соответственно, процесс будет таким: | |||
# Следуйте инструкциям для своей платформы по настройке тулчейна и сборке порта. К примеру, инструкции для [[ESP8266-порт]]а находятся в ''«ports/esp8266/README.md»''. Перед тем, как приступать к следующим шагам, убедитесь, что сборка порта и установка получившейся прошивки прошли успешно. | |||
# Соберите порт [[MicroPython]] [[Unix]], и убедитесь, что он находится в ''PATH'', а затем выполните ''micropython''. | |||
# Переключитесь на директорию порта (например, у [[ESP8266]] это ''«ports/esp8266/»''). | |||
# Запустите ''make clean-frozen''. Это удалит все предыдущие модули, которые были установлены для заморозки (если вы хотите добавить новые модули, этот шаг надо пропустить, чтобы не начинать с нуля). | |||
# Запустите ''micropython -m upip install -p modules <пакеты>...'', чтобы установить пакеты, которые вы хотите заморозить. | |||
# Запустите ''make clean''. | |||
# Запустите ''make''. | |||
После этого вы должны получить прошивку, внутри которой будут модули в виде замороженного [[байт-код]]а, которую можно устанавливать как обычно. | |||
Пара примечаний: | |||
# Шаг 5 в инструкции выше подразумевает, что используемый дистрибутив есть в каталоге [[PyPI]]. Если его там нет, вам надо будет вручную скопировать файлы исходного кода [[Python]] в поддиректорию ''«modules/»'' в директории порта. (Учтите, что [[upip]] не поддерживает установку из репозиториев системы управления версиями). | |||
# У прошивки для ''«голого железа»'' обычно имеются ограничения по размеру, поэтому слишком большое количество замороженных модулей может ее переполнить. Обычно в таком случае выдается ошибка связывания. Но иногда сгенерированный образ запустить не получается – это типовой баг, о нем нужно сообщить разработчикам, чтобы они разобрались в чем дело. Если вы столкнулись с такой проблемой, первым делом можно попробовать уменьшить количество замороженных модулей в прошивке. | |||
== Создание дистрибутивов == | |||
Дистрибутивы для [[MicroPython]] создаются также, как и для [[CPython]] и любой другой реализации [[Python]] (более подробно см. в ссылках в конце статьи). Вместо ''distutils'' необходимо использовать ''setuptools'', потому что в ''distutils'' не поддерживаются зависимости и другие функции. Для упаковки используется формат ''sdist'' (от англ. ''«source distribution»''). Постобработка, о которой рассказывалось выше (и предобработка, о которой будет рассказано в следующем разделе) выполняется при помощи модифицированной ''setuptools''-команды ''sdist''. То есть упаковка будет работать, как и у стандартного ''setuptools'', но пользователю лишь нужно переопределить команду ''sdist'', вставив в ''setup()'' вот такой аргумент: | |||
<syntaxhighlight lang="python"> | |||
from setuptools import setup | |||
import sdist_upip | |||
setup( | |||
..., | |||
cmdclass={'sdist': sdist_upip.sdist} | |||
) | |||
</syntaxhighlight> | |||
Модуль ''sdist_upip.py'' из фрагмента выше можно найти в [https://github.com/micropython/micropython-lib/blob/master/sdist_upip.py micropython-lib]. | |||
== Ресурсы приложения == | |||
Помимо исходного кода, в готовом приложении также часто содержатся файлы данных: шаблоны веб-страниц, изображения и т.д. Понятно, как работать с ними, если приложение установлено вручную – вы просто помещаете эти данные в какое-то место файловой системы, а затем используете обычные функции для доступа к данным. | |||
Но все меняется, когда приложение устанавливается из пакета. Это более продвинутый, простой и гибкий способ установки, но в этом случае вам также нужно воспользоваться более продвинутым методом для доступа к файлам данных. Он заключается в том, чтобы относиться к этим файлам данных как к «ресурсам» и сделать парочку дополнительных манипуляций. | |||
В Python доступ к ресурсам поддерживается с помощью модуля ''pkg_resources'' из библиотеки ''«setuptools»''. [[MicroPython]] тоже частично поддерживает функционал этого модуля – в частности, за это отвечает функция ''pkg_resources.resource_stream(пакет, ресурс)''. Идея в том, что приложение может вызвать эту функцию и задать в ней аргументом идентификатор нужного ресурса – это будет относительный путь к файлу данных внутри заданного пакета (как правило, пакета приложения высокого уровня). Она вернет потоковый объект, который можно использовать для доступа к содержимому ресурсов. Таким образом, функция ''resource_stream()'' эмулирует интерфейс стандартной функции ''open()''. | |||
Если пакет установлен в файловую систему, то ''resourse_stream()'' будет использовать файловые операции. Но эта функция может работать и без файловой системы – например, если пакет заморожен в виде [[байт-код]]а. Это, однако, требует дополнительного этапа при упаковке приложения – создания ''«ресурсного Python-модуля»''. | |||
Идея этого модуля в том, чтобы преобразовать двоичные данные в [[Python-объект]] [[bytes]], а затем поместить его в словарь, данные в котором будут упорядочены по названиям ресурсов. Это преобразование выполняется автоматически при помощи переопределенной команды ''sdist'', описанной в предыдущем разделе. | |||
Теперь давайте рассмотрим всё это с помощью наглядного примера. Допустим, ваше приложение имеет следующую структуру: | |||
<syntaxhighlight lang="python"> | |||
my_app/ | |||
__main__.py | |||
utils.py | |||
data/ | |||
page.html | |||
image.png | |||
</syntaxhighlight> | |||
Файлы ''«__main__.py»'' и ''«utils.py»'' получают доступ к ресурсам с помощью вот этих функций: | |||
<syntaxhighlight lang="python"> | |||
import pkg_resources | |||
pkg_resources.resource_stream(__name__, "data/page.html") | |||
pkg_resources.resource_stream(__name__, "data/image.png") | |||
</syntaxhighlight> | |||
Вы можете как обычно разрабатывать и делать отладку приложения на порте [[MicroPython]] [[Unix]]. Когда наступит время делать из него дистрибутив, просто воспользуйтесь переопределенной командой ''sdist'' из модуля ''sdist_upip'', как описывалось в разделе выше. | |||
Это создаст ресурсный [[Python-модуль]] под названием ''R.py'' на основе файлов, объявленных в файлах ''MANIFEST'' и ''MANIFEST.in'' (любой файл без ''«[[*.py]]»'' будет считаться ресурсом и добавлен в ''R.py'') – перед тем, как приступить к обычным этапам упаковки. | |||
Если подготовить приложение таким образом, оно будет работать и в виде замороженного [[байт-код]]а, и будучи установленным в файловую систему. | |||
Чтобы начать отладку создания ''R.py'', запустите следующее: | |||
<syntaxhighlight lang="python"> | |||
python3 setup.py sdist --manifest-only | |||
</syntaxhighlight> | |||
В качестве альтернативы можно воспользоваться скриптом ''«tools/mpy_bin2res.py»'' из дистрибутива [[MicroPython]] – в этом случае вам нужно будет также указать пути ко всем файлам ресурсов: | |||
<syntaxhighlight lang="python"> | |||
mpy_bin2res.py data/page.html data/image.png | |||
</syntaxhighlight> | |||
==Ссылки== | |||
* [https://packaging.python.org/ Руководство по упаковке в Python] | |||
* [https://setuptools.readthedocs.io/en/latest/ Документация поsetuptools] | |||
* [https://docs.python.org/3/library/distutils.html Документация по distutils] | |||
=См.также= | =См.также= | ||
{{ads}} | |||
=Внешние ссылки= | =Внешние ссылки= | ||
<references /> | <references /> |
Текущая версия от 18:17, 14 мая 2023
Дистрибутивы, управление пакетами и развертка приложений[1]
Как и в «старшем» Python, в MicroPython можно создавать «сторонние» пакеты, распространять их и легко устанавливать на платформу каждого пользователя. Здесь рассказывается, как все это делать, но подразумевается, что у вас уже есть некоторые знания о работе с пакетами в Python.
Процесс создания и использования пакетов включает в себя следующие этапы:
- Модули и пакеты Python преобразовываются в дистрибутивные пакеты-архивы и публикуются в каталоге Python Package Index («каталог пакетов Python») или PyPI.
- Для установки дистрибутивного пакета (дистрибутива) в MicroPython-порт, у которого есть средства для выхода в сеть (например, Unix), можно воспользоваться менеджером пакетов upip.
- Для установки дистрибутива в MicroPython-порт, у которого нет средства для выхода в сеть, можно сначала подготовить «установочный образ» на Unix-порте, а затем с помощью подходящих коммуникационных средств передать его на устройство.
- Если речь об устройства с ограниченной памятью, установочный образ можно заморозить как байт-код в прошивку MicroPython, что позволит минимизировать требования к памяти.
Ниже все эти шаги описаны более подробно.
Распространение пакетов
Модули и пакеты Python можно упаковать в архивы, которые затем можно передавать из одной системы в другую, сохранять в общеизвестном хранилище (PyPl) и при необходимости оттуда их скачивать (чтобы потом установить). Эти архивы также называются «дистрибутивами» (что отличает их от Python-пакетов, предназначенных для организации исходного кода Python).
Форматом для дистрибутива MicroPython является широко известный «tar.gz», но с некоторыми адаптациями. В компрессоре GZIP для работы с TAR-архивами используется внешняя утилита, которая по умолчанию использует размер словаря в 32 Кб, и это значит, что при распаковке сжатого потокового объекта понадобятся смежные участки памяти общим размером в 32 Кб. На устройствах с ограниченной памятью такой вариант может быть неприемлем, потому что вся их память может быть меньше, чем эти 32 Кб, но даже если больше, из-за фрагментации такой большой блок смежных участков памяти, возможно, найти будет трудно. Для решения этой проблемы в дистрибутивах MicroPython используется GZIP-сжатие с размером словаря в 4 Кб, что создает приемлемый компромисс между возможностью более-менее сжать данные и возможностью распаковать их даже на самых маленьких устройствах.
Помимо маленького размера словаря при сжатии, в дистрибутивах MicroPython есть и другие оптимизационные функции – вроде удаления из архива всех файлов, не используемых в процессе установки. В частности, во время установки менеджер пакетов upip не выполняет файл «setup.py» (см. выше), и поэтому этот файл в архив добавлен не будет.
В то же время эти оптимизационные меры делают дистрибутивы MicroPython не совместимыми с пакетным менеджером CPython – pip. Но это не такая уж большая проблема, потому что пакеты можно установить с помощью upip, а потом использовать с помощью CPython (если они совместимы). С другой стороны, большинство пакетов CPython по разным причинам не совместимы с MicroPython, в первую очередь – потому что полагаются на функции, которые не реализованы в MicroPython.
Итак, если вкратце, дистрибутивы-архивы MicroPython хорошо оптимизированы под целевые платформы MicroPython, коими являются устройства с ограниченными ресурсами.
Менеджер пакетов upip
Дистрибутивы MicroPython необходимо устанавливать с помощью менеджера пакетов upip. Это Python-приложение, которое обычно распространяется (в виде замороженного байт-кода) вместе с портами MicroPython, имеющими средства для работы с сетью. Менеджер пакетов upip доступен как минимум на порте MicroPython Unix.
На любом MicroPython-порте, где есть upip, доступ к нему можно получить следующим образом:
import upip
upip.help()
upip.install(package_or_package_list, [path])
Здесь package_or_package_list – это название дистрибутива или список с названиями дистрибутивов, которые нужно установить. В опциональном параметре path указывается место в файловой системе, куда его/их надо установить. По умолчанию установка выполняется в стандартную директорию с библиотеками (см. ниже).
Ниже – пример установки пакета и его последующего использования:
>>> import upip
>>> upip.install("micropython-pystone_lowmem")
[...]
>>> import pystone_lowmem
>>> pystone_lowmem.main()
Обратите внимание, что названия Python-пакета и дистрибутива, как правило, совпадать не должны, и зачастую действительно не совпадают. Дело в том, что PyPI – это центральный репозиторий пакетов для всего разнообразия реализаций и версий Python, и поэтому ваш дистрибутив, возможно, надо будет поместить в пространство имен конкретной реализации. К примеру, названия всех пакетов в «micropython-lib» следуют следующему правилу: если модуль или пакет Python назван foo, то его дистрибутив будет называться micropython-foo.
В портах, где прошивка MicroPython запускается из командной оболочки ОС (вроде Unix-порта), upip можно запустить (и обычно именно так он и запускается) именно оттуда, а не из MicroPython’овского терминала REPL. Вот команды, соответствующие фрагменту выше:
micropython -m upip -h
micropython -m upip install [-p <path>] <packages>...
micropython -m upip install micropython-pystone_lowmem
Кросс-установка пакетов
Для MicroPython-портов, не имеющих средства для работы с сетью, рекомендуется «кросс-установить» их в «установочный образ» при помощи порта MicroPython Unix, а затем передать этот образ на устройство с помощью подходящих коммуникационных средств.
Для установки в установочный образ в upip нужно воспользоваться переключателем -p:
micropython -m upip install -p install_dir micropython-pystone_lowmem
После того, как эта команда будет выполнена, содержимое пакета (и всех зависимых пакетов) можно будет найти в поддиректории install_dir/. Вам нужно будет отправить содержимое этой директории (без префикса install_dir/) на необходимое место в устройстве – туда, где его сможет найти Python-оператор import (см. раздел «Менеджер пакетов upip» выше).
Кросс-установка пакетов с заморозкой
Для устройств с ограниченной памятью вариант установки в предыдущем разделе не слишком эффективен с точки зрения использования памяти, потому что в нем пакеты устанавливаются в виде исходного кода, поэтому при каждом импорте их надо будет компилировать в байт-код. Эта компиляция требует RAM-памяти, и получившийся байт-код тоже будет храниться в RAM-памяти, что уменьшит количество памяти для хранения данных приложения. Более того, процесс установки выше требует наличия файловой системы на устройстве, а у большинства устройств с ограниченной памятью ее может даже не быть.
Заморозка байт-кода – это процесс, позволяющий решить все описанные выше проблемы, потому что:
- Исходный код предкомпилируется в байт-код и будет сохранен в таком виде
- Байт-код хранится в ROM-, а не в RAM-памяти
- Замороженным пакетам файловая система не нужна
Использование замороженного байт-кода требует создания прошивки MicroPython-порта из исходного кода на Си. Соответственно, процесс будет таким:
- Следуйте инструкциям для своей платформы по настройке тулчейна и сборке порта. К примеру, инструкции для ESP8266-порта находятся в «ports/esp8266/README.md». Перед тем, как приступать к следующим шагам, убедитесь, что сборка порта и установка получившейся прошивки прошли успешно.
- Соберите порт MicroPython Unix, и убедитесь, что он находится в PATH, а затем выполните micropython.
- Переключитесь на директорию порта (например, у ESP8266 это «ports/esp8266/»).
- Запустите make clean-frozen. Это удалит все предыдущие модули, которые были установлены для заморозки (если вы хотите добавить новые модули, этот шаг надо пропустить, чтобы не начинать с нуля).
- Запустите micropython -m upip install -p modules <пакеты>..., чтобы установить пакеты, которые вы хотите заморозить.
- Запустите make clean.
- Запустите make.
После этого вы должны получить прошивку, внутри которой будут модули в виде замороженного байт-кода, которую можно устанавливать как обычно. Пара примечаний:
- Шаг 5 в инструкции выше подразумевает, что используемый дистрибутив есть в каталоге PyPI. Если его там нет, вам надо будет вручную скопировать файлы исходного кода Python в поддиректорию «modules/» в директории порта. (Учтите, что upip не поддерживает установку из репозиториев системы управления версиями).
- У прошивки для «голого железа» обычно имеются ограничения по размеру, поэтому слишком большое количество замороженных модулей может ее переполнить. Обычно в таком случае выдается ошибка связывания. Но иногда сгенерированный образ запустить не получается – это типовой баг, о нем нужно сообщить разработчикам, чтобы они разобрались в чем дело. Если вы столкнулись с такой проблемой, первым делом можно попробовать уменьшить количество замороженных модулей в прошивке.
Создание дистрибутивов
Дистрибутивы для MicroPython создаются также, как и для CPython и любой другой реализации Python (более подробно см. в ссылках в конце статьи). Вместо distutils необходимо использовать setuptools, потому что в distutils не поддерживаются зависимости и другие функции. Для упаковки используется формат sdist (от англ. «source distribution»). Постобработка, о которой рассказывалось выше (и предобработка, о которой будет рассказано в следующем разделе) выполняется при помощи модифицированной setuptools-команды sdist. То есть упаковка будет работать, как и у стандартного setuptools, но пользователю лишь нужно переопределить команду sdist, вставив в setup() вот такой аргумент:
from setuptools import setup
import sdist_upip
setup(
...,
cmdclass={'sdist': sdist_upip.sdist}
)
Модуль sdist_upip.py из фрагмента выше можно найти в micropython-lib.
Ресурсы приложения
Помимо исходного кода, в готовом приложении также часто содержатся файлы данных: шаблоны веб-страниц, изображения и т.д. Понятно, как работать с ними, если приложение установлено вручную – вы просто помещаете эти данные в какое-то место файловой системы, а затем используете обычные функции для доступа к данным.
Но все меняется, когда приложение устанавливается из пакета. Это более продвинутый, простой и гибкий способ установки, но в этом случае вам также нужно воспользоваться более продвинутым методом для доступа к файлам данных. Он заключается в том, чтобы относиться к этим файлам данных как к «ресурсам» и сделать парочку дополнительных манипуляций.
В Python доступ к ресурсам поддерживается с помощью модуля pkg_resources из библиотеки «setuptools». MicroPython тоже частично поддерживает функционал этого модуля – в частности, за это отвечает функция pkg_resources.resource_stream(пакет, ресурс). Идея в том, что приложение может вызвать эту функцию и задать в ней аргументом идентификатор нужного ресурса – это будет относительный путь к файлу данных внутри заданного пакета (как правило, пакета приложения высокого уровня). Она вернет потоковый объект, который можно использовать для доступа к содержимому ресурсов. Таким образом, функция resource_stream() эмулирует интерфейс стандартной функции open().
Если пакет установлен в файловую систему, то resourse_stream() будет использовать файловые операции. Но эта функция может работать и без файловой системы – например, если пакет заморожен в виде байт-кода. Это, однако, требует дополнительного этапа при упаковке приложения – создания «ресурсного Python-модуля».
Идея этого модуля в том, чтобы преобразовать двоичные данные в Python-объект bytes, а затем поместить его в словарь, данные в котором будут упорядочены по названиям ресурсов. Это преобразование выполняется автоматически при помощи переопределенной команды sdist, описанной в предыдущем разделе.
Теперь давайте рассмотрим всё это с помощью наглядного примера. Допустим, ваше приложение имеет следующую структуру:
my_app/
__main__.py
utils.py
data/
page.html
image.png
Файлы «__main__.py» и «utils.py» получают доступ к ресурсам с помощью вот этих функций:
import pkg_resources
pkg_resources.resource_stream(__name__, "data/page.html")
pkg_resources.resource_stream(__name__, "data/image.png")
Вы можете как обычно разрабатывать и делать отладку приложения на порте MicroPython Unix. Когда наступит время делать из него дистрибутив, просто воспользуйтесь переопределенной командой sdist из модуля sdist_upip, как описывалось в разделе выше.
Это создаст ресурсный Python-модуль под названием R.py на основе файлов, объявленных в файлах MANIFEST и MANIFEST.in (любой файл без «*.py» будет считаться ресурсом и добавлен в R.py) – перед тем, как приступить к обычным этапам упаковки.
Если подготовить приложение таким образом, оно будет работать и в виде замороженного байт-кода, и будучи установленным в файловую систему.
Чтобы начать отладку создания R.py, запустите следующее:
python3 setup.py sdist --manifest-only
В качестве альтернативы можно воспользоваться скриптом «tools/mpy_bin2res.py» из дистрибутива MicroPython – в этом случае вам нужно будет также указать пути ко всем файлам ресурсов:
mpy_bin2res.py data/page.html data/image.png