Несколько месяцев назад компания Wolfram Research открыла общий доступ к Wolfram Language Paclet Repository. Это централизованное хранилище пользовательских пакетов, написанных на языке Wolfram. Данное хранилище не является чем-то новым само по себе. Для языка Wolfram уже есть несколько возможных способов публикации пакетов. Однако, у официального репозитория есть несколько очень важный преимуществ перед существующими решениями. В этой статье я сначала коротко расскажу что из себя представляет репозиторий, а затем пошагово покажу как опубликовать в него свой собственный пакет при помощи предоставленных компанией Wolfram Research инструментов.
Что такое пакет на языке Wolfram
Пакет - это почти любой код, который можно загрузить в текущую сессию пользователя. Это может быть всего один файл, где есть одна функция, а может быть довольно большая библиотека, где много файлов с исходным кодом и функций. Обычно расширение у файлов с кодом это *.wl или *.m, однако, иногда попадаются пакеты с файлами *.mx, которые представляют собой сериализованный варианты *.m и *.wl. Чаще всего, к сожалению, пользователи свои пакеты распространяют как есть в виде одного файла или папки с набором файлов. Но чуть-чуть более ответственные пользователи для удобства других людей упаковывают свой код в специальный файл с расширением *.paclet. Изначально паклеты придумали исключительно для того, чтобы стандартизировать создание документации для модулей Mathematica, однако, позже их возможности применения увеличились и на сегодняшний день *.paclet - это по сути архив, где содержится код, документация к нему и специальный файл PacletInfo.wl, который выполняет функцию, похожую на ту, что несет в себе например файл package-info.java для файлов *.jar. И что самое важное - PacletInfo.wl содержит в себе информацию для функции PacletInstall, которая выполняет стандартную установку пакетов. Интересно, что как и с файлам *.jar, файлы *.paclet можно просто распаковать архиватором, взять файлы с исходным кодом и в ручную поместить в нужную директорию, по сути выполнив установку.
Как устанавливать пакеты
Будем считать, что у пользователя уже установлены Wolfram Mathematica или Wolfram Engine. Тогда если он вдруг каким-то образом уже нашел необходимый для себя пакет, то у него есть несколько вариантов этот пакет установить.
Если это просто папка с файлами или один файл
Самый просто вариант - это использовать пакет без установки, а просто поместить найденный файл или папку рядом с вашим рабочим блокнотом, а в самом блокноте тогда нужно будет просто выполнить следующий код:
SetDirectory[NotebookDirectory[]];
Get["PackageName`"]
Или даже без изменения рабочей директории для текущей сессии:
Get["/path/to/the/package"]
Или даже без скачивания на свой компьютер - вы можете импортировать исходники прямо из github (или из любого другого места, доступного по http/https), если там всего один файл:
Get["https://raw.githubusercontent.com/UserName/RepoName/master/PackageName.wl"]
Однако, удобнее всего поместить пакет в ту директорию, где Wolfram Language всегда сможет его найти без необходимости указания полного пути или изменения рабочий директории. Такое расположение всегда можно посмотреть если посмотреть значение системной переменной:
$Path
Эта переменная - просто список директорий, по которым проходит ядро Wolfram в поисках пакета или при импорте любого файла. И там скорее всего будет строка примерно вот такого вида (для пользователей Windows и Mathematica):
C:\Users\UserName\AppData\Roaming\Mathematica\Applications
Вот это и есть та самая папка, куда стоит помещать готовые пакеты, если вы их устанавливаете в ручную. Кроме того, путь к это директории можно получить использую другую системную переменную языка Wolfram:
FileNameJoin[{$UserBaseDirectory, "Applications"}]
Т.е. вам будет достаточно скопировать любой скачанный на компьютер файл в эту директорию, после чего код из него он станет доступен для импорта в любом блокноте Wolfram:
CopyFile[
FileNameJoin[{$HomeDirectory, "Downloads", "PackageName.wl"}],
FileNameJoin[{$UserBaseDirectory, "Applications", "PackageName.wl"}]
]
Get["PackageName`"]
Если это упакованный паклет
Тогда все очень просто. Либо распаковать его при помощи специальной функции и поместить файлы в папку с локальными пользовательскими пакетами:
dir = ExtractPacletArchive[
FileNameJoin[{$HomeDirectory, "Downloads", "PackageName.paclet"}]
]
CopyDirectory[
dir,
FileNameJoin[{$UserBaseDirectory, "Applications", "PackageName"}]
]
Либо воспользоваться недавно (в 2020 году) добавленной функций, которая сделает это автоматически, но еще и с сохранением информации о версии пакета:
PacletInstall[FileNameJoin[{$HomeDirectory, "Downloads", "PackageName.paclet"}]]
Тогда скачанный пакет установится в папку, путь в которой можно получить вот так:
FileNameJoin[{$UserBasePacletsDirectory, "Repository"}]
Кроме того, начиная с версии 12.1 в языке Wolfram стала доступна подобная установка пакетов прям по http/https. Выглядеть это будет примерно вот так:
PacletInstall["https://github.com/UserName/PackageName/releases/download\
/vX.Y.Z/PackageName-X.Y.Z.paclet"]
Где можно найти пакеты
Чаще всего пользователи, как и для всех остальных языков программирования, публикуют исходный код своих пакетов на github. Там же в разделе с релизами можно добавить и упакованные пакеты или архивы с исходными файлами. Выше мы рассмотрели как установить упакованный пакет напрямую по ссылке на загрузку файла, однако, некоторые пользователи либо запускаются собственные паклет-сайты. Кроме того, достаточно долгое время существовал официальный закрытый репозиторий компании Wolfram Research, из которого скачивались встроенные в Wolfram Language пакеты. Этот репозиторий является хранилищем по умолчанию, из него можно получать обновления встроенных пакетов, но в него никто ничего не может добавлять.
О Wolfram Language Paclet Repository
Не так давно появился Wolfram Function Repository, статья о котором есть на хабре (перевод статьи опубликовал Пётр Тенишев, который является администратором в группе по Wolfram Mathematica. Если вдруг читатели заинтересуются дополнительными материалами по языку Wolfram, то там постоянно появляется что-то новое на русском языке). Теперь компания добавила примерно тоже самое, но не для конкретных функций, а для пакетов. Пользователи получили возможность выложить в репозиторий любой свой пакет, после чего он станет доступен всем. Ключевым отличием является то, что данный репозиторий включен в список мест, откуда Wolfram Language может скачивать пакеты по умолчанию. То есть больше не нужно самостоятельно добавлять в системные настройки путь до паклет-сайта или указывать расположение архива напрямую.
Вторым отличием является то, что компания Wolfram Research выложила заранее заготовленный блокнот на языке Wolfram, в котором в виде дополнительного пользовательского интерфейса реализованы основные действия с пакетами. По сути этот блокнот похож чем-то на maven или ms build, но в достаточно необычной оболочке. На самом деле далее мы увидим какие именно шаги позволяет делать этот блокнот-сборщик.
Третье отличие - в репозиторий пакетов по умолчанию можно выкладывать и документацию на языке Wolfram. Т.е. сразу же писать блокноты с документацией и их отправлять в репозиторий. В общем лучше один раз увидеть...
Получаем PublisherID
Это просто необходимая системная переменная, которая будет связана с вашим аккаунтов в Wolfram Cloud. Для того чтобы его получить нужно просто иметь аккаунт на wolframcloud.com. А затем перейти на страницу, где можно заполнить форму и отправить запрос на получение PublisherID. Я уже выкладывал пакеты в репозиторий, поэтому у меня есть PublisherID == KirillBelov. Именно под этим именем я могу публиковать свои пакеты в репозитоии. Сделано это очевидно для того, чтобы не возникало ситуации когда пользователи выкладывают одинаковые пакеты. Ниже скриншот формы для получения идентификатора:
Создаем проект
Собственно перейдем к практике. В данный момент, пока я пишу эти строки, у меня на компьютере есть совсем небольшой пакет, где есть чуть-чуть исходного кода и он хорошо подходит для демонстрационных целей. В статье мы не будем описывать сам процесс написания пакета, а сосредоточимся только на его подготовке и публикации. Мой пакет называется BankCalculator. Он умеет показывать ожидаемый доход от банковских вкладов. В данный момент папка с проектом выглядит следующим образом:
Файл BankCalculator.wl переместим во внутреннюю папку Kernel. Если этой папки нет, то ее можно просто создать. Это нужно для удобства сборщика, т.к. сборщик ищет файлы в определенной папке. Если же файлы с исходным кодом будут находиться рядом с файлом PacletInfo.wl, то сборщик может найти лишние файлы.
Так же нужно добавить в эту директорию файл PacletInfo.wl и заполнить его необходимо следующими данными:
PacletObject[<|
"Name" -> "KirillBelov/BankCalculator",
"Description" -> "Bank calculator",
"Creator" -> "Kirill Belov",
"License" -> "MIT",
"Version" -> "1.0.0",
"WolframVersion" -> "13.0+",
"PublisherID" -> "KirillBelov",
"Extensions" -> {
{
"Kernel",
"Root" -> "Kernel",
"Context" -> {
{"KirillBelov`BankCalculator`", "BankCalculator.wl"}
},
"Symbols" -> {}
},
{"Documentation", "Language" -> "English"}
}
|>]
PacletObject это просто тип, который говорит о том, что это файл с описанием пакета. $PublisherID
мы получали в одном из пунктов выше. Значение ключа "Name"
должно соответствовать шаблону "$PublisherID/$PackageName"
, Контекст соответственно должен выглядеть как "$PublisherID`PackageName`"
. Контекст - это аналог пространств имен, в котором будут находится все функции пакета. Этот же контекст должен быть указан в файле BankCalculator.wl. Все остальные ключи ассоциации интуитивно понятны. Теперь папка с проектом выглядит следующим образом:
Скачиваем шаблон сборщика
Для того, чтобы перейти к дальнейшей работе нам необходимо скачать специальный блокнот по следующей ссылке: https://resources.wolframcloud.com/PacletRepository/Unnamed-Paclet.nb. Это пустой шаблон для любого пакета. Нам не важно куда скачать и поместить данный блокнот.
Создаем PacletResource.nb
Открываем только что скачанный блокнот:
Нас приветствует всего одна кнопка Select Paclet Directory. Нажимаем на нее, после чего откроется следующее окно с полем ввода, где можно указать путь до нашего пакета:
Подтверждаем выбор, после чего открывается следующее окно, где нас уже информируют о том, что в указанной директории нашелся файл PacletInfo.wl с указанными именем пакета, контекстом и директорий. Опять подтверждаем выбор:
Далее мы получили почти окончательный результат настройки - сгенерированный блокнот, в котором добавлено меню для проверки, сборки и выкладки проекта в репозиторий. Выглядит он следующим образом:
Опять же, все достаточно интуитивно понятно. Правда первое, что я бы рекомендовал сделать сохранить данный блокнот в директорию с проектом. Назвать его можно как угодно, я назывe этот файл ResourceDefenition.nb. Теперь в папке с проектом уже 3 файла, плюс добавилась новая (пустая на данный момент) директория для документации к проекту:
После того, как файл с определением пакета был сохранен в папку с проектом можно переключить галочку с указанием расположения файлов в поле "Paclet Directory":
Рассмотрим внимательнее дополнительный пункты меню (которые на сером фоне и ниже). Там есть несколько разделов, которые отвечают как раз за шаги поверки, сборки и публикации пакета.
Open Sample - тут все понятно - просто показывает примеры
Guidelines - открывает в браузере ссылку на небольшое руководство
Tools - в данный момент этот раздел как раз развернут на скриншоте выше и содержит в себе дополнительное меню
[Template Input | Literal Input | ... ]
.Check - позволяет запустить анализатор кода пакета. Причем можно отдельно выбрать что анализировать: документацию, исходный код или текущий блокнот с определением пакета
Build - собирает пакет или документацию
Deploy - публикует пакет в собственное хранилище в облаке Wolfram
Submit to Repository - то ради чего написана эта статья. Возможность выложить результат в публичный репозиторий пакетов
Заполнение шаблона
Сначала заполним все самые простые поля ввода. Вставим картинку для заголовка:
Укажем базовое описание. Basic Description автоматически добавилось описание из файла PacletInfo.wl. Путь к основном файлу документации мы пока не можем указать, так как пока что документации не написана:
Вот этот раздел можно не трогать, так как ячейки с таким стилем не публикуются, а нужны только для разработчика. Но стоит отметить, что точно так же эти ячейки были сгенерированы автоматически на основе информации из PacletInfo.wl:
Добавим несколько базовых примеров:
И дополнительные примеры:
В последнем разделе должно быть автоматически добавлено имя автора. так же выберем подходящие разделы для пакета и укажем ключевые слова.
В самом низу отмечаем тип пакета, т.е. с чем он будет взаимодействовать. В нашем случае - это просто пакет, который используется встроенные функции Wolfram Language и не читает никакие файлы и не обращается к внешним сервисам:
Документация
Приступим к созданию документации. В версии 13 стали доступны встроенные средства для создания документации к функциям. Эти же средства встроены в виде дополнительного меню в наш рабочий блокнот. В нашем пакете всего два имени, поэтому создать для них документацию не составит труда. Для этого выбираем пункт меню "New Function Page":
После нажатия откроется автоматически форма, где можно ввести имя функции:
После подтверждения откроется автоматически сгенерированный файл для этой функции. При этом, опции (если есть) и описание использования копируются напрямую из определения. Страница документации будет выглядеть вот так:
В таких блокнотах необходимо заполнить описание, добавить ссылки на связанные руководства и функции. Но самое главное добавить максимально показательные примеры.
После того как страницы будут созданы и заполнены - можно создать одно объединяющее руководство или "гайд", где будут список доступных функций пакета. Для этого в том же меню определения пакета нужно выбрать уже "New Guide Page". Введем название и получим блокнот вот такого вида:
Отдельно стоит сказать про то, как нужно пользоваться палитрой Documentation Tools. Вот она:
Это набор кнопок, который чаще всего форматирует выделенный мышкой текст. Т.е. например, я хочу вставить внутреннюю ссылку на страницу CalcROI из страницы Deposit. Для этого я пишу имя CalcROI там где хочу чтобы была ссылка, выделяю его, а затем мышкой кликаю п кнопке Link to Function, которую можно увидеть на скриншоте выше. В принципе с остальными кнопками все работает примерно так же. На этом наша первая версия документации закончена, перейдем к следующим шагам.
Проверка и сборка
После того как определение пакета оформлено, документация написана (документация на самом деле не обязательна) можно проверить пакет. Из дополнительного меню просто выбирает пункт Check > All. С нажатием этой кнопки запустится процесс анализа кода блокнота и пакета, результат которого визуально отобразится в виде сообщений под дополнительным меню и прямо в блокноте:
В общем-то в нашем случае есть только рекомендации, которые мы пока что проигнорируем, но часто анализатор показывает и серьезные ошибки. Если они были - их необходимо исправить. А мы перейдем уже к шагу сборки. Из дополнительного меню запустим процесс сборки пакета - Build > All:
После подтверждения в папке проекта появится директория build, в которой окажется результат сборки:
Это уже упакованный файл с расширением *.paclet, который можно установить на локальный компьютер при помощи PacletInstall и тот же самый пакет в виде папки - по сути содержание паклета.
Отправка в облако
Если выбрать пункт Deploy > Publicy in the Cloud, то готовый пакет будет опубликован в вашем личном хранилище в Wolfram Cloud. После завершения сборки автоматически откроется браузер на странице этого пакета. Выглядеть страница в браузере будет вот так:
Соответственно здесь контент из определения пакета, а так же слева видно ссылки на документацию. Вот как выглядит собранная документация:
Отправка в публичный репозиторий
Собственно кульминация всей этой статьи. Давайте просто нажмем на кнопку и опубликуем пакет в Wolfram Language Paclet Repository. :
Перейдем на страницу со опубликованными пакетами:
Теперь пакет можно найти в публичном репозитории или читатели просто могут посмотреть его по прямой ссылке: https://resources.wolframcloud.com/PacletRepository/resources/KirillBelov/BankCalculator/.
Установка
Собственно заключительный шаг - пробуем установить пакет, посчитать доход. Следуем инструкции на странице пакета, открываем любой блокнот Mathematica или консоль Wolfram Engune и выполняем код:
PacletSiteUpdate /@ PacletSites[];
PacletInstall["KirillBelov/BankCalculator"]
Пакет установлен и можно что-то посчитать:
Заключение
На этом на сегодня все. В заключении я хочу описать свои личные эмоции по поводу появления такого хранилища пользовательских пакетов. Я являюсь давним фанатом языка Wolfram и очень давно хотел чтобы нечто подобное NuGet или Maven появилось и для Wolfram Language. Сначала я своим глазам не поверил, когда появился Wolfram Engine, затем когда появился Function Repository, а теперь еще и репозиторий пакетов. Для меня лично это одна из лучших новостей касающихся языка Wolfram за последние годы вместе с бесплатным ядром. Я очень надеюсь, что читателям будет полезна эта статья и что она у кого-то вызовет интерес к языку Wolfram. Всем спасибо за внимание!