Как правильно использовать сторонние зависимости с плагинами Sublime Text?

Я пытаюсь написать плагин для Sublime Text 3.

Я должен использовать несколько сторонних пакетов в своем коде. Мне удалось заставить код работать, вручную скопировав пакеты в /home/user/.config/sublime-text-3/Packages/User/, затем я использовал относительный импорт, чтобы получить нужный код. Как я могу распространять плагин среди конечных пользователей? Говорить им, чтобы они копировали необходимые зависимости в соответствующее место, конечно, не лучший выход. Как сторонние модули должны правильно использоваться с плагинами Sublime Text? Я не могу найти документацию в Интернете; все, что я вижу, это рекомендация класть модули в папку.


person adder    schedule 13.04.2020    source источник


Ответы (1)


Sublime использует собственный встроенный интерпретатор Python (в настоящее время Python 3.3.6, хотя следующая версия также будет поддерживать Python 3.8), и поэтому он будет полностью игнорировать любую версию Python, которая может быть установлена ​​или не установлена ​​в вашей системе. как любые библиотеки, установленные для этой версии.

По этой причине, если вы хотите использовать внешние модули (далее dependencies), вам нужно проделать дополнительную работу. Для этого существует множество способов, каждый из которых имеет свои плюсы и минусы.

Ниже перечислены различные способы достижения этого; все они требуют некоторого понимания того, как модули работают в Python, чтобы понять, что происходит. По большому счету, за исключением задействованных путей, в действующих механизмах нет ничего слишком «возвышенного текста».

ПРИМЕЧАНИЕ. Приведенное ниже верно на момент написания этого ответа. Однако есть планы для управления пакетами изменить то, как он работает с зависимостями, которые ожидаются, что может изменить некоторые аспекты этого.

Это связано с предстоящей версией Sublime, поддерживающей несколько версий Python (и способ их поддержки), которые не поддерживает текущий механизм управления пакетами.

На данный момент неясно, принесет ли изменение новый способ указания зависимостей или изменится только внутренняя работа установки зависимостей. Однако существующий механизм может остаться в силе независимо только для обратной совместимости.

Все пути к доступу к Python dependency из плагина Sublime предполагают размещение его кода в том месте, где его будет искать интерпретатор Python. Это похоже на то, как работает стандартный Python, за исключением того, что проверяемые местоположения содержатся в области, которую Sublime использует для хранения вашей конфигурации (называемой каталогом Data), и вместо автономного интерпретатора Python Python работает в хост плагина.

Заполните библиотеку в папку Lib

Начиная с версии 3.0 (сборка 3143), Sublime создаст папку с именем Lib в каталоге данных, а внутри него каталог на основе имени версии Python. Если вы используете Preferences > Browse Packages и подниметесь на один уровень папки, вы увидите Lib, а внутри него папку с именем, например. python3.3 (или, если вы используете более новую сборку, python33 и python38).

Эти каталоги находятся непосредственно на Python sys.path по умолчанию, поэтому все, что находится внутри них, будет немедленно доступно для любого плагина, как и обычная библиотека Python (или любая из встроенных). Вы можете считать эти папки чем-то вроде папки site-packages в стандартном Python.

Таким образом, можно использовать любой метод, с помощью которого вы можете установить стандартную библиотеку Python, если в результате файлы попадают в эту папку. Например, вы можете установить библиотеку через pip, а затем вручную скопировать файлы в это место из site-packages, вручную установить из исходников и т. д.

Lib/python3.3/
|-- librarya
|   `-- file1.py
|-- libraryb
|   `-- file2.py
`-- singlefile.py

Здесь действуют ограничения версии; dependency, который вы хотите использовать, должен поддерживать версию Python, которую использует Sublime, иначе он не будет работать. Это особенно важно для библиотек Python с собственным компонентом (например, .dll, .so или .dylib), для которых может потребоваться ручная компиляция кода.

Этот метод не является автоматическим; вам нужно будет сделать это, чтобы использовать ваш пакет локально, и любой, кто хочет использовать ваш пакет, также должен будет это сделать. Поскольку Sublime в настоящее время использует более старую версию Python, также может быть проблематично получить правильную версию библиотек.

В будущем Package Control установит dependencies в это место (будет добавлена ​​папка специально для этой цели во время перехода к версии 3.0), но на момент написания этого ответа это не так.

Продавайте свои зависимости непосредственно внутри вашего собственного пакета

Папка Packages по умолчанию также находится на sys.path; вот как Sublime находит и загружает пакеты. Это относится как к физической папке Packages, так и к «виртуальной» папке пакетов, содержащей содержимое sublime-package файлов.

Например, можно получить доступ к классу, который предоставляет команду exec, через:

from Default.exec import ExecCommand

Это будет работать, даже если файл exec.py фактически хранится в Default.sublime-package в папке установки Sublime text и физически не присутствует в папке Packages.

В результате вы можете vendor любой dependencies, который вам нужен, непосредственно внутри вашего собственного пакета. Здесь это может быть пакет User или любой другой пакет, который вы создаете.

Важно отметить, что Sublime будет рассматривать любой файл Python на верхнем уровне пакета как плагин и пытаться загрузить его как один. Следовательно, важно, чтобы, если вы пойдете по этому пути, вы создали подпапку в своем пакете и поместили туда библиотеку.

MyPackage/
|-- alibrary
|   `-- code.py
`-- my_plugin.py

С помощью этой структуры вы можете получить доступ к модулю напрямую:

import MyPackage.alibrary 

from MyPackage.alibrary import someSymbol

Не все модули Python подходят для этого метода напрямую без модификации; могут потребоваться некоторые изменения кода в dependency, чтобы позволить различным частям библиотеки видеть другие части самой себя, например, если она не использует относительный import для доступа к одноуровневым файлам. Этому также могут помешать лицензионные ограничения, в зависимости от используемой вами библиотеки.

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

Используя этот метод, все, что вы делаете для распространения своего пакета, автоматически также распространяет библиотеку поставщика, содержащуюся внутри. Так что, если вы распространяете с помощью Package Control, вам не нужно делать ничего особенного, и это будет Just Work™.

Измените sys.path, чтобы он указывал на пользовательское местоположение.

Python, встроенный в Sublime, по-прежнему является стандартным Python, поэтому при желании вы можете вручную манипулировать sys.path, описывающим, в каких папках искать пакеты, чтобы он искал место по вашему выбору в дополнение к стандартным местоположениям, которые устанавливает Sublime. автоматически.

Как правило, это не очень хорошая идея, поскольку, если все сделано неправильно, все может быстро стать грушевидным. Это также по-прежнему требует, чтобы вы сначала вручную установили библиотеки где-нибудь самостоятельно, и в этом случае вам лучше использовать папку Lib, как указано выше, которая уже находится на sys.path.

Я бы посчитал этот метод продвинутым решением, которое вы можете использовать для целей тестирования во время разработки, но в остальном это не то, с чем может столкнуться пользователь. Если вы планируете распространять свой пакет через Управление пакетами, проверка вашего пакета, скорее всего, отбросит манипуляцию sys.path с запросом на использование другого метода.

Используйте систему зависимостей Package Control (и зависимость существует)

Управление пакетами содержит механизм зависимости, который использует комбинацию двух предыдущих методов для обеспечения способа установки зависимости. автоматически. Существует также список доступных зависимостей, хотя этот список может быть неполным.

Если dependency, который вы хотите использовать, уже доступен, все готово. Есть два разных способа объявить, что вам нужна одна или несколько зависимостей от вашего пакета.

ПРИМЕЧАНИЕ. Управление пакетами в настоящее время не поддерживает зависимости зависимостей; если зависимость требует, чтобы была установлена ​​еще одна библиотека, вам нужно явно указать их обе самостоятельно.

Первый включает добавление ключа dependencies к записи для вашего пакета в файле канала управления пакетами. Это шаг, который вы предпримете в момент добавления своего пакета в Управление пакетами, что выходит за рамки этого ответа.

Пока вы разрабатываете свой пакет (или если вы решили, что не хотите распространять свой пакет через Управление пакетами, когда вы закончите), вы можете вместо этого добавить файл dependencies.json в корень вашего пакета (пример файла dependencies.json доступен для иллюстрации).

Как только вы это сделаете, вы можете выбрать Package Control: Satisfy Dependencies из палитры команд, чтобы Package Control загрузил и установил для вас зависимость (при необходимости).

Этот шаг выполняется автоматически, если ваш пакет распространяется и устанавливается с помощью Package Control; в противном случае вам нужно сообщить своим пользователям, чтобы они сделали этот шаг после установки пакета.

Используйте систему зависимостей Package Control (но зависимость не существует)

Метод, используемый Package Control для установки dependencies, как указано в верхней части вопроса, может быть изменен в какой-то момент в (возможно, ближайшем) будущем. Это может повлиять на приведенные здесь инструкции. Общий механизм может остаться прежним, что касается установки, с изменением только места установки, но это еще предстоит увидеть в настоящее время.

Управление пакетами устанавливает зависимости с помощью специальной комбинации vendoring, а также манипулирует sys.path, чтобы можно было что-то найти. Для этого требуется, чтобы вы изложили свою зависимость определенным образом, а также предоставили некоторые дополнительные метаданные.

Макет пакета, содержащего зависимость, при его сборке будет иметь структуру, подобную следующей:

Packages/my_dependency/
├── .sublime-dependency
└── prefix
    └── my_dependency
        └── file.py

Управление пакетами устанавливает dependency как пакет, а поскольку Sublime рассматривает каждый файл Python в корне пакета как плагин, код зависимости не хранится на верхнем уровне пакета. Как видно выше, фактическое содержимое зависимости хранится внутри папки, помеченной выше как prefix (подробнее об этом чуть позже).

Когда зависимость установлена, Package Control добавляет в свой специальный пакет 0_package_control_loader запись, которая приводит к тому, что папка prefix добавляется в sys.path, что делает все внутри нее доступным для операторов import, как обычно. Вот почему существует неотъемлемое дублирование имени библиотеки (в этом примере my_dependency).

Что касается папки prefix, на самом деле она не называется так, а вместо этого имеет специальное имя, которое определяет, на какой комбинации версии Sublime Text, платформы и архитектуры доступна зависимость (важно, например, для библиотек, содержащих двоичные файлы).

Имя папки prefix на самом деле соответствует форме {st_version}_{os}_{arch}, {st_version}_{os}, {st_version} или all. {st_version} может быть st2 или st3, {os} может быть windows, linux или osx, а {arch} может быть x32 или x64.

Таким образом, вы можете сказать, что ваша зависимость поддерживает только st3, st3_linux, st3_windows_x64 или любую их комбинацию. Для чего-то с собственным кодом вы можете указать несколько разных версий, имея несколько папок, хотя обычно all используется, когда dependency содержит чистый код Python, который будет работать независимо от версии Sublime, ОС или архитектуры.

В этом примере, если мы предположим, что папка prefix называется all, потому что my_dependency — это чистый Python, то результатом установки этой зависимости будет то, что Packages/my_dependency/all будет добавлено к sys.path, а это означает, что если вы import my_dependency получаете код из внутри этой папки.

Во время разработки (или если вы не хотите распространять свою зависимость через Package Control) вы создаете файл .sublime-dependency в корне пакета, как показано выше. Это должен быть текстовый файл с одной строкой, содержащей двузначное число (например, 01 или 50). Это определяет, в каком порядке каждая установленная зависимость будет добавлена ​​в файл sys.path. Обычно вы выбираете меньшее число, если у вашей зависимости нет других зависимостей, и большее значение, если оно есть (чтобы он был внедрен после них).

После того, как исходная зависимость будет размещена в правильном формате в папке Packages, вы должны использовать команду Package Control: Install Local Dependency из палитры команд, а затем выбрать имя своей зависимости.

Это заставляет Package Control «установить» зависимость (т. е. обновить пакет 0_package_control_loader), чтобы сделать зависимость активной. Этот шаг обычно выполняется Package Control автоматически, когда он устанавливает зависимость в первый раз, поэтому, если вы также вручную распространяете свою зависимость, вам необходимо предоставить инструкции для выполнения этого шага.

person OdatNurd    schedule 14.04.2020